@siuver/omp-debug-mode 0.1.3 → 0.1.4

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/src/ui.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import type { ExtensionContext } from "@oh-my-pi/pi-coding-agent";
2
2
  import { PROCEED_REMINDER } from "./methodology";
3
- import type { DebugState } from "./state";
3
+ import type { DebugState, EvidenceRequest } from "./state";
4
+ import { pendingEvidenceRequests } from "./state";
4
5
 
5
- /** `setWidget` caps string-array widgets at 10 lines. */
6
6
  export const WIDGET_MAX_LINES = 10;
7
- const WIDGET_MAX_STEPS = 6;
8
7
  const WIDGET_MAX_WIDTH = 90;
9
8
 
10
9
  export type WidgetTone = "accent" | "dim";
@@ -24,6 +23,13 @@ function clip(text: string): string {
24
23
  return text.length > WIDGET_MAX_WIDTH ? `${text.slice(0, WIDGET_MAX_WIDTH - 1)}…` : text;
25
24
  }
26
25
 
26
+ /** The command surface is the only interaction path at the gate. */
27
+ const COMMAND_LINES = [
28
+ "/debug-proceed [details]",
29
+ "/debug-evidence <request-id> <path>",
30
+ "/debug-done · /debug-abort · /debug-status",
31
+ ] as const;
32
+
27
33
  function plural(count: number, singular: string): string {
28
34
  return `${count} ${singular}${count === 1 ? "" : "s"}`;
29
35
  }
@@ -33,27 +39,46 @@ function logEntries(count: number): string {
33
39
  }
34
40
 
35
41
  /**
36
- * Reproduction-gate widget: the call to action, an excerpt of the agent's
37
- * reproduction steps, and the live evidence counter. Always within the host's
38
- * line budget so nothing important is silently dropped.
42
+ * Reproduction-gate widget: the call to action, pending user evidence,
43
+ * reproduction-step context, the command surface, and the live evidence
44
+ * counter. Commands are the only interaction path — there is no menu. The
45
+ * live log counter is always the final line within the host's line budget.
39
46
  */
40
- export function waitingWidgetLines(state: DebugState, logCount: number): WidgetLine[] {
47
+ export function waitingWidgetLines(
48
+ state: DebugState,
49
+ logCount: number,
50
+ pendingEvidence: EvidenceRequest[] = pendingEvidenceRequests(state, state.round),
51
+ ): WidgetLine[] {
41
52
  const lines: WidgetLine[] = [{ text: PROCEED_REMINDER, tone: "accent" }];
42
- const shown = state.reproductionSteps.slice(0, WIDGET_MAX_STEPS);
43
- for (const step of shown) lines.push({ text: clip(step), tone: "dim" });
44
- const hidden = state.reproductionSteps.length - shown.length;
45
- if (hidden > 0) lines.push({ text: `… +${plural(hidden, "more step")} in the transcript`, tone: "dim" });
53
+ for (const request of pendingEvidence.slice(0, 2)) {
54
+ lines.push({ text: clip(`↪ ${request.id} ${request.title}: ${request.instructions[0] ?? ""}`), tone: "accent" });
55
+ }
56
+ for (const command of COMMAND_LINES) lines.push({ text: command, tone: "accent" });
57
+
58
+ // Reproduction details are useful context, but command discoverability and
59
+ // the live log counter must survive the host's ten-line widget limit.
60
+ const reserved = lines.length + 2;
61
+ const stepBudget = Math.max(0, WIDGET_MAX_LINES - reserved);
62
+ if (stepBudget > 0 && state.reproductionSteps.length > 0) {
63
+ const showMoreLine = state.reproductionSteps.length > stepBudget;
64
+ const shownCount = showMoreLine ? Math.max(0, stepBudget - 1) : stepBudget;
65
+ for (const step of state.reproductionSteps.slice(0, shownCount)) {
66
+ lines.push({ text: clip(step), tone: "dim" });
67
+ }
68
+ const hidden = state.reproductionSteps.length - shownCount;
69
+ if (hidden > 0) lines.push({ text: `… +${plural(hidden, "more step")} in the transcript`, tone: "dim" });
70
+ }
46
71
  lines.push({
47
- text: `/debug-menu · run ${state.runId ?? "none"} ${logEntries(logCount)}`,
72
+ text: `evidence: ${plural(pendingEvidence.length, "pending request")}, ${plural(state.evidenceArtifacts.length, "attached artifact")}`,
73
+ tone: pendingEvidence.length > 0 || state.evidenceArtifacts.length > 0 ? "accent" : "dim",
74
+ });
75
+ lines.push({
76
+ text: `run ${state.runId ?? "none"} — ${logEntries(logCount)}`,
48
77
  tone: logCount > 0 ? "accent" : "dim",
49
78
  });
50
79
  return lines.slice(0, WIDGET_MAX_LINES);
51
80
  }
52
81
 
53
- export function reviewMenuTitle(round: number, logCount: number, probeCount: number): string {
54
- return `Review debug round ${round} · ${logEntries(logCount)} · ${plural(probeCount, "probe")}`;
55
- }
56
-
57
82
  /**
58
83
  * Render the status entry and the reproduction widget. `getLogCount` is only
59
84
  * consulted at the reproduction gate so idle phases do not touch the log files.
@@ -1,22 +0,0 @@
1
- export const REVIEW_MARK_FIXED = "Mark as fixed";
2
- export const REVIEW_PROCEED = "Proceed";
3
- export const REVIEW_ADD_DETAILS = "Add reproduction details";
4
- export const REVIEW_ABORT = "Abort debug mode";
5
-
6
- export const REVIEW_OPTIONS = [
7
- REVIEW_MARK_FIXED,
8
- REVIEW_PROCEED,
9
- REVIEW_ADD_DETAILS,
10
- REVIEW_ABORT,
11
- ] as const;
12
-
13
- export const REVIEW_DESCRIPTIONS: Record<string, string> = {
14
- [REVIEW_MARK_FIXED]: "Remove every probe and summarize the root cause",
15
- [REVIEW_PROCEED]: "Read the captured logs, judge each hypothesis, continue",
16
- [REVIEW_ADD_DETAILS]: "Describe what you observed before continuing",
17
- [REVIEW_ABORT]: "Stop debugging and delete the logs; code changes stay",
18
- };
19
-
20
- export function reviewMenuOptions(): { label: string; description: string }[] {
21
- return REVIEW_OPTIONS.map(label => ({ label, description: REVIEW_DESCRIPTIONS[label] ?? "" }));
22
- }