@pellux/goodvibes-tui 0.27.0 → 0.29.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 (143) hide show
  1. package/CHANGELOG.md +124 -0
  2. package/README.md +1 -1
  3. package/package.json +1 -1
  4. package/src/core/context-usage.ts +53 -0
  5. package/src/core/conversation.ts +4 -6
  6. package/src/core/session-recovery.ts +2 -0
  7. package/src/core/turn-event-wiring.ts +1 -0
  8. package/src/input/commands/cost-runtime.ts +49 -0
  9. package/src/input/commands/eval.ts +4 -3
  10. package/src/input/commands/operator-runtime.ts +5 -1
  11. package/src/input/commands.ts +2 -0
  12. package/src/input/handler-feed-routes.ts +60 -26
  13. package/src/input/handler-feed.ts +17 -8
  14. package/src/input/handler-picker-routes.ts +18 -13
  15. package/src/input/handler-shortcuts.ts +51 -0
  16. package/src/input/handler-ui-state.ts +4 -0
  17. package/src/input/handler.ts +43 -6
  18. package/src/input/keybindings.ts +53 -8
  19. package/src/input/model-picker.ts +5 -0
  20. package/src/input/panel-integration-actions.ts +117 -1
  21. package/src/main.ts +5 -2
  22. package/src/panels/agent-inspector-panel.ts +139 -45
  23. package/src/panels/agent-inspector-shared.ts +147 -3
  24. package/src/panels/approval-panel.ts +204 -102
  25. package/src/panels/automation-control-panel.ts +370 -103
  26. package/src/panels/base-panel.ts +26 -2
  27. package/src/panels/builtin/agent.ts +28 -37
  28. package/src/panels/builtin/development.ts +40 -32
  29. package/src/panels/builtin/knowledge.ts +15 -6
  30. package/src/panels/builtin/operations.ts +178 -117
  31. package/src/panels/builtin/session.ts +35 -9
  32. package/src/panels/builtin/shared.ts +98 -6
  33. package/src/panels/cockpit-panel.ts +253 -75
  34. package/src/panels/cockpit-read-model.ts +2 -1
  35. package/src/panels/communication-panel.ts +159 -56
  36. package/src/panels/confirm-state.ts +8 -1
  37. package/src/panels/control-plane-panel.ts +354 -95
  38. package/src/panels/cost-tracker-panel.ts +243 -57
  39. package/src/panels/debug-panel.ts +347 -159
  40. package/src/panels/diff-panel.ts +257 -82
  41. package/src/panels/docs-panel.ts +166 -64
  42. package/src/panels/eval-panel.ts +336 -109
  43. package/src/panels/expandable-list-panel.ts +189 -0
  44. package/src/panels/file-explorer-panel.ts +238 -159
  45. package/src/panels/file-preview-panel.ts +141 -59
  46. package/src/panels/git-panel.ts +360 -191
  47. package/src/panels/hooks-panel.ts +181 -19
  48. package/src/panels/incident-review-panel.ts +252 -43
  49. package/src/panels/index.ts +0 -4
  50. package/src/panels/intelligence-panel.ts +310 -103
  51. package/src/panels/knowledge-graph-panel.ts +480 -58
  52. package/src/panels/local-auth-panel.ts +251 -33
  53. package/src/panels/marketplace-panel.ts +219 -33
  54. package/src/panels/memory-panel.ts +83 -81
  55. package/src/panels/ops-control-panel.ts +211 -32
  56. package/src/panels/ops-strategy-panel.ts +131 -45
  57. package/src/panels/orchestration-panel.ts +259 -67
  58. package/src/panels/panel-list-panel.ts +184 -136
  59. package/src/panels/panel-manager.ts +120 -13
  60. package/src/panels/plan-dashboard-panel.ts +507 -74
  61. package/src/panels/plugins-panel.ts +227 -34
  62. package/src/panels/policy-panel.ts +264 -55
  63. package/src/panels/polish-core.ts +162 -0
  64. package/src/panels/polish-tables.ts +258 -0
  65. package/src/panels/polish.ts +67 -149
  66. package/src/panels/project-planning-answer-actions.ts +134 -0
  67. package/src/panels/project-planning-panel.ts +84 -113
  68. package/src/panels/provider-health-panel.ts +438 -480
  69. package/src/panels/provider-health-routes.ts +203 -0
  70. package/src/panels/provider-health-tracker.ts +194 -6
  71. package/src/panels/provider-health-views.ts +560 -0
  72. package/src/panels/qr-panel.ts +136 -38
  73. package/src/panels/remote-panel.ts +123 -38
  74. package/src/panels/routes-panel.ts +87 -24
  75. package/src/panels/sandbox-panel.ts +232 -65
  76. package/src/panels/scrollable-list-panel.ts +143 -145
  77. package/src/panels/security-panel.ts +204 -52
  78. package/src/panels/services-panel.ts +174 -76
  79. package/src/panels/session-browser-panel.ts +101 -6
  80. package/src/panels/session-maintenance.ts +4 -122
  81. package/src/panels/settings-sync-panel.ts +346 -68
  82. package/src/panels/skills-panel.ts +157 -89
  83. package/src/panels/subscription-panel.ts +105 -34
  84. package/src/panels/symbol-outline-panel.ts +287 -154
  85. package/src/panels/system-messages-panel.ts +172 -38
  86. package/src/panels/tasks-panel.ts +348 -134
  87. package/src/panels/thinking-panel.ts +66 -32
  88. package/src/panels/token-budget-panel.ts +233 -46
  89. package/src/panels/tool-inspector-panel.ts +170 -54
  90. package/src/panels/types.ts +65 -4
  91. package/src/panels/work-plan-panel.ts +393 -39
  92. package/src/panels/worktree-panel.ts +239 -61
  93. package/src/panels/wrfc-panel-format.ts +133 -0
  94. package/src/panels/wrfc-panel.ts +146 -150
  95. package/src/renderer/compaction-preview.ts +2 -1
  96. package/src/renderer/compositor.ts +46 -43
  97. package/src/renderer/conversation-overlays.ts +25 -11
  98. package/src/renderer/footer-tips.ts +41 -0
  99. package/src/renderer/fullscreen-primitives.ts +22 -16
  100. package/src/renderer/help-overlay.ts +91 -14
  101. package/src/renderer/hint-grammar.ts +52 -0
  102. package/src/renderer/layout.ts +7 -7
  103. package/src/renderer/modal-factory.ts +23 -15
  104. package/src/renderer/model-picker-overlay.ts +30 -11
  105. package/src/renderer/model-workspace.ts +2 -3
  106. package/src/renderer/overlay-box.ts +16 -10
  107. package/src/renderer/panel-composite.ts +7 -20
  108. package/src/renderer/panel-workspace-bar.ts +14 -8
  109. package/src/renderer/process-indicator.ts +3 -1
  110. package/src/renderer/progress.ts +8 -6
  111. package/src/renderer/search-overlay.ts +27 -6
  112. package/src/renderer/session-picker-modal.ts +6 -4
  113. package/src/renderer/settings-modal.ts +70 -10
  114. package/src/renderer/shell-surface.ts +41 -15
  115. package/src/renderer/status-glyphs.ts +11 -9
  116. package/src/renderer/tab-strip.ts +148 -34
  117. package/src/renderer/theme.ts +60 -3
  118. package/src/renderer/ui-factory.ts +45 -36
  119. package/src/renderer/ui-primitives.ts +23 -2
  120. package/src/runtime/bootstrap-shell.ts +35 -18
  121. package/src/runtime/diagnostics/panels/index.ts +0 -3
  122. package/src/runtime/ui/model-picker/health-enrichment.ts +3 -0
  123. package/src/runtime/ui/model-picker/types.ts +4 -0
  124. package/src/shell/ui-openers.ts +14 -22
  125. package/src/utils/format-duration.ts +55 -0
  126. package/src/utils/format-number.ts +71 -0
  127. package/src/utils/splash-lines.ts +44 -3
  128. package/src/version.ts +1 -1
  129. package/src/work-plans/work-plan-store.ts +13 -0
  130. package/src/panels/agent-logs-panel.ts +0 -666
  131. package/src/panels/agent-logs-shared.ts +0 -129
  132. package/src/panels/context-visualizer-panel.ts +0 -214
  133. package/src/panels/forensics-panel.ts +0 -364
  134. package/src/panels/panel-picker.ts +0 -106
  135. package/src/panels/provider-account-snapshot.ts +0 -259
  136. package/src/panels/provider-accounts-panel.ts +0 -218
  137. package/src/panels/provider-stats-panel.ts +0 -366
  138. package/src/panels/schedule-panel.ts +0 -342
  139. package/src/panels/watchers-panel.ts +0 -193
  140. package/src/renderer/panel-picker-overlay.ts +0 -202
  141. package/src/renderer/panel-tab-bar.ts +0 -69
  142. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  143. package/src/runtime/diagnostics/panels/policy.ts +0 -177
