@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.
- package/CHANGELOG.md +124 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/core/context-usage.ts +53 -0
- package/src/core/conversation.ts +4 -6
- package/src/core/session-recovery.ts +2 -0
- package/src/core/turn-event-wiring.ts +1 -0
- package/src/input/commands/cost-runtime.ts +49 -0
- package/src/input/commands/eval.ts +4 -3
- package/src/input/commands/operator-runtime.ts +5 -1
- package/src/input/commands.ts +2 -0
- package/src/input/handler-feed-routes.ts +60 -26
- package/src/input/handler-feed.ts +17 -8
- package/src/input/handler-picker-routes.ts +18 -13
- package/src/input/handler-shortcuts.ts +51 -0
- package/src/input/handler-ui-state.ts +4 -0
- package/src/input/handler.ts +43 -6
- package/src/input/keybindings.ts +53 -8
- package/src/input/model-picker.ts +5 -0
- package/src/input/panel-integration-actions.ts +117 -1
- package/src/main.ts +5 -2
- package/src/panels/agent-inspector-panel.ts +139 -45
- package/src/panels/agent-inspector-shared.ts +147 -3
- package/src/panels/approval-panel.ts +204 -102
- package/src/panels/automation-control-panel.ts +370 -103
- package/src/panels/base-panel.ts +26 -2
- package/src/panels/builtin/agent.ts +28 -37
- package/src/panels/builtin/development.ts +40 -32
- package/src/panels/builtin/knowledge.ts +15 -6
- package/src/panels/builtin/operations.ts +178 -117
- package/src/panels/builtin/session.ts +35 -9
- package/src/panels/builtin/shared.ts +98 -6
- package/src/panels/cockpit-panel.ts +253 -75
- package/src/panels/cockpit-read-model.ts +2 -1
- package/src/panels/communication-panel.ts +159 -56
- package/src/panels/confirm-state.ts +8 -1
- package/src/panels/control-plane-panel.ts +354 -95
- package/src/panels/cost-tracker-panel.ts +243 -57
- package/src/panels/debug-panel.ts +347 -159
- package/src/panels/diff-panel.ts +257 -82
- package/src/panels/docs-panel.ts +166 -64
- package/src/panels/eval-panel.ts +336 -109
- package/src/panels/expandable-list-panel.ts +189 -0
- package/src/panels/file-explorer-panel.ts +238 -159
- package/src/panels/file-preview-panel.ts +141 -59
- package/src/panels/git-panel.ts +360 -191
- package/src/panels/hooks-panel.ts +181 -19
- package/src/panels/incident-review-panel.ts +252 -43
- package/src/panels/index.ts +0 -4
- package/src/panels/intelligence-panel.ts +310 -103
- package/src/panels/knowledge-graph-panel.ts +480 -58
- package/src/panels/local-auth-panel.ts +251 -33
- package/src/panels/marketplace-panel.ts +219 -33
- package/src/panels/memory-panel.ts +83 -81
- package/src/panels/ops-control-panel.ts +211 -32
- package/src/panels/ops-strategy-panel.ts +131 -45
- package/src/panels/orchestration-panel.ts +259 -67
- package/src/panels/panel-list-panel.ts +184 -136
- package/src/panels/panel-manager.ts +120 -13
- package/src/panels/plan-dashboard-panel.ts +507 -74
- package/src/panels/plugins-panel.ts +227 -34
- package/src/panels/policy-panel.ts +264 -55
- package/src/panels/polish-core.ts +162 -0
- package/src/panels/polish-tables.ts +258 -0
- package/src/panels/polish.ts +67 -149
- package/src/panels/project-planning-answer-actions.ts +134 -0
- package/src/panels/project-planning-panel.ts +84 -113
- package/src/panels/provider-health-panel.ts +438 -480
- package/src/panels/provider-health-routes.ts +203 -0
- package/src/panels/provider-health-tracker.ts +194 -6
- package/src/panels/provider-health-views.ts +560 -0
- package/src/panels/qr-panel.ts +136 -38
- package/src/panels/remote-panel.ts +123 -38
- package/src/panels/routes-panel.ts +87 -24
- package/src/panels/sandbox-panel.ts +232 -65
- package/src/panels/scrollable-list-panel.ts +143 -145
- package/src/panels/security-panel.ts +204 -52
- package/src/panels/services-panel.ts +174 -76
- package/src/panels/session-browser-panel.ts +101 -6
- package/src/panels/session-maintenance.ts +4 -122
- package/src/panels/settings-sync-panel.ts +346 -68
- package/src/panels/skills-panel.ts +157 -89
- package/src/panels/subscription-panel.ts +105 -34
- package/src/panels/symbol-outline-panel.ts +287 -154
- package/src/panels/system-messages-panel.ts +172 -38
- package/src/panels/tasks-panel.ts +348 -134
- package/src/panels/thinking-panel.ts +66 -32
- package/src/panels/token-budget-panel.ts +233 -46
- package/src/panels/tool-inspector-panel.ts +170 -54
- package/src/panels/types.ts +65 -4
- package/src/panels/work-plan-panel.ts +393 -39
- package/src/panels/worktree-panel.ts +239 -61
- package/src/panels/wrfc-panel-format.ts +133 -0
- package/src/panels/wrfc-panel.ts +146 -150
- package/src/renderer/compaction-preview.ts +2 -1
- package/src/renderer/compositor.ts +46 -43
- package/src/renderer/conversation-overlays.ts +25 -11
- package/src/renderer/footer-tips.ts +41 -0
- package/src/renderer/fullscreen-primitives.ts +22 -16
- package/src/renderer/help-overlay.ts +91 -14
- package/src/renderer/hint-grammar.ts +52 -0
- package/src/renderer/layout.ts +7 -7
- package/src/renderer/modal-factory.ts +23 -15
- package/src/renderer/model-picker-overlay.ts +30 -11
- package/src/renderer/model-workspace.ts +2 -3
- package/src/renderer/overlay-box.ts +16 -10
- package/src/renderer/panel-composite.ts +7 -20
- package/src/renderer/panel-workspace-bar.ts +14 -8
- package/src/renderer/process-indicator.ts +3 -1
- package/src/renderer/progress.ts +8 -6
- package/src/renderer/search-overlay.ts +27 -6
- package/src/renderer/session-picker-modal.ts +6 -4
- package/src/renderer/settings-modal.ts +70 -10
- package/src/renderer/shell-surface.ts +41 -15
- package/src/renderer/status-glyphs.ts +11 -9
- package/src/renderer/tab-strip.ts +148 -34
- package/src/renderer/theme.ts +60 -3
- package/src/renderer/ui-factory.ts +45 -36
- package/src/renderer/ui-primitives.ts +23 -2
- package/src/runtime/bootstrap-shell.ts +35 -18
- package/src/runtime/diagnostics/panels/index.ts +0 -3
- package/src/runtime/ui/model-picker/health-enrichment.ts +3 -0
- package/src/runtime/ui/model-picker/types.ts +4 -0
- package/src/shell/ui-openers.ts +14 -22
- package/src/utils/format-duration.ts +55 -0
- package/src/utils/format-number.ts +71 -0
- package/src/utils/splash-lines.ts +44 -3
- package/src/version.ts +1 -1
- package/src/work-plans/work-plan-store.ts +13 -0
- package/src/panels/agent-logs-panel.ts +0 -666
- package/src/panels/agent-logs-shared.ts +0 -129
- package/src/panels/context-visualizer-panel.ts +0 -214
- package/src/panels/forensics-panel.ts +0 -364
- package/src/panels/panel-picker.ts +0 -106
- package/src/panels/provider-account-snapshot.ts +0 -259
- package/src/panels/provider-accounts-panel.ts +0 -218
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/schedule-panel.ts +0 -342
- package/src/panels/watchers-panel.ts +0 -193
- package/src/renderer/panel-picker-overlay.ts +0 -202
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- 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.
|
|
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
|
-
|
|
208
|
-
|
|
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.
|
|
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 && !
|
|
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 && !
|
|
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) {
|