edge-pi-cli 0.1.5 → 0.2.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/context.d.ts +2 -4
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +18 -21
- package/dist/main.js.map +1 -1
- package/dist/skills.d.ts +3 -14
- package/dist/skills.d.ts.map +1 -1
- package/dist/skills.js +10 -67
- package/dist/skills.js.map +1 -1
- package/package.json +2 -2
package/dist/context.d.ts
CHANGED
|
@@ -4,10 +4,8 @@
|
|
|
4
4
|
* Loads AGENTS.md files from the current working directory and parent
|
|
5
5
|
* directories, following the convention from the coding-agent.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
content: string;
|
|
10
|
-
}
|
|
7
|
+
import type { ContextFile } from "edge-pi";
|
|
8
|
+
export type { ContextFile };
|
|
11
9
|
/**
|
|
12
10
|
* Load AGENTS.md context files by walking up from `cwd` to the filesystem root.
|
|
13
11
|
* Files closer to the root are returned first (broadest context first).
|
package/dist/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3C,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,EAAE,CAyB3D","sourcesContent":["/**\n * Context file loading for the system prompt.\n *\n * Loads AGENTS.md files from the current working directory and parent\n * directories, following the convention from the coding-agent.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport type { ContextFile } from \"edge-pi\";\n\nexport type { ContextFile };\n\n/**\n * Load AGENTS.md context files by walking up from `cwd` to the filesystem root.\n * Files closer to the root are returned first (broadest context first).\n */\nexport function loadContextFiles(cwd: string): ContextFile[] {\n\tconst files: ContextFile[] = [];\n\tlet dir = resolve(cwd);\n\n\twhile (true) {\n\t\tconst agentsFile = join(dir, \"AGENTS.md\");\n\t\tif (existsSync(agentsFile)) {\n\t\t\ttry {\n\t\t\t\tconst content = readFileSync(agentsFile, \"utf-8\").trim();\n\t\t\t\tif (content) {\n\t\t\t\t\tfiles.push({ path: agentsFile, content });\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// skip unreadable files\n\t\t\t}\n\t\t}\n\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break; // reached root\n\t\tdir = parent;\n\t}\n\n\t// Reverse so broadest context (root) comes first\n\tfiles.reverse();\n\treturn files;\n}\n"]}
|
package/dist/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKnD;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAiB;IAC5D,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,IAAI,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAEvB,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QAC1C,IAAI,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;YAC5B,IAAI,CAAC;gBACJ,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;gBACzD,IAAI,OAAO,EAAE,CAAC;oBACb,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC3C,CAAC;YACF,CAAC;YAAC,MAAM,CAAC;gBACR,wBAAwB;YACzB,CAAC;QACF,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG;YAAE,MAAM,CAAC,eAAe;QAC1C,GAAG,GAAG,MAAM,CAAC;IACd,CAAC;IAED,iDAAiD;IACjD,KAAK,CAAC,OAAO,EAAE,CAAC;IAChB,OAAO,KAAK,CAAC;AAAA,CACb","sourcesContent":["/**\n * Context file loading for the system prompt.\n *\n * Loads AGENTS.md files from the current working directory and parent\n * directories, following the convention from the coding-agent.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\nimport type { ContextFile } from \"edge-pi\";\n\nexport type { ContextFile };\n\n/**\n * Load AGENTS.md context files by walking up from `cwd` to the filesystem root.\n * Files closer to the root are returned first (broadest context first).\n */\nexport function loadContextFiles(cwd: string): ContextFile[] {\n\tconst files: ContextFile[] = [];\n\tlet dir = resolve(cwd);\n\n\twhile (true) {\n\t\tconst agentsFile = join(dir, \"AGENTS.md\");\n\t\tif (existsSync(agentsFile)) {\n\t\t\ttry {\n\t\t\t\tconst content = readFileSync(agentsFile, \"utf-8\").trim();\n\t\t\t\tif (content) {\n\t\t\t\t\tfiles.push({ path: agentsFile, content });\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// skip unreadable files\n\t\t\t}\n\t\t}\n\n\t\tconst parent = dirname(dir);\n\t\tif (parent === dir) break; // reached root\n\t\tdir = parent;\n\t}\n\n\t// Reverse so broadest context (root) comes first\n\tfiles.reverse();\n\treturn files;\n}\n"]}
|
package/dist/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA+HH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAoMxC","sourcesContent":["/**\n * Main entry point for the edge-pi CLI.\n *\n * Handles argument parsing, model creation, skill loading,\n * session management, auth, and mode dispatch.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport type { CodingAgentConfig } from \"edge-pi\";\nimport { CodingAgent, SessionManager } from \"edge-pi\";\nimport {\n\tAuthStorage,\n\tanthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\topenaiCodexOAuthProvider,\n} from \"./auth/index.js\";\nimport { parseArgs, printHelp, printModels } from \"./cli/args.js\";\nimport { loadContextFiles } from \"./context.js\";\nimport { createModel } from \"./model-factory.js\";\nimport { runInteractiveMode } from \"./modes/interactive-mode.js\";\nimport { runPrintMode } from \"./modes/print-mode.js\";\nimport { loadPrompts } from \"./prompts.js\";\nimport { buildProviderOptions } from \"./provider-options.js\";\nimport { SettingsManager } from \"./settings.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport { findFd } from \"./utils/find-fd.js\";\n\nconst VERSION = \"0.1.0\";\nconst CONFIG_DIR_NAME = \".pi\";\n\nfunction getAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\nfunction getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY.\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\n/**\n * Process @file arguments into text content.\n */\nfunction processFileArgs(fileArgs: string[]): string {\n\tconst parts: string[] = [];\n\tfor (const filePath of fileArgs) {\n\t\tconst resolved = resolve(filePath);\n\t\tif (!existsSync(resolved)) {\n\t\t\tconsole.error(chalk.yellow(`Warning: File not found: ${resolved}`));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(resolved, \"utf-8\");\n\t\t\tparts.push(`<file path=\"${resolved}\">\\n${content}\\n</file>`);\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${resolved}: ${(error as Error).message}`));\n\t\t}\n\t}\n\treturn parts.length > 0 ? `${parts.join(\"\\n\\n\")}\\n\\n` : \"\";\n}\n\n/**\n * Create a session directory path based on the current working directory.\n */\nfunction getProjectSessionDir(cwd: string): string {\n\tconst sanitized = cwd.replace(/\\//g, \"--\").replace(/^--/, \"\");\n\treturn join(getSessionsDir(), sanitized);\n}\n\n/**\n * Find the most recent session file in a directory.\n */\nfunction findRecentSession(sessionDir: string): string | undefined {\n\tif (!existsSync(sessionDir)) return undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((f: string) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f: string) => ({\n\t\t\t\tname: f,\n\t\t\t\tpath: join(sessionDir, f),\n\t\t\t\tmtime: statSync(join(sessionDir, f)).mtime.getTime(),\n\t\t\t}))\n\t\t\t.sort((a: { mtime: number }, b: { mtime: number }) => b.mtime - a.mtime);\n\t\treturn files[0]?.path;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create and configure AuthStorage with built-in OAuth providers.\n */\nfunction createAuthStorage(): AuthStorage {\n\tconst authStorage = new AuthStorage(getAuthPath());\n\tauthStorage.registerProvider(anthropicOAuthProvider);\n\tauthStorage.registerProvider(githubCopilotOAuthProvider);\n\tauthStorage.registerProvider(openaiCodexOAuthProvider);\n\treturn authStorage;\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels) {\n\t\tprintModels();\n\t\treturn;\n\t}\n\n\t// Read piped stdin\n\tconst stdinContent = await readPipedStdin();\n\tif (stdinContent !== undefined) {\n\t\tparsed.print = true;\n\t\tparsed.messages.unshift(stdinContent);\n\t}\n\n\t// Process @file arguments\n\tlet initialMessage: string | undefined;\n\tif (parsed.fileArgs.length > 0) {\n\t\tconst fileContent = processFileArgs(parsed.fileArgs);\n\t\tif (parsed.messages.length > 0) {\n\t\t\tinitialMessage = fileContent + parsed.messages.shift();\n\t\t} else {\n\t\t\tinitialMessage = fileContent;\n\t\t}\n\t}\n\n\tconst cwd = process.cwd();\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\t// Set up auth storage\n\tconst authStorage = createAuthStorage();\n\n\t// Set up settings persistence\n\tconst settingsManager = SettingsManager.create(getAgentDir());\n\n\t// Apply CLI --api-key override\n\tif (parsed.apiKey && parsed.provider) {\n\t\tauthStorage.setRuntimeApiKey(parsed.provider, parsed.apiKey);\n\t}\n\n\t// Create model (async - may resolve OAuth tokens)\n\t// Fall back to saved defaults when CLI args are not specified\n\tconst { model, provider, modelId } = await createModel({\n\t\tprovider: parsed.provider ?? settingsManager.getDefaultProvider(),\n\t\tmodel: parsed.model ?? settingsManager.getDefaultModel(),\n\t\tapiKey: parsed.apiKey,\n\t\tauthStorage,\n\t});\n\n\t// Load skills\n\tlet skills: Skill[] = [];\n\tif (!parsed.noSkills) {\n\t\tconst skillResult = loadSkills({\n\t\t\tcwd,\n\t\t\tskillPaths: parsed.skills,\n\t\t\tincludeDefaults: true,\n\t\t});\n\t\tskills = skillResult.skills;\n\n\t\tif (parsed.verbose && skillResult.diagnostics.length > 0) {\n\t\t\tfor (const d of skillResult.diagnostics) {\n\t\t\t\tconsole.error(chalk.yellow(`Skill warning: ${d.message} (${d.path})`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load context files (AGENTS.md)\n\tconst contextFiles = loadContextFiles(cwd);\n\tif (parsed.verbose && contextFiles.length > 0) {\n\t\tconsole.log(chalk.dim(`Loaded ${contextFiles.length} context file(s).`));\n\t}\n\n\t// Load prompt templates\n\tconst promptsResult = loadPrompts({ cwd });\n\tconst prompts = promptsResult.prompts;\n\tif (parsed.verbose && promptsResult.diagnostics.length > 0) {\n\t\tfor (const d of promptsResult.diagnostics) {\n\t\t\tconsole.error(chalk.yellow(`Prompt warning: ${d.message} (${d.path})`));\n\t\t}\n\t}\n\n\t// Find fd binary for @ file autocomplete\n\tconst fdPath = findFd();\n\n\t// Build system prompt additions\n\tconst skillsPrompt = formatSkillsForPrompt(skills);\n\tconst appendParts: string[] = [];\n\tif (skillsPrompt) {\n\t\tappendParts.push(skillsPrompt);\n\t}\n\tif (parsed.appendSystemPrompt) {\n\t\tappendParts.push(parsed.appendSystemPrompt);\n\t}\n\tconst appendSystemPrompt = appendParts.length > 0 ? appendParts.join(\"\\n\\n\") : undefined;\n\n\t// Set up session manager\n\tconst sessionDir = parsed.sessionDir ?? getProjectSessionDir(cwd);\n\tlet sessionManager: SessionManager | undefined;\n\tif (parsed.noSession) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else if (parsed.session) {\n\t\tsessionManager = SessionManager.open(parsed.session, parsed.sessionDir);\n\t} else if (parsed.resume) {\n\t\t// Start a new session; the TUI will show the session picker on startup\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t} else if (parsed.continue) {\n\t\tconst recentFile = findRecentSession(sessionDir);\n\t\tif (recentFile) {\n\t\t\tsessionManager = SessionManager.open(recentFile, sessionDir);\n\t\t} else {\n\t\t\tif (parsed.verbose) {\n\t\t\t\tconsole.log(chalk.dim(\"No previous session found, starting new.\"));\n\t\t\t}\n\t\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t\t}\n\t} else {\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t}\n\n\t// Create agent config\n\tconst agentConfig: CodingAgentConfig = {\n\t\tmodel,\n\t\tcwd,\n\t\ttoolSet: parsed.toolSet ?? \"coding\",\n\t\tproviderOptions: buildProviderOptions(provider, parsed.thinking),\n\t\tsessionManager,\n\t};\n\n\tif (parsed.systemPrompt) {\n\t\tagentConfig.systemPrompt = parsed.systemPrompt;\n\t\tif (appendSystemPrompt) {\n\t\t\tagentConfig.systemPrompt += `\\n\\n${appendSystemPrompt}`;\n\t\t}\n\t} else {\n\t\tagentConfig.systemPromptOptions = {\n\t\t\tappendSystemPrompt,\n\t\t\tcontextFiles,\n\t\t};\n\t}\n\n\t// Create agent (session messages are auto-restored from sessionManager)\n\tconst agent = new CodingAgent(agentConfig);\n\n\tif (parsed.verbose && agent.messages.length > 0) {\n\t\tconsole.log(chalk.dim(`Restored ${agent.messages.length} messages from session.`));\n\t}\n\n\t// Dispatch to mode\n\tif (isInteractive) {\n\t\tawait runInteractiveMode(agent, {\n\t\t\tinitialMessage,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tsessionDir,\n\t\t\tagentConfig,\n\t\t\tresumeOnStart: parsed.resume,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tprompts,\n\t\t\tverbose: parsed.verbose,\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t\tauthStorage,\n\t\t\tsettingsManager,\n\t\t\tfdPath,\n\t\t\tonModelChange: async (newProvider: string, newModelId: string) => {\n\t\t\t\tconst { model: newModel } = await createModel({\n\t\t\t\t\tprovider: newProvider,\n\t\t\t\t\tmodel: newModelId,\n\t\t\t\t\tauthStorage,\n\t\t\t\t});\n\t\t\t\treturn new CodingAgent({\n\t\t\t\t\t...agentConfig,\n\t\t\t\t\tmodel: newModel,\n\t\t\t\t\tproviderOptions: buildProviderOptions(newProvider, parsed.thinking),\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t} else {\n\t\tawait runPrintMode(agent, {\n\t\t\tmode,\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t});\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA2IH,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,iBAsLxC","sourcesContent":["/**\n * Main entry point for the edge-pi CLI.\n *\n * Handles argument parsing, model creation, skill loading,\n * session management, auth, and mode dispatch.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport type { CodingAgentConfig, Skill as PromptSkill } from \"edge-pi\";\nimport { CodingAgent, SessionManager } from \"edge-pi\";\nimport {\n\tAuthStorage,\n\tanthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\topenaiCodexOAuthProvider,\n} from \"./auth/index.js\";\nimport { parseArgs, printHelp, printModels } from \"./cli/args.js\";\nimport { loadContextFiles } from \"./context.js\";\nimport { createModel } from \"./model-factory.js\";\nimport { runInteractiveMode } from \"./modes/interactive-mode.js\";\nimport { runPrintMode } from \"./modes/print-mode.js\";\nimport { loadPrompts } from \"./prompts.js\";\nimport { buildProviderOptions } from \"./provider-options.js\";\nimport { SettingsManager } from \"./settings.js\";\nimport { loadSkills, type Skill } from \"./skills.js\";\nimport { findFd } from \"./utils/find-fd.js\";\n\nconst VERSION = \"0.1.0\";\nconst CONFIG_DIR_NAME = \".pi\";\n\nfunction getAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\nfunction getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY.\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\n/**\n * Process @file arguments into text content.\n */\nfunction processFileArgs(fileArgs: string[]): string {\n\tconst parts: string[] = [];\n\tfor (const filePath of fileArgs) {\n\t\tconst resolved = resolve(filePath);\n\t\tif (!existsSync(resolved)) {\n\t\t\tconsole.error(chalk.yellow(`Warning: File not found: ${resolved}`));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(resolved, \"utf-8\");\n\t\t\tparts.push(`<file path=\"${resolved}\">\\n${content}\\n</file>`);\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${resolved}: ${(error as Error).message}`));\n\t\t}\n\t}\n\treturn parts.length > 0 ? `${parts.join(\"\\n\\n\")}\\n\\n` : \"\";\n}\n\n/**\n * Create a session directory path based on the current working directory.\n */\nfunction getProjectSessionDir(cwd: string): string {\n\tconst sanitized = cwd.replace(/\\//g, \"--\").replace(/^--/, \"\");\n\treturn join(getSessionsDir(), sanitized);\n}\n\n/**\n * Find the most recent session file in a directory.\n */\nfunction findRecentSession(sessionDir: string): string | undefined {\n\tif (!existsSync(sessionDir)) return undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((f: string) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f: string) => ({\n\t\t\t\tname: f,\n\t\t\t\tpath: join(sessionDir, f),\n\t\t\t\tmtime: statSync(join(sessionDir, f)).mtime.getTime(),\n\t\t\t}))\n\t\t\t.sort((a: { mtime: number }, b: { mtime: number }) => b.mtime - a.mtime);\n\t\treturn files[0]?.path;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create and configure AuthStorage with built-in OAuth providers.\n */\nfunction createAuthStorage(): AuthStorage {\n\tconst authStorage = new AuthStorage(getAuthPath());\n\tauthStorage.registerProvider(anthropicOAuthProvider);\n\tauthStorage.registerProvider(githubCopilotOAuthProvider);\n\tauthStorage.registerProvider(openaiCodexOAuthProvider);\n\treturn authStorage;\n}\n\nfunction toSkillMap(skills: Skill[]): Record<string, PromptSkill> {\n\tconst map: Record<string, PromptSkill> = {};\n\tfor (const skill of skills) {\n\t\tmap[skill.name] = {\n\t\t\tdescription: skill.description,\n\t\t\tfilePath: skill.filePath,\n\t\t\tdisableModelInvocation: skill.disableModelInvocation,\n\t\t};\n\t}\n\treturn map;\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels) {\n\t\tprintModels();\n\t\treturn;\n\t}\n\n\t// Read piped stdin\n\tconst stdinContent = await readPipedStdin();\n\tif (stdinContent !== undefined) {\n\t\tparsed.print = true;\n\t\tparsed.messages.unshift(stdinContent);\n\t}\n\n\t// Process @file arguments\n\tlet initialMessage: string | undefined;\n\tif (parsed.fileArgs.length > 0) {\n\t\tconst fileContent = processFileArgs(parsed.fileArgs);\n\t\tif (parsed.messages.length > 0) {\n\t\t\tinitialMessage = fileContent + parsed.messages.shift();\n\t\t} else {\n\t\t\tinitialMessage = fileContent;\n\t\t}\n\t}\n\n\tconst cwd = process.cwd();\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\t// Set up auth storage\n\tconst authStorage = createAuthStorage();\n\n\t// Set up settings persistence\n\tconst settingsManager = SettingsManager.create(getAgentDir());\n\n\t// Apply CLI --api-key override\n\tif (parsed.apiKey && parsed.provider) {\n\t\tauthStorage.setRuntimeApiKey(parsed.provider, parsed.apiKey);\n\t}\n\n\t// Create model (async - may resolve OAuth tokens)\n\t// Fall back to saved defaults when CLI args are not specified\n\tconst { model, provider, modelId } = await createModel({\n\t\tprovider: parsed.provider ?? settingsManager.getDefaultProvider(),\n\t\tmodel: parsed.model ?? settingsManager.getDefaultModel(),\n\t\tapiKey: parsed.apiKey,\n\t\tauthStorage,\n\t});\n\n\t// Load skills\n\tlet skills: Skill[] = [];\n\tif (!parsed.noSkills) {\n\t\tconst skillResult = loadSkills({\n\t\t\tcwd,\n\t\t\tskillPaths: parsed.skills,\n\t\t\tincludeDefaults: true,\n\t\t});\n\t\tskills = skillResult.skills;\n\n\t\tif (parsed.verbose && skillResult.diagnostics.length > 0) {\n\t\t\tfor (const d of skillResult.diagnostics) {\n\t\t\t\tconsole.error(chalk.yellow(`Skill warning: ${d.message} (${d.path})`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load context files (AGENTS.md)\n\tconst contextFiles = loadContextFiles(cwd);\n\tif (parsed.verbose && contextFiles.length > 0) {\n\t\tconsole.log(chalk.dim(`Loaded ${contextFiles.length} context file(s).`));\n\t}\n\n\t// Load prompt templates\n\tconst promptsResult = loadPrompts({ cwd });\n\tconst prompts = promptsResult.prompts;\n\tif (parsed.verbose && promptsResult.diagnostics.length > 0) {\n\t\tfor (const d of promptsResult.diagnostics) {\n\t\t\tconsole.error(chalk.yellow(`Prompt warning: ${d.message} (${d.path})`));\n\t\t}\n\t}\n\n\t// Find fd binary for @ file autocomplete\n\tconst fdPath = findFd();\n\n\t// Set up session manager\n\tconst sessionDir = parsed.sessionDir ?? getProjectSessionDir(cwd);\n\tlet sessionManager: SessionManager | undefined;\n\tif (parsed.noSession) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else if (parsed.session) {\n\t\tsessionManager = SessionManager.open(parsed.session, parsed.sessionDir);\n\t} else if (parsed.resume) {\n\t\t// Start a new session; the TUI will show the session picker on startup\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t} else if (parsed.continue) {\n\t\tconst recentFile = findRecentSession(sessionDir);\n\t\tif (recentFile) {\n\t\t\tsessionManager = SessionManager.open(recentFile, sessionDir);\n\t\t} else {\n\t\t\tif (parsed.verbose) {\n\t\t\t\tconsole.log(chalk.dim(\"No previous session found, starting new.\"));\n\t\t\t}\n\t\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t\t}\n\t} else {\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t}\n\n\t// Create agent config\n\tconst agentConfig: CodingAgentConfig = {\n\t\tmodel,\n\t\tcwd,\n\t\ttoolSet: parsed.toolSet ?? \"coding\",\n\t\tproviderOptions: buildProviderOptions(provider, parsed.thinking),\n\t\tsessionManager,\n\t};\n\n\tagentConfig.systemPromptOptions = {\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tcontextFiles,\n\t\tskills: toSkillMap(skills),\n\t};\n\tif (parsed.systemPrompt) {\n\t\tagentConfig.systemPromptOptions.customPrompt = parsed.systemPrompt;\n\t}\n\n\t// Create agent (session messages are auto-restored from sessionManager)\n\tconst agent = new CodingAgent(agentConfig);\n\n\tif (parsed.verbose && agent.messages.length > 0) {\n\t\tconsole.log(chalk.dim(`Restored ${agent.messages.length} messages from session.`));\n\t}\n\n\t// Dispatch to mode\n\tif (isInteractive) {\n\t\tawait runInteractiveMode(agent, {\n\t\t\tinitialMessage,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tsessionDir,\n\t\t\tagentConfig,\n\t\t\tresumeOnStart: parsed.resume,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tprompts,\n\t\t\tverbose: parsed.verbose,\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t\tauthStorage,\n\t\t\tsettingsManager,\n\t\t\tfdPath,\n\t\t\tonModelChange: async (newProvider: string, newModelId: string) => {\n\t\t\t\tconst { model: newModel } = await createModel({\n\t\t\t\t\tprovider: newProvider,\n\t\t\t\t\tmodel: newModelId,\n\t\t\t\t\tauthStorage,\n\t\t\t\t});\n\t\t\t\treturn new CodingAgent({\n\t\t\t\t\t...agentConfig,\n\t\t\t\t\tmodel: newModel,\n\t\t\t\t\tproviderOptions: buildProviderOptions(newProvider, parsed.thinking),\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t} else {\n\t\tawait runPrintMode(agent, {\n\t\t\tmode,\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t});\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
package/dist/main.js
CHANGED
|
@@ -18,7 +18,7 @@ import { runPrintMode } from "./modes/print-mode.js";
|
|
|
18
18
|
import { loadPrompts } from "./prompts.js";
|
|
19
19
|
import { buildProviderOptions } from "./provider-options.js";
|
|
20
20
|
import { SettingsManager } from "./settings.js";
|
|
21
|
-
import {
|
|
21
|
+
import { loadSkills } from "./skills.js";
|
|
22
22
|
import { findFd } from "./utils/find-fd.js";
|
|
23
23
|
const VERSION = "0.1.0";
|
|
24
24
|
const CONFIG_DIR_NAME = ".pi";
|
|
@@ -118,6 +118,17 @@ function createAuthStorage() {
|
|
|
118
118
|
authStorage.registerProvider(openaiCodexOAuthProvider);
|
|
119
119
|
return authStorage;
|
|
120
120
|
}
|
|
121
|
+
function toSkillMap(skills) {
|
|
122
|
+
const map = {};
|
|
123
|
+
for (const skill of skills) {
|
|
124
|
+
map[skill.name] = {
|
|
125
|
+
description: skill.description,
|
|
126
|
+
filePath: skill.filePath,
|
|
127
|
+
disableModelInvocation: skill.disableModelInvocation,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return map;
|
|
131
|
+
}
|
|
121
132
|
export async function main(args) {
|
|
122
133
|
const parsed = parseArgs(args);
|
|
123
134
|
if (parsed.version) {
|
|
@@ -198,16 +209,6 @@ export async function main(args) {
|
|
|
198
209
|
}
|
|
199
210
|
// Find fd binary for @ file autocomplete
|
|
200
211
|
const fdPath = findFd();
|
|
201
|
-
// Build system prompt additions
|
|
202
|
-
const skillsPrompt = formatSkillsForPrompt(skills);
|
|
203
|
-
const appendParts = [];
|
|
204
|
-
if (skillsPrompt) {
|
|
205
|
-
appendParts.push(skillsPrompt);
|
|
206
|
-
}
|
|
207
|
-
if (parsed.appendSystemPrompt) {
|
|
208
|
-
appendParts.push(parsed.appendSystemPrompt);
|
|
209
|
-
}
|
|
210
|
-
const appendSystemPrompt = appendParts.length > 0 ? appendParts.join("\n\n") : undefined;
|
|
211
212
|
// Set up session manager
|
|
212
213
|
const sessionDir = parsed.sessionDir ?? getProjectSessionDir(cwd);
|
|
213
214
|
let sessionManager;
|
|
@@ -244,17 +245,13 @@ export async function main(args) {
|
|
|
244
245
|
providerOptions: buildProviderOptions(provider, parsed.thinking),
|
|
245
246
|
sessionManager,
|
|
246
247
|
};
|
|
248
|
+
agentConfig.systemPromptOptions = {
|
|
249
|
+
appendSystemPrompt: parsed.appendSystemPrompt,
|
|
250
|
+
contextFiles,
|
|
251
|
+
skills: toSkillMap(skills),
|
|
252
|
+
};
|
|
247
253
|
if (parsed.systemPrompt) {
|
|
248
|
-
agentConfig.
|
|
249
|
-
if (appendSystemPrompt) {
|
|
250
|
-
agentConfig.systemPrompt += `\n\n${appendSystemPrompt}`;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
agentConfig.systemPromptOptions = {
|
|
255
|
-
appendSystemPrompt,
|
|
256
|
-
contextFiles,
|
|
257
|
-
};
|
|
254
|
+
agentConfig.systemPromptOptions.customPrompt = parsed.systemPrompt;
|
|
258
255
|
}
|
|
259
256
|
// Create agent (session messages are auto-restored from sessionManager)
|
|
260
257
|
const agent = new CodingAgent(agentConfig);
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main entry point for the edge-pi CLI.\n *\n * Handles argument parsing, model creation, skill loading,\n * session management, auth, and mode dispatch.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport type { CodingAgentConfig } from \"edge-pi\";\nimport { CodingAgent, SessionManager } from \"edge-pi\";\nimport {\n\tAuthStorage,\n\tanthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\topenaiCodexOAuthProvider,\n} from \"./auth/index.js\";\nimport { parseArgs, printHelp, printModels } from \"./cli/args.js\";\nimport { loadContextFiles } from \"./context.js\";\nimport { createModel } from \"./model-factory.js\";\nimport { runInteractiveMode } from \"./modes/interactive-mode.js\";\nimport { runPrintMode } from \"./modes/print-mode.js\";\nimport { loadPrompts } from \"./prompts.js\";\nimport { buildProviderOptions } from \"./provider-options.js\";\nimport { SettingsManager } from \"./settings.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport { findFd } from \"./utils/find-fd.js\";\n\nconst VERSION = \"0.1.0\";\nconst CONFIG_DIR_NAME = \".pi\";\n\nfunction getAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\nfunction getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY.\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\n/**\n * Process @file arguments into text content.\n */\nfunction processFileArgs(fileArgs: string[]): string {\n\tconst parts: string[] = [];\n\tfor (const filePath of fileArgs) {\n\t\tconst resolved = resolve(filePath);\n\t\tif (!existsSync(resolved)) {\n\t\t\tconsole.error(chalk.yellow(`Warning: File not found: ${resolved}`));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(resolved, \"utf-8\");\n\t\t\tparts.push(`<file path=\"${resolved}\">\\n${content}\\n</file>`);\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${resolved}: ${(error as Error).message}`));\n\t\t}\n\t}\n\treturn parts.length > 0 ? `${parts.join(\"\\n\\n\")}\\n\\n` : \"\";\n}\n\n/**\n * Create a session directory path based on the current working directory.\n */\nfunction getProjectSessionDir(cwd: string): string {\n\tconst sanitized = cwd.replace(/\\//g, \"--\").replace(/^--/, \"\");\n\treturn join(getSessionsDir(), sanitized);\n}\n\n/**\n * Find the most recent session file in a directory.\n */\nfunction findRecentSession(sessionDir: string): string | undefined {\n\tif (!existsSync(sessionDir)) return undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((f: string) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f: string) => ({\n\t\t\t\tname: f,\n\t\t\t\tpath: join(sessionDir, f),\n\t\t\t\tmtime: statSync(join(sessionDir, f)).mtime.getTime(),\n\t\t\t}))\n\t\t\t.sort((a: { mtime: number }, b: { mtime: number }) => b.mtime - a.mtime);\n\t\treturn files[0]?.path;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create and configure AuthStorage with built-in OAuth providers.\n */\nfunction createAuthStorage(): AuthStorage {\n\tconst authStorage = new AuthStorage(getAuthPath());\n\tauthStorage.registerProvider(anthropicOAuthProvider);\n\tauthStorage.registerProvider(githubCopilotOAuthProvider);\n\tauthStorage.registerProvider(openaiCodexOAuthProvider);\n\treturn authStorage;\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels) {\n\t\tprintModels();\n\t\treturn;\n\t}\n\n\t// Read piped stdin\n\tconst stdinContent = await readPipedStdin();\n\tif (stdinContent !== undefined) {\n\t\tparsed.print = true;\n\t\tparsed.messages.unshift(stdinContent);\n\t}\n\n\t// Process @file arguments\n\tlet initialMessage: string | undefined;\n\tif (parsed.fileArgs.length > 0) {\n\t\tconst fileContent = processFileArgs(parsed.fileArgs);\n\t\tif (parsed.messages.length > 0) {\n\t\t\tinitialMessage = fileContent + parsed.messages.shift();\n\t\t} else {\n\t\t\tinitialMessage = fileContent;\n\t\t}\n\t}\n\n\tconst cwd = process.cwd();\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\t// Set up auth storage\n\tconst authStorage = createAuthStorage();\n\n\t// Set up settings persistence\n\tconst settingsManager = SettingsManager.create(getAgentDir());\n\n\t// Apply CLI --api-key override\n\tif (parsed.apiKey && parsed.provider) {\n\t\tauthStorage.setRuntimeApiKey(parsed.provider, parsed.apiKey);\n\t}\n\n\t// Create model (async - may resolve OAuth tokens)\n\t// Fall back to saved defaults when CLI args are not specified\n\tconst { model, provider, modelId } = await createModel({\n\t\tprovider: parsed.provider ?? settingsManager.getDefaultProvider(),\n\t\tmodel: parsed.model ?? settingsManager.getDefaultModel(),\n\t\tapiKey: parsed.apiKey,\n\t\tauthStorage,\n\t});\n\n\t// Load skills\n\tlet skills: Skill[] = [];\n\tif (!parsed.noSkills) {\n\t\tconst skillResult = loadSkills({\n\t\t\tcwd,\n\t\t\tskillPaths: parsed.skills,\n\t\t\tincludeDefaults: true,\n\t\t});\n\t\tskills = skillResult.skills;\n\n\t\tif (parsed.verbose && skillResult.diagnostics.length > 0) {\n\t\t\tfor (const d of skillResult.diagnostics) {\n\t\t\t\tconsole.error(chalk.yellow(`Skill warning: ${d.message} (${d.path})`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load context files (AGENTS.md)\n\tconst contextFiles = loadContextFiles(cwd);\n\tif (parsed.verbose && contextFiles.length > 0) {\n\t\tconsole.log(chalk.dim(`Loaded ${contextFiles.length} context file(s).`));\n\t}\n\n\t// Load prompt templates\n\tconst promptsResult = loadPrompts({ cwd });\n\tconst prompts = promptsResult.prompts;\n\tif (parsed.verbose && promptsResult.diagnostics.length > 0) {\n\t\tfor (const d of promptsResult.diagnostics) {\n\t\t\tconsole.error(chalk.yellow(`Prompt warning: ${d.message} (${d.path})`));\n\t\t}\n\t}\n\n\t// Find fd binary for @ file autocomplete\n\tconst fdPath = findFd();\n\n\t// Build system prompt additions\n\tconst skillsPrompt = formatSkillsForPrompt(skills);\n\tconst appendParts: string[] = [];\n\tif (skillsPrompt) {\n\t\tappendParts.push(skillsPrompt);\n\t}\n\tif (parsed.appendSystemPrompt) {\n\t\tappendParts.push(parsed.appendSystemPrompt);\n\t}\n\tconst appendSystemPrompt = appendParts.length > 0 ? appendParts.join(\"\\n\\n\") : undefined;\n\n\t// Set up session manager\n\tconst sessionDir = parsed.sessionDir ?? getProjectSessionDir(cwd);\n\tlet sessionManager: SessionManager | undefined;\n\tif (parsed.noSession) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else if (parsed.session) {\n\t\tsessionManager = SessionManager.open(parsed.session, parsed.sessionDir);\n\t} else if (parsed.resume) {\n\t\t// Start a new session; the TUI will show the session picker on startup\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t} else if (parsed.continue) {\n\t\tconst recentFile = findRecentSession(sessionDir);\n\t\tif (recentFile) {\n\t\t\tsessionManager = SessionManager.open(recentFile, sessionDir);\n\t\t} else {\n\t\t\tif (parsed.verbose) {\n\t\t\t\tconsole.log(chalk.dim(\"No previous session found, starting new.\"));\n\t\t\t}\n\t\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t\t}\n\t} else {\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t}\n\n\t// Create agent config\n\tconst agentConfig: CodingAgentConfig = {\n\t\tmodel,\n\t\tcwd,\n\t\ttoolSet: parsed.toolSet ?? \"coding\",\n\t\tproviderOptions: buildProviderOptions(provider, parsed.thinking),\n\t\tsessionManager,\n\t};\n\n\tif (parsed.systemPrompt) {\n\t\tagentConfig.systemPrompt = parsed.systemPrompt;\n\t\tif (appendSystemPrompt) {\n\t\t\tagentConfig.systemPrompt += `\\n\\n${appendSystemPrompt}`;\n\t\t}\n\t} else {\n\t\tagentConfig.systemPromptOptions = {\n\t\t\tappendSystemPrompt,\n\t\t\tcontextFiles,\n\t\t};\n\t}\n\n\t// Create agent (session messages are auto-restored from sessionManager)\n\tconst agent = new CodingAgent(agentConfig);\n\n\tif (parsed.verbose && agent.messages.length > 0) {\n\t\tconsole.log(chalk.dim(`Restored ${agent.messages.length} messages from session.`));\n\t}\n\n\t// Dispatch to mode\n\tif (isInteractive) {\n\t\tawait runInteractiveMode(agent, {\n\t\t\tinitialMessage,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tsessionDir,\n\t\t\tagentConfig,\n\t\t\tresumeOnStart: parsed.resume,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tprompts,\n\t\t\tverbose: parsed.verbose,\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t\tauthStorage,\n\t\t\tsettingsManager,\n\t\t\tfdPath,\n\t\t\tonModelChange: async (newProvider: string, newModelId: string) => {\n\t\t\t\tconst { model: newModel } = await createModel({\n\t\t\t\t\tprovider: newProvider,\n\t\t\t\t\tmodel: newModelId,\n\t\t\t\t\tauthStorage,\n\t\t\t\t});\n\t\t\t\treturn new CodingAgent({\n\t\t\t\t\t...agentConfig,\n\t\t\t\t\tmodel: newModel,\n\t\t\t\t\tproviderOptions: buildProviderOptions(newProvider, parsed.thinking),\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t} else {\n\t\tawait runPrintMode(agent, {\n\t\t\tmode,\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t});\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Main entry point for the edge-pi CLI.\n *\n * Handles argument parsing, model creation, skill loading,\n * session management, auth, and mode dispatch.\n */\n\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport chalk from \"chalk\";\nimport type { CodingAgentConfig, Skill as PromptSkill } from \"edge-pi\";\nimport { CodingAgent, SessionManager } from \"edge-pi\";\nimport {\n\tAuthStorage,\n\tanthropicOAuthProvider,\n\tgithubCopilotOAuthProvider,\n\topenaiCodexOAuthProvider,\n} from \"./auth/index.js\";\nimport { parseArgs, printHelp, printModels } from \"./cli/args.js\";\nimport { loadContextFiles } from \"./context.js\";\nimport { createModel } from \"./model-factory.js\";\nimport { runInteractiveMode } from \"./modes/interactive-mode.js\";\nimport { runPrintMode } from \"./modes/print-mode.js\";\nimport { loadPrompts } from \"./prompts.js\";\nimport { buildProviderOptions } from \"./provider-options.js\";\nimport { SettingsManager } from \"./settings.js\";\nimport { loadSkills, type Skill } from \"./skills.js\";\nimport { findFd } from \"./utils/find-fd.js\";\n\nconst VERSION = \"0.1.0\";\nconst CONFIG_DIR_NAME = \".pi\";\n\nfunction getAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction getSessionsDir(): string {\n\treturn join(getAgentDir(), \"sessions\");\n}\n\nfunction getAuthPath(): string {\n\treturn join(getAgentDir(), \"auth.json\");\n}\n\n/**\n * Read all content from piped stdin.\n * Returns undefined if stdin is a TTY.\n */\nasync function readPipedStdin(): Promise<string | undefined> {\n\tif (process.stdin.isTTY) {\n\t\treturn undefined;\n\t}\n\treturn new Promise((resolve) => {\n\t\tlet data = \"\";\n\t\tprocess.stdin.setEncoding(\"utf8\");\n\t\tprocess.stdin.on(\"data\", (chunk) => {\n\t\t\tdata += chunk;\n\t\t});\n\t\tprocess.stdin.on(\"end\", () => {\n\t\t\tresolve(data.trim() || undefined);\n\t\t});\n\t\tprocess.stdin.resume();\n\t});\n}\n\n/**\n * Process @file arguments into text content.\n */\nfunction processFileArgs(fileArgs: string[]): string {\n\tconst parts: string[] = [];\n\tfor (const filePath of fileArgs) {\n\t\tconst resolved = resolve(filePath);\n\t\tif (!existsSync(resolved)) {\n\t\t\tconsole.error(chalk.yellow(`Warning: File not found: ${resolved}`));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst content = readFileSync(resolved, \"utf-8\");\n\t\t\tparts.push(`<file path=\"${resolved}\">\\n${content}\\n</file>`);\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${resolved}: ${(error as Error).message}`));\n\t\t}\n\t}\n\treturn parts.length > 0 ? `${parts.join(\"\\n\\n\")}\\n\\n` : \"\";\n}\n\n/**\n * Create a session directory path based on the current working directory.\n */\nfunction getProjectSessionDir(cwd: string): string {\n\tconst sanitized = cwd.replace(/\\//g, \"--\").replace(/^--/, \"\");\n\treturn join(getSessionsDir(), sanitized);\n}\n\n/**\n * Find the most recent session file in a directory.\n */\nfunction findRecentSession(sessionDir: string): string | undefined {\n\tif (!existsSync(sessionDir)) return undefined;\n\ttry {\n\t\tconst files = readdirSync(sessionDir)\n\t\t\t.filter((f: string) => f.endsWith(\".jsonl\"))\n\t\t\t.map((f: string) => ({\n\t\t\t\tname: f,\n\t\t\t\tpath: join(sessionDir, f),\n\t\t\t\tmtime: statSync(join(sessionDir, f)).mtime.getTime(),\n\t\t\t}))\n\t\t\t.sort((a: { mtime: number }, b: { mtime: number }) => b.mtime - a.mtime);\n\t\treturn files[0]?.path;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\n/**\n * Create and configure AuthStorage with built-in OAuth providers.\n */\nfunction createAuthStorage(): AuthStorage {\n\tconst authStorage = new AuthStorage(getAuthPath());\n\tauthStorage.registerProvider(anthropicOAuthProvider);\n\tauthStorage.registerProvider(githubCopilotOAuthProvider);\n\tauthStorage.registerProvider(openaiCodexOAuthProvider);\n\treturn authStorage;\n}\n\nfunction toSkillMap(skills: Skill[]): Record<string, PromptSkill> {\n\tconst map: Record<string, PromptSkill> = {};\n\tfor (const skill of skills) {\n\t\tmap[skill.name] = {\n\t\t\tdescription: skill.description,\n\t\t\tfilePath: skill.filePath,\n\t\t\tdisableModelInvocation: skill.disableModelInvocation,\n\t\t};\n\t}\n\treturn map;\n}\n\nexport async function main(args: string[]) {\n\tconst parsed = parseArgs(args);\n\n\tif (parsed.version) {\n\t\tconsole.log(VERSION);\n\t\treturn;\n\t}\n\n\tif (parsed.help) {\n\t\tprintHelp();\n\t\treturn;\n\t}\n\n\tif (parsed.listModels) {\n\t\tprintModels();\n\t\treturn;\n\t}\n\n\t// Read piped stdin\n\tconst stdinContent = await readPipedStdin();\n\tif (stdinContent !== undefined) {\n\t\tparsed.print = true;\n\t\tparsed.messages.unshift(stdinContent);\n\t}\n\n\t// Process @file arguments\n\tlet initialMessage: string | undefined;\n\tif (parsed.fileArgs.length > 0) {\n\t\tconst fileContent = processFileArgs(parsed.fileArgs);\n\t\tif (parsed.messages.length > 0) {\n\t\t\tinitialMessage = fileContent + parsed.messages.shift();\n\t\t} else {\n\t\t\tinitialMessage = fileContent;\n\t\t}\n\t}\n\n\tconst cwd = process.cwd();\n\tconst isInteractive = !parsed.print && parsed.mode === undefined;\n\tconst mode = parsed.mode || \"text\";\n\n\t// Set up auth storage\n\tconst authStorage = createAuthStorage();\n\n\t// Set up settings persistence\n\tconst settingsManager = SettingsManager.create(getAgentDir());\n\n\t// Apply CLI --api-key override\n\tif (parsed.apiKey && parsed.provider) {\n\t\tauthStorage.setRuntimeApiKey(parsed.provider, parsed.apiKey);\n\t}\n\n\t// Create model (async - may resolve OAuth tokens)\n\t// Fall back to saved defaults when CLI args are not specified\n\tconst { model, provider, modelId } = await createModel({\n\t\tprovider: parsed.provider ?? settingsManager.getDefaultProvider(),\n\t\tmodel: parsed.model ?? settingsManager.getDefaultModel(),\n\t\tapiKey: parsed.apiKey,\n\t\tauthStorage,\n\t});\n\n\t// Load skills\n\tlet skills: Skill[] = [];\n\tif (!parsed.noSkills) {\n\t\tconst skillResult = loadSkills({\n\t\t\tcwd,\n\t\t\tskillPaths: parsed.skills,\n\t\t\tincludeDefaults: true,\n\t\t});\n\t\tskills = skillResult.skills;\n\n\t\tif (parsed.verbose && skillResult.diagnostics.length > 0) {\n\t\t\tfor (const d of skillResult.diagnostics) {\n\t\t\t\tconsole.error(chalk.yellow(`Skill warning: ${d.message} (${d.path})`));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Load context files (AGENTS.md)\n\tconst contextFiles = loadContextFiles(cwd);\n\tif (parsed.verbose && contextFiles.length > 0) {\n\t\tconsole.log(chalk.dim(`Loaded ${contextFiles.length} context file(s).`));\n\t}\n\n\t// Load prompt templates\n\tconst promptsResult = loadPrompts({ cwd });\n\tconst prompts = promptsResult.prompts;\n\tif (parsed.verbose && promptsResult.diagnostics.length > 0) {\n\t\tfor (const d of promptsResult.diagnostics) {\n\t\t\tconsole.error(chalk.yellow(`Prompt warning: ${d.message} (${d.path})`));\n\t\t}\n\t}\n\n\t// Find fd binary for @ file autocomplete\n\tconst fdPath = findFd();\n\n\t// Set up session manager\n\tconst sessionDir = parsed.sessionDir ?? getProjectSessionDir(cwd);\n\tlet sessionManager: SessionManager | undefined;\n\tif (parsed.noSession) {\n\t\tsessionManager = SessionManager.inMemory(cwd);\n\t} else if (parsed.session) {\n\t\tsessionManager = SessionManager.open(parsed.session, parsed.sessionDir);\n\t} else if (parsed.resume) {\n\t\t// Start a new session; the TUI will show the session picker on startup\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t} else if (parsed.continue) {\n\t\tconst recentFile = findRecentSession(sessionDir);\n\t\tif (recentFile) {\n\t\t\tsessionManager = SessionManager.open(recentFile, sessionDir);\n\t\t} else {\n\t\t\tif (parsed.verbose) {\n\t\t\t\tconsole.log(chalk.dim(\"No previous session found, starting new.\"));\n\t\t\t}\n\t\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t\t}\n\t} else {\n\t\tsessionManager = SessionManager.create(cwd, sessionDir);\n\t}\n\n\t// Create agent config\n\tconst agentConfig: CodingAgentConfig = {\n\t\tmodel,\n\t\tcwd,\n\t\ttoolSet: parsed.toolSet ?? \"coding\",\n\t\tproviderOptions: buildProviderOptions(provider, parsed.thinking),\n\t\tsessionManager,\n\t};\n\n\tagentConfig.systemPromptOptions = {\n\t\tappendSystemPrompt: parsed.appendSystemPrompt,\n\t\tcontextFiles,\n\t\tskills: toSkillMap(skills),\n\t};\n\tif (parsed.systemPrompt) {\n\t\tagentConfig.systemPromptOptions.customPrompt = parsed.systemPrompt;\n\t}\n\n\t// Create agent (session messages are auto-restored from sessionManager)\n\tconst agent = new CodingAgent(agentConfig);\n\n\tif (parsed.verbose && agent.messages.length > 0) {\n\t\tconsole.log(chalk.dim(`Restored ${agent.messages.length} messages from session.`));\n\t}\n\n\t// Dispatch to mode\n\tif (isInteractive) {\n\t\tawait runInteractiveMode(agent, {\n\t\t\tinitialMessage,\n\t\t\tinitialMessages: parsed.messages,\n\t\t\tsessionDir,\n\t\t\tagentConfig,\n\t\t\tresumeOnStart: parsed.resume,\n\t\t\tskills,\n\t\t\tcontextFiles,\n\t\t\tprompts,\n\t\t\tverbose: parsed.verbose,\n\t\t\tprovider,\n\t\t\tmodelId,\n\t\t\tauthStorage,\n\t\t\tsettingsManager,\n\t\t\tfdPath,\n\t\t\tonModelChange: async (newProvider: string, newModelId: string) => {\n\t\t\t\tconst { model: newModel } = await createModel({\n\t\t\t\t\tprovider: newProvider,\n\t\t\t\t\tmodel: newModelId,\n\t\t\t\t\tauthStorage,\n\t\t\t\t});\n\t\t\t\treturn new CodingAgent({\n\t\t\t\t\t...agentConfig,\n\t\t\t\t\tmodel: newModel,\n\t\t\t\t\tproviderOptions: buildProviderOptions(newProvider, parsed.thinking),\n\t\t\t\t});\n\t\t\t},\n\t\t});\n\t} else {\n\t\tawait runPrintMode(agent, {\n\t\t\tmode,\n\t\t\tmessages: parsed.messages,\n\t\t\tinitialMessage,\n\t\t});\n\t\tprocess.exit(0);\n\t}\n}\n"]}
|
package/dist/skills.d.ts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Skill loading
|
|
2
|
+
* Skill loading implementation.
|
|
3
3
|
* Implements the Agent Skills spec: https://agentskills.io/specification
|
|
4
4
|
*
|
|
5
5
|
* Standalone implementation - no dependency on the old SDK.
|
|
6
6
|
*/
|
|
7
|
+
import type { Skill as PromptSkill } from "edge-pi";
|
|
7
8
|
export interface SkillFrontmatter {
|
|
8
9
|
name?: string;
|
|
9
10
|
description?: string;
|
|
10
11
|
"disable-model-invocation"?: boolean;
|
|
11
12
|
[key: string]: unknown;
|
|
12
13
|
}
|
|
13
|
-
export interface Skill {
|
|
14
|
+
export interface Skill extends PromptSkill {
|
|
14
15
|
name: string;
|
|
15
|
-
description: string;
|
|
16
|
-
filePath: string;
|
|
17
|
-
baseDir: string;
|
|
18
|
-
source: string;
|
|
19
|
-
disableModelInvocation: boolean;
|
|
20
16
|
}
|
|
21
17
|
export interface SkillDiagnostic {
|
|
22
18
|
type: "warning" | "collision";
|
|
@@ -41,11 +37,4 @@ export interface LoadSkillsOptions {
|
|
|
41
37
|
* Load skills from all configured locations.
|
|
42
38
|
*/
|
|
43
39
|
export declare function loadSkills(options?: LoadSkillsOptions): LoadSkillsResult;
|
|
44
|
-
/**
|
|
45
|
-
* Format skills for inclusion in a system prompt.
|
|
46
|
-
* Uses XML format per Agent Skills standard.
|
|
47
|
-
*
|
|
48
|
-
* Skills with disableModelInvocation=true are excluded from the prompt.
|
|
49
|
-
*/
|
|
50
|
-
export declare function formatSkillsForPrompt(skills: Skill[]): string;
|
|
51
40
|
//# sourceMappingURL=skills.d.ts.map
|
package/dist/skills.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsBH,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,eAAe,EAAE,CAAC;CAC/B;AAiJD,MAAM,WAAW,iBAAiB;IACjC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAyBD;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA0F5E;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CA0B7D","sourcesContent":["/**\n * Skill loading and formatting for the system prompt.\n * Implements the Agent Skills spec: https://agentskills.io/specification\n *\n * Standalone implementation - no dependency on the old SDK.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport { parseFrontmatter } from \"./utils/frontmatter.js\";\n\nconst CONFIG_DIR_NAME = \".pi\";\n\nconst ALLOWED_FRONTMATTER_FIELDS = new Set([\n\t\"name\",\n\t\"description\",\n\t\"license\",\n\t\"compatibility\",\n\t\"metadata\",\n\t\"allowed-tools\",\n\t\"disable-model-invocation\",\n]);\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\n\nexport interface SkillDiagnostic {\n\ttype: \"warning\" | \"collision\";\n\tmessage: string;\n\tpath: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: SkillDiagnostic[];\n}\n\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\n\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\n\nfunction validateFrontmatterFields(keys: string[]): string[] {\n\tconst errors: string[] = [];\n\tfor (const key of keys) {\n\t\tif (!ALLOWED_FRONTMATTER_FIELDS.has(key)) {\n\t\t\terrors.push(`unknown frontmatter field \"${key}\"`);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; diagnostics: SkillDiagnostic[] } {\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst allKeys = Object.keys(frontmatter);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, includeRootFiles: boolean): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!isFile) continue;\n\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) continue;\n\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\n\treturn { skills, diagnostics };\n}\n\nexport interface LoadSkillsOptions {\n\t/** Working directory for project-local skills. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global skills. Default: ~/.pi/agent */\n\tagentDir?: string;\n\t/** Explicit skill paths (files or directories) */\n\tskillPaths?: string[];\n\t/** Include default skill directories. Default: true */\n\tincludeDefaults?: boolean;\n}\n\nfunction getDefaultAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\n\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\n\n/**\n * Load skills from all configured locations.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: SkillDiagnostic[] = [];\n\tconst collisionDiagnostics: SkillDiagnostic[] = [];\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\n\t\t\tif (realPathSet.has(realPath)) continue;\n\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", true));\n\t}\n\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) return true;\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n *\n * Skills with disableModelInvocation=true are excluded from the prompt.\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tconst lines = [\n\t\t\"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n\t\t\"Use the read tool to load a skill's file when the task matches its description.\",\n\t\t\"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\n\tlines.push(\"</available_skills>\");\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,SAAS,CAAC;AAkBpD,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,KAAM,SAAQ,WAAW;IACzC,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,SAAS,GAAG,WAAW,CAAC;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,WAAW,EAAE,eAAe,EAAE,CAAC;CAC/B;AA+ID,MAAM,WAAW,iBAAiB;IACjC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,uDAAuD;IACvD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAyBD;;GAEG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CAuE5E","sourcesContent":["/**\n * Skill loading implementation.\n * Implements the Agent Skills spec: https://agentskills.io/specification\n *\n * Standalone implementation - no dependency on the old SDK.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\nimport type { Skill as PromptSkill } from \"edge-pi\";\nimport { parseFrontmatter } from \"./utils/frontmatter.js\";\n\nconst CONFIG_DIR_NAME = \".pi\";\n\nconst ALLOWED_FRONTMATTER_FIELDS = new Set([\n\t\"name\",\n\t\"description\",\n\t\"license\",\n\t\"compatibility\",\n\t\"metadata\",\n\t\"allowed-tools\",\n\t\"disable-model-invocation\",\n]);\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface Skill extends PromptSkill {\n\tname: string;\n}\n\nexport interface SkillDiagnostic {\n\ttype: \"warning\" | \"collision\";\n\tmessage: string;\n\tpath: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: SkillDiagnostic[];\n}\n\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\n\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\n\nfunction validateFrontmatterFields(keys: string[]): string[] {\n\tconst errors: string[] = [];\n\tfor (const key of keys) {\n\t\tif (!ALLOWED_FRONTMATTER_FIELDS.has(key)) {\n\t\t\terrors.push(`unknown frontmatter field \"${key}\"`);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction loadSkillFromFile(filePath: string): { skill: Skill | null; diagnostics: SkillDiagnostic[] } {\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst allKeys = Object.keys(frontmatter);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\n\nfunction loadSkillsFromDirInternal(dir: string, includeRootFiles: boolean): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, false);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!isFile) continue;\n\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) continue;\n\n\t\t\tconst result = loadSkillFromFile(fullPath);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\n\treturn { skills, diagnostics };\n}\n\nexport interface LoadSkillsOptions {\n\t/** Working directory for project-local skills. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global skills. Default: ~/.pi/agent */\n\tagentDir?: string;\n\t/** Explicit skill paths (files or directories) */\n\tskillPaths?: string[];\n\t/** Include default skill directories. Default: true */\n\tincludeDefaults?: boolean;\n}\n\nfunction getDefaultAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\n\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\n\n/**\n * Load skills from all configured locations.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: SkillDiagnostic[] = [];\n\tconst collisionDiagnostics: SkillDiagnostic[] = [];\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\n\t\t\tif (realPathSet.has(realPath)) continue;\n\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), true));\n\t}\n\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
|
package/dist/skills.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Skill loading
|
|
2
|
+
* Skill loading implementation.
|
|
3
3
|
* Implements the Agent Skills spec: https://agentskills.io/specification
|
|
4
4
|
*
|
|
5
5
|
* Standalone implementation - no dependency on the old SDK.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync, readdirSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
8
8
|
import { homedir } from "node:os";
|
|
9
|
-
import { basename, dirname, isAbsolute, join, resolve
|
|
9
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
10
10
|
import { parseFrontmatter } from "./utils/frontmatter.js";
|
|
11
11
|
const CONFIG_DIR_NAME = ".pi";
|
|
12
12
|
const ALLOWED_FRONTMATTER_FIELDS = new Set([
|
|
@@ -58,7 +58,7 @@ function validateFrontmatterFields(keys) {
|
|
|
58
58
|
}
|
|
59
59
|
return errors;
|
|
60
60
|
}
|
|
61
|
-
function loadSkillFromFile(filePath
|
|
61
|
+
function loadSkillFromFile(filePath) {
|
|
62
62
|
const diagnostics = [];
|
|
63
63
|
try {
|
|
64
64
|
const rawContent = readFileSync(filePath, "utf-8");
|
|
@@ -87,8 +87,6 @@ function loadSkillFromFile(filePath, source) {
|
|
|
87
87
|
name,
|
|
88
88
|
description: frontmatter.description,
|
|
89
89
|
filePath,
|
|
90
|
-
baseDir: skillDir,
|
|
91
|
-
source,
|
|
92
90
|
disableModelInvocation: frontmatter["disable-model-invocation"] === true,
|
|
93
91
|
},
|
|
94
92
|
diagnostics,
|
|
@@ -100,7 +98,7 @@ function loadSkillFromFile(filePath, source) {
|
|
|
100
98
|
return { skill: null, diagnostics };
|
|
101
99
|
}
|
|
102
100
|
}
|
|
103
|
-
function loadSkillsFromDirInternal(dir,
|
|
101
|
+
function loadSkillsFromDirInternal(dir, includeRootFiles) {
|
|
104
102
|
const skills = [];
|
|
105
103
|
const diagnostics = [];
|
|
106
104
|
if (!existsSync(dir)) {
|
|
@@ -126,7 +124,7 @@ function loadSkillsFromDirInternal(dir, source, includeRootFiles) {
|
|
|
126
124
|
}
|
|
127
125
|
}
|
|
128
126
|
if (isDirectory) {
|
|
129
|
-
const subResult = loadSkillsFromDirInternal(fullPath,
|
|
127
|
+
const subResult = loadSkillsFromDirInternal(fullPath, false);
|
|
130
128
|
skills.push(...subResult.skills);
|
|
131
129
|
diagnostics.push(...subResult.diagnostics);
|
|
132
130
|
continue;
|
|
@@ -137,7 +135,7 @@ function loadSkillsFromDirInternal(dir, source, includeRootFiles) {
|
|
|
137
135
|
const isSkillMd = !includeRootFiles && entry.name === "SKILL.md";
|
|
138
136
|
if (!isRootMd && !isSkillMd)
|
|
139
137
|
continue;
|
|
140
|
-
const result = loadSkillFromFile(fullPath
|
|
138
|
+
const result = loadSkillFromFile(fullPath);
|
|
141
139
|
if (result.skill) {
|
|
142
140
|
skills.push(result.skill);
|
|
143
141
|
}
|
|
@@ -209,27 +207,9 @@ export function loadSkills(options = {}) {
|
|
|
209
207
|
}
|
|
210
208
|
}
|
|
211
209
|
if (includeDefaults) {
|
|
212
|
-
addSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, "skills"),
|
|
213
|
-
addSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, "skills"),
|
|
210
|
+
addSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, "skills"), true));
|
|
211
|
+
addSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, "skills"), true));
|
|
214
212
|
}
|
|
215
|
-
const userSkillsDir = join(resolvedAgentDir, "skills");
|
|
216
|
-
const projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, "skills");
|
|
217
|
-
const isUnderPath = (target, root) => {
|
|
218
|
-
const normalizedRoot = resolve(root);
|
|
219
|
-
if (target === normalizedRoot)
|
|
220
|
-
return true;
|
|
221
|
-
const prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
|
|
222
|
-
return target.startsWith(prefix);
|
|
223
|
-
};
|
|
224
|
-
const getSource = (resolvedPath) => {
|
|
225
|
-
if (!includeDefaults) {
|
|
226
|
-
if (isUnderPath(resolvedPath, userSkillsDir))
|
|
227
|
-
return "user";
|
|
228
|
-
if (isUnderPath(resolvedPath, projectSkillsDir))
|
|
229
|
-
return "project";
|
|
230
|
-
}
|
|
231
|
-
return "path";
|
|
232
|
-
};
|
|
233
213
|
for (const rawPath of skillPaths) {
|
|
234
214
|
const resolvedPath = resolveSkillPath(rawPath, cwd);
|
|
235
215
|
if (!existsSync(resolvedPath)) {
|
|
@@ -238,12 +218,11 @@ export function loadSkills(options = {}) {
|
|
|
238
218
|
}
|
|
239
219
|
try {
|
|
240
220
|
const stats = statSync(resolvedPath);
|
|
241
|
-
const source = getSource(resolvedPath);
|
|
242
221
|
if (stats.isDirectory()) {
|
|
243
|
-
addSkills(loadSkillsFromDirInternal(resolvedPath,
|
|
222
|
+
addSkills(loadSkillsFromDirInternal(resolvedPath, true));
|
|
244
223
|
}
|
|
245
224
|
else if (stats.isFile() && resolvedPath.endsWith(".md")) {
|
|
246
|
-
const result = loadSkillFromFile(resolvedPath
|
|
225
|
+
const result = loadSkillFromFile(resolvedPath);
|
|
247
226
|
if (result.skill) {
|
|
248
227
|
addSkills({ skills: [result.skill], diagnostics: result.diagnostics });
|
|
249
228
|
}
|
|
@@ -265,40 +244,4 @@ export function loadSkills(options = {}) {
|
|
|
265
244
|
diagnostics: [...allDiagnostics, ...collisionDiagnostics],
|
|
266
245
|
};
|
|
267
246
|
}
|
|
268
|
-
/**
|
|
269
|
-
* Format skills for inclusion in a system prompt.
|
|
270
|
-
* Uses XML format per Agent Skills standard.
|
|
271
|
-
*
|
|
272
|
-
* Skills with disableModelInvocation=true are excluded from the prompt.
|
|
273
|
-
*/
|
|
274
|
-
export function formatSkillsForPrompt(skills) {
|
|
275
|
-
const visibleSkills = skills.filter((s) => !s.disableModelInvocation);
|
|
276
|
-
if (visibleSkills.length === 0) {
|
|
277
|
-
return "";
|
|
278
|
-
}
|
|
279
|
-
const lines = [
|
|
280
|
-
"\n\nThe following skills provide specialized instructions for specific tasks.",
|
|
281
|
-
"Use the read tool to load a skill's file when the task matches its description.",
|
|
282
|
-
"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.",
|
|
283
|
-
"",
|
|
284
|
-
"<available_skills>",
|
|
285
|
-
];
|
|
286
|
-
for (const skill of visibleSkills) {
|
|
287
|
-
lines.push(" <skill>");
|
|
288
|
-
lines.push(` <name>${escapeXml(skill.name)}</name>`);
|
|
289
|
-
lines.push(` <description>${escapeXml(skill.description)}</description>`);
|
|
290
|
-
lines.push(` <location>${escapeXml(skill.filePath)}</location>`);
|
|
291
|
-
lines.push(" </skill>");
|
|
292
|
-
}
|
|
293
|
-
lines.push("</available_skills>");
|
|
294
|
-
return lines.join("\n");
|
|
295
|
-
}
|
|
296
|
-
function escapeXml(str) {
|
|
297
|
-
return str
|
|
298
|
-
.replace(/&/g, "&")
|
|
299
|
-
.replace(/</g, "<")
|
|
300
|
-
.replace(/>/g, ">")
|
|
301
|
-
.replace(/"/g, """)
|
|
302
|
-
.replace(/'/g, "'");
|
|
303
|
-
}
|
|
304
247
|
//# sourceMappingURL=skills.js.map
|
package/dist/skills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill loading and formatting for the system prompt.\n * Implements the Agent Skills spec: https://agentskills.io/specification\n *\n * Standalone implementation - no dependency on the old SDK.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve, sep } from \"node:path\";\nimport { parseFrontmatter } from \"./utils/frontmatter.js\";\n\nconst CONFIG_DIR_NAME = \".pi\";\n\nconst ALLOWED_FRONTMATTER_FIELDS = new Set([\n\t\"name\",\n\t\"description\",\n\t\"license\",\n\t\"compatibility\",\n\t\"metadata\",\n\t\"allowed-tools\",\n\t\"disable-model-invocation\",\n]);\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface Skill {\n\tname: string;\n\tdescription: string;\n\tfilePath: string;\n\tbaseDir: string;\n\tsource: string;\n\tdisableModelInvocation: boolean;\n}\n\nexport interface SkillDiagnostic {\n\ttype: \"warning\" | \"collision\";\n\tmessage: string;\n\tpath: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: SkillDiagnostic[];\n}\n\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\n\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\n\nfunction validateFrontmatterFields(keys: string[]): string[] {\n\tconst errors: string[] = [];\n\tfor (const key of keys) {\n\t\tif (!ALLOWED_FRONTMATTER_FIELDS.has(key)) {\n\t\t\terrors.push(`unknown frontmatter field \"${key}\"`);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; diagnostics: SkillDiagnostic[] } {\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst allKeys = Object.keys(frontmatter);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tbaseDir: skillDir,\n\t\t\t\tsource,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, includeRootFiles: boolean): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, false);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!isFile) continue;\n\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) continue;\n\n\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\n\treturn { skills, diagnostics };\n}\n\nexport interface LoadSkillsOptions {\n\t/** Working directory for project-local skills. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global skills. Default: ~/.pi/agent */\n\tagentDir?: string;\n\t/** Explicit skill paths (files or directories) */\n\tskillPaths?: string[];\n\t/** Include default skill directories. Default: true */\n\tincludeDefaults?: boolean;\n}\n\nfunction getDefaultAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\n\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\n\n/**\n * Load skills from all configured locations.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: SkillDiagnostic[] = [];\n\tconst collisionDiagnostics: SkillDiagnostic[] = [];\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\n\t\t\tif (realPathSet.has(realPath)) continue;\n\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", true));\n\t}\n\n\tconst userSkillsDir = join(resolvedAgentDir, \"skills\");\n\tconst projectSkillsDir = resolve(cwd, CONFIG_DIR_NAME, \"skills\");\n\n\tconst isUnderPath = (target: string, root: string): boolean => {\n\t\tconst normalizedRoot = resolve(root);\n\t\tif (target === normalizedRoot) return true;\n\t\tconst prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;\n\t\treturn target.startsWith(prefix);\n\t};\n\n\tconst getSource = (resolvedPath: string): \"user\" | \"project\" | \"path\" => {\n\t\tif (!includeDefaults) {\n\t\t\tif (isUnderPath(resolvedPath, userSkillsDir)) return \"user\";\n\t\t\tif (isUnderPath(resolvedPath, projectSkillsDir)) return \"project\";\n\t\t}\n\t\treturn \"path\";\n\t};\n\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tconst source = getSource(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, source, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n *\n * Skills with disableModelInvocation=true are excluded from the prompt.\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tconst visibleSkills = skills.filter((s) => !s.disableModelInvocation);\n\n\tif (visibleSkills.length === 0) {\n\t\treturn \"\";\n\t}\n\n\tconst lines = [\n\t\t\"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n\t\t\"Use the read tool to load a skill's file when the task matches its description.\",\n\t\t\"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n\t\t\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of visibleSkills) {\n\t\tlines.push(\" <skill>\");\n\t\tlines.push(` <name>${escapeXml(skill.name)}</name>`);\n\t\tlines.push(` <description>${escapeXml(skill.description)}</description>`);\n\t\tlines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n\t\tlines.push(\" </skill>\");\n\t}\n\n\tlines.push(\"</available_skills>\");\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction escapeXml(str: string): string {\n\treturn str\n\t\t.replace(/&/g, \"&\")\n\t\t.replace(/</g, \"<\")\n\t\t.replace(/>/g, \">\")\n\t\t.replace(/\"/g, \""\")\n\t\t.replace(/'/g, \"'\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill loading implementation.\n * Implements the Agent Skills spec: https://agentskills.io/specification\n *\n * Standalone implementation - no dependency on the old SDK.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { basename, dirname, isAbsolute, join, resolve } from \"node:path\";\nimport type { Skill as PromptSkill } from \"edge-pi\";\nimport { parseFrontmatter } from \"./utils/frontmatter.js\";\n\nconst CONFIG_DIR_NAME = \".pi\";\n\nconst ALLOWED_FRONTMATTER_FIELDS = new Set([\n\t\"name\",\n\t\"description\",\n\t\"license\",\n\t\"compatibility\",\n\t\"metadata\",\n\t\"allowed-tools\",\n\t\"disable-model-invocation\",\n]);\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\n\t\"disable-model-invocation\"?: boolean;\n\t[key: string]: unknown;\n}\n\nexport interface Skill extends PromptSkill {\n\tname: string;\n}\n\nexport interface SkillDiagnostic {\n\ttype: \"warning\" | \"collision\";\n\tmessage: string;\n\tpath: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\tdiagnostics: SkillDiagnostic[];\n}\n\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\tif (!/^[a-z0-9-]+$/.test(name)) {\n\t\terrors.push(`name contains invalid characters (must be lowercase a-z, 0-9, hyphens only)`);\n\t}\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\treturn errors;\n}\n\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\tif (!description || description.trim() === \"\") {\n\t\terrors.push(\"description is required\");\n\t} else if (description.length > MAX_DESCRIPTION_LENGTH) {\n\t\terrors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n\t}\n\treturn errors;\n}\n\nfunction validateFrontmatterFields(keys: string[]): string[] {\n\tconst errors: string[] = [];\n\tfor (const key of keys) {\n\t\tif (!ALLOWED_FRONTMATTER_FIELDS.has(key)) {\n\t\t\terrors.push(`unknown frontmatter field \"${key}\"`);\n\t\t}\n\t}\n\treturn errors;\n}\n\nfunction loadSkillFromFile(filePath: string): { skill: Skill | null; diagnostics: SkillDiagnostic[] } {\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter } = parseFrontmatter<SkillFrontmatter>(rawContent);\n\t\tconst allKeys = Object.keys(frontmatter);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\tdiagnostics.push({ type: \"warning\", message: error, path: filePath });\n\t\t}\n\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, diagnostics };\n\t\t}\n\n\t\treturn {\n\t\t\tskill: {\n\t\t\t\tname,\n\t\t\t\tdescription: frontmatter.description,\n\t\t\t\tfilePath,\n\t\t\t\tdisableModelInvocation: frontmatter[\"disable-model-invocation\"] === true,\n\t\t\t},\n\t\t\tdiagnostics,\n\t\t};\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : \"failed to parse skill file\";\n\t\tdiagnostics.push({ type: \"warning\", message, path: filePath });\n\t\treturn { skill: null, diagnostics };\n\t}\n}\n\nfunction loadSkillsFromDirInternal(dir: string, includeRootFiles: boolean): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst diagnostics: SkillDiagnostic[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, diagnostics };\n\t}\n\n\ttry {\n\t\tconst entries = readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tif (entry.name.startsWith(\".\") || entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tlet isDirectory = entry.isDirectory();\n\t\t\tlet isFile = entry.isFile();\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = statSync(fullPath);\n\t\t\t\t\tisDirectory = stats.isDirectory();\n\t\t\t\t\tisFile = stats.isFile();\n\t\t\t\t} catch {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (isDirectory) {\n\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, false);\n\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\tdiagnostics.push(...subResult.diagnostics);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!isFile) continue;\n\n\t\t\tconst isRootMd = includeRootFiles && entry.name.endsWith(\".md\");\n\t\t\tconst isSkillMd = !includeRootFiles && entry.name === \"SKILL.md\";\n\t\t\tif (!isRootMd && !isSkillMd) continue;\n\n\t\t\tconst result = loadSkillFromFile(fullPath);\n\t\t\tif (result.skill) {\n\t\t\t\tskills.push(result.skill);\n\t\t\t}\n\t\t\tdiagnostics.push(...result.diagnostics);\n\t\t}\n\t} catch {}\n\n\treturn { skills, diagnostics };\n}\n\nexport interface LoadSkillsOptions {\n\t/** Working directory for project-local skills. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global skills. Default: ~/.pi/agent */\n\tagentDir?: string;\n\t/** Explicit skill paths (files or directories) */\n\tskillPaths?: string[];\n\t/** Include default skill directories. Default: true */\n\tincludeDefaults?: boolean;\n}\n\nfunction getDefaultAgentDir(): string {\n\tconst envDir = process.env.PI_CODING_AGENT_DIR;\n\tif (envDir) {\n\t\tif (envDir === \"~\") return homedir();\n\t\tif (envDir.startsWith(\"~/\")) return homedir() + envDir.slice(1);\n\t\treturn envDir;\n\t}\n\treturn join(homedir(), CONFIG_DIR_NAME, \"agent\");\n}\n\nfunction normalizePath(input: string): string {\n\tconst trimmed = input.trim();\n\tif (trimmed === \"~\") return homedir();\n\tif (trimmed.startsWith(\"~/\")) return join(homedir(), trimmed.slice(2));\n\tif (trimmed.startsWith(\"~\")) return join(homedir(), trimmed.slice(1));\n\treturn trimmed;\n}\n\nfunction resolveSkillPath(p: string, cwd: string): string {\n\tconst normalized = normalizePath(p);\n\treturn isAbsolute(normalized) ? normalized : resolve(cwd, normalized);\n}\n\n/**\n * Load skills from all configured locations.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst { cwd = process.cwd(), agentDir, skillPaths = [], includeDefaults = true } = options;\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst realPathSet = new Set<string>();\n\tconst allDiagnostics: SkillDiagnostic[] = [];\n\tconst collisionDiagnostics: SkillDiagnostic[] = [];\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallDiagnostics.push(...result.diagnostics);\n\t\tfor (const skill of result.skills) {\n\t\t\tlet realPath: string;\n\t\t\ttry {\n\t\t\t\trealPath = realpathSync(skill.filePath);\n\t\t\t} catch {\n\t\t\t\trealPath = skill.filePath;\n\t\t\t}\n\n\t\t\tif (realPathSet.has(realPath)) continue;\n\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionDiagnostics.push({\n\t\t\t\t\ttype: \"collision\",\n\t\t\t\t\tmessage: `name \"${skill.name}\" collision`,\n\t\t\t\t\tpath: skill.filePath,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t\trealPathSet.add(realPath);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (includeDefaults) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), true));\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), true));\n\t}\n\n\tfor (const rawPath of skillPaths) {\n\t\tconst resolvedPath = resolveSkillPath(rawPath, cwd);\n\t\tif (!existsSync(resolvedPath)) {\n\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path does not exist\", path: resolvedPath });\n\t\t\tcontinue;\n\t\t}\n\n\t\ttry {\n\t\t\tconst stats = statSync(resolvedPath);\n\t\t\tif (stats.isDirectory()) {\n\t\t\t\taddSkills(loadSkillsFromDirInternal(resolvedPath, true));\n\t\t\t} else if (stats.isFile() && resolvedPath.endsWith(\".md\")) {\n\t\t\t\tconst result = loadSkillFromFile(resolvedPath);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\taddSkills({ skills: [result.skill], diagnostics: result.diagnostics });\n\t\t\t\t} else {\n\t\t\t\t\tallDiagnostics.push(...result.diagnostics);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tallDiagnostics.push({ type: \"warning\", message: \"skill path is not a markdown file\", path: resolvedPath });\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"failed to read skill path\";\n\t\t\tallDiagnostics.push({ type: \"warning\", message, path: resolvedPath });\n\t\t}\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\tdiagnostics: [...allDiagnostics, ...collisionDiagnostics],\n\t};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "edge-pi-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI for the edge-pi coding agent SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@ai-sdk/openai": "^3.0.26",
|
|
28
28
|
"@mariozechner/pi-tui": "^0.50.9",
|
|
29
29
|
"chalk": "^5.5.0",
|
|
30
|
-
"edge-pi": "^0.
|
|
30
|
+
"edge-pi": "^0.2.0",
|
|
31
31
|
"proper-lockfile": "^4.1.2",
|
|
32
32
|
"yaml": "^2.7.1"
|
|
33
33
|
},
|