@mrclrchtr/supi-skills 7.2.0 → 7.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/node_modules/@mrclrchtr/supi-core/README.md +10 -0
- package/node_modules/@mrclrchtr/supi-core/package.json +3 -2
- package/node_modules/@mrclrchtr/supi-core/src/api.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/index.ts +2 -0
- package/node_modules/@mrclrchtr/supi-core/src/session-capabilities.ts +188 -0
- package/node_modules/@mrclrchtr/supi-core/src/session.ts +17 -0
- package/node_modules/@mrclrchtr/supi-core/src/tui.ts +141 -0
- package/package.json +2 -2
- package/src/skill-model-invocation.ts +89 -17
- package/src/skill-settings-controller.ts +365 -0
- package/src/skill-settings.ts +52 -359
package/src/skill-settings.ts
CHANGED
|
@@ -1,398 +1,91 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
1
2
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from "@earendil-works/pi-coding-agent";
|
|
9
|
-
import {
|
|
10
|
-
registerSettings,
|
|
11
|
-
type ScopedFieldValue,
|
|
12
|
-
type SettingsAction,
|
|
13
|
-
type SettingsApplyResult,
|
|
14
|
-
type SettingsContext,
|
|
15
|
-
type SettingsModule,
|
|
16
|
-
type SettingsScope,
|
|
17
|
-
type ValueSource,
|
|
18
|
-
} from "@mrclrchtr/supi-core/settings";
|
|
19
|
-
import {
|
|
20
|
-
buildSkillCatalog,
|
|
21
|
-
mergeRuntimeSkills,
|
|
22
|
-
type SkillCatalog,
|
|
23
|
-
type SkillRecord,
|
|
24
|
-
skillSourceIdentity,
|
|
25
|
-
} from "./skill-catalog.ts";
|
|
26
|
-
import {
|
|
27
|
-
hasExactSkillLoadOverride,
|
|
28
|
-
type SkillLoadOverride,
|
|
29
|
-
updateSkillLoadOverrides,
|
|
30
|
-
} from "./skill-load-settings.ts";
|
|
31
|
-
import {
|
|
32
|
-
applyPromptOverrides,
|
|
33
|
-
DISABLED,
|
|
34
|
-
ENABLED,
|
|
35
|
-
MODEL_DISABLED,
|
|
36
|
-
notifyInvocationConfigWarnings,
|
|
37
|
-
persistInvocation,
|
|
38
|
-
resolveInvocation,
|
|
39
|
-
} from "./skill-model-invocation.ts";
|
|
3
|
+
registerSessionCapabilitySkillProvider,
|
|
4
|
+
sessionCapabilityState,
|
|
5
|
+
} from "@mrclrchtr/supi-core/session";
|
|
6
|
+
import { registerSettings, type SettingsModule } from "@mrclrchtr/supi-core/settings";
|
|
7
|
+
import { applyPromptOverrides, notifyInvocationConfigWarnings } from "./skill-model-invocation.ts";
|
|
8
|
+
import { SkillSettingsController, type SkillSettingsOptions } from "./skill-settings-controller.ts";
|
|
40
9
|
|
|
41
10
|
const SETTINGS_SECTION_ID = "skills";
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
interface SkillSettingsControllerOptions {
|
|
47
|
-
cwd: string;
|
|
48
|
-
agentDir: string;
|
|
49
|
-
homeDir?: string;
|
|
50
|
-
projectTrusted: boolean;
|
|
51
|
-
settingsManager: SettingsManager;
|
|
52
|
-
globalSettingsManager: SettingsManager;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function recordResources(record: SkillRecord): ResolvedResource[] {
|
|
56
|
-
return record.sources.flatMap((source) => (source.resource ? [source.resource] : []));
|
|
57
|
-
}
|
|
58
|
-
function isLoaded(record: SkillRecord): boolean {
|
|
59
|
-
return (
|
|
60
|
-
record.activeSkill !== undefined ||
|
|
61
|
-
record.sources.some((source) => source.runtime || source.resource?.enabled)
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
function canDisable(record: SkillRecord): boolean {
|
|
65
|
-
return record.sources.length > 0 && record.sources.every((source) => !source.runtime);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function sourceDefault(record: SkillRecord): boolean {
|
|
69
|
-
const winner =
|
|
70
|
-
record.activeSkill ??
|
|
71
|
-
record.sources.find((source) => source.runtime || source.resource?.enabled)?.skill ??
|
|
72
|
-
record.sources[0]?.skill;
|
|
73
|
-
return winner?.disableModelInvocation ?? false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function moreSpecificSource(left: ValueSource, right: ValueSource): ValueSource {
|
|
77
|
-
const rank: Record<ValueSource, number> = { default: 0, global: 1, project: 2 };
|
|
78
|
-
return rank[left] >= rank[right] ? left : right;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function displayValue(value: string, source: ValueSource): string {
|
|
82
|
-
return `${value} (${source})`;
|
|
83
|
-
}
|
|
11
|
+
type SkillControllerGetter = (
|
|
12
|
+
cwd: string,
|
|
13
|
+
projectTrusted: boolean,
|
|
14
|
+
) => Promise<SkillSettingsController>;
|
|
84
15
|
|
|
85
|
-
function
|
|
86
|
-
if (action.kind !== "set") return;
|
|
87
|
-
if (![ENABLED, MODEL_DISABLED, DISABLED].includes(action.value)) {
|
|
88
|
-
throw new Error(`Invalid skill state: "${action.value}"`);
|
|
89
|
-
}
|
|
90
|
-
if (action.value === DISABLED && !canDisable(record)) {
|
|
91
|
-
throw new Error(`Full disable is unavailable for skill "${record.name}"`);
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function loadOverride(
|
|
96
|
-
record: SkillRecord,
|
|
97
|
-
action: SettingsAction,
|
|
98
|
-
hasExactOverride: boolean,
|
|
99
|
-
): SkillLoadOverride | undefined {
|
|
100
|
-
if (action.kind === "unset") return hasExactOverride ? "inherit" : undefined;
|
|
101
|
-
if (action.value === DISABLED) return "unload";
|
|
102
|
-
return isLoaded(record) ? undefined : "load";
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
class SkillSettingsController {
|
|
106
|
-
private readonly cwd: string;
|
|
107
|
-
private readonly agentDir: string;
|
|
108
|
-
private readonly homeDir: string | undefined;
|
|
109
|
-
private readonly projectTrusted: boolean;
|
|
110
|
-
private readonly settingsManager: SettingsManager;
|
|
111
|
-
private readonly globalSettingsManager: SettingsManager;
|
|
112
|
-
private readonly pendingDisabled = new Map<string, Set<string>>();
|
|
113
|
-
private globalCatalog: SkillCatalog = new Map();
|
|
114
|
-
private projectCatalog: SkillCatalog = new Map();
|
|
115
|
-
|
|
116
|
-
private constructor(options: SkillSettingsControllerOptions) {
|
|
117
|
-
this.cwd = options.cwd;
|
|
118
|
-
this.agentDir = options.agentDir;
|
|
119
|
-
this.homeDir = options.homeDir;
|
|
120
|
-
this.projectTrusted = options.projectTrusted;
|
|
121
|
-
this.settingsManager = options.settingsManager;
|
|
122
|
-
this.globalSettingsManager = options.globalSettingsManager;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
static async create(
|
|
126
|
-
cwd: string,
|
|
127
|
-
projectTrusted: boolean,
|
|
128
|
-
options: SkillSettingsOptions,
|
|
129
|
-
): Promise<SkillSettingsController> {
|
|
130
|
-
const agentDir = options.agentDir ?? getAgentDir();
|
|
131
|
-
const controller = new SkillSettingsController({
|
|
132
|
-
cwd,
|
|
133
|
-
agentDir,
|
|
134
|
-
homeDir: options.homeDir,
|
|
135
|
-
projectTrusted,
|
|
136
|
-
settingsManager: SettingsManager.create(cwd, agentDir, { projectTrusted }),
|
|
137
|
-
globalSettingsManager: SettingsManager.create(cwd, agentDir, { projectTrusted: false }),
|
|
138
|
-
});
|
|
139
|
-
await controller.refreshCatalogs();
|
|
140
|
-
return controller;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
private async refreshCatalogs(): Promise<void> {
|
|
144
|
-
await Promise.all([this.settingsManager.reload(), this.globalSettingsManager.reload()]);
|
|
145
|
-
const [globalPaths, projectPaths] = await Promise.all([
|
|
146
|
-
new DefaultPackageManager({
|
|
147
|
-
cwd: this.cwd,
|
|
148
|
-
agentDir: this.agentDir,
|
|
149
|
-
settingsManager: this.globalSettingsManager,
|
|
150
|
-
}).resolve(async () => "skip"),
|
|
151
|
-
new DefaultPackageManager({
|
|
152
|
-
cwd: this.cwd,
|
|
153
|
-
agentDir: this.agentDir,
|
|
154
|
-
settingsManager: this.settingsManager,
|
|
155
|
-
}).resolve(async () => "skip"),
|
|
156
|
-
]);
|
|
157
|
-
this.globalCatalog = buildSkillCatalog(globalPaths.skills, this.cwd, this.agentDir);
|
|
158
|
-
this.projectCatalog = buildSkillCatalog(projectPaths.skills, this.cwd, this.agentDir);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
private records(scope: SettingsScope, ctx?: ExtensionContext): SkillCatalog {
|
|
162
|
-
return mergeRuntimeSkills(
|
|
163
|
-
scope === "project" ? this.projectCatalog : this.globalCatalog,
|
|
164
|
-
ctx,
|
|
165
|
-
scope,
|
|
166
|
-
this.pendingDisabled,
|
|
167
|
-
);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Prefer original global provenance when a project support path resolves the
|
|
172
|
-
* same file as a project resource. This lets Unset remove both the exact
|
|
173
|
-
* override and the generated support path after a catalog refresh.
|
|
174
|
-
*/
|
|
175
|
-
private actionResources(record: SkillRecord, scope: SettingsScope): ResolvedResource[] {
|
|
176
|
-
const globalResources =
|
|
177
|
-
scope === "project" ? recordResources(this.globalCatalog.get(record.name) ?? record) : [];
|
|
178
|
-
const unique = new Map<string, ResolvedResource>();
|
|
179
|
-
for (const resource of [...globalResources, ...recordResources(record)]) {
|
|
180
|
-
const key = `${resource.path}\0${resource.metadata.origin}\0${resource.metadata.source}`;
|
|
181
|
-
if (!unique.has(key)) unique.set(key, resource);
|
|
182
|
-
}
|
|
183
|
-
return Array.from(unique.values());
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Attribute the effective load value to the narrowest scoped override.
|
|
188
|
-
* Project resources can be support-path surrogates, so attribution compares
|
|
189
|
-
* their effective load state with the original global catalog.
|
|
190
|
-
*/
|
|
191
|
-
private loadSource(record: SkillRecord, scope: SettingsScope): ValueSource {
|
|
192
|
-
const resources = recordResources(record);
|
|
193
|
-
const exact = hasExactSkillLoadOverride({
|
|
194
|
-
settingsManager: this.settingsManager,
|
|
195
|
-
resources,
|
|
196
|
-
scope,
|
|
197
|
-
cwd: this.cwd,
|
|
198
|
-
agentDir: this.agentDir,
|
|
199
|
-
});
|
|
200
|
-
if (exact) return scope;
|
|
201
|
-
if (scope === "global") {
|
|
202
|
-
return resources.some((resource) => !resource.enabled) ? "global" : "default";
|
|
203
|
-
}
|
|
204
|
-
if (resources.some((resource) => resource.metadata.scope === "project" && !resource.enabled)) {
|
|
205
|
-
return "project";
|
|
206
|
-
}
|
|
207
|
-
const globalRecord = this.globalCatalog.get(record.name);
|
|
208
|
-
if (!globalRecord) return "default";
|
|
209
|
-
const globalResources = recordResources(globalRecord);
|
|
210
|
-
const projectLoaded = resources.some((resource) => resource.enabled);
|
|
211
|
-
const globalLoaded = globalResources.some((resource) => resource.enabled);
|
|
212
|
-
if (projectLoaded !== globalLoaded) return "project";
|
|
213
|
-
return this.loadSource(globalRecord, "global");
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
private rowSource(
|
|
217
|
-
record: SkillRecord,
|
|
218
|
-
scope: SettingsScope,
|
|
219
|
-
invocationSource: ValueSource,
|
|
220
|
-
): ValueSource {
|
|
221
|
-
return moreSpecificSource(this.loadSource(record, scope), invocationSource);
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
private row(record: SkillRecord, scope: SettingsScope): ScopedFieldValue {
|
|
225
|
-
const invocation = resolveInvocation({
|
|
226
|
-
name: record.name,
|
|
227
|
-
sourceDefault: sourceDefault(record),
|
|
228
|
-
scope,
|
|
229
|
-
cwd: this.cwd,
|
|
230
|
-
projectTrusted: this.projectTrusted,
|
|
231
|
-
homeDir: this.homeDir,
|
|
232
|
-
});
|
|
233
|
-
const value = !isLoaded(record) ? DISABLED : invocation.disabled ? MODEL_DISABLED : ENABLED;
|
|
234
|
-
const source = this.rowSource(record, scope, invocation.source);
|
|
235
|
-
const values = canDisable(record)
|
|
236
|
-
? [ENABLED, MODEL_DISABLED, DISABLED]
|
|
237
|
-
: [ENABLED, MODEL_DISABLED];
|
|
238
|
-
const sourceCount = record.sources.length;
|
|
239
|
-
const limitation = canDisable(record)
|
|
240
|
-
? ""
|
|
241
|
-
: " Full disable is unavailable because PI does not expose a load setting for one or more sources.";
|
|
242
|
-
return {
|
|
243
|
-
field: {
|
|
244
|
-
kind: "enum",
|
|
245
|
-
key: record.name,
|
|
246
|
-
label: record.name,
|
|
247
|
-
values,
|
|
248
|
-
description: `${record.description}${sourceCount > 1 ? ` ${sourceCount} sources.` : ""}${limitation}`,
|
|
249
|
-
},
|
|
250
|
-
displayValue: displayValue(value, source),
|
|
251
|
-
editValue: value,
|
|
252
|
-
source,
|
|
253
|
-
...(scope === "project" && source === "project"
|
|
254
|
-
? {
|
|
255
|
-
inheritanceSource:
|
|
256
|
-
this.globalRowSource(record.name) === "global" ? "global" : "default",
|
|
257
|
-
}
|
|
258
|
-
: {}),
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
private globalRowSource(name: string): ValueSource {
|
|
263
|
-
const record = this.globalCatalog.get(name);
|
|
264
|
-
if (!record) return "default";
|
|
265
|
-
const invocation = resolveInvocation({
|
|
266
|
-
name,
|
|
267
|
-
sourceDefault: sourceDefault(record),
|
|
268
|
-
scope: "global",
|
|
269
|
-
cwd: this.cwd,
|
|
270
|
-
projectTrusted: false,
|
|
271
|
-
homeDir: this.homeDir,
|
|
272
|
-
});
|
|
273
|
-
return this.rowSource(record, "global", invocation.source);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
read(scope: SettingsScope, ctx?: ExtensionContext): ScopedFieldValue[] {
|
|
277
|
-
return Array.from(this.records(scope, ctx).values())
|
|
278
|
-
.sort((left, right) => left.name.localeCompare(right.name))
|
|
279
|
-
.map((record) => this.row(record, scope));
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
private updatePendingDisabled(
|
|
283
|
-
fieldKey: string,
|
|
284
|
-
nextLoadOverride: SkillLoadOverride,
|
|
285
|
-
activeSkillIdentity: string | undefined,
|
|
286
|
-
): void {
|
|
287
|
-
if (nextLoadOverride !== "unload") {
|
|
288
|
-
this.pendingDisabled.delete(fieldKey);
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
if (activeSkillIdentity) {
|
|
292
|
-
this.pendingDisabled.set(fieldKey, new Set([activeSkillIdentity]));
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
async apply(
|
|
297
|
-
scope: SettingsScope,
|
|
298
|
-
fieldKey: string,
|
|
299
|
-
action: SettingsAction,
|
|
300
|
-
ctx?: ExtensionContext,
|
|
301
|
-
): Promise<SettingsApplyResult> {
|
|
302
|
-
if (scope === "project" && !this.projectTrusted) {
|
|
303
|
-
throw new Error("Project is not trusted; refusing to write project skill settings");
|
|
304
|
-
}
|
|
305
|
-
const record = this.records(scope, ctx).get(fieldKey);
|
|
306
|
-
if (!record) return {};
|
|
307
|
-
validateAction(record, action);
|
|
308
|
-
const activeSkillIdentity = record.activeSkill
|
|
309
|
-
? skillSourceIdentity(record.activeSkill)
|
|
310
|
-
: undefined;
|
|
311
|
-
|
|
312
|
-
if (action.kind !== "set" || action.value !== DISABLED) {
|
|
313
|
-
persistInvocation({
|
|
314
|
-
name: fieldKey,
|
|
315
|
-
disabled: action.kind === "set" ? action.value === MODEL_DISABLED : undefined,
|
|
316
|
-
scope,
|
|
317
|
-
cwd: this.cwd,
|
|
318
|
-
homeDir: this.homeDir,
|
|
319
|
-
});
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
const resources = this.actionResources(record, scope);
|
|
323
|
-
const hasLoadOverride = hasExactSkillLoadOverride({
|
|
324
|
-
settingsManager: this.settingsManager,
|
|
325
|
-
resources,
|
|
326
|
-
scope,
|
|
327
|
-
cwd: this.cwd,
|
|
328
|
-
agentDir: this.agentDir,
|
|
329
|
-
});
|
|
330
|
-
const nextLoadOverride = loadOverride(record, action, hasLoadOverride);
|
|
331
|
-
if (nextLoadOverride && resources.length > 0) {
|
|
332
|
-
updateSkillLoadOverrides({
|
|
333
|
-
settingsManager: this.settingsManager,
|
|
334
|
-
resources,
|
|
335
|
-
scope,
|
|
336
|
-
state: nextLoadOverride,
|
|
337
|
-
cwd: this.cwd,
|
|
338
|
-
agentDir: this.agentDir,
|
|
339
|
-
});
|
|
340
|
-
await this.settingsManager.flush();
|
|
341
|
-
const error = this.settingsManager.drainErrors()[0];
|
|
342
|
-
await this.refreshCatalogs();
|
|
343
|
-
if (error) throw error.error;
|
|
344
|
-
this.updatePendingDisabled(fieldKey, nextLoadOverride, activeSkillIdentity);
|
|
345
|
-
return {
|
|
346
|
-
notice: { message: "Reload required for skill load changes", level: "info" },
|
|
347
|
-
};
|
|
348
|
-
}
|
|
349
|
-
return {};
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
function createSkillSettingsModule(options: SkillSettingsOptions): SettingsModule {
|
|
16
|
+
function createSkillControllerGetter(options: SkillSettingsOptions): SkillControllerGetter {
|
|
354
17
|
let controllerKey: string | undefined;
|
|
355
18
|
let controllerPromise: Promise<SkillSettingsController> | undefined;
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
const projectTrusted = context.ctx?.isProjectTrusted() ?? false;
|
|
359
|
-
const key = `${context.cwd}\0${projectTrusted}`;
|
|
19
|
+
return (cwd, projectTrusted) => {
|
|
20
|
+
const key = `${cwd}\0${projectTrusted}`;
|
|
360
21
|
if (!controllerPromise || controllerKey !== key) {
|
|
361
22
|
controllerKey = key;
|
|
362
|
-
controllerPromise = SkillSettingsController.create(
|
|
23
|
+
controllerPromise = SkillSettingsController.create(cwd, projectTrusted, options);
|
|
363
24
|
}
|
|
364
25
|
return controllerPromise;
|
|
365
26
|
};
|
|
27
|
+
}
|
|
366
28
|
|
|
29
|
+
function createSkillSettingsModule(
|
|
30
|
+
options: SkillSettingsOptions,
|
|
31
|
+
getController: SkillControllerGetter,
|
|
32
|
+
): SettingsModule {
|
|
367
33
|
return {
|
|
368
34
|
id: SETTINGS_SECTION_ID,
|
|
369
35
|
label: "Skills",
|
|
370
36
|
read: async (context) => {
|
|
371
37
|
if (context.ctx) notifyInvocationConfigWarnings(context.ctx, options.homeDir);
|
|
372
|
-
|
|
38
|
+
const projectTrusted = context.ctx?.isProjectTrusted() ?? false;
|
|
39
|
+
return {
|
|
40
|
+
rows: (await getController(context.cwd, projectTrusted)).read(context.scope, context.ctx),
|
|
41
|
+
};
|
|
373
42
|
},
|
|
374
|
-
apply: async (request) =>
|
|
375
|
-
|
|
43
|
+
apply: async (request) => {
|
|
44
|
+
const projectTrusted = request.ctx?.isProjectTrusted() ?? false;
|
|
45
|
+
return (await getController(request.cwd, projectTrusted)).apply(
|
|
376
46
|
request.scope,
|
|
377
47
|
request.fieldKey,
|
|
378
48
|
request.action,
|
|
379
49
|
request.ctx,
|
|
380
|
-
)
|
|
50
|
+
);
|
|
51
|
+
},
|
|
381
52
|
};
|
|
382
53
|
}
|
|
383
54
|
|
|
384
55
|
/** Register scoped skill availability settings and prompt overrides. */
|
|
385
56
|
export default function skillSettings(pi: ExtensionAPI, options: SkillSettingsOptions = {}): void {
|
|
386
|
-
|
|
57
|
+
const getController = createSkillControllerGetter(options);
|
|
58
|
+
const providerDisposers = new Map<string, () => void>();
|
|
59
|
+
registerSettings(pi, createSkillSettingsModule(options, getController));
|
|
60
|
+
|
|
61
|
+
pi.on("session_start", (_event, ctx) => {
|
|
62
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
63
|
+
providerDisposers.get(sessionId)?.();
|
|
64
|
+
const dispose = registerSessionCapabilitySkillProvider<ExtensionCommandContext>(sessionId, {
|
|
65
|
+
listEligibleSkills: async (commandCtx) => {
|
|
66
|
+
const controller = await getController(commandCtx.cwd, commandCtx.isProjectTrusted());
|
|
67
|
+
return controller.eligibleModelSkills(commandCtx);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
providerDisposers.set(sessionId, dispose);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pi.on("session_shutdown", (_event, ctx) => {
|
|
74
|
+
const sessionId = ctx.sessionManager.getSessionId();
|
|
75
|
+
providerDisposers.get(sessionId)?.();
|
|
76
|
+
providerDisposers.delete(sessionId);
|
|
77
|
+
});
|
|
387
78
|
|
|
388
79
|
pi.on("before_agent_start", (event, ctx) => {
|
|
389
80
|
notifyInvocationConfigWarnings(ctx, options.homeDir);
|
|
81
|
+
const state = sessionCapabilityState.get(ctx.sessionManager.getSessionId());
|
|
390
82
|
const systemPrompt = applyPromptOverrides({
|
|
391
83
|
options: event.systemPromptOptions,
|
|
392
84
|
systemPrompt: event.systemPrompt,
|
|
393
85
|
cwd: ctx.cwd,
|
|
394
86
|
projectTrusted: ctx.isProjectTrusted(),
|
|
395
87
|
homeDir: options.homeDir,
|
|
88
|
+
hiddenSkillNames: new Set(state?.hiddenSkillNames ?? []),
|
|
396
89
|
});
|
|
397
90
|
return systemPrompt === undefined ? undefined : { systemPrompt };
|
|
398
91
|
});
|