@phnx-labs/agents-cli 1.20.89 → 1.20.91
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 +361 -0
- package/README.md +6 -0
- package/dist/bin/agents +0 -0
- package/dist/commands/exec.js +7 -1
- package/dist/commands/feed.js +77 -4
- package/dist/commands/harness.d.ts +27 -0
- package/dist/commands/harness.js +120 -13
- package/dist/commands/hooks.js +22 -6
- package/dist/commands/perf.d.ts +14 -0
- package/dist/commands/perf.js +221 -0
- package/dist/commands/profiles.d.ts +3 -0
- package/dist/commands/profiles.js +1 -1
- package/dist/commands/routines.d.ts +19 -0
- package/dist/commands/routines.js +58 -30
- package/dist/commands/secrets.d.ts +52 -4
- package/dist/commands/secrets.js +234 -37
- package/dist/commands/send.d.ts +5 -1
- package/dist/commands/send.js +1 -1
- package/dist/commands/sessions-browser.d.ts +4 -0
- package/dist/commands/sessions-browser.js +51 -9
- package/dist/commands/sessions-favorite.d.ts +20 -0
- package/dist/commands/sessions-favorite.js +120 -0
- package/dist/commands/sessions-picker.js +70 -1
- package/dist/commands/sessions.d.ts +103 -20
- package/dist/commands/sessions.js +356 -62
- package/dist/commands/setup-secrets.d.ts +7 -0
- package/dist/commands/setup-secrets.js +12 -9
- package/dist/commands/versions.js +12 -4
- package/dist/commands/view.d.ts +14 -1
- package/dist/commands/view.js +103 -128
- package/dist/index.js +18 -3
- package/dist/lib/activity.d.ts +11 -1
- package/dist/lib/activity.js +1 -0
- package/dist/lib/agents.d.ts +4 -2
- package/dist/lib/agents.js +21 -6
- package/dist/lib/catchup.d.ts +105 -0
- package/dist/lib/catchup.js +160 -0
- package/dist/lib/channels/providers/desktop.d.ts +49 -0
- package/dist/lib/channels/providers/desktop.js +132 -0
- package/dist/lib/channels/providers/index.js +2 -0
- package/dist/lib/daemon.js +74 -13
- package/dist/lib/events.d.ts +12 -0
- package/dist/lib/events.js +122 -9
- package/dist/lib/exec.js +10 -0
- package/dist/lib/feed-broadcast.d.ts +47 -0
- package/dist/lib/feed-broadcast.js +65 -1
- package/dist/lib/feed-post.d.ts +10 -0
- package/dist/lib/feed-post.js +1 -1
- package/dist/lib/feed.d.ts +47 -1
- package/dist/lib/feed.js +38 -0
- package/dist/lib/hooks/cache.d.ts +2 -0
- package/dist/lib/hooks/cache.js +24 -4
- package/dist/lib/hosts/dispatch.js +19 -1
- package/dist/lib/hq/floor.js +12 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/overdue.d.ts +14 -0
- package/dist/lib/overdue.js +37 -1
- package/dist/lib/perf/db.d.ts +25 -0
- package/dist/lib/perf/db.js +290 -0
- package/dist/lib/perf/spool.d.ts +18 -0
- package/dist/lib/perf/spool.js +79 -0
- package/dist/lib/perf/types.d.ts +45 -0
- package/dist/lib/perf/types.js +2 -0
- package/dist/lib/picker.d.ts +27 -2
- package/dist/lib/picker.js +71 -7
- package/dist/lib/profiles.d.ts +48 -0
- package/dist/lib/profiles.js +67 -0
- package/dist/lib/rotate.d.ts +24 -2
- package/dist/lib/rotate.js +63 -6
- package/dist/lib/routines-project.js +6 -0
- package/dist/lib/routines.d.ts +30 -1
- package/dist/lib/routines.js +11 -0
- 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/list-filter.d.ts +94 -0
- package/dist/lib/secrets/list-filter.js +245 -0
- package/dist/lib/session/active.d.ts +109 -3
- package/dist/lib/session/active.js +269 -13
- package/dist/lib/session/db.d.ts +14 -0
- package/dist/lib/session/db.js +35 -0
- package/dist/lib/session/digest.d.ts +7 -0
- package/dist/lib/session/digest.js +29 -1
- package/dist/lib/session/discover.d.ts +1 -2
- package/dist/lib/session/discover.js +7 -24
- package/dist/lib/session/favorites.d.ts +39 -0
- package/dist/lib/session/favorites.js +101 -0
- package/dist/lib/session/highlights.d.ts +82 -0
- package/dist/lib/session/highlights.js +251 -0
- package/dist/lib/session/host-link.d.ts +68 -0
- package/dist/lib/session/host-link.js +64 -0
- package/dist/lib/session/parse.js +23 -1
- package/dist/lib/session/presence.d.ts +85 -0
- package/dist/lib/session/presence.js +150 -0
- package/dist/lib/session/relative-time.d.ts +14 -0
- package/dist/lib/session/relative-time.js +36 -0
- package/dist/lib/session/remote-list.d.ts +10 -0
- package/dist/lib/session/remote-list.js +47 -9
- package/dist/lib/session/render.d.ts +7 -0
- package/dist/lib/session/render.js +87 -17
- package/dist/lib/session/types.d.ts +4 -1
- package/dist/lib/startup/command-registry.d.ts +1 -0
- package/dist/lib/startup/command-registry.js +2 -0
- package/dist/lib/state.d.ts +9 -0
- package/dist/lib/state.js +11 -0
- package/dist/lib/tmux/binary.d.ts +7 -0
- package/dist/lib/tmux/binary.js +11 -1
- package/dist/lib/types.d.ts +4 -3
- package/dist/lib/usage-backoff.d.ts +29 -0
- package/dist/lib/usage-backoff.js +165 -0
- package/dist/lib/usage.d.ts +112 -5
- package/dist/lib/usage.js +464 -46
- package/dist/lib/watchdog/runner.d.ts +13 -0
- package/dist/lib/watchdog/runner.js +16 -1
- package/package.json +3 -1
|
@@ -19,9 +19,10 @@ import { fireWebhookJobs, matchJobsToWebhook } from '../lib/triggers/webhook.js'
|
|
|
19
19
|
import { getRoutinesDir } from '../lib/state.js';
|
|
20
20
|
import { IS_WINDOWS } from '../lib/platform/index.js';
|
|
21
21
|
import { safeJoin } from '../lib/paths.js';
|
|
22
|
-
import { executeJob,
|
|
22
|
+
import { executeJob, monitorRunningJobs, ROUTINE_AGENT_IDS } from '../lib/runner.js';
|
|
23
23
|
import { JobScheduler } from '../lib/scheduler.js';
|
|
24
24
|
import { detectOverdueJobs } from '../lib/overdue.js';
|
|
25
|
+
import { runCatchup } from '../lib/catchup.js';
|
|
25
26
|
import { isInteractiveTerminal, requireInteractiveSelection } from './utils.js';
|
|
26
27
|
import { setHelpSections } from '../lib/help.js';
|
|
27
28
|
import { loadDevices, loadDevicesSync } from '../lib/devices/registry.js';
|
|
@@ -138,6 +139,21 @@ function deviceLabel(job, width) {
|
|
|
138
139
|
: raw;
|
|
139
140
|
return { raw, display, dim: full.length === 0 || !jobRunsOnThisDevice(job) };
|
|
140
141
|
}
|
|
142
|
+
/**
|
|
143
|
+
* The last run THIS device can speak for.
|
|
144
|
+
*
|
|
145
|
+
* A run record is written by whichever daemon fired the routine, into that
|
|
146
|
+
* machine's own runs dir — records carry no device attribution, so a record
|
|
147
|
+
* found here only ever describes this device's history. When a routine is
|
|
148
|
+
* pinned away from this machine (`devices:` excludes it) any local record is a
|
|
149
|
+
* leftover from before the pin, and reporting it as the routine's status paints
|
|
150
|
+
* another device's healthy routine red. Report nothing instead; the local
|
|
151
|
+
* history stays readable via `agents routines runs <name>`, and the owning
|
|
152
|
+
* device's status via `agents routines list --device <name>`.
|
|
153
|
+
*/
|
|
154
|
+
export function localLatestRun(job) {
|
|
155
|
+
return jobRunsOnThisDevice(job) ? getLatestRun(job.name) : null;
|
|
156
|
+
}
|
|
141
157
|
export function groupRoutineJobsByDevice(jobs, registry, self = machineId()) {
|
|
142
158
|
const groups = new Map();
|
|
143
159
|
const add = (key, title, job) => {
|
|
@@ -146,7 +162,9 @@ export function groupRoutineJobsByDevice(jobs, registry, self = machineId()) {
|
|
|
146
162
|
existing.jobs.push(job);
|
|
147
163
|
return;
|
|
148
164
|
}
|
|
149
|
-
|
|
165
|
+
// `device:` is the only group that describes a machine other than this one,
|
|
166
|
+
// so it is the only one whose rows this device cannot report a status for.
|
|
167
|
+
groups.set(key, { key, title, jobs: [job], local: !key.startsWith('device:') });
|
|
150
168
|
};
|
|
151
169
|
for (const job of jobs) {
|
|
152
170
|
const strategy = resolveHostStrategy(job);
|
|
@@ -193,7 +211,7 @@ export function groupRoutineJobsByDevice(jobs, registry, self = machineId()) {
|
|
|
193
211
|
};
|
|
194
212
|
return [...groups.values()].sort((a, b) => order(a) - order(b) || a.title.localeCompare(b.title));
|
|
195
213
|
}
|
|
196
|
-
function renderRoutineRows({ jobs, scheduler, overdueSet, link, now }) {
|
|
214
|
+
function renderRoutineRows({ jobs, scheduler, overdueSet, link, now, local = true }) {
|
|
197
215
|
const NAME_W = 24;
|
|
198
216
|
const AGENT_W = 10;
|
|
199
217
|
const REPO_W = REPO_DISPLAY_MAX;
|
|
@@ -207,7 +225,7 @@ function renderRoutineRows({ jobs, scheduler, overdueSet, link, now }) {
|
|
|
207
225
|
for (const job of jobs) {
|
|
208
226
|
const nextStr = nextRunLabel(job, scheduler, now);
|
|
209
227
|
const schedStr = scheduleLabel(job);
|
|
210
|
-
const latestRun =
|
|
228
|
+
const latestRun = local ? localLatestRun(job) : null;
|
|
211
229
|
const lastStatus = latestRun?.status || '-';
|
|
212
230
|
const sourceRepo = job.source?.repo ?? job.repo;
|
|
213
231
|
const sourceLabel = sourceRepo
|
|
@@ -225,7 +243,10 @@ function renderRoutineRows({ jobs, scheduler, overdueSet, link, now }) {
|
|
|
225
243
|
const statusColor = lastStatus === 'completed' ? chalk.green
|
|
226
244
|
: lastStatus === 'failed' ? chalk.red
|
|
227
245
|
: lastStatus === 'timeout' ? chalk.yellow
|
|
228
|
-
|
|
246
|
+
// A miss is an infrastructure problem, not a task failure — the routine
|
|
247
|
+
// never ran. Distinct from red so the two prompt different reactions.
|
|
248
|
+
: lastStatus === 'missed' ? chalk.magenta
|
|
249
|
+
: chalk.gray;
|
|
229
250
|
const overdueTag = overdueSet.has(job.name) ? chalk.yellow(' (overdue)') : '';
|
|
230
251
|
const agentLabelPadded = job.command
|
|
231
252
|
? chalk.magenta('command'.padEnd(10))
|
|
@@ -509,7 +530,7 @@ export function registerRoutinesCommands(program) {
|
|
|
509
530
|
if (options.json) {
|
|
510
531
|
const nowJson = new Date();
|
|
511
532
|
const payload = jobs.map((job) => {
|
|
512
|
-
const latestRun =
|
|
533
|
+
const latestRun = localLatestRun(job);
|
|
513
534
|
return {
|
|
514
535
|
name: job.name,
|
|
515
536
|
agent: job.agent ?? null,
|
|
@@ -527,6 +548,7 @@ export function registerRoutinesCommands(program) {
|
|
|
527
548
|
sourceRepo: job.source?.repo ?? job.repo ?? null,
|
|
528
549
|
sourceBranch: job.source?.branch ?? null,
|
|
529
550
|
runOnce: Boolean(job.runOnce),
|
|
551
|
+
catchup: job.catchup !== false,
|
|
530
552
|
oneShot: isOneShotRoutine(job),
|
|
531
553
|
expired: isPastOneShotRoutine(job, nowJson),
|
|
532
554
|
runsHere: jobRunsOnThisDevice(job),
|
|
@@ -562,9 +584,14 @@ export function registerRoutinesCommands(program) {
|
|
|
562
584
|
catch (err) {
|
|
563
585
|
console.error(chalk.yellow(`Could not read device registry: ${err.message}`));
|
|
564
586
|
}
|
|
565
|
-
|
|
587
|
+
const groups = groupRoutineJobsByDevice(jobs, registry);
|
|
588
|
+
for (const group of groups) {
|
|
566
589
|
console.log(chalk.bold(`\n${group.title}`));
|
|
567
|
-
renderRoutineRows({ jobs: group.jobs, scheduler, overdueSet, link, now });
|
|
590
|
+
renderRoutineRows({ jobs: group.jobs, scheduler, overdueSet, link, now, local: group.local });
|
|
591
|
+
}
|
|
592
|
+
if (groups.some((group) => !group.local)) {
|
|
593
|
+
console.log();
|
|
594
|
+
console.log(chalk.gray(' Last Status is per-device: rows under another device show "-" — read it there with: agents routines list --device <name>'));
|
|
568
595
|
}
|
|
569
596
|
}
|
|
570
597
|
if (overdueSet.size > 0) {
|
|
@@ -600,6 +627,7 @@ export function registerRoutinesCommands(program) {
|
|
|
600
627
|
.option('--state-to <name>', 'Linear current-state filter for --on linear:<event> (e.g. Plan)')
|
|
601
628
|
.option('--state-from <name>', 'Linear previous-state filter for --on linear:<event> (e.g. Triage)')
|
|
602
629
|
.option('--end-at <iso>', 'Stop firing on or after this ISO 8601 timestamp (e.g., "2026-12-31T23:59:00Z"); routine auto-disables.')
|
|
630
|
+
.option('--no-catchup', 'Do not run this routine late if its fire is missed (daemon down/asleep). The miss is still recorded. For routines whose value expires with their slot, e.g. a 9am brief.')
|
|
603
631
|
.option('--disabled', 'Create the routine but keep it paused (enable later with resume)')
|
|
604
632
|
.option('--resume <sessionId>', 'At fire time, resume this existing session id (via `agents run <agent> --resume`) instead of starting fresh — the actual session reopens with full context and the prompt becomes its next turn. Powers self-scheduled wake-ups (e.g. /hibernate). Requires --agent claude or codex; runs un-sandboxed (the session store lives in the real home, not the job overlay).')
|
|
605
633
|
.option('--json', 'Emit machine-readable JSON with the created routine id and status')
|
|
@@ -712,6 +740,7 @@ export function registerRoutinesCommands(program) {
|
|
|
712
740
|
...(hostStrategy ? { hostStrategy } : {}),
|
|
713
741
|
...(options.runCwd ? { remoteCwd: options.runCwd } : {}),
|
|
714
742
|
...(runOnce ? { runOnce: true } : {}),
|
|
743
|
+
...(options.catchup === false ? { catchup: false } : {}),
|
|
715
744
|
...(options.endAt ? { endAt: options.endAt } : {}),
|
|
716
745
|
...(options.resume ? { resume: options.resume } : {}),
|
|
717
746
|
};
|
|
@@ -1087,44 +1116,42 @@ export function registerRoutinesCommands(program) {
|
|
|
1087
1116
|
});
|
|
1088
1117
|
routinesCmd
|
|
1089
1118
|
.command('catchup')
|
|
1090
|
-
.description('Run any routines that missed their last scheduled fire
|
|
1091
|
-
.option('--dry-run', '
|
|
1119
|
+
.description('Run any routines that missed their last scheduled fire on demand. The daemon already does this every 5 minutes — use this to force a pass now. Detached: runs in the background under the scheduler.')
|
|
1120
|
+
.option('--dry-run', 'Record the misses and list them without running anything')
|
|
1092
1121
|
.action(async (options) => {
|
|
1093
1122
|
const overdue = detectOverdueJobs();
|
|
1094
1123
|
if (overdue.length === 0) {
|
|
1095
|
-
console.log(chalk.gray('No
|
|
1124
|
+
console.log(chalk.gray('No missed fires.'));
|
|
1096
1125
|
return;
|
|
1097
1126
|
}
|
|
1098
|
-
console.log(chalk.bold(`${overdue.length}
|
|
1127
|
+
console.log(chalk.bold(`${overdue.length} missed fire(s):\n`));
|
|
1099
1128
|
for (const job of overdue) {
|
|
1100
1129
|
const last = job.lastRanAt ? job.lastRanAt.toLocaleString() : 'never';
|
|
1101
1130
|
console.log(` ${chalk.cyan(job.name)} — missed ${chalk.gray(job.expectedAt.toLocaleString())}, last ran ${chalk.gray(last)}`);
|
|
1102
1131
|
}
|
|
1103
|
-
if (options.dryRun) {
|
|
1104
|
-
console.log(chalk.gray('\n(dry run — no jobs triggered)'));
|
|
1105
|
-
return;
|
|
1106
|
-
}
|
|
1107
1132
|
// Need the daemon alive so spawned jobs are monitored and meta.json is
|
|
1108
1133
|
// finalized. Start it if it isn't already running.
|
|
1109
|
-
if (!isDaemonRunning()) {
|
|
1134
|
+
if (!options.dryRun && !isDaemonRunning()) {
|
|
1110
1135
|
const started = startDaemon();
|
|
1111
1136
|
if (started.pid) {
|
|
1112
1137
|
console.log(chalk.gray(`\nStarted scheduler (PID: ${started.pid}) so catchup runs are monitored.`));
|
|
1113
1138
|
}
|
|
1114
1139
|
}
|
|
1115
|
-
console.log(chalk.bold('\nTriggering catchup runs...'));
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
if (
|
|
1119
|
-
console.log(` ${
|
|
1120
|
-
continue;
|
|
1140
|
+
console.log(chalk.bold(options.dryRun ? '\nRecording misses...' : '\nTriggering catchup runs...'));
|
|
1141
|
+
const outcomes = await runCatchup({ overdue, dryRun: options.dryRun });
|
|
1142
|
+
for (const o of outcomes) {
|
|
1143
|
+
if (o.result === 'ran') {
|
|
1144
|
+
console.log(` ${o.name} → ${chalk.green('started')} (run: ${o.runId})`);
|
|
1121
1145
|
}
|
|
1122
|
-
|
|
1123
|
-
const
|
|
1124
|
-
console.log(` ${
|
|
1146
|
+
else if (o.result === 'recorded') {
|
|
1147
|
+
const why = options.dryRun ? 'dry run' : 'catchup: false';
|
|
1148
|
+
console.log(` ${o.name} → ${chalk.yellow('recorded as missed')} (${why})`);
|
|
1125
1149
|
}
|
|
1126
|
-
|
|
1127
|
-
console.log(` ${
|
|
1150
|
+
else if (o.result === 'claimed-elsewhere') {
|
|
1151
|
+
console.log(` ${o.name} → ${chalk.gray('already claimed by the scheduler')}`);
|
|
1152
|
+
}
|
|
1153
|
+
else {
|
|
1154
|
+
console.log(` ${o.name} → ${chalk.red('failed to start')}: ${o.error}`);
|
|
1128
1155
|
}
|
|
1129
1156
|
}
|
|
1130
1157
|
console.log(chalk.gray('\nTrack progress with: agents routines runs <name>'));
|
|
@@ -1248,8 +1275,9 @@ export function registerRoutinesCommands(program) {
|
|
|
1248
1275
|
// is the concise view. Falls back to a bounded stdout tail when no report
|
|
1249
1276
|
// was extracted (e.g. the run failed before finishing).
|
|
1250
1277
|
const statusColor = run.status === 'completed' ? chalk.green
|
|
1251
|
-
: run.status === '
|
|
1252
|
-
: chalk.
|
|
1278
|
+
: run.status === 'missed' ? chalk.magenta
|
|
1279
|
+
: run.status === 'failed' || run.status === 'timeout' ? chalk.red
|
|
1280
|
+
: chalk.yellow;
|
|
1253
1281
|
console.log(chalk.bold(name) + chalk.gray(` run ${runId}`));
|
|
1254
1282
|
console.log(statusColor(run.status) +
|
|
1255
1283
|
chalk.gray(` ${run.startedAt}`) +
|
|
@@ -9,6 +9,7 @@ import { type Command } from 'commander';
|
|
|
9
9
|
import { SSH_TARGET_RE, assertValidSshTarget } from '../lib/ssh-exec.js';
|
|
10
10
|
import { quoteWin32ExecArg } from '../lib/platform/index.js';
|
|
11
11
|
import { type SecretsBackend, type SecretsBundle, type SecretsPolicy } from '../lib/secrets/bundles.js';
|
|
12
|
+
import { type SecretsListFilterOpts } from '../lib/secrets/list-filter.js';
|
|
12
13
|
/** Read all available data from stdin synchronously, trimmed. */
|
|
13
14
|
/**
|
|
14
15
|
* Read the raw `.env` text for `import --from <path|->`. A `-` reads the .env
|
|
@@ -51,6 +52,21 @@ export declare function buildRemoteUnlockArgs(names: string[], opts: {
|
|
|
51
52
|
ttl?: string;
|
|
52
53
|
durable?: boolean;
|
|
53
54
|
}): string[];
|
|
55
|
+
/**
|
|
56
|
+
* Build the remote `agents secrets list` argv for `list --host`. Every filter
|
|
57
|
+
* must be forwarded: `browseRemote` sends this argv verbatim, so a flag left out
|
|
58
|
+
* here is not an error — the remote just lists everything, and
|
|
59
|
+
* `secrets list --host zion --expired` reports every bundle on zion as expired.
|
|
60
|
+
* Silent and wrong beats loud and wrong only for the person who wrote the bug.
|
|
61
|
+
*
|
|
62
|
+
* Values pass through unparsed so the REMOTE validates them under its own rules,
|
|
63
|
+
* matching how `--ttl` is forwarded by buildRemoteUnlockArgs.
|
|
64
|
+
*/
|
|
65
|
+
export declare function buildRemoteListArgs(opts: SecretsListFilterOpts & {
|
|
66
|
+
json?: boolean;
|
|
67
|
+
sort?: string;
|
|
68
|
+
limit?: string;
|
|
69
|
+
}, query?: string): string[];
|
|
54
70
|
export { SSH_TARGET_RE, assertValidSshTarget };
|
|
55
71
|
/**
|
|
56
72
|
* Build the child environment for `agents secrets exec`. Strips
|
|
@@ -79,15 +95,47 @@ export declare function exportBundleToFile(env: Record<string, string>, filePath
|
|
|
79
95
|
* Throws on a missing file, an invalid JSON envelope, or a wrong passphrase.
|
|
80
96
|
*/
|
|
81
97
|
export declare function importBundleFromFile(filePath: string, passphrase: string): Record<string, string>;
|
|
82
|
-
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
98
|
+
/** Compact span for a fixed duration: "45m" / "19h" / "2d". Shared by
|
|
99
|
+
* `compactRemaining` (a countdown) and the POLICY column's hold-window
|
|
100
|
+
* annotation (a fixed length) so the two can never round onto different unit
|
|
101
|
+
* thresholds and disagree about the same number of milliseconds. */
|
|
102
|
+
export declare function compactDurationMs(ms: number): string;
|
|
103
|
+
/** The POLICY column for `secrets list`. `hold` is a duration, not a mode — it
|
|
104
|
+
* means "prompt once, then stay silent for this long" — so the column states
|
|
105
|
+
* the window (`hold 7d`) rather than the bare tier name, and appends `· held Nd`
|
|
106
|
+
* while the secrets-agent is actually caching the bundle. `always` and `never`
|
|
107
|
+
* carry no window and gain nothing here. `holdMs` is the configured global hold
|
|
108
|
+
* (`secretsHoldMs()`), passed in rather than read so this stays pure; `held`
|
|
85
109
|
* maps bundle name → expiry epoch-ms (from agentStatus()). */
|
|
86
|
-
export declare function renderPolicyCol(b: SecretsBundle, held?: Map<string, number>): string;
|
|
110
|
+
export declare function renderPolicyCol(b: SecretsBundle, holdMs: number, held?: Map<string, number>): string;
|
|
111
|
+
/** The hold-window line at the top of `secrets status`. Names the `hold` policy
|
|
112
|
+
* the window belongs to — the rename in #1604 left this surface still saying
|
|
113
|
+
* "daily", the one name the CLI no longer accepts in its own help. Pure so the
|
|
114
|
+
* vocabulary is pinned by a test rather than re-drifting on the next rename. */
|
|
115
|
+
export declare function renderHoldSummary(holdStr: string, configured: boolean): string;
|
|
116
|
+
/** The empty-broker line under the hold summary. Named here, beside
|
|
117
|
+
* `renderHoldSummary`, for the same reason: it is the second line the rename
|
|
118
|
+
* left saying `daily`, and a test pins both. */
|
|
119
|
+
export declare const NO_BUNDLES_HELD_LINE = "No bundles held. The next read of each hold-policy bundle will prompt once, then hold.";
|
|
87
120
|
/** Human-readable hold window for `secrets status`. Sub-hour values render in
|
|
88
121
|
* minutes (so a near-floor `holdMs` never shows a confusing "0 hours"), whole
|
|
89
122
|
* hours up to 2 days, whole days beyond. Pure — unit-tested. */
|
|
90
123
|
export declare function formatHoldWindow(ms: number): string;
|
|
124
|
+
/** A broker hold expiry, or null once it has lapsed. One definition of "held",
|
|
125
|
+
* shared by the POLICY column, the `--held` filter, and the JSON payload, so the
|
|
126
|
+
* three can never disagree about the same bundle. */
|
|
127
|
+
export declare function liveHold(expiresAt: number | undefined, now?: number): number | null;
|
|
128
|
+
/**
|
|
129
|
+
* The EXPIRING cell. Counts keys needing attention — already expired plus due
|
|
130
|
+
* within 30 days — and colours by the worst of the two: red once anything has
|
|
131
|
+
* lapsed, yellow while everything is merely upcoming.
|
|
132
|
+
*
|
|
133
|
+
* Expired keys used to be invisible here. `countExpiringSoon` requires
|
|
134
|
+
* `d >= 0`, so a bundle whose token died last month rendered `-`, identical to
|
|
135
|
+
* one with no expiry at all; the only places it surfaced were `secrets view`
|
|
136
|
+
* and a hard abort at inject time, i.e. after it had already broken something.
|
|
137
|
+
*/
|
|
138
|
+
export declare function renderExpiringCol(b: SecretsBundle, now?: number): string;
|
|
91
139
|
/** Register the `agents secrets` command tree. */
|
|
92
140
|
export declare function registerSecretsCommands(program: Command): void;
|
|
93
141
|
/** Validate a prompt-policy value, throwing a clear message on a bad one (the
|