@mariozechner/pi-coding-agent 0.49.3 → 0.50.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 +110 -1
- package/README.md +310 -1230
- package/dist/cli/args.d.ts +5 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +57 -23
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts +14 -0
- package/dist/cli/config-selector.d.ts.map +1 -0
- package/dist/cli/config-selector.js +31 -0
- package/dist/cli/config-selector.js.map +1 -0
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +1 -1
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session.d.ts +60 -37
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +272 -69
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts +8 -18
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +39 -55
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/bash-executor.d.ts.map +1 -1
- package/dist/core/bash-executor.js +2 -1
- package/dist/core/bash-executor.js.map +1 -1
- package/dist/core/diagnostics.d.ts +15 -0
- package/dist/core/diagnostics.d.ts.map +1 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/export-html/template.css +9 -0
- package/dist/core/export-html/template.js +6 -4
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +10 -1
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +9 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +39 -12
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +112 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +9 -2
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +13 -0
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-registry.d.ts +42 -2
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +154 -44
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +3 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +130 -0
- package/dist/core/package-manager.d.ts.map +1 -0
- package/dist/core/package-manager.js +1177 -0
- package/dist/core/package-manager.js.map +1 -0
- package/dist/core/prompt-templates.d.ts +6 -0
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +114 -54
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts +160 -0
- package/dist/core/resource-loader.d.ts.map +1 -0
- package/dist/core/resource-loader.js +604 -0
- package/dist/core/resource-loader.js.map +1 -0
- package/dist/core/sdk.d.ts +14 -105
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +52 -304
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +45 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +34 -16
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +104 -25
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills.d.ts +18 -10
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +126 -93
- package/dist/core/skills.js.map +1 -1
- package/dist/core/system-prompt.d.ts +3 -27
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +16 -103
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +2 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +4 -4
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +12 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +209 -97
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +5 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js +29 -9
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +71 -0
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/config-selector.js +468 -0
- package/dist/modes/interactive/components/config-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +4 -0
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +3 -4
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +18 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +195 -87
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts +17 -0
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -0
- package/dist/modes/interactive/components/skill-invocation-message.js +47 -0
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +5 -5
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +42 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +538 -204
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/theme/dark.json +1 -1
- package/dist/modes/interactive/theme/light.json +1 -1
- package/dist/modes/interactive/theme/theme-schema.json +8 -1
- package/dist/modes/interactive/theme/theme.d.ts +8 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/dist/modes/interactive/theme/theme.js +72 -25
- package/dist/modes/interactive/theme/theme.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +7 -74
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +17 -82
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/git.d.ts +2 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +6 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/shell.d.ts +1 -0
- package/dist/utils/shell.d.ts.map +1 -1
- package/dist/utils/shell.js +14 -1
- package/dist/utils/shell.js.map +1 -1
- package/dist/utils/sleep.d.ts +5 -0
- package/dist/utils/sleep.d.ts.map +1 -0
- package/dist/utils/sleep.js +17 -0
- package/dist/utils/sleep.js.map +1 -0
- package/docs/compaction.md +23 -21
- package/docs/custom-provider.md +538 -0
- package/docs/development.md +69 -0
- package/docs/extensions.md +182 -118
- package/docs/images/doom-extension.png +0 -0
- package/docs/images/interactive-mode.png +0 -0
- package/docs/images/tree-view.png +0 -0
- package/docs/json.md +79 -0
- package/docs/keybindings.md +162 -0
- package/docs/models.md +193 -0
- package/docs/packages.md +168 -0
- package/docs/prompt-templates.md +67 -0
- package/docs/providers.md +147 -0
- package/docs/sdk.md +111 -178
- package/docs/session.md +167 -16
- package/docs/settings.md +216 -0
- package/docs/shell-aliases.md +13 -0
- package/docs/skills.md +111 -202
- package/docs/terminal-setup.md +65 -0
- package/docs/themes.md +295 -0
- package/docs/tui.md +36 -5
- package/docs/windows.md +17 -0
- package/examples/README.md +1 -0
- package/examples/extensions/README.md +22 -2
- package/examples/extensions/bookmark.ts +50 -0
- package/examples/extensions/custom-provider-anthropic/index.ts +604 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
- package/examples/extensions/custom-provider-anthropic/package.json +19 -0
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +349 -0
- package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
- package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -0
- package/examples/extensions/doom-overlay/doom/build.sh +1 -1
- package/examples/extensions/event-bus.ts +43 -0
- package/examples/extensions/message-renderer.ts +59 -0
- package/examples/extensions/session-name.ts +27 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/02-custom-model.ts +3 -3
- package/examples/sdk/03-custom-prompt.ts +20 -9
- package/examples/sdk/04-skills.ts +26 -27
- package/examples/sdk/06-extensions.ts +15 -6
- package/examples/sdk/07-context-files.ts +22 -18
- package/examples/sdk/08-prompt-templates.ts +19 -14
- package/examples/sdk/09-api-keys-and-oauth.ts +5 -12
- package/examples/sdk/10-settings.ts +3 -3
- package/examples/sdk/12-full-control.ts +16 -7
- package/examples/sdk/README.md +24 -30
- package/package.json +4 -4
- package/docs/theme.md +0 -617
- package/examples/extensions/chalk-logger.ts +0 -26
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, resolve, sep } from "node:path";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
|
|
6
|
+
import { loadThemeFromPath } from "../modes/interactive/theme/theme.js";
|
|
7
|
+
import { createEventBus } from "./event-bus.js";
|
|
8
|
+
import { createExtensionRuntime, loadExtensionFromFactory, loadExtensions } from "./extensions/loader.js";
|
|
9
|
+
import { DefaultPackageManager } from "./package-manager.js";
|
|
10
|
+
import { loadPromptTemplates } from "./prompt-templates.js";
|
|
11
|
+
import { SettingsManager } from "./settings-manager.js";
|
|
12
|
+
import { loadSkills } from "./skills.js";
|
|
13
|
+
function resolvePromptInput(input, description) {
|
|
14
|
+
if (!input) {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
if (existsSync(input)) {
|
|
18
|
+
try {
|
|
19
|
+
return readFileSync(input, "utf-8");
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error(chalk.yellow(`Warning: Could not read ${description} file ${input}: ${error}`));
|
|
23
|
+
return input;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return input;
|
|
27
|
+
}
|
|
28
|
+
function loadContextFileFromDir(dir) {
|
|
29
|
+
const candidates = ["AGENTS.md", "CLAUDE.md"];
|
|
30
|
+
for (const filename of candidates) {
|
|
31
|
+
const filePath = join(dir, filename);
|
|
32
|
+
if (existsSync(filePath)) {
|
|
33
|
+
try {
|
|
34
|
+
return {
|
|
35
|
+
path: filePath,
|
|
36
|
+
content: readFileSync(filePath, "utf-8"),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
console.error(chalk.yellow(`Warning: Could not read ${filePath}: ${error}`));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function loadProjectContextFiles(options = {}) {
|
|
47
|
+
const resolvedCwd = options.cwd ?? process.cwd();
|
|
48
|
+
const resolvedAgentDir = options.agentDir ?? getAgentDir();
|
|
49
|
+
const contextFiles = [];
|
|
50
|
+
const seenPaths = new Set();
|
|
51
|
+
const globalContext = loadContextFileFromDir(resolvedAgentDir);
|
|
52
|
+
if (globalContext) {
|
|
53
|
+
contextFiles.push(globalContext);
|
|
54
|
+
seenPaths.add(globalContext.path);
|
|
55
|
+
}
|
|
56
|
+
const ancestorContextFiles = [];
|
|
57
|
+
let currentDir = resolvedCwd;
|
|
58
|
+
const root = resolve("/");
|
|
59
|
+
while (true) {
|
|
60
|
+
const contextFile = loadContextFileFromDir(currentDir);
|
|
61
|
+
if (contextFile && !seenPaths.has(contextFile.path)) {
|
|
62
|
+
ancestorContextFiles.unshift(contextFile);
|
|
63
|
+
seenPaths.add(contextFile.path);
|
|
64
|
+
}
|
|
65
|
+
if (currentDir === root)
|
|
66
|
+
break;
|
|
67
|
+
const parentDir = resolve(currentDir, "..");
|
|
68
|
+
if (parentDir === currentDir)
|
|
69
|
+
break;
|
|
70
|
+
currentDir = parentDir;
|
|
71
|
+
}
|
|
72
|
+
contextFiles.push(...ancestorContextFiles);
|
|
73
|
+
return contextFiles;
|
|
74
|
+
}
|
|
75
|
+
export class DefaultResourceLoader {
|
|
76
|
+
cwd;
|
|
77
|
+
agentDir;
|
|
78
|
+
settingsManager;
|
|
79
|
+
eventBus;
|
|
80
|
+
packageManager;
|
|
81
|
+
additionalExtensionPaths;
|
|
82
|
+
additionalSkillPaths;
|
|
83
|
+
additionalPromptTemplatePaths;
|
|
84
|
+
additionalThemePaths;
|
|
85
|
+
extensionFactories;
|
|
86
|
+
noExtensions;
|
|
87
|
+
noSkills;
|
|
88
|
+
noPromptTemplates;
|
|
89
|
+
noThemes;
|
|
90
|
+
systemPromptSource;
|
|
91
|
+
appendSystemPromptSource;
|
|
92
|
+
extensionsOverride;
|
|
93
|
+
skillsOverride;
|
|
94
|
+
promptsOverride;
|
|
95
|
+
themesOverride;
|
|
96
|
+
agentsFilesOverride;
|
|
97
|
+
systemPromptOverride;
|
|
98
|
+
appendSystemPromptOverride;
|
|
99
|
+
extensionsResult;
|
|
100
|
+
skills;
|
|
101
|
+
skillDiagnostics;
|
|
102
|
+
prompts;
|
|
103
|
+
promptDiagnostics;
|
|
104
|
+
themes;
|
|
105
|
+
themeDiagnostics;
|
|
106
|
+
agentsFiles;
|
|
107
|
+
systemPrompt;
|
|
108
|
+
appendSystemPrompt;
|
|
109
|
+
pathMetadata;
|
|
110
|
+
constructor(options) {
|
|
111
|
+
this.cwd = options.cwd ?? process.cwd();
|
|
112
|
+
this.agentDir = options.agentDir ?? getAgentDir();
|
|
113
|
+
this.settingsManager = options.settingsManager ?? SettingsManager.create(this.cwd, this.agentDir);
|
|
114
|
+
this.eventBus = options.eventBus ?? createEventBus();
|
|
115
|
+
this.packageManager = new DefaultPackageManager({
|
|
116
|
+
cwd: this.cwd,
|
|
117
|
+
agentDir: this.agentDir,
|
|
118
|
+
settingsManager: this.settingsManager,
|
|
119
|
+
});
|
|
120
|
+
this.additionalExtensionPaths = options.additionalExtensionPaths ?? [];
|
|
121
|
+
this.additionalSkillPaths = options.additionalSkillPaths ?? [];
|
|
122
|
+
this.additionalPromptTemplatePaths = options.additionalPromptTemplatePaths ?? [];
|
|
123
|
+
this.additionalThemePaths = options.additionalThemePaths ?? [];
|
|
124
|
+
this.extensionFactories = options.extensionFactories ?? [];
|
|
125
|
+
this.noExtensions = options.noExtensions ?? false;
|
|
126
|
+
this.noSkills = options.noSkills ?? false;
|
|
127
|
+
this.noPromptTemplates = options.noPromptTemplates ?? false;
|
|
128
|
+
this.noThemes = options.noThemes ?? false;
|
|
129
|
+
this.systemPromptSource = options.systemPrompt;
|
|
130
|
+
this.appendSystemPromptSource = options.appendSystemPrompt;
|
|
131
|
+
this.extensionsOverride = options.extensionsOverride;
|
|
132
|
+
this.skillsOverride = options.skillsOverride;
|
|
133
|
+
this.promptsOverride = options.promptsOverride;
|
|
134
|
+
this.themesOverride = options.themesOverride;
|
|
135
|
+
this.agentsFilesOverride = options.agentsFilesOverride;
|
|
136
|
+
this.systemPromptOverride = options.systemPromptOverride;
|
|
137
|
+
this.appendSystemPromptOverride = options.appendSystemPromptOverride;
|
|
138
|
+
this.extensionsResult = { extensions: [], errors: [], runtime: createExtensionRuntime() };
|
|
139
|
+
this.skills = [];
|
|
140
|
+
this.skillDiagnostics = [];
|
|
141
|
+
this.prompts = [];
|
|
142
|
+
this.promptDiagnostics = [];
|
|
143
|
+
this.themes = [];
|
|
144
|
+
this.themeDiagnostics = [];
|
|
145
|
+
this.agentsFiles = [];
|
|
146
|
+
this.appendSystemPrompt = [];
|
|
147
|
+
this.pathMetadata = new Map();
|
|
148
|
+
}
|
|
149
|
+
getExtensions() {
|
|
150
|
+
return this.extensionsResult;
|
|
151
|
+
}
|
|
152
|
+
getSkills() {
|
|
153
|
+
return { skills: this.skills, diagnostics: this.skillDiagnostics };
|
|
154
|
+
}
|
|
155
|
+
getPrompts() {
|
|
156
|
+
return { prompts: this.prompts, diagnostics: this.promptDiagnostics };
|
|
157
|
+
}
|
|
158
|
+
getThemes() {
|
|
159
|
+
return { themes: this.themes, diagnostics: this.themeDiagnostics };
|
|
160
|
+
}
|
|
161
|
+
getAgentsFiles() {
|
|
162
|
+
return { agentsFiles: this.agentsFiles };
|
|
163
|
+
}
|
|
164
|
+
getSystemPrompt() {
|
|
165
|
+
return this.systemPrompt;
|
|
166
|
+
}
|
|
167
|
+
getAppendSystemPrompt() {
|
|
168
|
+
return this.appendSystemPrompt;
|
|
169
|
+
}
|
|
170
|
+
getPathMetadata() {
|
|
171
|
+
return this.pathMetadata;
|
|
172
|
+
}
|
|
173
|
+
async reload() {
|
|
174
|
+
const resolvedPaths = await this.packageManager.resolve();
|
|
175
|
+
const cliExtensionPaths = await this.packageManager.resolveExtensionSources(this.additionalExtensionPaths, {
|
|
176
|
+
temporary: true,
|
|
177
|
+
});
|
|
178
|
+
// Helper to extract enabled paths and store metadata
|
|
179
|
+
const getEnabledResources = (resources) => {
|
|
180
|
+
for (const r of resources) {
|
|
181
|
+
if (!this.pathMetadata.has(r.path)) {
|
|
182
|
+
this.pathMetadata.set(r.path, r.metadata);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return resources.filter((r) => r.enabled);
|
|
186
|
+
};
|
|
187
|
+
const getEnabledPaths = (resources) => getEnabledResources(resources).map((r) => r.path);
|
|
188
|
+
// Store metadata and get enabled paths
|
|
189
|
+
this.pathMetadata = new Map();
|
|
190
|
+
const enabledExtensions = getEnabledPaths(resolvedPaths.extensions);
|
|
191
|
+
const enabledSkillResources = getEnabledResources(resolvedPaths.skills);
|
|
192
|
+
const enabledPrompts = getEnabledPaths(resolvedPaths.prompts);
|
|
193
|
+
const enabledThemes = getEnabledPaths(resolvedPaths.themes);
|
|
194
|
+
const mapSkillPath = (resource) => {
|
|
195
|
+
if (resource.metadata.source !== "auto" && resource.metadata.origin !== "package") {
|
|
196
|
+
return resource.path;
|
|
197
|
+
}
|
|
198
|
+
try {
|
|
199
|
+
const stats = statSync(resource.path);
|
|
200
|
+
if (!stats.isDirectory()) {
|
|
201
|
+
return resource.path;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return resource.path;
|
|
206
|
+
}
|
|
207
|
+
const skillFile = join(resource.path, "SKILL.md");
|
|
208
|
+
if (existsSync(skillFile)) {
|
|
209
|
+
if (!this.pathMetadata.has(skillFile)) {
|
|
210
|
+
this.pathMetadata.set(skillFile, resource.metadata);
|
|
211
|
+
}
|
|
212
|
+
return skillFile;
|
|
213
|
+
}
|
|
214
|
+
return resource.path;
|
|
215
|
+
};
|
|
216
|
+
const enabledSkills = enabledSkillResources.map(mapSkillPath);
|
|
217
|
+
// Add CLI paths metadata
|
|
218
|
+
for (const r of cliExtensionPaths.extensions) {
|
|
219
|
+
if (!this.pathMetadata.has(r.path)) {
|
|
220
|
+
this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
for (const r of cliExtensionPaths.skills) {
|
|
224
|
+
if (!this.pathMetadata.has(r.path)) {
|
|
225
|
+
this.pathMetadata.set(r.path, { source: "cli", scope: "temporary", origin: "top-level" });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const cliEnabledExtensions = getEnabledPaths(cliExtensionPaths.extensions);
|
|
229
|
+
const cliEnabledSkills = getEnabledPaths(cliExtensionPaths.skills);
|
|
230
|
+
const cliEnabledPrompts = getEnabledPaths(cliExtensionPaths.prompts);
|
|
231
|
+
const cliEnabledThemes = getEnabledPaths(cliExtensionPaths.themes);
|
|
232
|
+
const extensionPaths = this.noExtensions
|
|
233
|
+
? cliEnabledExtensions
|
|
234
|
+
: this.mergePaths(enabledExtensions, cliEnabledExtensions);
|
|
235
|
+
const extensionsResult = await loadExtensions(extensionPaths, this.cwd, this.eventBus);
|
|
236
|
+
const inlineExtensions = await this.loadExtensionFactories(extensionsResult.runtime);
|
|
237
|
+
extensionsResult.extensions.push(...inlineExtensions.extensions);
|
|
238
|
+
extensionsResult.errors.push(...inlineExtensions.errors);
|
|
239
|
+
// Detect extension conflicts (tools, commands, flags with same names from different extensions)
|
|
240
|
+
const conflicts = this.detectExtensionConflicts(extensionsResult.extensions);
|
|
241
|
+
if (conflicts.length > 0) {
|
|
242
|
+
const conflictingPaths = new Set(conflicts.map((c) => c.path));
|
|
243
|
+
extensionsResult.extensions = extensionsResult.extensions.filter((ext) => !conflictingPaths.has(ext.path));
|
|
244
|
+
for (const conflict of conflicts) {
|
|
245
|
+
extensionsResult.errors.push({ path: conflict.path, error: conflict.message });
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
this.extensionsResult = this.extensionsOverride ? this.extensionsOverride(extensionsResult) : extensionsResult;
|
|
249
|
+
const skillPaths = this.noSkills
|
|
250
|
+
? this.mergePaths(cliEnabledSkills, this.additionalSkillPaths)
|
|
251
|
+
: this.mergePaths([...enabledSkills, ...cliEnabledSkills], this.additionalSkillPaths);
|
|
252
|
+
let skillsResult;
|
|
253
|
+
if (this.noSkills && skillPaths.length === 0) {
|
|
254
|
+
skillsResult = { skills: [], diagnostics: [] };
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
skillsResult = loadSkills({
|
|
258
|
+
cwd: this.cwd,
|
|
259
|
+
agentDir: this.agentDir,
|
|
260
|
+
skillPaths,
|
|
261
|
+
includeDefaults: false,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const resolvedSkills = this.skillsOverride ? this.skillsOverride(skillsResult) : skillsResult;
|
|
265
|
+
this.skills = resolvedSkills.skills;
|
|
266
|
+
this.skillDiagnostics = resolvedSkills.diagnostics;
|
|
267
|
+
for (const skill of this.skills) {
|
|
268
|
+
this.addDefaultMetadataForPath(skill.filePath);
|
|
269
|
+
}
|
|
270
|
+
const promptPaths = this.noPromptTemplates
|
|
271
|
+
? this.mergePaths(cliEnabledPrompts, this.additionalPromptTemplatePaths)
|
|
272
|
+
: this.mergePaths([...enabledPrompts, ...cliEnabledPrompts], this.additionalPromptTemplatePaths);
|
|
273
|
+
let promptsResult;
|
|
274
|
+
if (this.noPromptTemplates && promptPaths.length === 0) {
|
|
275
|
+
promptsResult = { prompts: [], diagnostics: [] };
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
const allPrompts = loadPromptTemplates({
|
|
279
|
+
cwd: this.cwd,
|
|
280
|
+
agentDir: this.agentDir,
|
|
281
|
+
promptPaths,
|
|
282
|
+
includeDefaults: false,
|
|
283
|
+
});
|
|
284
|
+
promptsResult = this.dedupePrompts(allPrompts);
|
|
285
|
+
}
|
|
286
|
+
const resolvedPrompts = this.promptsOverride ? this.promptsOverride(promptsResult) : promptsResult;
|
|
287
|
+
this.prompts = resolvedPrompts.prompts;
|
|
288
|
+
this.promptDiagnostics = resolvedPrompts.diagnostics;
|
|
289
|
+
for (const prompt of this.prompts) {
|
|
290
|
+
this.addDefaultMetadataForPath(prompt.filePath);
|
|
291
|
+
}
|
|
292
|
+
const themePaths = this.noThemes
|
|
293
|
+
? this.mergePaths(cliEnabledThemes, this.additionalThemePaths)
|
|
294
|
+
: this.mergePaths([...enabledThemes, ...cliEnabledThemes], this.additionalThemePaths);
|
|
295
|
+
let themesResult;
|
|
296
|
+
if (this.noThemes && themePaths.length === 0) {
|
|
297
|
+
themesResult = { themes: [], diagnostics: [] };
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
const loaded = this.loadThemes(themePaths, false);
|
|
301
|
+
const deduped = this.dedupeThemes(loaded.themes);
|
|
302
|
+
themesResult = { themes: deduped.themes, diagnostics: [...loaded.diagnostics, ...deduped.diagnostics] };
|
|
303
|
+
}
|
|
304
|
+
const resolvedThemes = this.themesOverride ? this.themesOverride(themesResult) : themesResult;
|
|
305
|
+
this.themes = resolvedThemes.themes;
|
|
306
|
+
this.themeDiagnostics = resolvedThemes.diagnostics;
|
|
307
|
+
for (const theme of this.themes) {
|
|
308
|
+
if (theme.sourcePath) {
|
|
309
|
+
this.addDefaultMetadataForPath(theme.sourcePath);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
for (const extension of this.extensionsResult.extensions) {
|
|
313
|
+
this.addDefaultMetadataForPath(extension.path);
|
|
314
|
+
}
|
|
315
|
+
const agentsFiles = { agentsFiles: loadProjectContextFiles({ cwd: this.cwd, agentDir: this.agentDir }) };
|
|
316
|
+
const resolvedAgentsFiles = this.agentsFilesOverride ? this.agentsFilesOverride(agentsFiles) : agentsFiles;
|
|
317
|
+
this.agentsFiles = resolvedAgentsFiles.agentsFiles;
|
|
318
|
+
const baseSystemPrompt = resolvePromptInput(this.systemPromptSource ?? this.discoverSystemPromptFile(), "system prompt");
|
|
319
|
+
this.systemPrompt = this.systemPromptOverride ? this.systemPromptOverride(baseSystemPrompt) : baseSystemPrompt;
|
|
320
|
+
const appendSource = this.appendSystemPromptSource ?? this.discoverAppendSystemPromptFile();
|
|
321
|
+
const resolvedAppend = resolvePromptInput(appendSource, "append system prompt");
|
|
322
|
+
const baseAppend = resolvedAppend ? [resolvedAppend] : [];
|
|
323
|
+
this.appendSystemPrompt = this.appendSystemPromptOverride
|
|
324
|
+
? this.appendSystemPromptOverride(baseAppend)
|
|
325
|
+
: baseAppend;
|
|
326
|
+
}
|
|
327
|
+
mergePaths(primary, additional) {
|
|
328
|
+
const merged = [];
|
|
329
|
+
const seen = new Set();
|
|
330
|
+
for (const p of [...primary, ...additional]) {
|
|
331
|
+
const resolved = this.resolveResourcePath(p);
|
|
332
|
+
if (seen.has(resolved))
|
|
333
|
+
continue;
|
|
334
|
+
seen.add(resolved);
|
|
335
|
+
merged.push(resolved);
|
|
336
|
+
}
|
|
337
|
+
return merged;
|
|
338
|
+
}
|
|
339
|
+
resolveResourcePath(p) {
|
|
340
|
+
const trimmed = p.trim();
|
|
341
|
+
let expanded = trimmed;
|
|
342
|
+
if (trimmed === "~") {
|
|
343
|
+
expanded = homedir();
|
|
344
|
+
}
|
|
345
|
+
else if (trimmed.startsWith("~/")) {
|
|
346
|
+
expanded = join(homedir(), trimmed.slice(2));
|
|
347
|
+
}
|
|
348
|
+
else if (trimmed.startsWith("~")) {
|
|
349
|
+
expanded = join(homedir(), trimmed.slice(1));
|
|
350
|
+
}
|
|
351
|
+
return resolve(this.cwd, expanded);
|
|
352
|
+
}
|
|
353
|
+
loadThemes(paths, includeDefaults = true) {
|
|
354
|
+
const themes = [];
|
|
355
|
+
const diagnostics = [];
|
|
356
|
+
if (includeDefaults) {
|
|
357
|
+
const defaultDirs = [join(this.agentDir, "themes"), join(this.cwd, CONFIG_DIR_NAME, "themes")];
|
|
358
|
+
for (const dir of defaultDirs) {
|
|
359
|
+
this.loadThemesFromDir(dir, themes, diagnostics);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
for (const p of paths) {
|
|
363
|
+
const resolved = resolve(this.cwd, p);
|
|
364
|
+
if (!existsSync(resolved)) {
|
|
365
|
+
diagnostics.push({ type: "warning", message: "theme path does not exist", path: resolved });
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
try {
|
|
369
|
+
const stats = statSync(resolved);
|
|
370
|
+
if (stats.isDirectory()) {
|
|
371
|
+
this.loadThemesFromDir(resolved, themes, diagnostics);
|
|
372
|
+
}
|
|
373
|
+
else if (stats.isFile() && resolved.endsWith(".json")) {
|
|
374
|
+
this.loadThemeFromFile(resolved, themes, diagnostics);
|
|
375
|
+
}
|
|
376
|
+
else {
|
|
377
|
+
diagnostics.push({ type: "warning", message: "theme path is not a json file", path: resolved });
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
const message = error instanceof Error ? error.message : "failed to read theme path";
|
|
382
|
+
diagnostics.push({ type: "warning", message, path: resolved });
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return { themes, diagnostics };
|
|
386
|
+
}
|
|
387
|
+
loadThemesFromDir(dir, themes, diagnostics) {
|
|
388
|
+
if (!existsSync(dir)) {
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
try {
|
|
392
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
393
|
+
for (const entry of entries) {
|
|
394
|
+
let isFile = entry.isFile();
|
|
395
|
+
if (entry.isSymbolicLink()) {
|
|
396
|
+
try {
|
|
397
|
+
isFile = statSync(join(dir, entry.name)).isFile();
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
if (!isFile) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (!entry.name.endsWith(".json")) {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
this.loadThemeFromFile(join(dir, entry.name), themes, diagnostics);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
const message = error instanceof Error ? error.message : "failed to read theme directory";
|
|
414
|
+
diagnostics.push({ type: "warning", message, path: dir });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
loadThemeFromFile(filePath, themes, diagnostics) {
|
|
418
|
+
try {
|
|
419
|
+
themes.push(loadThemeFromPath(filePath));
|
|
420
|
+
}
|
|
421
|
+
catch (error) {
|
|
422
|
+
const message = error instanceof Error ? error.message : "failed to load theme";
|
|
423
|
+
diagnostics.push({ type: "warning", message, path: filePath });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
async loadExtensionFactories(runtime) {
|
|
427
|
+
const extensions = [];
|
|
428
|
+
const errors = [];
|
|
429
|
+
for (const [index, factory] of this.extensionFactories.entries()) {
|
|
430
|
+
const extensionPath = `<inline:${index + 1}>`;
|
|
431
|
+
try {
|
|
432
|
+
const extension = await loadExtensionFromFactory(factory, this.cwd, this.eventBus, runtime, extensionPath);
|
|
433
|
+
extensions.push(extension);
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
436
|
+
const message = error instanceof Error ? error.message : "failed to load extension";
|
|
437
|
+
errors.push({ path: extensionPath, error: message });
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return { extensions, errors };
|
|
441
|
+
}
|
|
442
|
+
dedupePrompts(prompts) {
|
|
443
|
+
const seen = new Map();
|
|
444
|
+
const diagnostics = [];
|
|
445
|
+
for (const prompt of prompts) {
|
|
446
|
+
const existing = seen.get(prompt.name);
|
|
447
|
+
if (existing) {
|
|
448
|
+
diagnostics.push({
|
|
449
|
+
type: "collision",
|
|
450
|
+
message: `name "/${prompt.name}" collision`,
|
|
451
|
+
path: prompt.filePath,
|
|
452
|
+
collision: {
|
|
453
|
+
resourceType: "prompt",
|
|
454
|
+
name: prompt.name,
|
|
455
|
+
winnerPath: existing.filePath,
|
|
456
|
+
loserPath: prompt.filePath,
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
else {
|
|
461
|
+
seen.set(prompt.name, prompt);
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
return { prompts: Array.from(seen.values()), diagnostics };
|
|
465
|
+
}
|
|
466
|
+
dedupeThemes(themes) {
|
|
467
|
+
const seen = new Map();
|
|
468
|
+
const diagnostics = [];
|
|
469
|
+
for (const t of themes) {
|
|
470
|
+
const name = t.name ?? "unnamed";
|
|
471
|
+
const existing = seen.get(name);
|
|
472
|
+
if (existing) {
|
|
473
|
+
diagnostics.push({
|
|
474
|
+
type: "collision",
|
|
475
|
+
message: `name "${name}" collision`,
|
|
476
|
+
path: t.sourcePath,
|
|
477
|
+
collision: {
|
|
478
|
+
resourceType: "theme",
|
|
479
|
+
name,
|
|
480
|
+
winnerPath: existing.sourcePath ?? "<builtin>",
|
|
481
|
+
loserPath: t.sourcePath ?? "<builtin>",
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
else {
|
|
486
|
+
seen.set(name, t);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return { themes: Array.from(seen.values()), diagnostics };
|
|
490
|
+
}
|
|
491
|
+
discoverSystemPromptFile() {
|
|
492
|
+
const projectPath = join(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md");
|
|
493
|
+
if (existsSync(projectPath)) {
|
|
494
|
+
return projectPath;
|
|
495
|
+
}
|
|
496
|
+
const globalPath = join(this.agentDir, "SYSTEM.md");
|
|
497
|
+
if (existsSync(globalPath)) {
|
|
498
|
+
return globalPath;
|
|
499
|
+
}
|
|
500
|
+
return undefined;
|
|
501
|
+
}
|
|
502
|
+
discoverAppendSystemPromptFile() {
|
|
503
|
+
const projectPath = join(this.cwd, CONFIG_DIR_NAME, "APPEND_SYSTEM.md");
|
|
504
|
+
if (existsSync(projectPath)) {
|
|
505
|
+
return projectPath;
|
|
506
|
+
}
|
|
507
|
+
const globalPath = join(this.agentDir, "APPEND_SYSTEM.md");
|
|
508
|
+
if (existsSync(globalPath)) {
|
|
509
|
+
return globalPath;
|
|
510
|
+
}
|
|
511
|
+
return undefined;
|
|
512
|
+
}
|
|
513
|
+
addDefaultMetadataForPath(filePath) {
|
|
514
|
+
if (!filePath || filePath.startsWith("<")) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const normalizedPath = resolve(filePath);
|
|
518
|
+
if (this.pathMetadata.has(normalizedPath) || this.pathMetadata.has(filePath)) {
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
521
|
+
const agentRoots = [
|
|
522
|
+
join(this.agentDir, "skills"),
|
|
523
|
+
join(this.agentDir, "prompts"),
|
|
524
|
+
join(this.agentDir, "themes"),
|
|
525
|
+
join(this.agentDir, "extensions"),
|
|
526
|
+
];
|
|
527
|
+
const projectRoots = [
|
|
528
|
+
join(this.cwd, CONFIG_DIR_NAME, "skills"),
|
|
529
|
+
join(this.cwd, CONFIG_DIR_NAME, "prompts"),
|
|
530
|
+
join(this.cwd, CONFIG_DIR_NAME, "themes"),
|
|
531
|
+
join(this.cwd, CONFIG_DIR_NAME, "extensions"),
|
|
532
|
+
];
|
|
533
|
+
for (const root of agentRoots) {
|
|
534
|
+
if (this.isUnderPath(normalizedPath, root)) {
|
|
535
|
+
this.pathMetadata.set(normalizedPath, { source: "local", scope: "user", origin: "top-level" });
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
for (const root of projectRoots) {
|
|
540
|
+
if (this.isUnderPath(normalizedPath, root)) {
|
|
541
|
+
this.pathMetadata.set(normalizedPath, { source: "local", scope: "project", origin: "top-level" });
|
|
542
|
+
return;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
isUnderPath(target, root) {
|
|
547
|
+
const normalizedRoot = resolve(root);
|
|
548
|
+
if (target === normalizedRoot) {
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
const prefix = normalizedRoot.endsWith(sep) ? normalizedRoot : `${normalizedRoot}${sep}`;
|
|
552
|
+
return target.startsWith(prefix);
|
|
553
|
+
}
|
|
554
|
+
detectExtensionConflicts(extensions) {
|
|
555
|
+
const conflicts = [];
|
|
556
|
+
// Track which extension registered each tool, command, and flag
|
|
557
|
+
const toolOwners = new Map();
|
|
558
|
+
const commandOwners = new Map();
|
|
559
|
+
const flagOwners = new Map();
|
|
560
|
+
for (const ext of extensions) {
|
|
561
|
+
// Check tools
|
|
562
|
+
for (const toolName of ext.tools.keys()) {
|
|
563
|
+
const existingOwner = toolOwners.get(toolName);
|
|
564
|
+
if (existingOwner && existingOwner !== ext.path) {
|
|
565
|
+
conflicts.push({
|
|
566
|
+
path: ext.path,
|
|
567
|
+
message: `Tool "${toolName}" conflicts with ${existingOwner}`,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
toolOwners.set(toolName, ext.path);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
// Check commands
|
|
575
|
+
for (const commandName of ext.commands.keys()) {
|
|
576
|
+
const existingOwner = commandOwners.get(commandName);
|
|
577
|
+
if (existingOwner && existingOwner !== ext.path) {
|
|
578
|
+
conflicts.push({
|
|
579
|
+
path: ext.path,
|
|
580
|
+
message: `Command "/${commandName}" conflicts with ${existingOwner}`,
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
else {
|
|
584
|
+
commandOwners.set(commandName, ext.path);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
// Check flags
|
|
588
|
+
for (const flagName of ext.flags.keys()) {
|
|
589
|
+
const existingOwner = flagOwners.get(flagName);
|
|
590
|
+
if (existingOwner && existingOwner !== ext.path) {
|
|
591
|
+
conflicts.push({
|
|
592
|
+
path: ext.path,
|
|
593
|
+
message: `Flag "--${flagName}" conflicts with ${existingOwner}`,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
flagOwners.set(flagName, ext.path);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
return conflicts;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
//# sourceMappingURL=resource-loader.js.map
|