@phnx-labs/agents-cli 1.22.22 → 1.22.23
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 +209 -0
- package/README.md +8 -2
- package/dist/commands/doctor.js +15 -7
- package/dist/commands/exec.js +20 -6
- package/dist/commands/focus.d.ts +76 -4
- package/dist/commands/focus.js +219 -40
- package/dist/commands/fork.d.ts +20 -2
- package/dist/commands/fork.js +91 -64
- package/dist/commands/go.d.ts +25 -0
- package/dist/commands/go.js +63 -2
- package/dist/commands/harness-wizard.d.ts +206 -0
- package/dist/commands/harness-wizard.js +403 -0
- package/dist/commands/harness.d.ts +12 -0
- package/dist/commands/harness.js +97 -101
- package/dist/commands/resume.js +10 -3
- package/dist/commands/secrets.js +25 -30
- package/dist/commands/sessions-resume.d.ts +21 -3
- package/dist/commands/sessions-resume.js +50 -11
- package/dist/commands/sessions.d.ts +81 -5
- package/dist/commands/sessions.js +325 -66
- package/dist/commands/watchdog.js +13 -2
- package/dist/lib/agents.d.ts +1 -1
- package/dist/lib/agents.js +132 -0
- package/dist/lib/codex-policy.d.ts +17 -0
- package/dist/lib/codex-policy.js +48 -0
- package/dist/lib/crabbox/lease.d.ts +25 -0
- package/dist/lib/crabbox/lease.js +62 -0
- package/dist/lib/daemon.js +70 -0
- package/dist/lib/exec.d.ts +4 -0
- package/dist/lib/exec.js +88 -54
- package/dist/lib/feed-broadcast.d.ts +1 -20
- package/dist/lib/feed-broadcast.js +31 -1
- package/dist/lib/hooks.js +12 -2
- package/dist/lib/mcp.js +44 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Info.plist +1 -5
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/_CodeSignature/CodeResources +2 -15
- package/dist/lib/models.d.ts +0 -5
- package/dist/lib/models.js +48 -0
- package/dist/lib/plugin-marketplace.js +9 -0
- package/dist/lib/pricing/prices.json +119 -92
- package/dist/lib/pricing/table.js +13 -0
- package/dist/lib/remote-agents-json.d.ts +29 -1
- package/dist/lib/remote-agents-json.js +47 -10
- package/dist/lib/resources/mcp.js +2 -0
- package/dist/lib/resources/permissions.js +3 -0
- package/dist/lib/resources/types.d.ts +2 -1
- package/dist/lib/runner.js +28 -19
- package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Info.plist +0 -2
- package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/_CodeSignature/CodeResources +1 -13
- package/dist/lib/secrets/index.d.ts +15 -1
- package/dist/lib/secrets/index.js +118 -49
- package/dist/lib/secrets/reaper.d.ts +87 -0
- package/dist/lib/secrets/reaper.js +184 -0
- package/dist/lib/secrets/remote.d.ts +29 -0
- package/dist/lib/secrets/remote.js +37 -1
- package/dist/lib/session/active.d.ts +36 -1
- package/dist/lib/session/active.js +60 -19
- package/dist/lib/session/actor-sidecar.d.ts +14 -0
- package/dist/lib/session/actor-sidecar.js +67 -4
- package/dist/lib/session/db.d.ts +1 -1
- package/dist/lib/session/db.js +32 -1
- package/dist/lib/session/discover.js +168 -0
- package/dist/lib/session/parse.d.ts +10 -0
- package/dist/lib/session/parse.js +98 -0
- package/dist/lib/session/remote-list.d.ts +10 -1
- package/dist/lib/session/remote-list.js +2 -8
- package/dist/lib/session/remote.d.ts +57 -3
- package/dist/lib/session/remote.js +90 -26
- package/dist/lib/session/resume-command.d.ts +6 -0
- package/dist/lib/session/resume-command.js +8 -0
- package/dist/lib/session/session-cache.d.ts +173 -0
- package/dist/lib/session/session-cache.js +399 -0
- package/dist/lib/session/types.d.ts +1 -1
- package/dist/lib/session/types.js +1 -1
- package/dist/lib/session/width.d.ts +1 -1
- package/dist/lib/session/width.js +12 -2
- package/dist/lib/shims.d.ts +2 -2
- package/dist/lib/shims.js +40 -5
- package/dist/lib/staleness/writers/hooks.js +1 -1
- package/dist/lib/types.d.ts +1 -1
- package/dist/lib/usage.d.ts +13 -0
- package/dist/lib/usage.js +215 -0
- package/dist/lib/versions.js +13 -2
- package/package.json +1 -1
- package/dist/bin/agents +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/Resources/AppIcon.icns +0 -0
- package/dist/lib/secrets/Agents CLI.app/Contents/Resources/AppIcon.icns +0 -0
package/dist/lib/usage.js
CHANGED
|
@@ -139,6 +139,7 @@ const USAGE_SOURCES = {
|
|
|
139
139
|
grok: { fetch: getGrokUsageInfo, network: false },
|
|
140
140
|
cursor: { fetch: getCursorUsageInfo, network: true },
|
|
141
141
|
antigravity: { fetch: getAntigravityUsageInfo, network: true },
|
|
142
|
+
muse: { fetch: getMuseUsageInfo, network: true },
|
|
142
143
|
};
|
|
143
144
|
export const USAGE_SOURCE_AGENT_IDS = Object.keys(USAGE_SOURCES);
|
|
144
145
|
function getUsageSource(agentId) {
|
|
@@ -1873,6 +1874,220 @@ async function getGrokUsageInfo(options) {
|
|
|
1873
1874
|
return { snapshot: null, error: null };
|
|
1874
1875
|
}
|
|
1875
1876
|
}
|
|
1877
|
+
/**
|
|
1878
|
+
* Muse Code usage.
|
|
1879
|
+
*
|
|
1880
|
+
* Prefer live Meta Model API rate-limit headers when a key is available
|
|
1881
|
+
* (META_API_KEY / MODEL_API_KEY / ~/.config/muse/auth.json). Fall back to
|
|
1882
|
+
* aggregating `model_completed.usage` from local session.jsonl logs under
|
|
1883
|
+
* ~/.local/share/muse/sessions for a last-7-days token window.
|
|
1884
|
+
*/
|
|
1885
|
+
async function getMuseUsageInfo(options) {
|
|
1886
|
+
try {
|
|
1887
|
+
const base = options?.home || os.homedir();
|
|
1888
|
+
const live = await probeMuseRateLimits(base);
|
|
1889
|
+
if (live)
|
|
1890
|
+
return { snapshot: live, error: null };
|
|
1891
|
+
const local = await readMuseLocalSessionUsage(base);
|
|
1892
|
+
if (!local)
|
|
1893
|
+
return { snapshot: null, error: null };
|
|
1894
|
+
return { snapshot: local, error: null };
|
|
1895
|
+
}
|
|
1896
|
+
catch {
|
|
1897
|
+
return { snapshot: null, error: null };
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
/** Resolve a Muse API key from env or auth.json without logging the value. */
|
|
1901
|
+
function resolveMuseApiKey(base) {
|
|
1902
|
+
const envKey = process.env.META_API_KEY?.trim() || process.env.MODEL_API_KEY?.trim();
|
|
1903
|
+
if (envKey)
|
|
1904
|
+
return envKey;
|
|
1905
|
+
const authPath = path.join(base, '.config', 'muse', 'auth.json');
|
|
1906
|
+
try {
|
|
1907
|
+
if (!fs.existsSync(authPath))
|
|
1908
|
+
return null;
|
|
1909
|
+
const data = JSON.parse(fs.readFileSync(authPath, 'utf-8'));
|
|
1910
|
+
if (typeof data.access_token === 'string' && data.access_token)
|
|
1911
|
+
return data.access_token;
|
|
1912
|
+
if (typeof data.api_key === 'string' && data.api_key)
|
|
1913
|
+
return data.api_key;
|
|
1914
|
+
for (const slot of Object.values(data)) {
|
|
1915
|
+
if (!slot || typeof slot !== 'object' || Array.isArray(slot))
|
|
1916
|
+
continue;
|
|
1917
|
+
const entry = slot;
|
|
1918
|
+
if (typeof entry.access_token === 'string' && entry.access_token)
|
|
1919
|
+
return entry.access_token;
|
|
1920
|
+
if (typeof entry.api_key === 'string' && entry.api_key)
|
|
1921
|
+
return entry.api_key;
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
catch {
|
|
1925
|
+
/* unreadable auth */
|
|
1926
|
+
}
|
|
1927
|
+
return null;
|
|
1928
|
+
}
|
|
1929
|
+
/**
|
|
1930
|
+
* Probe Meta Model API for rate-limit headers. Uses GET /v1/models (no token
|
|
1931
|
+
* spend). Returns null when unauthenticated or the headers are absent.
|
|
1932
|
+
*/
|
|
1933
|
+
async function probeMuseRateLimits(base) {
|
|
1934
|
+
if (usageRateLimitedUntil('muse'))
|
|
1935
|
+
return null;
|
|
1936
|
+
const key = resolveMuseApiKey(base);
|
|
1937
|
+
if (!key)
|
|
1938
|
+
return null;
|
|
1939
|
+
try {
|
|
1940
|
+
const response = await fetch('https://api.meta.ai/v1/models', {
|
|
1941
|
+
headers: { Authorization: `Bearer ${key}` },
|
|
1942
|
+
signal: AbortSignal.timeout(8_000),
|
|
1943
|
+
});
|
|
1944
|
+
if (response.status === 429) {
|
|
1945
|
+
noteUsageRateLimited('muse', response.headers.get('retry-after'));
|
|
1946
|
+
return null;
|
|
1947
|
+
}
|
|
1948
|
+
if (!response.ok)
|
|
1949
|
+
return null;
|
|
1950
|
+
const limitTokens = headerNumber(response.headers, 'x-ratelimit-limit-tokens');
|
|
1951
|
+
const remainingTokens = headerNumber(response.headers, 'x-ratelimit-remaining-tokens');
|
|
1952
|
+
const limitRequests = headerNumber(response.headers, 'x-ratelimit-limit-requests');
|
|
1953
|
+
const remainingRequests = headerNumber(response.headers, 'x-ratelimit-remaining-requests');
|
|
1954
|
+
const windows = [];
|
|
1955
|
+
if (limitTokens !== null && remainingTokens !== null && limitTokens > 0) {
|
|
1956
|
+
const used = Math.max(0, Math.min(100, ((limitTokens - remainingTokens) / limitTokens) * 100));
|
|
1957
|
+
windows.push({
|
|
1958
|
+
key: 'session',
|
|
1959
|
+
label: 'Tokens (current window)',
|
|
1960
|
+
shortLabel: 'Tok',
|
|
1961
|
+
usedPercent: used,
|
|
1962
|
+
resetsAt: null,
|
|
1963
|
+
windowMinutes: 1,
|
|
1964
|
+
});
|
|
1965
|
+
}
|
|
1966
|
+
if (limitRequests !== null && remainingRequests !== null && limitRequests > 0) {
|
|
1967
|
+
const used = Math.max(0, Math.min(100, ((limitRequests - remainingRequests) / limitRequests) * 100));
|
|
1968
|
+
windows.push({
|
|
1969
|
+
key: 'session',
|
|
1970
|
+
label: 'Requests (current window)',
|
|
1971
|
+
shortLabel: 'Req',
|
|
1972
|
+
usedPercent: used,
|
|
1973
|
+
resetsAt: null,
|
|
1974
|
+
windowMinutes: 1,
|
|
1975
|
+
});
|
|
1976
|
+
}
|
|
1977
|
+
if (windows.length === 0)
|
|
1978
|
+
return null;
|
|
1979
|
+
return {
|
|
1980
|
+
source: 'live',
|
|
1981
|
+
sourceLabel: 'Meta Model API rate limits',
|
|
1982
|
+
capturedAt: new Date(),
|
|
1983
|
+
windows,
|
|
1984
|
+
plan: 'Meta Model API',
|
|
1985
|
+
};
|
|
1986
|
+
}
|
|
1987
|
+
catch {
|
|
1988
|
+
return null;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
function headerNumber(headers, name) {
|
|
1992
|
+
const raw = headers.get(name);
|
|
1993
|
+
if (raw === null || raw === '')
|
|
1994
|
+
return null;
|
|
1995
|
+
const n = Number(raw);
|
|
1996
|
+
return Number.isFinite(n) ? n : null;
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Aggregate Muse session token usage from local session.jsonl files for the
|
|
2000
|
+
* last 7 days. Scales the bar against 10M tokens (soft visibility scale — Meta
|
|
2001
|
+
* is pay-as-you-go with no hard local cap).
|
|
2002
|
+
*/
|
|
2003
|
+
async function readMuseLocalSessionUsage(base) {
|
|
2004
|
+
const root = path.join(base, '.local', 'share', 'muse', 'sessions');
|
|
2005
|
+
if (!fs.existsSync(root))
|
|
2006
|
+
return null;
|
|
2007
|
+
const cutoff = Date.now() - 7 * 24 * 60 * 60 * 1000;
|
|
2008
|
+
let inputTokens = 0;
|
|
2009
|
+
let outputTokens = 0;
|
|
2010
|
+
let cachedTokens = 0;
|
|
2011
|
+
let latestAt = null;
|
|
2012
|
+
let files = 0;
|
|
2013
|
+
const walk = (dir) => {
|
|
2014
|
+
let entries;
|
|
2015
|
+
try {
|
|
2016
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
2017
|
+
}
|
|
2018
|
+
catch {
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
for (const ent of entries) {
|
|
2022
|
+
const full = path.join(dir, ent.name);
|
|
2023
|
+
if (ent.isDirectory()) {
|
|
2024
|
+
walk(full);
|
|
2025
|
+
continue;
|
|
2026
|
+
}
|
|
2027
|
+
if (ent.name !== 'session.jsonl')
|
|
2028
|
+
continue;
|
|
2029
|
+
try {
|
|
2030
|
+
const st = fs.statSync(full);
|
|
2031
|
+
if (st.mtimeMs < cutoff)
|
|
2032
|
+
continue;
|
|
2033
|
+
files++;
|
|
2034
|
+
if (!latestAt || st.mtime > latestAt)
|
|
2035
|
+
latestAt = st.mtime;
|
|
2036
|
+
const content = fs.readFileSync(full, 'utf-8');
|
|
2037
|
+
for (const line of content.split('\n')) {
|
|
2038
|
+
if (!line.trim())
|
|
2039
|
+
continue;
|
|
2040
|
+
let raw;
|
|
2041
|
+
try {
|
|
2042
|
+
raw = JSON.parse(line);
|
|
2043
|
+
}
|
|
2044
|
+
catch {
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
2047
|
+
const event = raw?.payload?.event ?? raw?.payload;
|
|
2048
|
+
if (!event || event.kind !== 'model_completed')
|
|
2049
|
+
continue;
|
|
2050
|
+
const usage = event.usage;
|
|
2051
|
+
if (!usage || typeof usage !== 'object')
|
|
2052
|
+
continue;
|
|
2053
|
+
if (typeof usage.input_tokens === 'number')
|
|
2054
|
+
inputTokens += usage.input_tokens;
|
|
2055
|
+
if (typeof usage.output_tokens === 'number')
|
|
2056
|
+
outputTokens += usage.output_tokens;
|
|
2057
|
+
if (typeof usage.cached_tokens === 'number')
|
|
2058
|
+
cachedTokens += usage.cached_tokens;
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
catch {
|
|
2062
|
+
/* skip unreadable session */
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
};
|
|
2066
|
+
walk(root);
|
|
2067
|
+
const total = inputTokens + outputTokens + cachedTokens;
|
|
2068
|
+
if (total === 0 && files === 0)
|
|
2069
|
+
return null;
|
|
2070
|
+
// Soft 10M-token scale for the bar (pay-as-you-go has no hard local cap).
|
|
2071
|
+
const softCap = 10_000_000;
|
|
2072
|
+
const usedPercent = Math.max(0, Math.min(100, (total / softCap) * 100));
|
|
2073
|
+
const formatK = (n) => n >= 1_000_000 ? `${(n / 1_000_000).toFixed(1)}M` : n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
|
|
2074
|
+
return {
|
|
2075
|
+
source: 'last_seen',
|
|
2076
|
+
sourceLabel: `local Muse sessions · ${formatK(total)} tokens (7d)`,
|
|
2077
|
+
capturedAt: latestAt,
|
|
2078
|
+
windows: [
|
|
2079
|
+
{
|
|
2080
|
+
key: 'week',
|
|
2081
|
+
label: 'Local tokens (7d)',
|
|
2082
|
+
shortLabel: '7d',
|
|
2083
|
+
usedPercent,
|
|
2084
|
+
resetsAt: null,
|
|
2085
|
+
windowMinutes: 7 * 24 * 60,
|
|
2086
|
+
},
|
|
2087
|
+
],
|
|
2088
|
+
plan: 'Meta Model API',
|
|
2089
|
+
};
|
|
2090
|
+
}
|
|
1876
2091
|
async function readLatestGrokBilling(filePath) {
|
|
1877
2092
|
return new Promise((resolve) => {
|
|
1878
2093
|
let latest = null;
|
package/dist/lib/versions.js
CHANGED
|
@@ -917,6 +917,17 @@ export function getBinaryPath(agent, version) {
|
|
|
917
917
|
? path.join(getHomeDir(), 'bin', 'droid.exe')
|
|
918
918
|
: path.join(getHomeDir(), '.local', 'bin', 'droid');
|
|
919
919
|
}
|
|
920
|
+
if (agent === 'muse') {
|
|
921
|
+
// Muse Code install script drops a self-updating launcher at
|
|
922
|
+
// ~/.local/bin/muse (curl -fsSL https://dev.meta.ai/install.sh | sh).
|
|
923
|
+
// Same global-binary shape as droid: one binary for every version dir,
|
|
924
|
+
// config isolation via version-home HOME rewrite. Mirror the shim's
|
|
925
|
+
// `muse` branch so isVersionInstalled / agents view / agents import
|
|
926
|
+
// agree with what executes.
|
|
927
|
+
return IS_WINDOWS
|
|
928
|
+
? path.join(getHomeDir(), 'bin', 'muse.exe')
|
|
929
|
+
: path.join(getHomeDir(), '.local', 'bin', 'muse');
|
|
930
|
+
}
|
|
920
931
|
const versionDir = getVersionDir(agent, version);
|
|
921
932
|
return path.join(versionDir, 'node_modules', '.bin', agentConfig.cliCommand);
|
|
922
933
|
}
|
|
@@ -1521,14 +1532,14 @@ export async function installVersion(agent, version, onProgress, opts) {
|
|
|
1521
1532
|
// ~/.local/bin (or similar) rather than the version's node_modules/.bin.
|
|
1522
1533
|
//
|
|
1523
1534
|
// Agents whose binary is special-cased in getBinaryPath (grok ->
|
|
1524
|
-
// ~/.grok/downloads, droid -> ~/.local/bin
|
|
1535
|
+
// ~/.grok/downloads, droid/muse -> ~/.local/bin/<cli>) need no symlink — and
|
|
1525
1536
|
// creating one is actively harmful: `which <cli>` can resolve to OUR OWN
|
|
1526
1537
|
// dispatcher shim, because ~/.agents/.cache/shims sits ahead of ~/.local/bin
|
|
1527
1538
|
// on PATH. Symlinking node_modules/.bin/<cli> at the shim makes the shim
|
|
1528
1539
|
// exec itself forever. So we skip the resolver-backed agents here AND, for
|
|
1529
1540
|
// everyone else, filter the shims dir out of the `which` candidates so the
|
|
1530
1541
|
// same race can't bite a non-special-cased installScript agent.
|
|
1531
|
-
if (agent !== 'grok' && agent !== 'droid') {
|
|
1542
|
+
if (agent !== 'grok' && agent !== 'droid' && agent !== 'muse') {
|
|
1532
1543
|
// findInPath is a pure-Node PATH scan that already skips our own shims
|
|
1533
1544
|
// dir — so it returns the genuine install, never our dispatcher shim
|
|
1534
1545
|
// (which sits ahead of ~/.local/bin on PATH and would otherwise be
|
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.23",
|
|
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",
|
package/dist/bin/agents
DELETED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|