@@ -24,6 +24,7 @@ import {
24
24
  type PanelWorkspaceSection,
25
25
  } from './polish.ts';
26
26
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
27
+ import { buildAnswerActions, isGenericRecommendation, type PlanningAnswerAction } from './project-planning-answer-actions.ts';
27
28
 
28
29
  const C = extendPalette(DEFAULT_PANEL_PALETTE, {
29
30
  planning: '#38bdf8',
@@ -48,15 +49,6 @@ export interface ProjectPlanningPanelOptions {
48
49
  readonly dismissPlanning?: () => void;
49
50
  }
50
51
 
51
- interface PlanningAnswerAction {
52
- readonly id: string;
53
- readonly label: string;
54
- readonly detail: string;
55
- readonly answer: string;
56
- readonly kind?: 'answer' | 'approve' | 'dismiss';
57
- readonly disabled?: boolean;
58
- }
59
-
60
52
  interface RenderedPlanningSection extends PanelWorkspaceSection {
61
53
  readonly selectedLineIndex?: number;
62
54
  }
@@ -111,9 +103,32 @@ export class ProjectPlanningPanel extends BasePanel {
111
103
  }
112
104
  // confirmResult === 'inactive': proceed with normal dispatch.
113
105
 
106
+ // Ctrl+R (refresh) / Ctrl+A (approve) are alternate bindings for 'r'/'a'
107
+ // that stay reachable while a question is active, where plain 'r'/'a'
108
+ // are swallowed into the draft-answer text below instead. They are
109
+ // checked before the question gate so they work in both modes.
110
+ //
111
+ // NOTE: the input-routing layer (src/input/handler-feed-routes.ts, owned
112
+ // by WO-150 in this wave) does not yet forward ctrl-modified keys to the
113
+ // active panel — it currently intercepts all `token.ctrl` input before
114
+ // panel.handleInput is ever called, and a bare Ctrl+R is already bound
115
+ // globally to 'history-search'. This handler recognizes the logical key
116
+ // strings 'ctrl+r'/'ctrl+a' so the panel-side behavior is correct and
117
+ // testable now; wiring a real Ctrl+R/Ctrl+A keypress through to these
118
+ // strings is an input-handler change outside this work order's file
119
+ // scope.
120
+ if (key === 'ctrl+r') {
121
+ this.refresh(true);
122
+ return true;
123
+ }
124
+ if (key === 'ctrl+a') {
125
+ this.approveExecution();
126
+ return true;
127
+ }
128
+
114
129
  const question = this.getCurrentQuestion();
115
130
  if (question) {
116
- const actions = this.getAnswerActions(question);
131
+ const actions = buildAnswerActions(question, this.draftAnswer);
117
132
  this.selectedActionIndex = this.clampActionIndex(actions.length);
118
133
  if (key === 'up') {
119
134
  this.selectedActionIndex = Math.max(0, this.selectedActionIndex - 1);
@@ -204,9 +219,15 @@ export class ProjectPlanningPanel extends BasePanel {
204
219
  { label: 'space', value: status?.knowledgeSpaceId ?? `project:${this.projectId}`, valueColor: C.value },
205
220
  { label: 'mode', value: 'TUI-owned passive backing store', valueColor: C.info },
206
221
  ], C),
207
- buildPanelLine(width, [
208
- [' Planning never starts from daemon, webhooks, ntfy, Home Assistant, or companion surfaces.', C.dim],
209
- ]),
222
+ // Live artifact counts from the SDK status route (same counts /plan
223
+ // prints at planning-runtime.ts:90) instead of static filler prose.
224
+ status
225
+ ? buildKeyValueLine(width, [
226
+ { label: 'states', value: String(status.counts.states), valueColor: status.counts.states > 0 ? C.value : C.dim },
227
+ { label: 'decisions', value: String(status.counts.decisions), valueColor: status.counts.decisions > 0 ? C.value : C.dim },
228
+ { label: 'language', value: String(status.counts.languageArtifacts), valueColor: status.counts.languageArtifacts > 0 ? C.value : C.dim },
229
+ ], C)
230
+ : buildPanelLine(width, [[' Artifact counts unavailable — refreshing…', C.dim]]),
210
231
  ],
211
232
  });
