@dbx-tools/appkit-mastra 0.9.93 → 0.9.95
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 +85 -40
- package/index.ts +4 -10
- package/lib/index.d.ts +4 -10
- package/lib/index.js +4 -8
- package/lib/src/agents.js +11 -23
- package/lib/src/chat.js +20 -1
- package/lib/src/config.d.ts +9 -11
- package/lib/src/config.js +7 -7
- package/lib/src/filesystems.d.ts +20 -2
- package/lib/src/filesystems.js +29 -2
- package/lib/src/plugin.js +3 -2
- package/lib/src/remote-skills.d.ts +3 -4
- package/lib/src/remote-skills.js +5 -14
- package/lib/src/server.d.ts +7 -0
- package/lib/src/server.js +33 -2
- package/lib/src/skill-paths.d.ts +8 -4
- package/lib/src/skill-paths.js +12 -6
- package/lib/src/workspaces.d.ts +39 -33
- package/lib/src/workspaces.js +208 -168
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +14 -30
- package/src/agents.ts +11 -24
- package/src/chat.ts +24 -0
- package/src/config.ts +15 -17
- package/src/filesystems.ts +43 -0
- package/src/plugin.ts +2 -0
- package/src/remote-skills.ts +5 -15
- package/src/server.ts +33 -1
- package/src/skill-paths.ts +13 -5
- package/src/workspaces.ts +285 -210
- package/lib/src/skill-cache.d.ts +0 -94
- package/lib/src/skill-cache.js +0 -251
- package/lib/src/skill-search.d.ts +0 -30
- package/lib/src/skill-search.js +0 -171
- package/src/skill-cache.ts +0 -347
- package/src/skill-search.ts +0 -203
package/lib/src/skill-cache.d.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User-scoped workspace skill catalogues cached as one semantic record.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import type { RequestContext } from "@mastra/core/request-context";
|
|
7
|
-
import { z } from "zod";
|
|
8
|
-
declare const SkillCatalogueEntrySchema: z.ZodObject<{
|
|
9
|
-
name: z.ZodString;
|
|
10
|
-
description: z.ZodString;
|
|
11
|
-
instructions: z.ZodString;
|
|
12
|
-
sourceId: z.ZodString;
|
|
13
|
-
sourcePath: z.ZodString;
|
|
14
|
-
signature: z.ZodOptional<z.ZodString>;
|
|
15
|
-
}, z.core.$strip>;
|
|
16
|
-
declare const SkillCatalogueSchema: z.ZodObject<{
|
|
17
|
-
version: z.ZodLiteral<1>;
|
|
18
|
-
generatedAt: z.ZodString;
|
|
19
|
-
roots: z.ZodArray<z.ZodString>;
|
|
20
|
-
skills: z.ZodArray<z.ZodObject<{
|
|
21
|
-
name: z.ZodString;
|
|
22
|
-
description: z.ZodString;
|
|
23
|
-
instructions: z.ZodString;
|
|
24
|
-
sourceId: z.ZodString;
|
|
25
|
-
sourcePath: z.ZodString;
|
|
26
|
-
signature: z.ZodOptional<z.ZodString>;
|
|
27
|
-
}, z.core.$strip>>;
|
|
28
|
-
}, z.core.$strip>;
|
|
29
|
-
/** Parsed skill retained in a materialized workspace catalogue. */
|
|
30
|
-
export type SkillCatalogueEntry = z.infer<typeof SkillCatalogueEntrySchema>;
|
|
31
|
-
/** Versioned persisted skill catalogue. */
|
|
32
|
-
export type SkillCatalogue = z.infer<typeof SkillCatalogueSchema>;
|
|
33
|
-
/** One ordered filesystem root contributing skills to a catalogue. */
|
|
34
|
-
export interface SkillCatalogueSource {
|
|
35
|
-
/** Stable source identity including its mount precedence. */
|
|
36
|
-
id: string;
|
|
37
|
-
/** List one source-relative directory with provider metadata when available. */
|
|
38
|
-
list(path: string): Promise<SkillCatalogueFileEntry[]>;
|
|
39
|
-
/** Read one source-relative file fresh from its owning filesystem. */
|
|
40
|
-
read(path: string): Promise<string>;
|
|
41
|
-
}
|
|
42
|
-
/** Minimal directory metadata used to compare one catalogue refresh. */
|
|
43
|
-
export interface SkillCatalogueFileEntry {
|
|
44
|
-
metadata?: Readonly<Record<string, unknown>>;
|
|
45
|
-
name: string;
|
|
46
|
-
size?: number;
|
|
47
|
-
type: "directory" | "file";
|
|
48
|
-
}
|
|
49
|
-
/** Options for one user-scoped workspace skill catalogue. */
|
|
50
|
-
export interface WorkspaceSkillCatalogueOptions {
|
|
51
|
-
host: string;
|
|
52
|
-
sources: readonly SkillCatalogueSource[];
|
|
53
|
-
ttlMs?: number;
|
|
54
|
-
userKey: string;
|
|
55
|
-
}
|
|
56
|
-
/** Request state used to resolve one user-scoped catalogue owner. */
|
|
57
|
-
export interface SkillCatalogueResolveContext {
|
|
58
|
-
abortSignal?: AbortSignal;
|
|
59
|
-
requestContext?: RequestContext;
|
|
60
|
-
}
|
|
61
|
-
/** Resolve one request's complete skill catalogue. */
|
|
62
|
-
export type SkillCatalogueResolver = (context: SkillCatalogueResolveContext) => Promise<WorkspaceSkillCatalogue>;
|
|
63
|
-
/** Default lifetime for one complete workspace skill catalogue. */
|
|
64
|
-
export declare const DEFAULT_WORKSPACE_SKILL_CACHE_TTL_MS: number;
|
|
65
|
-
/** Materialized catalogue with one AppKit cache record and fresh auxiliary reads. */
|
|
66
|
-
export declare class WorkspaceSkillCatalogue {
|
|
67
|
-
private readonly options;
|
|
68
|
-
readonly cacheKey: string;
|
|
69
|
-
readonly host: string;
|
|
70
|
-
readonly userKey: string;
|
|
71
|
-
private lastValid?;
|
|
72
|
-
private readonly ttlMs;
|
|
73
|
-
private sources;
|
|
74
|
-
constructor(options: WorkspaceSkillCatalogueOptions);
|
|
75
|
-
/** Rebind refreshes and lazy reads to the current request's filesystem clients. */
|
|
76
|
-
bind(sources: readonly SkillCatalogueSource[]): void;
|
|
77
|
-
/** Return the cached catalogue, refreshing all roots once on cache miss. */
|
|
78
|
-
get(signal?: AbortSignal): Promise<SkillCatalogue>;
|
|
79
|
-
/** Expire this complete catalogue without touching unrelated cache entries. */
|
|
80
|
-
invalidate(): Promise<void>;
|
|
81
|
-
/** Read one selected skill's auxiliary file directly from its current source. */
|
|
82
|
-
readSkillFile(skillName: string, inputPath: string, signal?: AbortSignal): Promise<string>;
|
|
83
|
-
private refresh;
|
|
84
|
-
private rootKey;
|
|
85
|
-
private persistentKey;
|
|
86
|
-
}
|
|
87
|
-
/** Return one stable catalogue owner for a user, host, and ordered root set. */
|
|
88
|
-
export declare function workspaceSkillCatalogue(options: WorkspaceSkillCatalogueOptions): WorkspaceSkillCatalogue;
|
|
89
|
-
/** Invalidate matching complete catalogues and retain their stable owners. */
|
|
90
|
-
export declare function clearWorkspaceSkillCache(options: {
|
|
91
|
-
host: string;
|
|
92
|
-
userKey?: string;
|
|
93
|
-
}): Promise<void>;
|
|
94
|
-
export {};
|
package/lib/src/skill-cache.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* User-scoped workspace skill catalogues cached as one semantic record.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import { CacheManager } from "@databricks/appkit";
|
|
7
|
-
import { errorUtils, log, object } from "@dbx-tools/shared-core";
|
|
8
|
-
import { posixPath } from "@dbx-tools/shared-fs";
|
|
9
|
-
import { LRUCache } from "lru-cache";
|
|
10
|
-
import { parse as parseYaml } from "yaml";
|
|
11
|
-
import { z } from "zod";
|
|
12
|
-
const CACHE_NAMESPACE = "mastra:workspace-skill-catalogue";
|
|
13
|
-
const CATALOGUE_VERSION = 1;
|
|
14
|
-
const MAX_SCOPED_CATALOGUES = 256;
|
|
15
|
-
const logger = log.logger("mastra/skill-cache");
|
|
16
|
-
const SkillCatalogueEntrySchema = z
|
|
17
|
-
.object({
|
|
18
|
-
name: z.string().describe("Unique skill name from SKILL.md frontmatter."),
|
|
19
|
-
description: z.string().describe("Skill description from SKILL.md frontmatter."),
|
|
20
|
-
instructions: z.string().describe("Markdown instructions below SKILL.md frontmatter."),
|
|
21
|
-
sourceId: z.string().describe("Identity of the mounted source that owns this skill."),
|
|
22
|
-
sourcePath: z.string().describe("Path to SKILL.md relative to its source root."),
|
|
23
|
-
signature: z
|
|
24
|
-
.string()
|
|
25
|
-
.optional()
|
|
26
|
-
.describe("Stable metadata signature used to retain unchanged instructions."),
|
|
27
|
-
})
|
|
28
|
-
.describe("One parsed skill in a materialized workspace catalogue.");
|
|
29
|
-
const SkillCatalogueSchema = z
|
|
30
|
-
.object({
|
|
31
|
-
version: z.literal(CATALOGUE_VERSION).describe("Persisted catalogue schema version."),
|
|
32
|
-
generatedAt: z.string().datetime().describe("Time the catalogue was last refreshed."),
|
|
33
|
-
roots: z.array(z.string()).describe("Ordered source identities included in the catalogue."),
|
|
34
|
-
skills: z
|
|
35
|
-
.array(SkillCatalogueEntrySchema)
|
|
36
|
-
.describe("Parsed skills after ordered duplicate-name precedence is applied."),
|
|
37
|
-
})
|
|
38
|
-
.describe("One user-scoped materialized workspace skill catalogue.");
|
|
39
|
-
const scopedCatalogues = new LRUCache({
|
|
40
|
-
max: MAX_SCOPED_CATALOGUES,
|
|
41
|
-
});
|
|
42
|
-
/** Default lifetime for one complete workspace skill catalogue. */
|
|
43
|
-
export const DEFAULT_WORKSPACE_SKILL_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
44
|
-
/** Materialized catalogue with one AppKit cache record and fresh auxiliary reads. */
|
|
45
|
-
export class WorkspaceSkillCatalogue {
|
|
46
|
-
options;
|
|
47
|
-
cacheKey;
|
|
48
|
-
host;
|
|
49
|
-
userKey;
|
|
50
|
-
lastValid;
|
|
51
|
-
ttlMs;
|
|
52
|
-
sources;
|
|
53
|
-
constructor(options) {
|
|
54
|
-
this.options = options;
|
|
55
|
-
this.host = options.host;
|
|
56
|
-
this.userKey = options.userKey;
|
|
57
|
-
this.sources = options.sources;
|
|
58
|
-
this.ttlMs = positiveTtl(options.ttlMs);
|
|
59
|
-
this.cacheKey = object.toStableKey({
|
|
60
|
-
host: options.host,
|
|
61
|
-
roots: options.sources.map(({ id }) => id),
|
|
62
|
-
userKey: options.userKey,
|
|
63
|
-
version: CATALOGUE_VERSION,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
/** Rebind refreshes and lazy reads to the current request's filesystem clients. */
|
|
67
|
-
bind(sources) {
|
|
68
|
-
const identities = sources.map(({ id }) => id);
|
|
69
|
-
if (object.toStableKey(identities) !== object.toStableKey(this.sources.map(({ id }) => id))) {
|
|
70
|
-
throw new Error("Cannot rebind a skill catalogue to a different ordered root set");
|
|
71
|
-
}
|
|
72
|
-
this.sources = sources;
|
|
73
|
-
}
|
|
74
|
-
/** Return the cached catalogue, refreshing all roots once on cache miss. */
|
|
75
|
-
async get(signal) {
|
|
76
|
-
const cache = CacheManager.getInstanceSync();
|
|
77
|
-
try {
|
|
78
|
-
const catalogue = SkillCatalogueSchema.parse(await cache.getOrExecute([CACHE_NAMESPACE, CATALOGUE_VERSION, this.options.host, this.rootKey()], () => this.refresh(), this.options.userKey, {
|
|
79
|
-
ttl: Math.max(1, Math.ceil(this.ttlMs / 1000)),
|
|
80
|
-
callerSignal: signal,
|
|
81
|
-
}));
|
|
82
|
-
this.lastValid = catalogue;
|
|
83
|
-
return catalogue;
|
|
84
|
-
}
|
|
85
|
-
catch (error) {
|
|
86
|
-
if (!this.lastValid)
|
|
87
|
-
throw error;
|
|
88
|
-
logger.warn("skill catalogue refresh failed; retaining last valid catalogue", {
|
|
89
|
-
error: errorUtils.errorMessage(error),
|
|
90
|
-
roots: this.sources.map(({ id }) => id),
|
|
91
|
-
});
|
|
92
|
-
return this.lastValid;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
/** Expire this complete catalogue without touching unrelated cache entries. */
|
|
96
|
-
async invalidate() {
|
|
97
|
-
const cache = CacheManager.getInstanceSync();
|
|
98
|
-
await cache.delete(this.persistentKey(cache));
|
|
99
|
-
}
|
|
100
|
-
/** Read one selected skill's auxiliary file directly from its current source. */
|
|
101
|
-
async readSkillFile(skillName, inputPath, signal) {
|
|
102
|
-
signal?.throwIfAborted();
|
|
103
|
-
const catalogue = await this.get(signal);
|
|
104
|
-
const skill = catalogue.skills.find(({ name }) => name === skillName);
|
|
105
|
-
if (!skill)
|
|
106
|
-
throw new Error(`Unknown skill: ${skillName}`);
|
|
107
|
-
const normalized = posixPath.normalize(inputPath);
|
|
108
|
-
if (!normalized.ok ||
|
|
109
|
-
normalized.path === "/" ||
|
|
110
|
-
inputPath.split("/").some((segment) => segment === "..")) {
|
|
111
|
-
throw new Error(`Invalid skill file path: ${inputPath}`);
|
|
112
|
-
}
|
|
113
|
-
const source = this.sources.find(({ id }) => id === skill.sourceId);
|
|
114
|
-
if (!source)
|
|
115
|
-
throw new Error(`Skill source is no longer mounted: ${skill.sourceId}`);
|
|
116
|
-
const parent = skill.sourcePath.split("/").slice(0, -1).join("/");
|
|
117
|
-
const path = [parent, normalized.path.replace(/^\/+/, "")].filter(Boolean).join("/");
|
|
118
|
-
return source.read(path);
|
|
119
|
-
}
|
|
120
|
-
async refresh() {
|
|
121
|
-
const previous = new Map(this.lastValid?.skills.map((skill) => [`${skill.sourceId}\0${skill.sourcePath}`, skill]) ?? []);
|
|
122
|
-
const selected = new Map();
|
|
123
|
-
for (const source of this.sources) {
|
|
124
|
-
for (const candidate of await discoverSkillFiles(source)) {
|
|
125
|
-
const prior = previous.get(`${source.id}\0${candidate.path}`);
|
|
126
|
-
const signature = fileSignature(candidate.entry);
|
|
127
|
-
let parsed;
|
|
128
|
-
if (signature && prior?.signature === signature) {
|
|
129
|
-
parsed = prior;
|
|
130
|
-
}
|
|
131
|
-
else {
|
|
132
|
-
parsed = parseSkill(await source.read(candidate.path), candidate.path);
|
|
133
|
-
}
|
|
134
|
-
if (!parsed || selected.has(parsed.name))
|
|
135
|
-
continue;
|
|
136
|
-
selected.set(parsed.name, {
|
|
137
|
-
...parsed,
|
|
138
|
-
sourceId: source.id,
|
|
139
|
-
sourcePath: candidate.path,
|
|
140
|
-
...(signature ? { signature } : {}),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return SkillCatalogueSchema.parse({
|
|
145
|
-
version: CATALOGUE_VERSION,
|
|
146
|
-
generatedAt: new Date().toISOString(),
|
|
147
|
-
roots: this.sources.map(({ id }) => id),
|
|
148
|
-
skills: [...selected.values()],
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
rootKey() {
|
|
152
|
-
return object.toStableKey(this.sources.map(({ id }) => id));
|
|
153
|
-
}
|
|
154
|
-
persistentKey(cache) {
|
|
155
|
-
return cache.generateKey([CACHE_NAMESPACE, CATALOGUE_VERSION, this.options.host, this.rootKey()], this.options.userKey);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/** Return one stable catalogue owner for a user, host, and ordered root set. */
|
|
159
|
-
export function workspaceSkillCatalogue(options) {
|
|
160
|
-
const key = object.toStableKey({
|
|
161
|
-
host: options.host,
|
|
162
|
-
roots: options.sources.map(({ id }) => id),
|
|
163
|
-
userKey: options.userKey,
|
|
164
|
-
});
|
|
165
|
-
const existing = scopedCatalogues.get(key);
|
|
166
|
-
if (existing) {
|
|
167
|
-
existing.bind(options.sources);
|
|
168
|
-
return existing;
|
|
169
|
-
}
|
|
170
|
-
const catalogue = new WorkspaceSkillCatalogue(options);
|
|
171
|
-
scopedCatalogues.set(key, catalogue);
|
|
172
|
-
return catalogue;
|
|
173
|
-
}
|
|
174
|
-
/** Invalidate matching complete catalogues and retain their stable owners. */
|
|
175
|
-
export async function clearWorkspaceSkillCache(options) {
|
|
176
|
-
const matches = [...scopedCatalogues.values()].filter((catalogue) => catalogue.host === options.host &&
|
|
177
|
-
(options.userKey === undefined || catalogue.userKey === options.userKey));
|
|
178
|
-
await Promise.all(matches.map((catalogue) => catalogue.invalidate()));
|
|
179
|
-
}
|
|
180
|
-
async function discoverSkillFiles(source) {
|
|
181
|
-
let rootEntries;
|
|
182
|
-
try {
|
|
183
|
-
rootEntries = await source.list(".");
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
if (errorUtils.errorContext(error).notAccessible)
|
|
187
|
-
return [];
|
|
188
|
-
throw error;
|
|
189
|
-
}
|
|
190
|
-
const candidates = [];
|
|
191
|
-
const rootSkill = rootEntries.find(({ name, type }) => name.toLowerCase() === "skill.md" && type === "file");
|
|
192
|
-
if (rootSkill)
|
|
193
|
-
candidates.push({ entry: rootSkill, path: rootSkill.name });
|
|
194
|
-
await Promise.all(rootEntries
|
|
195
|
-
.filter(({ type }) => type === "directory")
|
|
196
|
-
.map(async (directory) => {
|
|
197
|
-
const entries = await source.list(directory.name);
|
|
198
|
-
const skill = entries.find(({ name, type }) => name.toLowerCase() === "skill.md" && type === "file");
|
|
199
|
-
if (skill)
|
|
200
|
-
candidates.push({ entry: skill, path: posixPath.join(directory.name, skill.name) });
|
|
201
|
-
}));
|
|
202
|
-
return candidates.sort((left, right) => left.path.localeCompare(right.path));
|
|
203
|
-
}
|
|
204
|
-
function parseSkill(source, path) {
|
|
205
|
-
const match = /^---\s*\r?\n([\s\S]*?)\r?\n---\s*(?:\r?\n|$)([\s\S]*)$/.exec(source);
|
|
206
|
-
if (!match) {
|
|
207
|
-
logger.warn("skill skipped (missing YAML frontmatter)", { path });
|
|
208
|
-
return undefined;
|
|
209
|
-
}
|
|
210
|
-
const metadata = parseYaml(match[1]);
|
|
211
|
-
if (!object.isRecord(metadata)) {
|
|
212
|
-
logger.warn("skill skipped (invalid YAML frontmatter)", { path });
|
|
213
|
-
return undefined;
|
|
214
|
-
}
|
|
215
|
-
const parsed = z
|
|
216
|
-
.object({
|
|
217
|
-
name: z.string().trim().min(1),
|
|
218
|
-
description: z.string().trim().min(1),
|
|
219
|
-
})
|
|
220
|
-
.safeParse(metadata);
|
|
221
|
-
if (!parsed.success) {
|
|
222
|
-
logger.warn("skill skipped (invalid metadata)", {
|
|
223
|
-
path,
|
|
224
|
-
error: parsed.error.message,
|
|
225
|
-
});
|
|
226
|
-
return undefined;
|
|
227
|
-
}
|
|
228
|
-
return {
|
|
229
|
-
name: parsed.data.name,
|
|
230
|
-
description: parsed.data.description,
|
|
231
|
-
instructions: match[2].trim(),
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
function fileSignature(entry) {
|
|
235
|
-
const metadata = object.isRecord(entry.metadata) ? entry.metadata : {};
|
|
236
|
-
const values = {
|
|
237
|
-
modifiedAt: metadata.modifiedAt,
|
|
238
|
-
objectId: metadata.objectId,
|
|
239
|
-
size: entry.size,
|
|
240
|
-
};
|
|
241
|
-
return Object.values(values).some((value) => value !== undefined)
|
|
242
|
-
? object.toStableKey(values)
|
|
243
|
-
: undefined;
|
|
244
|
-
}
|
|
245
|
-
function positiveTtl(value = DEFAULT_WORKSPACE_SKILL_CACHE_TTL_MS) {
|
|
246
|
-
if (!Number.isFinite(value) || value <= 0) {
|
|
247
|
-
throw new RangeError("Workspace skill catalogue ttlMs must be a positive finite number");
|
|
248
|
-
}
|
|
249
|
-
return value;
|
|
250
|
-
}
|
|
251
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tpbGwtY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2tpbGwtY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7R0FJRztBQUVILE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUNqRSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFFakQsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyQyxPQUFPLEVBQUUsS0FBSyxJQUFJLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMxQyxPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sS0FBSyxDQUFDO0FBRXhCLE1BQU0sZUFBZSxHQUFHLGtDQUFrQyxDQUFDO0FBQzNELE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0FBQzVCLE1BQU0scUJBQXFCLEdBQUcsR0FBRyxDQUFDO0FBQ2xDLE1BQU0sTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLENBQUMsb0JBQW9CLENBQUMsQ0FBQztBQUVoRCxNQUFNLHlCQUF5QixHQUFHLENBQUM7S0FDaEMsTUFBTSxDQUFDO0lBQ04sSUFBSSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsOENBQThDLENBQUM7SUFDekUsV0FBVyxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsOENBQThDLENBQUM7SUFDaEYsWUFBWSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsbURBQW1ELENBQUM7SUFDdEYsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsc0RBQXNELENBQUM7SUFDckYsVUFBVSxFQUFFLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FB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O1FBQzNCLElBQUksRUFBRSxLQUFLLENBQUMsSUFBSTtLQUNqQixDQUFDO0lBQ0YsT0FBTyxNQUFNLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxLQUFLLFNBQVMsQ0FBQztRQUMvRCxDQUFDLENBQUMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUM7UUFDNUIsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNoQixDQUFDO0FBRUQsU0FBUyxXQUFXLENBQUMsS0FBSyxHQUFHLG9DQUFvQztJQUMvRCxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsSUFBSSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDMUMsTUFBTSxJQUFJLFVBQVUsQ0FBQyxrRUFBa0UsQ0FBQyxDQUFDO0lBQzNGLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVzZXItc2NvcGVkIHdvcmtzcGFjZSBza2lsbCBjYXRhbG9ndWVzIGNhY2hlZCBhcyBvbmUgc2VtYW50aWMgcmVjb3JkLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBDYWNoZU1hbmFnZXIgfSBmcm9tIFwiQGRhdGFicmlja3MvYXBwa2l0XCI7XG5pbXBvcnQgeyBlcnJvclV0aWxzLCBsb2csIG9iamVjdCB9IGZyb20gXCJAZGJ4LXRvb2xzL3NoYXJlZC1jb3JlXCI7XG5pbXBvcnQgeyBwb3NpeFBhdGggfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtZnNcIjtcbmltcG9ydCB0eXBlIHsgUmVxdWVzdENvbnRleHQgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3JlcXVlc3QtY29udGV4dFwiO1xuaW1wb3J0IHsgTFJVQ2FjaGUgfSBmcm9tIFwibHJ1LWNhY2hlXCI7XG5pbXBvcnQgeyBwYXJzZSBhcyBwYXJzZVlhbWwgfSBmcm9tIFwieWFtbFwiO1xuaW1wb3J0IHsgeiB9IGZyb20gXCJ6b2RcIjtcblxuY29uc3QgQ0FDSEVfTkFNRVNQQUNFID0gXCJtYXN0cmE6d29ya3NwYWNlLXNraWxsLWNhdGFsb2d1ZVwiO1xuY29uc3QgQ0FUQUxPR1VFX1ZFUlNJT04gPSAxO1xuY29uc3QgTUFYX1NDT1BFRF9DQVRBTE9HVUVTID0gMjU2O1xuY29uc3QgbG9nZ2VyID0gbG9nLmxvZ2dlcihcIm1hc3RyYS9za2lsbC1jYWNoZVwiKTtcblxuY29uc3QgU2tpbGxDYXRhbG9ndWVFbnRyeVNjaGVtYSA9IHpcbiAgLm9iamVjdCh7XG4gICAgbmFtZTogei5zdHJpbmcoKS5kZXNjcmliZShcIlVuaXF1ZSBza2lsbCBuYW1lIGZyb20gU0tJTEwubWQgZnJvbnRtYXR0ZXIuXCIpLFxuICAgIGRlc2NyaXB0aW9uOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiU2tpbGwgZGVzY3JpcHRpb24gZnJvbSBTS0lMTC5tZCBmcm9udG1hdHRlci5cIiksXG4gICAgaW5zdHJ1Y3Rpb25zOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiTWFya2Rvd24gaW5zdHJ1Y3Rpb25zIGJlbG93IFNLSUxMLm1kIGZyb250bWF0dGVyLlwiKSxcbiAgICBzb3VyY2VJZDogei5zdHJpbmcoKS5kZXNjcmliZShcIklkZW50aXR5IG9mIHRoZSBtb3VudGVkIHNvdXJjZSB0aGF0IG93bnMgdGhpcyBza2lsbC5cIiksXG4gICAgc291cmNlUGF0aDogei5zdHJpbmcoKS5kZXNjcmliZShcIlBhdGggdG8gU0tJTEwubWQgcmVsYXRpdmUgdG8gaXRzIHNvdXJjZSByb290LlwiKSxcbiAgICBzaWduYXR1cmU6IHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLm9wdGlvbmFsKClcbiAgICAgIC5kZXNjcmliZShcIlN0YWJsZSBtZXRhZGF0YSBzaWduYXR1cmUgdXNlZCB0byByZXRhaW4gdW5jaGFuZ2VkIGluc3RydWN0aW9ucy5cIiksXG4gIH0pXG4gIC5kZXNjcmliZShcIk9uZSBwYXJzZWQgc2tpbGwgaW4gYSBtYXRlcmlhbGl6ZWQgd29ya3NwYWNlIGNhdGFsb2d1ZS5cIik7XG5cbmNvbnN0IFNraWxsQ2F0YWxvZ3VlU2NoZW1hID0gelxuICAub2JqZWN0KHtcbiAgICB2ZXJzaW9uOiB6LmxpdGVyYWwoQ0FUQUxPR1VFX1ZFUlNJT04pLmRlc2NyaWJlKFwiUGVyc2lzdGVkIGNhdGFsb2d1ZSBzY2hlbWEgdmVyc2lvbi5cIiksXG4gICAgZ2VuZXJhdGVkQXQ6IHouc3RyaW5nKCkuZGF0ZXRpbWUoKS5kZXNjcmliZShcIlRpbWUgdGhlIGNhdGFsb2d1ZSB3YXMgbGFzdCByZWZyZXNoZWQuXCIpLFxuICAgIHJvb3RzOiB6LmFycmF5KHouc3RyaW5nKCkpLmRlc2NyaWJlKFwiT3JkZXJlZCBzb3VyY2UgaWRlbnRpdGllcyBpbmNsdWRlZCBpbiB0aGUgY2F0YWxvZ3VlLlwiKSxcbiAgICBza2lsbHM6IHpcbiAgICAgIC5hcnJheShTa2lsbENhdGFsb2d1ZUVudHJ5U2NoZW1hKVxuICAgICAgLmRlc2NyaWJlKFwiUGFyc2VkIHNraWxscyBhZnRlciBvcmRlcmVkIGR1cGxpY2F0ZS1uYW1lIHByZWNlZGVuY2UgaXMgYXBwbGllZC5cIiksXG4gIH0pXG4gIC5kZXNjcmliZShcIk9uZSB1c2VyLXNjb3BlZCBtYXRlcmlhbGl6ZWQgd29ya3NwYWNlIHNraWxsIGNhdGFsb2d1ZS5cIik7XG5cbi8qKiBQYXJzZWQgc2tpbGwgcmV0YWluZWQgaW4gYSBtYXRlcmlhbGl6ZWQgd29ya3NwYWNlIGNhdGFsb2d1ZS4gKi9cbmV4cG9ydCB0eXBlIFNraWxsQ2F0YWxvZ3VlRW50cnkgPSB6LmluZmVyPHR5cGVvZiBTa2lsbENhdGFsb2d1ZUVudHJ5U2NoZW1hPjtcblxuLyoqIFZlcnNpb25lZCBwZXJzaXN0ZWQgc2tpbGwgY2F0YWxvZ3VlLiAqL1xuZXhwb3J0IHR5cGUgU2tpbGxDYXRhbG9ndWUgPSB6LmluZmVyPHR5cGVvZiBTa2lsbENhdGFsb2d1ZVNjaGVtYT47XG5cbi8qKiBPbmUgb3JkZXJlZCBmaWxlc3lzdGVtIHJvb3QgY29udHJpYnV0aW5nIHNraWxscyB0byBhIGNhdGFsb2d1ZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgU2tpbGxDYXRhbG9ndWVTb3VyY2Uge1xuICAvKiogU3RhYmxlIHNvdXJjZSBpZGVudGl0eSBpbmNsdWRpbmcgaXRzIG1vdW50IHByZWNlZGVuY2UuICovXG4gIGlkOiBzdHJpbmc7XG4gIC8qKiBMaXN0IG9uZSBzb3VyY2UtcmVsYXRpdmUgZGlyZWN0b3J5IHdpdGggcHJvdmlkZXIgbWV0YWRhdGEgd2hlbiBhdmFpbGFibGUuICovXG4gIGxpc3QocGF0aDogc3RyaW5nKTogUHJvbWlzZTxTa2lsbENhdGFsb2d1ZUZpbGVFbnRyeVtdPjtcbiAgLyoqIFJlYWQgb25lIHNvdXJjZS1yZWxhdGl2ZSBmaWxlIGZyZXNoIGZyb20gaXRzIG93bmluZyBmaWxlc3lzdGVtLiAqL1xuICByZWFkKHBhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPjtcbn1cblxuLyoqIE1pbmltYWwgZGlyZWN0b3J5IG1ldGFkYXRhIHVzZWQgdG8gY29tcGFyZSBvbmUgY2F0YWxvZ3VlIHJlZnJlc2guICovXG5leHBvcnQgaW50ZXJmYWNlIFNraWxsQ2F0YWxvZ3VlRmlsZUVudHJ5IHtcbiAgbWV0YWRhdGE/OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj47XG4gIG5hbWU6IHN0cmluZztcbiAgc2l6ZT86IG51bWJlcjtcbiAgdHlwZTogXCJkaXJlY3RvcnlcIiB8IFwiZmlsZVwiO1xufVxuXG4vKiogT3B0aW9ucyBmb3Igb25lIHVzZXItc2NvcGVkIHdvcmtzcGFjZSBza2lsbCBjYXRhbG9ndWUuICovXG5leHBvcnQgaW50ZXJmYWNlIFdvcmtzcGFjZVNraWxsQ2F0YWxvZ3VlT3B0aW9ucyB7XG4gIGhvc3Q6IHN0cmluZztcbiAgc291cmNlczogcmVhZG9ubHkgU2tpbGxDYXRhbG9ndWVTb3VyY2VbXTtcbiAgdHRsTXM/OiBudW1iZXI7XG4gIHVzZXJLZXk6IHN0cmluZztcbn1cblxuLyoqIFJlcXVlc3Qgc3RhdGUgdXNlZCB0byByZXNvbHZlIG9uZSB1c2VyLXNjb3BlZCBjYXRhbG9ndWUgb3duZXIuICovXG5leHBvcnQgaW50ZXJmYWNlIFNraWxsQ2F0YWxvZ3VlUmVzb2x2ZUNvbnRleHQge1xuICBhYm9ydFNpZ25hbD86IEFib3J0U2lnbmFsO1xuICByZXF1ZXN0Q29udGV4dD86IFJlcXVlc3RDb250ZXh0O1xufVxuXG4vKiogUmVzb2x2ZSBvbmUgcmVxdWVzdCdzIGNvbXBsZXRlIHNraWxsIGNhdGFsb2d1ZS4gKi9cbmV4cG9ydCB0eXBlIFNraWxsQ2F0YWxvZ3VlUmVzb2x2ZXIgPSAoXG4gIGNvbnRleHQ6IFNraWxsQ2F0YWxvZ3VlUmVzb2x2ZUNvbnRleHQsXG4pID0+IFByb21pc2U8V29ya3NwYWNlU2tpbGxDYXRhbG9ndWU+O1xuXG5pbnRlcmZhY2UgUGFyc2VkU2tpbGwge1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICBpbnN0cnVjdGlvbnM6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xufVxuXG5jb25zdCBzY29wZWRDYXRhbG9ndWVzID0gbmV3IExSVUNhY2hlPHN0cmluZywgV29ya3NwYWNlU2tpbGxDYXRhbG9ndWU+KHtcbiAgbWF4OiBNQVhfU0NPUEVEX0NBVEFMT0dVRVMsXG59KTtcblxuLyoqIERlZmF1bHQgbGlmZXRpbWUgZm9yIG9uZSBjb21wbGV0ZSB3b3Jrc3BhY2Ugc2tpbGwgY2F0YWxvZ3VlLiAqL1xuZXhwb3J0IGNvbnN0IERFRkFVTFRfV09SS1NQQUNFX1NLSUxMX0NBQ0hFX1RUTF9NUyA9IDUgKiA2MCAqIDEwMDA7XG5cbi8qKiBNYXRlcmlhbGl6ZWQgY2F0YWxvZ3VlIHdpdGggb25lIEFwcEtpdCBjYWNoZSByZWNvcmQgYW5kIGZyZXNoIGF1eGlsaWFyeSByZWFkcy4gKi9cbmV4cG9ydCBjbGFzcyBXb3Jrc3BhY2VTa2lsbENhdGFsb2d1ZSB7XG4gIHJlYWRvbmx5IGNhY2hlS2V5OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGhvc3Q6IHN0cmluZztcbiAgcmVhZG9ubHkgdXNlcktleTogc3RyaW5nO1xuXG4gIHByaXZhdGUgbGFzdFZhbGlkPzogU2tpbGxDYXRhbG9ndWU7XG4gIHByaXZhdGUgcmVhZG9ubHkgdHRsTXM6IG51bWJlcjtcbiAgcHJpdmF0ZSBzb3VyY2VzOiByZWFkb25seSBTa2lsbENhdGFsb2d1ZVNvdXJjZVtdO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogV29ya3NwYWNlU2tpbGxDYXRhbG9ndWVPcHRpb25zKSB7XG4gICAgdGhpcy5ob3N0ID0gb3B0aW9ucy5ob3N0O1xuICAgIHRoaXMudXNlcktleSA9IG9wdGlvbnMudXNlcktleTtcbiAgICB0aGlzLnNvdXJjZXMgPSBvcHRpb25zLnNvdXJjZXM7XG4gICAgdGhpcy50dGxNcyA9IHBvc2l0aXZlVHRsKG9wdGlvbnMudHRsTXMpO1xuICAgIHRoaXMuY2FjaGVLZXkgPSBvYmplY3QudG9TdGFibGVLZXkoe1xuICAgICAgaG9zdDogb3B0aW9ucy5ob3N0LFxuICAgICAgcm9vdHM6IG9wdGlvbnMuc291cmNlcy5tYXAoKHsgaWQgfSkgPT4gaWQpLFxuICAgICAgdXNlcktleTogb3B0aW9ucy51c2VyS2V5LFxuICAgICAgdmVyc2lvbjogQ0FUQUxPR1VFX1ZFUlNJT04sXG4gICAgfSk7XG4gIH1cblxuICAvKiogUmViaW5kIHJlZnJlc2hlcyBhbmQgbGF6eSByZWFkcyB0byB0aGUgY3VycmVudCByZXF1ZXN0J3MgZmlsZXN5c3RlbSBjbGllbnRzLiAqL1xuICBiaW5kKHNvdXJjZXM6IHJlYWRvbmx5IFNraWxsQ2F0YWxvZ3VlU291cmNlW10pOiB2b2lkIHtcbiAgICBjb25zdCBpZGVudGl0aWVzID0gc291cmNlcy5tYXAoKHsgaWQgfSkgPT4gaWQpO1xuICAgIGlmIChvYmplY3QudG9TdGFibGVLZXkoaWRlbnRpdGllcykgIT09IG9iamVjdC50b1N0YWJsZUtleSh0aGlzLnNvdXJjZXMubWFwKCh7IGlkIH0pID0+IGlkKSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbm5vdCByZWJpbmQgYSBza2lsbCBjYXRhbG9ndWUgdG8gYSBkaWZmZXJlbnQgb3JkZXJlZCByb290IHNldFwiKTtcbiAgICB9XG4gICAgdGhpcy5zb3VyY2VzID0gc291cmNlcztcbiAgfVxuXG4gIC8qKiBSZXR1cm4gdGhlIGNhY2hlZCBjYXRhbG9ndWUsIHJlZnJlc2hpbmcgYWxsIHJvb3RzIG9uY2Ugb24gY2FjaGUgbWlzcy4gKi9cbiAgYXN5bmMgZ2V0KHNpZ25hbD86IEFib3J0U2lnbmFsKTogUHJvbWlzZTxTa2lsbENhdGFsb2d1ZT4ge1xuICAgIGNvbnN0IGNhY2hlID0gQ2FjaGVNYW5hZ2VyLmdldEluc3RhbmNlU3luYygpO1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBjYXRhbG9ndWUgPSBTa2lsbENhdGFsb2d1ZVNjaGVtYS5wYXJzZShcbiAgICAgICAgYXdhaXQgY2FjaGUuZ2V0T3JFeGVjdXRlKFxuICAgICAgICAgIFtDQUNIRV9OQU1FU1BBQ0UsIENBVEFMT0dVRV9WRVJTSU9OLCB0aGlzLm9wdGlvbnMuaG9zdCwgdGhpcy5yb290S2V5KCldLFxuICAgICAgICAgICgpID0+IHRoaXMucmVmcmVzaCgpLFxuICAgICAgICAgIHRoaXMub3B0aW9ucy51c2VyS2V5LFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIHR0bDogTWF0aC5tYXgoMSwgTWF0aC5jZWlsKHRoaXMudHRsTXMgLyAxMDAwKSksXG4gICAgICAgICAgICBjYWxsZXJTaWduYWw6IHNpZ25hbCxcbiAgICAgICAgICB9LFxuICAgICAgICApLFxuICAgICAgKTtcbiAgICAgIHRoaXMubGFzdFZhbGlkID0gY2F0YWxvZ3VlO1xuICAgICAgcmV0dXJuIGNhdGFsb2d1ZTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKCF0aGlzLmxhc3RWYWxpZCkgdGhyb3cgZXJyb3I7XG4gICAgICBsb2dnZXIud2FybihcInNraWxsIGNhdGFsb2d1ZSByZWZyZXNoIGZhaWxlZDsgcmV0YWluaW5nIGxhc3QgdmFsaWQgY2F0YWxvZ3VlXCIsIHtcbiAgICAgICAgZXJyb3I6IGVycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVycm9yKSxcbiAgICAgICAgcm9vdHM6IHRoaXMuc291cmNlcy5tYXAoKHsgaWQgfSkgPT4gaWQpLFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gdGhpcy5sYXN0VmFsaWQ7XG4gICAgfVxuICB9XG5cbiAgLyoqIEV4cGlyZSB0aGlzIGNvbXBsZXRlIGNhdGFsb2d1ZSB3aXRob3V0IHRvdWNoaW5nIHVucmVsYXRlZCBjYWNoZSBlbnRyaWVzLiAqL1xuICBhc3luYyBpbnZhbGlkYXRlKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGNhY2hlID0gQ2FjaGVNYW5hZ2VyLmdldEluc3RhbmNlU3luYygpO1xuICAgIGF3YWl0IGNhY2hlLmRlbGV0ZSh0aGlzLnBlcnNpc3RlbnRLZXkoY2FjaGUpKTtcbiAgfVxuXG4gIC8qKiBSZWFkIG9uZSBzZWxlY3RlZCBza2lsbCdzIGF1eGlsaWFyeSBmaWxlIGRpcmVjdGx5IGZyb20gaXRzIGN1cnJlbnQgc291cmNlLiAqL1xuICBhc3luYyByZWFkU2tpbGxGaWxlKFxuICAgIHNraWxsTmFtZTogc3RyaW5nLFxuICAgIGlucHV0UGF0aDogc3RyaW5nLFxuICAgIHNpZ25hbD86IEFib3J0U2lnbmFsLFxuICApOiBQcm9taXNlPHN0cmluZz4ge1xuICAgIHNpZ25hbD8udGhyb3dJZkFib3J0ZWQoKTtcbiAgICBjb25zdCBjYXRhbG9ndWUgPSBhd2FpdCB0aGlzLmdldChzaWduYWwpO1xuICAgIGNvbnN0IHNraWxsID0gY2F0YWxvZ3VlLnNraWxscy5maW5kKCh7IG5hbWUgfSkgPT4gbmFtZSA9PT0gc2tpbGxOYW1lKTtcbiAgICBpZiAoIXNraWxsKSB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gc2tpbGw6ICR7c2tpbGxOYW1lfWApO1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSBwb3NpeFBhdGgubm9ybWFsaXplKGlucHV0UGF0aCk7XG4gICAgaWYgKFxuICAgICAgIW5vcm1hbGl6ZWQub2sgfHxcbiAgICAgIG5vcm1hbGl6ZWQucGF0aCA9PT0gXCIvXCIgfHxcbiAgICAgIGlucHV0UGF0aC5zcGxpdChcIi9cIikuc29tZSgoc2VnbWVudCkgPT4gc2VnbWVudCA9PT0gXCIuLlwiKVxuICAgICkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHNraWxsIGZpbGUgcGF0aDogJHtpbnB1dFBhdGh9YCk7XG4gICAgfVxuICAgIGNvbnN0IHNvdXJjZSA9IHRoaXMuc291cmNlcy5maW5kKCh7IGlkIH0pID0+IGlkID09PSBza2lsbC5zb3VyY2VJZCk7XG4gICAgaWYgKCFzb3VyY2UpIHRocm93IG5ldyBFcnJvcihgU2tpbGwgc291cmNlIGlzIG5vIGxvbmdlciBtb3VudGVkOiAke3NraWxsLnNvdXJjZUlkfWApO1xuICAgIGNvbnN0IHBhcmVudCA9IHNraWxsLnNvdXJjZVBhdGguc3BsaXQoXCIvXCIpLnNsaWNlKDAsIC0xKS5qb2luKFwiL1wiKTtcbiAgICBjb25zdCBwYXRoID0gW3BhcmVudCwgbm9ybWFsaXplZC5wYXRoLnJlcGxhY2UoL15cXC8rLywgXCJcIildLmZpbHRlcihCb29sZWFuKS5qb2luKFwiL1wiKTtcbiAgICByZXR1cm4gc291cmNlLnJlYWQocGF0aCk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlZnJlc2goKTogUHJvbWlzZTxTa2lsbENhdGFsb2d1ZT4ge1xuICAgIGNvbnN0IHByZXZpb3VzID0gbmV3IE1hcChcbiAgICAgIHRoaXMubGFzdFZhbGlkPy5za2lsbHMubWFwKChza2lsbCkgPT4gW2Ake3NraWxsLnNvdXJjZUlkfVxcMCR7c2tpbGwuc291cmNlUGF0aH1gLCBza2lsbF0pID8/IFtdLFxuICAgICk7XG4gICAgY29uc3Qgc2VsZWN0ZWQgPSBuZXcgTWFwPHN0cmluZywgU2tpbGxDYXRhbG9ndWVFbnRyeT4oKTtcbiAgICBmb3IgKGNvbnN0IHNvdXJjZSBvZiB0aGlzLnNvdXJjZXMpIHtcbiAgICAgIGZvciAoY29uc3QgY2FuZGlkYXRlIG9mIGF3YWl0IGRpc2NvdmVyU2tpbGxGaWxlcyhzb3VyY2UpKSB7XG4gICAgICAgIGNvbnN0IHByaW9yID0gcHJldmlvdXMuZ2V0KGAke3NvdXJjZS5pZH1cXDAke2NhbmRpZGF0ZS5wYXRofWApO1xuICAgICAgICBjb25zdCBzaWduYXR1cmUgPSBmaWxlU2lnbmF0dXJlKGNhbmRpZGF0ZS5lbnRyeSk7XG4gICAgICAgIGxldCBwYXJzZWQ6IFBhcnNlZFNraWxsIHwgdW5kZWZpbmVkO1xuICAgICAgICBpZiAoc2lnbmF0dXJlICYmIHByaW9yPy5zaWduYXR1cmUgPT09IHNpZ25hdHVyZSkge1xuICAgICAgICAgIHBhcnNlZCA9IHByaW9yO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHBhcnNlZCA9IHBhcnNlU2tpbGwoXG4gICAgICAgICAgICBhd2FpdCBzb3VyY2UucmVhZChjYW5kaWRhdGUucGF0aCksXG4gICAgICAgICAgICBjYW5kaWRhdGUucGF0aCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGlmICghcGFyc2VkIHx8IHNlbGVjdGVkLmhhcyhwYXJzZWQubmFtZSkpIGNvbnRpbnVlO1xuICAgICAgICBzZWxlY3RlZC5zZXQocGFyc2VkLm5hbWUsIHtcbiAgICAgICAgICAuLi5wYXJzZWQsXG4gICAgICAgICAgc291cmNlSWQ6IHNvdXJjZS5pZCxcbiAgICAgICAgICBzb3VyY2VQYXRoOiBjYW5kaWRhdGUucGF0aCxcbiAgICAgICAgICAuLi4oc2lnbmF0dXJlID8geyBzaWduYXR1cmUgfSA6IHt9KSxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBTa2lsbENhdGFsb2d1ZVNjaGVtYS5wYXJzZSh7XG4gICAgICB2ZXJzaW9uOiBDQVRBTE9HVUVfVkVSU0lPTixcbiAgICAgIGdlbmVyYXRlZEF0OiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICByb290czogdGhpcy5zb3VyY2VzLm1hcCgoeyBpZCB9KSA9PiBpZCksXG4gICAgICBza2lsbHM6IFsuLi5zZWxlY3RlZC52YWx1ZXMoKV0sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHJvb3RLZXkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gb2JqZWN0LnRvU3RhYmxlS2V5KHRoaXMuc291cmNlcy5tYXAoKHsgaWQgfSkgPT4gaWQpKTtcbiAgfVxuXG4gIHByaXZhdGUgcGVyc2lzdGVudEtleShjYWNoZTogQ2FjaGVNYW5hZ2VyKTogc3RyaW5nIHtcbiAgICByZXR1cm4gY2FjaGUuZ2VuZXJhdGVLZXkoXG4gICAgICBbQ0FDSEVfTkFNRVNQQUNFLCBDQVRBTE9HVUVfVkVSU0lPTiwgdGhpcy5vcHRpb25zLmhvc3QsIHRoaXMucm9vdEtleSgpXSxcbiAgICAgIHRoaXMub3B0aW9ucy51c2VyS2V5LFxuICAgICk7XG4gIH1cbn1cblxuLyoqIFJldHVybiBvbmUgc3RhYmxlIGNhdGFsb2d1ZSBvd25lciBmb3IgYSB1c2VyLCBob3N0LCBhbmQgb3JkZXJlZCByb290IHNldC4gKi9cbmV4cG9ydCBmdW5jdGlvbiB3b3Jrc3BhY2VTa2lsbENhdGFsb2d1ZShcbiAgb3B0aW9uczogV29ya3NwYWNlU2tpbGxDYXRhbG9ndWVPcHRpb25zLFxuKTogV29ya3NwYWNlU2tpbGxDYXRhbG9ndWUge1xuICBjb25zdCBrZXkgPSBvYmplY3QudG9TdGFibGVLZXkoe1xuICAgIGhvc3Q6IG9wdGlvbnMuaG9zdCxcbiAgICByb290czogb3B0aW9ucy5zb3VyY2VzLm1hcCgoeyBpZCB9KSA9PiBpZCksXG4gICAgdXNlcktleTogb3B0aW9ucy51c2VyS2V5LFxuICB9KTtcbiAgY29uc3QgZXhpc3RpbmcgPSBzY29wZWRDYXRhbG9ndWVzLmdldChrZXkpO1xuICBpZiAoZXhpc3RpbmcpIHtcbiAgICBleGlzdGluZy5iaW5kKG9wdGlvbnMuc291cmNlcyk7XG4gICAgcmV0dXJuIGV4aXN0aW5nO1xuICB9XG4gIGNvbnN0IGNhdGFsb2d1ZSA9IG5ldyBXb3Jrc3BhY2VTa2lsbENhdGFsb2d1ZShvcHRpb25zKTtcbiAgc2NvcGVkQ2F0YWxvZ3Vlcy5zZXQoa2V5LCBjYXRhbG9ndWUpO1xuICByZXR1cm4gY2F0YWxvZ3VlO1xufVxuXG4vKiogSW52YWxpZGF0ZSBtYXRjaGluZyBjb21wbGV0ZSBjYXRhbG9ndWVzIGFuZCByZXRhaW4gdGhlaXIgc3RhYmxlIG93bmVycy4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhcldvcmtzcGFjZVNraWxsQ2FjaGUob3B0aW9uczoge1xuICBob3N0OiBzdHJpbmc7XG4gIHVzZXJLZXk/OiBzdHJpbmc7XG59KTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IG1hdGNoZXMgPSBbLi4uc2NvcGVkQ2F0YWxvZ3Vlcy52YWx1ZXMoKV0uZmlsdGVyKFxuICAgIChjYXRhbG9ndWUpID0+XG4gICAgICBjYXRhbG9ndWUuaG9zdCA9PT0gb3B0aW9ucy5ob3N0ICYmXG4gICAgICAob3B0aW9ucy51c2VyS2V5ID09PSB1bmRlZmluZWQgfHwgY2F0YWxvZ3VlLnVzZXJLZXkgPT09IG9wdGlvbnMudXNlcktleSksXG4gICk7XG4gIGF3YWl0IFByb21pc2UuYWxsKG1hdGNoZXMubWFwKChjYXRhbG9ndWUpID0+IGNhdGFsb2d1ZS5pbnZhbGlkYXRlKCkpKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGlzY292ZXJTa2lsbEZpbGVzKFxuICBzb3VyY2U6IFNraWxsQ2F0YWxvZ3VlU291cmNlLFxuKTogUHJvbWlzZTxBcnJheTx7IGVudHJ5OiBTa2lsbENhdGFsb2d1ZUZpbGVFbnRyeTsgcGF0aDogc3RyaW5nIH0+PiB7XG4gIGxldCByb290RW50cmllczogU2tpbGxDYXRhbG9ndWVGaWxlRW50cnlbXTtcbiAgdHJ5IHtcbiAgICByb290RW50cmllcyA9IGF3YWl0IHNvdXJjZS5saXN0KFwiLlwiKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBpZiAoZXJyb3JVdGlscy5lcnJvckNvbnRleHQoZXJyb3IpLm5vdEFjY2Vzc2libGUpIHJldHVybiBbXTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxuICBjb25zdCBjYW5kaWRhdGVzOiBBcnJheTx7IGVudHJ5OiBTa2lsbENhdGFsb2d1ZUZpbGVFbnRyeTsgcGF0aDogc3RyaW5nIH0+ID0gW107XG4gIGNvbnN0IHJvb3RTa2lsbCA9IHJvb3RFbnRyaWVzLmZpbmQoXG4gICAgKHsgbmFtZSwgdHlwZSB9KSA9PiBuYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwic2tpbGwubWRcIiAmJiB0eXBlID09PSBcImZpbGVcIixcbiAgKTtcbiAgaWYgKHJvb3RTa2lsbCkgY2FuZGlkYXRlcy5wdXNoKHsgZW50cnk6IHJvb3RTa2lsbCwgcGF0aDogcm9vdFNraWxsLm5hbWUgfSk7XG4gIGF3YWl0IFByb21pc2UuYWxsKFxuICAgIHJvb3RFbnRyaWVzXG4gICAgICAuZmlsdGVyKCh7IHR5cGUgfSkgPT4gdHlwZSA9PT0gXCJkaXJlY3RvcnlcIilcbiAgICAgIC5tYXAoYXN5bmMgKGRpcmVjdG9yeSkgPT4ge1xuICAgICAgICBjb25zdCBlbnRyaWVzID0gYXdhaXQgc291cmNlLmxpc3QoZGlyZWN0b3J5Lm5hbWUpO1xuICAgICAgICBjb25zdCBza2lsbCA9IGVudHJpZXMuZmluZChcbiAgICAgICAgICAoeyBuYW1lLCB0eXBlIH0pID0+IG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJza2lsbC5tZFwiICYmIHR5cGUgPT09IFwiZmlsZVwiLFxuICAgICAgICApO1xuICAgICAgICBpZiAoc2tpbGwpIGNhbmRpZGF0ZXMucHVzaCh7IGVudHJ5OiBza2lsbCwgcGF0aDogcG9zaXhQYXRoLmpvaW4oZGlyZWN0b3J5Lm5hbWUsIHNraWxsLm5hbWUpIH0pO1xuICAgICAgfSksXG4gICk7XG4gIHJldHVybiBjYW5kaWRhdGVzLnNvcnQoKGxlZnQsIHJpZ2h0KSA9PiBsZWZ0LnBhdGgubG9jYWxlQ29tcGFyZShyaWdodC5wYXRoKSk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlU2tpbGwoc291cmNlOiBzdHJpbmcsIHBhdGg6IHN0cmluZyk6IFBhcnNlZFNraWxsIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWF0Y2ggPSAvXi0tLVxccypcXHI/XFxuKFtcXHNcXFNdKj8pXFxyP1xcbi0tLVxccyooPzpcXHI/XFxufCQpKFtcXHNcXFNdKikkLy5leGVjKHNvdXJjZSk7XG4gIGlmICghbWF0Y2gpIHtcbiAgICBsb2dnZXIud2FybihcInNraWxsIHNraXBwZWQgKG1pc3NpbmcgWUFNTCBmcm9udG1hdHRlcilcIiwgeyBwYXRoIH0pO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgbWV0YWRhdGEgPSBwYXJzZVlhbWwobWF0Y2hbMV0hKSBhcyB1bmtub3duO1xuICBpZiAoIW9iamVjdC5pc1JlY29yZChtZXRhZGF0YSkpIHtcbiAgICBsb2dnZXIud2FybihcInNraWxsIHNraXBwZWQgKGludmFsaWQgWUFNTCBmcm9udG1hdHRlcilcIiwgeyBwYXRoIH0pO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgcGFyc2VkID0gelxuICAgIC5vYmplY3Qoe1xuICAgICAgbmFtZTogei5zdHJpbmcoKS50cmltKCkubWluKDEpLFxuICAgICAgZGVzY3JpcHRpb246IHouc3RyaW5nKCkudHJpbSgpLm1pbigxKSxcbiAgICB9KVxuICAgIC5zYWZlUGFyc2UobWV0YWRhdGEpO1xuICBpZiAoIXBhcnNlZC5zdWNjZXNzKSB7XG4gICAgbG9nZ2VyLndhcm4oXCJza2lsbCBza2lwcGVkIChpbnZhbGlkIG1ldGFkYXRhKVwiLCB7XG4gICAgICBwYXRoLFxuICAgICAgZXJyb3I6IHBhcnNlZC5lcnJvci5tZXNzYWdlLFxuICAgIH0pO1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBuYW1lOiBwYXJzZWQuZGF0YS5uYW1lLFxuICAgIGRlc2NyaXB0aW9uOiBwYXJzZWQuZGF0YS5kZXNjcmlwdGlvbixcbiAgICBpbnN0cnVjdGlvbnM6IG1hdGNoWzJdIS50cmltKCksXG4gIH07XG59XG5cbmZ1bmN0aW9uIGZpbGVTaWduYXR1cmUoZW50cnk6IFNraWxsQ2F0YWxvZ3VlRmlsZUVudHJ5KTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgbWV0YWRhdGEgPSBvYmplY3QuaXNSZWNvcmQoZW50cnkubWV0YWRhdGEpID8gZW50cnkubWV0YWRhdGEgOiB7fTtcbiAgY29uc3QgdmFsdWVzID0ge1xuICAgIG1vZGlmaWVkQXQ6IG1ldGFkYXRhLm1vZGlmaWVkQXQsXG4gICAgb2JqZWN0SWQ6IG1ldGFkYXRhLm9iamVjdElkLFxuICAgIHNpemU6IGVudHJ5LnNpemUsXG4gIH07XG4gIHJldHVybiBPYmplY3QudmFsdWVzKHZhbHVlcykuc29tZSgodmFsdWUpID0+IHZhbHVlICE9PSB1bmRlZmluZWQpXG4gICAgPyBvYmplY3QudG9TdGFibGVLZXkodmFsdWVzKVxuICAgIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBwb3NpdGl2ZVR0bCh2YWx1ZSA9IERFRkFVTFRfV09SS1NQQUNFX1NLSUxMX0NBQ0hFX1RUTF9NUyk6IG51bWJlciB7XG4gIGlmICghTnVtYmVyLmlzRmluaXRlKHZhbHVlKSB8fCB2YWx1ZSA8PSAwKSB7XG4gICAgdGhyb3cgbmV3IFJhbmdlRXJyb3IoXCJXb3Jrc3BhY2Ugc2tpbGwgY2F0YWxvZ3VlIHR0bE1zIG11c3QgYmUgYSBwb3NpdGl2ZSBmaW5pdGUgbnVtYmVyXCIpO1xuICB9XG4gIHJldHVybiB2YWx1ZTtcbn1cbiJdfQ==
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* On-demand skill discovery backed by a materialized workspace catalogue.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import type { ProcessInputStepArgs, Processor } from "@mastra/core/processors";
|
|
7
|
-
import type { SkillCatalogueResolver } from "./skill-cache.ts";
|
|
8
|
-
/** Configuration for {@link CatalogueSkillSearchProcessor}. */
|
|
9
|
-
export interface CatalogueSkillSearchProcessorOptions {
|
|
10
|
-
minScore?: number;
|
|
11
|
-
resolve: SkillCatalogueResolver;
|
|
12
|
-
topK?: number;
|
|
13
|
-
ttlMs?: number;
|
|
14
|
-
}
|
|
15
|
-
/** Mastra-compatible search, load, and lazy-read tools over one cached catalogue. */
|
|
16
|
-
export declare class CatalogueSkillSearchProcessor implements Processor<"skill-catalogue-search"> {
|
|
17
|
-
readonly id = "skill-catalogue-search";
|
|
18
|
-
readonly name = "Skill Catalogue Search";
|
|
19
|
-
readonly providesSkillDiscovery: "on-demand";
|
|
20
|
-
private readonly minScore;
|
|
21
|
-
private readonly resolve;
|
|
22
|
-
private readonly states;
|
|
23
|
-
private readonly topK;
|
|
24
|
-
private readonly ttlMs;
|
|
25
|
-
constructor(options: CatalogueSkillSearchProcessorOptions);
|
|
26
|
-
processInputStep(args: ProcessInputStepArgs): Promise<{
|
|
27
|
-
tools: Record<string, unknown>;
|
|
28
|
-
}>;
|
|
29
|
-
private threadState;
|
|
30
|
-
}
|
package/lib/src/skill-search.js
DELETED
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* On-demand skill discovery backed by a materialized workspace catalogue.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
import { errorUtils } from "@dbx-tools/shared-core";
|
|
7
|
-
import { MASTRA_THREAD_ID_KEY } from "@mastra/core/request-context";
|
|
8
|
-
import { createTool } from "@mastra/core/tools";
|
|
9
|
-
import Fuse from "fuse.js";
|
|
10
|
-
import { z } from "zod";
|
|
11
|
-
const DEFAULT_STATE_TTL_MS = 60 * 60 * 1000;
|
|
12
|
-
/** Mastra-compatible search, load, and lazy-read tools over one cached catalogue. */
|
|
13
|
-
export class CatalogueSkillSearchProcessor {
|
|
14
|
-
id = "skill-catalogue-search";
|
|
15
|
-
name = "Skill Catalogue Search";
|
|
16
|
-
providesSkillDiscovery = "on-demand";
|
|
17
|
-
minScore;
|
|
18
|
-
resolve;
|
|
19
|
-
states = new Map();
|
|
20
|
-
topK;
|
|
21
|
-
ttlMs;
|
|
22
|
-
constructor(options) {
|
|
23
|
-
this.resolve = options.resolve;
|
|
24
|
-
this.topK = options.topK ?? 5;
|
|
25
|
-
this.minScore = options.minScore ?? 0.1;
|
|
26
|
-
this.ttlMs = options.ttlMs ?? DEFAULT_STATE_TTL_MS;
|
|
27
|
-
}
|
|
28
|
-
async processInputStep(args) {
|
|
29
|
-
const owner = await this.resolve(args);
|
|
30
|
-
const catalogue = await owner.get(args.abortSignal);
|
|
31
|
-
const state = this.threadState(args);
|
|
32
|
-
args.messageList.addSystem("To discover available skills, call search_skills with a keyword query. " +
|
|
33
|
-
"To load a skill's instructions, call load_skill with the exact skill name. " +
|
|
34
|
-
"Use skill_read only after loading a skill when its instructions require a reference, script, or asset.");
|
|
35
|
-
for (const [skillName, instructions] of state.skills) {
|
|
36
|
-
args.messageList.addSystem(`[Skill: ${skillName}]\n\n${instructions}`);
|
|
37
|
-
}
|
|
38
|
-
const search = new Fuse(catalogue.skills, {
|
|
39
|
-
includeScore: true,
|
|
40
|
-
ignoreLocation: true,
|
|
41
|
-
threshold: 1,
|
|
42
|
-
keys: [
|
|
43
|
-
{ name: "name", weight: 0.5 },
|
|
44
|
-
{ name: "description", weight: 0.35 },
|
|
45
|
-
{ name: "instructions", weight: 0.15 },
|
|
46
|
-
],
|
|
47
|
-
});
|
|
48
|
-
return {
|
|
49
|
-
tools: {
|
|
50
|
-
...(args.tools ?? {}),
|
|
51
|
-
search_skills: createTool({
|
|
52
|
-
id: "search_skills",
|
|
53
|
-
description: "Search for available skills by keyword. Load a useful result with load_skill.",
|
|
54
|
-
inputSchema: z.object({
|
|
55
|
-
query: z.string().trim().min(1, "Query is required").describe("Search keywords."),
|
|
56
|
-
}),
|
|
57
|
-
outputSchema: z.object({
|
|
58
|
-
results: z.array(z.object({
|
|
59
|
-
name: z.string(),
|
|
60
|
-
description: z.string(),
|
|
61
|
-
score: z.number(),
|
|
62
|
-
})),
|
|
63
|
-
message: z.string(),
|
|
64
|
-
}),
|
|
65
|
-
execute: async ({ query }) => {
|
|
66
|
-
const results = search
|
|
67
|
-
.search(query)
|
|
68
|
-
.map((result) => ({
|
|
69
|
-
name: result.item.name,
|
|
70
|
-
description: result.item.description.length > 150
|
|
71
|
-
? `${result.item.description.slice(0, 147)}...`
|
|
72
|
-
: result.item.description,
|
|
73
|
-
score: Math.round((1 - (result.score ?? 1)) * 100) / 100,
|
|
74
|
-
}))
|
|
75
|
-
.filter(({ score }) => score >= this.minScore)
|
|
76
|
-
.slice(0, this.topK);
|
|
77
|
-
return {
|
|
78
|
-
results,
|
|
79
|
-
message: results.length === 0
|
|
80
|
-
? `No skills found matching "${query}". Try different keywords.`
|
|
81
|
-
: `Found ${results.length} skill(s). Use load_skill with the exact skill name to load its instructions.`,
|
|
82
|
-
};
|
|
83
|
-
},
|
|
84
|
-
}),
|
|
85
|
-
load_skill: createTool({
|
|
86
|
-
id: "load_skill",
|
|
87
|
-
description: "Load a skill's full instructions into the conversation.",
|
|
88
|
-
inputSchema: z.object({
|
|
89
|
-
skillName: z.string().describe("Exact skill name returned by search_skills."),
|
|
90
|
-
}),
|
|
91
|
-
outputSchema: z.object({
|
|
92
|
-
success: z.boolean(),
|
|
93
|
-
message: z.string(),
|
|
94
|
-
skillName: z.string().optional(),
|
|
95
|
-
}),
|
|
96
|
-
execute: async ({ skillName }) => {
|
|
97
|
-
if (state.skills.has(skillName)) {
|
|
98
|
-
return {
|
|
99
|
-
success: true,
|
|
100
|
-
message: `Skill "${skillName}" is already loaded.`,
|
|
101
|
-
skillName,
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
const skill = catalogue.skills.find(({ name }) => name === skillName);
|
|
105
|
-
if (!skill) {
|
|
106
|
-
return {
|
|
107
|
-
success: false,
|
|
108
|
-
message: `Skill "${skillName}" not found. Use search_skills to find available skills.`,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
state.skills.set(skillName, skill.instructions);
|
|
112
|
-
return {
|
|
113
|
-
success: true,
|
|
114
|
-
message: `Skill "${skillName}" loaded. Its instructions are now available as context.`,
|
|
115
|
-
skillName,
|
|
116
|
-
};
|
|
117
|
-
},
|
|
118
|
-
}),
|
|
119
|
-
skill_read: createTool({
|
|
120
|
-
id: "skill_read",
|
|
121
|
-
description: "Read a reference, script, template, or asset from a loaded skill. The path is relative to the skill root.",
|
|
122
|
-
inputSchema: z.object({
|
|
123
|
-
skillName: z.string().describe("Exact loaded skill name."),
|
|
124
|
-
path: z.string().describe("File path relative to the skill root."),
|
|
125
|
-
startLine: z.number().int().positive().optional(),
|
|
126
|
-
endLine: z.number().int().positive().optional(),
|
|
127
|
-
}),
|
|
128
|
-
execute: async ({ skillName, path, startLine, endLine }) => {
|
|
129
|
-
if (!state.skills.has(skillName)) {
|
|
130
|
-
return `Skill "${skillName}" is not loaded. Call load_skill first.`;
|
|
131
|
-
}
|
|
132
|
-
try {
|
|
133
|
-
const source = await owner.readSkillFile(skillName, path, args.abortSignal);
|
|
134
|
-
return lineRange(source, path, startLine, endLine);
|
|
135
|
-
}
|
|
136
|
-
catch (error) {
|
|
137
|
-
return `Could not read "${path}" from skill "${skillName}": ${errorUtils.errorMessage(error)}`;
|
|
138
|
-
}
|
|
139
|
-
},
|
|
140
|
-
}),
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
threadState(args) {
|
|
145
|
-
const now = Date.now();
|
|
146
|
-
for (const [key, state] of this.states) {
|
|
147
|
-
if (now - state.lastAccessed > this.ttlMs)
|
|
148
|
-
this.states.delete(key);
|
|
149
|
-
}
|
|
150
|
-
const key = args.requestContext?.get(MASTRA_THREAD_ID_KEY) ?? "default";
|
|
151
|
-
const current = this.states.get(String(key)) ?? {
|
|
152
|
-
lastAccessed: now,
|
|
153
|
-
skills: new Map(),
|
|
154
|
-
};
|
|
155
|
-
current.lastAccessed = now;
|
|
156
|
-
this.states.set(String(key), current);
|
|
157
|
-
return current;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function lineRange(source, path, startLine, endLine) {
|
|
161
|
-
if (startLine === undefined && endLine === undefined)
|
|
162
|
-
return source;
|
|
163
|
-
const lines = source.split(/\r?\n/);
|
|
164
|
-
const start = Math.max(1, startLine ?? 1);
|
|
165
|
-
const end = Math.min(lines.length, endLine ?? lines.length);
|
|
166
|
-
if (start > end || start > lines.length) {
|
|
167
|
-
return `File "${path}" has ${lines.length} lines; requested range ${start}-${end} is empty.`;
|
|
168
|
-
}
|
|
169
|
-
return `${path} (lines ${start}-${end} of ${lines.length})\n${lines.slice(start - 1, end).join("\n")}`;
|
|
170
|
-
}
|
|
171
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2tpbGwtc2VhcmNoLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NraWxsLXNlYXJjaC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7OztHQUlHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXBELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNoRCxPQUFPLElBQUksTUFBTSxTQUFTLENBQUM7QUFDM0IsT0FBTyxFQUFFLENBQUMsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUd4QixNQUFNLG9CQUFvQixHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0FBZTVDLHFGQUFxRjtBQUNyRixNQUFNLE9BQU8sNkJBQTZCO0lBQy9CLEVBQUUsR0FBRyx3QkFBd0IsQ0FBQztJQUM5QixJQUFJLEdBQUcsd0JBQXdCLENBQUM7SUFDaEMsc0JBQXNCLEdBQUcsV0FBb0IsQ0FBQztJQUV0QyxRQUFRLENBQVM7SUFDakIsT0FBTyxDQUF5QjtJQUNoQyxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQXVCLENBQUM7SUFDeEMsSUFBSSxDQUFTO0lBQ2IsS0FBSyxDQUFTO0lBRS9CLFlBQVksT0FBNkM7UUFDdkQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDO1FBQy9CLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxDQUFDLENBQUM7UUFDOUIsSUFBSSxDQUFDLFFBQVEsR0FBRyxPQUFPLENBQUMsUUFBUSxJQUFJLEdBQUcsQ0FBQztRQUN4QyxJQUFJLENBQUMsS0FBSyxHQUFHLE9BQU8sQ0FBQyxLQUFLLElBQUksb0JBQW9CLENBQUM7SUFDckQsQ0FBQztJQUVELEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxJQUEwQjtRQUMvQyxNQUFNLEtBQUss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Y292ZXJ5IGJhY2tlZCBieSBhIG1hdGVyaWFsaXplZCB3b3Jrc3BhY2UgY2F0YWxvZ3VlLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBlcnJvclV0aWxzIH0gZnJvbSBcIkBkYngtdG9vbHMvc2hhcmVkLWNvcmVcIjtcbmltcG9ydCB0eXBlIHsgUHJvY2Vzc0lucHV0U3RlcEFyZ3MsIFByb2Nlc3NvciB9IGZyb20gXCJAbWFzdHJhL2NvcmUvcHJvY2Vzc29yc1wiO1xuaW1wb3J0IHsgTUFTVFJBX1RIUkVBRF9JRF9LRVkgfSBmcm9tIFwiQG1hc3RyYS9jb3JlL3JlcXVlc3QtY29udGV4dFwiO1xuaW1wb3J0IHsgY3JlYXRlVG9vbCB9IGZyb20gXCJAbWFzdHJhL2NvcmUvdG9vbHNcIjtcbmltcG9ydCBGdXNlIGZyb20gXCJmdXNlLmpzXCI7XG5pbXBvcnQgeyB6IH0gZnJvbSBcInpvZFwiO1xuaW1wb3J0IHR5cGUgeyBTa2lsbENhdGFsb2d1ZVJlc29sdmVyIH0gZnJvbSBcIi4vc2tpbGwtY2FjaGUudHNcIjtcblxuY29uc3QgREVGQVVMVF9TVEFURV9UVExfTVMgPSA2MCAqIDYwICogMTAwMDtcblxuaW50ZXJmYWNlIFRocmVhZFN0YXRlIHtcbiAgbGFzdEFjY2Vzc2VkOiBudW1iZXI7XG4gIHNraWxsczogTWFwPHN0cmluZywgc3RyaW5nPjtcbn1cblxuLyoqIENvbmZpZ3VyYXRpb24gZm9yIHtAbGluayBDYXRhbG9ndWVTa2lsbFNlYXJjaFByb2Nlc3Nvcn0uICovXG5leHBvcnQgaW50ZXJmYWNlIENhdGFsb2d1ZVNraWxsU2VhcmNoUHJvY2Vzc29yT3B0aW9ucyB7XG4gIG1pblNjb3JlPzogbnVtYmVyO1xuICByZXNvbHZlOiBTa2lsbENhdGFsb2d1ZVJlc29sdmVyO1xuICB0b3BLPzogbnVtYmVyO1xuICB0dGxNcz86IG51bWJlcjtcbn1cblxuLyoqIE1hc3RyYS1jb21wYXRpYmxlIHNlYXJjaCwgbG9hZCwgYW5kIGxhenktcmVhZCB0b29scyBvdmVyIG9uZSBjYWNoZWQgY2F0YWxvZ3VlLiAqL1xuZXhwb3J0IGNsYXNzIENhdGFsb2d1ZVNraWxsU2VhcmNoUHJvY2Vzc29yIGltcGxlbWVudHMgUHJvY2Vzc29yPFwic2tpbGwtY2F0YWxvZ3VlLXNlYXJjaFwiPiB7XG4gIHJlYWRvbmx5IGlkID0gXCJza2lsbC1jYXRhbG9ndWUtc2VhcmNoXCI7XG4gIHJlYWRvbmx5IG5hbWUgPSBcIlNraWxsIENhdGFsb2d1ZSBTZWFyY2hcIjtcbiAgcmVhZG9ubHkgcHJvdmlkZXNTa2lsbERpc2NvdmVyeSA9IFwib24tZGVtYW5kXCIgYXMgY29uc3Q7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBtaW5TY29yZTogbnVtYmVyO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlc29sdmU6IFNraWxsQ2F0YWxvZ3VlUmVzb2x2ZXI7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3RhdGVzID0gbmV3IE1hcDxzdHJpbmcsIFRocmVhZFN0YXRlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHRvcEs6IG51bWJlcjtcbiAgcHJpdmF0ZSByZWFkb25seSB0dGxNczogbnVtYmVyO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IENhdGFsb2d1ZVNraWxsU2VhcmNoUHJvY2Vzc29yT3B0aW9ucykge1xuICAgIHRoaXMucmVzb2x2ZSA9IG9wdGlvbnMucmVzb2x2ZTtcbiAgICB0aGlzLnRvcEsgPSBvcHRpb25zLnRvcEsgPz8gNTtcbiAgICB0aGlzLm1pblNjb3JlID0gb3B0aW9ucy5taW5TY29yZSA/PyAwLjE7XG4gICAgdGhpcy50dGxNcyA9IG9wdGlvbnMudHRsTXMgPz8gREVGQVVMVF9TVEFURV9UVExfTVM7XG4gIH1cblxuICBhc3luYyBwcm9jZXNzSW5wdXRTdGVwKGFyZ3M6IFByb2Nlc3NJbnB1dFN0ZXBBcmdzKTogUHJvbWlzZTx7IHRvb2xzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiB9PiB7XG4gICAgY29uc3Qgb3duZXIgPSBhd2FpdCB0aGlzLnJlc29sdmUoYXJncyk7XG4gICAgY29uc3QgY2F0YWxvZ3VlID0gYXdhaXQgb3duZXIuZ2V0KGFyZ3MuYWJvcnRTaWduYWwpO1xuICAgIGNvbnN0IHN0YXRlID0gdGhpcy50aHJlYWRTdGF0ZShhcmdzKTtcbiAgICBhcmdzLm1lc3NhZ2VMaXN0LmFkZFN5c3RlbShcbiAgICAgIFwiVG8gZGlzY292ZXIgYXZhaWxhYmxlIHNraWxscywgY2FsbCBzZWFyY2hfc2tpbGxzIHdpdGggYSBrZXl3b3JkIHF1ZXJ5LiBcIiArXG4gICAgICAgIFwiVG8gbG9hZCBhIHNraWxsJ3MgaW5zdHJ1Y3Rpb25zLCBjYWxsIGxvYWRfc2tpbGwgd2l0aCB0aGUgZXhhY3Qgc2tpbGwgbmFtZS4gXCIgK1xuICAgICAgICBcIlVzZSBza2lsbF9yZWFkIG9ubHkgYWZ0ZXIgbG9hZGluZyBhIHNraWxsIHdoZW4gaXRzIGluc3RydWN0aW9ucyByZXF1aXJlIGEgcmVmZXJlbmNlLCBzY3JpcHQsIG9yIGFzc2V0LlwiLFxuICAgICk7XG4gICAgZm9yIChjb25zdCBbc2tpbGxOYW1lLCBpbnN0cnVjdGlvbnNdIG9mIHN0YXRlLnNraWxscykge1xuICAgICAgYXJncy5tZXNzYWdlTGlzdC5hZGRTeXN0ZW0oYFtTa2lsbDogJHtza2lsbE5hbWV9XVxcblxcbiR7aW5zdHJ1Y3Rpb25zfWApO1xuICAgIH1cbiAgICBjb25zdCBzZWFyY2ggPSBuZXcgRnVzZShjYXRhbG9ndWUuc2tpbGxzLCB7XG4gICAgICBpbmNsdWRlU2NvcmU6IHRydWUsXG4gICAgICBpZ25vcmVMb2NhdGlvbjogdHJ1ZSxcbiAgICAgIHRocmVzaG9sZDogMSxcbiAgICAgIGtleXM6IFtcbiAgICAgICAgeyBuYW1lOiBcIm5hbWVcIiwgd2VpZ2h0OiAwLjUgfSxcbiAgICAgICAgeyBuYW1lOiBcImRlc2NyaXB0aW9uXCIsIHdlaWdodDogMC4zNSB9LFxuICAgICAgICB7IG5hbWU6IFwiaW5zdHJ1Y3Rpb25zXCIsIHdlaWdodDogMC4xNSB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICByZXR1cm4ge1xuICAgICAgdG9vbHM6IHtcbiAgICAgICAgLi4uKGFyZ3MudG9vbHMgPz8ge30pLFxuICAgICAgICBzZWFyY2hfc2tpbGxzOiBjcmVhdGVUb29sKHtcbiAgICAgICAgICBpZDogXCJzZWFyY2hfc2tpbGxzXCIsXG4gICAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgICBcIlNlYXJjaCBmb3IgYXZhaWxhYmxlIHNraWxscyBieSBrZXl3b3JkLiBMb2FkIGEgdXNlZnVsIHJlc3VsdCB3aXRoIGxvYWRfc2tpbGwuXCIsXG4gICAgICAgICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgICAgIHF1ZXJ5OiB6LnN0cmluZygpLnRyaW0oKS5taW4oMSwgXCJRdWVyeSBpcyByZXF1aXJlZFwiKS5kZXNjcmliZShcIlNlYXJjaCBrZXl3b3Jkcy5cIiksXG4gICAgICAgICAgfSksXG4gICAgICAgICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICAgICAgICByZXN1bHRzOiB6LmFycmF5KFxuICAgICAgICAgICAgICB6Lm9iamVjdCh7XG4gICAgICAgICAgICAgICAgbmFtZTogei5zdHJpbmcoKSxcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogei5zdHJpbmcoKSxcbiAgICAgICAgICAgICAgICBzY29yZTogei5udW1iZXIoKSxcbiAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICApLFxuICAgICAgICAgICAgbWVzc2FnZTogei5zdHJpbmcoKSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBleGVjdXRlOiBhc3luYyAoeyBxdWVyeSB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZXN1bHRzID0gc2VhcmNoXG4gICAgICAgICAgICAgIC5zZWFyY2gocXVlcnkpXG4gICAgICAgICAgICAgIC5tYXAoKHJlc3VsdCkgPT4gKHtcbiAgICAgICAgICAgICAgICBuYW1lOiByZXN1bHQuaXRlbS5uYW1lLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgICAgICAgcmVzdWx0Lml0ZW0uZGVzY3JpcHRpb24ubGVuZ3RoID4gMTUwXG4gICAgICAgICAgICAgICAgICAgID8gYCR7cmVzdWx0Lml0ZW0uZGVzY3JpcHRpb24uc2xpY2UoMCwgMTQ3KX0uLi5gXG4gICAgICAgICAgICAgICAgICAgIDogcmVzdWx0Lml0ZW0uZGVzY3JpcHRpb24sXG4gICAgICAgICAgICAgICAgc2NvcmU6IE1hdGgucm91bmQoKDEgLSAocmVzdWx0LnNjb3JlID8/IDEpKSAqIDEwMCkgLyAxMDAsXG4gICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAuZmlsdGVyKCh7IHNjb3JlIH0pID0+IHNjb3JlID49IHRoaXMubWluU2NvcmUpXG4gICAgICAgICAgICAgIC5zbGljZSgwLCB0aGlzLnRvcEspO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgcmVzdWx0cyxcbiAgICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgICByZXN1bHRzLmxlbmd0aCA9PT0gMFxuICAgICAgICAgICAgICAgICAgPyBgTm8gc2tpbGxzIGZvdW5kIG1hdGNoaW5nIFwiJHtxdWVyeX1cIi4gVHJ5IGRpZmZlcmVudCBrZXl3b3Jkcy5gXG4gICAgICAgICAgICAgICAgICA6IGBGb3VuZCAke3Jlc3VsdHMubGVuZ3RofSBza2lsbChzKS4gVXNlIGxvYWRfc2tpbGwgd2l0aCB0aGUgZXhhY3Qgc2tpbGwgbmFtZSB0byBsb2FkIGl0cyBpbnN0cnVjdGlvbnMuYCxcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgfSxcbiAgICAgICAgfSksXG4gICAgICAgIGxvYWRfc2tpbGw6IGNyZWF0ZVRvb2woe1xuICAgICAgICAgIGlkOiBcImxvYWRfc2tpbGxcIixcbiAgICAgICAgICBkZXNjcmlwdGlvbjogXCJMb2FkIGEgc2tpbGwncyBmdWxsIGluc3RydWN0aW9ucyBpbnRvIHRoZSBjb252ZXJzYXRpb24uXCIsXG4gICAgICAgICAgaW5wdXRTY2hlbWE6IHoub2JqZWN0KHtcbiAgICAgICAgICAgIHNraWxsTmFtZTogei5zdHJpbmcoKS5kZXNjcmliZShcIkV4YWN0IHNraWxsIG5hbWUgcmV0dXJuZWQgYnkgc2VhcmNoX3NraWxscy5cIiksXG4gICAgICAgICAgfSksXG4gICAgICAgICAgb3V0cHV0U2NoZW1hOiB6Lm9iamVjdCh7XG4gICAgICAgICAgICBzdWNjZXNzOiB6LmJvb2xlYW4oKSxcbiAgICAgICAgICAgIG1lc3NhZ2U6IHouc3RyaW5nKCksXG4gICAgICAgICAgICBza2lsbE5hbWU6IHouc3RyaW5nKCkub3B0aW9uYWwoKSxcbiAgICAgICAgICB9KSxcbiAgICAgICAgICBleGVjdXRlOiBhc3luYyAoeyBza2lsbE5hbWUgfSkgPT4ge1xuICAgICAgICAgICAgaWYgKHN0YXRlLnNraWxscy5oYXMoc2tpbGxOYW1lKSkge1xuICAgICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFNraWxsIFwiJHtza2lsbE5hbWV9XCIgaXMgYWxyZWFkeSBsb2FkZWQuYCxcbiAgICAgICAgICAgICAgICBza2lsbE5hbWUsXG4gICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBza2lsbCA9IGNhdGFsb2d1ZS5za2lsbHMuZmluZCgoeyBuYW1lIH0pID0+IG5hbWUgPT09IHNraWxsTmFtZSk7XG4gICAgICAgICAgICBpZiAoIXNraWxsKSB7XG4gICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFNraWxsIFwiJHtza2lsbE5hbWV9XCIgbm90IGZvdW5kLiBVc2Ugc2VhcmNoX3NraWxscyB0byBmaW5kIGF2YWlsYWJsZSBza2lsbHMuYCxcbiAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHN0YXRlLnNraWxscy5zZXQoc2tpbGxOYW1lLCBza2lsbC5pbnN0cnVjdGlvbnMpO1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogYFNraWxsIFwiJHtza2lsbE5hbWV9XCIgbG9hZGVkLiBJdHMgaW5zdHJ1Y3Rpb25zIGFyZSBub3cgYXZhaWxhYmxlIGFzIGNvbnRleHQuYCxcbiAgICAgICAgICAgICAgc2tpbGxOYW1lLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9LFxuICAgICAgICB9KSxcbiAgICAgICAgc2tpbGxfcmVhZDogY3JlYXRlVG9vbCh7XG4gICAgICAgICAgaWQ6IFwic2tpbGxfcmVhZFwiLFxuICAgICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICAgXCJSZWFkIGEgcmVmZXJlbmNlLCBzY3JpcHQsIHRlbXBsYXRlLCBvciBhc3NldCBmcm9tIGEgbG9hZGVkIHNraWxsLiBUaGUgcGF0aCBpcyByZWxhdGl2ZSB0byB0aGUgc2tpbGwgcm9vdC5cIixcbiAgICAgICAgICBpbnB1dFNjaGVtYTogei5vYmplY3Qoe1xuICAgICAgICAgICAgc2tpbGxOYW1lOiB6LnN0cmluZygpLmRlc2NyaWJlKFwiRXhhY3QgbG9hZGVkIHNraWxsIG5hbWUuXCIpLFxuICAgICAgICAgICAgcGF0aDogei5zdHJpbmcoKS5kZXNjcmliZShcIkZpbGUgcGF0aCByZWxhdGl2ZSB0byB0aGUgc2tpbGwgcm9vdC5cIiksXG4gICAgICAgICAgICBzdGFydExpbmU6IHoubnVtYmVyKCkuaW50KCkucG9zaXRpdmUoKS5vcHRpb25hbCgpLFxuICAgICAgICAgICAgZW5kTGluZTogei5udW1iZXIoKS5pbnQoKS5wb3NpdGl2ZSgpLm9wdGlvbmFsKCksXG4gICAgICAgICAgfSksXG4gICAgICAgICAgZXhlY3V0ZTogYXN5bmMgKHsgc2tpbGxOYW1lLCBwYXRoLCBzdGFydExpbmUsIGVuZExpbmUgfSkgPT4ge1xuICAgICAgICAgICAgaWYgKCFzdGF0ZS5za2lsbHMuaGFzKHNraWxsTmFtZSkpIHtcbiAgICAgICAgICAgICAgcmV0dXJuIGBTa2lsbCBcIiR7c2tpbGxOYW1lfVwiIGlzIG5vdCBsb2FkZWQuIENhbGwgbG9hZF9za2lsbCBmaXJzdC5gO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgY29uc3Qgc291cmNlID0gYXdhaXQgb3duZXIucmVhZFNraWxsRmlsZShza2lsbE5hbWUsIHBhdGgsIGFyZ3MuYWJvcnRTaWduYWwpO1xuICAgICAgICAgICAgICByZXR1cm4gbGluZVJhbmdlKHNvdXJjZSwgcGF0aCwgc3RhcnRMaW5lLCBlbmRMaW5lKTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgIHJldHVybiBgQ291bGQgbm90IHJlYWQgXCIke3BhdGh9XCIgZnJvbSBza2lsbCBcIiR7c2tpbGxOYW1lfVwiOiAke2Vycm9yVXRpbHMuZXJyb3JNZXNzYWdlKGVycm9yKX1gO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSB0aHJlYWRTdGF0ZShhcmdzOiBQcm9jZXNzSW5wdXRTdGVwQXJncyk6IFRocmVhZFN0YXRlIHtcbiAgICBjb25zdCBub3cgPSBEYXRlLm5vdygpO1xuICAgIGZvciAoY29uc3QgW2tleSwgc3RhdGVdIG9mIHRoaXMuc3RhdGVzKSB7XG4gICAgICBpZiAobm93IC0gc3RhdGUubGFzdEFjY2Vzc2VkID4gdGhpcy50dGxNcykgdGhpcy5zdGF0ZXMuZGVsZXRlKGtleSk7XG4gICAgfVxuICAgIGNvbnN0IGtleSA9IGFyZ3MucmVxdWVzdENvbnRleHQ/LmdldChNQVNUUkFfVEhSRUFEX0lEX0tFWSkgPz8gXCJkZWZhdWx0XCI7XG4gICAgY29uc3QgY3VycmVudCA9IHRoaXMuc3RhdGVzLmdldChTdHJpbmcoa2V5KSkgPz8ge1xuICAgICAgbGFzdEFjY2Vzc2VkOiBub3csXG4gICAgICBza2lsbHM6IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCksXG4gICAgfTtcbiAgICBjdXJyZW50Lmxhc3RBY2Nlc3NlZCA9IG5vdztcbiAgICB0aGlzLnN0YXRlcy5zZXQoU3RyaW5nKGtleSksIGN1cnJlbnQpO1xuICAgIHJldHVybiBjdXJyZW50O1xuICB9XG59XG5cbmZ1bmN0aW9uIGxpbmVSYW5nZShcbiAgc291cmNlOiBzdHJpbmcsXG4gIHBhdGg6IHN0cmluZyxcbiAgc3RhcnRMaW5lOiBudW1iZXIgfCB1bmRlZmluZWQsXG4gIGVuZExpbmU6IG51bWJlciB8IHVuZGVmaW5lZCxcbik6IHN0cmluZyB7XG4gIGlmIChzdGFydExpbmUgPT09IHVuZGVmaW5lZCAmJiBlbmRMaW5lID09PSB1bmRlZmluZWQpIHJldHVybiBzb3VyY2U7XG4gIGNvbnN0IGxpbmVzID0gc291cmNlLnNwbGl0KC9cXHI/XFxuLyk7XG4gIGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoMSwgc3RhcnRMaW5lID8/IDEpO1xuICBjb25zdCBlbmQgPSBNYXRoLm1pbihsaW5lcy5sZW5ndGgsIGVuZExpbmUgPz8gbGluZXMubGVuZ3RoKTtcbiAgaWYgKHN0YXJ0ID4gZW5kIHx8IHN0YXJ0ID4gbGluZXMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGBGaWxlIFwiJHtwYXRofVwiIGhhcyAke2xpbmVzLmxlbmd0aH0gbGluZXM7IHJlcXVlc3RlZCByYW5nZSAke3N0YXJ0fS0ke2VuZH0gaXMgZW1wdHkuYDtcbiAgfVxuICByZXR1cm4gYCR7cGF0aH0gKGxpbmVzICR7c3RhcnR9LSR7ZW5kfSBvZiAke2xpbmVzLmxlbmd0aH0pXFxuJHtsaW5lcy5zbGljZShzdGFydCAtIDEsIGVuZCkuam9pbihcIlxcblwiKX1gO1xufVxuIl19
|