@earendil-works/pi-coding-agent 0.80.2 → 0.80.5
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 +115 -1
- package/README.md +3 -2
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts +4 -2
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/file-processor.d.ts.map +1 -1
- package/dist/cli/file-processor.js +13 -25
- package/dist/cli/file-processor.js.map +1 -1
- package/dist/core/agent-session.d.ts +22 -5
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +133 -50
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +13 -5
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/cache-stats.d.ts +49 -0
- package/dist/core/cache-stats.d.ts.map +1 -0
- package/dist/core/cache-stats.js +101 -0
- package/dist/core/cache-stats.js.map +1 -0
- package/dist/core/compaction/compaction.d.ts +1 -2
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +56 -81
- package/dist/core/compaction/compaction.js.map +1 -1
- 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.map +1 -1
- package/dist/core/extensions/loader.js +10 -0
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +5 -3
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +38 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +39 -5
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +28 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/keybindings.d.ts.map +1 -1
- package/dist/core/keybindings.js +3 -6
- package/dist/core/keybindings.js.map +1 -1
- package/dist/core/model-registry.d.ts +3 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +16 -2
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts +10 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +15 -18
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +4 -1
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +68 -26
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/provider-attribution.d.ts.map +1 -1
- package/dist/core/provider-attribution.js +0 -10
- package/dist/core/provider-attribution.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -2
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +8 -7
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +8 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +21 -2
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +104 -72
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +10 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +27 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts +1 -0
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +3 -3
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/timings.d.ts +4 -2
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +24 -14
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +20 -5
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +2 -2
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +12 -25
- package/dist/core/tools/read.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +2 -2
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +17 -4
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +3 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +23 -15
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts +34 -3
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +280 -25
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts +19 -0
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -0
- package/dist/modes/interactive/components/custom-entry.js +52 -0
- package/dist/modes/interactive/components/custom-entry.js.map +1 -0
- package/dist/modes/interactive/components/extension-editor.d.ts +3 -1
- package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/extension-editor.js +12 -3
- package/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts +4 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +3 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +17 -6
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +4 -0
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +23 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts +28 -0
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -0
- package/dist/modes/interactive/components/status-indicator.js +60 -0
- package/dist/modes/interactive/components/status-indicator.js.map +1 -0
- package/dist/modes/interactive/components/user-message.d.ts +6 -2
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +19 -6
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +21 -10
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +417 -196
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +1 -1
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +21 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +17 -3
- 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 +20 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +26 -0
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/package-manager-cli.d.ts +2 -2
- package/dist/package-manager-cli.d.ts.map +1 -1
- package/dist/package-manager-cli.js +71 -17
- package/dist/package-manager-cli.js.map +1 -1
- package/dist/rpc-entry.d.ts +3 -0
- package/dist/rpc-entry.d.ts.map +1 -0
- package/dist/rpc-entry.js +10 -0
- package/dist/rpc-entry.js.map +1 -0
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -1
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/image-convert.d.ts +1 -0
- package/dist/utils/image-convert.d.ts.map +1 -1
- package/dist/utils/image-convert.js +21 -15
- package/dist/utils/image-convert.js.map +1 -1
- package/dist/utils/image-process.d.ts +18 -0
- package/dist/utils/image-process.d.ts.map +1 -0
- package/dist/utils/image-process.js +83 -0
- package/dist/utils/image-process.js.map +1 -0
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +41 -0
- package/dist/utils/mime.js.map +1 -1
- package/docs/extensions.md +88 -17
- package/docs/keybindings.md +1 -1
- package/docs/models.md +4 -4
- package/docs/packages.md +2 -2
- package/docs/providers.md +2 -1
- package/docs/rpc.md +71 -3
- package/docs/sdk.md +50 -0
- package/docs/session-format.md +18 -8
- package/docs/settings.md +11 -0
- package/docs/usage.md +3 -3
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-compaction.ts +1 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/entry-renderer.ts +41 -0
- package/examples/extensions/gondolin/package-lock.json +2 -2
- package/examples/extensions/gondolin/package.json +1 -1
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -0
- package/examples/extensions/reload-runtime.ts +2 -2
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/summarize.ts +1 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/examples/sdk/12-full-control.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +8 -5
|
@@ -5,9 +5,11 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import { basename, dirname, join, relative } from "node:path";
|
|
6
6
|
import { Container, getKeybindings, Input, matchesKey, Spacer, truncateToWidth, visibleWidth, } from "@earendil-works/pi-tui";
|
|
7
7
|
import { CONFIG_DIR_NAME } from "../../../config.js";
|
|
8
|
+
import { canonicalizePath, isLocalPath, resolvePath } from "../../../utils/paths.js";
|
|
8
9
|
import { theme } from "../theme/theme.js";
|
|
9
10
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
10
|
-
import { rawKeyHint } from "./keybinding-hints.js";
|
|
11
|
+
import { keyHint, rawKeyHint } from "./keybinding-hints.js";
|
|
12
|
+
const RESOURCE_TYPES = ["extensions", "skills", "prompts", "themes"];
|
|
11
13
|
const RESOURCE_TYPE_LABELS = {
|
|
12
14
|
extensions: "Extensions",
|
|
13
15
|
skills: "Skills",
|
|
@@ -121,22 +123,34 @@ function buildGroups(resolved, agentDir) {
|
|
|
121
123
|
return groups;
|
|
122
124
|
}
|
|
123
125
|
class ConfigSelectorHeader {
|
|
126
|
+
writeScope;
|
|
127
|
+
projectModeAvailable;
|
|
128
|
+
constructor(writeScope, projectModeAvailable) {
|
|
129
|
+
this.writeScope = writeScope;
|
|
130
|
+
this.projectModeAvailable = projectModeAvailable;
|
|
131
|
+
}
|
|
132
|
+
setWriteScope(writeScope) {
|
|
133
|
+
this.writeScope = writeScope;
|
|
134
|
+
}
|
|
124
135
|
invalidate() { }
|
|
125
136
|
render(width) {
|
|
126
|
-
const title = theme.bold("
|
|
137
|
+
const title = theme.bold(this.writeScope === "project" ? "Project Local Resources" : "Global Resources");
|
|
127
138
|
const sep = theme.fg("muted", " · ");
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
const
|
|
131
|
-
const spacing = Math.max(1, width -
|
|
139
|
+
const switchHint = this.projectModeAvailable ? keyHint("tui.input.tab", "switch mode") + sep : "";
|
|
140
|
+
const actionHint = this.writeScope === "project" ? rawKeyHint("space", "cycle inherit/+/-") : rawKeyHint("space", "toggle");
|
|
141
|
+
const hint = switchHint + actionHint + sep + rawKeyHint("esc", "close");
|
|
142
|
+
const spacing = Math.max(1, width - visibleWidth(title) - visibleWidth(hint));
|
|
143
|
+
const scopeHint = this.writeScope === "project"
|
|
144
|
+
? theme.fg("muted", `${CONFIG_DIR_NAME}/settings.json · inherited global resources are dimmed`)
|
|
145
|
+
: theme.fg("muted", `~/${CONFIG_DIR_NAME}/agent/settings.json`);
|
|
132
146
|
return [
|
|
133
147
|
truncateToWidth(`${title}${" ".repeat(spacing)}${hint}`, width, ""),
|
|
134
|
-
|
|
148
|
+
truncateToWidth(scopeHint, width, ""),
|
|
135
149
|
];
|
|
136
150
|
}
|
|
137
151
|
}
|
|
138
152
|
class ResourceList {
|
|
139
|
-
|
|
153
|
+
groupsByScope;
|
|
140
154
|
flatItems = [];
|
|
141
155
|
filteredItems = [];
|
|
142
156
|
selectedIndex = 0;
|
|
@@ -145,9 +159,12 @@ class ResourceList {
|
|
|
145
159
|
settingsManager;
|
|
146
160
|
cwd;
|
|
147
161
|
agentDir;
|
|
162
|
+
writeScope;
|
|
163
|
+
inheritedEnabledByKey;
|
|
148
164
|
onCancel;
|
|
149
165
|
onExit;
|
|
150
166
|
onToggle;
|
|
167
|
+
onSwitchMode;
|
|
151
168
|
_focused = false;
|
|
152
169
|
get focused() {
|
|
153
170
|
return this._focused;
|
|
@@ -156,11 +173,13 @@ class ResourceList {
|
|
|
156
173
|
this._focused = value;
|
|
157
174
|
this.searchInput.focused = value;
|
|
158
175
|
}
|
|
159
|
-
constructor(
|
|
160
|
-
this.
|
|
176
|
+
constructor(groupsByScope, settingsManager, cwd, agentDir, terminalHeight, writeScope = "global") {
|
|
177
|
+
this.groupsByScope = groupsByScope;
|
|
161
178
|
this.settingsManager = settingsManager;
|
|
162
179
|
this.cwd = cwd;
|
|
163
180
|
this.agentDir = agentDir;
|
|
181
|
+
this.writeScope = writeScope;
|
|
182
|
+
this.inheritedEnabledByKey = this.buildInheritedEnabledMap(groupsByScope.global);
|
|
164
183
|
this.searchInput = new Input();
|
|
165
184
|
// 8 lines of chrome: top spacer + top border + spacer + header (2 lines) + spacer + bottom spacer + bottom border
|
|
166
185
|
const chrome = 8;
|
|
@@ -168,6 +187,25 @@ class ResourceList {
|
|
|
168
187
|
this.buildFlatList();
|
|
169
188
|
this.filteredItems = [...this.flatItems];
|
|
170
189
|
}
|
|
190
|
+
setWriteScope(writeScope) {
|
|
191
|
+
this.writeScope = writeScope;
|
|
192
|
+
this.buildFlatList();
|
|
193
|
+
this.filterItems(this.searchInput.getValue());
|
|
194
|
+
}
|
|
195
|
+
get groups() {
|
|
196
|
+
return this.groupsByScope[this.writeScope];
|
|
197
|
+
}
|
|
198
|
+
buildInheritedEnabledMap(groups) {
|
|
199
|
+
const result = new Map();
|
|
200
|
+
for (const group of groups) {
|
|
201
|
+
for (const subgroup of group.subgroups) {
|
|
202
|
+
for (const item of subgroup.items) {
|
|
203
|
+
result.set(this.getResourceItemKey(item), item.enabled);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return result;
|
|
208
|
+
}
|
|
171
209
|
buildFlatList() {
|
|
172
210
|
this.flatItems = [];
|
|
173
211
|
for (const group of this.groups) {
|
|
@@ -274,21 +312,25 @@ class ResourceList {
|
|
|
274
312
|
const isSelected = i === this.selectedIndex;
|
|
275
313
|
if (entry.type === "group") {
|
|
276
314
|
// Main group header (no cursor)
|
|
277
|
-
const
|
|
315
|
+
const inherited = this.writeScope === "project" && entry.group.scope === "user";
|
|
316
|
+
const label = theme.bold(`${entry.group.label}${inherited ? " · inherited global" : ""}`);
|
|
317
|
+
const groupLine = theme.fg(inherited ? "dim" : "accent", label);
|
|
278
318
|
lines.push(truncateToWidth(` ${groupLine}`, width, ""));
|
|
279
319
|
}
|
|
280
320
|
else if (entry.type === "subgroup") {
|
|
281
321
|
// Subgroup header (indented, no cursor)
|
|
282
|
-
const
|
|
322
|
+
const color = this.writeScope === "project" && entry.group.scope === "user" ? "dim" : "muted";
|
|
323
|
+
const subgroupLine = theme.fg(color, entry.subgroup.label);
|
|
283
324
|
lines.push(truncateToWidth(` ${subgroupLine}`, width, ""));
|
|
284
325
|
}
|
|
285
326
|
else {
|
|
286
327
|
// Resource item (cursor only on items)
|
|
287
328
|
const item = entry.item;
|
|
288
329
|
const cursor = isSelected ? "> " : " ";
|
|
289
|
-
const
|
|
290
|
-
const
|
|
291
|
-
|
|
330
|
+
const dimmed = this.isDimmedItem(item);
|
|
331
|
+
const nameText = isSelected && !dimmed ? theme.bold(item.displayName) : item.displayName;
|
|
332
|
+
const name = dimmed ? theme.fg("dim", nameText) : nameText;
|
|
333
|
+
lines.push(truncateToWidth(`${cursor} ${this.renderCheckbox(item)} ${name}${this.getItemSuffix(item)}`, width, "..."));
|
|
292
334
|
}
|
|
293
335
|
}
|
|
294
336
|
// Scroll indicator
|
|
@@ -339,13 +381,18 @@ class ResourceList {
|
|
|
339
381
|
this.onExit?.();
|
|
340
382
|
return;
|
|
341
383
|
}
|
|
384
|
+
if (kb.matches(data, "tui.input.tab")) {
|
|
385
|
+
this.onSwitchMode?.();
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
342
388
|
if (data === " " || kb.matches(data, "tui.select.confirm")) {
|
|
343
389
|
const entry = this.filteredItems[this.selectedIndex];
|
|
344
|
-
if (entry?.type === "item") {
|
|
345
|
-
const newEnabled =
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
390
|
+
if (entry?.type === "item" && (this.writeScope === "project" || this.getItemScope(entry.item) === "user")) {
|
|
391
|
+
const newEnabled = this.toggleResource(entry.item);
|
|
392
|
+
if (newEnabled !== undefined) {
|
|
393
|
+
this.updateItem(entry.item, newEnabled);
|
|
394
|
+
this.onToggle?.(entry.item, newEnabled);
|
|
395
|
+
}
|
|
349
396
|
}
|
|
350
397
|
return;
|
|
351
398
|
}
|
|
@@ -353,13 +400,21 @@ class ResourceList {
|
|
|
353
400
|
this.searchInput.handleInput(data);
|
|
354
401
|
this.filterItems(this.searchInput.getValue());
|
|
355
402
|
}
|
|
356
|
-
toggleResource(item
|
|
403
|
+
toggleResource(item) {
|
|
404
|
+
if (this.writeScope === "project") {
|
|
405
|
+
const state = this.getNextOverrideState(item);
|
|
406
|
+
if (!this.setProjectResourceOverride(item, state))
|
|
407
|
+
return undefined;
|
|
408
|
+
return state === "inherit" ? this.getInheritedEnabled(item) : state === "load";
|
|
409
|
+
}
|
|
410
|
+
const enabled = !item.enabled;
|
|
357
411
|
if (item.metadata.origin === "top-level") {
|
|
358
412
|
this.toggleTopLevelResource(item, enabled);
|
|
359
413
|
}
|
|
360
414
|
else {
|
|
361
415
|
this.togglePackageResource(item, enabled);
|
|
362
416
|
}
|
|
417
|
+
return enabled;
|
|
363
418
|
}
|
|
364
419
|
toggleTopLevelResource(item, enabled) {
|
|
365
420
|
const scope = item.metadata.scope;
|
|
@@ -457,6 +512,188 @@ class ResourceList {
|
|
|
457
512
|
this.settingsManager.setPackages(packages);
|
|
458
513
|
}
|
|
459
514
|
}
|
|
515
|
+
renderCheckbox(item) {
|
|
516
|
+
if (this.writeScope === "project") {
|
|
517
|
+
const state = this.getProjectOverrideState(item);
|
|
518
|
+
if (state === "load")
|
|
519
|
+
return theme.fg("success", "[+]");
|
|
520
|
+
if (state === "unload")
|
|
521
|
+
return theme.fg("warning", "[-]");
|
|
522
|
+
return theme.fg("dim", item.enabled ? "[x]" : "[ ]");
|
|
523
|
+
}
|
|
524
|
+
return item.enabled ? theme.fg("success", "[x]") : theme.fg("dim", "[ ]");
|
|
525
|
+
}
|
|
526
|
+
getItemSuffix(item) {
|
|
527
|
+
if (this.writeScope !== "project")
|
|
528
|
+
return "";
|
|
529
|
+
const state = this.getProjectOverrideState(item);
|
|
530
|
+
if (state === "load")
|
|
531
|
+
return theme.fg("muted", " project load");
|
|
532
|
+
if (state === "unload")
|
|
533
|
+
return theme.fg("muted", " project unload");
|
|
534
|
+
return this.isInheritedGlobalItem(item) ? theme.fg("dim", " inherited global") : "";
|
|
535
|
+
}
|
|
536
|
+
isDimmedItem(item) {
|
|
537
|
+
return (this.writeScope === "project" &&
|
|
538
|
+
this.isInheritedGlobalItem(item) &&
|
|
539
|
+
this.getProjectOverrideState(item) === "inherit");
|
|
540
|
+
}
|
|
541
|
+
setProjectResourceOverride(item, state) {
|
|
542
|
+
return item.metadata.origin === "top-level"
|
|
543
|
+
? this.setProjectTopLevelOverride(item, state)
|
|
544
|
+
: this.setProjectPackageOverride(item, state);
|
|
545
|
+
}
|
|
546
|
+
setProjectTopLevelOverride(item, state) {
|
|
547
|
+
const current = (this.settingsManager.getProjectSettings()[item.resourceType] ?? []);
|
|
548
|
+
const pattern = this.isInheritedGlobalItem(item) ? item.path : this.getResourcePatternForScope(item, "project");
|
|
549
|
+
const patterns = this.getTopLevelOverridePatterns(item, "project");
|
|
550
|
+
const updated = current.filter((entry) => {
|
|
551
|
+
const target = this.getPatternEntryTarget(entry);
|
|
552
|
+
if ((entry.startsWith("!") || entry.startsWith("+") || entry.startsWith("-")) && patterns.has(target))
|
|
553
|
+
return false;
|
|
554
|
+
return !(state === "inherit" && this.isInheritedGlobalItem(item) && target === pattern);
|
|
555
|
+
});
|
|
556
|
+
if (state !== "inherit") {
|
|
557
|
+
if (this.isInheritedGlobalItem(item) && !updated.includes(pattern))
|
|
558
|
+
updated.push(pattern);
|
|
559
|
+
updated.push(`${state === "load" ? "+" : "-"}${pattern}`);
|
|
560
|
+
}
|
|
561
|
+
this.setProjectTopLevelPaths(item.resourceType, updated);
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
setProjectTopLevelPaths(key, paths) {
|
|
565
|
+
if (key === "extensions")
|
|
566
|
+
this.settingsManager.setProjectExtensionPaths(paths);
|
|
567
|
+
else if (key === "skills")
|
|
568
|
+
this.settingsManager.setProjectSkillPaths(paths);
|
|
569
|
+
else if (key === "prompts")
|
|
570
|
+
this.settingsManager.setProjectPromptTemplatePaths(paths);
|
|
571
|
+
else
|
|
572
|
+
this.settingsManager.setProjectThemePaths(paths);
|
|
573
|
+
}
|
|
574
|
+
setProjectPackageOverride(item, state) {
|
|
575
|
+
const packages = [...(this.settingsManager.getProjectSettings().packages ?? [])];
|
|
576
|
+
let pkgIndex = packages.findIndex((pkg) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, "project"));
|
|
577
|
+
if (pkgIndex === -1) {
|
|
578
|
+
if (state === "inherit")
|
|
579
|
+
return false;
|
|
580
|
+
packages.push(this.createPackageOverrideSource(item));
|
|
581
|
+
pkgIndex = packages.length - 1;
|
|
582
|
+
}
|
|
583
|
+
let pkg = packages[pkgIndex];
|
|
584
|
+
if (pkg === undefined)
|
|
585
|
+
return false;
|
|
586
|
+
if (typeof pkg === "string") {
|
|
587
|
+
pkg = { source: pkg };
|
|
588
|
+
packages[pkgIndex] = pkg;
|
|
589
|
+
}
|
|
590
|
+
const pattern = this.getPackageResourcePattern(item);
|
|
591
|
+
const updated = (pkg[item.resourceType] ?? []).filter((entry) => this.getPatternEntryTarget(entry) !== pattern);
|
|
592
|
+
if (state !== "inherit")
|
|
593
|
+
updated.push(`${state === "load" ? "+" : "-"}${pattern}`);
|
|
594
|
+
pkg[item.resourceType] = updated.length > 0 ? updated : undefined;
|
|
595
|
+
if (!RESOURCE_TYPES.some((key) => pkg[key] !== undefined)) {
|
|
596
|
+
if (pkg.autoload === false)
|
|
597
|
+
packages.splice(pkgIndex, 1);
|
|
598
|
+
else
|
|
599
|
+
packages[pkgIndex] = pkg.source;
|
|
600
|
+
}
|
|
601
|
+
this.settingsManager.setProjectPackages(packages);
|
|
602
|
+
return true;
|
|
603
|
+
}
|
|
604
|
+
getNextOverrideState(item) {
|
|
605
|
+
const state = this.getProjectOverrideState(item);
|
|
606
|
+
const inheritedEnabled = this.getInheritedEnabled(item);
|
|
607
|
+
if (state === "inherit")
|
|
608
|
+
return inheritedEnabled ? "unload" : "load";
|
|
609
|
+
if (state === "unload")
|
|
610
|
+
return inheritedEnabled ? "load" : "inherit";
|
|
611
|
+
return inheritedEnabled ? "inherit" : "unload";
|
|
612
|
+
}
|
|
613
|
+
getProjectOverrideState(item) {
|
|
614
|
+
if (this.writeScope !== "project")
|
|
615
|
+
return "inherit";
|
|
616
|
+
if (item.metadata.origin === "top-level") {
|
|
617
|
+
return this.getOverrideStateFromEntries((this.settingsManager.getProjectSettings()[item.resourceType] ?? []), this.getTopLevelOverridePatterns(item, "project"), false);
|
|
618
|
+
}
|
|
619
|
+
const pkg = this.findMatchingPackageSource(item, "project");
|
|
620
|
+
if (typeof pkg !== "object")
|
|
621
|
+
return "inherit";
|
|
622
|
+
const entries = pkg[item.resourceType];
|
|
623
|
+
if (entries === undefined)
|
|
624
|
+
return "inherit";
|
|
625
|
+
return this.getOverrideStateFromEntries(entries, new Set([this.getPackageResourcePattern(item)]), pkg.autoload !== false);
|
|
626
|
+
}
|
|
627
|
+
getOverrideStateFromEntries(entries, patterns, emptyArrayIsUnload) {
|
|
628
|
+
if (entries.length === 0 && emptyArrayIsUnload)
|
|
629
|
+
return "unload";
|
|
630
|
+
let state = "inherit";
|
|
631
|
+
for (const entry of entries) {
|
|
632
|
+
if (!patterns.has(this.getPatternEntryTarget(entry)))
|
|
633
|
+
continue;
|
|
634
|
+
if (entry.startsWith("!") || entry.startsWith("-"))
|
|
635
|
+
state = "unload";
|
|
636
|
+
else
|
|
637
|
+
state = "load";
|
|
638
|
+
}
|
|
639
|
+
return state;
|
|
640
|
+
}
|
|
641
|
+
getInheritedEnabled(item) {
|
|
642
|
+
return (this.inheritedEnabledByKey.get(this.getResourceItemKey(item)) ??
|
|
643
|
+
(this.getItemScope(item) === "user" ? item.enabled : true));
|
|
644
|
+
}
|
|
645
|
+
isInheritedGlobalItem(item) {
|
|
646
|
+
return this.getItemScope(item) === "user" || this.inheritedEnabledByKey.has(this.getResourceItemKey(item));
|
|
647
|
+
}
|
|
648
|
+
getTopLevelOverridePatterns(item, scope) {
|
|
649
|
+
const baseDir = this.getTopLevelBaseDir(scope);
|
|
650
|
+
const patterns = new Set([
|
|
651
|
+
this.getResourcePatternForScope(item, scope),
|
|
652
|
+
item.path,
|
|
653
|
+
relative(baseDir, item.path),
|
|
654
|
+
]);
|
|
655
|
+
if (item.metadata.baseDir)
|
|
656
|
+
patterns.add(relative(item.metadata.baseDir, item.path));
|
|
657
|
+
return patterns;
|
|
658
|
+
}
|
|
659
|
+
getResourcePatternForScope(item, scope) {
|
|
660
|
+
const sourceScope = this.getItemScope(item);
|
|
661
|
+
if (scope !== sourceScope)
|
|
662
|
+
return item.path;
|
|
663
|
+
const baseDir = item.metadata.baseDir ?? this.getTopLevelBaseDir(sourceScope);
|
|
664
|
+
return relative(baseDir, item.path);
|
|
665
|
+
}
|
|
666
|
+
createPackageOverrideSource(item) {
|
|
667
|
+
const source = item.metadata.source;
|
|
668
|
+
if (!isLocalPath(source))
|
|
669
|
+
return { source, autoload: false };
|
|
670
|
+
const sourcePath = resolvePath(source, this.getTopLevelBaseDir(this.getItemScope(item)), { trim: true });
|
|
671
|
+
return { source: relative(this.getTopLevelBaseDir("project"), sourcePath) || ".", autoload: false };
|
|
672
|
+
}
|
|
673
|
+
packageSourceStringMatches(leftSource, leftScope, rightSource, rightScope) {
|
|
674
|
+
if (leftSource === rightSource)
|
|
675
|
+
return true;
|
|
676
|
+
if (!isLocalPath(leftSource) || !isLocalPath(rightSource))
|
|
677
|
+
return false;
|
|
678
|
+
const left = resolvePath(leftSource, this.getTopLevelBaseDir(leftScope), { trim: true });
|
|
679
|
+
const right = resolvePath(rightSource, this.getTopLevelBaseDir(rightScope), { trim: true });
|
|
680
|
+
return left === right;
|
|
681
|
+
}
|
|
682
|
+
findMatchingPackageSource(item, targetScope) {
|
|
683
|
+
const settings = targetScope === "project"
|
|
684
|
+
? this.settingsManager.getProjectSettings()
|
|
685
|
+
: this.settingsManager.getGlobalSettings();
|
|
686
|
+
return (settings.packages ?? []).find((pkg) => this.packageSourceStringMatches(item.metadata.source, this.getItemScope(item), typeof pkg === "string" ? pkg : pkg.source, targetScope));
|
|
687
|
+
}
|
|
688
|
+
getPatternEntryTarget(entry) {
|
|
689
|
+
return entry.startsWith("!") || entry.startsWith("+") || entry.startsWith("-") ? entry.slice(1) : entry;
|
|
690
|
+
}
|
|
691
|
+
getResourceItemKey(item) {
|
|
692
|
+
return `${item.resourceType}:${canonicalizePath(item.path)}`;
|
|
693
|
+
}
|
|
694
|
+
getItemScope(item) {
|
|
695
|
+
return item.metadata.scope === "project" ? "project" : "user";
|
|
696
|
+
}
|
|
460
697
|
getTopLevelBaseDir(scope) {
|
|
461
698
|
return scope === "project" ? join(this.cwd, CONFIG_DIR_NAME) : this.agentDir;
|
|
462
699
|
}
|
|
@@ -471,7 +708,9 @@ class ResourceList {
|
|
|
471
708
|
}
|
|
472
709
|
}
|
|
473
710
|
export class ConfigSelectorComponent extends Container {
|
|
711
|
+
header;
|
|
474
712
|
resourceList;
|
|
713
|
+
writeScope;
|
|
475
714
|
_focused = false;
|
|
476
715
|
get focused() {
|
|
477
716
|
return this._focused;
|
|
@@ -480,25 +719,41 @@ export class ConfigSelectorComponent extends Container {
|
|
|
480
719
|
this._focused = value;
|
|
481
720
|
this.resourceList.focused = value;
|
|
482
721
|
}
|
|
483
|
-
constructor(resolvedPaths, settingsManager, cwd, agentDir, onClose, onExit, requestRender, terminalHeight) {
|
|
722
|
+
constructor(resolvedPaths, settingsManager, cwd, agentDir, onClose, onExit, requestRender, terminalHeight, writeScope = "global", projectModeAvailable = true) {
|
|
484
723
|
super();
|
|
485
|
-
|
|
724
|
+
this.writeScope = writeScope;
|
|
725
|
+
const groupsByScope = {
|
|
726
|
+
global: buildGroups(resolvedPaths.global, agentDir),
|
|
727
|
+
project: buildGroups(resolvedPaths.project, agentDir),
|
|
728
|
+
};
|
|
486
729
|
// Add header
|
|
487
730
|
this.addChild(new Spacer(1));
|
|
488
731
|
this.addChild(new DynamicBorder());
|
|
489
732
|
this.addChild(new Spacer(1));
|
|
490
|
-
this.
|
|
733
|
+
this.header = new ConfigSelectorHeader(this.writeScope, projectModeAvailable);
|
|
734
|
+
this.addChild(this.header);
|
|
491
735
|
this.addChild(new Spacer(1));
|
|
492
736
|
// Resource list
|
|
493
|
-
this.resourceList = new ResourceList(
|
|
737
|
+
this.resourceList = new ResourceList(groupsByScope, settingsManager, cwd, agentDir, terminalHeight, this.writeScope);
|
|
494
738
|
this.resourceList.onCancel = onClose;
|
|
495
739
|
this.resourceList.onExit = onExit;
|
|
496
740
|
this.resourceList.onToggle = () => requestRender();
|
|
741
|
+
if (projectModeAvailable) {
|
|
742
|
+
this.resourceList.onSwitchMode = () => {
|
|
743
|
+
this.switchWriteScope();
|
|
744
|
+
requestRender();
|
|
745
|
+
};
|
|
746
|
+
}
|
|
497
747
|
this.addChild(this.resourceList);
|
|
498
748
|
// Bottom border
|
|
499
749
|
this.addChild(new Spacer(1));
|
|
500
750
|
this.addChild(new DynamicBorder());
|
|
501
751
|
}
|
|
752
|
+
switchWriteScope() {
|
|
753
|
+
this.writeScope = this.writeScope === "global" ? "project" : "global";
|
|
754
|
+
this.header.setWriteScope(this.writeScope);
|
|
755
|
+
this.resourceList.setWriteScope(this.writeScope);
|
|
756
|
+
}
|
|
502
757
|
getResourceList() {
|
|
503
758
|
return this.resourceList;
|
|
504
759
|
}
|