Skip to content

fix(skills): import full skill folder instead of single SKILL.md#708

Open
RajdeepKushwaha5 wants to merge 1 commit intoaccomplish-ai:mainfrom
RajdeepKushwaha5:fix/skill-folder-import-656
Open

fix(skills): import full skill folder instead of single SKILL.md#708
RajdeepKushwaha5 wants to merge 1 commit intoaccomplish-ai:mainfrom
RajdeepKushwaha5:fix/skill-folder-import-656

Conversation

@RajdeepKushwaha5
Copy link
Contributor

@RajdeepKushwaha5 RajdeepKushwaha5 commented Mar 12, 2026

Summary

Fixes #656

When importing a local skill via Settings → Skills → Add → Upload a skill, only the SKILL.md file was copied. Any companion files bundled alongside the skill (e.g. template_layouts.md, template.pptx, data.json) were silently ignored, making locally-authored multi-file skills unusable after import.

This PR changes the import flow to select an entire folder instead of a single file, then copies all files within that folder into the user skills directory.


Problem

Skills can contain companion files that the agent reads at runtime (templates, reference data, etc.). The previous file-picker dialog only accepted a single .md file, so importing a skill stripped out everything except SKILL.md.

Before:

  • Dialog: "Select a SKILL.md file" (single-file picker)
  • Result: only SKILL.md copied → companion files lost

After:

  • Dialog: "Select a skill folder" (directory picker)
  • Result: all files in the selected folder are copied → full skill preserved

Changes

File Change
packages/agent-core/src/internal/classes/SkillsManager.ts addSkill() detects directory vs file; new addFromFolder() copies all sibling files
apps/desktop/src/main/ipc/handlers.ts skills:pick-fileskills:pick-folder with openDirectory property
apps/desktop/src/preload/index.ts pickSkillFile()pickSkillFolder()
apps/web/src/client/lib/accomplish.ts AccomplishAPI interface updated to pickSkillFolder()
apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx Calls pickSkillFolder() instead of pickSkillFile()
apps/web/locales/en/settings.json Description updated to "Upload a skill folder"
apps/web/locales/zh-CN/settings.json Description updated to "上传技能文件夹"
packages/agent-core/tests/unit/skills/skills-manager.test.ts New tests: folder import copies all files; error when SKILL.md missing

Testing

  • TypeScript typecheck passes (pnpm typecheck) — all 3 workspaces clean
  • ESLint passes (pnpm lint:eslint) — no new issues
  • New unit tests added for addSkill from folder:
    • Copies SKILL.md and all companion files to the destination directory
    • Throws a descriptive error when the selected folder has no SKILL.md
  • Backward-compatible: passing a file path (not a directory) to addSkill() still works via the existing addFromFile() path

Notes

  • Sub-directories inside the skill folder are intentionally not recursively copied — skills are expected to be flat folders (matching how bundled skills are structured).
  • The addSkillFromFile IPC channel and preload method are renamed to addSkillFromFolder / pickSkillFolder for clarity. The underlying addSkill(sourcePath) API in agent-core remains unchanged.

Summary by CodeRabbit

  • New Features

    • Skill import switched to folder-based selection (desktop dialog now lets you pick a skill folder).
  • UI

    • Updated import text in English, French, Russian, and Chinese to reflect folder-based workflow.
  • Bug Fixes / Validation

    • Import now validates presence of SKILL.md and reports a clear error if missing.
  • Tests

    • Added tests for successful folder import and missing-SKILL.md error.

Copilot AI review requested due to automatic review settings March 12, 2026 07:36
@orcaman
Copy link
Contributor

orcaman commented Mar 12, 2026

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: aa471d3c-8ea1-47d6-9509-be141ae6b7ab

📥 Commits

Reviewing files that changed from the base of the PR and between 78a0ccc and 3af8d79.

