pi-agent: Fix final integrated review
This commit is contained in:
+37
-35
@@ -57,54 +57,56 @@ func (m Model) dashboardQuitAvailable() bool {
|
||||
}
|
||||
|
||||
func (p terminalPresentation) helpDialogView(model presentationState) terminalPage {
|
||||
content := lipgloss.NewStyle().Width(max(1, model.width)).Render(protectRenderedText(p.contextualHelp(model)))
|
||||
content := lipgloss.NewStyle().Width(max(1, model.terminal.width)).Render(protectRenderedText(p.contextualHelp(model)))
|
||||
exitHint := "Ctrl+C: exit"
|
||||
if model.operationActive {
|
||||
if model.operation.active {
|
||||
exitHint = "Ctrl+C: defer safe exit"
|
||||
}
|
||||
if model.exitDeferred {
|
||||
if model.operation.exitDeferred {
|
||||
exitHint = "Exit pending until safe completion"
|
||||
}
|
||||
return terminalPage{
|
||||
primary: content,
|
||||
footer: "↑/k ↓/j PgUp/PgDn Home/End: scroll\nq/Esc: close Help " + exitHint,
|
||||
focusLine: -1,
|
||||
primaryOffset: model.help.offset,
|
||||
primaryOffset: model.help.dialog.offset,
|
||||
}
|
||||
}
|
||||
|
||||
func (p terminalPresentation) contextualHelp(model presentationState) string {
|
||||
dashboard, operation := model.dashboard, model.operation
|
||||
profiles, form := model.profile, model.form.state
|
||||
var body strings.Builder
|
||||
body.WriteString(p.theme.section.Render("Contextual Help"))
|
||||
body.WriteString("\nThis describes the page or dialog beneath Help. While Help is open, only its scrolling and closing keys plus global Ctrl+C are accepted; the underlying state remains unchanged.\n\n")
|
||||
|
||||
switch {
|
||||
case model.confirmation != nil:
|
||||
case operation.confirmation != nil:
|
||||
body.WriteString(p.theme.section.Render("Safety confirmation"))
|
||||
fmt.Fprintf(&body, "\n%s\n", model.confirmation.Title)
|
||||
if model.confirmation.Summary != "" {
|
||||
fmt.Fprintf(&body, "%s\n", model.confirmation.Summary)
|
||||
fmt.Fprintf(&body, "\n%s\n", operation.confirmation.Title)
|
||||
if operation.confirmation.Summary != "" {
|
||||
fmt.Fprintf(&body, "%s\n", operation.confirmation.Summary)
|
||||
}
|
||||
body.WriteString("Left/Right, Tab, or Shift+Tab changes the focused choice. Enter chooses it. y confirms. n, q, or Escape cancels. ")
|
||||
if model.confirmationDialog != nil {
|
||||
if operation.confirmationDialog != nil {
|
||||
body.WriteByte('\n')
|
||||
body.WriteString(confirmationFocusDescription(*model.confirmationDialog))
|
||||
body.WriteString(confirmationFocusDescription(*operation.confirmationDialog))
|
||||
}
|
||||
body.WriteByte('\n')
|
||||
case model.profileDelete != nil:
|
||||
case profiles.deletion != nil:
|
||||
body.WriteString(p.theme.section.Render("Delete confirmation"))
|
||||
fmt.Fprintf(&body, "\nDelete Proxy Profile %q. Deletion cannot be undone.\n", model.profileDelete.name)
|
||||
fmt.Fprintf(&body, "\nDelete Proxy Profile %q. Deletion cannot be undone.\n", profiles.deletion.name)
|
||||
body.WriteString("Left/Right, Tab, or Shift+Tab changes the focused choice. Enter chooses it. y deletes. n, q, or Escape cancels. ")
|
||||
body.WriteByte('\n')
|
||||
body.WriteString(confirmationFocusDescription(model.profileDelete.dialog))
|
||||
body.WriteString(confirmationFocusDescription(profiles.deletion.dialog))
|
||||
body.WriteByte('\n')
|
||||
case model.picker.open:
|
||||
case dashboard.picker.open:
|
||||
body.WriteString(p.theme.section.Render("Active Profile picker"))
|
||||
body.WriteString("\nType to filter Proxy Profiles; q is ordinary search input here. Up/Down or Ctrl+P/Ctrl+N selects, and PgUp/PgDn moves by a page. Enter activates the selection. Escape cancels.\n")
|
||||
case model.driftResolutionTargetID != "":
|
||||
case dashboard.driftResolutionTargetID != "":
|
||||
body.WriteString(p.theme.section.Render("Drift Resolution dialog"))
|
||||
body.WriteString("\nr reapplies the Active Profile. o restores original configuration when ownership evidence permits. Enter, q, or Escape cancels.\n")
|
||||
if selected, ok := newTargetCatalog(model.snapshot, true, model.driftResolutionTargetID).selected(model.driftResolutionTargetID); ok {
|
||||
if selected, ok := newTargetCatalog(model.snapshot, true, dashboard.driftResolutionTargetID).selected(dashboard.driftResolutionTargetID); ok {
|
||||
for _, kind := range []app.TargetActionKind{app.ReapplyActiveProfileAction, app.RestoreOriginalAction} {
|
||||
action, found := driftResolutionAction(selected, kind)
|
||||
if found && action.Available {
|
||||
@@ -120,10 +122,10 @@ func (p terminalPresentation) contextualHelp(model presentationState) string {
|
||||
}
|
||||
case model.page == profilesPage:
|
||||
body.WriteString(p.theme.section.Render("Profile management"))
|
||||
if selected, ok := profileAt(model.snapshot, model.selected); ok {
|
||||
if selected, ok := profileAt(model.snapshot, profiles.selected); ok {
|
||||
fmt.Fprintf(&body, "\nSelected Profile: %s.\n", selected.Name)
|
||||
body.WriteString("Up/Down or j/k selects a Profile. PgUp/PgDn scrolls its details. n creates, e or Enter edits, and d opens the delete confirmation. q or Escape returns to the dashboard.\n")
|
||||
if model.operationActive || model.exitDeferred {
|
||||
if operation.active || operation.exitDeferred {
|
||||
body.WriteString("Profile modifications are disabled until the current mutation completes.\n")
|
||||
} else {
|
||||
body.WriteString("Create, Edit selected Profile, and Delete selected Profile are available.\n")
|
||||
@@ -133,36 +135,36 @@ func (p terminalPresentation) contextualHelp(model presentationState) string {
|
||||
}
|
||||
case model.page == formPage:
|
||||
body.WriteString(p.theme.section.Render("Profile form"))
|
||||
if model.form.field >= 0 && model.form.field < len(model.form.inputs) {
|
||||
fmt.Fprintf(&body, "\nFocus: %s field.\n", model.form.inputs[model.form.field].label)
|
||||
if form.field >= 0 && form.field < len(form.inputs) {
|
||||
fmt.Fprintf(&body, "\nFocus: %s field.\n", form.inputs[form.field].label)
|
||||
}
|
||||
body.WriteString("Type or paste to insert at the cursor. Left/Right moves the cursor; Home/End moves to the field boundary; Backspace/Delete removes text. Long inputs scroll horizontally. Tab or Down moves to the next field; Shift+Tab or Up moves to the previous field. Ctrl+T changes mode while preserving Profile values. Ctrl+S validates and saves. q or Escape cancels and returns to Profile management.\n")
|
||||
if model.form.currentField() == profile.BypassField {
|
||||
if form.currentField() == profile.BypassField {
|
||||
body.WriteString("PgUp/PgDn scrolls the normalized Bypass preview while the Bypass field is focused.\n")
|
||||
}
|
||||
if model.form.profile.Mode == profile.SingleMode {
|
||||
if form.profile.Mode == profile.SingleMode {
|
||||
switch {
|
||||
case model.form.probe.active:
|
||||
case form.probe.active:
|
||||
body.WriteString("Protocol Probe is in progress for the Single proxy URL field. Its progress remains attached to that field; Ctrl+D does not start a duplicate probe while that field is focused.\n")
|
||||
case model.form.currentField() == profile.SingleURLField:
|
||||
case form.currentField() == profile.SingleURLField:
|
||||
body.WriteString("Ctrl+D explicitly runs Protocol Probe for the focused Single proxy URL field. It never runs on form entry, focus changes, or save.\n")
|
||||
default:
|
||||
body.WriteString("The Single proxy URL field visibly offers Protocol Probe; focus that field and press Ctrl+D to run it explicitly.\n")
|
||||
}
|
||||
} else if model.form.hasProbeSourceAttachment() {
|
||||
} else if form.hasProbeSourceAttachment() {
|
||||
body.WriteString("The Protocol Probe result remains attached to its read-only initiating Single proxy URL context. The HTTP, HTTPS, and ALL/SOCKS values were generated from that probe.\n")
|
||||
}
|
||||
default:
|
||||
body.WriteString(p.theme.section.Render("Dashboard"))
|
||||
focus := "Targets focus"
|
||||
if model.dashboardFocus == targetDetailsPane {
|
||||
if dashboard.focus == targetDetailsPane {
|
||||
focus = "Target details focus"
|
||||
}
|
||||
fmt.Fprintf(&body, "\nContext: %s.\n", focus)
|
||||
catalog := newTargetCatalog(model.snapshot, model.showUnavailable, model.selectedTargetID)
|
||||
if selected, ok := catalog.selected(model.selectedTargetID); ok {
|
||||
catalog := newTargetCatalog(model.snapshot, dashboard.showUnavailable, dashboard.selectedTargetID)
|
||||
if selected, ok := catalog.selected(dashboard.selectedTargetID); ok {
|
||||
fmt.Fprintf(&body, "Selected Target: %s. State: %s.\n", selected.Description.Name, targetStateLabel(selected.State))
|
||||
availability := targetMutationAvailability(selected, true, model.operationActive || model.exitDeferred)
|
||||
availability := targetMutationAvailability(selected, true, operation.active || operation.exitDeferred)
|
||||
label := targetActionLabel(selected.PrimaryAction.Kind)
|
||||
if availability.available {
|
||||
fmt.Fprintf(&body, "Primary action: %s — available with Space.\n", label)
|
||||
@@ -170,12 +172,12 @@ func (p terminalPresentation) contextualHelp(model presentationState) string {
|
||||
fmt.Fprintf(&body, "Primary action: %s — disabled: %s.\n", label, availability.reason)
|
||||
}
|
||||
}
|
||||
if model.dashboardFocus == targetDetailsPane {
|
||||
if dashboard.focus == targetDetailsPane {
|
||||
body.WriteString("Up/Down, j/k, and PgUp/PgDn scroll Target details. Tab focuses Targets.\n")
|
||||
} else {
|
||||
body.WriteString("Up/Down or j/k selects a Target. Tab focuses Target details.\n")
|
||||
}
|
||||
if model.operationActive || model.exitDeferred {
|
||||
if operation.active || operation.exitDeferred {
|
||||
body.WriteString("u still shows or hides unavailable Targets. p, m, r, and Space modifications are disabled until the current mutation completes.\n")
|
||||
} else {
|
||||
body.WriteString("u shows or hides unavailable Targets. p opens the Active Profile picker. m opens Profile management. r refreshes Targets.\n")
|
||||
@@ -185,18 +187,18 @@ func (p terminalPresentation) contextualHelp(model presentationState) string {
|
||||
body.WriteString("\n")
|
||||
body.WriteString(p.theme.section.Render("Operation state"))
|
||||
switch {
|
||||
case model.exitDeferred:
|
||||
case operation.exitDeferred:
|
||||
body.WriteString("\nExit is pending. Read-only browsing and Help remain available; all new work is disabled until the mutation completes safely.\n")
|
||||
case model.operationActive:
|
||||
case operation.active:
|
||||
body.WriteString("\nMutation in progress. Target selection, details scrolling, and Help remain available.\nConflicting mutations are disabled until completion. Ctrl+C requests a deferred safe exit.\n")
|
||||
default:
|
||||
body.WriteString("\nNo mutation is in progress. Ctrl+C exits immediately.\n")
|
||||
}
|
||||
if model.currentError != nil && model.page == mainPage && model.confirmation == nil && !model.picker.open && model.driftResolutionTargetID == "" {
|
||||
if operation.currentError != nil && model.page == mainPage && operation.confirmation == nil && !dashboard.picker.open && dashboard.driftResolutionTargetID == "" {
|
||||
body.WriteString("e expands or collapses the current error; x acknowledges it.\n")
|
||||
}
|
||||
|
||||
if model.page == mainPage && model.profileDelete == nil {
|
||||
if model.page == mainPage && profiles.deletion == nil {
|
||||
body.WriteString("\n")
|
||||
body.WriteString(p.theme.section.Render("Built-in Target reference"))
|
||||
body.WriteString("\n")
|
||||
|
||||
Reference in New Issue
Block a user