@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.
- package/CHANGELOG.md +6 -0
- package/README.md +5 -4
- package/dist/bin/agents +0 -0
- package/dist/commands/focus.d.ts +4 -1
- package/dist/commands/focus.js +19 -4
- package/dist/commands/secrets.d.ts +20 -0
- package/dist/commands/secrets.js +59 -93
- package/dist/commands/{sessions-favorite.d.ts → sessions-bookmark.d.ts} +7 -7
- package/dist/commands/{sessions-favorite.js → sessions-bookmark.js} +38 -38
- package/dist/commands/sessions-browser.d.ts +10 -8
- package/dist/commands/sessions-browser.js +61 -32
- package/dist/commands/sessions-stats.js +1 -1
- package/dist/commands/sessions.d.ts +10 -8
- package/dist/commands/sessions.js +70 -55
- package/dist/index.js +1 -1
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/migrate.js +6 -0
- package/dist/lib/picker.d.ts +6 -3
- package/dist/lib/picker.js +7 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/agent.d.ts +0 -1
- package/dist/lib/secrets/agent.js +0 -4
- package/dist/lib/secrets/session-store.d.ts +0 -4
- package/dist/lib/secrets/session-store.js +0 -5
- package/dist/lib/session/{favorites.d.ts → bookmarks.d.ts} +14 -14
- package/dist/lib/session/{favorites.js → bookmarks.js} +22 -22
- package/package.json +1 -1
package/dist/lib/picker.d.ts
CHANGED
|
@@ -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>;
|
package/dist/lib/picker.js
CHANGED
|
@@ -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);
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
-
*
|
|
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
|
|
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.
|
|
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 `
|
|
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
|
|
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
|
|
24
|
+
export declare function clearBookmarksCache(): void;
|
|
25
25
|
/**
|
|
26
|
-
* Every
|
|
27
|
-
* unreadable, or malformed — a corrupt
|
|
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
|
|
31
|
-
export declare function
|
|
30
|
+
export declare function listBookmarks(): Set<string>;
|
|
31
|
+
export declare function isBookmarked(sessionId: string | undefined): boolean;
|
|
32
32
|
/**
|
|
33
|
-
* Set (or clear) the
|
|
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
|
|
38
|
-
/** Flip the mark; returns the new state (`true` = now
|
|
39
|
-
export declare function
|
|
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
|
-
*
|
|
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
|
|
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.
|
|
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 `
|
|
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
|
|
25
|
-
return path.join(getHistoryDir(), '
|
|
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
|
|
41
|
+
export function clearBookmarksCache() {
|
|
42
42
|
cache = null;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
|
-
* Every
|
|
46
|
-
* unreadable, or malformed — a corrupt
|
|
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
|
|
50
|
-
const file =
|
|
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
|
|
67
|
+
export function isBookmarked(sessionId) {
|
|
68
68
|
if (!sessionId)
|
|
69
69
|
return false;
|
|
70
|
-
return
|
|
70
|
+
return listBookmarks().has(sessionId);
|
|
71
71
|
}
|
|
72
72
|
/** Atomic write (tmp + rename) so a concurrent reader never sees a half file. */
|
|
73
|
-
function
|
|
74
|
-
const file =
|
|
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
|
|
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
|
|
88
|
-
const ids = new Set(
|
|
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
|
-
|
|
95
|
+
writeBookmarks(ids);
|
|
96
96
|
return on;
|
|
97
97
|
}
|
|
98
|
-
/** Flip the mark; returns the new state (`true` = now
|
|
99
|
-
export function
|
|
100
|
-
return
|
|
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.
|
|
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",
|