pi-better-goal 0.1.21 → 0.2.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/package.json +1 -1
- package/src/goal-clock.ts +18 -2
- package/src/index.ts +18 -2
package/package.json
CHANGED
package/src/goal-clock.ts
CHANGED
|
@@ -62,7 +62,7 @@ export function formatGoalClock(
|
|
|
62
62
|
): string {
|
|
63
63
|
const timing = goalTiming(goal, now);
|
|
64
64
|
return (
|
|
65
|
-
`Goal [${goal.status}]: ${goal.objective}` +
|
|
65
|
+
`Goal [${goal.status}]: ${flattenObjectiveForRail(goal.objective)}` +
|
|
66
66
|
` | active ${formatClockDuration(timing.activeSeconds)}` +
|
|
67
67
|
` | elapsed ${formatClockDuration(timing.elapsedSeconds)}`
|
|
68
68
|
);
|
|
@@ -85,10 +85,26 @@ export function renderGoalClockLine(
|
|
|
85
85
|
if (fixedWidth >= width) {
|
|
86
86
|
return truncateToWidth(`${heading} ${active}`, width);
|
|
87
87
|
}
|
|
88
|
-
const objective = truncateToWidth(
|
|
88
|
+
const objective = truncateToWidth(
|
|
89
|
+
flattenObjectiveForRail(goal.objective),
|
|
90
|
+
width - fixedWidth,
|
|
91
|
+
);
|
|
89
92
|
return styleGoalRailLine(heading, `${active} ${objective}`, fg);
|
|
90
93
|
}
|
|
91
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Goal rail / clock lines must stay one terminal row. Raw objectives can keep
|
|
97
|
+
* newlines for prompts and `/goal` inspection, but embedding them here makes
|
|
98
|
+
* the widget taller than the dock budget and desyncs main-screen differential
|
|
99
|
+
* paints (Working... / Elapsed stacking into scrollback).
|
|
100
|
+
*/
|
|
101
|
+
export function flattenObjectiveForRail(objective: string): string {
|
|
102
|
+
return objective
|
|
103
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
104
|
+
.replace(/ {2,}/g, " ")
|
|
105
|
+
.trim();
|
|
106
|
+
}
|
|
107
|
+
|
|
92
108
|
function styleGoalRailLine(
|
|
93
109
|
heading: string,
|
|
94
110
|
tail: string,
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { AutocompleteItem } from "@earendil-works/pi-tui";
|
|
2
3
|
import { Type } from "typebox";
|
|
3
4
|
|
|
4
5
|
import {
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
import { continuationEvidence, type ContinuationEvidence } from "./continuation.js";
|
|
25
26
|
import { observeGoalStall } from "./stall.js";
|
|
26
27
|
import {
|
|
28
|
+
flattenObjectiveForRail,
|
|
27
29
|
goalClockRefreshDelayMs,
|
|
28
30
|
goalTiming,
|
|
29
31
|
isGoalClockVisible,
|
|
@@ -58,6 +60,19 @@ const MAX_NO_PROGRESS_RETRIES = parseRetryLimit(
|
|
|
58
60
|
DEFAULT_MAX_NO_PROGRESS_RETRIES,
|
|
59
61
|
);
|
|
60
62
|
|
|
63
|
+
const GOAL_ACTIONS: readonly AutocompleteItem[] = [
|
|
64
|
+
{ value: "pause", label: "pause", description: "Pause the active goal" },
|
|
65
|
+
{ value: "resume", label: "resume", description: "Resume the paused goal" },
|
|
66
|
+
{ value: "clear", label: "clear", description: "Remove the current goal" },
|
|
67
|
+
{ value: "complete", label: "complete", description: "Mark the current goal complete" },
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
export function goalArgumentCompletions(argumentPrefix: string): AutocompleteItem[] | null {
|
|
71
|
+
const prefix = argumentPrefix.trimStart().toLowerCase();
|
|
72
|
+
const matches = GOAL_ACTIONS.filter((action) => action.value.startsWith(prefix));
|
|
73
|
+
return matches.length > 0 ? [...matches] : null;
|
|
74
|
+
}
|
|
75
|
+
|
|
61
76
|
function parseDurationEnv(raw: string | undefined, fallback: number): number {
|
|
62
77
|
if (raw === undefined || raw.trim() === "") {
|
|
63
78
|
return fallback;
|
|
@@ -485,6 +500,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
485
500
|
|
|
486
501
|
pi.registerCommand("goal", {
|
|
487
502
|
description: "Create, inspect, pause, resume, clear, or complete the active goal",
|
|
503
|
+
getArgumentCompletions: goalArgumentCompletions,
|
|
488
504
|
handler: async (args, ctx) => {
|
|
489
505
|
currentCtx = ctx;
|
|
490
506
|
const trimmed = args.trim();
|
|
@@ -541,7 +557,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
541
557
|
if (current && current.status !== "complete" && ctx.hasUI && !isForegroundBusy(ctx)) {
|
|
542
558
|
const replace = await ctx.ui.confirm(
|
|
543
559
|
"Replace active goal?",
|
|
544
|
-
`Current goal: ${current.objective}`,
|
|
560
|
+
`Current goal: ${flattenObjectiveForRail(current.objective)}`,
|
|
545
561
|
);
|
|
546
562
|
if (!replace) {
|
|
547
563
|
return;
|
|
@@ -550,7 +566,7 @@ export default function (pi: ExtensionAPI): void {
|
|
|
550
566
|
|
|
551
567
|
try {
|
|
552
568
|
const goal = startOrReplaceGoal(trimmed, null, ctx, "command");
|
|
553
|
-
notifyGoal(ctx, `Goal set: ${goal.objective}`);
|
|
569
|
+
notifyGoal(ctx, `Goal set: ${flattenObjectiveForRail(goal.objective)}`);
|
|
554
570
|
} catch (error) {
|
|
555
571
|
notifyGoal(ctx, error instanceof Error ? error.message : String(error), "error");
|
|
556
572
|
}
|