pi-agent: Fix final integrated review

This commit is contained in:
proxyctl coordinator
2026-07-18 02:37:54 +08:00
parent ed8b527f1f
commit 652d7eba2b
18 changed files with 566 additions and 393 deletions
+37 -35
View File
@@ -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")