mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-03 14:09:42 +02:00
fix: cover tui in the CLI inventory and drop the em-dashes it printed
The inventory test predates the `tui` command, so a rename or an accidental removal would have gone unnoticed: it now asserts the command, its `-l`/`--list` flag and its optional position operand. The digest and search-result lines joined their halves with an em-dash, which the repo's own convention rules out, so both now use the middle dot the surrounding lines already use. The one em-dash left in `src/tui/` is load-bearing: `search-service.ts` builds a session snippet with it, and the pattern that strips the repeated label has to match it. Also moves `buildSearchEntries`'s doc comment back onto `buildSearchEntries`; it had ended up stacked above a helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1399,7 +1399,7 @@ class TuiApp {
|
||||
}
|
||||
// Nothing to switch to (a history or file hit), so the row's own facts are
|
||||
// the answer; resuming one is phase 3.
|
||||
this.model.updateSearch({ note: [entry.text, entry.detail].filter((part) => part).join(' — ') });
|
||||
this.model.updateSearch({ note: [entry.text, entry.detail].filter((part) => part).join(' · ') });
|
||||
}
|
||||
|
||||
private async openDigest(): Promise<void> {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* API the web UI uses, so the two surfaces can never disagree. This module is
|
||||
* the only place in `src/tui/` that does IO. It covers four jobs:
|
||||
*
|
||||
* 1. **Discovery + auth** — find the instance's server (`CODEMAN_API_URL`, else
|
||||
* 1. **Discovery + auth**: find the instance's server (`CODEMAN_API_URL`, else
|
||||
* loopback on `CODEMAN_PORT`), accepting the self-signed cert `--https`
|
||||
* generates, and read credentials the way `codeman attach` already does
|
||||
* (env, then the data dir's `.env`).
|
||||
@@ -15,7 +15,7 @@
|
||||
* 3. **Live updates** over SSE, decoded by `tui-sse.ts`, with a staleness
|
||||
* watchdog and capped backoff. The TUI does not patch rows from payloads: an
|
||||
* interesting event means "resync", and the app layer debounces the refetch.
|
||||
* 4. **Degraded mode** — when nothing answers, sessions are enumerated straight
|
||||
* 4. **Degraded mode**: when nothing answers, sessions are enumerated straight
|
||||
* from tmux plus a read-only peek at `state.json`, which keeps the "the
|
||||
* server died, get me to my sessions" path that `sc` has today.
|
||||
*
|
||||
|
||||
@@ -47,7 +47,7 @@ function ageColumn(item: AwayDigestItem, now: number): string {
|
||||
|
||||
function itemLine(item: AwayDigestItem, now: number): string {
|
||||
const who = item.sessionName ?? item.sessionId?.slice(0, 8) ?? '';
|
||||
const what = [item.title, item.detail].filter((part) => part && part.trim() !== '').join(' — ');
|
||||
const what = [item.title, item.detail].filter((part) => part && part.trim() !== '').join(' · ');
|
||||
return ` ${ageColumn(item, now)} ${[who, what].filter((part) => part !== '').join(' ')}`.replace(/\s+$/, '');
|
||||
}
|
||||
|
||||
|
||||
+11
-10
@@ -208,6 +208,17 @@ const SEARCH_GROUP_LABELS: Record<SearchSourceType, string> = {
|
||||
file: 'FILES',
|
||||
};
|
||||
|
||||
/**
|
||||
* A session snippet opens with the session's own name, which the row already
|
||||
* shows in its first column (`search-service.ts` builds it as
|
||||
* `w1-alpha <em dash> /tmp/alpha`, hence the separator in the pattern).
|
||||
* Dropping the repeat is what keeps a result row from reading as a stutter.
|
||||
*/
|
||||
function withoutLabelPrefix(snippet: string, label: string): string {
|
||||
const rest = snippet.startsWith(label) ? snippet.slice(label.length) : snippet;
|
||||
return rest === snippet ? snippet : rest.replace(/^\s*(?:[—:-]\s*)?/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatten `GET /api/search`'s typed groups into the overlay's lines: a header
|
||||
* per group, then its results. Only a result row carries a session id, which is
|
||||
@@ -217,16 +228,6 @@ const SEARCH_GROUP_LABELS: Record<SearchSourceType, string> = {
|
||||
* has a session id too, but selecting it would move the cursor to a row that is
|
||||
* not on the list.
|
||||
*/
|
||||
/**
|
||||
* A session snippet opens with the session's own name (`w1-alpha — /tmp/alpha`),
|
||||
* which the row already shows in its first column. Dropping the repeat is what
|
||||
* keeps a result row from reading as a stutter.
|
||||
*/
|
||||
function withoutLabelPrefix(snippet: string, label: string): string {
|
||||
const rest = snippet.startsWith(label) ? snippet.slice(label.length) : snippet;
|
||||
return rest === snippet ? snippet : rest.replace(/^\s*(?:[—:-]\s*)?/, '');
|
||||
}
|
||||
|
||||
export function buildSearchEntries(
|
||||
groups: readonly SearchResultGroup[],
|
||||
isLive: (sessionId: string) => boolean
|
||||
|
||||
@@ -40,6 +40,7 @@ const TOP_LEVEL: Record<string, string[]> = {
|
||||
reset: [],
|
||||
start: [],
|
||||
list: ['ls'],
|
||||
tui: [],
|
||||
web: [],
|
||||
service: [],
|
||||
users: [],
|
||||
@@ -137,6 +138,10 @@ describe('registered options', () => {
|
||||
expect(flagsOf(find(program, 'doctor')!)).toEqual(expect.arrayContaining(['--json', '--category']));
|
||||
});
|
||||
|
||||
it('keeps the two `tui` fast paths, which stand in for `sc -l` and `sc 2`', () => {
|
||||
expect(flagsOf(find(program, 'tui')!)).toEqual(expect.arrayContaining(['-l', '--list']));
|
||||
});
|
||||
|
||||
it('keeps the escape hatches that scripts depend on', () => {
|
||||
expect(flagsOf(find(program, 'reset')!)).toEqual(expect.arrayContaining(['-f', '--force']));
|
||||
expect(flagsOf(find(program, 'status')!)).toEqual(expect.arrayContaining(['--url']));
|
||||
@@ -164,6 +169,8 @@ describe('registered arguments', () => {
|
||||
it.each([
|
||||
['attach', ['path']],
|
||||
['start', []],
|
||||
// Optional: bare `codeman tui` opens the dashboard.
|
||||
['tui', ['n']],
|
||||
])('declares the operands of `%s`', (name, expected) => {
|
||||
const args = find(program, name)!.registeredArguments.map((arg) => arg.name());
|
||||
expect(args).toEqual(expected);
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('formatAwayDigest', () => {
|
||||
{ now: NOW }
|
||||
);
|
||||
expect(lines).toContain('NEEDS ATTENTION (1)');
|
||||
expect(lines).toContain(' 2m w4-api permission prompt — Bash(git push)');
|
||||
expect(lines).toContain(' 2m w4-api permission prompt · Bash(git push)');
|
||||
});
|
||||
|
||||
it('caps a long section instead of burying the next one', () => {
|
||||
|
||||
Reference in New Issue
Block a user