System skills were failing to execute with the error:
SyntaxError: Unexpected identifier 'not'
This occurred because the skill execution system was trying to execute the string "File not found" as JavaScript code.
- User registers a skill in their namespace (e.g.,
ns_k0ro71
) withfileKey: "my-skill.js"
- Admin promotes the skill to system-wide availability
- System skill is stored with the original
fileKey: "my-skill.js"
(from the user's namespace) - Another user tries to execute the system skill
- Skill execution calls
handleCodeExec({ key: skill.fileKey, input: args }, authContext)
- File retrieval fails because it tries to fetch
"my-skill.js"
from the current user's namespace, not the original user's namespace where the file actually exists - Files handler returns
"File not found"
as the content - Code execution tries to execute the string
"File not found"
as JavaScript code - VM throws syntax error
SyntaxError: Unexpected identifier 'not'
because"File not found"
is not valid JavaScript
System skills store the original user's fileKey
, but when executed, they try to fetch the file from the current user's namespace instead of the original user's namespace.
Approach: When promoting a skill, copy the file content and store it in the system folder (system/skills/skillName.js
)
Benefits:
- ✅ Complete isolation from original user
- ✅ System skills work independently
- ✅ No namespace confusion
- ✅ Consistent with system-wide availability concept
- ✅ Files are accessible to all users via system folder
Trade-offs:
- File content is duplicated
- Updates require explicit admin action via
admin-update-promoted-skill
-
src/storage/skill-registry.ts
:- Updated
promoteSkillToSystem()
to accept afilesStore
parameter - Added file copying logic to copy skill file to
system/skills/skillName.js
- Updated
fileKey
in promoted skill to point to system folder - Updated
updatePromotedSkill()
to sync file content from original user - Updated
demoteSkillFromSystem()
to clean up system files
- Updated
-
src/tools/handlers/admin-tools.ts
:- Updated constructor to accept S3 client and bucket name
- Modified admin handlers to create
NamespacedFilesStore
instances - Updated promotion/demotion/update handlers to pass files store to skill registry
-
src/mcp/handler.ts
:- Updated admin handler instantiation to pass S3 client and bucket name
// Copy the skill file to system folder
systemFileKey = `system/skills/${skillName}.js`;
// Store the file content in the system folder using admin context
await filesStore.putWithSystemFolder(
systemFileKey,
originalFile.content,
originalFile.contentType || 'application/javascript',
{
originalFileKey: userSkill.fileKey,
originalNamespace: userNamespace,
promotedBy: authContext.namespace,
promotedAt: new Date().toISOString(),
skillName: skillName
},
authContext
);
const promotedSkillDefinition: SkillDefinition = {
...userSkill,
fileKey: systemFileKey, // Use the system file key instead of original
isSystemSkill: true,
promotedFrom: userNamespace,
promotedAt: now,
promotedBy: authContext.namespace,
updatedAt: now,
};
The fix has been implemented and the server compiles successfully. The system now:
- Promotes skills correctly: Copies file content to system folder during promotion
- Executes system skills reliably: Uses system folder files that are accessible to all users
- Updates promoted skills: Syncs latest content from original user to system folder
- Cleans up properly: Removes system files when skills are demoted
curl -X POST https://your-server/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-admin-key" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "admin-promote-skill", "arguments": { "userNamespace": "user123", "skillName": "my-skill" } }, "id": 1 }'
curl -X POST https://your-server/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-admin-key" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "admin-update-promoted-skill", "arguments": { "skillName": "my-skill" } }, "id": 1 }'
System skills now execute reliably without namespace-related file access issues. The file isolation ensures that promoted skills work consistently for all users, regardless of the original user's namespace or file availability.