212
233
 
@@ -227,6 +248,7 @@ export class ProjectPlanningPanel extends BasePanel {
227
248
  if (question) sections.push(this.buildQuestionSection(width, question));
228
249
  sections.push(this.buildGapsSection(width, evaluation));
229
250
  sections.push(this.buildTasksSection(width, state));
251
+ sections.push(this.buildAnsweredHistorySection(width, state));
230
252
  sections.push(this.buildDecisionsSection(width, state, decisions));
231
253
  sections.push(this.buildLanguageSection(width, language));
232
254
  }
@@ -278,6 +300,12 @@ export class ProjectPlanningPanel extends BasePanel {
278
300
  ['Enter', C.info],
279
301
  [' submit Esc prompt focus Ctrl+X close panel', C.dim],
280
302
  ]),
303
+ buildPanelLine(width, [
304
+ [' Ctrl+R', C.info],
305
+ [' refresh ', C.dim],
306
+ ['Ctrl+A', C.info],
307
+ [' approve (r/a type into the draft while a question is active)', C.dim],
308
+ ]),
281
309
  ];
282
310
  }
283
311
  return [
@@ -311,7 +339,7 @@ export class ProjectPlanningPanel extends BasePanel {
311
339
  }
312
340
 
313
341
  private buildQuestionSection(width: number, question: ProjectPlanningQuestion): RenderedPlanningSection {
314
- const actions = this.getAnswerActions(question);
342
+ const actions = buildAnswerActions(question, this.draftAnswer);
315
343
  this.selectedActionIndex = this.clampActionIndex(actions.length);
316
344
  // When a clear-draft confirmation is pending, show the confirm prompt
317
345
  // inline above the draft line instead of the normal content.
@@ -329,7 +357,7 @@ export class ProjectPlanningPanel extends BasePanel {
329
357
  if (question.whyItMatters) {
330
358
  lines.push(...buildBodyText(width, `Why this matters: ${question.whyItMatters}`, C, C.dim));
331
359
  }
332
- if (question.recommendedAnswer && !this.isGenericRecommendation(question.recommendedAnswer)) {
360
+ if (question.recommendedAnswer && !isGenericRecommendation(question.recommendedAnswer)) {
333
361
  lines.push(...buildBodyText(width, `Recommendation: ${question.recommendedAnswer}`, C, C.good));
334
362
  }
335
363
  lines.push(...buildBodyText(
@@ -367,12 +395,34 @@ export class ProjectPlanningPanel extends BasePanel {
367
395
  : readiness === 'needs-user-input'
368
396
  ? C.blocked
369
397
  : C.dim;
398
+ const blockingGaps = (evaluation?.gaps ?? []).filter((gap) => gap.severity === 'blocking').length;
399
+ const openQuestions = state.openQuestions.filter((q) => (q.status ?? 'open') === 'open').length;
400
+ // Surface the most important thing first: is this plan executable, and what
401
+ // is the single blocker to getting there.
402
+ const nextStep = state.executionApproved
403
+ ? 'approved — execution may proceed'
404
+ : openQuestions > 0
405
+ ? `answer ${openQuestions} open question${openQuestions === 1 ? '' : 's'}`
406
+ : blockingGaps > 0
407
+ ? `resolve ${blockingGaps} blocking gap${blockingGaps === 1 ? '' : 's'}`
408
+ : readiness === 'executable'
409
+ ? 'press a to approve execution'
410
+ : 'continue the planning interview';
370
411
  const lines: Line[] = [
371
412
  buildKeyValueLine(width, [
372
413
  { label: 'readiness', value: readiness, valueColor: readinessColor },
373
414
  { label: 'approved', value: state.executionApproved ? 'yes' : 'no', valueColor: state.executionApproved ? C.approved : C.blocked },
374
415
  { label: 'questions', value: `${state.openQuestions.length} open / ${state.answeredQuestions.length} answered`, valueColor: C.value },
375
416
  ], C),
417
+ buildKeyValueLine(width, [
418
+ { label: 'blocking gaps', value: String(blockingGaps), valueColor: blockingGaps > 0 ? C.blocked : C.good },
419
+ { label: 'tasks', value: String(state.tasks.length), valueColor: state.tasks.length > 0 ? C.value : C.dim },
420
+ { label: 'gates', value: String(state.verificationGates.length), valueColor: state.verificationGates.length > 0 ? C.good : C.dim },
421
+ ], C),
422
+ buildPanelLine(width, [
423
+ [' Next step ', C.label],
424
+ [nextStep, state.executionApproved ? C.approved : C.planning],
425
+ ]),
376
426
  ...buildBodyText(width, `Goal: ${state.goal || '(not set)'}`, C, state.goal ? C.value : C.blocked),
377
427
  ];
378
428
  if (state.scope) lines.push(...buildBodyText(width, `Scope: ${state.scope}`, C, C.value));
@@ -384,7 +434,7 @@ export class ProjectPlanningPanel extends BasePanel {
384
434
  if (evaluation.nextQuestion.whyItMatters) {
385
435
  lines.push(...buildBodyText(width, `Why it matters: ${evaluation.nextQuestion.whyItMatters}`, C, C.dim));
386
436
  }
387
- if (evaluation.nextQuestion.recommendedAnswer && !this.isGenericRecommendation(evaluation.nextQuestion.recommendedAnswer)) {
437
+ if (evaluation.nextQuestion.recommendedAnswer && !isGenericRecommendation(evaluation.nextQuestion.recommendedAnswer)) {
388
438
  lines.push(...buildBodyText(width, `Recommended answer: ${evaluation.nextQuestion.recommendedAnswer}`, C, C.good));
389
439
  }
390
440
  }
@@ -447,6 +497,24 @@ export class ProjectPlanningPanel extends BasePanel {
447
497
  return { title: 'Task Graph', lines };
448
498
  }
449
499
 
500
+ private buildAnsweredHistorySection(width: number, state: ProjectPlanningState): PanelWorkspaceSection {
501
+ const answered = state.answeredQuestions;
502
+ if (answered.length === 0) {
503
+ return {
504
+ title: 'Answered Questions',
505
+ lines: [buildPanelLine(width, [[' No questions answered yet.', C.dim]])],
506
+ };
507
+ }
508
+ const ordered = [...answered].sort((a, b) => (b.answeredAt ?? 0) - (a.answeredAt ?? 0));
509
+ return {
510
+ title: 'Answered Questions',
511
+ lines: ordered.slice(0, 12).flatMap((entry) => [
512
+ ...buildBodyText(width, `Q: ${entry.prompt}`, C, C.value),
513
+ ...buildBodyText(width, `A: ${entry.answer?.trim() || '(no answer recorded)'}`, C, entry.answer?.trim() ? C.good : C.dim),
514
+ ]),
515
+ };
516
+ }
517
+
450
518
  private buildDecisionsSection(
451
519
  width: number,
452
520
  state: ProjectPlanningState,
@@ -528,98 +596,6 @@ export class ProjectPlanningPanel extends BasePanel {
528
596
  return open ?? this.snapshot?.evaluation?.nextQuestion ?? null;
529
597
  }
530
598
 
531
- private getAnswerActions(question: ProjectPlanningQuestion): PlanningAnswerAction[] {
532
- const actions: PlanningAnswerAction[] = [];
533
- const prompt = question.prompt.toLowerCase();
534
- const isScopeQuestion = prompt.includes('scope') || prompt.includes('in or out');
535
- const isTaskQuestion = prompt.includes('task') || prompt.includes('dependency') || prompt.includes('work breakdown');
536
- const isVerificationQuestion = prompt.includes('verification') || prompt.includes('test') || prompt.includes('prove');
537
- const isApprovalQuestion = prompt.includes('approved') || prompt.includes('approve') || prompt.includes('execution');
538
- if (isApprovalQuestion) {
539
- actions.push({
540
- id: 'approve-execution',
541
- label: 'Approve execution',
542
- detail: 'Mark this plan approved so execution may proceed.',
543
- answer: 'Approve this planning state for execution.',
544
- kind: 'approve',
545
- });
546
- }
547
- if (isScopeQuestion) {
548
- actions.push({
549
- id: 'scope-focused-first-pass',
550
- label: 'Use focused first-pass scope',
551
- detail: 'Fill a concrete end-to-end scope for this goal and keep unrelated work out.',
552
- answer: 'Use a focused first-pass scope for this goal.',
553
- });
554
- }
555
- if (isTaskQuestion) {
556
- actions.push({
557
- id: 'tasks-default-breakdown',
558
- label: 'Create default task breakdown',
559
- detail: 'Create inspect, implement, wire, and verify tasks with dependencies.',
560
- answer: 'Create the default task breakdown for this goal.',
561
- });
562
- }
563
- if (isVerificationQuestion) {
564
- actions.push({
565
- id: 'verification-default-gates',
566
- label: 'Use standard verification gates',
567
- detail: 'Require focused regression coverage, typecheck/build validation, and a runtime smoke where feasible.',
568
- answer: 'Use standard verification gates for this goal.',
569
- });
570
- }
571
- if (question.recommendedAnswer?.trim() && !this.isGenericRecommendation(question.recommendedAnswer)) {
572
- actions.push({
573
- id: 'recommended',
574
- label: 'Use recommended answer',
575
- detail: this.compact(question.recommendedAnswer),
576
- answer: question.recommendedAnswer,
577
- });
578
- }
579
- if (isScopeQuestion) {
580
- actions.push({
581
- id: 'scope-end-to-end',
582
- label: 'End-to-end required scope',
583
- detail: 'Let the plan include every component needed to make this work, but avoid unrelated cleanup.',
584
- answer: 'Scope is everything required to make the requested outcome work end-to-end. Include TUI, daemon composition, configuration, docs, and tests if they are required. Do not include unrelated cleanup or broad refactors unless they are necessary for this task.',
585
- });
586
- actions.push({
587
- id: 'scope-tui-first',
588
- label: 'TUI-first scope',
589
- detail: 'Fix TUI behavior here; report SDK blockers instead of patching around SDK-owned bugs.',
590
- answer: 'Scope is TUI-owned behavior first. If a blocker is SDK-owned, report the exact SDK contract/runtime issue instead of patching around it in the TUI. Include daemon composition only where the TUI owns the wiring.',
591
- });
592
- }
593
- actions.push({
594
- id: 'ask-narrower',
595
- label: 'I am not sure yet',
596
- detail: 'Break this into smaller concrete choices with examples and a recommended default.',
597
- answer: `I do not know enough to answer "${question.prompt}" as asked. Break it into smaller concrete questions with 2-4 specific choices, explain the tradeoffs, recommend a default, and ask me the first one.`,
598
- });
599
- actions.push({
600
- id: 'custom',
601
- label: 'Submit typed answer',
602
- detail: this.draftAnswer ? this.compact(this.draftAnswer) : 'Type an answer first; this row becomes the custom answer.',
603
- answer: this.draftAnswer.trim(),
604
- disabled: !this.draftAnswer.trim(),
605
- });
606
- actions.push({
607
- id: 'dismiss-planning',
608
- label: 'Close planning and continue without it',
609
- detail: 'Pause project planning for this workspace. Normal chat continues; /plan can reopen it later.',
610
- answer: 'Pause project planning for this workspace and continue without the planning panel.',
611
- kind: 'dismiss',
612
- });
613
- return actions;
614
- }
615
-
616
- private isGenericRecommendation(value: string): boolean {
617
- return /\bdefine the first-pass scope\b/i.test(value)
618
- || /\bcreate task records\b/i.test(value)
619
- || /\brecord concrete tests\b/i.test(value)
620
- || /\bseparate out-of-scope work\b/i.test(value);
621
- }
622
-
623
599
  private submitSelectedAction(question: ProjectPlanningQuestion, actions: readonly PlanningAnswerAction[]): void {
624
600
  const action = actions[this.clampActionIndex(actions.length)];
625
601
  if (!action || action.disabled || !action.answer.trim()) {
@@ -714,11 +690,6 @@ export class ProjectPlanningPanel extends BasePanel {
714
690
  return key.length === 1 && key >= ' ';
715
691
  }
716
692
 
717
- private compact(text: string): string {
718
- const normalized = text.replace(/\s+/g, ' ').trim();
719
- return normalized.length > 86 ? `${normalized.slice(0, 83)}...` : normalized;
720
- }
721
-
722
693
  private approveExecution(): void {
723
694
  const state = this.snapshot?.state;
724
695
  if (!state) {