@dbx-tools/appkit-mastra 0.9.79 → 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 +90 -48
- package/index.ts +4 -12
- package/lib/index.d.ts +4 -12
- package/lib/index.js +4 -9
- 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/monty-sandbox.d.ts +4 -3
- package/lib/src/monty-sandbox.js +54 -21
- 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 -38
- 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/monty-sandbox.ts +61 -22
- 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/monty-native.d.ts +0 -40
- package/lib/src/monty-native.js +0 -100
- 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/monty-native.ts +0 -149
- package/src/skill-cache.ts +0 -347
- package/src/skill-search.ts +0 -203
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
|
package/src/monty-native.ts
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ensures Monty's platform native package is present before the Node addon loads.
|
|
3
|
-
*
|
|
4
|
-
* `@pydantic/monty` ships `@pydantic/monty-<platform>` as optionalDependencies.
|
|
5
|
-
* npm can skip those (https://github.com/npm/cli/issues/4828), which surfaces as
|
|
6
|
-
* "Cannot find native binding". This module installs only the current platform
|
|
7
|
-
* package, at the already-installed `@pydantic/monty` version, without rewriting
|
|
8
|
-
* package.json.
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { createRequire } from "node:module";
|
|
14
|
-
import { COMMAND_NOT_FOUND_EXIT_CODE, exec } from "@dbx-tools/core";
|
|
15
|
-
import { errorUtils, log } from "@dbx-tools/shared-core";
|
|
16
|
-
|
|
17
|
-
const logger = log.logger("mastra/monty-native");
|
|
18
|
-
const requireFromHere = createRequire(import.meta.url);
|
|
19
|
-
|
|
20
|
-
/** Result of spawning the package installer. */
|
|
21
|
-
export interface MontyNativeInstallResult {
|
|
22
|
-
exitCode: number | null;
|
|
23
|
-
stdout: string;
|
|
24
|
-
stderr: string;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Installer used by {@link ensureMontyNativeBinding}. */
|
|
28
|
-
export type MontyNativeInstaller = (
|
|
29
|
-
command: string,
|
|
30
|
-
args: readonly string[],
|
|
31
|
-
options: { cwd: string },
|
|
32
|
-
) => Promise<MontyNativeInstallResult>;
|
|
33
|
-
|
|
34
|
-
/** Overrides for {@link ensureMontyNativeBinding} (tests inject resolve/install). */
|
|
35
|
-
export interface EnsureMontyNativeBindingOptions {
|
|
36
|
-
/** Working directory for the in-place install. Defaults to `process.cwd()`. */
|
|
37
|
-
cwd?: string;
|
|
38
|
-
/** Module resolver; defaults to `createRequire(import.meta.url).resolve`. */
|
|
39
|
-
resolve?: (specifier: string) => string;
|
|
40
|
-
/** Package installer; defaults to npm, then bun when npm is missing. */
|
|
41
|
-
install?: MontyNativeInstaller;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* npm package that ships Monty's `.node` addon and `monty` binary for this
|
|
46
|
-
* process. Matches `@pydantic/monty`'s `platformTriple()` / optionalDependencies.
|
|
47
|
-
*/
|
|
48
|
-
export function montyNativeBindingPackage(
|
|
49
|
-
platform: NodeJS.Platform = process.platform,
|
|
50
|
-
arch: string = process.arch,
|
|
51
|
-
): string | undefined {
|
|
52
|
-
if (platform === "darwin" && (arch === "x64" || arch === "arm64")) {
|
|
53
|
-
return `@pydantic/monty-darwin-${arch}`;
|
|
54
|
-
}
|
|
55
|
-
if (platform === "linux" && (arch === "x64" || arch === "arm64")) {
|
|
56
|
-
return `@pydantic/monty-linux-${arch}-gnu`;
|
|
57
|
-
}
|
|
58
|
-
if (platform === "win32" && arch === "x64") {
|
|
59
|
-
return "@pydantic/monty-win32-x64-msvc";
|
|
60
|
-
}
|
|
61
|
-
return undefined;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* Resolve the current platform's Monty native package, installing it in place
|
|
66
|
-
* when npm omitted the optional dependency.
|
|
67
|
-
*/
|
|
68
|
-
export async function ensureMontyNativeBinding(
|
|
69
|
-
options: EnsureMontyNativeBindingOptions = {},
|
|
70
|
-
): Promise<void> {
|
|
71
|
-
const pkg = montyNativeBindingPackage();
|
|
72
|
-
if (!pkg) return;
|
|
73
|
-
|
|
74
|
-
const resolve = options.resolve ?? ((specifier: string) => requireFromHere.resolve(specifier));
|
|
75
|
-
if (isResolvable(pkg, resolve)) return;
|
|
76
|
-
|
|
77
|
-
const version = montyPackageVersion(resolve);
|
|
78
|
-
const spec = `${pkg}@${version}`;
|
|
79
|
-
const cwd = options.cwd ?? process.cwd();
|
|
80
|
-
logger.warn("native-binding:missing", { package: spec, cwd });
|
|
81
|
-
|
|
82
|
-
const install = options.install ?? defaultInstaller;
|
|
83
|
-
const output = await installNativePackage(spec, cwd, install);
|
|
84
|
-
if (!isResolvable(pkg, resolve)) {
|
|
85
|
-
throw new Error(
|
|
86
|
-
`Monty native binding ${spec} is still missing after ${output.command}. ${output.detail}`,
|
|
87
|
-
);
|
|
88
|
-
}
|
|
89
|
-
logger.info("native-binding:installed", { package: spec, command: output.command });
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function isResolvable(specifier: string, resolve: (specifier: string) => string): boolean {
|
|
93
|
-
try {
|
|
94
|
-
resolve(`${specifier}/package.json`);
|
|
95
|
-
return true;
|
|
96
|
-
} catch {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function montyPackageVersion(resolve: (specifier: string) => string): string {
|
|
102
|
-
const pkg = requireFromHere(resolve("@pydantic/monty/package.json")) as { version?: string };
|
|
103
|
-
const version = pkg.version?.trim();
|
|
104
|
-
if (!version) throw new Error("Installed @pydantic/monty has no version");
|
|
105
|
-
return version;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
async function installNativePackage(
|
|
109
|
-
spec: string,
|
|
110
|
-
cwd: string,
|
|
111
|
-
install: MontyNativeInstaller,
|
|
112
|
-
): Promise<{ command: string; detail: string }> {
|
|
113
|
-
const npm = await install("npm", ["install", spec, "--no-save", "--no-package-lock"], { cwd });
|
|
114
|
-
if (npm.exitCode === 0) return { command: `npm install ${spec}`, detail: npm.stdout };
|
|
115
|
-
if (npm.exitCode !== COMMAND_NOT_FOUND_EXIT_CODE) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
`Failed to install ${spec} with npm (exit ${npm.exitCode}): ${installDetail(npm)}`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const bun = await install("bun", ["add", spec, "--no-save"], { cwd });
|
|
122
|
-
if (bun.exitCode === 0) return { command: `bun add ${spec}`, detail: bun.stdout };
|
|
123
|
-
throw new Error(
|
|
124
|
-
`Failed to install ${spec}: npm was not found, bun add exited ${bun.exitCode}: ${installDetail(bun)}`,
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function defaultInstaller(
|
|
129
|
-
command: string,
|
|
130
|
-
args: readonly string[],
|
|
131
|
-
options: { cwd: string },
|
|
132
|
-
): Promise<MontyNativeInstallResult> {
|
|
133
|
-
const result = await exec.spawn(command, [...args], {
|
|
134
|
-
cwd: options.cwd,
|
|
135
|
-
stdout: "capture",
|
|
136
|
-
stderr: "capture",
|
|
137
|
-
stdin: "ignore",
|
|
138
|
-
check: false,
|
|
139
|
-
});
|
|
140
|
-
return {
|
|
141
|
-
exitCode: result.exitCode,
|
|
142
|
-
stdout: result.stdout,
|
|
143
|
-
stderr: result.stderr,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function installDetail(result: MontyNativeInstallResult): string {
|
|
148
|
-
return errorUtils.errorMessage(result.stderr || result.stdout || `exit ${result.exitCode}`);
|
|
149
|
-
}
|