📒 Files selected for processing (10)
  • apps/desktop/src/main/ipc/handlers.ts
  • apps/desktop/src/preload/index.ts
  • apps/web/locales/en/settings.json
  • apps/web/locales/fr/settings.json
  • apps/web/locales/ru/settings.json
  • apps/web/locales/zh-CN/settings.json
  • apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx
  • apps/web/src/client/lib/accomplish.ts
  • packages/agent-core/src/internal/classes/SkillsManager.ts
  • packages/agent-core/tests/unit/skills/skills-manager.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/desktop/src/preload/index.ts
  • packages/agent-core/tests/unit/skills/skills-manager.test.ts
  • apps/desktop/src/main/ipc/handlers.ts
  • packages/agent-core/src/internal/classes/SkillsManager.ts
  • apps/web/locales/fr/settings.json
  • apps/web/src/client/lib/accomplish.ts
  • apps/web/locales/ru/settings.json

📝 Walkthrough

Walkthrough

Converts skill import from selecting a single SKILL.md file to selecting a skill folder: desktop IPC and preload APIs updated, web UI and locale strings changed, core SkillsManager gains folder import logic and unit tests for folder imports were added.

Changes

Cohort / File(s) Summary
Desktop IPC & Preload
apps/desktop/src/main/ipc/handlers.ts, apps/desktop/src/preload/index.ts
Renamed IPC channel skills:pick-fileskills:pick-folder; native dialog now selects directories (openDirectory). Preload API renamed methods: pickSkillFilepickSkillFolder, addSkillFromFile(filePath)addSkillFromFolder(folderPath).
Web UI & API Surface
apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx, apps/web/src/client/lib/accomplish.ts
UI component and AccomplishAPI updated to call folder-based methods (pickSkillFolder, addSkillFromFolder) and use folderPath variable.
Localization
apps/web/locales/en/settings.json, apps/web/locales/fr/settings.json, apps/web/locales/ru/settings.json, apps/web/locales/zh-CN/settings.json
Changed skill import strings from file-centric to folder-centric wording (uploadDescription, uploadFailedDescription, selectFile) across locales.
Core Skill Management
packages/agent-core/src/internal/classes/SkillsManager.ts
addSkill now detects directory inputs and delegates to new private addFromFolder(folderPath) which validates presence of SKILL.md, parses frontmatter, copies top-level files into destination, and persists the skill as 'custom'.
Tests
packages/agent-core/tests/unit/skills/skills-manager.test.ts
Added "addSkill from folder" tests: successful folder import (verifies metadata and copied files) and error when SKILL.md is missing (duplicate blocks present in diff).

Sequence Diagram

sequenceDiagram
    participant User as User
    participant UI as AddSkillDropdown
    participant API as AccomplishAPI
    participant IPC as IPC Channel
    participant Dialog as Folder Dialog
    participant SkillsMgr as SkillsManager
    participant FS as Filesystem

    User->>UI: Click "Add Skill"
    UI->>API: pickSkillFolder()
    API->>IPC: invoke "skills:pick-folder"
    IPC->>Dialog: open folder selection dialog
    User->>Dialog: Select folder
    Dialog->>IPC: return folder path
    IPC->>API: return folder path
    API->>UI: deliver folder path or null

    alt Folder selected
        UI->>API: addSkillFromFolder(folderPath)
        API->>SkillsMgr: addSkill(folderPath)
        SkillsMgr->>FS: stat(path) -> isDirectory?
        FS-->>SkillsMgr: directory true
        SkillsMgr->>SkillsMgr: addFromFolder(folderPath)
        SkillsMgr->>FS: read SKILL.md
        FS-->>SkillsMgr: SKILL.md content
        SkillsMgr->>SkillsMgr: parse frontmatter & prepare dest
        SkillsMgr->>FS: copy top-level files to destination
        FS-->>SkillsMgr: copy complete
        SkillsMgr-->>API: return Skill object
        API-->>UI: Skill object
        UI->>UI: trigger onSkillAdded
    else Cancelled
        UI->>UI: handle cancellation
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • dotandavidovich-acc

Poem

