@mastra/code-sdk 1.0.3-alpha.0 → 1.1.0-alpha.2
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 +49 -0
- package/dist/acp/agent.js +155 -167
- package/dist/acp/agent.js.map +1 -1
- package/dist/acp/event-mapper.js +193 -168
- package/dist/acp/event-mapper.js.map +1 -1
- package/dist/acp/index.js +60 -49
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/server.js +31 -30
- package/dist/acp/server.js.map +1 -1
- package/dist/acp.js +1 -4
- package/dist/agents/credential-resolver.js +40 -29
- package/dist/agents/credential-resolver.js.map +1 -1
- package/dist/agents/custom-provider-source.js +16 -9
- package/dist/agents/custom-provider-source.js.map +1 -1
- package/dist/agents/instructions.js +27 -36
- package/dist/agents/instructions.js.map +1 -1
- package/dist/agents/mastracode-gateway.js +355 -428
- package/dist/agents/mastracode-gateway.js.map +1 -1
- package/dist/agents/memory.js +87 -78
- package/dist/agents/memory.js.map +1 -1
- package/dist/agents/model.js +114 -119
- package/dist/agents/model.js.map +1 -1
- package/dist/agents/modes/build.js +12 -13
- package/dist/agents/modes/build.js.map +1 -1
- package/dist/agents/modes/explore.js +14 -13
- package/dist/agents/modes/explore.js.map +1 -1
- package/dist/agents/modes/plan.js +14 -15
- package/dist/agents/modes/plan.js.map +1 -1
- package/dist/agents/prompts/agent-instructions.js +78 -69
- package/dist/agents/prompts/agent-instructions.js.map +1 -1
- package/dist/agents/prompts/build.js +19 -16
- package/dist/agents/prompts/build.js.map +1 -1
- package/dist/agents/prompts/fast.js +8 -4
- package/dist/agents/prompts/fast.js.map +1 -1
- package/dist/agents/prompts/index.js +48 -47
- package/dist/agents/prompts/index.js.map +1 -1
- package/dist/agents/prompts/model.js +6 -5
- package/dist/agents/prompts/model.js.map +1 -1
- package/dist/agents/prompts/plan.js +20 -16
- package/dist/agents/prompts/plan.js.map +1 -1
- package/dist/agents/prompts/tool-guidance.js +77 -109
- package/dist/agents/prompts/tool-guidance.js.map +1 -1
- package/dist/agents/sandbox-filesystem.js +245 -259
- package/dist/agents/sandbox-filesystem.js.map +1 -1
- package/dist/agents/sandbox-reattach.js +9 -11
- package/dist/agents/sandbox-reattach.js.map +1 -1
- package/dist/agents/thread-caveman-state.js +92 -81
- package/dist/agents/thread-caveman-state.js.map +1 -1
- package/dist/agents/tool-availability.js +62 -80
- package/dist/agents/tool-availability.js.map +1 -1
- package/dist/agents/tools.js +99 -139
- package/dist/agents/tools.js.map +1 -1
- package/dist/agents/workspace.js +232 -225
- package/dist/agents/workspace.js.map +1 -1
- package/dist/analytics.js +139 -128
- package/dist/analytics.js.map +1 -1
- package/dist/auth/authorization-input.js +39 -25
- package/dist/auth/authorization-input.js.map +1 -1
- package/dist/auth/device-code.js +112 -80
- package/dist/auth/device-code.js.map +1 -1
- package/dist/auth/index.js +2 -9
- package/dist/auth/pkce.js +27 -16
- package/dist/auth/pkce.js.map +1 -1
- package/dist/auth/providers/anthropic.js +107 -93
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/github-copilot.js +304 -293
- package/dist/auth/providers/github-copilot.js.map +1 -1
- package/dist/auth/providers/openai-codex.js +442 -460
- package/dist/auth/providers/openai-codex.js.map +1 -1
- package/dist/auth/providers/xai.js +179 -145
- package/dist/auth/providers/xai.js.map +1 -1
- package/dist/auth/storage.js +182 -175
- package/dist/auth/storage.js.map +1 -1
- package/dist/auth/types.js +1 -1
- package/dist/clipboard/index.js +206 -172
- package/dist/clipboard/index.js.map +1 -1
- package/dist/constants.js +11 -16
- package/dist/constants.js.map +1 -1
- package/dist/error-classification.js +19 -11
- package/dist/error-classification.js.map +1 -1
- package/dist/evals/context-builder.js +145 -104
- package/dist/evals/context-builder.js.map +1 -1
- package/dist/evals/index.js +4 -7
- package/dist/evals/scorers/classify-command.js +62 -41
- package/dist/evals/scorers/classify-command.js.map +1 -1
- package/dist/evals/scorers/efficiency.js +239 -181
- package/dist/evals/scorers/efficiency.js.map +1 -1
- package/dist/evals/scorers/extract-tools.js +51 -47
- package/dist/evals/scorers/extract-tools.js.map +1 -1
- package/dist/evals/scorers/index.js +1 -5
- package/dist/evals/scorers/outcome.js +321 -212
- package/dist/evals/scorers/outcome.js.map +1 -1
- package/dist/goal-manager.js +266 -261
- package/dist/goal-manager.js.map +1 -1
- package/dist/goal-signal.js +14 -13
- package/dist/goal-signal.js.map +1 -1
- package/dist/headless/cli.js +153 -154
- package/dist/headless/cli.js.map +1 -1
- package/dist/headless/flags.js +180 -178
- package/dist/headless/flags.js.map +1 -1
- package/dist/headless/format.js +72 -71
- package/dist/headless/format.js.map +1 -1
- package/dist/headless/index.js +5 -31
- package/dist/headless/policy.js +35 -31
- package/dist/headless/policy.js.map +1 -1
- package/dist/headless/run-mc.js +332 -334
- package/dist/headless/run-mc.js.map +1 -1
- package/dist/headless/types.js +16 -7
- package/dist/headless/types.js.map +1 -1
- package/dist/hooks/config.js +56 -61
- package/dist/hooks/config.js.map +1 -1
- package/dist/hooks/executor.js +118 -116
- package/dist/hooks/executor.js.map +1 -1
- package/dist/hooks/index.js +4 -15
- package/dist/hooks/manager.js +221 -280
- package/dist/hooks/manager.js.map +1 -1
- package/dist/hooks/types.js +5 -4
- package/dist/hooks/types.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +632 -712
- package/dist/index.js.map +1 -1
- package/dist/ipc/ipc-reporter.js +19 -22
- package/dist/ipc/ipc-reporter.js.map +1 -1
- package/dist/lsp/client.js +248 -306
- package/dist/lsp/client.js.map +1 -1
- package/dist/lsp/index.js +1 -6
- package/dist/lsp/language.js +39 -43
- package/dist/lsp/language.js.map +1 -1
- package/dist/lsp/manager.js +78 -93
- package/dist/lsp/manager.js.map +1 -1
- package/dist/lsp/server.js +151 -120
- package/dist/lsp/server.js.map +1 -1
- package/dist/lsp/workspace.js +50 -47
- package/dist/lsp/workspace.js.map +1 -1
- package/dist/mcp/config.js +210 -199
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/index.js +2 -9
- package/dist/mcp/manager.js +482 -475
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/types.js +1 -1
- package/dist/onboarding/custom-packs.js +14 -17
- package/dist/onboarding/custom-packs.js.map +1 -1
- package/dist/onboarding/custom-providers.js +22 -20
- package/dist/onboarding/custom-providers.js.map +1 -1
- package/dist/onboarding/index.d.ts +1 -1
- package/dist/onboarding/index.d.ts.map +1 -1
- package/dist/onboarding/index.js +3 -21
- package/dist/onboarding/om-settings.d.ts +5 -0
- package/dist/onboarding/om-settings.d.ts.map +1 -1
- package/dist/onboarding/om-settings.js +41 -20
- package/dist/onboarding/om-settings.js.map +1 -1
- package/dist/onboarding/packs.d.ts +4 -6
- package/dist/onboarding/packs.d.ts.map +1 -1
- package/dist/onboarding/packs.js +154 -105
- package/dist/onboarding/packs.js.map +1 -1
- package/dist/onboarding/settings.js +575 -517
- package/dist/onboarding/settings.js.map +1 -1
- package/dist/permissions.js +112 -99
- package/dist/permissions.js.map +1 -1
- package/dist/plugin.js +21 -23
- package/dist/plugin.js.map +1 -1
- package/dist/plugins/dependencies.js +64 -87
- package/dist/plugins/dependencies.js.map +1 -1
- package/dist/plugins/install.js +159 -169
- package/dist/plugins/install.js.map +1 -1
- package/dist/plugins/loader.js +170 -185
- package/dist/plugins/loader.js.map +1 -1
- package/dist/plugins/manager.js +374 -380
- package/dist/plugins/manager.js.map +1 -1
- package/dist/plugins/manifest.js +38 -63
- package/dist/plugins/manifest.js.map +1 -1
- package/dist/plugins/package-link.js +48 -64
- package/dist/plugins/package-link.js.map +1 -1
- package/dist/plugins/paths.js +18 -19
- package/dist/plugins/paths.js.map +1 -1
- package/dist/plugins/registry.js +97 -81
- package/dist/plugins/registry.js.map +1 -1
- package/dist/plugins/scaffold.js +62 -98
- package/dist/plugins/scaffold.js.map +1 -1
- package/dist/plugins/types.js +1 -1
- package/dist/processors/plan-rejection-abort.js +45 -44
- package/dist/processors/plan-rejection-abort.js.map +1 -1
- package/dist/providers/amazon-bedrock-gateway.js +134 -125
- package/dist/providers/amazon-bedrock-gateway.js.map +1 -1
- package/dist/providers/amazon-bedrock.js +68 -47
- package/dist/providers/amazon-bedrock.js.map +1 -1
- package/dist/providers/claude-max.js +153 -133
- package/dist/providers/claude-max.js.map +1 -1
- package/dist/providers/github-copilot.js +232 -230
- package/dist/providers/github-copilot.js.map +1 -1
- package/dist/providers/openai-codex.js +271 -260
- package/dist/providers/openai-codex.js.map +1 -1
- package/dist/providers/xai.js +57 -50
- package/dist/providers/xai.js.map +1 -1
- package/dist/schema.js +91 -89
- package/dist/schema.js.map +1 -1
- package/dist/theme-palette.js +18 -14
- package/dist/theme-palette.js.map +1 -1
- package/dist/tool-names.js +46 -37
- package/dist/tool-names.js.map +1 -1
- package/dist/tools/index.js +2 -8
- package/dist/tools/request-sandbox-access.js +71 -80
- package/dist/tools/request-sandbox-access.js.map +1 -1
- package/dist/tools/utils.js +26 -16
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/web-search.js +51 -55
- package/dist/tools/web-search.js.map +1 -1
- package/dist/utils/binaries.js +65 -61
- package/dist/utils/binaries.js.map +1 -1
- package/dist/utils/debug-log.js +51 -47
- package/dist/utils/debug-log.js.map +1 -1
- package/dist/utils/errors.js +157 -192
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/gateway-sync.js +49 -37
- package/dist/utils/gateway-sync.js.map +1 -1
- package/dist/utils/path-security.js +7 -6
- package/dist/utils/path-security.js.map +1 -1
- package/dist/utils/plan-diff.js +58 -39
- package/dist/utils/plan-diff.js.map +1 -1
- package/dist/utils/plans.js +92 -74
- package/dist/utils/plans.js.map +1 -1
- package/dist/utils/project.js +318 -256
- package/dist/utils/project.js.map +1 -1
- package/dist/utils/signals-pubsub.js +117 -99
- package/dist/utils/signals-pubsub.js.map +1 -1
- package/dist/utils/slash-command-loader.js +118 -154
- package/dist/utils/slash-command-loader.js.map +1 -1
- package/dist/utils/slash-command-processor.js +92 -83
- package/dist/utils/slash-command-processor.js.map +1 -1
- package/dist/utils/stdin-pipe.js +87 -63
- package/dist/utils/stdin-pipe.js.map +1 -1
- package/dist/utils/storage-factory.js +104 -84
- package/dist/utils/storage-factory.js.map +1 -1
- package/dist/utils/storage-maintenance.js +249 -211
- package/dist/utils/storage-maintenance.js.map +1 -1
- package/dist/utils/thread-lock.js +96 -92
- package/dist/utils/thread-lock.js.map +1 -1
- package/dist/utils/token-estimator.js +12 -12
- package/dist/utils/token-estimator.js.map +1 -1
- package/dist/utils/update-check.d.ts +1 -1
- package/dist/utils/update-check.js +341 -259
- package/dist/utils/update-check.js.map +1 -1
- package/dist/voice/stt-registry.js +131 -113
- package/dist/voice/stt-registry.js.map +1 -1
- package/package.json +11 -11
- package/dist/acp.js.map +0 -1
- package/dist/auth/index.js.map +0 -1
- package/dist/auth/types.js.map +0 -1
- package/dist/evals/index.js.map +0 -1
- package/dist/evals/scorers/index.js.map +0 -1
- package/dist/headless/index.js.map +0 -1
- package/dist/hooks/index.js.map +0 -1
- package/dist/lsp/index.js.map +0 -1
- package/dist/mcp/index.js.map +0 -1
- package/dist/mcp/types.js.map +0 -1
- package/dist/onboarding/index.js.map +0 -1
- package/dist/plugins/types.js.map +0 -1
- package/dist/tools/index.js.map +0 -1
package/dist/plugins/registry.js
CHANGED
|
@@ -1,96 +1,112 @@
|
|
|
1
|
-
import fs from "
|
|
2
|
-
import path from "
|
|
3
|
-
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
//#region src/plugins/registry.ts
|
|
4
|
+
const EMPTY_PLUGIN_REGISTRY = {
|
|
5
|
+
plugins: {},
|
|
6
|
+
disabledPlugins: []
|
|
7
|
+
};
|
|
4
8
|
function loadPluginRegistry(registryPath) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
try {
|
|
10
|
+
if (!fs.existsSync(registryPath)) return {
|
|
11
|
+
plugins: {},
|
|
12
|
+
disabledPlugins: []
|
|
13
|
+
};
|
|
14
|
+
return validatePluginRegistry(JSON.parse(fs.readFileSync(registryPath, "utf-8")));
|
|
15
|
+
} catch {
|
|
16
|
+
return {
|
|
17
|
+
plugins: {},
|
|
18
|
+
disabledPlugins: []
|
|
19
|
+
};
|
|
20
|
+
}
|
|
12
21
|
}
|
|
13
22
|
function savePluginRegistry(registryPath, registry) {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
`);
|
|
23
|
+
fs.mkdirSync(path.dirname(registryPath), { recursive: true });
|
|
24
|
+
fs.writeFileSync(registryPath, `${JSON.stringify(validatePluginRegistry(registry), null, 2)}\n`);
|
|
17
25
|
}
|
|
18
26
|
function mergePluginRegistries(globalRegistry, projectRegistry) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const merged = /* @__PURE__ */ new Map();
|
|
28
|
+
const disabledPlugins = /* @__PURE__ */ new Set([...globalRegistry.disabledPlugins ?? [], ...projectRegistry.disabledPlugins ?? []]);
|
|
29
|
+
for (const [id, record] of Object.entries(globalRegistry.plugins)) merged.set(id, {
|
|
30
|
+
id,
|
|
31
|
+
scope: "global",
|
|
32
|
+
...record
|
|
33
|
+
});
|
|
34
|
+
for (const [id, record] of Object.entries(projectRegistry.plugins)) merged.set(id, {
|
|
35
|
+
id,
|
|
36
|
+
scope: "project",
|
|
37
|
+
...record
|
|
38
|
+
});
|
|
39
|
+
return [...merged.values()].map((record) => disabledPlugins.has(record.id) ? {
|
|
40
|
+
...record,
|
|
41
|
+
blocked: true
|
|
42
|
+
} : record).sort((a, b) => {
|
|
43
|
+
if (a.scope !== b.scope) return a.scope === "project" ? -1 : 1;
|
|
44
|
+
return a.id.localeCompare(b.id);
|
|
45
|
+
});
|
|
34
46
|
}
|
|
35
47
|
function setPluginRecord(registry, pluginId, record) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
return {
|
|
49
|
+
plugins: {
|
|
50
|
+
...registry.plugins,
|
|
51
|
+
[pluginId]: record
|
|
52
|
+
},
|
|
53
|
+
disabledPlugins: registry.disabledPlugins ?? []
|
|
54
|
+
};
|
|
43
55
|
}
|
|
44
56
|
function removePluginRecord(registry, pluginId) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
const plugins = { ...registry.plugins };
|
|
58
|
+
delete plugins[pluginId];
|
|
59
|
+
return {
|
|
60
|
+
plugins,
|
|
61
|
+
disabledPlugins: registry.disabledPlugins ?? []
|
|
62
|
+
};
|
|
48
63
|
}
|
|
49
64
|
function validatePluginRegistry(raw) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
if (!raw || typeof raw !== "object") return {
|
|
66
|
+
plugins: {},
|
|
67
|
+
disabledPlugins: []
|
|
68
|
+
};
|
|
69
|
+
const plugins = raw.plugins;
|
|
70
|
+
if (!plugins || typeof plugins !== "object" || Array.isArray(plugins)) return {
|
|
71
|
+
plugins: {},
|
|
72
|
+
disabledPlugins: []
|
|
73
|
+
};
|
|
74
|
+
const disabledPlugins = raw.disabledPlugins;
|
|
75
|
+
const validated = {
|
|
76
|
+
plugins: {},
|
|
77
|
+
disabledPlugins: Array.isArray(disabledPlugins) ? [...new Set(disabledPlugins.filter((pluginId) => typeof pluginId === "string"))].sort() : []
|
|
78
|
+
};
|
|
79
|
+
for (const [id, value] of Object.entries(plugins)) {
|
|
80
|
+
if (typeof id !== "string" || id.trim().length === 0) continue;
|
|
81
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) continue;
|
|
82
|
+
const record = value;
|
|
83
|
+
if (typeof record.enabled !== "boolean") continue;
|
|
84
|
+
if (record.source !== "local" && record.source !== "github") continue;
|
|
85
|
+
if (typeof record.specifier !== "string") continue;
|
|
86
|
+
if (typeof record.path !== "string") continue;
|
|
87
|
+
if (typeof record.entry !== "string") continue;
|
|
88
|
+
validated.plugins[id] = {
|
|
89
|
+
enabled: record.enabled,
|
|
90
|
+
source: record.source,
|
|
91
|
+
specifier: record.specifier,
|
|
92
|
+
path: record.path,
|
|
93
|
+
entry: record.entry,
|
|
94
|
+
...typeof record.ref === "string" ? { ref: record.ref } : {},
|
|
95
|
+
...typeof record.version === "string" ? { version: record.version } : {},
|
|
96
|
+
...record.config && typeof record.config === "object" && !Array.isArray(record.config) ? { config: validatePluginConfigValues(record.config) } : {}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
return validated;
|
|
79
100
|
}
|
|
80
101
|
function validatePluginConfigValues(raw) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
102
|
+
const values = {};
|
|
103
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
104
|
+
if (typeof key !== "string" || key.trim().length === 0) continue;
|
|
105
|
+
if (typeof value === "string" || typeof value === "boolean") values[key] = value;
|
|
106
|
+
}
|
|
107
|
+
return values;
|
|
87
108
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
mergePluginRegistries,
|
|
92
|
-
removePluginRecord,
|
|
93
|
-
savePluginRegistry,
|
|
94
|
-
setPluginRecord
|
|
95
|
-
};
|
|
109
|
+
//#endregion
|
|
110
|
+
export { EMPTY_PLUGIN_REGISTRY, loadPluginRegistry, mergePluginRegistries, removePluginRecord, savePluginRegistry, setPluginRecord };
|
|
111
|
+
|
|
96
112
|
//# sourceMappingURL=registry.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/registry.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { InstalledPluginRecord, PluginRegistry, ScopedInstalledPluginRecord } from './types.js';\n\nexport const EMPTY_PLUGIN_REGISTRY: PluginRegistry = { plugins: {}, disabledPlugins: [] };\n\nexport function loadPluginRegistry(registryPath: string): PluginRegistry {\n try {\n if (!fs.existsSync(registryPath)) return { plugins: {}, disabledPlugins: [] };\n const raw = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as unknown;\n return validatePluginRegistry(raw);\n } catch {\n return { plugins: {}, disabledPlugins: [] };\n }\n}\n\nexport function savePluginRegistry(registryPath: string, registry: PluginRegistry): void {\n fs.mkdirSync(path.dirname(registryPath), { recursive: true });\n fs.writeFileSync(registryPath, `${JSON.stringify(validatePluginRegistry(registry), null, 2)}\\n`);\n}\n\nexport function mergePluginRegistries(\n globalRegistry: PluginRegistry,\n projectRegistry: PluginRegistry,\n): ScopedInstalledPluginRecord[] {\n const merged = new Map<string, ScopedInstalledPluginRecord>();\n const disabledPlugins = new Set([\n ...(globalRegistry.disabledPlugins ?? []),\n ...(projectRegistry.disabledPlugins ?? []),\n ]);\n\n for (const [id, record] of Object.entries(globalRegistry.plugins)) {\n merged.set(id, { id, scope: 'global', ...record });\n }\n\n for (const [id, record] of Object.entries(projectRegistry.plugins)) {\n merged.set(id, { id, scope: 'project', ...record });\n }\n\n return [...merged.values()]\n .map(record => (disabledPlugins.has(record.id) ? { ...record, blocked: true } : record))\n .sort((a, b) => {\n if (a.scope !== b.scope) return a.scope === 'project' ? -1 : 1;\n return a.id.localeCompare(b.id);\n });\n}\n\nexport function setPluginRecord(\n registry: PluginRegistry,\n pluginId: string,\n record: InstalledPluginRecord,\n): PluginRegistry {\n return {\n plugins: {\n ...registry.plugins,\n [pluginId]: record,\n },\n disabledPlugins: registry.disabledPlugins ?? [],\n };\n}\n\nexport function removePluginRecord(registry: PluginRegistry, pluginId: string): PluginRegistry {\n const plugins = { ...registry.plugins };\n delete plugins[pluginId];\n return { plugins, disabledPlugins: registry.disabledPlugins ?? [] };\n}\n\nfunction validatePluginRegistry(raw: unknown): PluginRegistry {\n if (!raw || typeof raw !== 'object') return { plugins: {}, disabledPlugins: [] };\n const plugins = (raw as { plugins?: unknown }).plugins;\n if (!plugins || typeof plugins !== 'object' || Array.isArray(plugins)) return { plugins: {}, disabledPlugins: [] };\n\n const disabledPlugins = (raw as { disabledPlugins?: unknown }).disabledPlugins;\n const validated: PluginRegistry = {\n plugins: {},\n disabledPlugins: Array.isArray(disabledPlugins)\n ? [...new Set(disabledPlugins.filter((pluginId): pluginId is string => typeof pluginId === 'string'))].sort()\n : [],\n };\n for (const [id, value] of Object.entries(plugins)) {\n if (typeof id !== 'string' || id.trim().length === 0) continue;\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue;\n const record = value as Record<string, unknown>;\n if (typeof record.enabled !== 'boolean') continue;\n if (record.source !== 'local' && record.source !== 'github') continue;\n if (typeof record.specifier !== 'string') continue;\n if (typeof record.path !== 'string') continue;\n if (typeof record.entry !== 'string') continue;\n\n validated.plugins[id] = {\n enabled: record.enabled,\n source: record.source,\n specifier: record.specifier,\n path: record.path,\n entry: record.entry,\n ...(typeof record.ref === 'string' ? { ref: record.ref } : {}),\n ...(typeof record.version === 'string' ? { version: record.version } : {}),\n ...(record.config && typeof record.config === 'object' && !Array.isArray(record.config)\n ? { config: validatePluginConfigValues(record.config) }\n : {}),\n };\n }\n\n return validated;\n}\n\nfunction validatePluginConfigValues(raw: object): Record<string, string | boolean> {\n const values: Record<string, string | boolean> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (typeof key !== 'string' || key.trim().length === 0) continue;\n if (typeof value === 'string' || typeof value === 'boolean') values[key] = value;\n }\n return values;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"registry.js","names":[],"sources":["../../src/plugins/registry.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport type { InstalledPluginRecord, PluginRegistry, ScopedInstalledPluginRecord } from './types.js';\n\nexport const EMPTY_PLUGIN_REGISTRY: PluginRegistry = { plugins: {}, disabledPlugins: [] };\n\nexport function loadPluginRegistry(registryPath: string): PluginRegistry {\n try {\n if (!fs.existsSync(registryPath)) return { plugins: {}, disabledPlugins: [] };\n const raw = JSON.parse(fs.readFileSync(registryPath, 'utf-8')) as unknown;\n return validatePluginRegistry(raw);\n } catch {\n return { plugins: {}, disabledPlugins: [] };\n }\n}\n\nexport function savePluginRegistry(registryPath: string, registry: PluginRegistry): void {\n fs.mkdirSync(path.dirname(registryPath), { recursive: true });\n fs.writeFileSync(registryPath, `${JSON.stringify(validatePluginRegistry(registry), null, 2)}\\n`);\n}\n\nexport function mergePluginRegistries(\n globalRegistry: PluginRegistry,\n projectRegistry: PluginRegistry,\n): ScopedInstalledPluginRecord[] {\n const merged = new Map<string, ScopedInstalledPluginRecord>();\n const disabledPlugins = new Set([\n ...(globalRegistry.disabledPlugins ?? []),\n ...(projectRegistry.disabledPlugins ?? []),\n ]);\n\n for (const [id, record] of Object.entries(globalRegistry.plugins)) {\n merged.set(id, { id, scope: 'global', ...record });\n }\n\n for (const [id, record] of Object.entries(projectRegistry.plugins)) {\n merged.set(id, { id, scope: 'project', ...record });\n }\n\n return [...merged.values()]\n .map(record => (disabledPlugins.has(record.id) ? { ...record, blocked: true } : record))\n .sort((a, b) => {\n if (a.scope !== b.scope) return a.scope === 'project' ? -1 : 1;\n return a.id.localeCompare(b.id);\n });\n}\n\nexport function setPluginRecord(\n registry: PluginRegistry,\n pluginId: string,\n record: InstalledPluginRecord,\n): PluginRegistry {\n return {\n plugins: {\n ...registry.plugins,\n [pluginId]: record,\n },\n disabledPlugins: registry.disabledPlugins ?? [],\n };\n}\n\nexport function removePluginRecord(registry: PluginRegistry, pluginId: string): PluginRegistry {\n const plugins = { ...registry.plugins };\n delete plugins[pluginId];\n return { plugins, disabledPlugins: registry.disabledPlugins ?? [] };\n}\n\nfunction validatePluginRegistry(raw: unknown): PluginRegistry {\n if (!raw || typeof raw !== 'object') return { plugins: {}, disabledPlugins: [] };\n const plugins = (raw as { plugins?: unknown }).plugins;\n if (!plugins || typeof plugins !== 'object' || Array.isArray(plugins)) return { plugins: {}, disabledPlugins: [] };\n\n const disabledPlugins = (raw as { disabledPlugins?: unknown }).disabledPlugins;\n const validated: PluginRegistry = {\n plugins: {},\n disabledPlugins: Array.isArray(disabledPlugins)\n ? [...new Set(disabledPlugins.filter((pluginId): pluginId is string => typeof pluginId === 'string'))].sort()\n : [],\n };\n for (const [id, value] of Object.entries(plugins)) {\n if (typeof id !== 'string' || id.trim().length === 0) continue;\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue;\n const record = value as Record<string, unknown>;\n if (typeof record.enabled !== 'boolean') continue;\n if (record.source !== 'local' && record.source !== 'github') continue;\n if (typeof record.specifier !== 'string') continue;\n if (typeof record.path !== 'string') continue;\n if (typeof record.entry !== 'string') continue;\n\n validated.plugins[id] = {\n enabled: record.enabled,\n source: record.source,\n specifier: record.specifier,\n path: record.path,\n entry: record.entry,\n ...(typeof record.ref === 'string' ? { ref: record.ref } : {}),\n ...(typeof record.version === 'string' ? { version: record.version } : {}),\n ...(record.config && typeof record.config === 'object' && !Array.isArray(record.config)\n ? { config: validatePluginConfigValues(record.config) }\n : {}),\n };\n }\n\n return validated;\n}\n\nfunction validatePluginConfigValues(raw: object): Record<string, string | boolean> {\n const values: Record<string, string | boolean> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (typeof key !== 'string' || key.trim().length === 0) continue;\n if (typeof value === 'string' || typeof value === 'boolean') values[key] = value;\n }\n return values;\n}\n"],"mappings":"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"}
|
package/dist/plugins/scaffold.js
CHANGED
|
@@ -1,107 +1,73 @@
|
|
|
1
|
-
import
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { DEFAULT_CONFIG_DIR } from "../constants.js";
|
|
1
|
+
import "../constants.js";
|
|
4
2
|
import { upsertPluginManifestEntry } from "./manifest.js";
|
|
5
3
|
import { ensureMastraCodePackageLink } from "./package-link.js";
|
|
4
|
+
import fs from "fs";
|
|
5
|
+
import path from "path";
|
|
6
|
+
//#region src/plugins/scaffold.ts
|
|
6
7
|
function resolveScaffoldTarget(target, options = {}) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
options.projectRoot ?? process.cwd(),
|
|
10
|
-
options.configDir ?? DEFAULT_CONFIG_DIR,
|
|
11
|
-
"plugins",
|
|
12
|
-
"sources",
|
|
13
|
-
"local",
|
|
14
|
-
target
|
|
15
|
-
);
|
|
16
|
-
}
|
|
17
|
-
return path.resolve(options.projectRoot ?? process.cwd(), target);
|
|
8
|
+
if (isBarePluginName(target)) return path.join(options.projectRoot ?? process.cwd(), options.configDir ?? ".mastracode", "plugins", "sources", "local", target);
|
|
9
|
+
return path.resolve(options.projectRoot ?? process.cwd(), target);
|
|
18
10
|
}
|
|
19
11
|
function scaffoldPlugin(targetDir, options = {}) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
`${JSON.stringify(
|
|
53
|
-
{
|
|
54
|
-
compilerOptions: {
|
|
55
|
-
target: "ES2024",
|
|
56
|
-
module: "NodeNext",
|
|
57
|
-
moduleResolution: "NodeNext",
|
|
58
|
-
strict: true,
|
|
59
|
-
verbatimModuleSyntax: true,
|
|
60
|
-
erasableSyntaxOnly: true,
|
|
61
|
-
skipLibCheck: true,
|
|
62
|
-
noEmit: true
|
|
63
|
-
},
|
|
64
|
-
include: ["src/**/*.ts"]
|
|
65
|
-
},
|
|
66
|
-
null,
|
|
67
|
-
2
|
|
68
|
-
)}
|
|
69
|
-
`
|
|
70
|
-
);
|
|
71
|
-
fs.writeFileSync(path.join(dir, "src/index.ts"), renderIndex(pluginId, pluginName));
|
|
72
|
-
fs.writeFileSync(path.join(dir, "README.md"), renderReadme(pluginName, pluginId));
|
|
73
|
-
writeScaffoldManifest(targetDir, dir, pluginId, pluginName, options);
|
|
74
|
-
ensureMastraCodePackageLink(dir);
|
|
75
|
-
return dir;
|
|
12
|
+
const dir = resolveScaffoldTarget(targetDir, options);
|
|
13
|
+
if (fs.existsSync(dir) && fs.readdirSync(dir).length > 0) throw new Error(`Directory already exists and is not empty: ${targetDir}`);
|
|
14
|
+
const packageName = path.basename(dir).toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/^-|-$/g, "") || "mastracode-plugin";
|
|
15
|
+
const pluginId = options.id ?? packageName;
|
|
16
|
+
const pluginName = options.name ?? humanizeName(packageName);
|
|
17
|
+
fs.mkdirSync(path.join(dir, "src"), { recursive: true });
|
|
18
|
+
fs.writeFileSync(path.join(dir, "package.json"), `${JSON.stringify({
|
|
19
|
+
name: packageName,
|
|
20
|
+
type: "module",
|
|
21
|
+
exports: "./src/index.ts",
|
|
22
|
+
peerDependencies: { mastracode: "*" },
|
|
23
|
+
devDependencies: { typescript: "^5.9.3" },
|
|
24
|
+
scripts: { check: "tsc --noEmit" }
|
|
25
|
+
}, null, 2)}\n`);
|
|
26
|
+
fs.writeFileSync(path.join(dir, "tsconfig.json"), `${JSON.stringify({
|
|
27
|
+
compilerOptions: {
|
|
28
|
+
target: "ES2024",
|
|
29
|
+
module: "NodeNext",
|
|
30
|
+
moduleResolution: "NodeNext",
|
|
31
|
+
strict: true,
|
|
32
|
+
verbatimModuleSyntax: true,
|
|
33
|
+
erasableSyntaxOnly: true,
|
|
34
|
+
skipLibCheck: true,
|
|
35
|
+
noEmit: true
|
|
36
|
+
},
|
|
37
|
+
include: ["src/**/*.ts"]
|
|
38
|
+
}, null, 2)}\n`);
|
|
39
|
+
fs.writeFileSync(path.join(dir, "src/index.ts"), renderIndex(pluginId, pluginName));
|
|
40
|
+
fs.writeFileSync(path.join(dir, "README.md"), renderReadme(pluginName, pluginId));
|
|
41
|
+
writeScaffoldManifest(targetDir, dir, pluginId, pluginName, options);
|
|
42
|
+
ensureMastraCodePackageLink(dir);
|
|
43
|
+
return dir;
|
|
76
44
|
}
|
|
77
45
|
function writeScaffoldManifest(originalTarget, scaffoldDir, pluginId, pluginName, options) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
entry: entry.split(path.sep).join("/")
|
|
85
|
-
});
|
|
46
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
47
|
+
upsertPluginManifestEntry(isBarePluginName(originalTarget) ? projectRoot : scaffoldDir, {
|
|
48
|
+
id: pluginId,
|
|
49
|
+
name: pluginName,
|
|
50
|
+
entry: (isBarePluginName(originalTarget) ? path.join(path.relative(projectRoot, scaffoldDir), "src/index.ts") : "src/index.ts").split(path.sep).join("/")
|
|
51
|
+
});
|
|
86
52
|
}
|
|
87
53
|
function formatScaffoldSuccess(targetDir) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
54
|
+
return [
|
|
55
|
+
`Created Mastra Code plugin scaffold at ${targetDir}`,
|
|
56
|
+
"",
|
|
57
|
+
"Next steps:",
|
|
58
|
+
` cd ${targetDir}`,
|
|
59
|
+
" pnpm install",
|
|
60
|
+
" pnpm check",
|
|
61
|
+
" mastracode",
|
|
62
|
+
" /plugins",
|
|
63
|
+
" Install new plugin → Local path"
|
|
64
|
+
].join("\n");
|
|
99
65
|
}
|
|
100
66
|
function isBarePluginName(target) {
|
|
101
|
-
|
|
67
|
+
return !path.isAbsolute(target) && !target.startsWith(".") && !target.includes("/") && !target.includes("\\");
|
|
102
68
|
}
|
|
103
69
|
function renderIndex(pluginId, pluginName) {
|
|
104
|
-
|
|
70
|
+
return `import { createTool, defineMastraCodePlugin, z } from 'mastracode/plugin';
|
|
105
71
|
|
|
106
72
|
export default defineMastraCodePlugin({
|
|
107
73
|
id: ${JSON.stringify(pluginId)},
|
|
@@ -125,7 +91,7 @@ export default defineMastraCodePlugin({
|
|
|
125
91
|
`;
|
|
126
92
|
}
|
|
127
93
|
function renderReadme(pluginName, pluginId) {
|
|
128
|
-
|
|
94
|
+
return `# ${pluginName}
|
|
129
95
|
|
|
130
96
|
Mastra Code tool plugin: \`${pluginId}\`.
|
|
131
97
|
|
|
@@ -142,11 +108,9 @@ Open Mastra Code, run \`/plugins\`, and install this directory as a local plugin
|
|
|
142
108
|
`;
|
|
143
109
|
}
|
|
144
110
|
function humanizeName(value) {
|
|
145
|
-
|
|
111
|
+
return value.split(/[-_.]+/g).filter(Boolean).map((part) => part[0]?.toUpperCase() + part.slice(1)).join(" ") || "Mastra Code Plugin";
|
|
146
112
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
scaffoldPlugin
|
|
151
|
-
};
|
|
113
|
+
//#endregion
|
|
114
|
+
export { formatScaffoldSuccess, resolveScaffoldTarget, scaffoldPlugin };
|
|
115
|
+
|
|
152
116
|
//# sourceMappingURL=scaffold.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/scaffold.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { upsertPluginManifestEntry } from './manifest.js';\nimport { ensureMastraCodePackageLink } from './package-link.js';\n\nexport type ScaffoldPluginOptions = {\n id?: string;\n name?: string;\n projectRoot?: string;\n configDir?: string;\n};\n\nexport function resolveScaffoldTarget(\n target: string,\n options: Pick<ScaffoldPluginOptions, 'projectRoot' | 'configDir'> = {},\n): string {\n if (isBarePluginName(target)) {\n return path.join(\n options.projectRoot ?? process.cwd(),\n options.configDir ?? DEFAULT_CONFIG_DIR,\n 'plugins',\n 'sources',\n 'local',\n target,\n );\n }\n return path.resolve(options.projectRoot ?? process.cwd(), target);\n}\n\nexport function scaffoldPlugin(targetDir: string, options: ScaffoldPluginOptions = {}): string {\n const dir = resolveScaffoldTarget(targetDir, options);\n if (fs.existsSync(dir) && fs.readdirSync(dir).length > 0) {\n throw new Error(`Directory already exists and is not empty: ${targetDir}`);\n }\n\n const packageName =\n path\n .basename(dir)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]+/g, '-')\n .replace(/^-|-$/g, '') || 'mastracode-plugin';\n const pluginId = options.id ?? packageName;\n const pluginName = options.name ?? humanizeName(packageName);\n\n fs.mkdirSync(path.join(dir, 'src'), { recursive: true });\n fs.writeFileSync(\n path.join(dir, 'package.json'),\n `${JSON.stringify(\n {\n name: packageName,\n type: 'module',\n exports: './src/index.ts',\n peerDependencies: {\n mastracode: '*',\n },\n devDependencies: {\n typescript: '^5.9.3',\n },\n scripts: {\n check: 'tsc --noEmit',\n },\n },\n null,\n 2,\n )}\\n`,\n );\n fs.writeFileSync(\n path.join(dir, 'tsconfig.json'),\n `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2024',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n strict: true,\n verbatimModuleSyntax: true,\n erasableSyntaxOnly: true,\n skipLibCheck: true,\n noEmit: true,\n },\n include: ['src/**/*.ts'],\n },\n null,\n 2,\n )}\\n`,\n );\n fs.writeFileSync(path.join(dir, 'src/index.ts'), renderIndex(pluginId, pluginName));\n fs.writeFileSync(path.join(dir, 'README.md'), renderReadme(pluginName, pluginId));\n writeScaffoldManifest(targetDir, dir, pluginId, pluginName, options);\n ensureMastraCodePackageLink(dir);\n return dir;\n}\n\nfunction writeScaffoldManifest(\n originalTarget: string,\n scaffoldDir: string,\n pluginId: string,\n pluginName: string,\n options: ScaffoldPluginOptions,\n): void {\n const projectRoot = options.projectRoot ?? process.cwd();\n const manifestRoot = isBarePluginName(originalTarget) ? projectRoot : scaffoldDir;\n const entry = isBarePluginName(originalTarget)\n ? path.join(path.relative(projectRoot, scaffoldDir), 'src/index.ts')\n : 'src/index.ts';\n upsertPluginManifestEntry(manifestRoot, {\n id: pluginId,\n name: pluginName,\n entry: entry.split(path.sep).join('/'),\n });\n}\n\nexport function formatScaffoldSuccess(targetDir: string): string {\n return [\n `Created Mastra Code plugin scaffold at ${targetDir}`,\n '',\n 'Next steps:',\n ` cd ${targetDir}`,\n ' pnpm install',\n ' pnpm check',\n ' mastracode',\n ' /plugins',\n ' Install new plugin → Local path',\n ].join('\\n');\n}\n\nfunction isBarePluginName(target: string): boolean {\n return !path.isAbsolute(target) && !target.startsWith('.') && !target.includes('/') && !target.includes('\\\\');\n}\n\nfunction renderIndex(pluginId: string, pluginName: string): string {\n return `import { createTool, defineMastraCodePlugin, z } from 'mastracode/plugin';\n\nexport default defineMastraCodePlugin({\n id: ${JSON.stringify(pluginId)},\n name: ${JSON.stringify(pluginName)},\n description: 'A Mastra Code tool plugin.',\n tools: {\n example_tool: {\n tool: createTool({\n id: 'example_tool',\n description: 'Echo a message from the scaffolded plugin.',\n inputSchema: z.object({\n message: z.string(),\n }),\n execute: async context => {\n return { message: context.message };\n },\n }),\n },\n },\n});\n`;\n}\n\nfunction renderReadme(pluginName: string, pluginId: string): string {\n return `# ${pluginName}\n\nMastra Code tool plugin: \\`${pluginId}\\`.\n\n## Develop\n\n\\`\\`\\`sh\npnpm install\npnpm check\n\\`\\`\\`\n\n## Install locally\n\nOpen Mastra Code, run \\`/plugins\\`, and install this directory as a local plugin.\n`;\n}\n\nfunction humanizeName(value: string): string {\n return (\n value\n .split(/[-_.]+/g)\n .filter(Boolean)\n .map(part => part[0]?.toUpperCase() + part.slice(1))\n .join(' ') || 'Mastra Code Plugin'\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"scaffold.js","names":[],"sources":["../../src/plugins/scaffold.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\n\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { upsertPluginManifestEntry } from './manifest.js';\nimport { ensureMastraCodePackageLink } from './package-link.js';\n\nexport type ScaffoldPluginOptions = {\n id?: string;\n name?: string;\n projectRoot?: string;\n configDir?: string;\n};\n\nexport function resolveScaffoldTarget(\n target: string,\n options: Pick<ScaffoldPluginOptions, 'projectRoot' | 'configDir'> = {},\n): string {\n if (isBarePluginName(target)) {\n return path.join(\n options.projectRoot ?? process.cwd(),\n options.configDir ?? DEFAULT_CONFIG_DIR,\n 'plugins',\n 'sources',\n 'local',\n target,\n );\n }\n return path.resolve(options.projectRoot ?? process.cwd(), target);\n}\n\nexport function scaffoldPlugin(targetDir: string, options: ScaffoldPluginOptions = {}): string {\n const dir = resolveScaffoldTarget(targetDir, options);\n if (fs.existsSync(dir) && fs.readdirSync(dir).length > 0) {\n throw new Error(`Directory already exists and is not empty: ${targetDir}`);\n }\n\n const packageName =\n path\n .basename(dir)\n .toLowerCase()\n .replace(/[^a-z0-9_.-]+/g, '-')\n .replace(/^-|-$/g, '') || 'mastracode-plugin';\n const pluginId = options.id ?? packageName;\n const pluginName = options.name ?? humanizeName(packageName);\n\n fs.mkdirSync(path.join(dir, 'src'), { recursive: true });\n fs.writeFileSync(\n path.join(dir, 'package.json'),\n `${JSON.stringify(\n {\n name: packageName,\n type: 'module',\n exports: './src/index.ts',\n peerDependencies: {\n mastracode: '*',\n },\n devDependencies: {\n typescript: '^5.9.3',\n },\n scripts: {\n check: 'tsc --noEmit',\n },\n },\n null,\n 2,\n )}\\n`,\n );\n fs.writeFileSync(\n path.join(dir, 'tsconfig.json'),\n `${JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2024',\n module: 'NodeNext',\n moduleResolution: 'NodeNext',\n strict: true,\n verbatimModuleSyntax: true,\n erasableSyntaxOnly: true,\n skipLibCheck: true,\n noEmit: true,\n },\n include: ['src/**/*.ts'],\n },\n null,\n 2,\n )}\\n`,\n );\n fs.writeFileSync(path.join(dir, 'src/index.ts'), renderIndex(pluginId, pluginName));\n fs.writeFileSync(path.join(dir, 'README.md'), renderReadme(pluginName, pluginId));\n writeScaffoldManifest(targetDir, dir, pluginId, pluginName, options);\n ensureMastraCodePackageLink(dir);\n return dir;\n}\n\nfunction writeScaffoldManifest(\n originalTarget: string,\n scaffoldDir: string,\n pluginId: string,\n pluginName: string,\n options: ScaffoldPluginOptions,\n): void {\n const projectRoot = options.projectRoot ?? process.cwd();\n const manifestRoot = isBarePluginName(originalTarget) ? projectRoot : scaffoldDir;\n const entry = isBarePluginName(originalTarget)\n ? path.join(path.relative(projectRoot, scaffoldDir), 'src/index.ts')\n : 'src/index.ts';\n upsertPluginManifestEntry(manifestRoot, {\n id: pluginId,\n name: pluginName,\n entry: entry.split(path.sep).join('/'),\n });\n}\n\nexport function formatScaffoldSuccess(targetDir: string): string {\n return [\n `Created Mastra Code plugin scaffold at ${targetDir}`,\n '',\n 'Next steps:',\n ` cd ${targetDir}`,\n ' pnpm install',\n ' pnpm check',\n ' mastracode',\n ' /plugins',\n ' Install new plugin → Local path',\n ].join('\\n');\n}\n\nfunction isBarePluginName(target: string): boolean {\n return !path.isAbsolute(target) && !target.startsWith('.') && !target.includes('/') && !target.includes('\\\\');\n}\n\nfunction renderIndex(pluginId: string, pluginName: string): string {\n return `import { createTool, defineMastraCodePlugin, z } from 'mastracode/plugin';\n\nexport default defineMastraCodePlugin({\n id: ${JSON.stringify(pluginId)},\n name: ${JSON.stringify(pluginName)},\n description: 'A Mastra Code tool plugin.',\n tools: {\n example_tool: {\n tool: createTool({\n id: 'example_tool',\n description: 'Echo a message from the scaffolded plugin.',\n inputSchema: z.object({\n message: z.string(),\n }),\n execute: async context => {\n return { message: context.message };\n },\n }),\n },\n },\n});\n`;\n}\n\nfunction renderReadme(pluginName: string, pluginId: string): string {\n return `# ${pluginName}\n\nMastra Code tool plugin: \\`${pluginId}\\`.\n\n## Develop\n\n\\`\\`\\`sh\npnpm install\npnpm check\n\\`\\`\\`\n\n## Install locally\n\nOpen Mastra Code, run \\`/plugins\\`, and install this directory as a local plugin.\n`;\n}\n\nfunction humanizeName(value: string): string {\n return (\n value\n .split(/[-_.]+/g)\n .filter(Boolean)\n .map(part => part[0]?.toUpperCase() + part.slice(1))\n .join(' ') || 'Mastra Code Plugin'\n );\n}\n"],"mappings":"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"}
|
package/dist/plugins/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
export {};
|
|
@@ -1,53 +1,54 @@
|
|
|
1
|
+
//#region src/processors/plan-rejection-abort.ts
|
|
1
2
|
const PLAN_REJECTED_PREFIX = "Plan was not approved";
|
|
2
3
|
function resultText(result) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
if (typeof result === "string") return result;
|
|
5
|
+
if (result && typeof result === "object") {
|
|
6
|
+
const content = result.content;
|
|
7
|
+
if (typeof content === "string") return content;
|
|
8
|
+
}
|
|
9
|
+
return "";
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns true when the invocation is a completed `submit_plan` rejection.
|
|
13
|
+
*/
|
|
10
14
|
function isPlanRejection(inv) {
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
if (!inv || inv.state !== "result" || inv.toolName !== "submit_plan") return false;
|
|
16
|
+
return resultText(inv.result).startsWith(PLAN_REJECTED_PREFIX);
|
|
13
17
|
}
|
|
14
18
|
function isPlanRejectionResultPart(part) {
|
|
15
|
-
|
|
19
|
+
return part.type === "tool_result" && part.name === "submit_plan" && resultText(part.result).startsWith(PLAN_REJECTED_PREFIX);
|
|
16
20
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}
|
|
47
|
-
return void 0;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
export {
|
|
51
|
-
PlanRejectionAbortProcessor
|
|
21
|
+
var PlanRejectionAbortProcessor = class {
|
|
22
|
+
id = "plan-rejection-abort";
|
|
23
|
+
async processInputStep({ messages, stepNumber, abort }) {
|
|
24
|
+
if (stepNumber === 0) return void 0;
|
|
25
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
26
|
+
const msg = messages[i];
|
|
27
|
+
if (!msg || msg.role !== "assistant") continue;
|
|
28
|
+
const content = msg.content;
|
|
29
|
+
const parts = Array.isArray(content) ? content : Array.isArray(content?.parts) ? content.parts : [];
|
|
30
|
+
for (const part of parts) {
|
|
31
|
+
if (!part || typeof part !== "object") continue;
|
|
32
|
+
const p = part;
|
|
33
|
+
if (p.type === "tool-invocation" && isPlanRejection(p.toolInvocation)) {
|
|
34
|
+
abort("Plan rejected by user — no further response needed");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (isPlanRejectionResultPart(p)) {
|
|
38
|
+
abort("Plan rejected by user — no further response needed");
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const legacy = !Array.isArray(content) && Array.isArray(content?.toolInvocations) ? content.toolInvocations : [];
|
|
43
|
+
for (const inv of legacy) if (isPlanRejection(inv)) {
|
|
44
|
+
abort("Plan rejected by user — no further response needed");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
52
50
|
};
|
|
51
|
+
//#endregion
|
|
52
|
+
export { PlanRejectionAbortProcessor };
|
|
53
|
+
|
|
53
54
|
//# sourceMappingURL=plan-rejection-abort.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/processors/plan-rejection-abort.ts"],"sourcesContent":["/**\n * Processor that aborts the agentic loop immediately after a `submit_plan` tool\n * returns a rejection result. This prevents the model from generating any text\n * after the user clicks \"Request Changes\" — the tool result is persisted in\n * thread history (for context on the next run) but no follow-up LLM call is made.\n */\nimport type { Processor, ProcessInputStepArgs } from '@mastra/core/processors';\n\nconst PLAN_REJECTED_PREFIX = 'Plan was not approved';\n\ntype ToolInvocation = {\n state?: string;\n toolName?: string;\n result?: unknown;\n};\n\ntype ToolResultPart = {\n type?: string;\n name?: string;\n result?: unknown;\n};\n\nfunction resultText(result: unknown): string {\n if (typeof result === 'string') return result;\n if (result && typeof result === 'object') {\n const content = (result as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n }\n return '';\n}\n\n/**\n * Returns true when the invocation is a completed `submit_plan` rejection.\n */\nfunction isPlanRejection(inv: ToolInvocation | undefined): boolean {\n if (!inv || inv.state !== 'result' || inv.toolName !== 'submit_plan') return false;\n return resultText(inv.result).startsWith(PLAN_REJECTED_PREFIX);\n}\n\nfunction isPlanRejectionResultPart(part: ToolResultPart): boolean {\n return (\n part.type === 'tool_result' &&\n part.name === 'submit_plan' &&\n resultText(part.result).startsWith(PLAN_REJECTED_PREFIX)\n );\n}\n\nexport class PlanRejectionAbortProcessor implements Processor<'plan-rejection-abort'> {\n id = 'plan-rejection-abort' as const;\n\n async processInputStep({ messages, stepNumber, abort }: ProcessInputStepArgs): Promise<undefined> {\n // Only act on continuation steps (stepNumber > 0) — step 0 is the initial\n // prompt where the model hasn't responded yet. After tool resume, the tool\n // result is part of step 0 and the loop advances to step 1 for the next\n // model call.\n if (stepNumber === 0) return undefined;\n\n // Walk messages from the end to find the last assistant message.\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (!msg || msg.role !== 'assistant') continue;\n\n // Check for a submit_plan rejection tool result. Handle the primary\n // `content.parts` shapes (tool-invocation and harness-style tool_result)\n // plus the legacy `content.toolInvocations` array.\n const content = msg.content as { parts?: unknown[]; toolInvocations?: unknown[] } | unknown[] | undefined;\n\n const parts = Array.isArray(content) ? content : Array.isArray(content?.parts) ? content.parts : [];\n for (const part of parts) {\n if (!part || typeof part !== 'object') continue;\n const p = part as { type?: string; toolInvocation?: ToolInvocation } & ToolResultPart;\n if (p.type === 'tool-invocation' && isPlanRejection(p.toolInvocation)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n if (isPlanRejectionResultPart(p)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n }\n\n const legacy = !Array.isArray(content) && Array.isArray(content?.toolInvocations) ? content.toolInvocations : [];\n for (const inv of legacy) {\n if (isPlanRejection(inv as ToolInvocation)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n }\n\n // Only check the most recent assistant message.\n break;\n }\n\n return undefined;\n }\n}\n"],"mappings":"AAQA,MAAM,uBAAuB;AAc7B,SAAS,WAAW,QAAyB;
|
|
1
|
+
{"version":3,"file":"plan-rejection-abort.js","names":[],"sources":["../../src/processors/plan-rejection-abort.ts"],"sourcesContent":["/**\n * Processor that aborts the agentic loop immediately after a `submit_plan` tool\n * returns a rejection result. This prevents the model from generating any text\n * after the user clicks \"Request Changes\" — the tool result is persisted in\n * thread history (for context on the next run) but no follow-up LLM call is made.\n */\nimport type { Processor, ProcessInputStepArgs } from '@mastra/core/processors';\n\nconst PLAN_REJECTED_PREFIX = 'Plan was not approved';\n\ntype ToolInvocation = {\n state?: string;\n toolName?: string;\n result?: unknown;\n};\n\ntype ToolResultPart = {\n type?: string;\n name?: string;\n result?: unknown;\n};\n\nfunction resultText(result: unknown): string {\n if (typeof result === 'string') return result;\n if (result && typeof result === 'object') {\n const content = (result as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n }\n return '';\n}\n\n/**\n * Returns true when the invocation is a completed `submit_plan` rejection.\n */\nfunction isPlanRejection(inv: ToolInvocation | undefined): boolean {\n if (!inv || inv.state !== 'result' || inv.toolName !== 'submit_plan') return false;\n return resultText(inv.result).startsWith(PLAN_REJECTED_PREFIX);\n}\n\nfunction isPlanRejectionResultPart(part: ToolResultPart): boolean {\n return (\n part.type === 'tool_result' &&\n part.name === 'submit_plan' &&\n resultText(part.result).startsWith(PLAN_REJECTED_PREFIX)\n );\n}\n\nexport class PlanRejectionAbortProcessor implements Processor<'plan-rejection-abort'> {\n id = 'plan-rejection-abort' as const;\n\n async processInputStep({ messages, stepNumber, abort }: ProcessInputStepArgs): Promise<undefined> {\n // Only act on continuation steps (stepNumber > 0) — step 0 is the initial\n // prompt where the model hasn't responded yet. After tool resume, the tool\n // result is part of step 0 and the loop advances to step 1 for the next\n // model call.\n if (stepNumber === 0) return undefined;\n\n // Walk messages from the end to find the last assistant message.\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (!msg || msg.role !== 'assistant') continue;\n\n // Check for a submit_plan rejection tool result. Handle the primary\n // `content.parts` shapes (tool-invocation and harness-style tool_result)\n // plus the legacy `content.toolInvocations` array.\n const content = msg.content as { parts?: unknown[]; toolInvocations?: unknown[] } | unknown[] | undefined;\n\n const parts = Array.isArray(content) ? content : Array.isArray(content?.parts) ? content.parts : [];\n for (const part of parts) {\n if (!part || typeof part !== 'object') continue;\n const p = part as { type?: string; toolInvocation?: ToolInvocation } & ToolResultPart;\n if (p.type === 'tool-invocation' && isPlanRejection(p.toolInvocation)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n if (isPlanRejectionResultPart(p)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n }\n\n const legacy = !Array.isArray(content) && Array.isArray(content?.toolInvocations) ? content.toolInvocations : [];\n for (const inv of legacy) {\n if (isPlanRejection(inv as ToolInvocation)) {\n abort('Plan rejected by user — no further response needed');\n return undefined;\n }\n }\n\n // Only check the most recent assistant message.\n break;\n }\n\n return undefined;\n }\n}\n"],"mappings":";AAQA,MAAM,uBAAuB;AAc7B,SAAS,WAAW,QAAyB;CAC3C,IAAI,OAAO,WAAW,UAAU,OAAO;CACvC,IAAI,UAAU,OAAO,WAAW,UAAU;EACxC,MAAM,UAAW,OAAiC;EAClD,IAAI,OAAO,YAAY,UAAU,OAAO;CAC1C;CACA,OAAO;AACT;;;;AAKA,SAAS,gBAAgB,KAA0C;CACjE,IAAI,CAAC,OAAO,IAAI,UAAU,YAAY,IAAI,aAAa,eAAe,OAAO;CAC7E,OAAO,WAAW,IAAI,MAAM,CAAC,CAAC,WAAW,oBAAoB;AAC/D;AAEA,SAAS,0BAA0B,MAA+B;CAChE,OACE,KAAK,SAAS,iBACd,KAAK,SAAS,iBACd,WAAW,KAAK,MAAM,CAAC,CAAC,WAAW,oBAAoB;AAE3D;AAEA,IAAa,8BAAb,MAAsF;CACpF,KAAK;CAEL,MAAM,iBAAiB,EAAE,UAAU,YAAY,SAAmD;EAKhG,IAAI,eAAe,GAAG,OAAO,KAAA;EAG7B,KAAK,IAAI,IAAI,SAAS,SAAS,GAAG,KAAK,GAAG,KAAK;GAC7C,MAAM,MAAM,SAAS;GACrB,IAAI,CAAC,OAAO,IAAI,SAAS,aAAa;GAKtC,MAAM,UAAU,IAAI;GAEpB,MAAM,QAAQ,MAAM,QAAQ,OAAO,IAAI,UAAU,MAAM,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC;GAClG,KAAK,MAAM,QAAQ,OAAO;IACxB,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;IACvC,MAAM,IAAI;IACV,IAAI,EAAE,SAAS,qBAAqB,gBAAgB,EAAE,cAAc,GAAG;KACrE,MAAM,oDAAoD;KAC1D;IACF;IACA,IAAI,0BAA0B,CAAC,GAAG;KAChC,MAAM,oDAAoD;KAC1D;IACF;GACF;GAEA,MAAM,SAAS,CAAC,MAAM,QAAQ,OAAO,KAAK,MAAM,QAAQ,SAAS,eAAe,IAAI,QAAQ,kBAAkB,CAAC;GAC/G,KAAK,MAAM,OAAO,QAChB,IAAI,gBAAgB,GAAqB,GAAG;IAC1C,MAAM,oDAAoD;IAC1D;GACF;GAIF;EACF;CAGF;AACF"}
|