mastracode 0.26.0-alpha.6 → 0.26.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/{acp-7ADCI4VS.js → acp-G5OLW7EV.js} +4 -4
  3. package/dist/{acp-7ADCI4VS.js.map → acp-G5OLW7EV.js.map} +1 -1
  4. package/dist/{acp-4KUBWHJK.cjs → acp-YSYEXVBE.cjs} +6 -6
  5. package/dist/{acp-4KUBWHJK.cjs.map → acp-YSYEXVBE.cjs.map} +1 -1
  6. package/dist/agents/modes/plan.d.ts.map +1 -1
  7. package/dist/agents/prompts/plan.d.ts +5 -4
  8. package/dist/agents/prompts/plan.d.ts.map +1 -1
  9. package/dist/agents/tool-availability.d.ts +5 -1
  10. package/dist/agents/tool-availability.d.ts.map +1 -1
  11. package/dist/{chunk-SHA3DXLU.js → chunk-GT3A3LAA.js} +119 -41
  12. package/dist/chunk-GT3A3LAA.js.map +1 -0
  13. package/dist/{chunk-DVBJN36L.cjs → chunk-KGBCGF6C.cjs} +47 -23
  14. package/dist/chunk-KGBCGF6C.cjs.map +1 -0
  15. package/dist/{chunk-IXP7JO6S.js → chunk-LUSQ75XP.js} +122 -66
  16. package/dist/chunk-LUSQ75XP.js.map +1 -0
  17. package/dist/{chunk-F3TKSK3C.js → chunk-NDCWIAKG.js} +43 -21
  18. package/dist/chunk-NDCWIAKG.js.map +1 -0
  19. package/dist/{chunk-EMEAUCQ7.cjs → chunk-NUKVNLFS.cjs} +1046 -990
  20. package/dist/chunk-NUKVNLFS.cjs.map +1 -0
  21. package/dist/{chunk-QPIUDTEY.cjs → chunk-Z3HFSXTB.cjs} +153 -75
  22. package/dist/chunk-Z3HFSXTB.cjs.map +1 -0
  23. package/dist/cli.cjs +19 -19
  24. package/dist/cli.js +4 -4
  25. package/dist/index.cjs +7 -7
  26. package/dist/index.d.ts +2 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/processors/plan-rejection-abort.d.ts.map +1 -1
  30. package/dist/tui/components/plan-approval-inline.d.ts.map +1 -1
  31. package/dist/tui/handlers/agent-lifecycle.d.ts.map +1 -1
  32. package/dist/tui/handlers/prompts.d.ts +1 -1
  33. package/dist/tui/handlers/prompts.d.ts.map +1 -1
  34. package/dist/tui/render-messages.d.ts.map +1 -1
  35. package/dist/tui/state.d.ts +8 -2
  36. package/dist/tui/state.d.ts.map +1 -1
  37. package/dist/tui.cjs +19 -19
  38. package/dist/tui.js +2 -2
  39. package/dist/utils/plan-diff.d.ts +25 -0
  40. package/dist/utils/plan-diff.d.ts.map +1 -0
  41. package/dist/utils/plans.d.ts +41 -12
  42. package/dist/utils/plans.d.ts.map +1 -1
  43. package/package.json +16 -16
  44. package/dist/chunk-DVBJN36L.cjs.map +0 -1
  45. package/dist/chunk-EMEAUCQ7.cjs.map +0 -1
  46. package/dist/chunk-F3TKSK3C.js.map +0 -1
  47. package/dist/chunk-IXP7JO6S.js.map +0 -1
  48. package/dist/chunk-QPIUDTEY.cjs.map +0 -1
  49. package/dist/chunk-SHA3DXLU.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { tintHex, mastra, theme, getMarkdownTheme, CHAT_INDENT, BOX_INDENT, getTermWidth, ensureTerminalGlyphContrast, TERM_WIDTH_BUFFER, getEditorTheme, loadSettings, MEMORY_GATEWAY_PROVIDER, getAvailableModePacks, resolveThreadActiveModelPackId, saveSettings, getAvailableOmPacks, ONBOARDING_VERSION, THREAD_ACTIVE_MODEL_PACK_ID_KEY, BOX_INDENT_STR, ThreadLockError, getPlanFilename, getSelectListTheme, luminance, extendedColors, mastraBrand, savePlanSnapshot, MEMORY_GATEWAY_DEFAULT_URL, getThemeMode, applyThemeMode, createBrowserFromSettings, setProfileProvider, getCustomProviderId, OBSERVABILITY_AUTH_PREFIX, checkProfileProviderMismatch, getSettingsListTheme, savePlanToDisk, toCustomProviderModelId } from './chunk-F3TKSK3C.js';
