@caupulican/pi-adaptative 0.93.4 → 0.93.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 +12 -0
- package/dist/core/skill-vault.d.ts +18 -14
- package/dist/core/skill-vault.d.ts.map +1 -1
- package/dist/core/skill-vault.js +140 -81
- package/dist/core/skill-vault.js.map +1 -1
- package/dist/core/tools/bash.d.ts +3 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +13 -4
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/shell-session.d.ts +3 -1
- package/dist/core/tools/shell-session.d.ts.map +1 -1
- package/dist/core/tools/shell-session.js +90 -15
- package/dist/core/tools/shell-session.js.map +1 -1
- package/dist/core/tools/skill.d.ts +1 -1
- package/dist/core/tools/skill.d.ts.map +1 -1
- package/dist/core/tools/skill.js +20 -11
- package/dist/core/tools/skill.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- 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/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [0.93.5] - 2026-08-17
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
|
|
5
|
+
- Made the skill vault multi-slot: up to three concurrent skills share one byte budget with least-recently-used eviction, load results state the pending activation, base directory, and any evicted skills instead of claiming immediate activation, and unload/status operate per slot.
|
|
6
|
+
- Bash failure results now report the effective working directory the command ran in on a final `cwd:` line — shell-reported `$PWD` from a collision-safe length-framed POSIX exit sentinel, or the state-tracked effective cwd on the Windows contract — and the tool description states the persistent-cwd contract.
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Stopped tool-failure records from destroying evidence: missing-path failures retain the diagnostic naming the exact path, and executed process-exit failures carry a bounded sanitized tail of the command output as evidence while blocked replays gain nothing new.
|
|
11
|
+
- Made catalogued per-error guidance lead the failure correction ahead of the recovery gate's loaded-action text, so specific advice (such as listing a missing path's parent) is no longer displaced by generic repair-action instructions.
|
|
12
|
+
|
|
1
13
|
## [0.93.4] - 2026-08-17
|
|
2
14
|
|
|
3
15
|
### Changed
|
|
@@ -2,6 +2,7 @@ import { type Skill } from "./skills.ts";
|
|
|
2
2
|
export declare const DEFAULT_SKILL_IDLE_TIMEOUT_MS: number;
|
|
3
3
|
export declare const MAX_ACTIVE_SKILL_BODY_BYTES: number;
|
|
4
4
|
export declare const MIN_ACTIVE_SKILL_BODY_BYTES: number;
|
|
5
|
+
export declare const MAX_LOADED_SKILLS = 3;
|
|
5
6
|
type SkillVaultRequester = "model" | "user";
|
|
6
7
|
type SkillVaultUnloadReason = "explicit" | "idle_expired" | "resource_unavailable" | "budget_exceeded";
|
|
7
8
|
interface LoadedSkill {
|
|
@@ -16,25 +17,25 @@ interface LoadedSkill {
|
|
|
16
17
|
fileModifiedAtMs: number;
|
|
17
18
|
fileChangedAtMs: number;
|
|
18
19
|
}
|
|
19
|
-
type
|
|
20
|
-
state: "unloaded";
|
|
21
|
-
reason?: SkillVaultUnloadReason;
|
|
22
|
-
} | ({
|
|
20
|
+
type SkillSlotState = ({
|
|
23
21
|
state: "loaded_pending";
|
|
24
22
|
} & LoadedSkill) | ({
|
|
25
23
|
state: "active";
|
|
26
24
|
lastUsedAtMs: number;
|
|
27
25
|
useCount: number;
|
|
28
26
|
} & LoadedSkill);
|
|
29
|
-
export interface
|
|
30
|
-
state:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
loadedAtMs?: number;
|
|
27
|
+
export interface SkillSlotStatus {
|
|
28
|
+
state: SkillSlotState["state"];
|
|
29
|
+
name: string;
|
|
30
|
+
loadedAtMs: number;
|
|
34
31
|
lastUsedAtMs?: number;
|
|
35
32
|
idleForMs?: number;
|
|
36
33
|
expiresInMs?: number;
|
|
37
34
|
useCount?: number;
|
|
35
|
+
}
|
|
36
|
+
export interface SkillVaultStatus {
|
|
37
|
+
idleTimeoutMs: number;
|
|
38
|
+
slots: SkillSlotStatus[];
|
|
38
39
|
reason?: SkillVaultUnloadReason;
|
|
39
40
|
}
|
|
40
41
|
export interface SkillSearchResult {
|
|
@@ -47,7 +48,8 @@ export type SkillLoadResult = {
|
|
|
47
48
|
ok: true;
|
|
48
49
|
state: "loaded_pending";
|
|
49
50
|
name: string;
|
|
50
|
-
|
|
51
|
+
baseDir: string;
|
|
52
|
+
evicted?: string[];
|
|
51
53
|
} | {
|
|
52
54
|
ok: false;
|
|
53
55
|
reason: "not_found" | "body_too_large" | "invalid_body" | "read_failed";
|
|
@@ -69,14 +71,15 @@ export declare class SkillVaultController {
|
|
|
69
71
|
private readonly idleTimeoutMs;
|
|
70
72
|
private readonly getMaxBodyBytes;
|
|
71
73
|
private readonly onSkillUsed;
|
|
72
|
-
private
|
|
74
|
+
private slots;
|
|
75
|
+
private unloadReason;
|
|
73
76
|
private contextRevision;
|
|
74
77
|
constructor(options: SkillVaultControllerOptions);
|
|
75
78
|
search(rawQuery: string): SkillSearchResult;
|
|
76
79
|
load(name: string, requester: SkillVaultRequester): SkillLoadResult;
|
|
77
|
-
unload(): {
|
|
80
|
+
unload(name?: string): {
|
|
78
81
|
ok: true;
|
|
79
|
-
unloaded
|
|
82
|
+
unloaded: string[];
|
|
80
83
|
};
|
|
81
84
|
status(): SkillVaultStatus;
|
|
82
85
|
commitSystemPromptSection(): string | undefined;
|
|
@@ -88,8 +91,9 @@ export declare class SkillVaultController {
|
|
|
88
91
|
getContextRevision(): number;
|
|
89
92
|
/** Record host-observed work derived from an active skill, independent of agent cooperation. */
|
|
90
93
|
noteActivity(): void;
|
|
94
|
+
private slotStatus;
|
|
91
95
|
private reconcile;
|
|
92
|
-
private
|
|
96
|
+
private reconcileSlot;
|
|
93
97
|
private replaceState;
|
|
94
98
|
private resolveMaxBodyBytes;
|
|
95
99
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-vault.d.ts","sourceRoot":"","sources":["../../src/core/skill-vault.ts"],"names":[],"mappings":"AAKA,OAAO,EAA+B,KAAK,KAAK,EAAyB,MAAM,aAAa,CAAC;AAG7F,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAC5D,eAAO,MAAM,2BAA2B,QAAY,CAAC;AACrD,eAAO,MAAM,2BAA2B,QAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"skill-vault.d.ts","sourceRoot":"","sources":["../../src/core/skill-vault.ts"],"names":[],"mappings":"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"}
|
package/dist/core/skill-vault.js
CHANGED
|
@@ -8,6 +8,7 @@ import { readBoundedTextFileSync, sameFileVersion } from "./util/bounded-file.js
|
|
|
8
8
|
export const DEFAULT_SKILL_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
9
9
|
export const MAX_ACTIVE_SKILL_BODY_BYTES = 64 * 1024;
|
|
10
10
|
export const MIN_ACTIVE_SKILL_BODY_BYTES = 4 * 1024;
|
|
11
|
+
export const MAX_LOADED_SKILLS = 3;
|
|
11
12
|
const MAX_SEARCH_RESULTS = 5;
|
|
12
13
|
const MAX_SEARCH_DESCRIPTION_CHARS = 240;
|
|
13
14
|
function compactDescription(description) {
|
|
@@ -36,6 +37,29 @@ function searchScore(skill, query, tokens) {
|
|
|
36
37
|
function activeSkillContext(skill, body) {
|
|
37
38
|
return [`ACTIVE SKILL ${skill.name}`, `BASE ${skill.baseDir}`, "NON-NEGOTIABLE WHILE ACTIVE:", body].join("\n");
|
|
38
39
|
}
|
|
40
|
+
function slotLastUsedAtMs(slot) {
|
|
41
|
+
return slot.state === "loaded_pending" ? slot.loadedAtMs : slot.lastUsedAtMs;
|
|
42
|
+
}
|
|
43
|
+
function aggregateBodyBytes(slots) {
|
|
44
|
+
let total = 0;
|
|
45
|
+
for (const slot of slots.values())
|
|
46
|
+
total += slot.bodyBytes;
|
|
47
|
+
return total;
|
|
48
|
+
}
|
|
49
|
+
function leastRecentlyUsedName(slots, excludeName) {
|
|
50
|
+
let lruName;
|
|
51
|
+
let lruUsedAtMs = Number.POSITIVE_INFINITY;
|
|
52
|
+
for (const [name, slot] of slots) {
|
|
53
|
+
if (name === excludeName)
|
|
54
|
+
continue;
|
|
55
|
+
const usedAtMs = slotLastUsedAtMs(slot);
|
|
56
|
+
if (usedAtMs < lruUsedAtMs) {
|
|
57
|
+
lruUsedAtMs = usedAtMs;
|
|
58
|
+
lruName = name;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return lruName;
|
|
62
|
+
}
|
|
39
63
|
/** Reserve at most roughly one context token's worth of bytes per advertised context token. */
|
|
40
64
|
export function resolveActiveSkillBodyByteLimit(contextWindow) {
|
|
41
65
|
if (contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) {
|
|
@@ -46,7 +70,7 @@ export function resolveActiveSkillBodyByteLimit(contextWindow) {
|
|
|
46
70
|
/** One host-owned, event-driven lifecycle for lazy skill discovery and transient context projection. */
|
|
47
71
|
export class SkillVaultController {
|
|
48
72
|
constructor(options) {
|
|
49
|
-
this.
|
|
73
|
+
this.slots = new Map();
|
|
50
74
|
this.contextRevision = 0;
|
|
51
75
|
if (!Number.isFinite(options.idleTimeoutMs ?? DEFAULT_SKILL_IDLE_TIMEOUT_MS)) {
|
|
52
76
|
throw new TypeError("Skill idle timeout must be finite.");
|
|
@@ -72,6 +96,8 @@ export class SkillVaultController {
|
|
|
72
96
|
return { candidates };
|
|
73
97
|
}
|
|
74
98
|
load(name, requester) {
|
|
99
|
+
const now = this.now();
|
|
100
|
+
this.reconcile(now);
|
|
75
101
|
const skill = this.getSkills().find((candidate) => candidate.name === name && (requester === "user" || !candidate.disableModelInvocation));
|
|
76
102
|
if (!skill) {
|
|
77
103
|
return { ok: false, reason: "not_found", message: `No eligible skill named ${JSON.stringify(name)}.` };
|
|
@@ -122,80 +148,87 @@ export class SkillVaultController {
|
|
|
122
148
|
if (!sameFileVersion(before, file)) {
|
|
123
149
|
return { ok: false, reason: "read_failed", message: "Skill changed while it was being loaded." };
|
|
124
150
|
}
|
|
125
|
-
const
|
|
126
|
-
|
|
151
|
+
const next = new Map(this.slots);
|
|
152
|
+
next.set(skill.name, {
|
|
127
153
|
state: "loaded_pending",
|
|
128
154
|
skill,
|
|
129
155
|
bodyBytes,
|
|
130
156
|
systemPromptSection: activeSkillContext(skill, body),
|
|
131
157
|
requester,
|
|
132
|
-
loadedAtMs:
|
|
158
|
+
loadedAtMs: now,
|
|
133
159
|
fileDevice: file.dev,
|
|
134
160
|
fileInode: file.ino,
|
|
135
161
|
fileSize: file.size,
|
|
136
162
|
fileModifiedAtMs: file.mtimeMs,
|
|
137
163
|
fileChangedAtMs: file.ctimeMs,
|
|
138
164
|
});
|
|
139
|
-
|
|
165
|
+
const evicted = [];
|
|
166
|
+
while (next.size > MAX_LOADED_SKILLS || aggregateBodyBytes(next) > maxBodyBytes) {
|
|
167
|
+
const victim = leastRecentlyUsedName(next, skill.name);
|
|
168
|
+
if (!victim)
|
|
169
|
+
break;
|
|
170
|
+
next.delete(victim);
|
|
171
|
+
evicted.push(victim);
|
|
172
|
+
}
|
|
173
|
+
this.replaceState(next);
|
|
174
|
+
return {
|
|
175
|
+
ok: true,
|
|
176
|
+
state: "loaded_pending",
|
|
177
|
+
name: skill.name,
|
|
178
|
+
baseDir: skill.baseDir,
|
|
179
|
+
...(evicted.length > 0 ? { evicted } : {}),
|
|
180
|
+
};
|
|
140
181
|
}
|
|
141
|
-
unload() {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
182
|
+
unload(name) {
|
|
183
|
+
this.reconcile(this.now());
|
|
184
|
+
const target = name?.trim();
|
|
185
|
+
const unloaded = !target ? [...this.slots.keys()] : this.slots.has(target) ? [target] : [];
|
|
186
|
+
if (unloaded.length > 0) {
|
|
187
|
+
const next = new Map(this.slots);
|
|
188
|
+
for (const slotName of unloaded)
|
|
189
|
+
next.delete(slotName);
|
|
190
|
+
this.replaceState(next, "explicit");
|
|
191
|
+
}
|
|
192
|
+
return { ok: true, unloaded };
|
|
145
193
|
}
|
|
146
194
|
status() {
|
|
147
195
|
const now = this.now();
|
|
148
196
|
this.reconcile(now);
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
state: "unloaded",
|
|
152
|
-
idleTimeoutMs: this.idleTimeoutMs,
|
|
153
|
-
...(this.current.reason ? { reason: this.current.reason } : {}),
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
if (this.current.state === "loaded_pending") {
|
|
157
|
-
return {
|
|
158
|
-
state: "loaded_pending",
|
|
159
|
-
idleTimeoutMs: this.idleTimeoutMs,
|
|
160
|
-
name: this.current.skill.name,
|
|
161
|
-
loadedAtMs: this.current.loadedAtMs,
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
const idleForMs = Math.max(0, now - this.current.lastUsedAtMs);
|
|
197
|
+
const slots = [...this.slots.values()].map((slot) => this.slotStatus(slot, now));
|
|
165
198
|
return {
|
|
166
|
-
state: "active",
|
|
167
199
|
idleTimeoutMs: this.idleTimeoutMs,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
lastUsedAtMs: this.current.lastUsedAtMs,
|
|
171
|
-
idleForMs,
|
|
172
|
-
expiresInMs: Math.max(0, this.idleTimeoutMs - idleForMs),
|
|
173
|
-
useCount: this.current.useCount,
|
|
200
|
+
slots,
|
|
201
|
+
...(slots.length === 0 && this.unloadReason ? { reason: this.unloadReason } : {}),
|
|
174
202
|
};
|
|
175
203
|
}
|
|
176
204
|
commitSystemPromptSection() {
|
|
177
205
|
const now = this.now();
|
|
178
206
|
this.reconcile(now);
|
|
179
|
-
if (this.
|
|
207
|
+
if (this.slots.size === 0)
|
|
180
208
|
return undefined;
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
209
|
+
const sections = [];
|
|
210
|
+
for (const [name, slot] of this.slots) {
|
|
211
|
+
sections.push(slot.systemPromptSection);
|
|
212
|
+
const firstUse = slot.state === "loaded_pending";
|
|
213
|
+
const useCount = firstUse ? 1 : slot.useCount + 1;
|
|
214
|
+
this.slots.set(name, { ...slot, state: "active", lastUsedAtMs: now, useCount });
|
|
215
|
+
if (firstUse) {
|
|
216
|
+
try {
|
|
217
|
+
this.onSkillUsed?.(slot.skill, now);
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// Usage telemetry must never block skill application.
|
|
221
|
+
}
|
|
191
222
|
}
|
|
192
223
|
}
|
|
193
|
-
return
|
|
224
|
+
return sections.join("\n\n");
|
|
194
225
|
}
|
|
195
226
|
/** Model the next request's transient system cost without treating a diagnostic read as use. */
|
|
196
227
|
previewSystemPromptSection() {
|
|
197
228
|
this.reconcile(this.now());
|
|
198
|
-
|
|
229
|
+
if (this.slots.size === 0)
|
|
230
|
+
return undefined;
|
|
231
|
+
return [...this.slots.values()].map((slot) => slot.systemPromptSection).join("\n\n");
|
|
199
232
|
}
|
|
200
233
|
/** Compose the exact provider system prompt for read-only diagnostics. */
|
|
201
234
|
previewRequestSystemPrompt(base) {
|
|
@@ -209,55 +242,81 @@ export class SkillVaultController {
|
|
|
209
242
|
/** Record host-observed work derived from an active skill, independent of agent cooperation. */
|
|
210
243
|
noteActivity() {
|
|
211
244
|
const now = this.now();
|
|
212
|
-
|
|
213
|
-
|
|
245
|
+
for (const [name, slot] of this.slots) {
|
|
246
|
+
if (slot.state === "active") {
|
|
247
|
+
this.slots.set(name, { ...slot, lastUsedAtMs: now });
|
|
248
|
+
}
|
|
214
249
|
}
|
|
215
250
|
}
|
|
251
|
+
slotStatus(slot, now) {
|
|
252
|
+
if (slot.state === "loaded_pending") {
|
|
253
|
+
return { state: "loaded_pending", name: slot.skill.name, loadedAtMs: slot.loadedAtMs };
|
|
254
|
+
}
|
|
255
|
+
const idleForMs = Math.max(0, now - slot.lastUsedAtMs);
|
|
256
|
+
return {
|
|
257
|
+
state: "active",
|
|
258
|
+
name: slot.skill.name,
|
|
259
|
+
loadedAtMs: slot.loadedAtMs,
|
|
260
|
+
lastUsedAtMs: slot.lastUsedAtMs,
|
|
261
|
+
idleForMs,
|
|
262
|
+
expiresInMs: Math.max(0, this.idleTimeoutMs - idleForMs),
|
|
263
|
+
useCount: slot.useCount,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
216
266
|
reconcile(now) {
|
|
217
|
-
if (
|
|
218
|
-
return;
|
|
219
|
-
const current = this.current;
|
|
220
|
-
if (current.state === "unloaded")
|
|
267
|
+
if (this.slots.size === 0)
|
|
221
268
|
return;
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
269
|
+
const maxBodyBytes = this.resolveMaxBodyBytes();
|
|
270
|
+
const skills = this.getSkills();
|
|
271
|
+
const next = new Map(this.slots);
|
|
272
|
+
let reason;
|
|
273
|
+
for (const [name, slot] of this.slots) {
|
|
274
|
+
const slotReason = this.reconcileSlot(slot, skills, maxBodyBytes, now);
|
|
275
|
+
if (slotReason !== undefined) {
|
|
276
|
+
next.delete(name);
|
|
277
|
+
reason = slotReason;
|
|
278
|
+
}
|
|
225
279
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
this.replaceState({ state: "unloaded", reason: "budget_exceeded" });
|
|
233
|
-
return false;
|
|
280
|
+
while (aggregateBodyBytes(next) > maxBodyBytes) {
|
|
281
|
+
const victim = leastRecentlyUsedName(next);
|
|
282
|
+
if (!victim)
|
|
283
|
+
break;
|
|
284
|
+
next.delete(victim);
|
|
285
|
+
reason = "budget_exceeded";
|
|
234
286
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
(loaded.requester === "user" || !skill.disableModelInvocation));
|
|
238
|
-
if (!currentSkill) {
|
|
239
|
-
this.replaceState({ state: "unloaded", reason: "resource_unavailable" });
|
|
240
|
-
return false;
|
|
287
|
+
if (next.size !== this.slots.size) {
|
|
288
|
+
this.replaceState(next, reason);
|
|
241
289
|
}
|
|
290
|
+
}
|
|
291
|
+
reconcileSlot(slot, skills, maxBodyBytes, now) {
|
|
292
|
+
if (slot.bodyBytes > maxBodyBytes)
|
|
293
|
+
return "budget_exceeded";
|
|
294
|
+
const currentSkill = skills.find((skill) => skill.name === slot.skill.name &&
|
|
295
|
+
skill.filePath === slot.skill.filePath &&
|
|
296
|
+
(slot.requester === "user" || !skill.disableModelInvocation));
|
|
297
|
+
if (!currentSkill)
|
|
298
|
+
return "resource_unavailable";
|
|
242
299
|
try {
|
|
243
|
-
const file = statSync(
|
|
244
|
-
if (file.dev !==
|
|
245
|
-
file.ino !==
|
|
246
|
-
file.size !==
|
|
247
|
-
file.mtimeMs !==
|
|
248
|
-
file.ctimeMs !==
|
|
249
|
-
|
|
250
|
-
return false;
|
|
300
|
+
const file = statSync(slot.skill.filePath);
|
|
301
|
+
if (file.dev !== slot.fileDevice ||
|
|
302
|
+
file.ino !== slot.fileInode ||
|
|
303
|
+
file.size !== slot.fileSize ||
|
|
304
|
+
file.mtimeMs !== slot.fileModifiedAtMs ||
|
|
305
|
+
file.ctimeMs !== slot.fileChangedAtMs) {
|
|
306
|
+
return "resource_unavailable";
|
|
251
307
|
}
|
|
252
308
|
}
|
|
253
309
|
catch {
|
|
254
|
-
|
|
255
|
-
return false;
|
|
310
|
+
return "resource_unavailable";
|
|
256
311
|
}
|
|
257
|
-
|
|
312
|
+
if (now - slotLastUsedAtMs(slot) >= this.idleTimeoutMs)
|
|
313
|
+
return "idle_expired";
|
|
314
|
+
return undefined;
|
|
258
315
|
}
|
|
259
|
-
replaceState(
|
|
260
|
-
this.
|
|
316
|
+
replaceState(slots, unloadReason) {
|
|
317
|
+
this.slots = slots;
|
|
318
|
+
if (unloadReason !== undefined)
|
|
319
|
+
this.unloadReason = unloadReason;
|
|
261
320
|
this.contextRevision++;
|
|
262
321
|
}
|
|
263
322
|
resolveMaxBodyBytes() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill-vault.js","sourceRoot":"","sources":["../../src/core/skill-vault.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oDAAoD,CAAC;AAChG,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAC1E,OAAO,EAAE,2BAA2B,EAAqC,MAAM,aAAa,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAElF,MAAM,CAAC,MAAM,6BAA6B,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5D,MAAM,CAAC,MAAM,2BAA2B,GAAG,EAAE,GAAG,IAAI,CAAC;AACrD,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAG,IAAI,CAAC;AACpD,MAAM,kBAAkB,GAAG,CAAC,CAAC;AAC7B,MAAM,4BAA4B,GAAG,GAAG,CAAC;AAmDzC,SAAS,kBAAkB,CAAC,WAAmB;IAC9C,MAAM,UAAU,GAAG,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAC3D,IAAI,UAAU,CAAC,MAAM,IAAI,4BAA4B;QAAE,OAAO,UAAU,CAAC;IACzE,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,4BAA4B,GAAG,CAAC,CAAC,GAAG,CAAC;AACpE,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IACjC,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,WAAW,CAAC,KAAY,EAAE,KAAa,EAAE,MAAyB;IAC1E,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IACtC,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC,WAAW,EAAE,CAAC;IACpD,IAAI,KAAK,GAAG,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpG,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,IAAI,KAAK,KAAK;YAAE,KAAK,IAAI,EAAE,CAAC;aAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;QAC1C,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,KAAK,IAAI,CAAC,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,KAAY,EAAE,IAAY;IACrD,OAAO,CAAC,gBAAgB,KAAK,CAAC,IAAI,EAAE,EAAE,QAAQ,KAAK,CAAC,OAAO,EAAE,EAAE,8BAA8B,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACjH,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,+BAA+B,CAAC,aAAiC;IAChF,IAAI,aAAa,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;QAC1F,OAAO,2BAA2B,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;AAChH,CAAC;AAED,wGAAwG;AACxG,MAAM,OAAO,oBAAoB;IAShC,YAAY,OAAoC;QAHxC,YAAO,GAAoB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;QACjD,oBAAe,GAAG,CAAC,CAAC;QAG3B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,aAAa,IAAI,6BAA6B,CAAC,EAAE,CAAC;YAC9E,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAC;QAC3D,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,aAAa,IAAI,6BAA6B,CAAC,CAAC;QACzF,IAAI,CAAC,eAAe,GAAG,OAAO,CAAC,eAAe,IAAI,CAAC,GAAG,EAAE,CAAC,2BAA2B,CAAC,CAAC;QACtF,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACxC,CAAC;IAED,MAAM,CAAC,QAAgB;QACtB,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC7D,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE;aACjC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,sBAAsB,CAAC;aAChD,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;aACrE,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;aAClC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aAClG,KAAK,CAAC,CAAC,EAAE,kBAAkB,CAAC;aAC5B,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,WAAW,EAAE,kBAAkB,CAAC,KAAK,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC;QACjG,OAAO,EAAE,UAAU,EAAE,CAAC;IACvB,CAAC;IAED,IAAI,CAAC,IAAY,EAAE,SAA8B;QAChD,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CAClC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,SAAS,KAAK,MAAM,IAAI,CAAC,SAAS,CAAC,sBAAsB,CAAC,CACrG,CAAC;QACF,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,EAAE,2BAA2B,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACxG,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAChD,IAAI,MAAmC,CAAC;QACxC,IAAI,CAAC;YACJ,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9G,CAAC;QACD,IAAI,GAAW,CAAC;QAChB,IAAI,CAAC;YACJ,GAAG,GAAG,uBAAuB,CAC5B,KAAK,CAAC,QAAQ,EACd,YAAY,GAAG,2BAA2B,EAC1C,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CACrC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC;gBAChD,CAAC,CAAC;oBACA,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,gBAAgB;oBACxB,OAAO,EAAE,sBAAsB,YAAY,wBAAwB;iBACnE;gBACF,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC;QAClD,CAAC;QACD,MAAM,MAAM,GAAG,gBAAgB,CAAmB,GAAG,CAAC,CAAC;QACvD,MAAM,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC;QAC1D,MAAM,IAAI,GAAG,0BAA0B,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,WAAW,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,WAAW,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5E,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,8CAA8C,EAAE,CAAC;QACvG,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QAClD,IAAI,SAAS,GAAG,YAAY,EAAE,CAAC;YAC9B,OAAO;gBACN,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,gBAAgB;gBACxB,OAAO,EAAE,sBAAsB,YAAY,wBAAwB;aACnE,CAAC;QACH,CAAC;QACD,IAAI,IAAiC,CAAC;QACtC,IAAI,CAAC;YACJ,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9G,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;YACpC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,0CAA0C,EAAE,CAAC;QAClG,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QACzF,IAAI,CAAC,YAAY,CAAC;YACjB,KAAK,EAAE,gBAAgB;YACvB,KAAK;YACL,SAAS;YACT,mBAAmB,EAAE,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC;YACpD,SAAS;YACT,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE;YACtB,UAAU,EAAE,IAAI,CAAC,GAAG;YACpB,SAAS,EAAE,IAAI,CAAC,GAAG;YACnB,QAAQ,EAAE,IAAI,CAAC,IAAI;YACnB,gBAAgB,EAAE,IAAI,CAAC,OAAO;YAC9B,eAAe,EAAE,IAAI,CAAC,OAAO;SAC7B,CAAC,CAAC;QACH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,gBAAgB,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACnG,CAAC;IAED,MAAM;QACL,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;QACzF,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC,CAAC;QAC7D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IACxD,CAAC;IAED,MAAM;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;YACvC,OAAO;gBACN,KAAK,EAAE,UAAU;gBACjB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC;QACH,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,gBAAgB,EAAE,CAAC;YAC7C,OAAO;gBACN,KAAK,EAAE,gBAAgB;gBACvB,aAAa,EAAE,IAAI,CAAC,aAAa;gBACjC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI;gBAC7B,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;aACnC,CAAC;QACH,CAAC;QACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QAC/D,OAAO;YACN,KAAK,EAAE,QAAQ;YACf,aAAa,EAAE,IAAI,CAAC,aAAa;YACjC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI;YAC7B,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU;YACnC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY;YACvC,SAAS;YACT,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,aAAa,GAAG,SAAS,CAAC;YACxD,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;SAC/B,CAAC;IACH,CAAC;IAED,yBAAyB;QACxB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU;YAAE,OAAO,SAAS,CAAC;QACxD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,KAAK,gBAAgB,CAAC;QACnD,MAAM,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC;QACpD,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC;QAC3E,IAAI,QAAQ,EAAE,CAAC;YACd,IAAI,CAAC;gBACJ,IAAI,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACR,sDAAsD;YACvD,CAAC;QACF,CAAC;QACD,OAAO,MAAM,CAAC,mBAAmB,CAAC;IACnC,CAAC;IAED,gGAAgG;IAChG,0BAA0B;QACzB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC;IACzF,CAAC;IAED,0EAA0E;IAC1E,0BAA0B,CAAC,IAAwB;QAClD,OAAO,0BAA0B,CAAC,IAAI,EAAE,IAAI,CAAC,0BAA0B,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,wEAAwE;IACxE,kBAAkB;QACjB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC,eAAe,CAAC;IAC7B,CAAC;IAED,gGAAgG;IAChG,YAAY;QACX,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC;QACvD,CAAC;IACF,CAAC;IAEO,SAAS,CAAC,GAAW;QAC5B,IAAI,CAAC,IAAI,CAAC,iBAAiB,EAAE;YAAE,OAAO;QACtC,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAC7B,IAAI,OAAO,CAAC,KAAK,KAAK,UAAU;YAAE,OAAO;QACzC,MAAM,YAAY,GAAG,OAAO,CAAC,KAAK,KAAK,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;QACpG,IAAI,GAAG,GAAG,YAAY,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YAC9C,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC,CAAC;QAClE,CAAC;IACF,CAAC;IAEO,iBAAiB;QACxB,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QACpD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAC5B,IAAI,MAAM,CAAC,SAAS,GAAG,IAAI,CAAC,mBAAmB,EAAE,EAAE,CAAC;YACnD,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;YACpE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,IAAI,CACzC,CAAC,KAAK,EAAE,EAAE,CACT,KAAK,CAAC,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,IAAI;YAChC,KAAK,CAAC,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,QAAQ;YACxC,CAAC,MAAM,CAAC,SAAS,KAAK,MAAM,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAC/D,CAAC;QACF,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACzE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAC7C,IACC,IAAI,CAAC,GAAG,KAAK,MAAM,CAAC,UAAU;gBAC9B,IAAI,CAAC,GAAG,KAAK,MAAM,CAAC,SAAS;gBAC7B,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC,QAAQ;gBAC7B,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,gBAAgB;gBACxC,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,eAAe,EACtC,CAAC;gBACF,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;gBACzE,OAAO,KAAK,CAAC;YACd,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,IAAI,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC,CAAC;YACzE,OAAO,KAAK,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACb,CAAC;IAEO,YAAY,CAAC,KAAsB;QAC1C,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,eAAe,EAAE,CAAC;IACxB,CAAC;IAEO,mBAAmB;QAC1B,MAAM,UAAU,GAAG,IAAI,CAAC,eAAe,EAAE,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC;YAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IACnF,CAAC;CACD","sourcesContent":["import { statSync } from \"node:fs\";\nimport { performance } from \"node:perf_hooks\";\nimport { composeRequestSystemPrompt } from \"@caupulican/pi-agent-core/provider-request-planner\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { MAX_SKILL_FRONTMATTER_BYTES, type Skill, type SkillFrontmatter } from \"./skills.ts\";\nimport { readBoundedTextFileSync, sameFileVersion } from \"./util/bounded-file.ts\";\n\nexport const DEFAULT_SKILL_IDLE_TIMEOUT_MS = 10 * 60 * 1000;\nexport const MAX_ACTIVE_SKILL_BODY_BYTES = 64 * 1024;\nexport const MIN_ACTIVE_SKILL_BODY_BYTES = 4 * 1024;\nconst MAX_SEARCH_RESULTS = 5;\nconst MAX_SEARCH_DESCRIPTION_CHARS = 240;\n\ntype SkillVaultRequester = \"model\" | \"user\";\ntype SkillVaultUnloadReason = \"explicit\" | \"idle_expired\" | \"resource_unavailable\" | \"budget_exceeded\";\n\ninterface LoadedSkill {\n\tskill: Skill;\n\tbodyBytes: number;\n\tsystemPromptSection: string;\n\trequester: SkillVaultRequester;\n\tloadedAtMs: number;\n\tfileDevice: number;\n\tfileInode: number;\n\tfileSize: number;\n\tfileModifiedAtMs: number;\n\tfileChangedAtMs: number;\n}\n\ntype SkillVaultState =\n\t| { state: \"unloaded\"; reason?: SkillVaultUnloadReason }\n\t| ({ state: \"loaded_pending\" } & LoadedSkill)\n\t| ({ state: \"active\"; lastUsedAtMs: number; useCount: number } & LoadedSkill);\n\nexport interface SkillVaultStatus {\n\tstate: SkillVaultState[\"state\"];\n\tidleTimeoutMs: number;\n\tname?: string;\n\tloadedAtMs?: number;\n\tlastUsedAtMs?: number;\n\tidleForMs?: number;\n\texpiresInMs?: number;\n\tuseCount?: number;\n\treason?: SkillVaultUnloadReason;\n}\n\nexport interface SkillSearchResult {\n\tcandidates: Array<{ name: string; description: string }>;\n}\n\nexport type SkillLoadResult =\n\t| { ok: true; state: \"loaded_pending\"; name: string; replaced?: string }\n\t| { ok: false; reason: \"not_found\" | \"body_too_large\" | \"invalid_body\" | \"read_failed\"; message: string };\n\nexport interface SkillVaultControllerOptions {\n\tgetSkills(): readonly Skill[];\n\tnow?: () => number;\n\tidleTimeoutMs?: number;\n\tgetMaxBodyBytes?: () => number;\n\tonSkillUsed?: (skill: Skill, usedAtMs: number) => void;\n}\n\nfunction compactDescription(description: string): string {\n\tconst normalized = description.replace(/\\s+/g, \" \").trim();\n\tif (normalized.length <= MAX_SEARCH_DESCRIPTION_CHARS) return normalized;\n\treturn `${normalized.slice(0, MAX_SEARCH_DESCRIPTION_CHARS - 1)}…`;\n}\n\nfunction queryTokens(value: string): string[] {\n\treturn [...new Set(value.toLowerCase().match(/[\\p{L}\\p{N}]+/gu) ?? [])];\n}\n\nfunction searchScore(skill: Skill, query: string, tokens: readonly string[]): number {\n\tconst name = skill.name.toLowerCase();\n\tconst description = skill.description.toLowerCase();\n\tlet score = name === query ? 100 : name.includes(query) ? 40 : description.includes(query) ? 20 : 0;\n\tfor (const token of tokens) {\n\t\tif (name === token) score += 16;\n\t\telse if (name.includes(token)) score += 8;\n\t\tif (description.includes(token)) score += 3;\n\t}\n\treturn score;\n}\n\nfunction activeSkillContext(skill: Skill, body: string): string {\n\treturn [`ACTIVE SKILL ${skill.name}`, `BASE ${skill.baseDir}`, \"NON-NEGOTIABLE WHILE ACTIVE:\", body].join(\"\\n\");\n}\n\n/** Reserve at most roughly one context token's worth of bytes per advertised context token. */\nexport function resolveActiveSkillBodyByteLimit(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) {\n\t\treturn MAX_ACTIVE_SKILL_BODY_BYTES;\n\t}\n\treturn Math.min(MAX_ACTIVE_SKILL_BODY_BYTES, Math.max(MIN_ACTIVE_SKILL_BODY_BYTES, Math.floor(contextWindow)));\n}\n\n/** One host-owned, event-driven lifecycle for lazy skill discovery and transient context projection. */\nexport class SkillVaultController {\n\tprivate readonly getSkills: () => readonly Skill[];\n\tprivate readonly now: () => number;\n\tprivate readonly idleTimeoutMs: number;\n\tprivate readonly getMaxBodyBytes: () => number;\n\tprivate readonly onSkillUsed: ((skill: Skill, usedAtMs: number) => void) | undefined;\n\tprivate current: SkillVaultState = { state: \"unloaded\" };\n\tprivate contextRevision = 0;\n\n\tconstructor(options: SkillVaultControllerOptions) {\n\t\tif (!Number.isFinite(options.idleTimeoutMs ?? DEFAULT_SKILL_IDLE_TIMEOUT_MS)) {\n\t\t\tthrow new TypeError(\"Skill idle timeout must be finite.\");\n\t\t}\n\t\tthis.getSkills = options.getSkills;\n\t\tthis.now = options.now ?? (() => performance.now());\n\t\tthis.idleTimeoutMs = Math.max(1, options.idleTimeoutMs ?? DEFAULT_SKILL_IDLE_TIMEOUT_MS);\n\t\tthis.getMaxBodyBytes = options.getMaxBodyBytes ?? (() => MAX_ACTIVE_SKILL_BODY_BYTES);\n\t\tthis.onSkillUsed = options.onSkillUsed;\n\t}\n\n\tsearch(rawQuery: string): SkillSearchResult {\n\t\tconst query = rawQuery.trim().toLowerCase();\n\t\tconst tokens = queryTokens(query);\n\t\tif (!query || tokens.length === 0) return { candidates: [] };\n\t\tconst candidates = this.getSkills()\n\t\t\t.filter((skill) => !skill.disableModelInvocation)\n\t\t\t.map((skill) => ({ skill, score: searchScore(skill, query, tokens) }))\n\t\t\t.filter((entry) => entry.score > 0)\n\t\t\t.sort((left, right) => right.score - left.score || left.skill.name.localeCompare(right.skill.name))\n\t\t\t.slice(0, MAX_SEARCH_RESULTS)\n\t\t\t.map(({ skill }) => ({ name: skill.name, description: compactDescription(skill.description) }));\n\t\treturn { candidates };\n\t}\n\n\tload(name: string, requester: SkillVaultRequester): SkillLoadResult {\n\t\tconst skill = this.getSkills().find(\n\t\t\t(candidate) => candidate.name === name && (requester === \"user\" || !candidate.disableModelInvocation),\n\t\t);\n\t\tif (!skill) {\n\t\t\treturn { ok: false, reason: \"not_found\", message: `No eligible skill named ${JSON.stringify(name)}.` };\n\t\t}\n\t\tconst maxBodyBytes = this.resolveMaxBodyBytes();\n\t\tlet before: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tbefore = statSync(skill.filePath);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = readBoundedTextFileSync(\n\t\t\t\tskill.filePath,\n\t\t\t\tmaxBodyBytes + MAX_SKILL_FRONTMATTER_BYTES,\n\t\t\t\t`Skill ${JSON.stringify(skill.name)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn message.includes(\"exceeds its byte limit\")\n\t\t\t\t? {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\treason: \"body_too_large\",\n\t\t\t\t\t\tmessage: `Skill body exceeds ${maxBodyBytes} bytes; not truncated.`,\n\t\t\t\t\t}\n\t\t\t\t: { ok: false, reason: \"read_failed\", message };\n\t\t}\n\t\tconst parsed = parseFrontmatter<SkillFrontmatter>(raw);\n\t\tconst currentName = parsed.frontmatter.name ?? skill.name;\n\t\tconst body = stripResourceProfileBlocks(parsed.body).trim();\n\t\tif (currentName !== skill.name || !parsed.frontmatter.description || !body) {\n\t\t\treturn { ok: false, reason: \"invalid_body\", message: \"Skill metadata changed or its body is empty.\" };\n\t\t}\n\t\tconst bodyBytes = Buffer.byteLength(body, \"utf8\");\n\t\tif (bodyBytes > maxBodyBytes) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"body_too_large\",\n\t\t\t\tmessage: `Skill body exceeds ${maxBodyBytes} bytes; not truncated.`,\n\t\t\t};\n\t\t}\n\t\tlet file: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tfile = statSync(skill.filePath);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t\tif (!sameFileVersion(before, file)) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: \"Skill changed while it was being loaded.\" };\n\t\t}\n\t\tconst replaced = this.current.state === \"unloaded\" ? undefined : this.current.skill.name;\n\t\tthis.replaceState({\n\t\t\tstate: \"loaded_pending\",\n\t\t\tskill,\n\t\t\tbodyBytes,\n\t\t\tsystemPromptSection: activeSkillContext(skill, body),\n\t\t\trequester,\n\t\t\tloadedAtMs: this.now(),\n\t\t\tfileDevice: file.dev,\n\t\t\tfileInode: file.ino,\n\t\t\tfileSize: file.size,\n\t\t\tfileModifiedAtMs: file.mtimeMs,\n\t\t\tfileChangedAtMs: file.ctimeMs,\n\t\t});\n\t\treturn { ok: true, state: \"loaded_pending\", name: skill.name, ...(replaced ? { replaced } : {}) };\n\t}\n\n\tunload(): { ok: true; unloaded?: string } {\n\t\tconst unloaded = this.current.state === \"unloaded\" ? undefined : this.current.skill.name;\n\t\tthis.replaceState({ state: \"unloaded\", reason: \"explicit\" });\n\t\treturn { ok: true, ...(unloaded ? { unloaded } : {}) };\n\t}\n\n\tstatus(): SkillVaultStatus {\n\t\tconst now = this.now();\n\t\tthis.reconcile(now);\n\t\tif (this.current.state === \"unloaded\") {\n\t\t\treturn {\n\t\t\t\tstate: \"unloaded\",\n\t\t\t\tidleTimeoutMs: this.idleTimeoutMs,\n\t\t\t\t...(this.current.reason ? { reason: this.current.reason } : {}),\n\t\t\t};\n\t\t}\n\t\tif (this.current.state === \"loaded_pending\") {\n\t\t\treturn {\n\t\t\t\tstate: \"loaded_pending\",\n\t\t\t\tidleTimeoutMs: this.idleTimeoutMs,\n\t\t\t\tname: this.current.skill.name,\n\t\t\t\tloadedAtMs: this.current.loadedAtMs,\n\t\t\t};\n\t\t}\n\t\tconst idleForMs = Math.max(0, now - this.current.lastUsedAtMs);\n\t\treturn {\n\t\t\tstate: \"active\",\n\t\t\tidleTimeoutMs: this.idleTimeoutMs,\n\t\t\tname: this.current.skill.name,\n\t\t\tloadedAtMs: this.current.loadedAtMs,\n\t\t\tlastUsedAtMs: this.current.lastUsedAtMs,\n\t\t\tidleForMs,\n\t\t\texpiresInMs: Math.max(0, this.idleTimeoutMs - idleForMs),\n\t\t\tuseCount: this.current.useCount,\n\t\t};\n\t}\n\n\tcommitSystemPromptSection(): string | undefined {\n\t\tconst now = this.now();\n\t\tthis.reconcile(now);\n\t\tif (this.current.state === \"unloaded\") return undefined;\n\t\tconst loaded = this.current;\n\t\tconst firstUse = loaded.state === \"loaded_pending\";\n\t\tconst useCount = firstUse ? 1 : loaded.useCount + 1;\n\t\tthis.current = { ...loaded, state: \"active\", lastUsedAtMs: now, useCount };\n\t\tif (firstUse) {\n\t\t\ttry {\n\t\t\t\tthis.onSkillUsed?.(loaded.skill, now);\n\t\t\t} catch {\n\t\t\t\t// Usage telemetry must never block skill application.\n\t\t\t}\n\t\t}\n\t\treturn loaded.systemPromptSection;\n\t}\n\n\t/** Model the next request's transient system cost without treating a diagnostic read as use. */\n\tpreviewSystemPromptSection(): string | undefined {\n\t\tthis.reconcile(this.now());\n\t\treturn this.current.state === \"unloaded\" ? undefined : this.current.systemPromptSection;\n\t}\n\n\t/** Compose the exact provider system prompt for read-only diagnostics. */\n\tpreviewRequestSystemPrompt(base: string | undefined): string | undefined {\n\t\treturn composeRequestSystemPrompt(base, this.previewSystemPromptSection());\n\t}\n\n\t/** Monotonic identity for provider-visible skill projection changes. */\n\tgetContextRevision(): number {\n\t\tthis.reconcile(this.now());\n\t\treturn this.contextRevision;\n\t}\n\n\t/** Record host-observed work derived from an active skill, independent of agent cooperation. */\n\tnoteActivity(): void {\n\t\tconst now = this.now();\n\t\tif (this.current.state === \"active\") {\n\t\t\tthis.current = { ...this.current, lastUsedAtMs: now };\n\t\t}\n\t}\n\n\tprivate reconcile(now: number): void {\n\t\tif (!this.reconcileResource()) return;\n\t\tconst current = this.current;\n\t\tif (current.state === \"unloaded\") return;\n\t\tconst lastUsedAtMs = current.state === \"loaded_pending\" ? current.loadedAtMs : current.lastUsedAtMs;\n\t\tif (now - lastUsedAtMs >= this.idleTimeoutMs) {\n\t\t\tthis.replaceState({ state: \"unloaded\", reason: \"idle_expired\" });\n\t\t}\n\t}\n\n\tprivate reconcileResource(): boolean {\n\t\tif (this.current.state === \"unloaded\") return false;\n\t\tconst loaded = this.current;\n\t\tif (loaded.bodyBytes > this.resolveMaxBodyBytes()) {\n\t\t\tthis.replaceState({ state: \"unloaded\", reason: \"budget_exceeded\" });\n\t\t\treturn false;\n\t\t}\n\t\tconst currentSkill = this.getSkills().find(\n\t\t\t(skill) =>\n\t\t\t\tskill.name === loaded.skill.name &&\n\t\t\t\tskill.filePath === loaded.skill.filePath &&\n\t\t\t\t(loaded.requester === \"user\" || !skill.disableModelInvocation),\n\t\t);\n\t\tif (!currentSkill) {\n\t\t\tthis.replaceState({ state: \"unloaded\", reason: \"resource_unavailable\" });\n\t\t\treturn false;\n\t\t}\n\t\ttry {\n\t\t\tconst file = statSync(loaded.skill.filePath);\n\t\t\tif (\n\t\t\t\tfile.dev !== loaded.fileDevice ||\n\t\t\t\tfile.ino !== loaded.fileInode ||\n\t\t\t\tfile.size !== loaded.fileSize ||\n\t\t\t\tfile.mtimeMs !== loaded.fileModifiedAtMs ||\n\t\t\t\tfile.ctimeMs !== loaded.fileChangedAtMs\n\t\t\t) {\n\t\t\t\tthis.replaceState({ state: \"unloaded\", reason: \"resource_unavailable\" });\n\t\t\t\treturn false;\n\t\t\t}\n\t\t} catch {\n\t\t\tthis.replaceState({ state: \"unloaded\", reason: \"resource_unavailable\" });\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivate replaceState(state: SkillVaultState): void {\n\t\tthis.current = state;\n\t\tthis.contextRevision++;\n\t}\n\n\tprivate resolveMaxBodyBytes(): number {\n\t\tconst configured = this.getMaxBodyBytes();\n\t\tif (!Number.isFinite(configured)) return 1;\n\t\treturn Math.min(MAX_ACTIVE_SKILL_BODY_BYTES, Math.max(1, Math.floor(configured)));\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skill-vault.js","sourceRoot":"","sources":["../../src/core/skill-vault.ts"],"names":[],"mappings":"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","sourcesContent":["import { statSync } from \"node:fs\";\nimport { performance } from \"node:perf_hooks\";\nimport { composeRequestSystemPrompt } from \"@caupulican/pi-agent-core/provider-request-planner\";\nimport { parseFrontmatter } from \"../utils/frontmatter.ts\";\nimport { stripResourceProfileBlocks } from \"./resource-profile-blocks.ts\";\nimport { MAX_SKILL_FRONTMATTER_BYTES, type Skill, type SkillFrontmatter } from \"./skills.ts\";\nimport { readBoundedTextFileSync, sameFileVersion } from \"./util/bounded-file.ts\";\n\nexport const DEFAULT_SKILL_IDLE_TIMEOUT_MS = 10 * 60 * 1000;\nexport const MAX_ACTIVE_SKILL_BODY_BYTES = 64 * 1024;\nexport const MIN_ACTIVE_SKILL_BODY_BYTES = 4 * 1024;\nexport const MAX_LOADED_SKILLS = 3;\nconst MAX_SEARCH_RESULTS = 5;\nconst MAX_SEARCH_DESCRIPTION_CHARS = 240;\n\ntype SkillVaultRequester = \"model\" | \"user\";\ntype SkillVaultUnloadReason = \"explicit\" | \"idle_expired\" | \"resource_unavailable\" | \"budget_exceeded\";\n\ninterface LoadedSkill {\n\tskill: Skill;\n\tbodyBytes: number;\n\tsystemPromptSection: string;\n\trequester: SkillVaultRequester;\n\tloadedAtMs: number;\n\tfileDevice: number;\n\tfileInode: number;\n\tfileSize: number;\n\tfileModifiedAtMs: number;\n\tfileChangedAtMs: number;\n}\n\ntype SkillSlotState =\n\t| ({ state: \"loaded_pending\" } & LoadedSkill)\n\t| ({ state: \"active\"; lastUsedAtMs: number; useCount: number } & LoadedSkill);\n\nexport interface SkillSlotStatus {\n\tstate: SkillSlotState[\"state\"];\n\tname: string;\n\tloadedAtMs: number;\n\tlastUsedAtMs?: number;\n\tidleForMs?: number;\n\texpiresInMs?: number;\n\tuseCount?: number;\n}\n\nexport interface SkillVaultStatus {\n\tidleTimeoutMs: number;\n\tslots: SkillSlotStatus[];\n\treason?: SkillVaultUnloadReason;\n}\n\nexport interface SkillSearchResult {\n\tcandidates: Array<{ name: string; description: string }>;\n}\n\nexport type SkillLoadResult =\n\t| { ok: true; state: \"loaded_pending\"; name: string; baseDir: string; evicted?: string[] }\n\t| { ok: false; reason: \"not_found\" | \"body_too_large\" | \"invalid_body\" | \"read_failed\"; message: string };\n\nexport interface SkillVaultControllerOptions {\n\tgetSkills(): readonly Skill[];\n\tnow?: () => number;\n\tidleTimeoutMs?: number;\n\tgetMaxBodyBytes?: () => number;\n\tonSkillUsed?: (skill: Skill, usedAtMs: number) => void;\n}\n\nfunction compactDescription(description: string): string {\n\tconst normalized = description.replace(/\\s+/g, \" \").trim();\n\tif (normalized.length <= MAX_SEARCH_DESCRIPTION_CHARS) return normalized;\n\treturn `${normalized.slice(0, MAX_SEARCH_DESCRIPTION_CHARS - 1)}…`;\n}\n\nfunction queryTokens(value: string): string[] {\n\treturn [...new Set(value.toLowerCase().match(/[\\p{L}\\p{N}]+/gu) ?? [])];\n}\n\nfunction searchScore(skill: Skill, query: string, tokens: readonly string[]): number {\n\tconst name = skill.name.toLowerCase();\n\tconst description = skill.description.toLowerCase();\n\tlet score = name === query ? 100 : name.includes(query) ? 40 : description.includes(query) ? 20 : 0;\n\tfor (const token of tokens) {\n\t\tif (name === token) score += 16;\n\t\telse if (name.includes(token)) score += 8;\n\t\tif (description.includes(token)) score += 3;\n\t}\n\treturn score;\n}\n\nfunction activeSkillContext(skill: Skill, body: string): string {\n\treturn [`ACTIVE SKILL ${skill.name}`, `BASE ${skill.baseDir}`, \"NON-NEGOTIABLE WHILE ACTIVE:\", body].join(\"\\n\");\n}\n\nfunction slotLastUsedAtMs(slot: SkillSlotState): number {\n\treturn slot.state === \"loaded_pending\" ? slot.loadedAtMs : slot.lastUsedAtMs;\n}\n\nfunction aggregateBodyBytes(slots: ReadonlyMap<string, SkillSlotState>): number {\n\tlet total = 0;\n\tfor (const slot of slots.values()) total += slot.bodyBytes;\n\treturn total;\n}\n\nfunction leastRecentlyUsedName(slots: ReadonlyMap<string, SkillSlotState>, excludeName?: string): string | undefined {\n\tlet lruName: string | undefined;\n\tlet lruUsedAtMs = Number.POSITIVE_INFINITY;\n\tfor (const [name, slot] of slots) {\n\t\tif (name === excludeName) continue;\n\t\tconst usedAtMs = slotLastUsedAtMs(slot);\n\t\tif (usedAtMs < lruUsedAtMs) {\n\t\t\tlruUsedAtMs = usedAtMs;\n\t\t\tlruName = name;\n\t\t}\n\t}\n\treturn lruName;\n}\n\n/** Reserve at most roughly one context token's worth of bytes per advertised context token. */\nexport function resolveActiveSkillBodyByteLimit(contextWindow: number | undefined): number {\n\tif (contextWindow === undefined || !Number.isFinite(contextWindow) || contextWindow <= 0) {\n\t\treturn MAX_ACTIVE_SKILL_BODY_BYTES;\n\t}\n\treturn Math.min(MAX_ACTIVE_SKILL_BODY_BYTES, Math.max(MIN_ACTIVE_SKILL_BODY_BYTES, Math.floor(contextWindow)));\n}\n\n/** One host-owned, event-driven lifecycle for lazy skill discovery and transient context projection. */\nexport class SkillVaultController {\n\tprivate readonly getSkills: () => readonly Skill[];\n\tprivate readonly now: () => number;\n\tprivate readonly idleTimeoutMs: number;\n\tprivate readonly getMaxBodyBytes: () => number;\n\tprivate readonly onSkillUsed: ((skill: Skill, usedAtMs: number) => void) | undefined;\n\tprivate slots = new Map<string, SkillSlotState>();\n\tprivate unloadReason: SkillVaultUnloadReason | undefined;\n\tprivate contextRevision = 0;\n\n\tconstructor(options: SkillVaultControllerOptions) {\n\t\tif (!Number.isFinite(options.idleTimeoutMs ?? DEFAULT_SKILL_IDLE_TIMEOUT_MS)) {\n\t\t\tthrow new TypeError(\"Skill idle timeout must be finite.\");\n\t\t}\n\t\tthis.getSkills = options.getSkills;\n\t\tthis.now = options.now ?? (() => performance.now());\n\t\tthis.idleTimeoutMs = Math.max(1, options.idleTimeoutMs ?? DEFAULT_SKILL_IDLE_TIMEOUT_MS);\n\t\tthis.getMaxBodyBytes = options.getMaxBodyBytes ?? (() => MAX_ACTIVE_SKILL_BODY_BYTES);\n\t\tthis.onSkillUsed = options.onSkillUsed;\n\t}\n\n\tsearch(rawQuery: string): SkillSearchResult {\n\t\tconst query = rawQuery.trim().toLowerCase();\n\t\tconst tokens = queryTokens(query);\n\t\tif (!query || tokens.length === 0) return { candidates: [] };\n\t\tconst candidates = this.getSkills()\n\t\t\t.filter((skill) => !skill.disableModelInvocation)\n\t\t\t.map((skill) => ({ skill, score: searchScore(skill, query, tokens) }))\n\t\t\t.filter((entry) => entry.score > 0)\n\t\t\t.sort((left, right) => right.score - left.score || left.skill.name.localeCompare(right.skill.name))\n\t\t\t.slice(0, MAX_SEARCH_RESULTS)\n\t\t\t.map(({ skill }) => ({ name: skill.name, description: compactDescription(skill.description) }));\n\t\treturn { candidates };\n\t}\n\n\tload(name: string, requester: SkillVaultRequester): SkillLoadResult {\n\t\tconst now = this.now();\n\t\tthis.reconcile(now);\n\t\tconst skill = this.getSkills().find(\n\t\t\t(candidate) => candidate.name === name && (requester === \"user\" || !candidate.disableModelInvocation),\n\t\t);\n\t\tif (!skill) {\n\t\t\treturn { ok: false, reason: \"not_found\", message: `No eligible skill named ${JSON.stringify(name)}.` };\n\t\t}\n\t\tconst maxBodyBytes = this.resolveMaxBodyBytes();\n\t\tlet before: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tbefore = statSync(skill.filePath);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t\tlet raw: string;\n\t\ttry {\n\t\t\traw = readBoundedTextFileSync(\n\t\t\t\tskill.filePath,\n\t\t\t\tmaxBodyBytes + MAX_SKILL_FRONTMATTER_BYTES,\n\t\t\t\t`Skill ${JSON.stringify(skill.name)}`,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn message.includes(\"exceeds its byte limit\")\n\t\t\t\t? {\n\t\t\t\t\t\tok: false,\n\t\t\t\t\t\treason: \"body_too_large\",\n\t\t\t\t\t\tmessage: `Skill body exceeds ${maxBodyBytes} bytes; not truncated.`,\n\t\t\t\t\t}\n\t\t\t\t: { ok: false, reason: \"read_failed\", message };\n\t\t}\n\t\tconst parsed = parseFrontmatter<SkillFrontmatter>(raw);\n\t\tconst currentName = parsed.frontmatter.name ?? skill.name;\n\t\tconst body = stripResourceProfileBlocks(parsed.body).trim();\n\t\tif (currentName !== skill.name || !parsed.frontmatter.description || !body) {\n\t\t\treturn { ok: false, reason: \"invalid_body\", message: \"Skill metadata changed or its body is empty.\" };\n\t\t}\n\t\tconst bodyBytes = Buffer.byteLength(body, \"utf8\");\n\t\tif (bodyBytes > maxBodyBytes) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\treason: \"body_too_large\",\n\t\t\t\tmessage: `Skill body exceeds ${maxBodyBytes} bytes; not truncated.`,\n\t\t\t};\n\t\t}\n\t\tlet file: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tfile = statSync(skill.filePath);\n\t\t} catch (error) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: error instanceof Error ? error.message : String(error) };\n\t\t}\n\t\tif (!sameFileVersion(before, file)) {\n\t\t\treturn { ok: false, reason: \"read_failed\", message: \"Skill changed while it was being loaded.\" };\n\t\t}\n\t\tconst next = new Map(this.slots);\n\t\tnext.set(skill.name, {\n\t\t\tstate: \"loaded_pending\",\n\t\t\tskill,\n\t\t\tbodyBytes,\n\t\t\tsystemPromptSection: activeSkillContext(skill, body),\n\t\t\trequester,\n\t\t\tloadedAtMs: now,\n\t\t\tfileDevice: file.dev,\n\t\t\tfileInode: file.ino,\n\t\t\tfileSize: file.size,\n\t\t\tfileModifiedAtMs: file.mtimeMs,\n\t\t\tfileChangedAtMs: file.ctimeMs,\n\t\t});\n\t\tconst evicted: string[] = [];\n\t\twhile (next.size > MAX_LOADED_SKILLS || aggregateBodyBytes(next) > maxBodyBytes) {\n\t\t\tconst victim = leastRecentlyUsedName(next, skill.name);\n\t\t\tif (!victim) break;\n\t\t\tnext.delete(victim);\n\t\t\tevicted.push(victim);\n\t\t}\n\t\tthis.replaceState(next);\n\t\treturn {\n\t\t\tok: true,\n\t\t\tstate: \"loaded_pending\",\n\t\t\tname: skill.name,\n\t\t\tbaseDir: skill.baseDir,\n\t\t\t...(evicted.length > 0 ? { evicted } : {}),\n\t\t};\n\t}\n\n\tunload(name?: string): { ok: true; unloaded: string[] } {\n\t\tthis.reconcile(this.now());\n\t\tconst target = name?.trim();\n\t\tconst unloaded = !target ? [...this.slots.keys()] : this.slots.has(target) ? [target] : [];\n\t\tif (unloaded.length > 0) {\n\t\t\tconst next = new Map(this.slots);\n\t\t\tfor (const slotName of unloaded) next.delete(slotName);\n\t\t\tthis.replaceState(next, \"explicit\");\n\t\t}\n\t\treturn { ok: true, unloaded };\n\t}\n\n\tstatus(): SkillVaultStatus {\n\t\tconst now = this.now();\n\t\tthis.reconcile(now);\n\t\tconst slots = [...this.slots.values()].map((slot) => this.slotStatus(slot, now));\n\t\treturn {\n\t\t\tidleTimeoutMs: this.idleTimeoutMs,\n\t\t\tslots,\n\t\t\t...(slots.length === 0 && this.unloadReason ? { reason: this.unloadReason } : {}),\n\t\t};\n\t}\n\n\tcommitSystemPromptSection(): string | undefined {\n\t\tconst now = this.now();\n\t\tthis.reconcile(now);\n\t\tif (this.slots.size === 0) return undefined;\n\t\tconst sections: string[] = [];\n\t\tfor (const [name, slot] of this.slots) {\n\t\t\tsections.push(slot.systemPromptSection);\n\t\t\tconst firstUse = slot.state === \"loaded_pending\";\n\t\t\tconst useCount = firstUse ? 1 : slot.useCount + 1;\n\t\t\tthis.slots.set(name, { ...slot, state: \"active\", lastUsedAtMs: now, useCount });\n\t\t\tif (firstUse) {\n\t\t\t\ttry {\n\t\t\t\t\tthis.onSkillUsed?.(slot.skill, now);\n\t\t\t\t} catch {\n\t\t\t\t\t// Usage telemetry must never block skill application.\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn sections.join(\"\\n\\n\");\n\t}\n\n\t/** Model the next request's transient system cost without treating a diagnostic read as use. */\n\tpreviewSystemPromptSection(): string | undefined {\n\t\tthis.reconcile(this.now());\n\t\tif (this.slots.size === 0) return undefined;\n\t\treturn [...this.slots.values()].map((slot) => slot.systemPromptSection).join(\"\\n\\n\");\n\t}\n\n\t/** Compose the exact provider system prompt for read-only diagnostics. */\n\tpreviewRequestSystemPrompt(base: string | undefined): string | undefined {\n\t\treturn composeRequestSystemPrompt(base, this.previewSystemPromptSection());\n\t}\n\n\t/** Monotonic identity for provider-visible skill projection changes. */\n\tgetContextRevision(): number {\n\t\tthis.reconcile(this.now());\n\t\treturn this.contextRevision;\n\t}\n\n\t/** Record host-observed work derived from an active skill, independent of agent cooperation. */\n\tnoteActivity(): void {\n\t\tconst now = this.now();\n\t\tfor (const [name, slot] of this.slots) {\n\t\t\tif (slot.state === \"active\") {\n\t\t\t\tthis.slots.set(name, { ...slot, lastUsedAtMs: now });\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate slotStatus(slot: SkillSlotState, now: number): SkillSlotStatus {\n\t\tif (slot.state === \"loaded_pending\") {\n\t\t\treturn { state: \"loaded_pending\", name: slot.skill.name, loadedAtMs: slot.loadedAtMs };\n\t\t}\n\t\tconst idleForMs = Math.max(0, now - slot.lastUsedAtMs);\n\t\treturn {\n\t\t\tstate: \"active\",\n\t\t\tname: slot.skill.name,\n\t\t\tloadedAtMs: slot.loadedAtMs,\n\t\t\tlastUsedAtMs: slot.lastUsedAtMs,\n\t\t\tidleForMs,\n\t\t\texpiresInMs: Math.max(0, this.idleTimeoutMs - idleForMs),\n\t\t\tuseCount: slot.useCount,\n\t\t};\n\t}\n\n\tprivate reconcile(now: number): void {\n\t\tif (this.slots.size === 0) return;\n\t\tconst maxBodyBytes = this.resolveMaxBodyBytes();\n\t\tconst skills = this.getSkills();\n\t\tconst next = new Map(this.slots);\n\t\tlet reason: SkillVaultUnloadReason | undefined;\n\t\tfor (const [name, slot] of this.slots) {\n\t\t\tconst slotReason = this.reconcileSlot(slot, skills, maxBodyBytes, now);\n\t\t\tif (slotReason !== undefined) {\n\t\t\t\tnext.delete(name);\n\t\t\t\treason = slotReason;\n\t\t\t}\n\t\t}\n\t\twhile (aggregateBodyBytes(next) > maxBodyBytes) {\n\t\t\tconst victim = leastRecentlyUsedName(next);\n\t\t\tif (!victim) break;\n\t\t\tnext.delete(victim);\n\t\t\treason = \"budget_exceeded\";\n\t\t}\n\t\tif (next.size !== this.slots.size) {\n\t\t\tthis.replaceState(next, reason);\n\t\t}\n\t}\n\n\tprivate reconcileSlot(\n\t\tslot: SkillSlotState,\n\t\tskills: readonly Skill[],\n\t\tmaxBodyBytes: number,\n\t\tnow: number,\n\t): SkillVaultUnloadReason | undefined {\n\t\tif (slot.bodyBytes > maxBodyBytes) return \"budget_exceeded\";\n\t\tconst currentSkill = skills.find(\n\t\t\t(skill) =>\n\t\t\t\tskill.name === slot.skill.name &&\n\t\t\t\tskill.filePath === slot.skill.filePath &&\n\t\t\t\t(slot.requester === \"user\" || !skill.disableModelInvocation),\n\t\t);\n\t\tif (!currentSkill) return \"resource_unavailable\";\n\t\ttry {\n\t\t\tconst file = statSync(slot.skill.filePath);\n\t\t\tif (\n\t\t\t\tfile.dev !== slot.fileDevice ||\n\t\t\t\tfile.ino !== slot.fileInode ||\n\t\t\t\tfile.size !== slot.fileSize ||\n\t\t\t\tfile.mtimeMs !== slot.fileModifiedAtMs ||\n\t\t\t\tfile.ctimeMs !== slot.fileChangedAtMs\n\t\t\t) {\n\t\t\t\treturn \"resource_unavailable\";\n\t\t\t}\n\t\t} catch {\n\t\t\treturn \"resource_unavailable\";\n\t\t}\n\t\tif (now - slotLastUsedAtMs(slot) >= this.idleTimeoutMs) return \"idle_expired\";\n\t\treturn undefined;\n\t}\n\n\tprivate replaceState(slots: Map<string, SkillSlotState>, unloadReason?: SkillVaultUnloadReason): void {\n\t\tthis.slots = slots;\n\t\tif (unloadReason !== undefined) this.unloadReason = unloadReason;\n\t\tthis.contextRevision++;\n\t}\n\n\tprivate resolveMaxBodyBytes(): number {\n\t\tconst configured = this.getMaxBodyBytes();\n\t\tif (!Number.isFinite(configured)) return 1;\n\t\treturn Math.min(MAX_ACTIVE_SKILL_BODY_BYTES, Math.max(1, Math.floor(configured)));\n\t}\n}\n"]}
|
|
@@ -41,7 +41,8 @@ export interface BashOperations {
|
|
|
41
41
|
* @param command The command to execute
|
|
42
42
|
* @param cwd Working directory
|
|
43
43
|
* @param options Execution options
|
|
44
|
-
* @returns Promise resolving to exit code (null if killed)
|
|
44
|
+
* @returns Promise resolving to exit code (null if killed) plus, when the backend tracks it,
|
|
45
|
+
* the shell-reported working directory after the command ran
|
|
45
46
|
*/
|
|
46
47
|
exec: (command: string, cwd: string, options: {
|
|
47
48
|
onData: (data: Buffer) => void;
|
|
@@ -50,6 +51,7 @@ export interface BashOperations {
|
|
|
50
51
|
env?: NodeJS.ProcessEnv;
|
|
51
52
|
}) => Promise<{
|
|
52
53
|
exitCode: number | null;
|
|
54
|
+
cwd?: string;
|
|
53
55
|
}>;
|
|
54
56
|
}
|
|
55
57
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"AAIA,OAAO,EAIN,KAAK,gBAAgB,EACrB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAIjE,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAc5C,OAAO,KAAK,EAAE,cAAc,EAA2B,MAAM,wBAAwB,CAAC;AACtF,OAAO,EACN,KAAK,4BAA4B,EAIjC,MAAM,4BAA4B,CAAC;AAYpC,OAAO,EAGN,KAAK,4BAA4B,EACjC,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAsC,KAAK,yBAAyB,EAAE,MAAM,2BAA2B,CAAC;AAK/G,qGAAqG;AACrG,eAAO,MAAM,+BAA+B,MAAM,CAAC;AACnD,eAAO,MAAM,2BAA2B,OAAO,CAAC;AAKhD,kGAAkG;AAClG,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAExE;AAED,mGAAmG;AACnG,wBAAgB,2BAA2B,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAExE;AAED,wBAAgB,4BAA4B,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAKhF;AAED,QAAA,MAAM,UAAU;;;;EAcd,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,OAAO,UAAU,CAAC,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC/B,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,YAAY,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,gBAAgB,CAAC,EAAE,4BAA4B,CAAC;CAChD;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC9B
|
|
1
|
+
{"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../../src/core/tools/bash.ts"],"names":[],"mappings":"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"}
|