@nanhara/hara 0.98.2 → 0.98.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/dist/index.js +6 -1
- package/dist/tui/App.js +10 -2
- package/dist/tui/InputBox.js +3 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2743,6 +2743,7 @@ program.action(async (opts) => {
|
|
|
2743
2743
|
orgId: __activeP.kind === "gateway" ? __activeP.deviceId || __activeP.id : undefined,
|
|
2744
2744
|
routeHost: __routeForHeader?.host,
|
|
2745
2745
|
modelSource: __modelSource,
|
|
2746
|
+
visionModel: cfg.visionModel,
|
|
2746
2747
|
},
|
|
2747
2748
|
visionNotice: __visionNotice,
|
|
2748
2749
|
cycleApproval: (m) => cycleMode(m),
|
|
@@ -3118,7 +3119,11 @@ program.action(async (opts) => {
|
|
|
3118
3119
|
await maybeAutoCompact(provider, history, meta, stats, cfg, (m) => h.sink.notice(m));
|
|
3119
3120
|
},
|
|
3120
3121
|
});
|
|
3121
|
-
|
|
3122
|
+
// Only claim "saved · resume" if a turn actually persisted the session. A zero-turn session (opened,
|
|
3123
|
+
// then exited without submitting anything) is never written by saveSession — so printing the resume
|
|
3124
|
+
// hint would mislead and `hara resume <id>` would fail with "no session matching".
|
|
3125
|
+
if (loadSession(meta.id))
|
|
3126
|
+
out("\n" + c.dim("Session ") + c.bold(shortId(meta.id)) + c.dim(" saved · resume: ") + c.cyan(`hara resume ${shortId(meta.id)}`) + "\n");
|
|
3122
3127
|
await closeMcp();
|
|
3123
3128
|
process.exit(0); // TUI done — exit cleanly (ink can leave stdin referenced)
|
|
3124
3129
|
}
|
package/dist/tui/App.js
CHANGED
|
@@ -165,6 +165,14 @@ export function shortenSession(uuid) {
|
|
|
165
165
|
* pad a label so the values align vertically across rows. */
|
|
166
166
|
const FIELD_PAD = 10;
|
|
167
167
|
const padField = (name) => name.padEnd(FIELD_PAD, " ");
|
|
168
|
+
/** Dim trailing clause for the model line: the vision sidecar (only when configured) then a subtle
|
|
169
|
+
* codex-style `/model` hint. Pure so the composition (spacing, ordering, silence-when-unset) can be
|
|
170
|
+
* pinned in a unit test without rendering React. Returns "" when there is nothing to show beyond
|
|
171
|
+
* the hint — the hint itself is always present (it's the discoverability affordance). */
|
|
172
|
+
export function modelLineSuffix(visionModel) {
|
|
173
|
+
const vision = visionModel ? ` · vision ${visionModel}` : "";
|
|
174
|
+
return `${vision} · /model to change`;
|
|
175
|
+
}
|
|
168
176
|
function HeaderCard(props) {
|
|
169
177
|
const { version, modelLabel, cwd, agentsMdLoaded, session, kind } = props;
|
|
170
178
|
const home = process.env.HOME ?? "";
|
|
@@ -172,8 +180,8 @@ function HeaderCard(props) {
|
|
|
172
180
|
const sessionShort = shortenSession(session);
|
|
173
181
|
// Identity line — branches on kind. Personal collapses kind+model into one line;
|
|
174
182
|
// org splits identity (org/label/id/route) from model (with its source).
|
|
175
|
-
const identity = kind === "org" ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("org")}` }), _jsx(Text, { children: props.orgLabel ?? props.orgId ?? "(unnamed)" }), props.orgId && props.orgLabel ? _jsx(Text, { dimColor: true, children: ` · ${props.orgId}` }) : null, props.routeHost ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " → " }), _jsx(Text, { dimColor: true, children: props.routeHost })] })) : null] })) : (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField(props.profileId ? `personal:${props.profileId}` : "personal")}` }), _jsx(Text, { children: modelLabel }), props.routeHost ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " → " }), _jsx(Text, { dimColor: true, children: props.routeHost })] })) : null] }));
|
|
176
|
-
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: accent(), children: "> " }), _jsx(Text, { color: accent(), bold: true, children: `hara` }), _jsx(Text, { dimColor: true, children: ` · v${version} — the coding agent that runs like an org` })] }), _jsx(Text, { children: " " }), identity, kind === "org" ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("model")}` }), _jsx(Text, { children: modelLabel }), props.modelSource ? _jsx(Text, { dimColor: true, children: ` · from ${props.modelSource}` }) : null] })) : null, _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("cwd")}` }), _jsx(Text, { dimColor: true, children: cwdShort }), agentsMdLoaded ? _jsx(Text, { dimColor: true, children: " · AGENTS.md" }) : null] }), sessionShort ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("session")}` }), _jsx(Text, { dimColor: true, children: sessionShort })] })) : null, _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " /help · @file · shift+tab · esc" })] }));
|
|
183
|
+
const identity = kind === "org" ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("org")}` }), _jsx(Text, { children: props.orgLabel ?? props.orgId ?? "(unnamed)" }), props.orgId && props.orgLabel ? _jsx(Text, { dimColor: true, children: ` · ${props.orgId}` }) : null, props.routeHost ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " → " }), _jsx(Text, { dimColor: true, children: props.routeHost })] })) : null] })) : (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField(props.profileId ? `personal:${props.profileId}` : "personal")}` }), _jsx(Text, { children: modelLabel }), props.routeHost ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: " → " }), _jsx(Text, { dimColor: true, children: props.routeHost })] })) : null, _jsx(Text, { dimColor: true, children: modelLineSuffix(props.visionModel) })] }));
|
|
184
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { children: [_jsx(Text, { color: accent(), children: "> " }), _jsx(Text, { color: accent(), bold: true, children: `hara` }), _jsx(Text, { dimColor: true, children: ` · v${version} — the coding agent that runs like an org` })] }), _jsx(Text, { children: " " }), identity, kind === "org" ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("model")}` }), _jsx(Text, { children: modelLabel }), props.modelSource ? _jsx(Text, { dimColor: true, children: ` · from ${props.modelSource}` }) : null, _jsx(Text, { dimColor: true, children: modelLineSuffix(props.visionModel) })] })) : null, _jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("cwd")}` }), _jsx(Text, { dimColor: true, children: cwdShort }), agentsMdLoaded ? _jsx(Text, { dimColor: true, children: " · AGENTS.md" }) : null] }), sessionShort ? (_jsxs(Text, { children: [_jsx(Text, { dimColor: true, children: ` ${padField("session")}` }), _jsx(Text, { dimColor: true, children: sessionShort })] })) : null, _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: " /help · @file · shift+tab · esc · ctrl+t transcript · ctrl+r reasoning" })] }));
|
|
177
185
|
}
|
|
178
186
|
// Spinner verb: while a turn is running, prefer the in_progress todo's activeForm (or its text),
|
|
179
187
|
// so the bottom line reads "▶ updating tests…" instead of an abstract "working". Falls back to
|
package/dist/tui/InputBox.js
CHANGED
|
@@ -31,7 +31,9 @@ const TopBorder = memo(function TopBorder({ name, width }) {
|
|
|
31
31
|
});
|
|
32
32
|
// Bottom border carries token usage + concurrency at the right corner (modes moved to ModeBar below).
|
|
33
33
|
const BottomBorder = memo(function BottomBorder({ s, width }) {
|
|
34
|
-
|
|
34
|
+
// Always render `ctx N%` (from 0 on) so the field is present from the first frame — otherwise it
|
|
35
|
+
// pops in mid-session the moment ctx first exceeds 0, shifting the whole bottom-border layout.
|
|
36
|
+
const usage = `↑${tok(s.input)} ↓${tok(s.output)} · ctx ${s.ctxPct}%`;
|
|
35
37
|
const label = s.agents > 0 ? `${usage} · ⛁${s.agents}` : `${usage} · ⛁ idle`;
|
|
36
38
|
const left = Math.max(2, width - label.length - 3);
|
|
37
39
|
return (_jsx(Box, { children: _jsx(Text, { dimColor: true, children: `${"─".repeat(left)} ${label} ─` }) }));
|