1
+ import { tintHex, mastra, theme, getMarkdownTheme, CHAT_INDENT, BOX_INDENT, getTermWidth, ensureTerminalGlyphContrast, TERM_WIDTH_BUFFER, getEditorTheme, loadSettings, MEMORY_GATEWAY_PROVIDER, getAvailableModePacks, resolveThreadActiveModelPackId, saveSettings, getAvailableOmPacks, ONBOARDING_VERSION, THREAD_ACTIVE_MODEL_PACK_ID_KEY, BOX_INDENT_STR, ThreadLockError, resolvePlanPath, readPlanFile, getSelectListTheme, luminance, extendedColors, mastraBrand, MEMORY_GATEWAY_DEFAULT_URL, getThemeMode, applyThemeMode, createBrowserFromSettings, setProfileProvider, getCustomProviderId, OBSERVABILITY_AUTH_PREFIX, checkProfileProviderMismatch, getSettingsListTheme, approvePlanFile, toCustomProviderModelId } from './chunk-NDCWIAKG.js';
2
2
  import { getOAuthProviders, detectProject, DEFAULT_CONFIG_DIR, getUserId, getCurrentGitBranchAsync, getUserName, PROVIDER_DEFAULT_MODELS } from './chunk-Z5EMG7I2.js';
3
3
  import { MC_TOOLS, getToolCategory, TOOL_CATEGORIES } from './chunk-UOFNLVKF.js';
4
4
  import { exec, spawn, execFile, execSync, execFileSync } from 'child_process';
@@ -1175,7 +1175,7 @@ function getInstallCommand(pm, version) {
1175
1175
  }
1176
1176
  function getCurrentVersion() {
1177
1177
  {
1178
- return "0.26.0-alpha.6";
1178
+ return "0.26.0";
1179
1179
  }
1180
1180
  }
1181
1181
  async function fetchLatestVersion() {
@@ -4433,6 +4433,48 @@ var OMOutputComponent = class extends Container {
4433
4433
  return "other";
4434
4434
  }
4435
4435
  };