🐇
I hopped the folders, nibbling through each file,
Found SKILL.md and friends, I stayed a little while.
Copied templates, data, every helpful clue,
Whole skills arrive — a garden fresh and new! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: converting skill import from file-based to folder-based approach.
Linked Issues check ✅ Passed All coding requirements from issue #656 are met: folder selection replaces file selection, all top-level files are copied, and the full skill is now uploadable.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing folder-based skill import. Locale updates, IPC handlers, UI components, and tests are all in scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

You can get early access to new features in CodeRabbit.

Enable the early_access setting to enable early access features such as new models, tools, and more.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes local skill import so that importing via Settings → Skills → Add → Upload selects a skill folder instead of a single SKILL.md, aiming to preserve companion files needed at runtime (issue #656).

Changes:

  • Update agent-core skill installation to detect directory paths and copy skill folder contents into the user skills directory.
  • Update Electron IPC + preload + web UI to pick a directory (openDirectory) and call the renamed pickSkillFolder() / addSkillFromFolder() APIs.
  • Update settings UI copy in multiple locales and add unit tests covering folder import + missing SKILL.md.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/agent-core/src/internal/classes/SkillsManager.ts Detect directory vs file in addSkill(); add addFromFolder() that copies folder contents.
packages/agent-core/tests/unit/skills/skills-manager.test.ts Add unit tests asserting companion files are copied and error when SKILL.md is missing.
apps/desktop/src/main/ipc/handlers.ts Replace skills:pick-file with skills:pick-folder using openDirectory.
apps/desktop/src/preload/index.ts Expose pickSkillFolder() and addSkillFromFolder() on the preload API.
apps/web/src/client/lib/accomplish.ts Update AccomplishAPI interface to folder-based methods.
apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx Use folder picker + folder import method in the UI flow.
apps/web/locales/en/settings.json Update upload text to “Select a skill folder to import”.
apps/web/locales/zh-CN/settings.json Update upload text to folder-based wording.
apps/web/locales/ru/settings.json Update upload text to folder-based wording.
apps/web/locales/fr/settings.json Update upload text to folder-based wording.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@@ -328,7 +328,7 @@
"uploadFailedTitle": "Échec de l'importation",
"uploadFailedDescription": "Le fichier de compétence n'a pas pu être importé.",
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI now imports a skill folder, but uploadFailedDescription still refers to a "fichier" (file). This string is shown when folder import fails, so it should be updated to refer to a folder ("dossier") or be phrased more generally.

Suggested change
"uploadFailedDescription": "Le fichier de compétence n'a pas pu être importé.",
"uploadFailedDescription": "Le dossier de compétence n'a pas pu être importé.",

Copilot uses AI. Check for mistakes.
@@ -328,7 +328,7 @@
"uploadFailedTitle": "Ошибка загрузки",
"uploadFailedDescription": "Не удалось загрузить файл навыка.",
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI now imports a skill folder, but uploadFailedDescription still says "файл" (file). This message should be updated to refer to a folder ("папку") or be made generic so it matches the new folder-based import flow.

Suggested change
"uploadFailedDescription": "Не удалось загрузить файл навыка.",
"uploadFailedDescription": "Не удалось импортировать навык.",

Copilot uses AI. Check for mistakes.
@@ -328,7 +328,7 @@
"uploadFailedTitle": "上传失败",
"uploadFailedDescription": "无法上传技能文件。",
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI now imports a skill folder, but uploadFailedDescription still says "技能文件" (skill file). This should be updated to "技能文件夹" (skill folder) or be phrased more generally to match the new folder-based import flow.

Suggested change
"uploadFailedDescription": "无法上传技能文件",
"uploadFailedDescription": "无法上传技能文件夹",

Copilot uses AI. Check for mistakes.
Comment on lines +257 to +264
// Copy all top-level files from the source folder into the destination
const entries = fs.readdirSync(folderPath, { withFileTypes: true });
for (const entry of entries) {
if (!entry.isFile()) continue;
const srcFile = path.join(folderPath, entry.name);
const destFile = path.join(destDir, entry.name);
fs.copyFileSync(srcFile, destFile);
}
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addFromFolder() currently only copies top-level files and skips subdirectories (if (!entry.isFile()) continue). Skills in this repo can include nested folders (e.g. references/, src/), and the reported issue example also uses a subfolder; importing such skills would still drop those nested companion files. Consider recursively copying the selected folder into the destination skill directory (while still validating that SKILL.md exists at the root), or explicitly documenting/enforcing the “flat folder” constraint in the UI and validation.

Copilot uses AI. Check for mistakes.
Comment on lines +440 to +442
pickSkillFolder: (): Promise<string | null> => ipcRenderer.invoke('skills:pick-folder'),
addSkillFromFolder: (folderPath: string): Promise<Skill> =>
ipcRenderer.invoke('skills:add-from-file', folderPath),
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

addSkillFromFolder is invoking the IPC channel 'skills:add-from-file'. Even though agent-core can now accept a directory path, the channel name no longer matches the behavior and contradicts the renamed API surface (addSkillFromFolder). Consider adding a dedicated 'skills:add-from-folder' handler (keeping 'skills:add-from-file' as a backward-compatible alias) and updating the preload call to use it to avoid future confusion/breakage if the main handler becomes file-specific again.

Copilot uses AI. Check for mistakes.
"uploadFailedDescription": "Не удалось загрузить файл навыка.",
"uploadErrorHelp": "Убедитесь, что ваш файл SKILL.md содержит корректный YAML-заголовок с полем",
"selectFile": "Выберите файл SKILL.md",
"selectFile": "Выберите папку c навыком",
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Russian translation uses a Latin "c" in "папку c навыком"; it should be the Cyrillic "с" ("with"), otherwise it reads as a typo to native speakers.

Suggested change
"selectFile": "Выберите папку c навыком",
"selectFile": "Выберите папку с навыком",

Copilot uses AI. Check for mistakes.
@@ -328,7 +328,7 @@
"uploadFailedTitle": "Upload Failed",
"uploadFailedDescription": "The skill file could not be uploaded.",
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UI now uploads/imports a skill folder, but uploadFailedDescription still says "skill file". This message will be shown for folder imports, so it should be updated to refer to a folder (or use more general wording like "skill" without specifying file/folder).

Suggested change
"uploadFailedDescription": "The skill file could not be uploaded.",
"uploadFailedDescription": "The skill could not be uploaded.",

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/web/locales/en/settings.json (1)

322-331: ⚠️ Potential issue | 🟡 Minor

The failure copy still describes a file upload.

This flow now asks the user to pick a folder, but uploadFailedDescription still says “The skill file could not be uploaded.” The error dialog will read wrong after a folder-import failure, and the localized equivalents likely need the same update.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/web/locales/en/settings.json` around lines 322 - 331, Update the failure
copy keys so the dialog matches the folder-import flow: change
"uploadFailedDescription" from "The skill file could not be uploaded." to
wording that references the folder import (e.g., "The skill folder could not be
imported.") and update "uploadErrorHelp" to remove/replace "file" with "folder"
and clarify YAML frontmatter expectations (e.g., "Make sure your SKILL.md in the
folder has valid YAML frontmatter with at least a ..."). Apply the same wording
changes for any localized equivalents of these keys.
apps/desktop/src/main/ipc/handlers.ts (1)

1178-1188: ⚠️ Potential issue | 🔴 Critical

Directory selection now feeds a file-only import path.

This dialog now returns a directory, but the next hop still goes through skills:add-from-fileskillsManager.addFromFile(). Selecting any folder will therefore try to read the directory as a file and fail before the new addFromFolder() path is ever reached. Route the import through the directory-aware entry point here as part of the same change.

🐛 Proposed fix
-  handle('skills:add-from-file', async (_event, filePath: string) => {
-    return skillsManager.addFromFile(filePath);
+  handle('skills:add-from-file', async (_event, sourcePath: string) => {
+    return skillsManager.addSkill(sourcePath);
   });
Based on learnings: IPC handlers in `apps/desktop/src/main/ipc/handlers.ts` must match `window.accomplish` API in preload.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ipc/handlers.ts` around lines 1178 - 1188, The
skills:pick-folder IPC handler currently returns a directory path that will be
routed later through the file-only path; change it so that once a directory is
chosen it immediately invokes the directory-aware import instead of returning
the path for skills:add-from-file. Concretely, in the handler for
'skills:pick-folder' replace the current return-of-path behavior with a call
into the directory-aware entry (either invoke the IPC channel
'skills:add-from-folder' or call skillsManager.addFromFolder(<selectedPath>)
directly) and return that result, and remove any routing that expects
skills:add-from-file/skillsManager.addFromFile() to handle a directory. Ensure
the handler name 'skills:pick-folder', the file-only channel
'skills:add-from-file', and the directory import entry 'skills:add-from-folder'
/ method 'skillsManager.addFromFolder' are used as referenced above.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/agent-core/src/internal/classes/SkillsManager.ts`:
- Around line 254-266: The import currently copies files from folderPath into
the existing destination dir returned by prepareSkillDir(frontmatter) but never
removes files that were deleted from the source; update the logic in the code
block around prepareSkillDir/destSkillMdPath and before calling persistSkill to
mirror the source: either remove any top-level files in destDir that are not
present in the source (compare entries from fs.readdirSync(folderPath) to
fs.readdirSync(destDir) and unlink extras) or clear/recreate destDir completely
before copying, then proceed with the existing copy loop and call to
persistSkill(frontmatter, destSkillMdPath, 'custom').

---

Outside diff comments:
In `@apps/desktop/src/main/ipc/handlers.ts`:
- Around line 1178-1188: The skills:pick-folder IPC handler currently returns a
directory path that will be routed later through the file-only path; change it
so that once a directory is chosen it immediately invokes the directory-aware
import instead of returning the path for skills:add-from-file. Concretely, in
the handler for 'skills:pick-folder' replace the current return-of-path behavior
with a call into the directory-aware entry (either invoke the IPC channel
'skills:add-from-folder' or call skillsManager.addFromFolder(<selectedPath>)
directly) and return that result, and remove any routing that expects
skills:add-from-file/skillsManager.addFromFile() to handle a directory. Ensure
the handler name 'skills:pick-folder', the file-only channel
'skills:add-from-file', and the directory import entry 'skills:add-from-folder'
/ method 'skillsManager.addFromFolder' are used as referenced above.

In `@apps/web/locales/en/settings.json`:
- Around line 322-331: Update the failure copy keys so the dialog matches the
folder-import flow: change "uploadFailedDescription" from "The skill file could
not be uploaded." to wording that references the folder import (e.g., "The skill
folder could not be imported.") and update "uploadErrorHelp" to remove/replace
"file" with "folder" and clarify YAML frontmatter expectations (e.g., "Make sure
your SKILL.md in the folder has valid YAML frontmatter with at least a ...").
Apply the same wording changes for any localized equivalents of these keys.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 58963bfc-738b-4497-811f-de55ac27f046

📥 Commits

Reviewing files that changed from the base of the PR and between 404aebf and a3bf2c1.

📒 Files selected for processing (10)
  • apps/desktop/src/main/ipc/handlers.ts
  • apps/desktop/src/preload/index.ts
  • apps/web/locales/en/settings.json
  • apps/web/locales/fr/settings.json
  • apps/web/locales/ru/settings.json
  • apps/web/locales/zh-CN/settings.json
  • apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx
  • apps/web/src/client/lib/accomplish.ts
  • packages/agent-core/src/internal/classes/SkillsManager.ts
  • packages/agent-core/tests/unit/skills/skills-manager.test.ts

@RajdeepKushwaha5 RajdeepKushwaha5 force-pushed the fix/skill-folder-import-656 branch from a3bf2c1 to 78a0ccc Compare March 12, 2026 09:14
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/main/ipc/handlers.ts (1)

1411-1413: ⚠️ Potential issue | 🔴 Critical

Fix handler to use public addSkill method instead of private addFromFile.

The handler at line 1411–1413 calls skillsManager.addFromFile(filePath), but addFromFile is a private method and cannot be invoked from the handler (TypeScript compilation error). Additionally, the preload's addSkillFromFolder sends folder paths to the skills:add-from-file channel, but addFromFile only handles single files.

Use the public addSkill(sourcePath) method instead, which properly routes based on path type:

  • Folder paths → addFromFolder (handles SKILL.md validation)
  • File paths → addFromFile
  • URLs → addFromUrl
Proposed fix
   handle('skills:add-from-file', async (_event, filePath: string) => {
-    return skillsManager.addFromFile(filePath);
+    return skillsManager.addSkill(filePath);
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/desktop/src/main/ipc/handlers.ts` around lines 1411 - 1413, The IPC
handler currently calls the private method skillsManager.addFromFile(filePath)
which causes a TypeScript error and mis-handles folder paths; change the handler
for 'skills:add-from-file' to call the public skillsManager.addSkill(sourcePath)
instead so the manager will route to addFromFolder, addFromFile, or addFromUrl
as appropriate (this also aligns with the preload's addSkillFromFolder which
sends folder paths).
♻️ Duplicate comments (1)
packages/agent-core/src/internal/classes/SkillsManager.ts (1)

259-261: 🛠️ Refactor suggestion | 🟠 Major

Add braces around single-line if statement.

As per coding guidelines, all if/else/for/while statements must use braces.

🔧 Proposed fix
     for (const entry of entries) {
-      if (!entry.isFile()) continue;
+      if (!entry.isFile()) {
+        continue;
+      }
       const srcFile = path.join(folderPath, entry.name);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agent-core/src/internal/classes/SkillsManager.ts` around lines 259 -
261, The for-loop iterating over entries in SkillsManager.ts contains a
single-line if: "if (!entry.isFile()) continue;" which must be wrapped in braces
per coding guidelines; update the loop (for (const entry of entries) { ... }) so
the check uses a block form (if (!entry.isFile()) { continue; }) before
computing srcFile/path.join(folderPath, entry.name) to comply with the brace
rule.
🧹 Nitpick comments (1)
packages/agent-core/src/internal/classes/SkillsManager.ts (1)

125-130: Missing error handling for fs.statSync.

If sourcePath doesn't exist, fs.statSync throws an exception. While this may be acceptable behavior (the error propagates), consider whether you want a more descriptive error message for the user.

💡 Optional: Add explicit existence check
+    if (!fs.existsSync(sourcePath)) {
+      throw new Error(`Path does not exist: ${sourcePath}`);
+    }
     const stat = fs.statSync(sourcePath);
     if (stat.isDirectory()) {
       return this.addFromFolder(sourcePath);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/agent-core/src/internal/classes/SkillsManager.ts` around lines 125 -
130, The call to fs.statSync(sourcePath) can throw if sourcePath does not exist;
wrap the stat check in a try/catch (or use fs.existsSync before calling
statSync) and surface a clearer, descriptive error using the SkillsManager
context (include sourcePath) instead of letting the raw exception propagate;
update the block that calls fs.statSync in SkillsManager so it either checks
existence first or catches the error and throws/logs a new Error mentioning
sourcePath and whether addFromFolder or addFromFile was intended.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/desktop/src/preload/index.ts`:
- Around line 458-460: The IPC channel name is mismatched: addSkillFromFolder
currently invokes 'skills:add-from-file' but the handler calls
skillsManager.addFromFile (wrong for folders); change the invoked channel to a
dedicated folder channel (e.g. ipcRenderer.invoke('skills:add-from-folder',
folderPath)) and add a matching handler in handlers.ts that calls
skillsManager.addSkill(folderPath) (or update the existing handler to call
skillsManager.addSkill when the channel is 'skills:add-from-folder') so folder
paths are routed to the folder-aware method instead of addFromFile.

---

Outside diff comments:
In `@apps/desktop/src/main/ipc/handlers.ts`:
- Around line 1411-1413: The IPC handler currently calls the private method
skillsManager.addFromFile(filePath) which causes a TypeScript error and
mis-handles folder paths; change the handler for 'skills:add-from-file' to call
the public skillsManager.addSkill(sourcePath) instead so the manager will route
to addFromFolder, addFromFile, or addFromUrl as appropriate (this also aligns
with the preload's addSkillFromFolder which sends folder paths).

---

Duplicate comments:
In `@packages/agent-core/src/internal/classes/SkillsManager.ts`:
- Around line 259-261: The for-loop iterating over entries in SkillsManager.ts
contains a single-line if: "if (!entry.isFile()) continue;" which must be
wrapped in braces per coding guidelines; update the loop (for (const entry of
entries) { ... }) so the check uses a block form (if (!entry.isFile()) {
continue; }) before computing srcFile/path.join(folderPath, entry.name) to
comply with the brace rule.

---

Nitpick comments:
In `@packages/agent-core/src/internal/classes/SkillsManager.ts`:
- Around line 125-130: The call to fs.statSync(sourcePath) can throw if
sourcePath does not exist; wrap the stat check in a try/catch (or use
fs.existsSync before calling statSync) and surface a clearer, descriptive error
using the SkillsManager context (include sourcePath) instead of letting the raw
exception propagate; update the block that calls fs.statSync in SkillsManager so
it either checks existence first or catches the error and throws/logs a new
Error mentioning sourcePath and whether addFromFolder or addFromFile was
intended.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 867e2037-0e16-4a3c-ad4e-79fdb009edaa

📥 Commits

Reviewing files that changed from the base of the PR and between a3bf2c1 and 78a0ccc.

📒 Files selected for processing (10)
  • apps/desktop/src/main/ipc/handlers.ts
  • apps/desktop/src/preload/index.ts
  • apps/web/locales/en/settings.json
  • apps/web/locales/fr/settings.json
  • apps/web/locales/ru/settings.json
  • apps/web/locales/zh-CN/settings.json
  • apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx
  • apps/web/src/client/lib/accomplish.ts
  • packages/agent-core/src/internal/classes/SkillsManager.ts
  • packages/agent-core/tests/unit/skills/skills-manager.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/agent-core/tests/unit/skills/skills-manager.test.ts
  • apps/web/locales/zh-CN/settings.json
  • apps/web/src/client/components/settings/skills/AddSkillDropdown.tsx
  • apps/web/src/client/lib/accomplish.ts
  • apps/web/locales/en/settings.json
  • apps/web/locales/ru/settings.json
  • apps/web/locales/fr/settings.json

When adding a local skill through Settings → Skills → Add → Upload a skill,
only the SKILL.md was copied. Any companion files bundled in the skill folder
(templates, reference data, etc.) were silently ignored, making multi-file
skills unusable after import.

This changes the import flow to select an entire folder instead of a single
file, then copies all top-level files from that folder into the user skills
directory.

Changes:
- SkillsManager.addSkill() now detects directory vs file path; new
  addFromFolder() copies SKILL.md and all sibling files
- skills:pick-file IPC handler renamed to skills:pick-folder; uses
  openDirectory so the user selects a folder, not a .md file
- Preload/AccomplishAPI updated: pickSkillFolder() + addSkillFromFolder()
- AddSkillDropdown calls pickSkillFolder() instead of pickSkillFile()
- Locale strings updated (en, zh-CN, fr, ru) to describe folder selection
- New unit tests: folder import copies all files; throws when SKILL.md absent

Fixes accomplish-ai#656
@RajdeepKushwaha5 RajdeepKushwaha5 force-pushed the fix/skill-folder-import-656 branch from 78a0ccc to 3af8d79 Compare March 17, 2026 18:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] adding a skill locally will only import skill.md file, not the whole skill

3 participants