pi-better-harness 0.1.16 → 0.1.17

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-goal",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Pi extension for goal tracking with background-aware continuation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,7 +23,7 @@ interface GoalLike {
23
23
  completedAt?: number | null;
24
24
  }
25
25
 
26
- export type GoalEntrySource = "command" | "tool" | "runtime" | "shortcut";
26
+ export type GoalEntrySource = "command" | "tool" | "runtime";
27
27
 
28
28
  export interface ContinuationState {
29
29
  goalId: string;
@@ -74,6 +74,26 @@ function parseRetryLimit(raw: string | undefined, fallback: number): number {
74
74
  return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
75
75
  }
76
76
 
77
+ /**
78
+ * True when the agent loop ended because the running turn was interrupted
79
+ * (escape / ctrl+c). An aborted run leaves a final assistant message whose
80
+ * stopReason is "aborted".
81
+ */
82
+ function wasTurnAborted(messages: readonly unknown[]): boolean {
83
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
84
+ const message = messages[index];
85
+ if (!message || typeof message !== "object") {
86
+ continue;
87
+ }
88
+ const candidate = message as { role?: unknown; stopReason?: unknown };
89
+ if (candidate.role !== "assistant") {
90
+ continue;
91
+ }
92
+ return candidate.stopReason === "aborted";
93
+ }
94
+ return false;
95
+ }
96
+
77
97
  function continuationPrompt(goal: GoalSnapshot): string {
78
98
  return [
79
99
  "Continue working toward the active thread goal.",
@@ -543,24 +563,6 @@ export default function (pi: ExtensionAPI): void {
543
563
  },
544
564
  });
545
565
 
546
- pi.registerShortcut("escape", {
547
- description: "Pause the active goal (also interrupts a running agent turn)",
548
- handler: (ctx) => {
549
- const goal = getGoal(ctx);
550
- const running = !ctx.isIdle();
551
- if (isPokeable(goal)) {
552
- setGoal(goalWithStatus(goal, "paused"), ctx, "shortcut");
553
- if (ctx.hasUI) {
554
- ctx.ui.notify("Goal paused.", "info");
555
- }
556
- }
557
- if (running) {
558
- // ESC keeps its built-in interrupt meaning while the agent is streaming.
559
- ctx.abort();
560
- }
561
- },
562
- });
563
-
564
566
  pi.registerCommand("better-activity", {
565
567
  description: "Show foreground/background activity known to pi-better-goal",
566
568
  handler: async (_args, ctx) => {
@@ -631,8 +633,21 @@ export default function (pi: ExtensionAPI): void {
631
633
  await publishSnapshot(ctx);
632
634
  });
633
635
 
634
- pi.on("agent_end", async (event, _ctx) => {
636
+ pi.on("agent_end", async (event, ctx) => {
635
637
  lastAgentEvidence = continuationEvidence(event.messages);
638
+ // `escape` is a pi-reserved built-in shortcut (`app.interrupt`), so extensions
639
+ // cannot register it. Observe the interrupt instead: when a running turn is
640
+ // aborted (escape / ctrl+c while streaming), pause the active goal so it does
641
+ // not auto-continue after the user stopped the agent.
642
+ if (wasTurnAborted(event.messages)) {
643
+ const goal = getGoal(ctx);
644
+ if (isPokeable(goal)) {
645
+ setGoal(goalWithStatus(goal, "paused"), ctx, "runtime");
646
+ if (ctx.hasUI) {
647
+ ctx.ui.notify("Goal paused (interrupted).", "info");
648
+ }
649
+ }
650
+ }
636
651
  });
637
652
 
638
653
  pi.on("agent_settled", async (_event, ctx) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-better-harness",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Pi extension bundle for subagents, durable background tasks, and goal tracking.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "pi-better-background-tasks": "0.1.18",
47
- "pi-better-goal": "0.1.19",
47
+ "pi-better-goal": "0.1.20",
48
48
  "pi-better-subagents": "0.1.19"
49
49
  },
50
50
  "bundledDependencies": [