killeros 2.0.2 → 2.0.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/CHANGELOG.md +34 -0
- package/Killeros.ts +17 -10
- package/README.md +21 -13
- package/killeros/commands.ts +2 -8
- package/killeros/concise.ts +12 -8
- package/killeros/footer.ts +46 -1
- package/killeros/goals.ts +118 -57
- package/killeros/hooks.ts +49 -17
- package/killeros/init-evidence.ts +240 -0
- package/killeros/init-target.ts +289 -0
- package/killeros/init.ts +139 -356
- package/killeros/notifications.ts +167 -0
- package/killeros/question.ts +16 -1
- package/killeros/runtime.ts +19 -31
- package/killeros/shell-ui.ts +18 -141
- package/package.json +2 -2
- package/killeros/context-compaction.ts +0 -614
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,40 @@ All notable changes to KillerOS are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.0.4] - 2026-08-10
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Rebuilt `/init` around a packaged four-section guideline-synthesis workflow that preserves compatible root policy without requiring an external skill.
|
|
12
|
+
- Removed live blue slash-command coloring while retaining slash autocomplete, the framed multiline editor, and Shift+Enter.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Prevented `/init` from reading Git-ignored files, known secrets, private keys, linked or non-regular files, other guidance, dependencies, and files outside its frozen evidence map.
|
|
17
|
+
- Protected root `AGENTS.md` from concurrent replacement and reported incompatible policy conflicts without writing.
|
|
18
|
+
- Made `/clear` confirm before aborting active work, wait for settlement, and then start the new session.
|
|
19
|
+
- Preserved explicit Responses API verbosity and reasoning-summary settings while applying concise defaults only to absent fields.
|
|
20
|
+
- Cancelled lifecycle hook process trees with bounded cleanup when Pi aborts the parent request.
|
|
21
|
+
- Kept `/init` middleware from freezing shared tool input and preserved custom editors installed by other extensions.
|
|
22
|
+
- Removed private Pi editor-state access in favor of public rendering contracts.
|
|
23
|
+
|
|
24
|
+
## [2.0.3] - 2026-08-09
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Added an opt-in global completion sound with `/notification` and an enabled-state Nerd Font bell in the terminal tab title.
|
|
29
|
+
- Moved active goal status to the footer's right side in warning yellow, replacing the path with `/goal is active (...)` and exact seconds.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- Returned compaction timing, summary generation, manual instructions, retries, file tracking, and overflow recovery to Pi's public lifecycle.
|
|
34
|
+
- Continued active goals only after Pi reaches its settled boundary and preserved `/goal` as the sole durable objective and status owner.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- Added fail-closed, revision-bound recovery after successful manual compaction, including reload and branch navigation recovery without reviving stale or explicitly paused goals.
|
|
39
|
+
- Rendered question help from the effective selector keybindings across supported Pi versions.
|
|
40
|
+
|
|
7
41
|
## [2.0.2] - 2026-08-08
|
|
8
42
|
|
|
9
43
|
### Changed
|
package/Killeros.ts
CHANGED
|
@@ -1,27 +1,34 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { registerAliases, registerSlashAutocomplete } from "./killeros/commands.ts";
|
|
3
3
|
import { registerConcisePrompt } from "./killeros/concise.ts";
|
|
4
|
-
import { registerContextCompaction } from "./killeros/context-compaction.ts";
|
|
5
4
|
import { registerFooter } from "./killeros/footer.ts";
|
|
6
5
|
import { registerGoal, registerGoalSettlement } from "./killeros/goals.ts";
|
|
7
6
|
import { registerLifecycleHooks } from "./killeros/hooks.ts";
|
|
8
7
|
import { registerInitCommand, registerInitSettlement } from "./killeros/init.ts";
|
|
8
|
+
import {
|
|
9
|
+
registerCompletionNotifications,
|
|
10
|
+
type CompletionNotificationDependencies,
|
|
11
|
+
} from "./killeros/notifications.ts";
|
|
9
12
|
import { registerPersonalInstructions } from "./killeros/personal-instructions.ts";
|
|
10
13
|
import { registerQuestionTool } from "./killeros/question.ts";
|
|
11
|
-
import {
|
|
14
|
+
import { createGoalRuntime, createInitRuntime } from "./killeros/runtime.ts";
|
|
12
15
|
import { registerShellUi } from "./killeros/shell-ui.ts";
|
|
13
16
|
import { registerVariants } from "./killeros/variants.ts";
|
|
14
17
|
|
|
15
|
-
export { CONCISE_SYSTEM_PROMPT, isConcisedEnabled } from "./killeros/concise.ts";
|
|
16
|
-
export { contextPercentRemaining } from "./killeros/
|
|
17
|
-
export { formatCost, formatContextProgress } from "./killeros/footer.ts";
|
|
18
|
+
export { CONCISE_SYSTEM_PROMPT, isConciseEnabled, isConcisedEnabled } from "./killeros/concise.ts";
|
|
19
|
+
export { contextPercentRemaining, formatCost, formatContextProgress } from "./killeros/footer.ts";
|
|
18
20
|
export { executeHook } from "./killeros/hooks.ts";
|
|
19
|
-
export { INIT_WORKFLOW_PROMPT
|
|
21
|
+
export { INIT_WORKFLOW_PROMPT } from "./killeros/init.ts";
|
|
22
|
+
export { buildInitEvidence, listInitEvidence, readInitEvidence } from "./killeros/init-evidence.ts";
|
|
23
|
+
export { captureInitTargetBaseline, installInitAgentsFile, validateGeneratedGuidance, writeInitAgentsFile } from "./killeros/init-target.ts";
|
|
20
24
|
|
|
21
|
-
export
|
|
25
|
+
export interface KillerosOptions {
|
|
26
|
+
completionNotifications?: CompletionNotificationDependencies;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export default function Killeros(pi: ExtensionAPI, options: KillerosOptions = {}): void {
|
|
22
30
|
const initRuntime = createInitRuntime();
|
|
23
31
|
const goalRuntime = createGoalRuntime();
|
|
24
|
-
const compactionRuntime = createCompactionRuntime();
|
|
25
32
|
registerShellUi(pi);
|
|
26
33
|
registerConcisePrompt(pi);
|
|
27
34
|
registerGoal(pi, goalRuntime, initRuntime);
|
|
@@ -33,7 +40,7 @@ export default function Killeros(pi: ExtensionAPI): void {
|
|
|
33
40
|
registerVariants(pi);
|
|
34
41
|
registerInitCommand(pi, initRuntime, goalRuntime);
|
|
35
42
|
registerLifecycleHooks(pi);
|
|
36
|
-
|
|
37
|
-
registerGoalSettlement(pi, goalRuntime, initRuntime, compactionRuntime);
|
|
43
|
+
registerGoalSettlement(pi, goalRuntime, initRuntime);
|
|
38
44
|
registerInitSettlement(pi, initRuntime);
|
|
45
|
+
registerCompletionNotifications(pi, options.completionNotifications);
|
|
39
46
|
}
|
package/README.md
CHANGED
|
@@ -31,7 +31,7 @@ pi install git:github.com/KyrosHendrix/pi-KillerOS
|
|
|
31
31
|
Pin an install to a release:
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
pi install git:github.com/KyrosHendrix/pi-KillerOS@v2.0.
|
|
34
|
+
pi install git:github.com/KyrosHendrix/pi-KillerOS@v2.0.4
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
@@ -41,16 +41,17 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
41
41
|
- 52-column Compact startup card with inline version, polished model/provider identity, adjacent `/model`, directory, conditional Git branch, and a shuffled session-stable tip
|
|
42
42
|
- Cohesive dark theme with coral accents and neutral tool-call containers across pending, success, and error states
|
|
43
43
|
- Animated orange 12-frame activity glyph loop at 120 ms per frame, with orange shuffled Claude-adjacent verbs changing every 2.5 seconds, a gray `(esc to interrupt · thinking)` status with bold `esc`, and a quiet hidden-thinking label
|
|
44
|
-
- Framed multiline editor with Shift+Enter support and
|
|
44
|
+
- Framed multiline editor with Shift+Enter support and slash-command autocomplete; KillerOS preserves an editor factory configured by another extension
|
|
45
45
|
- Responsive footer with polished model/provider identity, plain-language context, and active goal state remaining; reasoning, Git branch, elapsed time, cost, and path cut down by available width
|
|
46
|
-
-
|
|
46
|
+
- Pi-owned context compaction with active goals continuing from Pi's settled boundary after manual, threshold, and overflow compaction
|
|
47
|
+
- Optional completion sounds after successful or failed settled requests, excluding manual aborts
|
|
47
48
|
- `/variants` selector and direct reasoning-level arguments
|
|
48
49
|
- Codex-style `/goal` with an interactive status/action panel, durable objectives, pause, resume, edit, confirmed panel clearing, automatic continuation, and explicit completion
|
|
49
|
-
-
|
|
50
|
+
- Automatic `/init` guideline synthesis with a frozen safe evidence map, protected existing policy, and the four packaged behavioral sections adapted from `writing-great-guidelines`
|
|
50
51
|
- `question` tool with height-bounded option windows, configured Pi keybindings, live option/input progress, proposal previews, custom answers, history, cancellation, and compact expandable transcript rendering
|
|
51
52
|
- Mid-prompt slash completion with current Pi `0.82.1` commands, extensions, prompts, and skills; paths, URLs, and invalid commands remain plain text
|
|
52
|
-
- `/clear` for a
|
|
53
|
-
- Concise system-prompt guidance
|
|
53
|
+
- Goal-aware `/clear` that confirms, aborts active work, waits for settlement, and starts a new session, plus `/exit` for graceful shutdown
|
|
54
|
+
- Concise system-prompt guidance and supported native concise defaults that preserve explicit provider settings
|
|
54
55
|
|
|
55
56
|
## Commands
|
|
56
57
|
|
|
@@ -64,13 +65,16 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
64
65
|
/goal clear Remove the current goal
|
|
65
66
|
/variants Open the reasoning-level selector
|
|
66
67
|
/variants high Set a reasoning level directly
|
|
68
|
+
/notification Configure the completion sound
|
|
67
69
|
/clear Start a new session after confirmation
|
|
68
70
|
/exit Quit Pi gracefully
|
|
69
71
|
```
|
|
70
72
|
|
|
71
73
|
`/goal` requires a saved session in TUI or RPC mode. Goal state is stored in versioned session entries on the active branch and restored after reload, resume, fork, or tree navigation. Active goals inject their unchanged objective every turn and continue one settled turn at a time. The model must use KillerOS’s private goal tool to mark verified completion or a blocker repeated across at least three goal turns; final prose alone does not end the loop. Aborted turns, provider failures, and continuation failures pause safely. Replacing unfinished work requires confirmation, and `/goal edit` requires TUI mode.
|
|
72
74
|
|
|
73
|
-
`/init`
|
|
75
|
+
`/init` freezes a safe project-file map and exposes only dedicated read and list operations while it generates root `AGENTS.md`. Git-ignored files, known secret paths, private-key formats, other guidance, dependencies, links, non-regular files, and files outside that map are unavailable. Existing root `AGENTS.md` is separate protected policy: compatible rules are preserved, a real policy conflict leaves it unchanged with a reason, and any concurrent target change aborts installation without replacing the newer file.
|
|
76
|
+
|
|
77
|
+
The generated file uses the four behavioral sections adapted from `writing-great-guidelines`; no external skill installation is required. `/init` asks no setup questions, starts no second model process, writes no other file, and reloads Pi resources only after a successful write.
|
|
74
78
|
|
|
75
79
|
Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. KillerOS limits choices to levels supported by the current model.
|
|
76
80
|
|
|
@@ -78,21 +82,25 @@ Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh
|
|
|
78
82
|
|
|
79
83
|
KillerOS activates its packaged `killeros` theme when a TUI session starts. Tool-call backgrounds stay neutral across pending, successful, and failed states; restrained text and icons preserve status visibility.
|
|
80
84
|
|
|
81
|
-
|
|
85
|
+
The completion sound is a global user preference stored in Pi's agent directory and is off by default. Run `/notification` in TUI mode to enable or disable it; enabling does not play a preview. Enabled TUI tabs append ``, which requires a Nerd Font in the terminal tab UI. An unsupported font may show a box without affecting sound. KillerOS uses the terminal's audible bell and cannot produce sound when the terminal disables it.
|
|
86
|
+
|
|
87
|
+
KillerOS displays session costs in USD. The footer uses Pi's human-readable model name when available, keeps the provider visually secondary, and renders context as `percent left (tokens)` without a progress bar. An active goal replaces the right-side path with warning-yellow `/goal is active (...)` and keeps exact seconds in minute and hour formats. Paused and blocked goals retain their existing placement; completed goals remain in transcript history and `/goal` status rather than the footer. At narrow widths, context pressure and actionable goal state take priority.
|
|
88
|
+
|
|
89
|
+
Pi decides when compaction runs and Pi writes the summary, applies manual focus instructions, tracks files, retries summarization, and handles overflow recovery. KillerOS does not add a second threshold or replace Pi's summary. Active `/goal` work continues from Pi's settled boundary, after Pi finishes retries, compaction, and queued work.
|
|
82
90
|
|
|
83
|
-
|
|
91
|
+
Manual `/compact` aborts the current goal turn before summarization, so KillerOS records an honest temporary pause for that exact goal revision. After Pi saves the manual summary, KillerOS resumes that revision automatically. A failed or cancelled manual compaction stays paused; run `/goal pause` during the pause to cancel automatic recovery.
|
|
84
92
|
|
|
85
93
|
For trusted projects, KillerOS loads `AGENTS.local.md` after Pi's shared repository context. A one-line `@path` or `@~/path` file imports personal guidance from another location.
|
|
86
94
|
|
|
87
|
-
Lifecycle hooks are loaded from `.pi/killeros-hooks.json` at session start. Supported event keys are `tool_call`, `tool_result`, and `agent_settled`; matchers are JavaScript regular expressions over Pi tool names. Hook commands run from the repository root with `KILLEROS_EVENT`, `KILLEROS_TOOL`, and `KILLEROS_PAYLOAD` environment variables. Failed `tool_call` hooks block the tool, while later-event failures notify the user.
|
|
95
|
+
Lifecycle hooks are loaded from `.pi/killeros-hooks.json` at session start. Supported event keys are `tool_call`, `tool_result`, and `agent_settled`; matchers are JavaScript regular expressions over Pi tool names. Hook commands run from the repository root with `KILLEROS_EVENT`, `KILLEROS_TOOL`, and `KILLEROS_PAYLOAD` environment variables. Failed `tool_call` hooks block the tool, while later-event failures notify the user. Aborting the parent request stops the hook process tree with bounded graceful and forced cleanup without reporting cancellation as a hook failure.
|
|
88
96
|
|
|
89
97
|
## Behavior by mode
|
|
90
98
|
|
|
91
99
|
| Mode | Behavior |
|
|
92
100
|
|---|---|
|
|
93
|
-
| TUI | All features are available |
|
|
94
|
-
| RPC | Goal set/view/pause/resume/clear and concise prompt guidance work; TUI components, `/goal edit`,
|
|
95
|
-
| Print/JSON | Concise prompt guidance works; interactive questions, `/goal`, and `/init` fail explicitly |
|
|
101
|
+
| TUI | All features are available, including the completion sound and tab-title indicator |
|
|
102
|
+
| RPC | Goal set/view/pause/resume/clear and concise prompt guidance work; TUI components, `/goal edit`, `/init`, completion sounds, and the title indicator are disabled |
|
|
103
|
+
| Print/JSON | Concise prompt guidance works; interactive questions, `/goal`, and `/init` fail explicitly; completion sounds and the title indicator are disabled |
|
|
96
104
|
|
|
97
105
|
## Validation
|
|
98
106
|
|
package/killeros/commands.ts
CHANGED
|
@@ -8,8 +8,9 @@ async function confirmNewSession(ctx: ExtensionCommandContext): Promise<boolean>
|
|
|
8
8
|
|
|
9
9
|
export function registerAliases(pi: ExtensionAPI): void {
|
|
10
10
|
const startNewSession = async (_args: string, ctx: ExtensionCommandContext): Promise<void> => {
|
|
11
|
-
await ctx.waitForIdle();
|
|
12
11
|
if (!await confirmNewSession(ctx)) return;
|
|
12
|
+
if (!ctx.isIdle()) ctx.abort();
|
|
13
|
+
await ctx.waitForIdle();
|
|
13
14
|
await ctx.newSession();
|
|
14
15
|
};
|
|
15
16
|
pi.registerCommand("clear", { description: "Start a new session after confirmation", handler: startNewSession });
|
|
@@ -54,13 +55,6 @@ const BUILTIN_COMMANDS: ReadonlyArray<{ name: string; description: string }> = [
|
|
|
54
55
|
{ name: "quit", description: "Quit Pi" },
|
|
55
56
|
];
|
|
56
57
|
|
|
57
|
-
export function availableCommandNames(pi: ExtensionAPI): ReadonlySet<string> {
|
|
58
|
-
return new Set([
|
|
59
|
-
...BUILTIN_COMMANDS.map((command) => command.name),
|
|
60
|
-
...pi.getCommands().map((command) => command.name),
|
|
61
|
-
]);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
58
|
const COMMAND_SYNTAX_HINTS: Readonly<Record<string, string>> = {
|
|
65
59
|
goal: "/goal [objective|clear|edit|pause|resume]",
|
|
66
60
|
variants: "/variants [level]",
|
package/killeros/concise.ts
CHANGED
|
@@ -41,22 +41,26 @@ function applyConciseModelSettings(payload: unknown, api: unknown, modelId: unkn
|
|
|
41
41
|
const supportsVerbosity = api === "openai-codex-responses"
|
|
42
42
|
|| api === "openai-responses" && typeof modelId === "string" && /^gpt-5(?:[.-]|$)/u.test(modelId);
|
|
43
43
|
let updated = payload;
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
text: { ...(isRecord(payload.text) ? payload.text : {}), verbosity: "low" },
|
|
48
|
-
};
|
|
44
|
+
const text = isRecord(payload.text) ? payload.text : undefined;
|
|
45
|
+
if (supportsVerbosity && !Object.hasOwn(text ?? {}, "verbosity")) {
|
|
46
|
+
updated = { ...updated, text: { ...(text ?? {}), verbosity: "low" } };
|
|
49
47
|
}
|
|
50
|
-
|
|
51
|
-
|
|
48
|
+
const reasoning = isRecord(payload.reasoning) ? payload.reasoning : undefined;
|
|
49
|
+
if (supportsSummary && reasoning && !Object.hasOwn(reasoning, "summary")) {
|
|
50
|
+
updated = { ...updated, reasoning: { ...reasoning, summary: "concise" } };
|
|
52
51
|
}
|
|
53
52
|
return updated;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
export function
|
|
55
|
+
export function isConciseEnabled(): boolean {
|
|
57
56
|
return true;
|
|
58
57
|
}
|
|
59
58
|
|
|
59
|
+
/** @deprecated Use isConciseEnabled instead. */
|
|
60
|
+
export function isConcisedEnabled(): boolean {
|
|
61
|
+
return isConciseEnabled();
|
|
62
|
+
}
|
|
63
|
+
|
|
60
64
|
export function registerConcisePrompt(pi: ExtensionAPI): void {
|
|
61
65
|
pi.on("before_agent_start", (event) => ({
|
|
62
66
|
systemPrompt: `${event.systemPrompt}\n\n${CONCISE_SYSTEM_PROMPT}`,
|
package/killeros/footer.ts
CHANGED
|
@@ -12,6 +12,20 @@ export function formatCost(usd: number): string {
|
|
|
12
12
|
return `$${usd.toFixed(2)}`;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
export function contextPercentRemaining(ctx: ExtensionContext): number | null {
|
|
16
|
+
let usage: ReturnType<ExtensionContext["getContextUsage"]>;
|
|
17
|
+
try {
|
|
18
|
+
usage = ctx.getContextUsage();
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
if (!usage || !Number.isFinite(usage.contextWindow) || usage.contextWindow <= 0) return null;
|
|
23
|
+
if (usage.tokens === null || !Number.isFinite(usage.tokens)) return null;
|
|
24
|
+
|
|
25
|
+
const percentRemaining = ((usage.contextWindow - Math.max(0, usage.tokens)) / usage.contextWindow) * 100;
|
|
26
|
+
return Math.round(Math.max(0, Math.min(100, percentRemaining)));
|
|
27
|
+
}
|
|
28
|
+
|
|
15
29
|
export function formatContextProgress(tokensUsed: number | null, contextWindow: number, theme: Theme): string {
|
|
16
30
|
if (tokensUsed === null || !Number.isFinite(tokensUsed)) return theme.fg("dim", "—% left (—)");
|
|
17
31
|
const windowSize = Number.isFinite(contextWindow) && contextWindow > 0 ? contextWindow : 128_000;
|
|
@@ -111,9 +125,26 @@ function renderFooterRow(left: string, right: string, width: number): string {
|
|
|
111
125
|
return ` ${clippedLeft}${gap}${clippedRight} `;
|
|
112
126
|
}
|
|
113
127
|
|
|
128
|
+
function formatGoalElapsed(milliseconds: number): string {
|
|
129
|
+
const totalSeconds = Number.isFinite(milliseconds) ? Math.max(0, Math.floor(milliseconds / 1_000)) : 0;
|
|
130
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
131
|
+
|
|
132
|
+
const seconds = totalSeconds % 60;
|
|
133
|
+
const totalMinutes = Math.floor(totalSeconds / 60);
|
|
134
|
+
if (totalMinutes < 60) return `${totalMinutes}m ${seconds.toString().padStart(2, "0")}s`;
|
|
135
|
+
|
|
136
|
+
const hours = Math.floor(totalMinutes / 60);
|
|
137
|
+
const minutes = totalMinutes % 60;
|
|
138
|
+
return `${hours}h ${minutes.toString().padStart(2, "0")}m ${seconds.toString().padStart(2, "0")}s`;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function formatActiveGoalFooter(state: GoalState | undefined, theme: Theme): string {
|
|
142
|
+
if (state?.status !== "active") return "";
|
|
143
|
+
return theme.fg("warning", `/goal is active (${formatGoalElapsed(goalElapsedMilliseconds(state))})`);
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
function formatGoalFooter(state: GoalState | undefined, theme: Theme): string {
|
|
115
147
|
if (!state) return "";
|
|
116
|
-
if (state.status === "active") return theme.fg("accent", `✻ goal · ${formatTime(goalElapsedMilliseconds(state))}`);
|
|
117
148
|
if (state.status === "paused") return theme.fg("warning", "Ⅱ goal paused");
|
|
118
149
|
if (state.status === "blocked") return theme.fg("error", "! goal blocked");
|
|
119
150
|
return "";
|
|
@@ -180,6 +211,7 @@ export function registerFooter(pi: ExtensionAPI, goalRuntime: GoalRuntime): void
|
|
|
180
211
|
const signature = formatModel(model, theme);
|
|
181
212
|
const fullDirectory = theme.fg("dim", cwd);
|
|
182
213
|
const focusedDirectory = theme.fg("dim", compactDirectory(cwd));
|
|
214
|
+
const activeGoal = formatActiveGoalFooter(goalRuntime.state, theme);
|
|
183
215
|
const goal = formatGoalFooter(goalRuntime.state, theme);
|
|
184
216
|
const rich = joinFooterParts([
|
|
185
217
|
signature,
|
|
@@ -192,6 +224,19 @@ export function registerFooter(pi: ExtensionAPI, goalRuntime: GoalRuntime): void
|
|
|
192
224
|
], theme);
|
|
193
225
|
const focused = joinFooterParts([signature, context, goal], theme);
|
|
194
226
|
|
|
227
|
+
if (activeGoal) {
|
|
228
|
+
if (footerRowFits(rich, activeGoal, width)) {
|
|
229
|
+
return [renderFooterRow(rich, activeGoal, width)];
|
|
230
|
+
}
|
|
231
|
+
if (footerRowFits(focused, activeGoal, width)) {
|
|
232
|
+
return [renderFooterRow(focused, activeGoal, width)];
|
|
233
|
+
}
|
|
234
|
+
if (footerRowFits(context, activeGoal, width)) {
|
|
235
|
+
return [renderFooterRow(context, activeGoal, width)];
|
|
236
|
+
}
|
|
237
|
+
return [renderFooterRow("", activeGoal, width)];
|
|
238
|
+
}
|
|
239
|
+
|
|
195
240
|
if (footerRowFits(rich, fullDirectory, width)) {
|
|
196
241
|
return [renderFooterRow(rich, fullDirectory, width)];
|
|
197
242
|
}
|