@phnx-labs/agents-cli 1.22.100 → 1.22.102
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 +14 -0
- package/dist/commands/accounts.js +1 -1
- package/dist/commands/exec.js +2 -0
- package/dist/commands/menubar.js +4 -1
- package/dist/commands/ssh.js +12 -4
- package/dist/commands/status.js +3 -1
- package/dist/commands/view.d.ts +0 -2
- package/dist/commands/view.js +9 -28
- package/dist/lib/account-catalog.d.ts +24 -0
- package/dist/lib/account-catalog.js +45 -15
- package/dist/lib/accounting/usage.d.ts +7 -0
- package/dist/lib/accounting/usage.js +25 -0
- package/dist/lib/auth-health.d.ts +17 -4
- package/dist/lib/auth-health.js +60 -22
- package/dist/lib/auto-pull-worker.js +38 -1
- package/dist/lib/devices/harness-inventory.d.ts +4 -0
- package/dist/lib/devices/harness-inventory.js +3 -1
- package/dist/lib/drift-sync.js +5 -2
- package/dist/lib/exec.js +2 -0
- package/dist/lib/feed/pr-status.d.ts +18 -0
- package/dist/lib/feed/pr-status.js +43 -5
- package/dist/lib/feed/watch.d.ts +4 -1
- package/dist/lib/feed/watch.js +57 -25
- package/dist/lib/helper-versions.js +1 -1
- package/dist/lib/menubar/install-menubar.d.ts +29 -0
- package/dist/lib/menubar/install-menubar.js +49 -0
- package/dist/lib/session/active.d.ts +1 -1
- package/dist/lib/session/active.js +7 -0
- package/dist/lib/session/state.d.ts +7 -0
- package/dist/lib/sync-status.d.ts +6 -0
- package/dist/lib/sync-status.js +11 -0
- package/dist/lib/system-run-sync.d.ts +11 -0
- package/dist/lib/system-run-sync.js +114 -0
- package/package.json +1 -1
|
@@ -174,6 +174,13 @@ export function backfillActiveRowsFromMeta(sessions, metaById) {
|
|
|
174
174
|
s.durationMs = m.durationMs;
|
|
175
175
|
if (s.subAgentCount == null && m.subAgentCount != null)
|
|
176
176
|
s.subAgentCount = m.subAgentCount;
|
|
177
|
+
// A pane kept open for days has a start time but no activity signal of its
|
|
178
|
+
// own; the index's last transcript write is what "idle 14d" is read from.
|
|
179
|
+
if (s.lastActivityMs == null && m.lastActivity) {
|
|
180
|
+
const ts = Date.parse(m.lastActivity);
|
|
181
|
+
if (!Number.isNaN(ts))
|
|
182
|
+
s.lastActivityMs = ts;
|
|
183
|
+
}
|
|
177
184
|
}
|
|
178
185
|
}
|
|
179
186
|
function loadBackfillMetaFor(sessions) {
|
|
@@ -56,6 +56,13 @@ export interface StructuredQuestion {
|
|
|
56
56
|
export interface DetectedPr {
|
|
57
57
|
url: string;
|
|
58
58
|
number?: number;
|
|
59
|
+
/** `gh pr view` status, attached by the feed watch when it has fetched it. */
|
|
60
|
+
state?: string;
|
|
61
|
+
isDraft?: boolean;
|
|
62
|
+
reviewDecision?: string;
|
|
63
|
+
mergeable?: string;
|
|
64
|
+
/** The check rollup folded to one verdict. */
|
|
65
|
+
checks?: 'passing' | 'failing' | 'pending';
|
|
59
66
|
}
|
|
60
67
|
export interface DetectedWorktree {
|
|
61
68
|
/** Absolute worktree path (the session cwd). */
|
|
@@ -115,6 +115,12 @@ export interface ResidualDrift {
|
|
|
115
115
|
export declare function verifyVersionConverged(agent: AgentId, version: string, cwd?: string): ResidualDrift | null;
|
|
116
116
|
/** One-line-per-resource description of residual drift, for the sync exit line. */
|
|
117
117
|
export declare function formatResidualDrift(residual: ResidualDrift[]): string[];
|
|
118
|
+
/**
|
|
119
|
+
* The rows behind a "N drifted" count, one line each, for the human renderers.
|
|
120
|
+
* A count alone cannot be acted on; the name says which skill or hook to look
|
|
121
|
+
* at, and `detail` says what differs when the differ knows.
|
|
122
|
+
*/
|
|
123
|
+
export declare function formatDriftRows(v: AgentVersionStatus): string[];
|
|
118
124
|
export interface SyncStatusOptions {
|
|
119
125
|
cwd?: string;
|
|
120
126
|
/** Restrict to specific agent ids; undefined = every supported agent. */
|
package/dist/lib/sync-status.js
CHANGED
|
@@ -54,6 +54,17 @@ export function formatResidualDrift(residual) {
|
|
|
54
54
|
}
|
|
55
55
|
return lines;
|
|
56
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* The rows behind a "N drifted" count, one line each, for the human renderers.
|
|
59
|
+
* A count alone cannot be acted on; the name says which skill or hook to look
|
|
60
|
+
* at, and `detail` says what differs when the differ knows.
|
|
61
|
+
*/
|
|
62
|
+
export function formatDriftRows(v) {
|
|
63
|
+
return v.resources
|
|
64
|
+
.filter((r) => r.status === 'drifted' || r.status === 'missing')
|
|
65
|
+
.sort((a, b) => a.kind.localeCompare(b.kind) || a.name.localeCompare(b.name))
|
|
66
|
+
.map((r) => `${r.status.padEnd(7)} ${r.kind}/${r.name}${r.detail ? ` (${r.detail})` : ''}`);
|
|
67
|
+
}
|
|
57
68
|
const STATUS_MAP = {
|
|
58
69
|
ok: 'synced',
|
|
59
70
|
diff: 'drifted',
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AgentId } from './types.js';
|
|
2
|
+
export interface SystemRunSyncResult {
|
|
3
|
+
/** Names rewritten per kind; empty when the sentinel matched (skip-fast). */
|
|
4
|
+
skills: string[];
|
|
5
|
+
subagents: string[];
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Refresh the system layer's skills and subagents into the version home when
|
|
9
|
+
* their source directories changed since the last run for (agent, version).
|
|
10
|
+
*/
|
|
11
|
+
export declare function applySystemResourcesAtRun(agent: AgentId, version: string, versionHome: string): SystemRunSyncResult;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System-layer skills and subagents refresh at `agents run` launch time.
|
|
3
|
+
*
|
|
4
|
+
* `agents sync <harness>@all system` rewrites every version home, but nothing
|
|
5
|
+
* runs it when the `.system` mirror moves: the shim's `--launch` path compiles
|
|
6
|
+
* project rules and mirrors project resources only, and the SessionStart
|
|
7
|
+
* autosync fires the umbrella at most once per 4 h. Rules already close that
|
|
8
|
+
* gap per run (`rules/run-sync.ts`); skills and subagents did not, so a merged
|
|
9
|
+
* system-layer skill change left 31 of 33 installed copies on the old text
|
|
10
|
+
* (PHNX-4056). This is the same shape as the rules run-sync: a small per-
|
|
11
|
+
* (agent, version) sentinel of source fingerprints, stat-tier comparison, and
|
|
12
|
+
* a write through the registered writers only when a source file changed.
|
|
13
|
+
*
|
|
14
|
+
* Scope: the system layer's `skills/` and `subagents/` directories. The
|
|
15
|
+
* writers resolve each name through the normal precedence (a user-layer
|
|
16
|
+
* shadow still wins), and the active resource profile filters both kinds the
|
|
17
|
+
* same way `syncResourcesToVersion` does. Never blocks a launch: any failure
|
|
18
|
+
* is swallowed and leaves the sentinel stale, so the next run retries.
|
|
19
|
+
*/
|
|
20
|
+
import * as fs from 'fs';
|
|
21
|
+
import * as path from 'path';
|
|
22
|
+
import { getCacheDir, getSystemSkillsDir, getSystemSubagentsDir } from './state.js';
|
|
23
|
+
import { getWriter } from './staleness/registry.js';
|
|
24
|
+
import { fingerprintDir, isDirStale } from './staleness/fingerprint.js';
|
|
25
|
+
import { filterNamesForActiveResourceProfile } from './resource-profiles.js';
|
|
26
|
+
/** ~/.agents/.cache/system-run-sync/ — regenerable; a lost sentinel costs one extra write. */
|
|
27
|
+
function sentinelPath(agent, version) {
|
|
28
|
+
const key = `${agent}@${version}`.replace(/[^a-zA-Z0-9@._-]/g, '_');
|
|
29
|
+
return path.join(getCacheDir(), 'system-run-sync', `${key}.json`);
|
|
30
|
+
}
|
|
31
|
+
function loadSentinel(agent, version) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(fs.readFileSync(sentinelPath(agent, version), 'utf-8'));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return {};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function saveSentinel(agent, version, sentinel) {
|
|
40
|
+
const p = sentinelPath(agent, version);
|
|
41
|
+
try {
|
|
42
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
43
|
+
fs.writeFileSync(p, JSON.stringify(sentinel));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
// Best-effort — a failed write just means the next run redoes the copy.
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Subdirectories of `dir` that carry `marker` (SKILL.md / AGENT.md). */
|
|
50
|
+
function namesWithMarker(dir, marker) {
|
|
51
|
+
const out = new Map();
|
|
52
|
+
let entries;
|
|
53
|
+
try {
|
|
54
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
for (const e of entries) {
|
|
60
|
+
if (!e.isDirectory() || e.name.startsWith('.'))
|
|
61
|
+
continue;
|
|
62
|
+
const src = path.join(dir, e.name, marker);
|
|
63
|
+
if (fs.existsSync(src))
|
|
64
|
+
out.set(e.name, src);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Refresh the system layer's skills and subagents into the version home when
|
|
70
|
+
* their source directories changed since the last run for (agent, version).
|
|
71
|
+
*/
|
|
72
|
+
export function applySystemResourcesAtRun(agent, version, versionHome) {
|
|
73
|
+
const result = { skills: [], subagents: [] };
|
|
74
|
+
const stored = loadSentinel(agent, version);
|
|
75
|
+
const next = { ...stored };
|
|
76
|
+
const kinds = [
|
|
77
|
+
{ kind: 'skills', dir: getSystemSkillsDir(), marker: 'SKILL.md' },
|
|
78
|
+
{ kind: 'subagents', dir: getSystemSubagentsDir(), marker: 'AGENT.md' },
|
|
79
|
+
];
|
|
80
|
+
for (const { kind, dir, marker } of kinds) {
|
|
81
|
+
if (!fs.existsSync(dir))
|
|
82
|
+
continue;
|
|
83
|
+
const prev = stored[kind];
|
|
84
|
+
if (prev && prev.dir === dir && !isDirStale(prev.dir, prev.files, dir))
|
|
85
|
+
continue;
|
|
86
|
+
const writer = getWriter(kind, agent);
|
|
87
|
+
if (!writer)
|
|
88
|
+
continue;
|
|
89
|
+
const sources = namesWithMarker(dir, marker);
|
|
90
|
+
// The active resource profile is the per-client scoping seam (a brand pins
|
|
91
|
+
// one); it filters every kind here exactly as `syncResourcesToVersion` does.
|
|
92
|
+
const names = filterNamesForActiveResourceProfile(kind, Array.from(sources.keys()), sources);
|
|
93
|
+
if (names.length === 0) {
|
|
94
|
+
next[kind] = { dir, files: fingerprintDir(dir) };
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
let written;
|
|
98
|
+
try {
|
|
99
|
+
written = writer.write({ version, versionHome, selection: names, cwd: '' });
|
|
100
|
+
}
|
|
101
|
+
catch {
|
|
102
|
+
continue; // leave the sentinel stale so the next run retries
|
|
103
|
+
}
|
|
104
|
+
result[kind] = written.synced;
|
|
105
|
+
// A per-name failure (an AGENT.md that does not parse) also leaves the
|
|
106
|
+
// sentinel stale: the next run retries instead of never seeing it again.
|
|
107
|
+
if (written.errors?.length)
|
|
108
|
+
continue;
|
|
109
|
+
next[kind] = { dir, files: fingerprintDir(dir) };
|
|
110
|
+
}
|
|
111
|
+
if (JSON.stringify(next) !== JSON.stringify(stored))
|
|
112
|
+
saveSentinel(agent, version, next);
|
|
113
|
+
return result;
|
|
114
|
+
}
|
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.102",
|
|
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",
|