killeros 2.0.5 → 2.0.7
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 +38 -0
- package/Killeros.ts +4 -0
- package/README.md +19 -12
- package/killeros/activity.ts +97 -0
- package/killeros/footer.ts +31 -45
- package/killeros/goals.ts +118 -42
- package/killeros/init.ts +23 -2
- package/killeros/question.ts +382 -186
- package/killeros/runtime.ts +9 -0
- package/killeros/shell-ui.ts +14 -68
- package/killeros/variants.ts +74 -32
- package/killeros/worked-for.ts +135 -0
- package/package.json +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,44 @@ All notable changes to KillerOS are documented here.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [2.0.7] - 2026-08-13
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Raised the supported and locked Pi baseline from 0.82.1 to the current matched 0.84.1 AI, coding-agent, and TUI packages.
|
|
12
|
+
- Added a compact two-deck footer beneath the prompt and removed the work-trail widget.
|
|
13
|
+
- Replaced the framed prompt and shuffled activity verbs with a focus-aware single-arrow editor and event-derived working copy.
|
|
14
|
+
- Made settled timing entries report `Done`, `Stopped`, or `Failed` while keeping existing `Worked for` history readable.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
|
|
18
|
+
- Separated response output from the prompt editor while keeping footer telemetry close beneath a quiet muted divider.
|
|
19
|
+
- Kept `/variants` within the active terminal height, preserved the focused reasoning level across resizes, and initially focused the current level.
|
|
20
|
+
- Rendered `/variants` controls from the same Pi keybinding manager that handles input, including installations with separate package module instances.
|
|
21
|
+
- Rendered active, paused, and blocked `/goal` status text consistently in the footer's far-right slot.
|
|
22
|
+
- Kept the private goal-update tool inactive outside active `/goal` runs and rendered its real execution errors instead of malformed blocker-audit fields.
|
|
23
|
+
- Verified exact persisted paths for clearly declared file-deliverable goals before completion, while preserving model-reported completion for general objectives.
|
|
24
|
+
- Accepted explicit `1`/`1` bounds for single-select questions and applied the same bounds validation before rendering and execution.
|
|
25
|
+
- Prevented reload and branch navigation from preserving or reconstructing stale manual-compaction recovery eligibility; only Pi's live event in the current session can resume the interrupted goal safely.
|
|
26
|
+
- Restricted goal deliverable verification to explicit destination phrases so source and reference paths cannot be reported as completed output.
|
|
27
|
+
- Kept saved goals fully inactive in print and JSON modes, including the private update tool and shutdown checkpoints.
|
|
28
|
+
- Rejected concurrent `/init` starts during preflight, cancelled pending preflight work on shutdown, and settled active `/init` command handlers when their session closes.
|
|
29
|
+
|
|
30
|
+
## [2.0.6] - 2026-08-11
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Added a durable `✻ Worked for …` transcript line below each settled TUI response, including stopped and failed runs.
|
|
35
|
+
- Added optional multi-select to the `question` tool with bounded checked options, one additive custom answer, a dedicated multi-word filter editor, and compact expandable results while preserving single-select defaults.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Automated GitHub releases after successful `main` CI version bumps, with package, lockfile, changelog, tag, and verified-commit checks plus a manual tag recovery path.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
|
|
43
|
+
- Entered automatic `/goal` continuations into durable goal-turn state before dispatch so turn numbers advance and blocker audits work on Pi custom-message turns.
|
|
44
|
+
|
|
7
45
|
## [2.0.5] - 2026-08-11
|
|
8
46
|
|
|
9
47
|
### Added
|
package/Killeros.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { registerRequestActivity } from "./killeros/activity.ts";
|
|
2
3
|
import { registerAliases, registerSlashAutocomplete } from "./killeros/commands.ts";
|
|
3
4
|
import { registerConcisePrompt } from "./killeros/concise.ts";
|
|
4
5
|
import { registerFooter } from "./killeros/footer.ts";
|
|
@@ -14,6 +15,7 @@ import { registerQuestionTool } from "./killeros/question.ts";
|
|
|
14
15
|
import { createGoalRuntime, createInitRuntime } from "./killeros/runtime.ts";
|
|
15
16
|
import { registerShellUi } from "./killeros/shell-ui.ts";
|
|
16
17
|
import { registerVariants } from "./killeros/variants.ts";
|
|
18
|
+
import { registerWorkedFor } from "./killeros/worked-for.ts";
|
|
17
19
|
|
|
18
20
|
export { CONCISE_SYSTEM_PROMPT, isConciseEnabled, isConcisedEnabled } from "./killeros/concise.ts";
|
|
19
21
|
export { contextPercentRemaining, formatCost, formatContextProgress } from "./killeros/footer.ts";
|
|
@@ -42,5 +44,7 @@ export default function Killeros(pi: ExtensionAPI, options: KillerosOptions = {}
|
|
|
42
44
|
registerLifecycleHooks(pi);
|
|
43
45
|
registerGoalSettlement(pi, goalRuntime, initRuntime);
|
|
44
46
|
registerInitSettlement(pi, initRuntime);
|
|
47
|
+
registerRequestActivity(pi);
|
|
45
48
|
registerCompletionNotifications(pi, options.completionNotifications);
|
|
49
|
+
registerWorkedFor(pi);
|
|
46
50
|
}
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ A production-hardened Pi extension that combines a custom TUI, repository initia
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- Node.js `22.19.0` or later
|
|
8
|
-
- Pi `0.
|
|
8
|
+
- Pi `0.84.1` or later
|
|
9
9
|
- Interactive TUI mode for the custom header, editor, footer, `question` tool, and `/init`
|
|
10
10
|
|
|
11
11
|
The extension is strict TypeScript. Pi provides the runtime modules.
|
|
@@ -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.7
|
|
35
35
|
```
|
|
36
36
|
|
|
37
37
|
Add `-l` to either command for a project-only install. Restart Pi after installing.
|
|
@@ -40,16 +40,17 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
40
40
|
|
|
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
|
-
- Animated orange 12-frame activity glyph loop at 120 ms per frame
|
|
44
|
-
-
|
|
45
|
-
-
|
|
43
|
+
- Animated orange 12-frame activity glyph loop at 120 ms per frame with contextual copy derived from request, tool, result, and response events, plus a quiet hidden-thinking label
|
|
44
|
+
- Frameless multiline editor with one focus-aware `❯`, a shuffled session-stable empty-state suggestion, overflow-only scroll indicators, Shift+Enter support, and slash-command autocomplete; KillerOS preserves an editor factory configured by another extension
|
|
45
|
+
- One compact TUI transcript line reporting truthful `Done`, `Stopped`, or `Failed` settlement with elapsed time while preserving older `✻ Worked for …` entries
|
|
46
|
+
- Compact two-deck footer with session state above workspace state; model, context, and active goals stay prioritized as reasoning, time, cost, branch, and path reduce by available width
|
|
46
47
|
- Pi-owned context compaction with active goals continuing from Pi's settled boundary after manual, threshold, and overflow compaction
|
|
47
48
|
- Optional completion sounds after successful or failed settled requests, excluding manual aborts
|
|
48
49
|
- `/variants` selector and direct reasoning-level arguments
|
|
49
50
|
- Codex-style `/goal` with an interactive status/action panel, durable objectives, immediate pause and clear cancellation, automatic continuation, explicit completion, and durable blocker audits
|
|
50
51
|
- Automatic `/init` guideline synthesis with a frozen safe evidence map, protected existing policy, and the four packaged behavioral sections adapted from `writing-great-guidelines`
|
|
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
|
|
52
|
-
- Mid-prompt slash completion with current Pi `0.
|
|
52
|
+
- `question` tool with single-select and opt-in bounded multi-select, height-bounded option windows, configured Pi keybindings, live option/input progress, proposal previews, custom answers, history, cancellation, and compact expandable transcript rendering
|
|
53
|
+
- Mid-prompt slash completion with current Pi `0.84.1` commands, extensions, prompts, and skills; paths, URLs, and invalid commands remain plain text
|
|
53
54
|
- Goal-aware `/clear` that confirms, aborts active work, waits for settlement, and starts a new session, plus `/exit` for graceful shutdown
|
|
54
55
|
- Concise system-prompt guidance and supported native concise defaults that preserve explicit provider settings
|
|
55
56
|
|
|
@@ -70,7 +71,7 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
70
71
|
/exit Quit Pi gracefully
|
|
71
72
|
```
|
|
72
73
|
|
|
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
|
|
74
|
+
`/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 report completion. For an objective that clearly asks to create, write, save, or generate a named file-like deliverable at one quoted absolute path, KillerOS saves that exact path with the goal and verifies that a regular file exists there before accepting completion. Other objectives retain model-reported completion. Blocking requires one stable lowercase blocker key recorded on three consecutive goal turns; a changed key, skipped turn, resume, or edit resets the streak. Final prose alone does not end the loop.
|
|
74
75
|
|
|
75
76
|
`/goal pause` and `/goal clear` save paused or cleared state before aborting current goal work, so settlement cannot restart it. Aborted turns, provider failures, and continuation failures otherwise pause safely. Failed edit and replacement writes dispatch no edited objective; an active prior objective pauses fail-closed, while inactive durable state remains unchanged. Replacing unfinished work requires confirmation, and `/goal edit` requires TUI mode.
|
|
76
77
|
|
|
@@ -78,6 +79,12 @@ Add `-l` to either command for a project-only install. Restart Pi after installi
|
|
|
78
79
|
|
|
79
80
|
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.
|
|
80
81
|
|
|
82
|
+
### Interactive questions
|
|
83
|
+
|
|
84
|
+
Single-select remains the default. Explicit `minSelections: 1` and `maxSelections: 1` are equivalent to omitting both bounds; other single-select bounds are rejected. An agent opts into multi-select with `mode: "multiple"` and may set `minSelections` and `maxSelections`; the custom answer counts as one selection.
|
|
85
|
+
|
|
86
|
+
In multi-select, use Space or a visible number to toggle an option, `/` to filter, and Enter to submit. The filter accepts spaces; Enter applies it and Escape returns to the choices. Checked options remain selected when the filter changes. Select **Type a custom answer** with Enter to add or edit one custom item alongside checked options.
|
|
87
|
+
|
|
81
88
|
Supported reasoning levels are `off`, `minimal`, `low`, `medium`, `high`, `xhigh`, and `max`. KillerOS limits choices to levels supported by the current model.
|
|
82
89
|
|
|
83
90
|
## Configuration
|
|
@@ -120,17 +127,17 @@ The package manifest lists Pi’s built-in modules as peer dependencies, so npm
|
|
|
120
127
|
|
|
121
128
|
## Publish
|
|
122
129
|
|
|
123
|
-
|
|
130
|
+
To create a GitHub release, update the version in `package.json` and `package-lock.json`, add the matching `CHANGELOG.md` section, and push the release commit to `main`. After the full CI workflow passes, the release workflow creates the matching tag and GitHub release from that verified commit.
|
|
124
131
|
|
|
125
|
-
|
|
132
|
+
Do not manually tag a normal release. If automation must recover a missing GitHub release, push the matching version tag; the same workflow validates the tag against the package and changelog before creating the release.
|
|
133
|
+
|
|
134
|
+
The [`pi-package`](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md) keyword makes a published npm release visible in Pi’s package catalog. GitHub release automation does not publish to npm. Publish there separately after validation:
|
|
126
135
|
|
|
127
136
|
```bash
|
|
128
137
|
npm login
|
|
129
138
|
npm publish
|
|
130
139
|
```
|
|
131
140
|
|
|
132
|
-
For later releases, choose `patch`, `minor`, or `major` with `npm version`, then publish and push the version commit and tag.
|
|
133
|
-
|
|
134
141
|
## Security
|
|
135
142
|
|
|
136
143
|
Pi extensions run with your user permissions. Review the source before installing KillerOS globally. KillerOS executes lifecycle hook commands only for projects Pi marks as trusted; review `.pi/killeros-hooks.json` before enabling project trust.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { truncateToWidth } from "@earendil-works/pi-tui";
|
|
3
|
+
|
|
4
|
+
export type ActivityMessage =
|
|
5
|
+
| { kind: "prompt" }
|
|
6
|
+
| { kind: "tool"; toolName: string }
|
|
7
|
+
| { kind: "tool-result"; failed: boolean }
|
|
8
|
+
| { kind: "responding" };
|
|
9
|
+
|
|
10
|
+
function safeToolName(toolName: string): string {
|
|
11
|
+
const normalized = toolName.replace(/[\u0000-\u001F\u007F]+/gu, " ").replace(/\s+/gu, " ").trim();
|
|
12
|
+
return truncateToWidth(normalized || "tool", 32, "…");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function formatActivityMessage(message: ActivityMessage, theme: Theme): string {
|
|
16
|
+
let verb: string;
|
|
17
|
+
let detail: string;
|
|
18
|
+
|
|
19
|
+
switch (message.kind) {
|
|
20
|
+
case "prompt":
|
|
21
|
+
verb = "Mapping…";
|
|
22
|
+
detail = "understanding request";
|
|
23
|
+
break;
|
|
24
|
+
case "tool-result":
|
|
25
|
+
verb = message.failed ? "Recovering…" : "Reviewing…";
|
|
26
|
+
detail = message.failed ? "tool failed" : "reading the result";
|
|
27
|
+
break;
|
|
28
|
+
case "responding":
|
|
29
|
+
verb = "Responding…";
|
|
30
|
+
detail = "assembling the answer";
|
|
31
|
+
break;
|
|
32
|
+
case "tool":
|
|
33
|
+
switch (message.toolName.trim().toLocaleLowerCase()) {
|
|
34
|
+
case "read":
|
|
35
|
+
case "grep":
|
|
36
|
+
case "find":
|
|
37
|
+
case "ls":
|
|
38
|
+
verb = "Inspecting…";
|
|
39
|
+
detail = "reading relevant code";
|
|
40
|
+
break;
|
|
41
|
+
case "edit":
|
|
42
|
+
case "write":
|
|
43
|
+
verb = "Changing…";
|
|
44
|
+
detail = "editing";
|
|
45
|
+
break;
|
|
46
|
+
case "bash":
|
|
47
|
+
verb = "Running…";
|
|
48
|
+
detail = "command";
|
|
49
|
+
break;
|
|
50
|
+
default:
|
|
51
|
+
verb = "Working…";
|
|
52
|
+
detail = `using ${safeToolName(message.toolName)}`;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return `${theme.fg("accent", verb)} ${theme.fg("dim", `(${theme.bold("esc")} to interrupt · ${detail})`)}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function registerRequestActivity(pi: ExtensionAPI): void {
|
|
61
|
+
let active = false;
|
|
62
|
+
|
|
63
|
+
const clear = (ctx?: ExtensionContext): void => {
|
|
64
|
+
if (ctx?.mode === "tui") {
|
|
65
|
+
ctx.ui.setWorkingMessage();
|
|
66
|
+
}
|
|
67
|
+
active = false;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
pi.on("agent_start", (_event, ctx) => {
|
|
71
|
+
if (ctx.mode !== "tui") return;
|
|
72
|
+
active = true;
|
|
73
|
+
ctx.ui.setWorkingMessage(formatActivityMessage({ kind: "prompt" }, ctx.ui.theme));
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
pi.on("tool_execution_start", (event, ctx) => {
|
|
77
|
+
if (ctx.mode !== "tui" || !active) return;
|
|
78
|
+
ctx.ui.setWorkingMessage(formatActivityMessage({ kind: "tool", toolName: event.toolName }, ctx.ui.theme));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
pi.on("tool_execution_end", (event, ctx) => {
|
|
82
|
+
if (ctx.mode !== "tui" || !active) return;
|
|
83
|
+
ctx.ui.setWorkingMessage(formatActivityMessage({ kind: "tool-result", failed: event.isError }, ctx.ui.theme));
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
pi.on("message_update", (event, ctx) => {
|
|
87
|
+
if (ctx.mode !== "tui" || !active || event.assistantMessageEvent.type !== "text_start") return;
|
|
88
|
+
ctx.ui.setWorkingMessage(formatActivityMessage({ kind: "responding" }, ctx.ui.theme));
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
pi.on("agent_settled", (_event, ctx) => {
|
|
92
|
+
if (ctx.mode !== "tui" || !active || !ctx.isIdle?.() || ctx.hasPendingMessages?.()) return;
|
|
93
|
+
clear(ctx);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
pi.on("session_shutdown", (_event, ctx) => clear(ctx));
|
|
97
|
+
}
|
package/killeros/footer.ts
CHANGED
|
@@ -125,6 +125,10 @@ function renderFooterRow(left: string, right: string, width: number): string {
|
|
|
125
125
|
return ` ${clippedLeft}${gap}${clippedRight} `;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
+
function renderFooter(rows: string[], width: number, theme: Theme): string[] {
|
|
129
|
+
return [theme.fg("borderMuted", "─".repeat(width)), ...rows];
|
|
130
|
+
}
|
|
131
|
+
|
|
128
132
|
function formatGoalElapsed(milliseconds: number): string {
|
|
129
133
|
const totalSeconds = Number.isFinite(milliseconds) ? Math.max(0, Math.floor(milliseconds / 1_000)) : 0;
|
|
130
134
|
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
@@ -138,15 +142,13 @@ function formatGoalElapsed(milliseconds: number): string {
|
|
|
138
142
|
return `${hours}h ${minutes.toString().padStart(2, "0")}m ${seconds.toString().padStart(2, "0")}s`;
|
|
139
143
|
}
|
|
140
144
|
|
|
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
|
-
|
|
146
145
|
function formatGoalFooter(state: GoalState | undefined, theme: Theme): string {
|
|
147
146
|
if (!state) return "";
|
|
148
|
-
if (state.status === "
|
|
149
|
-
|
|
147
|
+
if (state.status === "active") {
|
|
148
|
+
return theme.fg("warning", `/goal is active (${formatGoalElapsed(goalElapsedMilliseconds(state))})`);
|
|
149
|
+
}
|
|
150
|
+
if (state.status === "paused") return theme.fg("warning", "/goal is paused");
|
|
151
|
+
if (state.status === "blocked") return theme.fg("error", "/goal is blocked");
|
|
150
152
|
return "";
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -211,52 +213,36 @@ export function registerFooter(pi: ExtensionAPI, goalRuntime: GoalRuntime): void
|
|
|
211
213
|
const signature = formatModel(model, theme);
|
|
212
214
|
const fullDirectory = theme.fg("dim", cwd);
|
|
213
215
|
const focusedDirectory = theme.fg("dim", compactDirectory(cwd));
|
|
214
|
-
const activeGoal = formatActiveGoalFooter(goalRuntime.state, theme);
|
|
215
216
|
const goal = formatGoalFooter(goalRuntime.state, theme);
|
|
216
|
-
const
|
|
217
|
+
const primary = joinFooterParts([
|
|
217
218
|
signature,
|
|
218
219
|
level,
|
|
219
220
|
context,
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
], theme);
|
|
222
|
+
const primaryFocused = joinFooterParts([signature, context], theme);
|
|
223
|
+
const session = joinFooterParts([
|
|
222
224
|
theme.fg("dim", formatTime(Date.now() - sessionStart)),
|
|
223
225
|
theme.fg("dim", formatCost(getSessionCost(ctx))),
|
|
224
226
|
], theme);
|
|
225
|
-
const focused = joinFooterParts([signature, context, goal], theme);
|
|
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
|
-
|
|
240
|
-
if (footerRowFits(rich, fullDirectory, width)) {
|
|
241
|
-
return [renderFooterRow(rich, fullDirectory, width)];
|
|
242
|
-
}
|
|
243
|
-
if (footerRowFits(rich, focusedDirectory, width)) {
|
|
244
|
-
return [renderFooterRow(rich, focusedDirectory, width)];
|
|
245
|
-
}
|
|
246
|
-
if (footerRowFits(focused, focusedDirectory, width)) {
|
|
247
|
-
return [renderFooterRow(focused, focusedDirectory, width)];
|
|
248
|
-
}
|
|
249
|
-
if (footerRowFits(focused, "", width)) {
|
|
250
|
-
return [renderFooterRow(focused, "", width)];
|
|
251
|
-
}
|
|
252
|
-
if (goal) {
|
|
253
|
-
const essentialGoal = joinFooterParts([context, goal], theme);
|
|
254
|
-
if (footerRowFits(essentialGoal, "", width)) return [renderFooterRow(essentialGoal, "", width)];
|
|
255
|
-
return [renderFooterRow(goal, context, width)];
|
|
256
|
-
}
|
|
257
|
-
|
|
258
227
|
const essentialModel = formatModel(model, theme, false);
|
|
259
|
-
|
|
228
|
+
const primaryRow = footerRowFits(primary, session, width)
|
|
229
|
+
? renderFooterRow(primary, session, width)
|
|
230
|
+
: footerRowFits(primary, "", width)
|
|
231
|
+
? renderFooterRow(primary, "", width)
|
|
232
|
+
: footerRowFits(primaryFocused, "", width)
|
|
233
|
+
? renderFooterRow(primaryFocused, "", width)
|
|
234
|
+
: renderFooterRow(essentialModel, context, width);
|
|
235
|
+
const branchLabel = branch ? theme.fg("dim", branch) : "";
|
|
236
|
+
const workspaceRight = goal || fullDirectory;
|
|
237
|
+
const secondaryRow = footerRowFits(branchLabel, workspaceRight, width)
|
|
238
|
+
? renderFooterRow(branchLabel, workspaceRight, width)
|
|
239
|
+
: goal
|
|
240
|
+
? renderFooterRow("", goal, width)
|
|
241
|
+
: footerRowFits(branchLabel, focusedDirectory, width)
|
|
242
|
+
? renderFooterRow(branchLabel, focusedDirectory, width)
|
|
243
|
+
: renderFooterRow(branchLabel, "", width);
|
|
244
|
+
|
|
245
|
+
return renderFooter([primaryRow, secondaryRow], width, theme);
|
|
260
246
|
},
|
|
261
247
|
};
|
|
262
248
|
});
|