4436
+
4437
+ // src/utils/plan-diff.ts
4438
+ function generatePlanDiff(oldText, newText) {
4439
+ const oldLines = oldText.split(/\r?\n/);
4440
+ const newLines = newText.split(/\r?\n/);
4441
+ const n = oldLines.length;
4442
+ const m = newLines.length;
4443
+ const lcs = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
4444
+ for (let i2 = n - 1; i2 >= 0; i2--) {
4445
+ for (let j2 = m - 1; j2 >= 0; j2--) {
4446
+ lcs[i2][j2] = oldLines[i2] === newLines[j2] ? lcs[i2 + 1][j2 + 1] + 1 : Math.max(lcs[i2 + 1][j2], lcs[i2][j2 + 1]);
4447
+ }
4448
+ }
4449
+ const entries = [];
4450
+ let i = 0;
4451
+ let j = 0;
4452
+ while (i < n && j < m) {
4453
+ if (oldLines[i] === newLines[j]) {
4454
+ entries.push({ type: "context", text: oldLines[i] });
4455
+ i++;
4456
+ j++;
4457
+ } else if (lcs[i + 1][j] >= lcs[i][j + 1]) {
4458
+ entries.push({ type: "removed", text: oldLines[i] });
4459
+ i++;
4460
+ } else {
4461
+ entries.push({ type: "added", text: newLines[j] });
4462
+ j++;
4463
+ }
4464
+ }
4465
+ while (i < n) entries.push({ type: "removed", text: oldLines[i++] });
4466
+ while (j < m) entries.push({ type: "added", text: newLines[j++] });
4467
+ return entries;
4468
+ }
4469
+ function shouldShowDiff(previousPlan, plan, maxChangedRatio = 0.5) {
4470
+ if (!previousPlan || previousPlan === plan) return false;
4471
+ const entries = generatePlanDiff(previousPlan, plan);
4472
+ const changed = entries.filter((e) => e.type !== "context").length;
4473
+ if (changed === 0) return false;
4474
+ return changed / Math.max(entries.length, 1) <= maxChangedRatio;
4475
+ }
4476
+
4477
+ // src/tui/components/plan-approval-inline.ts
4436
4478
  var PlanContentBox = class {
4437
4479
  constructor(plan) {
4438
4480
  this.plan = plan;
@@ -4495,25 +4537,6 @@ var PlanDiffBox = class {
4495
4537
  return [top, ...body, bottom];
4496
4538
  }
4497
4539
  };
4498
- function generatePlanDiff(oldText, newText) {
4499
- const oldLines = oldText.split("\n");
4500
- const newLines = newText.split("\n");
4501
- const entries = [];
4502
- const maxLines = Math.max(oldLines.length, newLines.length);
4503
- for (let i = 0; i < maxLines; i++) {
4504
- if (i >= oldLines.length) {
4505
- entries.push({ type: "added", text: newLines[i] });
4506
- } else if (i >= newLines.length) {
4507
- entries.push({ type: "removed", text: oldLines[i] });
4508
- } else if (oldLines[i] !== newLines[i]) {
4509
- entries.push({ type: "removed", text: oldLines[i] });
4510
- entries.push({ type: "added", text: newLines[i] });
4511
- } else {
4512
- entries.push({ type: "context", text: oldLines[i] });
4513
- }
4514
- }
4515
- return entries;
4516
- }
4517
4540
  var PlanApprovalInlineComponent = class _PlanApprovalInlineComponent extends Container {
4518
4541
  constructor(options, ui) {
4519
4542
  super();
@@ -4583,12 +4606,8 @@ var PlanApprovalInlineComponent = class _PlanApprovalInlineComponent extends Con
4583
4606
  updateArgs(args) {
4584
4607
  if (!args || typeof args !== "object" || this.resolved) return;
4585
4608
  const partial = args;
4586
- if (typeof partial.title === "string") {
4587
- this.planTitle = partial.title || "Untitled plan";
4588
- this.planFilename = getPlanFilename(this.planTitle);
4589
- }
4590
- if (typeof partial.plan === "string") {
4591
- this.planContent = partial.plan;
4609
+ if (typeof partial.path === "string" && partial.path) {
4610
+ this.planFilename = partial.path;
4592
4611
  }
4593
4612
  if (this.mode === "streaming") {
4594
4613
  this.renderStreaming();
@@ -4641,7 +4660,7 @@ var PlanApprovalInlineComponent = class _PlanApprovalInlineComponent extends Con
4641
4660
  renderPlanHeader(prefix = "") {
4642
4661
  this.contentBox.addChild(new Text(`${prefix}${theme.bold(theme.fg("accent", `Plan: ${this.planTitle}`))}`, 0, 0));
4643
4662
  if (this.planFilename) {
4644
- this.contentBox.addChild(new Text(theme.fg("dim", `.mastracode/plans/${this.planFilename}`), 0, 0));
4663
+ this.contentBox.addChild(new Text(theme.fg("dim", this.planFilename), 0, 0));
4645
4664
  }
4646
4665
  this.contentBox.addChild(new Spacer(1));
4647
4666
  }
@@ -4712,7 +4731,7 @@ var PlanResultComponent = class extends Container {
4712
4731
  const status = options.isApproved ? "Approved" : options.feedback ? "Changes requested" : "Rejected";
4713
4732
  contentBox.addChild(new Text(theme.bold(theme.fg("accent", `Plan: ${options.title}`)), 0, 0));
4714
4733
  if (options.planFilename) {
4715
- contentBox.addChild(new Text(theme.fg("dim", `.mastracode/plans/${options.planFilename}`), 0, 0));
4734
+ contentBox.addChild(new Text(theme.fg("dim", options.planFilename), 0, 0));
4716
4735
  }
4717
4736
  contentBox.addChild(new Spacer(1));
4718
4737
  contentBox.addChild(new PlanContentBox(options.plan));
@@ -8900,10 +8919,16 @@ async function renderExistingMessages(state) {
8900
8919
  if (content.name === "submit_plan" && toolResult?.type === "tool_result") {
8901
8920
  const args = content.args;
8902
8921
  let resultText = "";
8922
+ let submittedPlan;
8903
8923
  if (typeof toolResult.result === "string") {
8904
8924
  resultText = toolResult.result;
8905
- } else if (typeof toolResult.result === "object" && toolResult.result !== null && "content" in toolResult.result && typeof toolResult.result.content === "string") {
8906
- resultText = toolResult.result.content;
8925
+ } else if (typeof toolResult.result === "object" && toolResult.result !== null) {
8926
+ if ("content" in toolResult.result && typeof toolResult.result.content === "string") {
8927
+ resultText = toolResult.result.content;
8928
+ }
8929
+ if ("submittedPlan" in toolResult.result && typeof toolResult.result.submittedPlan === "object") {
8930
+ submittedPlan = toolResult.result.submittedPlan;
8931
+ }
8907
8932
  }
8908
8933
  const isApproved = resultText.startsWith("Plan approved");
8909
8934
  let feedback;
@@ -8911,17 +8936,24 @@ async function renderExistingMessages(state) {
8911
8936
  const feedbackMatch = resultText.match(/User feedback:\s*(.+?)(?:\n|$)/);
8912
8937
  feedback = feedbackMatch?.[1] || "Revision requested";
8913
8938
  }
8914
- if (args?.title && args?.plan) {
8939
+ const submittedPath = submittedPlan?.path || args?.path;
8940
+ if (submittedPath) {
8941
+ const sessionState = state.session.state.get();
8942
+ const projectPath = sessionState?.projectPath;
8943
+ const recoverAbsPath = !submittedPlan?.plan ? resolvePlanPath(projectPath ?? process.cwd(), submittedPath) : void 0;
8944
+ const recovered = recoverAbsPath ? await readPlanFile(recoverAbsPath) : void 0;
8945
+ const planBody = submittedPlan?.plan ?? recovered?.plan ?? "";
8946
+ const planTitle = submittedPlan?.title || recovered?.title || "Implementation Plan";
8915
8947
  const planResult = new PlanResultComponent({
8916
- title: args.title,
8917
- plan: args.plan,
8918
- planFilename: getPlanFilename(args.title),
8948
+ title: planTitle,
8949
+ plan: planBody,
8950
+ planFilename: submittedPath,
8919
8951
  isApproved,
8920
8952
  feedback
8921
8953
  });
8922
8954
  state.chatContainer.addChild(planResult);
8923
8955
  replacedWithInline = true;
8924
- state.previousPlanSnapshot = { title: args.title, plan: args.plan };
8956
+ state.previousPlanSnapshot = { path: submittedPath, plan: planBody };
8925
8957
  }
8926
8958
  }
8927
8959
  if (!replacedWithInline) {
@@ -15162,7 +15194,10 @@ function handleAgentAborted(ctx) {
15162
15194
  if (state.gradientAnimator) {
15163
15195
  state.gradientAnimator.fadeOut();
15164
15196
  }
15165
- if (state.streamingComponent && state.streamingMessage) {
15197
+ if (state.planRejectionAbort) {
15198
+ state.streamingComponent = void 0;
15199
+ state.streamingMessage = void 0;
15200
+ } else if (state.streamingComponent && state.streamingMessage) {
15166
15201
  state.streamingMessage.stopReason = "aborted";
15167
15202
  state.streamingMessage.errorMessage = "Interrupted";
15168
15203
  state.streamingComponent.updateContent(state.streamingMessage);
@@ -15172,6 +15207,7 @@ function handleAgentAborted(ctx) {
15172
15207
  showError(state, "Interrupted");
15173
15208
  }
15174
15209
  state.userInitiatedAbort = false;
15210
+ state.planRejectionAbort = false;
15175
15211
  if (state.activeGoalJudge) {
15176
15212
  removeJudgeComponent(state, state.activeGoalJudge.component);
15177
15213
  state.activeGoalJudge = void 0;
@@ -16031,7 +16067,7 @@ ${theme.fg("dim", `Reason: ${reason}`)}`,
16031
16067
  ctx.notify("sandbox_access", `Sandbox access requested: ${requestedPath}`);
16032
16068
  });
16033
16069
  }
16034
- async function approvePlan(ctx, toolCallId, title, plan) {
16070
+ async function approvePlan(ctx, toolCallId, title, plan, planPath, submittedPath) {
16035
16071
  const { state } = ctx;
16036
16072
  await state.session.state.set({
16037
16073
  activePlan: {
@@ -16040,15 +16076,19 @@ async function approvePlan(ctx, toolCallId, title, plan) {
16040
16076
  approvedAt: (/* @__PURE__ */ new Date()).toISOString()
16041
16077
  }
16042
16078
  });
16043
- savePlanToDisk({
16044
- title,
16045
- plan,
16046
- resourceId: state.session.identity.getResourceId()
16047
- }).catch(() => {
16048
- });
16079
+ if (planPath) {
16080
+ await approvePlanFile({
16081
+ planPath,
16082
+ title,
16083
+ resourceId: state.session.identity.getResourceId()
16084
+ }).catch(() => {
16085
+ });
16086
+ }
16087
+ state.previousPlanSnapshot = void 0;
16088
+ state.lastSubmitPlanComponent = void 0;
16049
16089
  await state.session.respondToToolSuspension({
16050
16090
  toolCallId,
16051
- resumeData: { action: "approved" }
16091
+ resumeData: { action: "approved", path: submittedPath, title, plan }
16052
16092
  });
16053
16093
  }
16054
16094
  function formatPlanGoalObjective(title, plan) {
@@ -16056,34 +16096,42 @@ function formatPlanGoalObjective(title, plan) {
16056
16096
 
16057
16097
  ${plan}`;
16058
16098
  }
16059
- async function handlePlanApproval(ctx, toolCallId, title, plan) {
16099
+ async function handlePlanApproval(ctx, toolCallId, submittedPath) {
16060
16100
  const { state } = ctx;
16061
- const previousPlan = state.previousPlanSnapshot?.plan;
16062
- state.previousPlanSnapshot = { title, plan };
16063
16101
  const projectPath = state.session.state.get()?.projectPath;
16064
- if (projectPath) {
16065
- savePlanSnapshot({ title, plan, projectPath }).catch(() => {
16066
- });
16102
+ const planPath = submittedPath ? resolvePlanPath(projectPath ?? process.cwd(), submittedPath) : void 0;
16103
+ const current = planPath ? await readPlanFile(planPath) : void 0;
16104
+ if (!current) {
16105
+ state.previousPlanSnapshot = void 0;
16106
+ }
16107
+ const plan = current?.plan ?? `\u26A0\uFE0F Could not read the plan file at \`${submittedPath}\`. Make sure it exists before submitting it.`;
16108
+ const resolvedTitle = current?.title || "Implementation Plan";
16109
+ const snapshotKey = submittedPath;
16110
+ const snapshot = state.previousPlanSnapshot;
16111
+ const snapshotPlan = snapshot && snapshot.path === snapshotKey ? snapshot.plan : void 0;
16112
+ const previousPlan = snapshotPlan && shouldShowDiff(snapshotPlan, plan) ? snapshotPlan : void 0;
16113
+ if (current) {
16114
+ state.previousPlanSnapshot = { path: snapshotKey, plan };
16067
16115
  }
16068
16116
  return new Promise((resolve3) => {
16069
- const planFilename = getPlanFilename(title);
16117
+ const planFilename = snapshotKey;
16070
16118
  const approvalOptions = {
16071
16119
  toolCallId,
16072
- title,
16120
+ title: resolvedTitle,
16073
16121
  plan,
16074
16122
  planFilename,
16075
16123
  previousPlan,
16076
16124
  onApprove: async () => {
16077
16125
  state.activeInlinePlanApproval = void 0;
16078
16126
  state.ui.setFocus(state.editor);
16079
- await approvePlan(ctx, toolCallId, title, plan);
16127
+ await approvePlan(ctx, toolCallId, resolvedTitle, plan, planPath, snapshotKey);
16080
16128
  resolve3();
16081
16129
  },
16082
16130
  onGoal: async () => {
16083
16131
  state.activeInlinePlanApproval = void 0;
16084
16132
  state.ui.setFocus(state.editor);
16085
- await approvePlan(ctx, toolCallId, title, plan);
16086
- const objective = formatPlanGoalObjective(title, plan);
16133
+ await approvePlan(ctx, toolCallId, resolvedTitle, plan, planPath, snapshotKey);
16134
+ const objective = formatPlanGoalObjective(resolvedTitle, plan);
16087
16135
  await ctx.startGoal(objective, "Goal cancelled.");
16088
16136
  const goal = state.goalManager.getGoal();
16089
16137
  if (goal?.id) {
@@ -16091,13 +16139,20 @@ async function handlePlanApproval(ctx, toolCallId, title, plan) {
16091
16139
  }
16092
16140
  resolve3();
16093
16141
  },
16094
- onReject: async () => {
16142
+ onReject: () => {
16095
16143
  state.activeInlinePlanApproval = void 0;
16096
16144
  state.ui.setFocus(state.editor);
16097
- await state.session.respondToToolSuspension({
16098
- toolCallId,
16099
- resumeData: { action: "rejected" }
16100
- });
16145
+ void (async () => {
16146
+ try {
16147
+ await state.session.respondToToolSuspension({
16148
+ toolCallId,
16149
+ resumeData: { action: "rejected", path: snapshotKey, title: resolvedTitle, plan }
16150
+ });
16151
+ } finally {
16152
+ state.planRejectionAbort = true;
16153
+ state.session.abort();
16154
+ }
16155
+ })();
16101
16156
  resolve3();
16102
16157
  }
16103
16158
  };
@@ -16127,7 +16182,7 @@ async function handlePlanApproval(ctx, toolCallId, title, plan) {
16127
16182
  state.ui.requestRender();
16128
16183
  state.chatContainer.invalidate();
16129
16184
  state.ui.setFocus(approvalComponent);
16130
- ctx.notify("plan_approval", `Plan "${title}" requires approval`);
16185
+ ctx.notify("plan_approval", `Plan "${resolvedTitle}" requires approval`);
16131
16186
  });
16132
16187
  }
16133
16188
 
@@ -16885,7 +16940,8 @@ function createTUIState(options) {
16885
16940
  pendingImages: [],
16886
16941
  // Abort tracking
16887
16942
  lastCtrlCTime: 0,
16888
- userInitiatedAbort: false
16943
+ userInitiatedAbort: false,
16944
+ planRejectionAbort: false
16889
16945
  };
16890
16946
  editor.getModeColor = () => {
16891
16947
  if (result.activeGoalJudge) {
@@ -17193,7 +17249,7 @@ async function dispatchEvent(event, ectx, state) {
17193
17249
  payload.selectionMode
17194
17250
  );
17195
17251
  } else if (event.toolName === "submit_plan") {
17196
- await handlePlanApproval(ectx, event.toolCallId, String(payload.title ?? ""), String(payload.plan ?? ""));
17252
+ await handlePlanApproval(ectx, event.toolCallId, String(payload.path ?? ""));
17197
17253
  }
17198
17254
  break;
17199
17255
  }
@@ -19380,5 +19436,5 @@ Would you like to update now?`;
19380
19436
  };
19381
19437
 
19382
19438
  export { AssistantMessageComponent, LoginDialogComponent, LoginSelectorComponent, MastraTUI, ModelSelectorComponent, OMProgressComponent, ToolExecutionComponentEnhanced, UserMessageComponent, createTUIState, detectTerminalTheme, formatOMStatus, getCurrentVersion };
19383
- //# sourceMappingURL=chunk-IXP7JO6S.js.map
19384
- //# sourceMappingURL=chunk-IXP7JO6S.js.map
19439
+ //# sourceMappingURL=chunk-LUSQ75XP.js.map
19440
+ //# sourceMappingURL=chunk-LUSQ75XP.js.map