@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/utils/plan-diff.js
CHANGED
|
@@ -1,43 +1,62 @@
|
|
|
1
|
+
//#region src/utils/plan-diff.ts
|
|
2
|
+
/** Produce structured diff entries between two plan texts using an LCS diff. */
|
|
1
3
|
function generatePlanDiff(oldText, newText) {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
4
|
+
const oldLines = oldText.split(/\r?\n/);
|
|
5
|
+
const newLines = newText.split(/\r?\n/);
|
|
6
|
+
const n = oldLines.length;
|
|
7
|
+
const m = newLines.length;
|
|
8
|
+
const lcs = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
|
|
9
|
+
for (let i = n - 1; i >= 0; i--) for (let j = m - 1; j >= 0; j--) lcs[i][j] = oldLines[i] === newLines[j] ? lcs[i + 1][j + 1] + 1 : Math.max(lcs[i + 1][j], lcs[i][j + 1]);
|
|
10
|
+
const entries = [];
|
|
11
|
+
let i = 0;
|
|
12
|
+
let j = 0;
|
|
13
|
+
while (i < n && j < m) if (oldLines[i] === newLines[j]) {
|
|
14
|
+
entries.push({
|
|
15
|
+
type: "context",
|
|
16
|
+
text: oldLines[i]
|
|
17
|
+
});
|
|
18
|
+
i++;
|
|
19
|
+
j++;
|
|
20
|
+
} else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
|
|
21
|
+
entries.push({
|
|
22
|
+
type: "removed",
|
|
23
|
+
text: oldLines[i]
|
|
24
|
+
});
|
|
25
|
+
i++;
|
|
26
|
+
} else {
|
|
27
|
+
entries.push({
|
|
28
|
+
type: "added",
|
|
29
|
+
text: newLines[j]
|
|
30
|
+
});
|
|
31
|
+
j++;
|
|
32
|
+
}
|
|
33
|
+
while (i < n) entries.push({
|
|
34
|
+
type: "removed",
|
|
35
|
+
text: oldLines[i++]
|
|
36
|
+
});
|
|
37
|
+
while (j < m) entries.push({
|
|
38
|
+
type: "added",
|
|
39
|
+
text: newLines[j++]
|
|
40
|
+
});
|
|
41
|
+
return entries;
|
|
31
42
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Decide whether a diff is worth rendering instead of just showing the full new plan.
|
|
45
|
+
*
|
|
46
|
+
* We generate the real diff and compare its size (added + removed lines) against the size
|
|
47
|
+
* of the whole diff (added + removed + unchanged context). When most of the diff is changes
|
|
48
|
+
* rather than shared context, the diff is no clearer than the full text, so callers fall
|
|
49
|
+
* back to rendering the whole plan. A genuinely new plan (no previous text, or no shared
|
|
50
|
+
* lines) is therefore shown in full.
|
|
51
|
+
*/
|
|
52
|
+
function shouldShowDiff(previousPlan, plan, maxChangedRatio = .5) {
|
|
53
|
+
if (!previousPlan || previousPlan === plan) return false;
|
|
54
|
+
const entries = generatePlanDiff(previousPlan, plan);
|
|
55
|
+
const changed = entries.filter((e) => e.type !== "context").length;
|
|
56
|
+
if (changed === 0) return false;
|
|
57
|
+
return changed / Math.max(entries.length, 1) <= maxChangedRatio;
|
|
38
58
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
59
|
+
//#endregion
|
|
60
|
+
export { generatePlanDiff, shouldShowDiff };
|
|
61
|
+
|
|
43
62
|
//# sourceMappingURL=plan-diff.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/plan-diff.ts"],"sourcesContent":["/**\n * Line-level diffing for plan revisions.\n *\n * Uses a real LCS (longest common subsequence) diff so that inserting or deleting a few\n * lines doesn't mark everything after it as changed. Both the rendered approval diff and\n * the \"is a diff worth showing\" heuristic share this so the heuristic measures the actual\n * diff rather than predicting one.\n */\n\nexport interface DiffEntry {\n type: 'added' | 'removed' | 'context';\n text: string;\n}\n\n/** Produce structured diff entries between two plan texts using an LCS diff. */\nexport function generatePlanDiff(oldText: string, newText: string): DiffEntry[] {\n const oldLines = oldText.split(/\\r?\\n/);\n const newLines = newText.split(/\\r?\\n/);\n const n = oldLines.length;\n const m = newLines.length;\n\n // LCS length table.\n const lcs: number[][] = Array.from({ length: n + 1 }, () => new Array<number>(m + 1).fill(0));\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n lcs[i]![j] = oldLines[i] === newLines[j] ? lcs[i + 1]![j + 1]! + 1 : Math.max(lcs[i + 1]![j]!, lcs[i]![j + 1]!);\n }\n }\n\n const entries: DiffEntry[] = [];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (oldLines[i] === newLines[j]) {\n entries.push({ type: 'context', text: oldLines[i]! });\n i++;\n j++;\n } else if (lcs[i + 1]![j]! >= lcs[i]![j + 1]!) {\n entries.push({ type: 'removed', text: oldLines[i]! });\n i++;\n } else {\n entries.push({ type: 'added', text: newLines[j]! });\n j++;\n }\n }\n while (i < n) entries.push({ type: 'removed', text: oldLines[i++]! });\n while (j < m) entries.push({ type: 'added', text: newLines[j++]! });\n\n return entries;\n}\n\n/**\n * Decide whether a diff is worth rendering instead of just showing the full new plan.\n *\n * We generate the real diff and compare its size (added + removed lines) against the size\n * of the whole diff (added + removed + unchanged context). When most of the diff is changes\n * rather than shared context, the diff is no clearer than the full text, so callers fall\n * back to rendering the whole plan. A genuinely new plan (no previous text, or no shared\n * lines) is therefore shown in full.\n */\nexport function shouldShowDiff(previousPlan: string, plan: string, maxChangedRatio = 0.5): boolean {\n if (!previousPlan || previousPlan === plan) return false;\n\n const entries = generatePlanDiff(previousPlan, plan);\n const changed = entries.filter(e => e.type !== 'context').length;\n if (changed === 0) return false;\n\n // changed / total entries == diff size relative to the full plan view.\n return changed / Math.max(entries.length, 1) <= maxChangedRatio;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plan-diff.js","names":[],"sources":["../../src/utils/plan-diff.ts"],"sourcesContent":["/**\n * Line-level diffing for plan revisions.\n *\n * Uses a real LCS (longest common subsequence) diff so that inserting or deleting a few\n * lines doesn't mark everything after it as changed. Both the rendered approval diff and\n * the \"is a diff worth showing\" heuristic share this so the heuristic measures the actual\n * diff rather than predicting one.\n */\n\nexport interface DiffEntry {\n type: 'added' | 'removed' | 'context';\n text: string;\n}\n\n/** Produce structured diff entries between two plan texts using an LCS diff. */\nexport function generatePlanDiff(oldText: string, newText: string): DiffEntry[] {\n const oldLines = oldText.split(/\\r?\\n/);\n const newLines = newText.split(/\\r?\\n/);\n const n = oldLines.length;\n const m = newLines.length;\n\n // LCS length table.\n const lcs: number[][] = Array.from({ length: n + 1 }, () => new Array<number>(m + 1).fill(0));\n for (let i = n - 1; i >= 0; i--) {\n for (let j = m - 1; j >= 0; j--) {\n lcs[i]![j] = oldLines[i] === newLines[j] ? lcs[i + 1]![j + 1]! + 1 : Math.max(lcs[i + 1]![j]!, lcs[i]![j + 1]!);\n }\n }\n\n const entries: DiffEntry[] = [];\n let i = 0;\n let j = 0;\n while (i < n && j < m) {\n if (oldLines[i] === newLines[j]) {\n entries.push({ type: 'context', text: oldLines[i]! });\n i++;\n j++;\n } else if (lcs[i + 1]![j]! >= lcs[i]![j + 1]!) {\n entries.push({ type: 'removed', text: oldLines[i]! });\n i++;\n } else {\n entries.push({ type: 'added', text: newLines[j]! });\n j++;\n }\n }\n while (i < n) entries.push({ type: 'removed', text: oldLines[i++]! });\n while (j < m) entries.push({ type: 'added', text: newLines[j++]! });\n\n return entries;\n}\n\n/**\n * Decide whether a diff is worth rendering instead of just showing the full new plan.\n *\n * We generate the real diff and compare its size (added + removed lines) against the size\n * of the whole diff (added + removed + unchanged context). When most of the diff is changes\n * rather than shared context, the diff is no clearer than the full text, so callers fall\n * back to rendering the whole plan. A genuinely new plan (no previous text, or no shared\n * lines) is therefore shown in full.\n */\nexport function shouldShowDiff(previousPlan: string, plan: string, maxChangedRatio = 0.5): boolean {\n if (!previousPlan || previousPlan === plan) return false;\n\n const entries = generatePlanDiff(previousPlan, plan);\n const changed = entries.filter(e => e.type !== 'context').length;\n if (changed === 0) return false;\n\n // changed / total entries == diff size relative to the full plan view.\n return changed / Math.max(entries.length, 1) <= maxChangedRatio;\n}\n"],"mappings":";;AAeA,SAAgB,iBAAiB,SAAiB,SAA8B;CAC9E,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,WAAW,QAAQ,MAAM,OAAO;CACtC,MAAM,IAAI,SAAS;CACnB,MAAM,IAAI,SAAS;CAGnB,MAAM,MAAkB,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAE,SAAS,IAAI,MAAc,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAC5F,KAAK,IAAI,IAAI,IAAI,GAAG,KAAK,GAAG,KAC1B,KAAK,IAAI,IAAI,IAAI,GAAG,KAAK,GAAG,KAC1B,IAAI,EAAE,CAAE,KAAK,SAAS,OAAO,SAAS,KAAK,IAAI,IAAI,EAAE,CAAE,IAAI,KAAM,IAAI,KAAK,IAAI,IAAI,IAAI,EAAE,CAAE,IAAK,IAAI,EAAE,CAAE,IAAI,EAAG;CAIlH,MAAM,UAAuB,CAAC;CAC9B,IAAI,IAAI;CACR,IAAI,IAAI;CACR,OAAO,IAAI,KAAK,IAAI,GAClB,IAAI,SAAS,OAAO,SAAS,IAAI;EAC/B,QAAQ,KAAK;GAAE,MAAM;GAAW,MAAM,SAAS;EAAI,CAAC;EACpD;EACA;CACF,OAAO,IAAI,IAAI,IAAI,EAAE,CAAE,MAAO,IAAI,EAAE,CAAE,IAAI,IAAK;EAC7C,QAAQ,KAAK;GAAE,MAAM;GAAW,MAAM,SAAS;EAAI,CAAC;EACpD;CACF,OAAO;EACL,QAAQ,KAAK;GAAE,MAAM;GAAS,MAAM,SAAS;EAAI,CAAC;EAClD;CACF;CAEF,OAAO,IAAI,GAAG,QAAQ,KAAK;EAAE,MAAM;EAAW,MAAM,SAAS;CAAM,CAAC;CACpE,OAAO,IAAI,GAAG,QAAQ,KAAK;EAAE,MAAM;EAAS,MAAM,SAAS;CAAM,CAAC;CAElE,OAAO;AACT;;;;;;;;;;AAWA,SAAgB,eAAe,cAAsB,MAAc,kBAAkB,IAAc;CACjG,IAAI,CAAC,gBAAgB,iBAAiB,MAAM,OAAO;CAEnD,MAAM,UAAU,iBAAiB,cAAc,IAAI;CACnD,MAAM,UAAU,QAAQ,QAAO,MAAK,EAAE,SAAS,SAAS,CAAC,CAAC;CAC1D,IAAI,YAAY,GAAG,OAAO;CAG1B,OAAO,UAAU,KAAK,IAAI,QAAQ,QAAQ,CAAC,KAAK;AAClD"}
|
package/dist/utils/plans.js
CHANGED
|
@@ -1,99 +1,117 @@
|
|
|
1
|
-
import fs from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
1
|
import { DEFAULT_CONFIG_DIR } from "../constants.js";
|
|
4
2
|
import { getAppDataDir } from "./project.js";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import fs from "fs/promises";
|
|
5
|
+
//#region src/utils/plans.ts
|
|
6
|
+
/** Global plans directory for approved-plan archives. */
|
|
5
7
|
function getPlansDir() {
|
|
6
|
-
|
|
8
|
+
return process.env.MASTRA_PLANS_DIR ?? path.join(getAppDataDir(), "plans");
|
|
7
9
|
}
|
|
10
|
+
/** Local (project-scoped) plans directory where the agent writes named plan files. */
|
|
8
11
|
function getLocalPlansDir(projectPath) {
|
|
9
|
-
|
|
12
|
+
return path.join(projectPath, DEFAULT_CONFIG_DIR, "plans");
|
|
10
13
|
}
|
|
14
|
+
/** Workspace-relative directory the agent writes plan files into. */
|
|
11
15
|
function getLocalPlansRelativeDir() {
|
|
12
|
-
|
|
16
|
+
return path.join(DEFAULT_CONFIG_DIR, "plans");
|
|
13
17
|
}
|
|
14
18
|
function slugify(str) {
|
|
15
|
-
|
|
16
|
-
return slug || "untitled";
|
|
19
|
+
return str.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "untitled";
|
|
17
20
|
}
|
|
21
|
+
/** Derive a plan filename from a title (e.g. `add-dark-mode.md`). */
|
|
18
22
|
function getPlanFilename(title) {
|
|
19
|
-
|
|
23
|
+
return `${slugify(title)}.md`;
|
|
20
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Suggested workspace-relative path for a new plan file, shown in plan-mode prompts.
|
|
27
|
+
* Without a title we fall back to a generic name the agent can rename later.
|
|
28
|
+
*/
|
|
21
29
|
function getSuggestedPlanRelativePath(title) {
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
const filename = title ? getPlanFilename(title) : "plan.md";
|
|
31
|
+
return path.join(getLocalPlansRelativeDir(), filename);
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a plan path submitted by the agent (absolute or project-relative) to an
|
|
35
|
+
* absolute path. Returns `undefined` when no usable path was provided.
|
|
36
|
+
*/
|
|
25
37
|
function resolvePlanPath(projectPath, submittedPath) {
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
if (!submittedPath) return void 0;
|
|
39
|
+
return path.isAbsolute(submittedPath) ? submittedPath : path.resolve(projectPath, submittedPath);
|
|
28
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Whether `targetPath` (absolute or project-relative) is a valid plan file: a `.md`
|
|
43
|
+
* file located directly inside the project's `.mastracode/plans/` directory. Used by the
|
|
44
|
+
* plan-mode write guard so the agent can write any named plan file there, but nothing
|
|
45
|
+
* outside that directory.
|
|
46
|
+
*/
|
|
29
47
|
function isPlanFilePath(projectPath, targetPath) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
const abs = resolvePlanPath(projectPath, targetPath);
|
|
49
|
+
if (!abs) return false;
|
|
50
|
+
if (path.extname(abs).toLowerCase() !== ".md") return false;
|
|
51
|
+
const plansDir = path.resolve(getLocalPlansDir(projectPath));
|
|
52
|
+
const rel = path.relative(plansDir, abs);
|
|
53
|
+
if (rel === "" || rel.startsWith("..") || path.isAbsolute(rel)) return false;
|
|
54
|
+
return !rel.includes(path.sep);
|
|
37
55
|
}
|
|
38
56
|
async function savePlanToDisk(opts) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const slug = slugify(title);
|
|
51
|
-
const filename = `${timestamp}-${slug}.md`;
|
|
52
|
-
const content = `# ${title}
|
|
53
|
-
|
|
54
|
-
Approved: ${now.toISOString()}
|
|
55
|
-
|
|
56
|
-
${plan}
|
|
57
|
-
`;
|
|
58
|
-
await fs.writeFile(path.join(dir, filename), content, "utf-8");
|
|
57
|
+
const { title, plan, resourceId } = opts;
|
|
58
|
+
const plansDir = opts.plansDir ?? getPlansDir();
|
|
59
|
+
const baseDir = path.resolve(plansDir);
|
|
60
|
+
const dir = path.resolve(baseDir, resourceId);
|
|
61
|
+
const rel = path.relative(baseDir, dir);
|
|
62
|
+
if (rel.startsWith("..") || path.isAbsolute(rel)) throw new Error(`Invalid resourceId: ${resourceId}`);
|
|
63
|
+
await fs.mkdir(dir, { recursive: true });
|
|
64
|
+
const now = /* @__PURE__ */ new Date();
|
|
65
|
+
const filename = `${now.toISOString().replace(/:/g, "-")}-${slugify(title)}.md`;
|
|
66
|
+
const content = `# ${title}\n\nApproved: ${now.toISOString()}\n\n${plan}\n`;
|
|
67
|
+
await fs.writeFile(path.join(dir, filename), content, "utf-8");
|
|
59
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* Read a plan markdown file by absolute path.
|
|
71
|
+
*
|
|
72
|
+
* The leading `# <title>` heading (if present) is parsed as the title and the remaining
|
|
73
|
+
* content is returned as the plan body. Returns `undefined` when the file does not exist.
|
|
74
|
+
*/
|
|
60
75
|
async function readPlanFile(absPath) {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
let raw;
|
|
77
|
+
try {
|
|
78
|
+
raw = await fs.readFile(absPath, "utf-8");
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const lines = raw.split(/\r?\n/);
|
|
83
|
+
const headingIndex = lines.findIndex((line) => line.trim().length > 0);
|
|
84
|
+
const heading = headingIndex >= 0 ? lines[headingIndex] : void 0;
|
|
85
|
+
if (heading?.startsWith("# ")) return {
|
|
86
|
+
title: heading.slice(2).trim(),
|
|
87
|
+
plan: lines.slice(headingIndex + 1).join("\n").replace(/^\n+/, "").trimEnd()
|
|
88
|
+
};
|
|
89
|
+
return {
|
|
90
|
+
title: "",
|
|
91
|
+
plan: raw.trimEnd()
|
|
92
|
+
};
|
|
76
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Approve the plan file at `planPath`: write a timestamped copy to the global plans
|
|
96
|
+
* archive so approved plans are findable later. The local named plan file is left in
|
|
97
|
+
* place so the user can review every plan made over time.
|
|
98
|
+
*
|
|
99
|
+
* Returns the local plan filename (e.g. `add-dark-mode.md`), or `undefined` when there
|
|
100
|
+
* was no plan file to approve.
|
|
101
|
+
*/
|
|
77
102
|
async function approvePlanFile(opts) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
const { planPath, title, resourceId, plansDir } = opts;
|
|
104
|
+
const current = await readPlanFile(planPath);
|
|
105
|
+
if (!current) return;
|
|
106
|
+
await savePlanToDisk({
|
|
107
|
+
title: title || current.title || "Implementation Plan",
|
|
108
|
+
plan: current.plan,
|
|
109
|
+
resourceId,
|
|
110
|
+
plansDir
|
|
111
|
+
});
|
|
112
|
+
return path.basename(planPath);
|
|
86
113
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
getLocalPlansRelativeDir,
|
|
91
|
-
getPlanFilename,
|
|
92
|
-
getPlansDir,
|
|
93
|
-
getSuggestedPlanRelativePath,
|
|
94
|
-
isPlanFilePath,
|
|
95
|
-
readPlanFile,
|
|
96
|
-
resolvePlanPath,
|
|
97
|
-
savePlanToDisk
|
|
98
|
-
};
|
|
114
|
+
//#endregion
|
|
115
|
+
export { approvePlanFile, getLocalPlansDir, getLocalPlansRelativeDir, getPlanFilename, getPlansDir, getSuggestedPlanRelativePath, isPlanFilePath, readPlanFile, resolvePlanPath, savePlanToDisk };
|
|
116
|
+
|
|
99
117
|
//# sourceMappingURL=plans.js.map
|
package/dist/utils/plans.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utils/plans.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getAppDataDir } from './project.js';\n\n/** Global plans directory for approved-plan archives. */\nexport function getPlansDir(): string {\n return process.env.MASTRA_PLANS_DIR ?? path.join(getAppDataDir(), 'plans');\n}\n\n/** Local (project-scoped) plans directory where the agent writes named plan files. */\nexport function getLocalPlansDir(projectPath: string): string {\n return path.join(projectPath, DEFAULT_CONFIG_DIR, 'plans');\n}\n\n/** Workspace-relative directory the agent writes plan files into. */\nexport function getLocalPlansRelativeDir(): string {\n return path.join(DEFAULT_CONFIG_DIR, 'plans');\n}\n\nfunction slugify(str: string): string {\n const slug = str\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n return slug || 'untitled';\n}\n\n/** Derive a plan filename from a title (e.g. `add-dark-mode.md`). */\nexport function getPlanFilename(title: string): string {\n return `${slugify(title)}.md`;\n}\n\n/**\n * Suggested workspace-relative path for a new plan file, shown in plan-mode prompts.\n * Without a title we fall back to a generic name the agent can rename later.\n */\nexport function getSuggestedPlanRelativePath(title?: string): string {\n const filename = title ? getPlanFilename(title) : 'plan.md';\n return path.join(getLocalPlansRelativeDir(), filename);\n}\n\n/**\n * Resolve a plan path submitted by the agent (absolute or project-relative) to an\n * absolute path. Returns `undefined` when no usable path was provided.\n */\nexport function resolvePlanPath(projectPath: string, submittedPath: string): string | undefined {\n if (!submittedPath) return undefined;\n return path.isAbsolute(submittedPath) ? submittedPath : path.resolve(projectPath, submittedPath);\n}\n\n/**\n * Whether `targetPath` (absolute or project-relative) is a valid plan file: a `.md`\n * file located directly inside the project's `.mastracode/plans/` directory. Used by the\n * plan-mode write guard so the agent can write any named plan file there, but nothing\n * outside that directory.\n */\nexport function isPlanFilePath(projectPath: string, targetPath: string): boolean {\n const abs = resolvePlanPath(projectPath, targetPath);\n if (!abs) return false;\n if (path.extname(abs).toLowerCase() !== '.md') return false;\n\n const plansDir = path.resolve(getLocalPlansDir(projectPath));\n const rel = path.relative(plansDir, abs);\n // Must be directly inside the plans dir (no nested subdirectories, no escaping it).\n if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) return false;\n return !rel.includes(path.sep);\n}\n\nexport async function savePlanToDisk(opts: {\n title: string;\n plan: string;\n resourceId: string;\n plansDir?: string;\n}): Promise<void> {\n const { title, plan, resourceId } = opts;\n const plansDir = opts.plansDir ?? getPlansDir();\n const baseDir = path.resolve(plansDir);\n const dir = path.resolve(baseDir, resourceId);\n const rel = path.relative(baseDir, dir);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Invalid resourceId: ${resourceId}`);\n }\n\n await fs.mkdir(dir, { recursive: true });\n\n const now = new Date();\n const timestamp = now.toISOString().replace(/:/g, '-');\n const slug = slugify(title);\n const filename = `${timestamp}-${slug}.md`;\n\n const content = `# ${title}\\n\\nApproved: ${now.toISOString()}\\n\\n${plan}\\n`;\n\n await fs.writeFile(path.join(dir, filename), content, 'utf-8');\n}\n\n/**\n * Read a plan markdown file by absolute path.\n *\n * The leading `# <title>` heading (if present) is parsed as the title and the remaining\n * content is returned as the plan body. Returns `undefined` when the file does not exist.\n */\nexport async function readPlanFile(absPath: string): Promise<{ title: string; plan: string } | undefined> {\n let raw: string;\n try {\n raw = await fs.readFile(absPath, 'utf-8');\n } catch {\n return undefined;\n }\n\n const lines = raw.split(/\\r?\\n/);\n const headingIndex = lines.findIndex(line => line.trim().length > 0);\n const heading = headingIndex >= 0 ? lines[headingIndex] : undefined;\n if (heading?.startsWith('# ')) {\n const title = heading.slice(2).trim();\n const plan = lines\n .slice(headingIndex + 1)\n .join('\\n')\n .replace(/^\\n+/, '')\n .trimEnd();\n return { title, plan };\n }\n\n return { title: '', plan: raw.trimEnd() };\n}\n\n/**\n * Approve the plan file at `planPath`: write a timestamped copy to the global plans\n * archive so approved plans are findable later. The local named plan file is left in\n * place so the user can review every plan made over time.\n *\n * Returns the local plan filename (e.g. `add-dark-mode.md`), or `undefined` when there\n * was no plan file to approve.\n */\nexport async function approvePlanFile(opts: {\n planPath: string;\n title: string;\n resourceId: string;\n plansDir?: string;\n}): Promise<string | undefined> {\n const { planPath, title, resourceId, plansDir } = opts;\n\n const current = await readPlanFile(planPath);\n if (!current) {\n return undefined;\n }\n\n const resolvedTitle = title || current.title || 'Implementation Plan';\n\n // Global archive (timestamped, never overwritten) so approved plans are findable later.\n await savePlanToDisk({ title: resolvedTitle, plan: current.plan, resourceId, plansDir });\n\n return path.basename(planPath);\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plans.js","names":[],"sources":["../../src/utils/plans.ts"],"sourcesContent":["import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { DEFAULT_CONFIG_DIR } from '../constants.js';\nimport { getAppDataDir } from './project.js';\n\n/** Global plans directory for approved-plan archives. */\nexport function getPlansDir(): string {\n return process.env.MASTRA_PLANS_DIR ?? path.join(getAppDataDir(), 'plans');\n}\n\n/** Local (project-scoped) plans directory where the agent writes named plan files. */\nexport function getLocalPlansDir(projectPath: string): string {\n return path.join(projectPath, DEFAULT_CONFIG_DIR, 'plans');\n}\n\n/** Workspace-relative directory the agent writes plan files into. */\nexport function getLocalPlansRelativeDir(): string {\n return path.join(DEFAULT_CONFIG_DIR, 'plans');\n}\n\nfunction slugify(str: string): string {\n const slug = str\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-|-$/g, '');\n return slug || 'untitled';\n}\n\n/** Derive a plan filename from a title (e.g. `add-dark-mode.md`). */\nexport function getPlanFilename(title: string): string {\n return `${slugify(title)}.md`;\n}\n\n/**\n * Suggested workspace-relative path for a new plan file, shown in plan-mode prompts.\n * Without a title we fall back to a generic name the agent can rename later.\n */\nexport function getSuggestedPlanRelativePath(title?: string): string {\n const filename = title ? getPlanFilename(title) : 'plan.md';\n return path.join(getLocalPlansRelativeDir(), filename);\n}\n\n/**\n * Resolve a plan path submitted by the agent (absolute or project-relative) to an\n * absolute path. Returns `undefined` when no usable path was provided.\n */\nexport function resolvePlanPath(projectPath: string, submittedPath: string): string | undefined {\n if (!submittedPath) return undefined;\n return path.isAbsolute(submittedPath) ? submittedPath : path.resolve(projectPath, submittedPath);\n}\n\n/**\n * Whether `targetPath` (absolute or project-relative) is a valid plan file: a `.md`\n * file located directly inside the project's `.mastracode/plans/` directory. Used by the\n * plan-mode write guard so the agent can write any named plan file there, but nothing\n * outside that directory.\n */\nexport function isPlanFilePath(projectPath: string, targetPath: string): boolean {\n const abs = resolvePlanPath(projectPath, targetPath);\n if (!abs) return false;\n if (path.extname(abs).toLowerCase() !== '.md') return false;\n\n const plansDir = path.resolve(getLocalPlansDir(projectPath));\n const rel = path.relative(plansDir, abs);\n // Must be directly inside the plans dir (no nested subdirectories, no escaping it).\n if (rel === '' || rel.startsWith('..') || path.isAbsolute(rel)) return false;\n return !rel.includes(path.sep);\n}\n\nexport async function savePlanToDisk(opts: {\n title: string;\n plan: string;\n resourceId: string;\n plansDir?: string;\n}): Promise<void> {\n const { title, plan, resourceId } = opts;\n const plansDir = opts.plansDir ?? getPlansDir();\n const baseDir = path.resolve(plansDir);\n const dir = path.resolve(baseDir, resourceId);\n const rel = path.relative(baseDir, dir);\n if (rel.startsWith('..') || path.isAbsolute(rel)) {\n throw new Error(`Invalid resourceId: ${resourceId}`);\n }\n\n await fs.mkdir(dir, { recursive: true });\n\n const now = new Date();\n const timestamp = now.toISOString().replace(/:/g, '-');\n const slug = slugify(title);\n const filename = `${timestamp}-${slug}.md`;\n\n const content = `# ${title}\\n\\nApproved: ${now.toISOString()}\\n\\n${plan}\\n`;\n\n await fs.writeFile(path.join(dir, filename), content, 'utf-8');\n}\n\n/**\n * Read a plan markdown file by absolute path.\n *\n * The leading `# <title>` heading (if present) is parsed as the title and the remaining\n * content is returned as the plan body. Returns `undefined` when the file does not exist.\n */\nexport async function readPlanFile(absPath: string): Promise<{ title: string; plan: string } | undefined> {\n let raw: string;\n try {\n raw = await fs.readFile(absPath, 'utf-8');\n } catch {\n return undefined;\n }\n\n const lines = raw.split(/\\r?\\n/);\n const headingIndex = lines.findIndex(line => line.trim().length > 0);\n const heading = headingIndex >= 0 ? lines[headingIndex] : undefined;\n if (heading?.startsWith('# ')) {\n const title = heading.slice(2).trim();\n const plan = lines\n .slice(headingIndex + 1)\n .join('\\n')\n .replace(/^\\n+/, '')\n .trimEnd();\n return { title, plan };\n }\n\n return { title: '', plan: raw.trimEnd() };\n}\n\n/**\n * Approve the plan file at `planPath`: write a timestamped copy to the global plans\n * archive so approved plans are findable later. The local named plan file is left in\n * place so the user can review every plan made over time.\n *\n * Returns the local plan filename (e.g. `add-dark-mode.md`), or `undefined` when there\n * was no plan file to approve.\n */\nexport async function approvePlanFile(opts: {\n planPath: string;\n title: string;\n resourceId: string;\n plansDir?: string;\n}): Promise<string | undefined> {\n const { planPath, title, resourceId, plansDir } = opts;\n\n const current = await readPlanFile(planPath);\n if (!current) {\n return undefined;\n }\n\n const resolvedTitle = title || current.title || 'Implementation Plan';\n\n // Global archive (timestamped, never overwritten) so approved plans are findable later.\n await savePlanToDisk({ title: resolvedTitle, plan: current.plan, resourceId, plansDir });\n\n return path.basename(planPath);\n}\n"],"mappings":"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"}
|