@mrclrchtr/supi-skills 8.0.1 → 9.1.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/node_modules/@mrclrchtr/supi-core/package.json +1 -1
- package/node_modules/@mrclrchtr/supi-core/src/debug-registry.ts +9 -4
- package/node_modules/@mrclrchtr/supi-core/src/session-capabilities.ts +55 -1
- package/node_modules/@mrclrchtr/supi-core/src/session-capability-profiles.ts +240 -0
- package/node_modules/@mrclrchtr/supi-core/src/session.ts +22 -0
- package/package.json +2 -2
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
export type DebugLevel = "debug" | "info" | "warning" | "error";
|
|
8
8
|
export type DebugAgentAccess = "off" | "sanitized" | "raw";
|
|
9
|
+
|
|
10
|
+
/** Custom session-entry type used to persist sanitized debug events. */
|
|
11
|
+
export const DEBUG_EVENT_ENTRY_TYPE = "supi-debug-event";
|
|
9
12
|
export interface DebugRegistryConfig {
|
|
10
13
|
/** Whether producers should retain debug events. */
|
|
11
14
|
enabled: boolean;
|
|
@@ -212,7 +215,7 @@ function toSanitizedView(event: DebugEvent): DebugEventView {
|
|
|
212
215
|
category: event.category,
|
|
213
216
|
message: event.message,
|
|
214
217
|
cwd: event.cwd,
|
|
215
|
-
data: event.data,
|
|
218
|
+
data: event.data === undefined ? undefined : redactDebugData(event.data),
|
|
216
219
|
};
|
|
217
220
|
}
|
|
218
221
|
|
|
@@ -241,15 +244,17 @@ export function recordDebugEvent(input: DebugEventInput): DebugEvent | null {
|
|
|
241
244
|
};
|
|
242
245
|
state.events.push(event);
|
|
243
246
|
trimToMaxEvents(state);
|
|
244
|
-
const view = toSanitizedView(event);
|
|
245
247
|
for (const listener of state.listeners) {
|
|
246
248
|
try {
|
|
247
|
-
listener(
|
|
249
|
+
listener(toSanitizedView(event));
|
|
248
250
|
} catch {
|
|
249
251
|
// Debug-event consumers must not alter producer behavior.
|
|
250
252
|
}
|
|
251
253
|
}
|
|
252
|
-
return {
|
|
254
|
+
return {
|
|
255
|
+
...event,
|
|
256
|
+
data: event.data === undefined ? undefined : redactDebugData(event.data),
|
|
257
|
+
};
|
|
253
258
|
}
|
|
254
259
|
|
|
255
260
|
/** Query retained debug events newest-first. Results are sanitized unless raw access is requested and allowed. */
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
decodeSessionCapabilityProfileSnapshot,
|
|
3
|
+
type SessionCapabilityProfile,
|
|
4
|
+
type SessionCapabilityProfileSnapshot,
|
|
5
|
+
} from "./session-capability-profiles.ts";
|
|
6
|
+
|
|
1
7
|
/** Session-only tool and skill visibility state. */
|
|
2
8
|
export interface SessionCapabilityState {
|
|
3
9
|
version: 1;
|
|
@@ -7,6 +13,8 @@ export interface SessionCapabilityState {
|
|
|
7
13
|
/** Tools that the user explicitly enabled for this session. */
|
|
8
14
|
toolEnabledNames?: string[];
|
|
9
15
|
hiddenSkillNames: string[];
|
|
16
|
+
/** Original profile identity and exclusions. Later configuration changes do not affect this copy. */
|
|
17
|
+
profileSnapshot?: SessionCapabilityProfileSnapshot;
|
|
10
18
|
}
|
|
11
19
|
|
|
12
20
|
/** A model-visible skill that a provider can offer to the selector. */
|
|
@@ -94,8 +102,9 @@ export function decodeSessionCapabilities(value: unknown): SessionCapabilityStat
|
|
|
94
102
|
(name) => !initiallyInactive.has(name),
|
|
95
103
|
);
|
|
96
104
|
const eligible = new Set(eligibleToolNames);
|
|
97
|
-
const toolDenylist = stringList(record.toolDenylist)
|
|
105
|
+
const toolDenylist = stringList(record.toolDenylist);
|
|
98
106
|
const denied = new Set(toolDenylist);
|
|
107
|
+
const profileSnapshot = decodeSessionCapabilityProfileSnapshot(record.profileSnapshot);
|
|
99
108
|
|
|
100
109
|
return {
|
|
101
110
|
version: 1,
|
|
@@ -106,9 +115,54 @@ export function decodeSessionCapabilities(value: unknown): SessionCapabilityStat
|
|
|
106
115
|
(name) => eligible.has(name) && !denied.has(name),
|
|
107
116
|
),
|
|
108
117
|
hiddenSkillNames: stringList(record.hiddenSkillNames),
|
|
118
|
+
...(profileSnapshot ? { profileSnapshot } : {}),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Copy current exclusion sets for saving. Do not use inventory to remove names. */
|
|
123
|
+
export function captureSessionCapabilityExclusions(
|
|
124
|
+
state: SessionCapabilityState,
|
|
125
|
+
): SessionCapabilityProfile {
|
|
126
|
+
return {
|
|
127
|
+
excludedTools: [...new Set(state.toolDenylist)],
|
|
128
|
+
hiddenSkills: [...new Set(state.hiddenSkillNames)],
|
|
109
129
|
};
|
|
110
130
|
}
|
|
111
131
|
|
|
132
|
+
/**
|
|
133
|
+
* Replace exclusions and capture a profile copy. Return undefined for an invalid profile.
|
|
134
|
+
* Do not mutate the input state or activate tools. The caller owns runtime restoration.
|
|
135
|
+
*/
|
|
136
|
+
export function applySessionCapabilityProfile(
|
|
137
|
+
state: SessionCapabilityState,
|
|
138
|
+
profile: unknown,
|
|
139
|
+
): SessionCapabilityState | undefined {
|
|
140
|
+
const profileSnapshot = decodeSessionCapabilityProfileSnapshot(profile);
|
|
141
|
+
if (!profileSnapshot) return undefined;
|
|
142
|
+
return decodeSessionCapabilities({
|
|
143
|
+
...state,
|
|
144
|
+
toolDenylist: profileSnapshot.excludedTools,
|
|
145
|
+
hiddenSkillNames: profileSnapshot.hiddenSkills,
|
|
146
|
+
profileSnapshot,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function equalNameSets(left: readonly string[], right: readonly string[]): boolean {
|
|
151
|
+
const leftSet = new Set(left);
|
|
152
|
+
const rightSet = new Set(right);
|
|
153
|
+
return leftSet.size === rightSet.size && [...leftSet].every((name) => rightSet.has(name));
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Compare current exclusions with the applied copy. No profile means no Modified marker. */
|
|
157
|
+
export function isSessionCapabilityProfileModified(state: SessionCapabilityState): boolean {
|
|
158
|
+
const snapshot = state.profileSnapshot;
|
|
159
|
+
return (
|
|
160
|
+
snapshot !== undefined &&
|
|
161
|
+
(!equalNameSets(state.toolDenylist, snapshot.excludedTools) ||
|
|
162
|
+
!equalNameSets(state.hiddenSkillNames, snapshot.hiddenSkills))
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
112
166
|
/** Return a safe copy of the latest valid snapshot in all session entries. */
|
|
113
167
|
export function findSessionCapabilities(
|
|
114
168
|
entries: readonly unknown[],
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/** Exact names to exclude. Omitted configuration lists mean empty sets. */
|
|
2
|
+
export interface SessionCapabilityProfileDefinition {
|
|
3
|
+
excludedTools?: string[];
|
|
4
|
+
hiddenSkills?: string[];
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** Validated exclusion sets. Names need not match the current inventory. */
|
|
8
|
+
export interface SessionCapabilityProfile {
|
|
9
|
+
excludedTools: string[];
|
|
10
|
+
hiddenSkills: string[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** A profile is available only when validation has no errors. */
|
|
14
|
+
export interface SessionCapabilityProfileValidation {
|
|
15
|
+
profile?: SessionCapabilityProfile;
|
|
16
|
+
errors: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
20
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
|
|
21
|
+
const prototype = Object.getPrototypeOf(value);
|
|
22
|
+
return prototype === Object.prototype || prototype === null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readNames(value: unknown): string[] | undefined {
|
|
26
|
+
if (!Array.isArray(value)) return undefined;
|
|
27
|
+
const names: unknown[] = [...new Set(value)];
|
|
28
|
+
return names.every((name): name is string => typeof name === "string") ? names : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Validate and copy a complete definition. Do not check inventory or expand patterns. */
|
|
32
|
+
export function validateSessionCapabilityProfile(
|
|
33
|
+
value: unknown,
|
|
34
|
+
): SessionCapabilityProfileValidation {
|
|
35
|
+
if (!isRecord(value)) return { errors: ["Profile must be an object."] };
|
|
36
|
+
const excludedTools = Object.hasOwn(value, "excludedTools") ? readNames(value.excludedTools) : [];
|
|
37
|
+
const hiddenSkills = Object.hasOwn(value, "hiddenSkills") ? readNames(value.hiddenSkills) : [];
|
|
38
|
+
const errors = Object.keys(value)
|
|
39
|
+
.filter((key) => key !== "excludedTools" && key !== "hiddenSkills")
|
|
40
|
+
.map((key) => `Unknown profile field: ${key}.`);
|
|
41
|
+
if (!excludedTools) errors.push("excludedTools must be an array of strings.");
|
|
42
|
+
if (!hiddenSkills) errors.push("hiddenSkills must be an array of strings.");
|
|
43
|
+
if (errors.length || !excludedTools || !hiddenSkills) return { errors };
|
|
44
|
+
return { profile: { excludedTools, hiddenSkills }, errors };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Configuration scope that supplied a profile or default. */
|
|
48
|
+
export type SessionCapabilityProfileScope = "global" | "project";
|
|
49
|
+
|
|
50
|
+
/** Configuration values for the sessionCapabilities section. */
|
|
51
|
+
export interface SessionCapabilityProfilesSection {
|
|
52
|
+
profiles?: Record<string, SessionCapabilityProfileDefinition>;
|
|
53
|
+
defaultProfile?: string | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Session-owned identity and original exclusion sets, independent of configuration. */
|
|
57
|
+
export interface SessionCapabilityProfileSnapshot extends SessionCapabilityProfile {
|
|
58
|
+
id: string;
|
|
59
|
+
source: SessionCapabilityProfileScope;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** A configuration error with a scope and field path for display. */
|
|
63
|
+
export interface SessionCapabilityProfileDiagnostic {
|
|
64
|
+
scope: SessionCapabilityProfileScope;
|
|
65
|
+
path: string;
|
|
66
|
+
message: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A scoped definition, including invalid definitions and hidden global definitions. */
|
|
70
|
+
export interface SessionCapabilityProfileEntry {
|
|
71
|
+
id: string;
|
|
72
|
+
source: SessionCapabilityProfileScope;
|
|
73
|
+
shadowed: boolean;
|
|
74
|
+
profile?: SessionCapabilityProfile;
|
|
75
|
+
errors: SessionCapabilityProfileDiagnostic[];
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Default selection source can differ from the effective profile source. */
|
|
79
|
+
export type SessionCapabilityProfileDefault =
|
|
80
|
+
| { status: "none"; source?: SessionCapabilityProfileScope }
|
|
81
|
+
| {
|
|
82
|
+
status: "resolved";
|
|
83
|
+
source: SessionCapabilityProfileScope;
|
|
84
|
+
id: string;
|
|
85
|
+
profile: SessionCapabilityProfileSnapshot;
|
|
86
|
+
}
|
|
87
|
+
| { status: "invalid"; source: SessionCapabilityProfileScope; id?: string };
|
|
88
|
+
|
|
89
|
+
/** Raw sections, not merged configuration. Callers must check trust before project reads. */
|
|
90
|
+
export interface ResolveSessionCapabilityProfilesOptions {
|
|
91
|
+
global?: unknown;
|
|
92
|
+
project?: unknown;
|
|
93
|
+
projectTrusted: boolean;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Data for profile rows, scoped actions, and default warnings. No I/O is performed. */
|
|
97
|
+
export interface SessionCapabilityProfilesResolution {
|
|
98
|
+
entries: SessionCapabilityProfileEntry[];
|
|
99
|
+
effectiveProfiles: SessionCapabilityProfileSnapshot[];
|
|
100
|
+
default: SessionCapabilityProfileDefault;
|
|
101
|
+
errors: SessionCapabilityProfileDiagnostic[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** IDs contain lowercase ASCII words separated by single hyphens. */
|
|
105
|
+
export function isSessionCapabilityProfileId(value: unknown): value is string {
|
|
106
|
+
return typeof value === "string" && /^[a-z]+(?:-[a-z]+)*$/.test(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** Validate and copy stored identity and original lists. Invalid metadata has no identity. */
|
|
110
|
+
export function decodeSessionCapabilityProfileSnapshot(
|
|
111
|
+
value: unknown,
|
|
112
|
+
): SessionCapabilityProfileSnapshot | undefined {
|
|
113
|
+
if (!isRecord(value) || !isSessionCapabilityProfileId(value.id)) return undefined;
|
|
114
|
+
if (value.source !== "global" && value.source !== "project") return undefined;
|
|
115
|
+
const { id, source, ...definition } = value;
|
|
116
|
+
if (!Object.hasOwn(definition, "excludedTools") || !Object.hasOwn(definition, "hiddenSkills"))
|
|
117
|
+
return undefined;
|
|
118
|
+
const result = validateSessionCapabilityProfile(definition);
|
|
119
|
+
return result.profile ? { id, source, ...result.profile } : undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function readEntries(
|
|
123
|
+
value: unknown,
|
|
124
|
+
source: SessionCapabilityProfileScope,
|
|
125
|
+
): SessionCapabilityProfileEntry[] {
|
|
126
|
+
if (!isRecord(value) || !isRecord(value.profiles)) return [];
|
|
127
|
+
return Object.entries(value.profiles).map(([id, definition]) => {
|
|
128
|
+
const result = validateSessionCapabilityProfile(definition);
|
|
129
|
+
if (!isSessionCapabilityProfileId(id))
|
|
130
|
+
result.errors.push("Invalid profile ID: use lowercase words with single hyphens.");
|
|
131
|
+
return {
|
|
132
|
+
id,
|
|
133
|
+
source,
|
|
134
|
+
shadowed: false,
|
|
135
|
+
profile: result.errors.length ? undefined : result.profile,
|
|
136
|
+
errors: result.errors.map((message) => ({ scope: source, path: `profiles.${id}`, message })),
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
type DefaultReference =
|
|
142
|
+
| SessionCapabilityProfileDefault
|
|
143
|
+
| { status: "pending"; source: SessionCapabilityProfileScope; id: string };
|
|
144
|
+
|
|
145
|
+
function readDefault(
|
|
146
|
+
value: unknown,
|
|
147
|
+
source: SessionCapabilityProfileScope,
|
|
148
|
+
errors: SessionCapabilityProfileDiagnostic[],
|
|
149
|
+
): DefaultReference | undefined {
|
|
150
|
+
if (!isRecord(value) || !Object.hasOwn(value, "defaultProfile")) return undefined;
|
|
151
|
+
if (value.defaultProfile === null) return { status: "none", source };
|
|
152
|
+
if (isSessionCapabilityProfileId(value.defaultProfile)) {
|
|
153
|
+
return { status: "pending", source, id: value.defaultProfile };
|
|
154
|
+
}
|
|
155
|
+
errors.push({
|
|
156
|
+
scope: source,
|
|
157
|
+
path: "defaultProfile",
|
|
158
|
+
message: "defaultProfile must be null or a valid profile ID.",
|
|
159
|
+
});
|
|
160
|
+
return { status: "invalid", source };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function resolveDefault(
|
|
164
|
+
selected: DefaultReference | undefined,
|
|
165
|
+
profiles: SessionCapabilityProfileSnapshot[],
|
|
166
|
+
errors: SessionCapabilityProfileDiagnostic[],
|
|
167
|
+
): SessionCapabilityProfileDefault {
|
|
168
|
+
if (!selected) return { status: "none" };
|
|
169
|
+
if (selected.status !== "pending") return selected;
|
|
170
|
+
const { source, id } = selected;
|
|
171
|
+
const profile = profiles.find((entry) => entry.id === id);
|
|
172
|
+
if (profile) return { status: "resolved", source, id, profile };
|
|
173
|
+
errors.push({
|
|
174
|
+
scope: source,
|
|
175
|
+
path: "defaultProfile",
|
|
176
|
+
message: `Default profile ${id} is missing or invalid. No profile will be applied.`,
|
|
177
|
+
});
|
|
178
|
+
return { status: "invalid", source, id };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
interface ScopedProfiles {
|
|
182
|
+
entries: SessionCapabilityProfileEntry[];
|
|
183
|
+
errors: SessionCapabilityProfileDiagnostic[];
|
|
184
|
+
default?: DefaultReference;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Reject malformed sections, but retain known IDs to prevent global fallback. */
|
|
188
|
+
function readSection(value: unknown, scope: SessionCapabilityProfileScope): ScopedProfiles {
|
|
189
|
+
if (value === undefined) return { entries: [], errors: [] };
|
|
190
|
+
if (!isRecord(value)) {
|
|
191
|
+
return {
|
|
192
|
+
entries: [],
|
|
193
|
+
default: { status: "invalid", source: scope },
|
|
194
|
+
errors: [
|
|
195
|
+
{ scope, path: "sessionCapabilities", message: "sessionCapabilities must be an object." },
|
|
196
|
+
],
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
const sectionErrors = Object.keys(value)
|
|
200
|
+
.filter((key) => key !== "profiles" && key !== "defaultProfile")
|
|
201
|
+
.map((key) => ({ scope, path: key, message: `Unknown section field: ${key}.` }));
|
|
202
|
+
if (Object.hasOwn(value, "profiles") && !isRecord(value.profiles)) {
|
|
203
|
+
sectionErrors.push({ scope, path: "profiles", message: "profiles must be an object." });
|
|
204
|
+
}
|
|
205
|
+
const entries = readEntries(value, scope);
|
|
206
|
+
const errors = [...sectionErrors, ...entries.flatMap((entry) => entry.errors)];
|
|
207
|
+
const selection = readDefault(value, scope, errors);
|
|
208
|
+
if (sectionErrors.length) {
|
|
209
|
+
for (const entry of entries) {
|
|
210
|
+
entry.profile = undefined;
|
|
211
|
+
entry.errors.push(...sectionErrors);
|
|
212
|
+
}
|
|
213
|
+
return { entries, errors, default: { status: "invalid", source: scope } };
|
|
214
|
+
}
|
|
215
|
+
return { entries, errors, default: selection };
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Resolve whole profiles by ID. Ignore project data unless projectTrusted is true.
|
|
220
|
+
* An absent section is undefined. Malformed sections cannot supply profiles or a default.
|
|
221
|
+
*/
|
|
222
|
+
export function resolveSessionCapabilityProfiles(
|
|
223
|
+
options: ResolveSessionCapabilityProfilesOptions,
|
|
224
|
+
): SessionCapabilityProfilesResolution {
|
|
225
|
+
const global = readSection(options.global, "global");
|
|
226
|
+
const project = readSection(options.projectTrusted ? options.project : undefined, "project");
|
|
227
|
+
const entries = [...global.entries, ...project.entries];
|
|
228
|
+
const errors = [...global.errors, ...project.errors];
|
|
229
|
+
const selected = new Map(entries.map((entry) => [entry.id, entry]));
|
|
230
|
+
for (const entry of entries) entry.shadowed = selected.get(entry.id) !== entry;
|
|
231
|
+
const effectiveProfiles = [...selected.values()].flatMap((entry) =>
|
|
232
|
+
entry.profile ? [{ id: entry.id, source: entry.source, ...entry.profile }] : [],
|
|
233
|
+
);
|
|
234
|
+
return {
|
|
235
|
+
entries,
|
|
236
|
+
effectiveProfiles,
|
|
237
|
+
default: resolveDefault(project.default ?? global.default, effectiveProfiles, errors),
|
|
238
|
+
errors,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
@@ -7,17 +7,39 @@ export type {
|
|
|
7
7
|
SessionCapabilityState,
|
|
8
8
|
} from "./session-capabilities.ts";
|
|
9
9
|
export {
|
|
10
|
+
applySessionCapabilityProfile,
|
|
11
|
+
captureSessionCapabilityExclusions,
|
|
10
12
|
clearPendingSessionCapabilityForks,
|
|
11
13
|
createEmptySessionCapabilityState,
|
|
12
14
|
decodeSessionCapabilities,
|
|
13
15
|
findSessionCapabilities,
|
|
14
16
|
getSessionCapabilitySkillProvider,
|
|
17
|
+
isSessionCapabilityProfileModified,
|
|
15
18
|
readPendingSessionCapabilityFork,
|
|
16
19
|
registerSessionCapabilitySkillProvider,
|
|
17
20
|
SESSION_CAPABILITIES_ENTRY,
|
|
18
21
|
sessionCapabilityState,
|
|
19
22
|
setPendingSessionCapabilityFork,
|
|
20
23
|
} from "./session-capabilities.ts";
|
|
24
|
+
export type {
|
|
25
|
+
ResolveSessionCapabilityProfilesOptions,
|
|
26
|
+
SessionCapabilityProfile,
|
|
27
|
+
SessionCapabilityProfileDefault,
|
|
28
|
+
SessionCapabilityProfileDefinition,
|
|
29
|
+
SessionCapabilityProfileDiagnostic,
|
|
30
|
+
SessionCapabilityProfileEntry,
|
|
31
|
+
SessionCapabilityProfileScope,
|
|
32
|
+
SessionCapabilityProfileSnapshot,
|
|
33
|
+
SessionCapabilityProfilesResolution,
|
|
34
|
+
SessionCapabilityProfilesSection,
|
|
35
|
+
SessionCapabilityProfileValidation,
|
|
36
|
+
} from "./session-capability-profiles.ts";
|
|
37
|
+
export {
|
|
38
|
+
decodeSessionCapabilityProfileSnapshot,
|
|
39
|
+
isSessionCapabilityProfileId,
|
|
40
|
+
resolveSessionCapabilityProfiles,
|
|
41
|
+
validateSessionCapabilityProfile,
|
|
42
|
+
} from "./session-capability-profiles.ts";
|
|
21
43
|
export type { SessionNameTrackerHost } from "./session-utils.ts";
|
|
22
44
|
export {
|
|
23
45
|
createSessionNameTracker,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrclrchtr/supi-skills",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.1.0",
|
|
4
4
|
"description": "Scoped skill controls and skill input shortcuts for PI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"README.md"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@mrclrchtr/supi-core": "
|
|
33
|
+
"@mrclrchtr/supi-core": "9.1.0"
|
|
34
34
|
},
|
|
35
35
|
"bundledDependencies": [
|
|
36
36
|
"@mrclrchtr/supi-core"
|