@phnx-labs/agents-cli 1.22.30 → 1.22.31

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.
@@ -96,7 +96,7 @@ export declare function itemPicker<T>(config: PickerConfig<T>): Promise<PickedIt
96
96
  */
97
97
  export declare function multiItemPicker<T>(config: MultiPickerConfig<T>): Promise<T[] | null>;
98
98
  /** Configuration for the dynamic (async-refetch) picker prompt. */
99
- export interface DynamicPickerConfig<T, F> {
99
+ export interface DynamicPickerConfig<T, F, A = never> {
100
100
  message: string;
101
101
  /** The initial filter state. Changing it (via a keybinding) re-runs {@link load}. */
102
102
  initialFilter: F;
@@ -117,6 +117,8 @@ export interface DynamicPickerConfig<T, F> {
117
117
  * SAME reference is a no-op; a new object triggers a reload.
118
118
  */
119
119
  keyBindings?: Record<string, (filter: F) => F>;
120
+ /** Keys that submit the highlighted row with an alternate typed action. */
121
+ submitKeys?: Record<string, A>;
120
122
  /**
121
123
  * Side-effecting keys that don't change the filter (e.g. `y` copies a command).
122
124
  * Receives the live search `query` so the effect can be search-aware. Return a
@@ -160,9 +162,10 @@ export declare function hotkeyToken(key: {
160
162
  meta?: boolean;
161
163
  }): string;
162
164
  /** The result returned when the user selects a row: the item plus the live filter. */
163
- export interface DynamicPicked<T, F> {
165
+ export interface DynamicPicked<T, F, A = never> {
164
166
  item: T;
165
167
  filter: F;
168
+ action?: A;
166
169
  }
167
170
  /**
168
171
  * Async-refetch variant of {@link itemPicker}. Holds a `filter` object in state and
@@ -174,4 +177,4 @@ export interface DynamicPicked<T, F> {
174
177
  * Same render/pagination/preview machinery as the static pickers — only the data
175
178
  * source and keymap are dynamic.
176
179
  */
177
- export declare function dynamicPicker<T, F>(config: DynamicPickerConfig<T, F>): Promise<DynamicPicked<T, F> | null>;
180
+ export declare function dynamicPicker<T, F, A = never>(config: DynamicPickerConfig<T, F, A>): Promise<DynamicPicked<T, F, A> | null>;
@@ -490,11 +490,11 @@ export function dynamicPicker(config) {
490
490
  setActive(0);
491
491
  }, [results]);
492
492
  const selected = results[active];
493
- const finish = () => {
493
+ const finish = (action) => {
494
494
  if (!selected)
495
495
  return;
496
496
  setStatus('done');
497
- done({ item: selected.value, filter });
497
+ done({ item: selected.value, filter, ...(action === undefined ? {} : { action }) });
498
498
  };
499
499
  useKeypress((key, rl) => {
500
500
  if (isEnterKey(key)) {
@@ -575,6 +575,11 @@ export function dynamicPicker(config) {
575
575
  // existing single-letter hotkey: `R`/`C`/`A` used to reach their bindings
576
576
  // via `key.name`, and keying on the character alone would silently retire
577
577
  // them for anyone with caps lock on.
578
+ const submitAction = cfg.submitKeys?.[token] ?? cfg.submitKeys?.[key.name ?? ''];
579
+ if (submitAction !== undefined) {
580
+ finish(submitAction);
581
+ return;
582
+ }
578
583
  const binding = cfg.keyBindings?.[token] ?? cfg.keyBindings?.[key.name ?? ''];
579
584
  if (binding) {
580
585
  const next = binding(filter);
@@ -463,7 +463,6 @@ export declare function agentLoad(name: string, bundle: SecretsBundle, env: Reco
463
463
  /** Wipe one bundle (or all if name omitted) from the broker. Returns the count
464
464
  * wiped, or 0 when no broker is running. */
465
465
  export declare function agentLock(name?: string): Promise<number>;
466
- export declare function agentRevoke(leaseId: string): Promise<number>;
467
466
  /** List currently-unlocked bundles, or [] when no broker is running. The
468
467
  * internal `secrets list` metadata-cache entry is filtered out here as well as
469
468
  * server-side: during a rollout a NEW client can talk to an OLD broker that
@@ -1310,10 +1310,6 @@ export async function agentLock(name) {
1310
1310
  const r = await request({ cmd: 'lock', name });
1311
1311
  return r?.ok === true && r.cmd === 'lock' ? r.wiped : 0;
1312
1312
  }
1313
- export async function agentRevoke(leaseId) {
1314
- const r = await request({ cmd: 'revoke', leaseId });
1315
- return r?.ok === true && r.cmd === 'revoke' ? r.wiped : 0;
1316
- }
1317
1313
  /** List currently-unlocked bundles, or [] when no broker is running. The
1318
1314
  * internal `secrets list` metadata-cache entry is filtered out here as well as
1319
1315
  * server-side: during a rollout a NEW client can talk to an OLD broker that
@@ -93,10 +93,6 @@ export declare function deleteBundleSessions(name: string): void;
93
93
  /** Delete one bundle's session blob and prune it from the index. */
94
94
  export declare function deleteSession(name: string, harness?: string): void;
95
95
  export declare function deleteLeaseSession(leaseId: string): number;
96
- export declare function activeLeaseSessions(now?: number): Array<{
97
- name: string;
98
- lease: SecretLease;
99
- }>;
100
96
  /** Delete every session blob + the index (for `secrets lock --all`). */
101
97
  export declare function deleteAllSessions(): void;
102
98
  /** Rehydrate every unexpired session into `[name, entry]` pairs for the broker to
@@ -208,11 +208,6 @@ export function deleteLeaseSession(leaseId) {
208
208
  }
209
209
  return deleted;
210
210
  }
211
- export function activeLeaseSessions(now = Date.now()) {
212
- return rehydrateSessions(now)
213
- .filter((item) => Boolean(item.entry.lease))
214
- .map(({ name, entry }) => ({ name, lease: entry.lease }));
215
- }
216
211
  /** Delete every session blob + the index (for `secrets lock --all`). */
217
212
  export function deleteAllSessions() {
218
213
  if (!shouldPersist())
@@ -1,39 +1,39 @@
1
1
  /**
2
- * Favorited sessions — the durable "keep this one handy" mark a human puts on a
2
+ * Bookmarked sessions — the durable "keep this one handy" mark a human puts on a
3
3
  * session, deliberately kept OUT of the session index.
4
4
  *
5
5
  * `sessions.db` is a rebuildable CACHE: a reindex or a schema bump throws its
6
- * rows away and re-derives them from the transcripts on disk. A favorite is not
6
+ * rows away and re-derives them from the transcripts on disk. A bookmark is not
7
7
  * derivable from a transcript — it is a human's choice — so a column there would
8
8
  * be silently lost on the next rebuild. It lives in `~/.agents/.history/` instead,
9
9
  * next to the actor sidecars, which is never pruned.
10
10
  *
11
11
  * One flat set of session ids. The id is the transcript's own uuid, so it is
12
12
  * stable and machine-independent — but the file is NOT synced today: session sync
13
- * carries `.history/backups/` (`lib/session/sync/agents.ts`), not this. Favorites
13
+ * carries `.history/backups/` (`lib/session/sync/agents.ts`), not this. Bookmarks
14
14
  * are therefore per-machine; carrying them across the fleet would mean adding
15
15
  * them to the sync manifest, which this does not do.
16
16
  *
17
- * Reads are memoized against the file's mtime — the picker asks `isFavorite` once
17
+ * Reads are memoized against the file's mtime — the picker asks `isBookmarked` once
18
18
  * per rendered row, and re-reading a JSON file per row on every keystroke is the
19
19
  * kind of cost that makes a TUI feel broken.
20
20
  */
21
- export declare function favoritesFilePath(): string;
21
+ export declare function bookmarksFilePath(): string;
22
22
  /** Drop the memoized read. Tests that write the file directly need this; nothing
23
23
  * in the CLI does, because every mutation here refreshes the cache itself. */
24
- export declare function clearFavoritesCache(): void;
24
+ export declare function clearBookmarksCache(): void;
25
25
  /**
26
- * Every favorited session id. Empty (never throws) when the file is absent,
27
- * unreadable, or malformed — a corrupt favorites file must not take down
26
+ * Every bookmarked session id. Empty (never throws) when the file is absent,
27
+ * unreadable, or malformed — a corrupt bookmarks file must not take down
28
28
  * `agents sessions`.
29
29
  */
30
- export declare function listFavorites(): Set<string>;
31
- export declare function isFavorite(sessionId: string | undefined): boolean;
30
+ export declare function listBookmarks(): Set<string>;
31
+ export declare function isBookmarked(sessionId: string | undefined): boolean;
32
32
  /**
33
- * Set (or clear) the favorite mark on a session. Returns the resulting state, so
33
+ * Set (or clear) the bookmark mark on a session. Returns the resulting state, so
34
34
  * a caller can report it without a second read. A no-op write is skipped, which
35
35
  * keeps the file's mtime — and every other process's memoized read — untouched.
36
36
  */
37
- export declare function setFavorite(sessionId: string, on: boolean): boolean;
38
- /** Flip the mark; returns the new state (`true` = now favorited). */
39
- export declare function toggleFavorite(sessionId: string): boolean;
37
+ export declare function setBookmark(sessionId: string, on: boolean): boolean;
38
+ /** Flip the mark; returns the new state (`true` = now bookmarked). */
39
+ export declare function toggleBookmark(sessionId: string): boolean;
@@ -1,28 +1,28 @@
1
1
  /**
2
- * Favorited sessions — the durable "keep this one handy" mark a human puts on a
2
+ * Bookmarked sessions — the durable "keep this one handy" mark a human puts on a
3
3
  * session, deliberately kept OUT of the session index.
4
4
  *
5
5
  * `sessions.db` is a rebuildable CACHE: a reindex or a schema bump throws its
6
- * rows away and re-derives them from the transcripts on disk. A favorite is not
6
+ * rows away and re-derives them from the transcripts on disk. A bookmark is not
7
7
  * derivable from a transcript — it is a human's choice — so a column there would
8
8
  * be silently lost on the next rebuild. It lives in `~/.agents/.history/` instead,
9
9
  * next to the actor sidecars, which is never pruned.
10
10
  *
11
11
  * One flat set of session ids. The id is the transcript's own uuid, so it is
12
12
  * stable and machine-independent — but the file is NOT synced today: session sync
13
- * carries `.history/backups/` (`lib/session/sync/agents.ts`), not this. Favorites
13
+ * carries `.history/backups/` (`lib/session/sync/agents.ts`), not this. Bookmarks
14
14
  * are therefore per-machine; carrying them across the fleet would mean adding
15
15
  * them to the sync manifest, which this does not do.
16
16
  *
17
- * Reads are memoized against the file's mtime — the picker asks `isFavorite` once
17
+ * Reads are memoized against the file's mtime — the picker asks `isBookmarked` once
18
18
  * per rendered row, and re-reading a JSON file per row on every keystroke is the
19
19
  * kind of cost that makes a TUI feel broken.
20
20
  */
21
21
  import fs from 'node:fs';
22
22
  import path from 'node:path';
23
23
  import { getHistoryDir } from '../state.js';
24
- export function favoritesFilePath() {
25
- return path.join(getHistoryDir(), 'favorites.json');
24
+ export function bookmarksFilePath() {
25
+ return path.join(getHistoryDir(), 'bookmarks.json');
26
26
  }
27
27
  /** Memoized parse, invalidated by the file's mtime+size (another process — or
28
28
  * another machine's sync — can rewrite it under us). */
@@ -38,16 +38,16 @@ function statKey(file) {
38
38
  }
39
39
  /** Drop the memoized read. Tests that write the file directly need this; nothing
40
40
  * in the CLI does, because every mutation here refreshes the cache itself. */
41
- export function clearFavoritesCache() {
41
+ export function clearBookmarksCache() {
42
42
  cache = null;
43
43
  }
44
44
  /**
45
- * Every favorited session id. Empty (never throws) when the file is absent,
46
- * unreadable, or malformed — a corrupt favorites file must not take down
45
+ * Every bookmarked session id. Empty (never throws) when the file is absent,
46
+ * unreadable, or malformed — a corrupt bookmarks file must not take down
47
47
  * `agents sessions`.
48
48
  */
49
- export function listFavorites() {
50
- const file = favoritesFilePath();
49
+ export function listBookmarks() {
50
+ const file = bookmarksFilePath();
51
51
  const key = statKey(file);
52
52
  if (cache && cache.key === key)
53
53
  return cache.ids;
@@ -64,14 +64,14 @@ export function listFavorites() {
64
64
  cache = { key, ids };
65
65
  return ids;
66
66
  }
67
- export function isFavorite(sessionId) {
67
+ export function isBookmarked(sessionId) {
68
68
  if (!sessionId)
69
69
  return false;
70
- return listFavorites().has(sessionId);
70
+ return listBookmarks().has(sessionId);
71
71
  }
72
72
  /** Atomic write (tmp + rename) so a concurrent reader never sees a half file. */
73
- function writeFavorites(ids) {
74
- const file = favoritesFilePath();
73
+ function writeBookmarks(ids) {
74
+ const file = bookmarksFilePath();
75
75
  fs.mkdirSync(path.dirname(file), { recursive: true });
76
76
  const body = { version: 1, sessionIds: [...ids].sort() };
77
77
  const tmp = `${file}.${process.pid}.tmp`;
@@ -80,22 +80,22 @@ function writeFavorites(ids) {
80
80
  cache = { key: statKey(file), ids };
81
81
  }
82
82
  /**
83
- * Set (or clear) the favorite mark on a session. Returns the resulting state, so
83
+ * Set (or clear) the bookmark mark on a session. Returns the resulting state, so
84
84
  * a caller can report it without a second read. A no-op write is skipped, which
85
85
  * keeps the file's mtime — and every other process's memoized read — untouched.
86
86
  */
87
- export function setFavorite(sessionId, on) {
88
- const ids = new Set(listFavorites());
87
+ export function setBookmark(sessionId, on) {
88
+ const ids = new Set(listBookmarks());
89
89
  if (ids.has(sessionId) === on)
90
90
  return on;
91
91
  if (on)
92
92
  ids.add(sessionId);
93
93
  else
94
94
  ids.delete(sessionId);
95
- writeFavorites(ids);
95
+ writeBookmarks(ids);
96
96
  return on;
97
97
  }
98
- /** Flip the mark; returns the new state (`true` = now favorited). */
99
- export function toggleFavorite(sessionId) {
100
- return setFavorite(sessionId, !isFavorite(sessionId));
98
+ /** Flip the mark; returns the new state (`true` = now bookmarked). */
99
+ export function toggleBookmark(sessionId) {
100
+ return setBookmark(sessionId, !isBookmarked(sessionId));
101
101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@phnx-labs/agents-cli",
3
- "version": "1.22.30",
3
+ "version": "1.22.31",
4
4
  "description": "One CLI for all your AI coding agents - versions, config, cloud dispatch, sessions, and teams (now with first-class Grok Build CLI support)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",