@mariozechner/pi-coding-agent 0.26.1 → 0.27.1
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/CHANGELOG.md +26 -0
- package/dist/core/agent-session.d.ts +7 -5
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +49 -15
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/hooks/index.d.ts +1 -1
- package/dist/core/hooks/index.d.ts.map +1 -1
- package/dist/core/hooks/index.js.map +1 -1
- package/dist/core/hooks/runner.d.ts +3 -3
- package/dist/core/hooks/runner.d.ts.map +1 -1
- package/dist/core/hooks/runner.js +7 -3
- package/dist/core/hooks/runner.js.map +1 -1
- package/dist/core/hooks/types.d.ts +30 -24
- package/dist/core/hooks/types.d.ts.map +1 -1
- package/dist/core/hooks/types.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +16 -0
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +4 -0
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +1 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.d.ts +7 -0
- package/dist/core/timings.d.ts.map +1 -0
- package/dist/core/timings.js +25 -0
- package/dist/core/timings.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +15 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +5 -5
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +8 -3
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +73 -47
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/visual-truncate.d.ts +24 -0
- package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -0
- package/dist/modes/interactive/components/visual-truncate.js +33 -0
- package/dist/modes/interactive/components/visual-truncate.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +26 -9
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +10 -2
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +7 -2
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +5 -5
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +7 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/hooks.md +42 -28
- package/docs/rpc.md +26 -6
- package/examples/hooks/README.md +19 -3
- package/examples/hooks/auto-commit-on-exit.ts +50 -0
- package/examples/hooks/confirm-destructive.ts +62 -0
- package/examples/hooks/dirty-repo-guard.ts +59 -0
- package/examples/hooks/git-checkpoint.ts +6 -5
- package/package.json +4 -4
package/dist/core/sdk.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Checks custom providers (models.json), OAuth, and environment variables.\n */\nexport function defaultGetApiKey(): (model: Model<any>) => Promise<string | undefined> {\n\treturn getApiKeyForModel;\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.loadSession();\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel) {\n\t\t\tconst key = await getApiKeyForModel(restoredModel);\n\t\t\tif (key) {\n\t\t\t\tmodel = restoredModel;\n\t\t\t}\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel) {\n\t\t\t\tconst key = await getApiKeyForModel(settingsModel);\n\t\t\t\tif (key) {\n\t\t\t\t\tmodel = settingsModel;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available\n\tif (!model) {\n\t\tconst available = await discoverAvailableModels();\n\t\tif (available.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No models available. Set an API key environment variable \" +\n\t\t\t\t\t\"(ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) or provide a model explicitly.\",\n\t\t\t);\n\t\t}\n\t\tmodel = available[0];\n\t\tif (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey();\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t});\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"sdk.js","sourceRoot":"","sources":["../../src/core/sdk.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SDK for programmatic usage of AgentSession.\n *\n * Provides a factory function and discovery helpers that allow full control\n * over agent configuration, or sensible defaults that match CLI behavior.\n *\n * @example\n * ```typescript\n * // Minimal - everything auto-discovered\n * const session = await createAgentSession();\n *\n * // With custom hooks\n * const session = await createAgentSession({\n * hooks: [\n * ...await discoverHooks(),\n * { factory: myHookFactory },\n * ],\n * });\n *\n * // Full control\n * const session = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionFile: false,\n * });\n * ```\n */\n\nimport { Agent, ProviderTransport, type ThinkingLevel } from \"@mariozechner/pi-agent-core\";\nimport { type Model, setOAuthStorage } from \"@mariozechner/pi-ai\";\nimport { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { getAgentDir } from \"../config.js\";\nimport { AgentSession } from \"./agent-session.js\";\nimport { discoverAndLoadCustomTools, type LoadedCustomTool } from \"./custom-tools/index.js\";\nimport type { CustomAgentTool } from \"./custom-tools/types.js\";\nimport { discoverAndLoadHooks, HookRunner, type LoadedHook, wrapToolsWithHooks } from \"./hooks/index.js\";\nimport type { HookFactory } from \"./hooks/types.js\";\nimport { messageTransformer } from \"./messages.js\";\nimport {\n\tfindModel as findModelInternal,\n\tgetApiKeyForModel,\n\tgetAvailableModels,\n\tloadAndMergeModels,\n} from \"./model-config.js\";\nimport { SessionManager } from \"./session-manager.js\";\nimport { type Settings, SettingsManager, type SkillsSettings } from \"./settings-manager.js\";\nimport { loadSkills as loadSkillsInternal, type Skill } from \"./skills.js\";\nimport { type FileSlashCommand, loadSlashCommands as loadSlashCommandsInternal } from \"./slash-commands.js\";\nimport {\n\tbuildSystemPrompt as buildSystemPromptInternal,\n\tloadProjectContextFiles as loadContextFilesInternal,\n} from \"./system-prompt.js\";\nimport { time } from \"./timings.js\";\nimport {\n\tallTools,\n\tbashTool,\n\tcodingTools,\n\tcreateBashTool,\n\tcreateCodingTools,\n\tcreateEditTool,\n\tcreateFindTool,\n\tcreateGrepTool,\n\tcreateLsTool,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateWriteTool,\n\teditTool,\n\tfindTool,\n\tgrepTool,\n\tlsTool,\n\treadOnlyTools,\n\treadTool,\n\ttype Tool,\n\twriteTool,\n} from \"./tools/index.js\";\n\n// Types\n\nexport interface CreateAgentSessionOptions {\n\t/** Working directory for project-local discovery. Default: process.cwd() */\n\tcwd?: string;\n\t/** Global config directory. Default: ~/.pi/agent */\n\tagentDir?: string;\n\n\t/** Model to use. Default: from settings, else first available */\n\tmodel?: Model<any>;\n\t/** Thinking level. Default: from settings, else 'off' (clamped to model capabilities) */\n\tthinkingLevel?: ThinkingLevel;\n\t/** Models available for cycling (Ctrl+P in interactive mode) */\n\tscopedModels?: Array<{ model: Model<any>; thinkingLevel: ThinkingLevel }>;\n\n\t/** API key resolver. Default: defaultGetApiKey() */\n\tgetApiKey?: (model: Model<any>) => Promise<string | undefined>;\n\n\t/** System prompt. String replaces default, function receives default and returns final. */\n\tsystemPrompt?: string | ((defaultPrompt: string) => string);\n\n\t/** Built-in tools to use. Default: codingTools [read, bash, edit, write] */\n\ttools?: Tool[];\n\t/** Custom tools (replaces discovery). */\n\tcustomTools?: Array<{ path?: string; tool: CustomAgentTool }>;\n\t/** Additional custom tool paths to load (merged with discovery). */\n\tadditionalCustomToolPaths?: string[];\n\n\t/** Hooks (replaces discovery). */\n\thooks?: Array<{ path?: string; factory: HookFactory }>;\n\t/** Additional hook paths to load (merged with discovery). */\n\tadditionalHookPaths?: string[];\n\n\t/** Skills. Default: discovered from multiple locations */\n\tskills?: Skill[];\n\t/** Context files (AGENTS.md content). Default: discovered walking up from cwd */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Slash commands. Default: discovered from cwd/.pi/commands/ + agentDir/commands/ */\n\tslashCommands?: FileSlashCommand[];\n\n\t/** Session manager. Default: SessionManager.create(cwd) */\n\tsessionManager?: SessionManager;\n\n\t/** Settings manager. Default: SettingsManager.create(cwd, agentDir) */\n\tsettingsManager?: SettingsManager;\n}\n\n/** Result from createAgentSession */\nexport interface CreateAgentSessionResult {\n\t/** The created session */\n\tsession: AgentSession;\n\t/** Custom tools result (for UI context setup in interactive mode) */\n\tcustomToolsResult: {\n\t\ttools: LoadedCustomTool[];\n\t\tsetUIContext: (uiContext: any, hasUI: boolean) => void;\n\t};\n\t/** Warning if session was restored with a different model than saved */\n\tmodelFallbackMessage?: string;\n}\n\n// Re-exports\n\nexport type { CustomAgentTool } from \"./custom-tools/types.js\";\nexport type { HookAPI, HookFactory } from \"./hooks/types.js\";\nexport type { Settings, SkillsSettings } from \"./settings-manager.js\";\nexport type { Skill } from \"./skills.js\";\nexport type { FileSlashCommand } from \"./slash-commands.js\";\nexport type { Tool } from \"./tools/index.js\";\n\nexport {\n\t// Pre-built tools (use process.cwd())\n\treadTool,\n\tbashTool,\n\teditTool,\n\twriteTool,\n\tgrepTool,\n\tfindTool,\n\tlsTool,\n\tcodingTools,\n\treadOnlyTools,\n\tallTools as allBuiltInTools,\n\t// Tool factories (for custom cwd)\n\tcreateCodingTools,\n\tcreateReadOnlyTools,\n\tcreateReadTool,\n\tcreateBashTool,\n\tcreateEditTool,\n\tcreateWriteTool,\n\tcreateGrepTool,\n\tcreateFindTool,\n\tcreateLsTool,\n};\n\n// Helper Functions\n\nfunction getDefaultAgentDir(): string {\n\treturn getAgentDir();\n}\n\n/**\n * Configure OAuth storage to use the specified agent directory.\n * Must be called before using OAuth-based authentication.\n */\nexport function configureOAuthStorage(agentDir: string = getDefaultAgentDir()): void {\n\tconst oauthPath = join(agentDir, \"oauth.json\");\n\n\tsetOAuthStorage({\n\t\tload: () => {\n\t\t\tif (!existsSync(oauthPath)) {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\treturn JSON.parse(readFileSync(oauthPath, \"utf-8\"));\n\t\t\t} catch {\n\t\t\t\treturn {};\n\t\t\t}\n\t\t},\n\t\tsave: (storage) => {\n\t\t\tconst dir = dirname(oauthPath);\n\t\t\tif (!existsSync(dir)) {\n\t\t\t\tmkdirSync(dir, { recursive: true, mode: 0o700 });\n\t\t\t}\n\t\t\twriteFileSync(oauthPath, JSON.stringify(storage, null, 2), \"utf-8\");\n\t\t\tchmodSync(oauthPath, 0o600);\n\t\t},\n\t});\n}\n\n// Discovery Functions\n\n/**\n * Get all models (built-in + custom from models.json).\n */\nexport function discoverModels(agentDir: string = getDefaultAgentDir()): Model<any>[] {\n\tconst { models, error } = loadAndMergeModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Get models that have valid API keys available.\n */\nexport async function discoverAvailableModels(agentDir: string = getDefaultAgentDir()): Promise<Model<any>[]> {\n\tconst { models, error } = await getAvailableModels(agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn models;\n}\n\n/**\n * Find a model by provider and ID.\n * @returns The model, or null if not found\n */\nexport function findModel(\n\tprovider: string,\n\tmodelId: string,\n\tagentDir: string = getDefaultAgentDir(),\n): Model<any> | null {\n\tconst { model, error } = findModelInternal(provider, modelId, agentDir);\n\tif (error) {\n\t\tthrow new Error(error);\n\t}\n\treturn model;\n}\n\n/**\n * Discover hooks from cwd and agentDir.\n */\nexport async function discoverHooks(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; factory: HookFactory }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { hooks, errors } = await discoverAndLoadHooks([], resolvedCwd, resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t}\n\n\treturn hooks.map((h) => ({\n\t\tpath: h.path,\n\t\tfactory: createFactoryFromLoadedHook(h),\n\t}));\n}\n\n/**\n * Discover custom tools from cwd and agentDir.\n */\nexport async function discoverCustomTools(\n\tcwd?: string,\n\tagentDir?: string,\n): Promise<Array<{ path: string; tool: CustomAgentTool }>> {\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedAgentDir = agentDir ?? getDefaultAgentDir();\n\n\tconst { tools, errors } = await discoverAndLoadCustomTools([], resolvedCwd, Object.keys(allTools), resolvedAgentDir);\n\n\t// Log errors but don't fail\n\tfor (const { path, error } of errors) {\n\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t}\n\n\treturn tools.map((t) => ({\n\t\tpath: t.path,\n\t\ttool: t.tool,\n\t}));\n}\n\n/**\n * Discover skills from cwd and agentDir.\n */\nexport function discoverSkills(cwd?: string, agentDir?: string, settings?: SkillsSettings): Skill[] {\n\tconst { skills } = loadSkillsInternal({\n\t\t...settings,\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n\treturn skills;\n}\n\n/**\n * Discover context files (AGENTS.md) walking up from cwd.\n */\nexport function discoverContextFiles(cwd?: string, agentDir?: string): Array<{ path: string; content: string }> {\n\treturn loadContextFilesInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n/**\n * Discover slash commands from cwd and agentDir.\n */\nexport function discoverSlashCommands(cwd?: string, agentDir?: string): FileSlashCommand[] {\n\treturn loadSlashCommandsInternal({\n\t\tcwd: cwd ?? process.cwd(),\n\t\tagentDir: agentDir ?? getDefaultAgentDir(),\n\t});\n}\n\n// API Key Helpers\n\n/**\n * Create the default API key resolver.\n * Checks custom providers (models.json), OAuth, and environment variables.\n */\nexport function defaultGetApiKey(): (model: Model<any>) => Promise<string | undefined> {\n\treturn getApiKeyForModel;\n}\n\n// System Prompt\n\nexport interface BuildSystemPromptOptions {\n\ttools?: Tool[];\n\tskills?: Skill[];\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\tcwd?: string;\n\tappendPrompt?: string;\n}\n\n/**\n * Build the default system prompt.\n */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\treturn buildSystemPromptInternal({\n\t\tcwd: options.cwd,\n\t\tskills: options.skills,\n\t\tcontextFiles: options.contextFiles,\n\t\tappendSystemPrompt: options.appendPrompt,\n\t});\n}\n\n// Settings\n\n/**\n * Load settings from agentDir/settings.json merged with cwd/.pi/settings.json.\n */\nexport function loadSettings(cwd?: string, agentDir?: string): Settings {\n\tconst manager = SettingsManager.create(cwd ?? process.cwd(), agentDir ?? getDefaultAgentDir());\n\treturn {\n\t\tdefaultProvider: manager.getDefaultProvider(),\n\t\tdefaultModel: manager.getDefaultModel(),\n\t\tdefaultThinkingLevel: manager.getDefaultThinkingLevel(),\n\t\tqueueMode: manager.getQueueMode(),\n\t\ttheme: manager.getTheme(),\n\t\tcompaction: manager.getCompactionSettings(),\n\t\tretry: manager.getRetrySettings(),\n\t\thideThinkingBlock: manager.getHideThinkingBlock(),\n\t\tshellPath: manager.getShellPath(),\n\t\tcollapseChangelog: manager.getCollapseChangelog(),\n\t\thooks: manager.getHookPaths(),\n\t\thookTimeout: manager.getHookTimeout(),\n\t\tcustomTools: manager.getCustomToolPaths(),\n\t\tskills: manager.getSkillsSettings(),\n\t\tterminal: { showImages: manager.getShowImages() },\n\t};\n}\n\n// Internal Helpers\n\n/**\n * Create a HookFactory from a LoadedHook.\n * This allows mixing discovered hooks with inline hooks.\n */\nfunction createFactoryFromLoadedHook(loaded: LoadedHook): HookFactory {\n\treturn (api) => {\n\t\tfor (const [eventType, handlers] of loaded.handlers) {\n\t\t\tfor (const handler of handlers) {\n\t\t\t\tapi.on(eventType as any, handler as any);\n\t\t\t}\n\t\t}\n\t};\n}\n\n/**\n * Convert hook definitions to LoadedHooks for the HookRunner.\n */\nfunction createLoadedHooksFromDefinitions(definitions: Array<{ path?: string; factory: HookFactory }>): LoadedHook[] {\n\treturn definitions.map((def) => {\n\t\tconst handlers = new Map<string, Array<(...args: unknown[]) => Promise<unknown>>>();\n\t\tlet sendHandler: (text: string, attachments?: any[]) => void = () => {};\n\n\t\tconst api = {\n\t\t\ton: (event: string, handler: (...args: unknown[]) => Promise<unknown>) => {\n\t\t\t\tconst list = handlers.get(event) ?? [];\n\t\t\t\tlist.push(handler);\n\t\t\t\thandlers.set(event, list);\n\t\t\t},\n\t\t\tsend: (text: string, attachments?: any[]) => {\n\t\t\t\tsendHandler(text, attachments);\n\t\t\t},\n\t\t};\n\n\t\tdef.factory(api as any);\n\n\t\treturn {\n\t\t\tpath: def.path ?? \"<inline>\",\n\t\t\tresolvedPath: def.path ?? \"<inline>\",\n\t\t\thandlers,\n\t\t\tsetSendHandler: (handler: (text: string, attachments?: any[]) => void) => {\n\t\t\t\tsendHandler = handler;\n\t\t\t},\n\t\t};\n\t});\n}\n\n// Factory\n\n/**\n * Create an AgentSession with the specified options.\n *\n * @example\n * ```typescript\n * // Minimal - uses defaults\n * const { session } = await createAgentSession();\n *\n * // With explicit model\n * const { session } = await createAgentSession({\n * model: findModel('anthropic', 'claude-sonnet-4-20250514'),\n * thinkingLevel: 'high',\n * });\n *\n * // Continue previous session\n * const { session, modelFallbackMessage } = await createAgentSession({\n * continueSession: true,\n * });\n *\n * // Full control\n * const { session } = await createAgentSession({\n * model: myModel,\n * getApiKey: async () => process.env.MY_KEY,\n * systemPrompt: 'You are helpful.',\n * tools: [readTool, bashTool],\n * hooks: [],\n * skills: [],\n * sessionManager: SessionManager.inMemory(),\n * });\n * ```\n */\nexport async function createAgentSession(options: CreateAgentSessionOptions = {}): Promise<CreateAgentSessionResult> {\n\tconst cwd = options.cwd ?? process.cwd();\n\tconst agentDir = options.agentDir ?? getDefaultAgentDir();\n\n\t// Configure OAuth storage for this agentDir\n\tconfigureOAuthStorage(agentDir);\n\ttime(\"configureOAuthStorage\");\n\n\tconst settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);\n\ttime(\"settingsManager\");\n\tconst sessionManager = options.sessionManager ?? SessionManager.create(cwd, agentDir);\n\ttime(\"sessionManager\");\n\n\t// Check if session has existing data to restore\n\tconst existingSession = sessionManager.loadSession();\n\ttime(\"loadSession\");\n\tconst hasExistingSession = existingSession.messages.length > 0;\n\n\tlet model = options.model;\n\tlet modelFallbackMessage: string | undefined;\n\n\t// If session has data, try to restore model from it\n\tif (!model && hasExistingSession && existingSession.model) {\n\t\tconst restoredModel = findModel(existingSession.model.provider, existingSession.model.modelId);\n\t\tif (restoredModel) {\n\t\t\tconst key = await getApiKeyForModel(restoredModel);\n\t\t\tif (key) {\n\t\t\t\tmodel = restoredModel;\n\t\t\t}\n\t\t}\n\t\tif (!model) {\n\t\t\tmodelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;\n\t\t}\n\t}\n\n\t// If still no model, try settings default\n\tif (!model) {\n\t\tconst defaultProvider = settingsManager.getDefaultProvider();\n\t\tconst defaultModelId = settingsManager.getDefaultModel();\n\t\tif (defaultProvider && defaultModelId) {\n\t\t\tconst settingsModel = findModel(defaultProvider, defaultModelId);\n\t\t\tif (settingsModel) {\n\t\t\t\tconst key = await getApiKeyForModel(settingsModel);\n\t\t\t\tif (key) {\n\t\t\t\t\tmodel = settingsModel;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Fall back to first available\n\tif (!model) {\n\t\tconst available = await discoverAvailableModels();\n\t\ttime(\"discoverAvailableModels\");\n\t\tif (available.length === 0) {\n\t\t\tthrow new Error(\n\t\t\t\t\"No models available. Set an API key environment variable \" +\n\t\t\t\t\t\"(ANTHROPIC_API_KEY, OPENAI_API_KEY, etc.) or provide a model explicitly.\",\n\t\t\t);\n\t\t}\n\t\tmodel = available[0];\n\t\tif (modelFallbackMessage) {\n\t\t\tmodelFallbackMessage += `. Using ${model.provider}/${model.id}`;\n\t\t}\n\t}\n\n\tlet thinkingLevel = options.thinkingLevel;\n\n\t// If session has data, restore thinking level from it\n\tif (thinkingLevel === undefined && hasExistingSession) {\n\t\tthinkingLevel = existingSession.thinkingLevel as ThinkingLevel;\n\t}\n\n\t// Fall back to settings default\n\tif (thinkingLevel === undefined) {\n\t\tthinkingLevel = settingsManager.getDefaultThinkingLevel() ?? \"off\";\n\t}\n\n\t// Clamp to model capabilities\n\tif (!model.reasoning) {\n\t\tthinkingLevel = \"off\";\n\t}\n\n\tconst getApiKey = options.getApiKey ?? defaultGetApiKey();\n\n\tconst skills = options.skills ?? discoverSkills(cwd, agentDir, settingsManager.getSkillsSettings());\n\ttime(\"discoverSkills\");\n\n\tconst contextFiles = options.contextFiles ?? discoverContextFiles(cwd, agentDir);\n\ttime(\"discoverContextFiles\");\n\n\tconst builtInTools = options.tools ?? createCodingTools(cwd);\n\ttime(\"createCodingTools\");\n\n\tlet customToolsResult: { tools: LoadedCustomTool[]; setUIContext: (ctx: any, hasUI: boolean) => void };\n\tif (options.customTools !== undefined) {\n\t\t// Use provided custom tools\n\t\tconst loadedTools: LoadedCustomTool[] = options.customTools.map((ct) => ({\n\t\t\tpath: ct.path ?? \"<inline>\",\n\t\t\tresolvedPath: ct.path ?? \"<inline>\",\n\t\t\ttool: ct.tool,\n\t\t}));\n\t\tcustomToolsResult = {\n\t\t\ttools: loadedTools,\n\t\t\tsetUIContext: () => {},\n\t\t};\n\t} else {\n\t\t// Discover custom tools, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getCustomToolPaths(), ...(options.additionalCustomToolPaths ?? [])];\n\t\tconst result = await discoverAndLoadCustomTools(configuredPaths, cwd, Object.keys(allTools), agentDir);\n\t\ttime(\"discoverAndLoadCustomTools\");\n\t\tfor (const { path, error } of result.errors) {\n\t\t\tconsole.error(`Failed to load custom tool \"${path}\": ${error}`);\n\t\t}\n\t\tcustomToolsResult = result;\n\t}\n\n\tlet hookRunner: HookRunner | null = null;\n\tif (options.hooks !== undefined) {\n\t\tif (options.hooks.length > 0) {\n\t\t\tconst loadedHooks = createLoadedHooksFromDefinitions(options.hooks);\n\t\t\thookRunner = new HookRunner(loadedHooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t} else {\n\t\t// Discover hooks, merging with additional paths\n\t\tconst configuredPaths = [...settingsManager.getHookPaths(), ...(options.additionalHookPaths ?? [])];\n\t\tconst { hooks, errors } = await discoverAndLoadHooks(configuredPaths, cwd, agentDir);\n\t\ttime(\"discoverAndLoadHooks\");\n\t\tfor (const { path, error } of errors) {\n\t\t\tconsole.error(`Failed to load hook \"${path}\": ${error}`);\n\t\t}\n\t\tif (hooks.length > 0) {\n\t\t\thookRunner = new HookRunner(hooks, cwd, settingsManager.getHookTimeout());\n\t\t}\n\t}\n\n\tlet allToolsArray: Tool[] = [...builtInTools, ...customToolsResult.tools.map((lt) => lt.tool as unknown as Tool)];\n\ttime(\"combineTools\");\n\tif (hookRunner) {\n\t\tallToolsArray = wrapToolsWithHooks(allToolsArray, hookRunner) as Tool[];\n\t}\n\n\tlet systemPrompt: string;\n\tconst defaultPrompt = buildSystemPromptInternal({\n\t\tcwd,\n\t\tagentDir,\n\t\tskills,\n\t\tcontextFiles,\n\t});\n\ttime(\"buildSystemPrompt\");\n\n\tif (options.systemPrompt === undefined) {\n\t\tsystemPrompt = defaultPrompt;\n\t} else if (typeof options.systemPrompt === \"string\") {\n\t\tsystemPrompt = options.systemPrompt;\n\t} else {\n\t\tsystemPrompt = options.systemPrompt(defaultPrompt);\n\t}\n\n\tconst slashCommands = options.slashCommands ?? discoverSlashCommands(cwd, agentDir);\n\ttime(\"discoverSlashCommands\");\n\n\tconst agent = new Agent({\n\t\tinitialState: {\n\t\t\tsystemPrompt,\n\t\t\tmodel,\n\t\t\tthinkingLevel,\n\t\t\ttools: allToolsArray,\n\t\t},\n\t\tmessageTransformer,\n\t\tqueueMode: settingsManager.getQueueMode(),\n\t\ttransport: new ProviderTransport({\n\t\t\tgetApiKey: async () => {\n\t\t\t\tconst currentModel = agent.state.model;\n\t\t\t\tif (!currentModel) {\n\t\t\t\t\tthrow new Error(\"No model selected\");\n\t\t\t\t}\n\t\t\t\tconst key = await getApiKey(currentModel);\n\t\t\t\tif (!key) {\n\t\t\t\t\tthrow new Error(`No API key found for provider \"${currentModel.provider}\"`);\n\t\t\t\t}\n\t\t\t\treturn key;\n\t\t\t},\n\t\t}),\n\t});\n\ttime(\"createAgent\");\n\n\t// Restore messages if session has existing data\n\tif (hasExistingSession) {\n\t\tagent.replaceMessages(existingSession.messages);\n\t}\n\n\tconst session = new AgentSession({\n\t\tagent,\n\t\tsessionManager,\n\t\tsettingsManager,\n\t\tscopedModels: options.scopedModels,\n\t\tfileCommands: slashCommands,\n\t\thookRunner,\n\t\tcustomTools: customToolsResult.tools,\n\t\tskillsSettings: settingsManager.getSkillsSettings(),\n\t});\n\ttime(\"createAgentSession\");\n\n\treturn {\n\t\tsession,\n\t\tcustomToolsResult,\n\t\tmodelFallbackMessage,\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAqB5D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,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;CACf;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CACzB;AAwGD,MAAM,WAAW,wBAAwB;IACxC,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AA8GD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAuB7D;AAWD,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACxD,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA+E5E","sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { minimatch } from \"minimatch\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\n\n/**\n * Standard frontmatter fields per Agent Skills spec.\n * See: https://agentskills.io/specification#frontmatter-required\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]);\n\n/** Max name length per spec */\nconst MAX_NAME_LENGTH = 64;\n\n/** Max description length per spec */\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\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}\n\nexport interface SkillWarning {\n\tskillPath: string;\n\tmessage: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\twarnings: SkillWarning[];\n}\n\ntype SkillFormat = \"recursive\" | \"claude\";\n\nfunction stripQuotes(value: string): string {\n\tif ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nfunction parseFrontmatter(content: string): { frontmatter: SkillFrontmatter; body: string; allKeys: string[] } {\n\tconst frontmatter: SkillFrontmatter = {};\n\tconst allKeys: string[] = [];\n\n\tconst normalizedContent = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n\tif (!normalizedContent.startsWith(\"---\")) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst endIndex = normalizedContent.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst frontmatterBlock = normalizedContent.slice(4, endIndex);\n\tconst body = normalizedContent.slice(endIndex + 4).trim();\n\n\tfor (const line of frontmatterBlock.split(\"\\n\")) {\n\t\tconst match = line.match(/^(\\w[\\w-]*):\\s*(.*)$/);\n\t\tif (match) {\n\t\t\tconst key = match[1];\n\t\t\tconst value = stripQuotes(match[2].trim());\n\t\t\tallKeys.push(key);\n\t\t\tif (key === \"name\") {\n\t\t\t\tfrontmatter.name = value;\n\t\t\t} else if (key === \"description\") {\n\t\t\t\tfrontmatter.description = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { frontmatter, body, allKeys };\n}\n\n/**\n * Validate skill name per Agent Skills spec.\n * Returns array of validation error messages (empty if valid).\n */\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\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\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate description per Agent Skills spec.\n */\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\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\n\treturn errors;\n}\n\n/**\n * Check for unknown frontmatter fields.\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\nexport interface LoadSkillsFromDirOptions {\n\t/** Directory to scan for skills */\n\tdir: string;\n\t/** Source identifier for these skills */\n\tsource: string;\n}\n\n/**\n * Load skills from a directory recursively.\n * Skills are directories containing a SKILL.md file with frontmatter including a description.\n */\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, \"recursive\");\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, format: SkillFormat): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst warnings: SkillWarning[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, warnings };\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(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tif (format === \"recursive\") {\n\t\t\t\t// Recursive format: scan directories, look for SKILL.md files\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, format);\n\t\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\t\twarnings.push(...subResult.warnings);\n\t\t\t\t} else if (entry.isFile() && entry.name === \"SKILL.md\") {\n\t\t\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\t\t\tif (result.skill) {\n\t\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t\t}\n\t\t\t\t\twarnings.push(...result.warnings);\n\t\t\t\t}\n\t\t\t} else if (format === \"claude\") {\n\t\t\t\t// Claude format: only one level deep, each directory must contain SKILL.md\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst skillFile = join(fullPath, \"SKILL.md\");\n\t\t\t\tif (!existsSync(skillFile)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = loadSkillFromFile(skillFile, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t}\n\t\t\t\twarnings.push(...result.warnings);\n\t\t\t}\n\t\t}\n\t} catch {}\n\n\treturn { skills, warnings };\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; warnings: SkillWarning[] } {\n\tconst warnings: SkillWarning[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, allKeys } = parseFrontmatter(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\t// Validate frontmatter fields\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Validate description\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Use name from frontmatter, or fall back to parent directory name\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\t// Validate name\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Still load the skill even with warnings (unless description is completely missing)\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, warnings };\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},\n\t\t\twarnings,\n\t\t};\n\t} catch {\n\t\treturn { skill: null, warnings };\n\t}\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n * See: https://agentskills.io/integrate-skills\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tif (skills.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\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of skills) {\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\nexport interface LoadSkillsOptions extends SkillsSettings {\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}\n\n/**\n * Load skills from all configured locations.\n * Returns skills and any validation warnings.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst {\n\t\tcwd = process.cwd(),\n\t\tagentDir,\n\t\tenableCodexUser = true,\n\t\tenableClaudeUser = true,\n\t\tenableClaudeProject = true,\n\t\tenablePiUser = true,\n\t\tenablePiProject = true,\n\t\tcustomDirectories = [],\n\t\tignoredSkills = [],\n\t\tincludeSkills = [],\n\t} = options;\n\n\t// Resolve agentDir - if not provided, use default from config\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst allWarnings: SkillWarning[] = [];\n\tconst collisionWarnings: SkillWarning[] = [];\n\n\t// Check if skill name matches any of the include patterns\n\tfunction matchesIncludePatterns(name: string): boolean {\n\t\tif (includeSkills.length === 0) return true; // No filter = include all\n\t\treturn includeSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\t// Check if skill name matches any of the ignore patterns\n\tfunction matchesIgnorePatterns(name: string): boolean {\n\t\tif (ignoredSkills.length === 0) return false;\n\t\treturn ignoredSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallWarnings.push(...result.warnings);\n\t\tfor (const skill of result.skills) {\n\t\t\t// Apply ignore filter (glob patterns) - takes precedence over include\n\t\t\tif (matchesIgnorePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Apply include filter (glob patterns)\n\t\t\tif (!matchesIncludePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionWarnings.push({\n\t\t\t\t\tskillPath: skill.filePath,\n\t\t\t\t\tmessage: `name collision: \"${skill.name}\" already loaded from ${existing.filePath}, skipping this one`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (enableCodexUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".codex\", \"skills\"), \"codex-user\", \"recursive\"));\n\t}\n\tif (enableClaudeUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".claude\", \"skills\"), \"claude-user\", \"claude\"));\n\t}\n\tif (enableClaudeProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, \".claude\", \"skills\"), \"claude-project\", \"claude\"));\n\t}\n\tif (enablePiUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", \"recursive\"));\n\t}\n\tif (enablePiProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", \"recursive\"));\n\t}\n\tfor (const customDir of customDirectories) {\n\t\taddSkills(loadSkillsFromDirInternal(customDir.replace(/^~(?=$|[\\\\/])/, homedir()), \"custom\", \"recursive\"));\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\twarnings: [...allWarnings, ...collisionWarnings],\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAqB5D,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,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;CACf;AAED,MAAM,WAAW,YAAY;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,YAAY,EAAE,CAAC;CACzB;AAwGD,MAAM,WAAW,wBAAwB;IACxC,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,yCAAyC;IACzC,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAGrF;AAmHD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAuB7D;AAWD,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACxD,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,OAAO,GAAE,iBAAsB,GAAG,gBAAgB,CA+E5E","sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { minimatch } from \"minimatch\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\n\n/**\n * Standard frontmatter fields per Agent Skills spec.\n * See: https://agentskills.io/specification#frontmatter-required\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]);\n\n/** Max name length per spec */\nconst MAX_NAME_LENGTH = 64;\n\n/** Max description length per spec */\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\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}\n\nexport interface SkillWarning {\n\tskillPath: string;\n\tmessage: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\twarnings: SkillWarning[];\n}\n\ntype SkillFormat = \"recursive\" | \"claude\";\n\nfunction stripQuotes(value: string): string {\n\tif ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nfunction parseFrontmatter(content: string): { frontmatter: SkillFrontmatter; body: string; allKeys: string[] } {\n\tconst frontmatter: SkillFrontmatter = {};\n\tconst allKeys: string[] = [];\n\n\tconst normalizedContent = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n\tif (!normalizedContent.startsWith(\"---\")) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst endIndex = normalizedContent.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst frontmatterBlock = normalizedContent.slice(4, endIndex);\n\tconst body = normalizedContent.slice(endIndex + 4).trim();\n\n\tfor (const line of frontmatterBlock.split(\"\\n\")) {\n\t\tconst match = line.match(/^(\\w[\\w-]*):\\s*(.*)$/);\n\t\tif (match) {\n\t\t\tconst key = match[1];\n\t\t\tconst value = stripQuotes(match[2].trim());\n\t\t\tallKeys.push(key);\n\t\t\tif (key === \"name\") {\n\t\t\t\tfrontmatter.name = value;\n\t\t\t} else if (key === \"description\") {\n\t\t\t\tfrontmatter.description = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { frontmatter, body, allKeys };\n}\n\n/**\n * Validate skill name per Agent Skills spec.\n * Returns array of validation error messages (empty if valid).\n */\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\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\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate description per Agent Skills spec.\n */\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\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\n\treturn errors;\n}\n\n/**\n * Check for unknown frontmatter fields.\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\nexport interface LoadSkillsFromDirOptions {\n\t/** Directory to scan for skills */\n\tdir: string;\n\t/** Source identifier for these skills */\n\tsource: string;\n}\n\n/**\n * Load skills from a directory recursively.\n * Skills are directories containing a SKILL.md file with frontmatter including a description.\n */\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, \"recursive\");\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, format: SkillFormat): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst warnings: SkillWarning[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, warnings };\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(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Skip node_modules to avoid scanning dependencies\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tif (format === \"recursive\") {\n\t\t\t\t// Recursive format: scan directories, look for SKILL.md files\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, format);\n\t\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\t\twarnings.push(...subResult.warnings);\n\t\t\t\t} else if (entry.isFile() && entry.name === \"SKILL.md\") {\n\t\t\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\t\t\tif (result.skill) {\n\t\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t\t}\n\t\t\t\t\twarnings.push(...result.warnings);\n\t\t\t\t}\n\t\t\t} else if (format === \"claude\") {\n\t\t\t\t// Claude format: only one level deep, each directory must contain SKILL.md\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst skillFile = join(fullPath, \"SKILL.md\");\n\t\t\t\tif (!existsSync(skillFile)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = loadSkillFromFile(skillFile, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t}\n\t\t\t\twarnings.push(...result.warnings);\n\t\t\t}\n\t\t}\n\t} catch {}\n\n\treturn { skills, warnings };\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; warnings: SkillWarning[] } {\n\tconst warnings: SkillWarning[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, allKeys } = parseFrontmatter(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\t// Validate frontmatter fields\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Validate description\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Use name from frontmatter, or fall back to parent directory name\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\t// Validate name\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Still load the skill even with warnings (unless description is completely missing)\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, warnings };\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},\n\t\t\twarnings,\n\t\t};\n\t} catch {\n\t\treturn { skill: null, warnings };\n\t}\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n * See: https://agentskills.io/integrate-skills\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tif (skills.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\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of skills) {\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\nexport interface LoadSkillsOptions extends SkillsSettings {\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}\n\n/**\n * Load skills from all configured locations.\n * Returns skills and any validation warnings.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst {\n\t\tcwd = process.cwd(),\n\t\tagentDir,\n\t\tenableCodexUser = true,\n\t\tenableClaudeUser = true,\n\t\tenableClaudeProject = true,\n\t\tenablePiUser = true,\n\t\tenablePiProject = true,\n\t\tcustomDirectories = [],\n\t\tignoredSkills = [],\n\t\tincludeSkills = [],\n\t} = options;\n\n\t// Resolve agentDir - if not provided, use default from config\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst allWarnings: SkillWarning[] = [];\n\tconst collisionWarnings: SkillWarning[] = [];\n\n\t// Check if skill name matches any of the include patterns\n\tfunction matchesIncludePatterns(name: string): boolean {\n\t\tif (includeSkills.length === 0) return true; // No filter = include all\n\t\treturn includeSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\t// Check if skill name matches any of the ignore patterns\n\tfunction matchesIgnorePatterns(name: string): boolean {\n\t\tif (ignoredSkills.length === 0) return false;\n\t\treturn ignoredSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallWarnings.push(...result.warnings);\n\t\tfor (const skill of result.skills) {\n\t\t\t// Apply ignore filter (glob patterns) - takes precedence over include\n\t\t\tif (matchesIgnorePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Apply include filter (glob patterns)\n\t\t\tif (!matchesIncludePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionWarnings.push({\n\t\t\t\t\tskillPath: skill.filePath,\n\t\t\t\t\tmessage: `name collision: \"${skill.name}\" already loaded from ${existing.filePath}, skipping this one`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (enableCodexUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".codex\", \"skills\"), \"codex-user\", \"recursive\"));\n\t}\n\tif (enableClaudeUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".claude\", \"skills\"), \"claude-user\", \"claude\"));\n\t}\n\tif (enableClaudeProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, \".claude\", \"skills\"), \"claude-project\", \"claude\"));\n\t}\n\tif (enablePiUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", \"recursive\"));\n\t}\n\tif (enablePiProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", \"recursive\"));\n\t}\n\tfor (const customDir of customDirectories) {\n\t\taddSkills(loadSkillsFromDirInternal(customDir.replace(/^~(?=$|[\\\\/])/, homedir()), \"custom\", \"recursive\"));\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\twarnings: [...allWarnings, ...collisionWarnings],\n\t};\n}\n"]}
|
package/dist/core/skills.js
CHANGED
|
@@ -122,6 +122,10 @@ function loadSkillsFromDirInternal(dir, source, format) {
|
|
|
122
122
|
if (entry.name.startsWith(".")) {
|
|
123
123
|
continue;
|
|
124
124
|
}
|
|
125
|
+
// Skip node_modules to avoid scanning dependencies
|
|
126
|
+
if (entry.name === "node_modules") {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
125
129
|
if (entry.isSymbolicLink()) {
|
|
126
130
|
continue;
|
|
127
131
|
}
|
package/dist/core/skills.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { minimatch } from \"minimatch\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\n\n/**\n * Standard frontmatter fields per Agent Skills spec.\n * See: https://agentskills.io/specification#frontmatter-required\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]);\n\n/** Max name length per spec */\nconst MAX_NAME_LENGTH = 64;\n\n/** Max description length per spec */\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\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}\n\nexport interface SkillWarning {\n\tskillPath: string;\n\tmessage: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\twarnings: SkillWarning[];\n}\n\ntype SkillFormat = \"recursive\" | \"claude\";\n\nfunction stripQuotes(value: string): string {\n\tif ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nfunction parseFrontmatter(content: string): { frontmatter: SkillFrontmatter; body: string; allKeys: string[] } {\n\tconst frontmatter: SkillFrontmatter = {};\n\tconst allKeys: string[] = [];\n\n\tconst normalizedContent = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n\tif (!normalizedContent.startsWith(\"---\")) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst endIndex = normalizedContent.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst frontmatterBlock = normalizedContent.slice(4, endIndex);\n\tconst body = normalizedContent.slice(endIndex + 4).trim();\n\n\tfor (const line of frontmatterBlock.split(\"\\n\")) {\n\t\tconst match = line.match(/^(\\w[\\w-]*):\\s*(.*)$/);\n\t\tif (match) {\n\t\t\tconst key = match[1];\n\t\t\tconst value = stripQuotes(match[2].trim());\n\t\t\tallKeys.push(key);\n\t\t\tif (key === \"name\") {\n\t\t\t\tfrontmatter.name = value;\n\t\t\t} else if (key === \"description\") {\n\t\t\t\tfrontmatter.description = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { frontmatter, body, allKeys };\n}\n\n/**\n * Validate skill name per Agent Skills spec.\n * Returns array of validation error messages (empty if valid).\n */\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\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\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate description per Agent Skills spec.\n */\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\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\n\treturn errors;\n}\n\n/**\n * Check for unknown frontmatter fields.\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\nexport interface LoadSkillsFromDirOptions {\n\t/** Directory to scan for skills */\n\tdir: string;\n\t/** Source identifier for these skills */\n\tsource: string;\n}\n\n/**\n * Load skills from a directory recursively.\n * Skills are directories containing a SKILL.md file with frontmatter including a description.\n */\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, \"recursive\");\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, format: SkillFormat): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst warnings: SkillWarning[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, warnings };\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(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tif (format === \"recursive\") {\n\t\t\t\t// Recursive format: scan directories, look for SKILL.md files\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, format);\n\t\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\t\twarnings.push(...subResult.warnings);\n\t\t\t\t} else if (entry.isFile() && entry.name === \"SKILL.md\") {\n\t\t\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\t\t\tif (result.skill) {\n\t\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t\t}\n\t\t\t\t\twarnings.push(...result.warnings);\n\t\t\t\t}\n\t\t\t} else if (format === \"claude\") {\n\t\t\t\t// Claude format: only one level deep, each directory must contain SKILL.md\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst skillFile = join(fullPath, \"SKILL.md\");\n\t\t\t\tif (!existsSync(skillFile)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = loadSkillFromFile(skillFile, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t}\n\t\t\t\twarnings.push(...result.warnings);\n\t\t\t}\n\t\t}\n\t} catch {}\n\n\treturn { skills, warnings };\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; warnings: SkillWarning[] } {\n\tconst warnings: SkillWarning[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, allKeys } = parseFrontmatter(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\t// Validate frontmatter fields\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Validate description\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Use name from frontmatter, or fall back to parent directory name\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\t// Validate name\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Still load the skill even with warnings (unless description is completely missing)\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, warnings };\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},\n\t\t\twarnings,\n\t\t};\n\t} catch {\n\t\treturn { skill: null, warnings };\n\t}\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n * See: https://agentskills.io/integrate-skills\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tif (skills.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\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of skills) {\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\nexport interface LoadSkillsOptions extends SkillsSettings {\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}\n\n/**\n * Load skills from all configured locations.\n * Returns skills and any validation warnings.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst {\n\t\tcwd = process.cwd(),\n\t\tagentDir,\n\t\tenableCodexUser = true,\n\t\tenableClaudeUser = true,\n\t\tenableClaudeProject = true,\n\t\tenablePiUser = true,\n\t\tenablePiProject = true,\n\t\tcustomDirectories = [],\n\t\tignoredSkills = [],\n\t\tincludeSkills = [],\n\t} = options;\n\n\t// Resolve agentDir - if not provided, use default from config\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst allWarnings: SkillWarning[] = [];\n\tconst collisionWarnings: SkillWarning[] = [];\n\n\t// Check if skill name matches any of the include patterns\n\tfunction matchesIncludePatterns(name: string): boolean {\n\t\tif (includeSkills.length === 0) return true; // No filter = include all\n\t\treturn includeSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\t// Check if skill name matches any of the ignore patterns\n\tfunction matchesIgnorePatterns(name: string): boolean {\n\t\tif (ignoredSkills.length === 0) return false;\n\t\treturn ignoredSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallWarnings.push(...result.warnings);\n\t\tfor (const skill of result.skills) {\n\t\t\t// Apply ignore filter (glob patterns) - takes precedence over include\n\t\t\tif (matchesIgnorePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Apply include filter (glob patterns)\n\t\t\tif (!matchesIncludePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionWarnings.push({\n\t\t\t\t\tskillPath: skill.filePath,\n\t\t\t\t\tmessage: `name collision: \"${skill.name}\" already loaded from ${existing.filePath}, skipping this one`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (enableCodexUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".codex\", \"skills\"), \"codex-user\", \"recursive\"));\n\t}\n\tif (enableClaudeUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".claude\", \"skills\"), \"claude-user\", \"claude\"));\n\t}\n\tif (enableClaudeProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, \".claude\", \"skills\"), \"claude-project\", \"claude\"));\n\t}\n\tif (enablePiUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", \"recursive\"));\n\t}\n\tif (enablePiProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", \"recursive\"));\n\t}\n\tfor (const customDir of customDirectories) {\n\t\taddSkills(loadSkillsFromDirInternal(customDir.replace(/^~(?=$|[\\\\/])/, homedir()), \"custom\", \"recursive\"));\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\twarnings: [...allWarnings, ...collisionWarnings],\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/core/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG5D;;;GAGG;AACH,MAAM,0BAA0B,GAAG,IAAI,GAAG,CAAC;IAC1C,MAAM;IACN,aAAa;IACb,SAAS;IACT,eAAe;IACf,UAAU;IACV,eAAe;CACf,CAAC,CAAC;AAEH,+BAA+B;AAC/B,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,sCAAsC;AACtC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AA4BpC,SAAS,WAAW,CAAC,KAAa,EAAU;IAC3C,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACtG,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAsE;IAC9G,MAAM,WAAW,GAAqB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,MAAM,iBAAiB,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAE9E,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,QAAQ,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACvD,IAAI,QAAQ,KAAK,CAAC,CAAC,EAAE,CAAC;QACrB,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC;IAC1D,CAAC;IAED,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;IAC9D,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAE1D,KAAK,MAAM,IAAI,IAAI,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QACjD,IAAI,KAAK,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACrB,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;gBACpB,WAAW,CAAC,IAAI,GAAG,KAAK,CAAC;YAC1B,CAAC;iBAAM,IAAI,GAAG,KAAK,aAAa,EAAE,CAAC;gBAClC,WAAW,CAAC,WAAW,GAAG,KAAK,CAAC;YACjC,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AAAA,CACtC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,IAAY,EAAE,aAAqB,EAAY;IACpE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;QAC5B,MAAM,CAAC,IAAI,CAAC,SAAS,IAAI,sCAAsC,aAAa,GAAG,CAAC,CAAC;IAClF,CAAC;IAED,IAAI,IAAI,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QACnC,MAAM,CAAC,IAAI,CAAC,gBAAgB,eAAe,gBAAgB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5E,CAAC;IAED,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;IAC5F,CAAC;IAED,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAChD,MAAM,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACd;AAED;;GAEG;AACH,SAAS,mBAAmB,CAAC,WAA+B,EAAY;IACvE,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,IAAI,CAAC,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,WAAW,CAAC,MAAM,GAAG,sBAAsB,EAAE,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,uBAAuB,sBAAsB,gBAAgB,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC;IACjG,CAAC;IAED,OAAO,MAAM,CAAC;AAAA,CACd;AAED;;GAEG;AACH,SAAS,yBAAyB,CAAC,IAAc,EAAY;IAC5D,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,CAAC,0BAA0B,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,8BAA8B,GAAG,GAAG,CAAC,CAAC;QACnD,CAAC;IACF,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AASD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAiC,EAAoB;IACtF,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IAChC,OAAO,yBAAyB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC;AAAA,CAC3D;AAED,SAAS,yBAAyB,CAAC,GAAW,EAAE,MAAc,EAAE,MAAmB,EAAoB;IACtG,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;gBAChC,SAAS;YACV,CAAC;YAED,mDAAmD;YACnD,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;gBACnC,SAAS;YACV,CAAC;YAED,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC5B,SAAS;YACV,CAAC;YAED,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAEvC,IAAI,MAAM,KAAK,WAAW,EAAE,CAAC;gBAC5B,8DAA8D;gBAC9D,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBACzB,MAAM,SAAS,GAAG,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;oBACtE,MAAM,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;oBACjC,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;gBACtC,CAAC;qBAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;oBACxD,MAAM,MAAM,GAAG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBACnD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;wBAClB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBAC3B,CAAC;oBACD,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;gBACnC,CAAC;YACF,CAAC;iBAAM,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,2EAA2E;gBAC3E,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;oBAC1B,SAAS;gBACV,CAAC;gBAED,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAC7C,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;oBAC5B,SAAS;gBACV,CAAC;gBAED,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBACpD,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBAClB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC3B,CAAC;gBACD,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnC,CAAC;QACF,CAAC;IACF,CAAC;IAAC,MAAM,CAAC,CAAA,CAAC;IAEV,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;AAAA,CAC5B;AAED,SAAS,iBAAiB,CAAC,QAAgB,EAAE,MAAc,EAAqD;IAC/G,MAAM,QAAQ,GAAmB,EAAE,CAAC;IAEpC,IAAI,CAAC;QACJ,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAC;QAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,aAAa,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEzC,8BAA8B;QAC9B,MAAM,WAAW,GAAG,yBAAyB,CAAC,OAAO,CAAC,CAAC;QACvD,KAAK,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,uBAAuB;QACvB,MAAM,UAAU,GAAG,mBAAmB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC;QAChE,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,mEAAmE;QACnE,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,IAAI,aAAa,CAAC;QAE/C,gBAAgB;QAChB,MAAM,UAAU,GAAG,YAAY,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACrD,KAAK,MAAM,KAAK,IAAI,UAAU,EAAE,CAAC;YAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACxD,CAAC;QAED,qFAAqF;QACrF,IAAI,CAAC,WAAW,CAAC,WAAW,IAAI,WAAW,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YACvE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;QAClC,CAAC;QAED,OAAO;YACN,KAAK,EAAE;gBACN,IAAI;gBACJ,WAAW,EAAE,WAAW,CAAC,WAAW;gBACpC,QAAQ;gBACR,OAAO,EAAE,QAAQ;gBACjB,MAAM;aACN;YACD,QAAQ;SACR,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAClC,CAAC;AAAA,CACD;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAe,EAAU;IAC9D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,CAAC;IACX,CAAC;IAED,MAAM,KAAK,GAAG;QACb,+EAA+E;QAC/E,iFAAiF;QACjF,EAAE;QACF,oBAAoB;KACpB,CAAC;IAEF,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,aAAa,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACxD,KAAK,CAAC,IAAI,CAAC,oBAAoB,SAAS,CAAC,KAAK,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAC;QAC7E,KAAK,CAAC,IAAI,CAAC,iBAAiB,SAAS,CAAC,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACpE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IAElC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAAA,CACxB;AAED,SAAS,SAAS,CAAC,GAAW,EAAU;IACvC,OAAO,GAAG;SACR,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,CAC1B;AASD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,OAAO,GAAsB,EAAE,EAAoB;IAC7E,MAAM,EACL,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EACnB,QAAQ,EACR,eAAe,GAAG,IAAI,EACtB,gBAAgB,GAAG,IAAI,EACvB,mBAAmB,GAAG,IAAI,EAC1B,YAAY,GAAG,IAAI,EACnB,eAAe,GAAG,IAAI,EACtB,iBAAiB,GAAG,EAAE,EACtB,aAAa,GAAG,EAAE,EAClB,aAAa,GAAG,EAAE,GAClB,GAAG,OAAO,CAAC;IAEZ,8DAA8D;IAC9D,MAAM,gBAAgB,GAAG,QAAQ,IAAI,WAAW,EAAE,CAAC;IAEnD,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAiB,CAAC;IAC1C,MAAM,WAAW,GAAmB,EAAE,CAAC;IACvC,MAAM,iBAAiB,GAAmB,EAAE,CAAC;IAE7C,0DAA0D;IAC1D,SAAS,sBAAsB,CAAC,IAAY,EAAW;QACtD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,CAAC,0BAA0B;QACvE,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAAA,CACjE;IAED,yDAAyD;IACzD,SAAS,qBAAqB,CAAC,IAAY,EAAW;QACrD,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,KAAK,CAAC;QAC7C,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;IAAA,CACjE;IAED,SAAS,SAAS,CAAC,MAAwB,EAAE;QAC5C,WAAW,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;QACrC,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YACnC,sEAAsE;YACtE,IAAI,qBAAqB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACvC,SAAS;YACV,CAAC;YACD,uCAAuC;YACvC,IAAI,CAAC,sBAAsB,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACzC,SAAS;YACV,CAAC;YACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC1C,IAAI,QAAQ,EAAE,CAAC;gBACd,iBAAiB,CAAC,IAAI,CAAC;oBACtB,SAAS,EAAE,KAAK,CAAC,QAAQ;oBACzB,OAAO,EAAE,oBAAoB,KAAK,CAAC,IAAI,yBAAyB,QAAQ,CAAC,QAAQ,qBAAqB;iBACtG,CAAC,CAAC;YACJ,CAAC;iBAAM,CAAC;gBACP,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YACjC,CAAC;QACF,CAAC;IAAA,CACD;IAED,IAAI,eAAe,EAAE,CAAC;QACrB,SAAS,CAAC,yBAAyB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,gBAAgB,EAAE,CAAC;QACtB,SAAS,CAAC,yBAAyB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrG,CAAC;IACD,IAAI,mBAAmB,EAAE,CAAC;QACzB,SAAS,CAAC,yBAAyB,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAC;IACrG,CAAC;IACD,IAAI,YAAY,EAAE,CAAC;QAClB,SAAS,CAAC,yBAAyB,CAAC,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;IAC7F,CAAC;IACD,IAAI,eAAe,EAAE,CAAC;QACrB,SAAS,CAAC,yBAAyB,CAAC,OAAO,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC;IACvG,CAAC;IACD,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;QAC3C,SAAS,CAAC,yBAAyB,CAAC,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC;IAC5G,CAAC;IAED,OAAO;QACN,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;QACrC,QAAQ,EAAE,CAAC,GAAG,WAAW,EAAE,GAAG,iBAAiB,CAAC;KAChD,CAAC;AAAA,CACF","sourcesContent":["import { existsSync, readdirSync, readFileSync } from \"fs\";\nimport { minimatch } from \"minimatch\";\nimport { homedir } from \"os\";\nimport { basename, dirname, join, resolve } from \"path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\n\n/**\n * Standard frontmatter fields per Agent Skills spec.\n * See: https://agentskills.io/specification#frontmatter-required\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]);\n\n/** Max name length per spec */\nconst MAX_NAME_LENGTH = 64;\n\n/** Max description length per spec */\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\nexport interface SkillFrontmatter {\n\tname?: string;\n\tdescription?: string;\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}\n\nexport interface SkillWarning {\n\tskillPath: string;\n\tmessage: string;\n}\n\nexport interface LoadSkillsResult {\n\tskills: Skill[];\n\twarnings: SkillWarning[];\n}\n\ntype SkillFormat = \"recursive\" | \"claude\";\n\nfunction stripQuotes(value: string): string {\n\tif ((value.startsWith('\"') && value.endsWith('\"')) || (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n\t\treturn value.slice(1, -1);\n\t}\n\treturn value;\n}\n\nfunction parseFrontmatter(content: string): { frontmatter: SkillFrontmatter; body: string; allKeys: string[] } {\n\tconst frontmatter: SkillFrontmatter = {};\n\tconst allKeys: string[] = [];\n\n\tconst normalizedContent = content.replace(/\\r\\n/g, \"\\n\").replace(/\\r/g, \"\\n\");\n\n\tif (!normalizedContent.startsWith(\"---\")) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst endIndex = normalizedContent.indexOf(\"\\n---\", 3);\n\tif (endIndex === -1) {\n\t\treturn { frontmatter, body: normalizedContent, allKeys };\n\t}\n\n\tconst frontmatterBlock = normalizedContent.slice(4, endIndex);\n\tconst body = normalizedContent.slice(endIndex + 4).trim();\n\n\tfor (const line of frontmatterBlock.split(\"\\n\")) {\n\t\tconst match = line.match(/^(\\w[\\w-]*):\\s*(.*)$/);\n\t\tif (match) {\n\t\t\tconst key = match[1];\n\t\t\tconst value = stripQuotes(match[2].trim());\n\t\t\tallKeys.push(key);\n\t\t\tif (key === \"name\") {\n\t\t\t\tfrontmatter.name = value;\n\t\t\t} else if (key === \"description\") {\n\t\t\t\tfrontmatter.description = value;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { frontmatter, body, allKeys };\n}\n\n/**\n * Validate skill name per Agent Skills spec.\n * Returns array of validation error messages (empty if valid).\n */\nfunction validateName(name: string, parentDirName: string): string[] {\n\tconst errors: string[] = [];\n\n\tif (name !== parentDirName) {\n\t\terrors.push(`name \"${name}\" does not match parent directory \"${parentDirName}\"`);\n\t}\n\n\tif (name.length > MAX_NAME_LENGTH) {\n\t\terrors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n\t}\n\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\n\tif (name.startsWith(\"-\") || name.endsWith(\"-\")) {\n\t\terrors.push(`name must not start or end with a hyphen`);\n\t}\n\n\tif (name.includes(\"--\")) {\n\t\terrors.push(`name must not contain consecutive hyphens`);\n\t}\n\n\treturn errors;\n}\n\n/**\n * Validate description per Agent Skills spec.\n */\nfunction validateDescription(description: string | undefined): string[] {\n\tconst errors: string[] = [];\n\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\n\treturn errors;\n}\n\n/**\n * Check for unknown frontmatter fields.\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\nexport interface LoadSkillsFromDirOptions {\n\t/** Directory to scan for skills */\n\tdir: string;\n\t/** Source identifier for these skills */\n\tsource: string;\n}\n\n/**\n * Load skills from a directory recursively.\n * Skills are directories containing a SKILL.md file with frontmatter including a description.\n */\nexport function loadSkillsFromDir(options: LoadSkillsFromDirOptions): LoadSkillsResult {\n\tconst { dir, source } = options;\n\treturn loadSkillsFromDirInternal(dir, source, \"recursive\");\n}\n\nfunction loadSkillsFromDirInternal(dir: string, source: string, format: SkillFormat): LoadSkillsResult {\n\tconst skills: Skill[] = [];\n\tconst warnings: SkillWarning[] = [];\n\n\tif (!existsSync(dir)) {\n\t\treturn { skills, warnings };\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(\".\")) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Skip node_modules to avoid scanning dependencies\n\t\t\tif (entry.name === \"node_modules\") {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (entry.isSymbolicLink()) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst fullPath = join(dir, entry.name);\n\n\t\t\tif (format === \"recursive\") {\n\t\t\t\t// Recursive format: scan directories, look for SKILL.md files\n\t\t\t\tif (entry.isDirectory()) {\n\t\t\t\t\tconst subResult = loadSkillsFromDirInternal(fullPath, source, format);\n\t\t\t\t\tskills.push(...subResult.skills);\n\t\t\t\t\twarnings.push(...subResult.warnings);\n\t\t\t\t} else if (entry.isFile() && entry.name === \"SKILL.md\") {\n\t\t\t\t\tconst result = loadSkillFromFile(fullPath, source);\n\t\t\t\t\tif (result.skill) {\n\t\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t\t}\n\t\t\t\t\twarnings.push(...result.warnings);\n\t\t\t\t}\n\t\t\t} else if (format === \"claude\") {\n\t\t\t\t// Claude format: only one level deep, each directory must contain SKILL.md\n\t\t\t\tif (!entry.isDirectory()) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst skillFile = join(fullPath, \"SKILL.md\");\n\t\t\t\tif (!existsSync(skillFile)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst result = loadSkillFromFile(skillFile, source);\n\t\t\t\tif (result.skill) {\n\t\t\t\t\tskills.push(result.skill);\n\t\t\t\t}\n\t\t\t\twarnings.push(...result.warnings);\n\t\t\t}\n\t\t}\n\t} catch {}\n\n\treturn { skills, warnings };\n}\n\nfunction loadSkillFromFile(filePath: string, source: string): { skill: Skill | null; warnings: SkillWarning[] } {\n\tconst warnings: SkillWarning[] = [];\n\n\ttry {\n\t\tconst rawContent = readFileSync(filePath, \"utf-8\");\n\t\tconst { frontmatter, allKeys } = parseFrontmatter(rawContent);\n\t\tconst skillDir = dirname(filePath);\n\t\tconst parentDirName = basename(skillDir);\n\n\t\t// Validate frontmatter fields\n\t\tconst fieldErrors = validateFrontmatterFields(allKeys);\n\t\tfor (const error of fieldErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Validate description\n\t\tconst descErrors = validateDescription(frontmatter.description);\n\t\tfor (const error of descErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Use name from frontmatter, or fall back to parent directory name\n\t\tconst name = frontmatter.name || parentDirName;\n\n\t\t// Validate name\n\t\tconst nameErrors = validateName(name, parentDirName);\n\t\tfor (const error of nameErrors) {\n\t\t\twarnings.push({ skillPath: filePath, message: error });\n\t\t}\n\n\t\t// Still load the skill even with warnings (unless description is completely missing)\n\t\tif (!frontmatter.description || frontmatter.description.trim() === \"\") {\n\t\t\treturn { skill: null, warnings };\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},\n\t\t\twarnings,\n\t\t};\n\t} catch {\n\t\treturn { skill: null, warnings };\n\t}\n}\n\n/**\n * Format skills for inclusion in a system prompt.\n * Uses XML format per Agent Skills standard.\n * See: https://agentskills.io/integrate-skills\n */\nexport function formatSkillsForPrompt(skills: Skill[]): string {\n\tif (skills.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\"\",\n\t\t\"<available_skills>\",\n\t];\n\n\tfor (const skill of skills) {\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\nexport interface LoadSkillsOptions extends SkillsSettings {\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}\n\n/**\n * Load skills from all configured locations.\n * Returns skills and any validation warnings.\n */\nexport function loadSkills(options: LoadSkillsOptions = {}): LoadSkillsResult {\n\tconst {\n\t\tcwd = process.cwd(),\n\t\tagentDir,\n\t\tenableCodexUser = true,\n\t\tenableClaudeUser = true,\n\t\tenableClaudeProject = true,\n\t\tenablePiUser = true,\n\t\tenablePiProject = true,\n\t\tcustomDirectories = [],\n\t\tignoredSkills = [],\n\t\tincludeSkills = [],\n\t} = options;\n\n\t// Resolve agentDir - if not provided, use default from config\n\tconst resolvedAgentDir = agentDir ?? getAgentDir();\n\n\tconst skillMap = new Map<string, Skill>();\n\tconst allWarnings: SkillWarning[] = [];\n\tconst collisionWarnings: SkillWarning[] = [];\n\n\t// Check if skill name matches any of the include patterns\n\tfunction matchesIncludePatterns(name: string): boolean {\n\t\tif (includeSkills.length === 0) return true; // No filter = include all\n\t\treturn includeSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\t// Check if skill name matches any of the ignore patterns\n\tfunction matchesIgnorePatterns(name: string): boolean {\n\t\tif (ignoredSkills.length === 0) return false;\n\t\treturn ignoredSkills.some((pattern) => minimatch(name, pattern));\n\t}\n\n\tfunction addSkills(result: LoadSkillsResult) {\n\t\tallWarnings.push(...result.warnings);\n\t\tfor (const skill of result.skills) {\n\t\t\t// Apply ignore filter (glob patterns) - takes precedence over include\n\t\t\tif (matchesIgnorePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Apply include filter (glob patterns)\n\t\t\tif (!matchesIncludePatterns(skill.name)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst existing = skillMap.get(skill.name);\n\t\t\tif (existing) {\n\t\t\t\tcollisionWarnings.push({\n\t\t\t\t\tskillPath: skill.filePath,\n\t\t\t\t\tmessage: `name collision: \"${skill.name}\" already loaded from ${existing.filePath}, skipping this one`,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tskillMap.set(skill.name, skill);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (enableCodexUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".codex\", \"skills\"), \"codex-user\", \"recursive\"));\n\t}\n\tif (enableClaudeUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(homedir(), \".claude\", \"skills\"), \"claude-user\", \"claude\"));\n\t}\n\tif (enableClaudeProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, \".claude\", \"skills\"), \"claude-project\", \"claude\"));\n\t}\n\tif (enablePiUser) {\n\t\taddSkills(loadSkillsFromDirInternal(join(resolvedAgentDir, \"skills\"), \"user\", \"recursive\"));\n\t}\n\tif (enablePiProject) {\n\t\taddSkills(loadSkillsFromDirInternal(resolve(cwd, CONFIG_DIR_NAME, \"skills\"), \"project\", \"recursive\"));\n\t}\n\tfor (const customDir of customDirectories) {\n\t\taddSkills(loadSkillsFromDirInternal(customDir.replace(/^~(?=$|[\\\\/])/, homedir()), \"custom\", \"recursive\"));\n\t}\n\n\treturn {\n\t\tskills: Array.from(skillMap.values()),\n\t\twarnings: [...allWarnings, ...collisionWarnings],\n\t};\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAkDjD,MAAM,WAAW,uBAAuB;IACvC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,GAAE,uBAA4B,GACnC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAyC1C;AAED,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC3B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,uDAAuD;IACvD,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAwKhF","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir, getDocsPath, getReadmePath } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport type { ToolName } from \"./tools/index.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<ToolName, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n};\n\n/** Resolve input as file path or literal string */\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n/** Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md) */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport interface LoadContextFilesOptions {\n\t/** Working directory to start walking up from. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global context. Default: from getAgentDir() */\n\tagentDir?: string;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: agentDir/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nexport function loadProjectContextFiles(\n\toptions: LoadContextFilesOptions = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\t// 1. Load global context from agentDir\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: ToolName[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Skills settings for discovery. */\n\tskillsSettings?: SkillsSettings;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory. Default: from getAgentDir() */\n\tagentDir?: string;\n\t/** Pre-loaded context files (skips discovery if provided). */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills (skips discovery if provided). */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tskillsSettings,\n\t\tcwd,\n\t\tagentDir,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedCustomPrompt = resolvePromptInput(customPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(appendSystemPrompt, \"append system prompt\");\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = resolvedAppendPrompt ? `\\n\\n${resolvedAppendPrompt}` : \"\";\n\n\t// Resolve context files: use provided or discover\n\tconst contextFiles = providedContextFiles ?? loadProjectContextFiles({ cwd: resolvedCwd, agentDir });\n\n\t// Resolve skills: use provided or discover\n\tconst skills =\n\t\tprovidedSkills ??\n\t\t(skillsSettings?.enabled !== false ? loadSkills({ ...skillsSettings, cwd: resolvedCwd, agentDir }).skills : []);\n\n\tif (resolvedCustomPrompt) {\n\t\tlet prompt = resolvedCustomPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\n\t// Build tools list based on selected tools\n\tconst tools = selectedTools || ([\"read\", \"bash\", \"edit\", \"write\"] as ToolName[]);\n\tconst toolsList = tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join(\"\\n\");\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// Read-only mode notice (no bash, edit, or write)\n\tif (!hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\"You are in READ-ONLY mode - you cannot modify files or execute arbitrary commands\");\n\t}\n\n\t// Bash without edit/write = read-only bash mode\n\tif (hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"Use bash ONLY for read-only operations (git log, gh issue view, curl, etc.) - do NOT modify any files\",\n\t\t);\n\t}\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\tguidelinesList.push(\"Use bash for file operations like ls, grep, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\tguidelinesList.push(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\tguidelinesList.push(\"Use read to examine files before editing\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\tguidelinesList.push(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\tguidelinesList.push(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing/executing)\n\tif (hasEdit || hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\t// Always include these\n\tguidelinesList.push(\"Be concise in your responses\");\n\tguidelinesList.push(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nGuidelines:\n${guidelines}\n\nDocumentation:\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- When asked about: custom models/providers (README sufficient), themes (docs/theme.md), skills (docs/skills.md), hooks (docs/hooks.md), custom tools (docs/custom-tools.md), RPC (docs/rpc.md)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAqC,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAkDjD,MAAM,WAAW,uBAAuB;IACvC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACtC,OAAO,GAAE,uBAA4B,GACnC,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAyC1C;AAED,MAAM,WAAW,wBAAwB;IACxC,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC;IAC3B,uCAAuC;IACvC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,qCAAqC;IACrC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gDAAgD;IAChD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxD,uDAAuD;IACvD,MAAM,CAAC,EAAE,KAAK,EAAE,CAAC;CACjB;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,MAAM,CAwKhF","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir, getDocsPath, getReadmePath } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport type { ToolName } from \"./tools/index.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<ToolName, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n};\n\n/** Resolve input as file path or literal string */\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n/** Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md) */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport interface LoadContextFilesOptions {\n\t/** Working directory to start walking up from. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global context. Default: from getAgentDir() */\n\tagentDir?: string;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: agentDir/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nexport function loadProjectContextFiles(\n\toptions: LoadContextFilesOptions = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\t// 1. Load global context from agentDir\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: ToolName[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Skills settings for discovery. */\n\tskillsSettings?: SkillsSettings;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory. Default: from getAgentDir() */\n\tagentDir?: string;\n\t/** Pre-loaded context files (skips discovery if provided). */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills (skips discovery if provided). */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tskillsSettings,\n\t\tcwd,\n\t\tagentDir,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedCustomPrompt = resolvePromptInput(customPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(appendSystemPrompt, \"append system prompt\");\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = resolvedAppendPrompt ? `\\n\\n${resolvedAppendPrompt}` : \"\";\n\n\t// Resolve context files: use provided or discover\n\tconst contextFiles = providedContextFiles ?? loadProjectContextFiles({ cwd: resolvedCwd, agentDir });\n\n\t// Resolve skills: use provided or discover\n\tconst skills =\n\t\tprovidedSkills ??\n\t\t(skillsSettings?.enabled !== false ? loadSkills({ ...skillsSettings, cwd: resolvedCwd, agentDir }).skills : []);\n\n\tif (resolvedCustomPrompt) {\n\t\tlet prompt = resolvedCustomPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\n\t// Build tools list based on selected tools\n\tconst tools = selectedTools || ([\"read\", \"bash\", \"edit\", \"write\"] as ToolName[]);\n\tconst toolsList = tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join(\"\\n\");\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// Read-only mode notice (no bash, edit, or write)\n\tif (!hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\"You are in READ-ONLY mode - you cannot modify files or execute arbitrary commands\");\n\t}\n\n\t// Bash without edit/write = read-only bash mode\n\tif (hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"Use bash ONLY for read-only operations (git log, gh issue view, curl, etc.) - do NOT modify any files\",\n\t\t);\n\t}\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\tguidelinesList.push(\"Use bash for file operations like ls, grep, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\tguidelinesList.push(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\tguidelinesList.push(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\tguidelinesList.push(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\tguidelinesList.push(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing/executing)\n\tif (hasEdit || hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\t// Always include these\n\tguidelinesList.push(\"Be concise in your responses\");\n\tguidelinesList.push(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nGuidelines:\n${guidelines}\n\nDocumentation:\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- When asked about: custom models/providers (README sufficient), themes (docs/theme.md), skills (docs/skills.md), hooks (docs/hooks.md), custom tools (docs/custom-tools.md), RPC (docs/rpc.md)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
@@ -170,7 +170,7 @@ export function buildSystemPrompt(options = {}) {
|
|
|
170
170
|
}
|
|
171
171
|
// Read before edit guideline
|
|
172
172
|
if (hasRead && hasEdit) {
|
|
173
|
-
guidelinesList.push("Use read to examine files before editing");
|
|
173
|
+
guidelinesList.push("Use read to examine files before editing. You must use this tool instead of cat or sed.");
|
|
174
174
|
}
|
|
175
175
|
// Edit guideline
|
|
176
176
|
if (hasEdit) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir, getDocsPath, getReadmePath } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport type { ToolName } from \"./tools/index.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<ToolName, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n};\n\n/** Resolve input as file path or literal string */\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n/** Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md) */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport interface LoadContextFilesOptions {\n\t/** Working directory to start walking up from. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global context. Default: from getAgentDir() */\n\tagentDir?: string;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: agentDir/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nexport function loadProjectContextFiles(\n\toptions: LoadContextFilesOptions = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\t// 1. Load global context from agentDir\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: ToolName[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Skills settings for discovery. */\n\tskillsSettings?: SkillsSettings;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory. Default: from getAgentDir() */\n\tagentDir?: string;\n\t/** Pre-loaded context files (skips discovery if provided). */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills (skips discovery if provided). */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tskillsSettings,\n\t\tcwd,\n\t\tagentDir,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedCustomPrompt = resolvePromptInput(customPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(appendSystemPrompt, \"append system prompt\");\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = resolvedAppendPrompt ? `\\n\\n${resolvedAppendPrompt}` : \"\";\n\n\t// Resolve context files: use provided or discover\n\tconst contextFiles = providedContextFiles ?? loadProjectContextFiles({ cwd: resolvedCwd, agentDir });\n\n\t// Resolve skills: use provided or discover\n\tconst skills =\n\t\tprovidedSkills ??\n\t\t(skillsSettings?.enabled !== false ? loadSkills({ ...skillsSettings, cwd: resolvedCwd, agentDir }).skills : []);\n\n\tif (resolvedCustomPrompt) {\n\t\tlet prompt = resolvedCustomPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\n\t// Build tools list based on selected tools\n\tconst tools = selectedTools || ([\"read\", \"bash\", \"edit\", \"write\"] as ToolName[]);\n\tconst toolsList = tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join(\"\\n\");\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// Read-only mode notice (no bash, edit, or write)\n\tif (!hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\"You are in READ-ONLY mode - you cannot modify files or execute arbitrary commands\");\n\t}\n\n\t// Bash without edit/write = read-only bash mode\n\tif (hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"Use bash ONLY for read-only operations (git log, gh issue view, curl, etc.) - do NOT modify any files\",\n\t\t);\n\t}\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\tguidelinesList.push(\"Use bash for file operations like ls, grep, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\tguidelinesList.push(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\tguidelinesList.push(\"Use read to examine files before editing\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\tguidelinesList.push(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\tguidelinesList.push(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing/executing)\n\tif (hasEdit || hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\t// Always include these\n\tguidelinesList.push(\"Be concise in your responses\");\n\tguidelinesList.push(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nGuidelines:\n${guidelines}\n\nDocumentation:\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- When asked about: custom models/providers (README sufficient), themes (docs/theme.md), skills (docs/skills.md), hooks (docs/hooks.md), custom tools (docs/custom-tools.md), RPC (docs/rpc.md)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../src/core/system-prompt.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEvE,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AAG5E,0CAA0C;AAC1C,MAAM,gBAAgB,GAA6B;IAClD,IAAI,EAAE,oBAAoB;IAC1B,IAAI,EAAE,8CAA8C;IACpD,IAAI,EAAE,4DAA4D;IAClE,KAAK,EAAE,2BAA2B;IAClC,IAAI,EAAE,yDAAyD;IAC/D,IAAI,EAAE,kDAAkD;IACxD,EAAE,EAAE,yBAAyB;CAC7B,CAAC;AAEF,mDAAmD;AACnD,SAAS,kBAAkB,CAAC,KAAyB,EAAE,WAAmB,EAAsB;IAC/F,IAAI,CAAC,KAAK,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACvB,IAAI,CAAC;YACJ,OAAO,YAAY,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,WAAW,SAAS,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9F,OAAO,KAAK,CAAC;QACd,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AAAA,CACb;AAED,yEAAyE;AACzE,SAAS,sBAAsB,CAAC,GAAW,EAA4C;IACtF,MAAM,UAAU,GAAG,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;IAC9C,KAAK,MAAM,QAAQ,IAAI,UAAU,EAAE,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACrC,IAAI,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACJ,OAAO;oBACN,IAAI,EAAE,QAAQ;oBACd,OAAO,EAAE,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;iBACxC,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,2BAA2B,QAAQ,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC;YAC9E,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AASD;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CACtC,OAAO,GAA4B,EAAE,EACM;IAC3C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACjD,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,IAAI,WAAW,EAAE,CAAC;IAE3D,MAAM,YAAY,GAA6C,EAAE,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,uCAAuC;IACvC,MAAM,aAAa,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;IAC/D,IAAI,aAAa,EAAE,CAAC;QACnB,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACjC,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,4DAA4D;IAC5D,MAAM,oBAAoB,GAA6C,EAAE,CAAC;IAE1E,IAAI,UAAU,GAAG,WAAW,CAAC;IAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAE1B,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,WAAW,GAAG,sBAAsB,CAAC,UAAU,CAAC,CAAC;QACvD,IAAI,WAAW,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;YACrD,mDAAmD;YACnD,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YAC1C,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QAED,6BAA6B;QAC7B,IAAI,UAAU,KAAK,IAAI;YAAE,MAAM;QAE/B,wBAAwB;QACxB,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC5C,IAAI,SAAS,KAAK,UAAU;YAAE,MAAM,CAAC,eAAe;QACpD,UAAU,GAAG,SAAS,CAAC;IACxB,CAAC;IAED,iDAA+C;IAC/C,YAAY,CAAC,IAAI,CAAC,GAAG,oBAAoB,CAAC,CAAC;IAE3C,OAAO,YAAY,CAAC;AAAA,CACpB;AAqBD,kEAAkE;AAClE,MAAM,UAAU,iBAAiB,CAAC,OAAO,GAA6B,EAAE,EAAU;IACjF,MAAM,EACL,YAAY,EACZ,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,GAAG,EACH,QAAQ,EACR,YAAY,EAAE,oBAAoB,EAClC,MAAM,EAAE,cAAc,GACtB,GAAG,OAAO,CAAC;IACZ,MAAM,WAAW,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACzC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;IAC/E,MAAM,oBAAoB,GAAG,kBAAkB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;IAE5F,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IACvB,MAAM,QAAQ,GAAG,GAAG,CAAC,cAAc,CAAC,OAAO,EAAE;QAC5C,OAAO,EAAE,MAAM;QACf,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM;QACb,GAAG,EAAE,SAAS;QACd,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,SAAS;QACjB,MAAM,EAAE,SAAS;QACjB,YAAY,EAAE,OAAO;KACrB,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,oBAAoB,CAAC,CAAC,CAAC,OAAO,oBAAoB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEhF,kDAAkD;IAClD,MAAM,YAAY,GAAG,oBAAoB,IAAI,uBAAuB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC;IAErG,2CAA2C;IAC3C,MAAM,MAAM,GACX,cAAc;QACd,CAAC,cAAc,EAAE,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,GAAG,cAAc,EAAE,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAEjH,IAAI,oBAAoB,EAAE,CAAC;QAC1B,IAAI,MAAM,GAAG,oBAAoB,CAAC;QAElC,IAAI,aAAa,EAAE,CAAC;YACnB,MAAM,IAAI,aAAa,CAAC;QACzB,CAAC;QAED,+BAA+B;QAC/B,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,2BAA2B,CAAC;YACtC,MAAM,IAAI,2DAA2D,CAAC;YACtE,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC;gBACxD,MAAM,IAAI,MAAM,QAAQ,OAAO,OAAO,MAAM,CAAC;YAC9C,CAAC;QACF,CAAC;QAED,yDAAyD;QACzD,MAAM,mBAAmB,GAAG,CAAC,aAAa,IAAI,aAAa,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC7E,IAAI,mBAAmB,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;QACzC,CAAC;QAED,2CAA2C;QAC3C,MAAM,IAAI,4BAA4B,QAAQ,EAAE,CAAC;QACjD,MAAM,IAAI,gCAAgC,WAAW,EAAE,CAAC;QAExD,OAAO,MAAM,CAAC;IACf,CAAC;IAED,sCAAsC;IACtC,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAC;IAE/B,2CAA2C;IAC3C,MAAM,KAAK,GAAG,aAAa,IAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAgB,CAAC;IACjF,MAAM,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEhF,+DAA+D;IAC/D,MAAM,cAAc,GAAa,EAAE,CAAC;IAEpC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACzC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEvC,kDAAkD;IAClD,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,cAAc,CAAC,IAAI,CAAC,mFAAmF,CAAC,CAAC;IAC1G,CAAC;IAED,gDAAgD;IAChD,IAAI,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtC,cAAc,CAAC,IAAI,CAClB,uGAAuG,CACvG,CAAC;IACH,CAAC;IAED,8BAA8B;IAC9B,IAAI,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QAC/C,cAAc,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC;IACzE,CAAC;SAAM,IAAI,OAAO,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,KAAK,CAAC,EAAE,CAAC;QACrD,cAAc,CAAC,IAAI,CAAC,wFAAwF,CAAC,CAAC;IAC/G,CAAC;IAED,6BAA6B;IAC7B,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;QACxB,cAAc,CAAC,IAAI,CAAC,yFAAyF,CAAC,CAAC;IAChH,CAAC;IAED,iBAAiB;IACjB,IAAI,OAAO,EAAE,CAAC;QACb,cAAc,CAAC,IAAI,CAAC,4DAA4D,CAAC,CAAC;IACnF,CAAC;IAED,kBAAkB;IAClB,IAAI,QAAQ,EAAE,CAAC;QACd,cAAc,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAC1E,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,IAAI,QAAQ,EAAE,CAAC;QACzB,cAAc,CAAC,IAAI,CAClB,4GAA4G,CAC5G,CAAC;IACH,CAAC;IAED,uBAAuB;IACvB,cAAc,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IACpD,cAAc,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC;IAEvE,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElE,IAAI,MAAM,GAAG;;;EAGZ,SAAS;;;EAGT,UAAU;;;wBAGY,UAAU;qBACb,QAAQ;gMACmK,CAAC;IAEhM,IAAI,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,aAAa,CAAC;IACzB,CAAC;IAED,+BAA+B;IAC/B,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,2BAA2B,CAAC;QACtC,MAAM,IAAI,2DAA2D,CAAC;QACtE,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,YAAY,EAAE,CAAC;YACxD,MAAM,IAAI,MAAM,QAAQ,OAAO,OAAO,MAAM,CAAC;QAC9C,CAAC;IACF,CAAC;IAED,yDAAyD;IACzD,IAAI,OAAO,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,qBAAqB,CAAC,MAAM,CAAC,CAAC;IACzC,CAAC;IAED,2CAA2C;IAC3C,MAAM,IAAI,4BAA4B,QAAQ,EAAE,CAAC;IACjD,MAAM,IAAI,gCAAgC,WAAW,EAAE,CAAC;IAExD,OAAO,MAAM,CAAC;AAAA,CACd","sourcesContent":["/**\n * System prompt construction and project context loading\n */\n\nimport chalk from \"chalk\";\nimport { existsSync, readFileSync } from \"fs\";\nimport { join, resolve } from \"path\";\nimport { getAgentDir, getDocsPath, getReadmePath } from \"../config.js\";\nimport type { SkillsSettings } from \"./settings-manager.js\";\nimport { formatSkillsForPrompt, loadSkills, type Skill } from \"./skills.js\";\nimport type { ToolName } from \"./tools/index.js\";\n\n/** Tool descriptions for system prompt */\nconst toolDescriptions: Record<ToolName, string> = {\n\tread: \"Read file contents\",\n\tbash: \"Execute bash commands (ls, grep, find, etc.)\",\n\tedit: \"Make surgical edits to files (find exact text and replace)\",\n\twrite: \"Create or overwrite files\",\n\tgrep: \"Search file contents for patterns (respects .gitignore)\",\n\tfind: \"Find files by glob pattern (respects .gitignore)\",\n\tls: \"List directory contents\",\n};\n\n/** Resolve input as file path or literal string */\nfunction resolvePromptInput(input: string | undefined, description: string): string | undefined {\n\tif (!input) {\n\t\treturn undefined;\n\t}\n\n\tif (existsSync(input)) {\n\t\ttry {\n\t\t\treturn readFileSync(input, \"utf-8\");\n\t\t} catch (error) {\n\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));\n\t\t\treturn input;\n\t\t}\n\t}\n\n\treturn input;\n}\n\n/** Look for AGENTS.md or CLAUDE.md in a directory (prefers AGENTS.md) */\nfunction loadContextFileFromDir(dir: string): { path: string; content: string } | null {\n\tconst candidates = [\"AGENTS.md\", \"CLAUDE.md\"];\n\tfor (const filename of candidates) {\n\t\tconst filePath = join(dir, filename);\n\t\tif (existsSync(filePath)) {\n\t\t\ttry {\n\t\t\t\treturn {\n\t\t\t\t\tpath: filePath,\n\t\t\t\t\tcontent: readFileSync(filePath, \"utf-8\"),\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nexport interface LoadContextFilesOptions {\n\t/** Working directory to start walking up from. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory for global context. Default: from getAgentDir() */\n\tagentDir?: string;\n}\n\n/**\n * Load all project context files in order:\n * 1. Global: agentDir/AGENTS.md or CLAUDE.md\n * 2. Parent directories (top-most first) down to cwd\n * Each returns {path, content} for separate messages\n */\nexport function loadProjectContextFiles(\n\toptions: LoadContextFilesOptions = {},\n): Array<{ path: string; content: string }> {\n\tconst resolvedCwd = options.cwd ?? process.cwd();\n\tconst resolvedAgentDir = options.agentDir ?? getAgentDir();\n\n\tconst contextFiles: Array<{ path: string; content: string }> = [];\n\tconst seenPaths = new Set<string>();\n\n\t// 1. Load global context from agentDir\n\tconst globalContext = loadContextFileFromDir(resolvedAgentDir);\n\tif (globalContext) {\n\t\tcontextFiles.push(globalContext);\n\t\tseenPaths.add(globalContext.path);\n\t}\n\n\t// 2. Walk up from cwd to root, collecting all context files\n\tconst ancestorContextFiles: Array<{ path: string; content: string }> = [];\n\n\tlet currentDir = resolvedCwd;\n\tconst root = resolve(\"/\");\n\n\twhile (true) {\n\t\tconst contextFile = loadContextFileFromDir(currentDir);\n\t\tif (contextFile && !seenPaths.has(contextFile.path)) {\n\t\t\t// Add to beginning so we get top-most parent first\n\t\t\tancestorContextFiles.unshift(contextFile);\n\t\t\tseenPaths.add(contextFile.path);\n\t\t}\n\n\t\t// Stop if we've reached root\n\t\tif (currentDir === root) break;\n\n\t\t// Move up one directory\n\t\tconst parentDir = resolve(currentDir, \"..\");\n\t\tif (parentDir === currentDir) break; // Safety check\n\t\tcurrentDir = parentDir;\n\t}\n\n\t// Add ancestor files in order (top-most → cwd)\n\tcontextFiles.push(...ancestorContextFiles);\n\n\treturn contextFiles;\n}\n\nexport interface BuildSystemPromptOptions {\n\t/** Custom system prompt (replaces default). */\n\tcustomPrompt?: string;\n\t/** Tools to include in prompt. Default: [read, bash, edit, write] */\n\tselectedTools?: ToolName[];\n\t/** Text to append to system prompt. */\n\tappendSystemPrompt?: string;\n\t/** Skills settings for discovery. */\n\tskillsSettings?: SkillsSettings;\n\t/** Working directory. Default: process.cwd() */\n\tcwd?: string;\n\t/** Agent config directory. Default: from getAgentDir() */\n\tagentDir?: string;\n\t/** Pre-loaded context files (skips discovery if provided). */\n\tcontextFiles?: Array<{ path: string; content: string }>;\n\t/** Pre-loaded skills (skips discovery if provided). */\n\tskills?: Skill[];\n}\n\n/** Build the system prompt with tools, guidelines, and context */\nexport function buildSystemPrompt(options: BuildSystemPromptOptions = {}): string {\n\tconst {\n\t\tcustomPrompt,\n\t\tselectedTools,\n\t\tappendSystemPrompt,\n\t\tskillsSettings,\n\t\tcwd,\n\t\tagentDir,\n\t\tcontextFiles: providedContextFiles,\n\t\tskills: providedSkills,\n\t} = options;\n\tconst resolvedCwd = cwd ?? process.cwd();\n\tconst resolvedCustomPrompt = resolvePromptInput(customPrompt, \"system prompt\");\n\tconst resolvedAppendPrompt = resolvePromptInput(appendSystemPrompt, \"append system prompt\");\n\n\tconst now = new Date();\n\tconst dateTime = now.toLocaleString(\"en-US\", {\n\t\tweekday: \"long\",\n\t\tyear: \"numeric\",\n\t\tmonth: \"long\",\n\t\tday: \"numeric\",\n\t\thour: \"2-digit\",\n\t\tminute: \"2-digit\",\n\t\tsecond: \"2-digit\",\n\t\ttimeZoneName: \"short\",\n\t});\n\n\tconst appendSection = resolvedAppendPrompt ? `\\n\\n${resolvedAppendPrompt}` : \"\";\n\n\t// Resolve context files: use provided or discover\n\tconst contextFiles = providedContextFiles ?? loadProjectContextFiles({ cwd: resolvedCwd, agentDir });\n\n\t// Resolve skills: use provided or discover\n\tconst skills =\n\t\tprovidedSkills ??\n\t\t(skillsSettings?.enabled !== false ? loadSkills({ ...skillsSettings, cwd: resolvedCwd, agentDir }).skills : []);\n\n\tif (resolvedCustomPrompt) {\n\t\tlet prompt = resolvedCustomPrompt;\n\n\t\tif (appendSection) {\n\t\t\tprompt += appendSection;\n\t\t}\n\n\t\t// Append project context files\n\t\tif (contextFiles.length > 0) {\n\t\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t\t}\n\t\t}\n\n\t\t// Append skills section (only if read tool is available)\n\t\tconst customPromptHasRead = !selectedTools || selectedTools.includes(\"read\");\n\t\tif (customPromptHasRead && skills.length > 0) {\n\t\t\tprompt += formatSkillsForPrompt(skills);\n\t\t}\n\n\t\t// Add date/time and working directory last\n\t\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\t\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\t\treturn prompt;\n\t}\n\n\t// Get absolute paths to documentation\n\tconst readmePath = getReadmePath();\n\tconst docsPath = getDocsPath();\n\n\t// Build tools list based on selected tools\n\tconst tools = selectedTools || ([\"read\", \"bash\", \"edit\", \"write\"] as ToolName[]);\n\tconst toolsList = tools.map((t) => `- ${t}: ${toolDescriptions[t]}`).join(\"\\n\");\n\n\t// Build guidelines based on which tools are actually available\n\tconst guidelinesList: string[] = [];\n\n\tconst hasBash = tools.includes(\"bash\");\n\tconst hasEdit = tools.includes(\"edit\");\n\tconst hasWrite = tools.includes(\"write\");\n\tconst hasGrep = tools.includes(\"grep\");\n\tconst hasFind = tools.includes(\"find\");\n\tconst hasLs = tools.includes(\"ls\");\n\tconst hasRead = tools.includes(\"read\");\n\n\t// Read-only mode notice (no bash, edit, or write)\n\tif (!hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\"You are in READ-ONLY mode - you cannot modify files or execute arbitrary commands\");\n\t}\n\n\t// Bash without edit/write = read-only bash mode\n\tif (hasBash && !hasEdit && !hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"Use bash ONLY for read-only operations (git log, gh issue view, curl, etc.) - do NOT modify any files\",\n\t\t);\n\t}\n\n\t// File exploration guidelines\n\tif (hasBash && !hasGrep && !hasFind && !hasLs) {\n\t\tguidelinesList.push(\"Use bash for file operations like ls, grep, find\");\n\t} else if (hasBash && (hasGrep || hasFind || hasLs)) {\n\t\tguidelinesList.push(\"Prefer grep/find/ls tools over bash for file exploration (faster, respects .gitignore)\");\n\t}\n\n\t// Read before edit guideline\n\tif (hasRead && hasEdit) {\n\t\tguidelinesList.push(\"Use read to examine files before editing. You must use this tool instead of cat or sed.\");\n\t}\n\n\t// Edit guideline\n\tif (hasEdit) {\n\t\tguidelinesList.push(\"Use edit for precise changes (old text must match exactly)\");\n\t}\n\n\t// Write guideline\n\tif (hasWrite) {\n\t\tguidelinesList.push(\"Use write only for new files or complete rewrites\");\n\t}\n\n\t// Output guideline (only when actually writing/executing)\n\tif (hasEdit || hasWrite) {\n\t\tguidelinesList.push(\n\t\t\t\"When summarizing your actions, output plain text directly - do NOT use cat or bash to display what you did\",\n\t\t);\n\t}\n\n\t// Always include these\n\tguidelinesList.push(\"Be concise in your responses\");\n\tguidelinesList.push(\"Show file paths clearly when working with files\");\n\n\tconst guidelines = guidelinesList.map((g) => `- ${g}`).join(\"\\n\");\n\n\tlet prompt = `You are an expert coding assistant. You help users with coding tasks by reading files, executing commands, editing code, and writing new files.\n\nAvailable tools:\n${toolsList}\n\nGuidelines:\n${guidelines}\n\nDocumentation:\n- Main documentation: ${readmePath}\n- Additional docs: ${docsPath}\n- When asked about: custom models/providers (README sufficient), themes (docs/theme.md), skills (docs/skills.md), hooks (docs/hooks.md), custom tools (docs/custom-tools.md), RPC (docs/rpc.md)`;\n\n\tif (appendSection) {\n\t\tprompt += appendSection;\n\t}\n\n\t// Append project context files\n\tif (contextFiles.length > 0) {\n\t\tprompt += \"\\n\\n# Project Context\\n\\n\";\n\t\tprompt += \"The following project context files have been loaded:\\n\\n\";\n\t\tfor (const { path: filePath, content } of contextFiles) {\n\t\t\tprompt += `## ${filePath}\\n\\n${content}\\n\\n`;\n\t\t}\n\t}\n\n\t// Append skills section (only if read tool is available)\n\tif (hasRead && skills.length > 0) {\n\t\tprompt += formatSkillsForPrompt(skills);\n\t}\n\n\t// Add date/time and working directory last\n\tprompt += `\\nCurrent date and time: ${dateTime}`;\n\tprompt += `\\nCurrent working directory: ${resolvedCwd}`;\n\n\treturn prompt;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timings.d.ts","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,wBAAgB,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKxC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAQnC","sourcesContent":["/**\n * Central timing instrumentation for startup profiling.\n * Enable with PI_TIMING=1 environment variable.\n */\n\nconst ENABLED = process.env.PI_TIMING === \"1\";\nconst timings: Array<{ label: string; ms: number }> = [];\nlet lastTime = Date.now();\n\nexport function time(label: string): void {\n\tif (!ENABLED) return;\n\tconst now = Date.now();\n\ttimings.push({ label, ms: now - lastTime });\n\tlastTime = now;\n}\n\nexport function printTimings(): void {\n\tif (!ENABLED || timings.length === 0) return;\n\tconsole.error(\"\\n--- Startup Timings ---\");\n\tfor (const t of timings) {\n\t\tconsole.error(` ${t.label}: ${t.ms}ms`);\n\t}\n\tconsole.error(` TOTAL: ${timings.reduce((a, b) => a + b.ms, 0)}ms`);\n\tconsole.error(\"------------------------\\n\");\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Central timing instrumentation for startup profiling.
|
|
3
|
+
* Enable with PI_TIMING=1 environment variable.
|
|
4
|
+
*/
|
|
5
|
+
const ENABLED = process.env.PI_TIMING === "1";
|
|
6
|
+
const timings = [];
|
|
7
|
+
let lastTime = Date.now();
|
|
8
|
+
export function time(label) {
|
|
9
|
+
if (!ENABLED)
|
|
10
|
+
return;
|
|
11
|
+
const now = Date.now();
|
|
12
|
+
timings.push({ label, ms: now - lastTime });
|
|
13
|
+
lastTime = now;
|
|
14
|
+
}
|
|
15
|
+
export function printTimings() {
|
|
16
|
+
if (!ENABLED || timings.length === 0)
|
|
17
|
+
return;
|
|
18
|
+
console.error("\n--- Startup Timings ---");
|
|
19
|
+
for (const t of timings) {
|
|
20
|
+
console.error(` ${t.label}: ${t.ms}ms`);
|
|
21
|
+
}
|
|
22
|
+
console.error(` TOTAL: ${timings.reduce((a, b) => a + b.ms, 0)}ms`);
|
|
23
|
+
console.error("------------------------\n");
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=timings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timings.js","sourceRoot":"","sources":["../../src/core/timings.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,KAAK,GAAG,CAAC;AAC9C,MAAM,OAAO,GAAyC,EAAE,CAAC;AACzD,IAAI,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE1B,MAAM,UAAU,IAAI,CAAC,KAAa,EAAQ;IACzC,IAAI,CAAC,OAAO;QAAE,OAAO;IACrB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,GAAG,GAAG,QAAQ,EAAE,CAAC,CAAC;IAC5C,QAAQ,GAAG,GAAG,CAAC;AAAA,CACf;AAED,MAAM,UAAU,YAAY,GAAS;IACpC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO;IAC7C,OAAO,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACzB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IAC1C,CAAC;IACD,OAAO,CAAC,KAAK,CAAC,YAAY,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACrE,OAAO,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAC;AAAA,CAC5C","sourcesContent":["/**\n * Central timing instrumentation for startup profiling.\n * Enable with PI_TIMING=1 environment variable.\n */\n\nconst ENABLED = process.env.PI_TIMING === \"1\";\nconst timings: Array<{ label: string; ms: number }> = [];\nlet lastTime = Date.now();\n\nexport function time(label: string): void {\n\tif (!ENABLED) return;\n\tconst now = Date.now();\n\ttimings.push({ label, ms: now - lastTime });\n\tlastTime = now;\n}\n\nexport function printTimings(): void {\n\tif (!ENABLED || timings.length === 0) return;\n\tconsole.error(\"\\n--- Startup Timings ---\");\n\tfor (const t of timings) {\n\t\tconsole.error(` ${t.label}: ${t.ms}ms`);\n\t}\n\tconsole.error(` TOTAL: ${timings.reduce((a, b) => a + b.ms, 0)}ms`);\n\tconsole.error(\"------------------------\\n\");\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { AgentSession, type AgentSessionConfig, type AgentSessionEvent, type Age
|
|
|
2
2
|
export { type CutPointResult, calculateContextTokens, compact, DEFAULT_COMPACTION_SETTINGS, estimateTokens, findCutPoint, findTurnStartIndex, generateSummary, getLastAssistantUsage, shouldCompact, } from "./core/compaction.js";
|
|
3
3
|
export type { AgentToolUpdateCallback, CustomAgentTool, CustomToolFactory, CustomToolsLoadResult, ExecResult, LoadedCustomTool, RenderResultOptions, SessionEvent as ToolSessionEvent, ToolAPI, ToolUIContext, } from "./core/custom-tools/index.js";
|
|
4
4
|
export { discoverAndLoadCustomTools, loadCustomTools } from "./core/custom-tools/index.js";
|
|
5
|
-
export type { AgentEndEvent, AgentStartEvent, BashToolResultEvent,
|
|
5
|
+
export type { AgentEndEvent, AgentStartEvent, BashToolResultEvent, CustomToolResultEvent, EditToolResultEvent, FindToolResultEvent, GrepToolResultEvent, HookAPI, HookEvent, HookEventContext, HookFactory, HookUIContext, LsToolResultEvent, ReadToolResultEvent, SessionEvent, SessionEventResult, ToolCallEvent, ToolCallEventResult, ToolResultEvent, ToolResultEventResult, TurnEndEvent, TurnStartEvent, WriteToolResultEvent, } from "./core/hooks/index.js";
|
|
6
6
|
export { isBashToolResult, isEditToolResult, isFindToolResult, isGrepToolResult, isLsToolResult, isReadToolResult, isWriteToolResult, } from "./core/hooks/index.js";
|
|
7
7
|
export { messageTransformer } from "./core/messages.js";
|
|
8
8
|
export { findModel, getApiKeyForModel, getAvailableModels } from "./core/model-config.js";
|