@phnx-labs/agents-cli 1.22.69 → 1.22.70
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 +16 -0
- package/README.md +3 -8
- package/dist/commands/accounts.js +23 -7
- package/dist/commands/exec.js +2 -2
- package/dist/commands/import.js +2 -2
- package/dist/commands/models.js +2 -2
- package/dist/commands/permissions.js +2 -2
- package/dist/commands/rules.js +1 -1
- package/dist/commands/send.js +9 -3
- package/dist/commands/traces.js +1 -1
- package/dist/lib/account-capabilities.js +0 -2
- package/dist/lib/account-registry.d.ts +3 -3
- package/dist/lib/account-registry.js +25 -7
- package/dist/lib/acp/client.d.ts +1 -1
- package/dist/lib/acp/client.js +12 -1
- package/dist/lib/acp/harnesses.js +1 -1
- package/dist/lib/add-dir.js +0 -2
- package/dist/lib/agent-cli-commands.js +0 -2
- package/dist/lib/agent-spec/agents.d.ts +1 -1
- package/dist/lib/agent-spec/agents.js +2 -83
- package/dist/lib/browser/ipc.js +9 -1
- package/dist/lib/browser/remote-control.d.ts +6 -3
- package/dist/lib/browser/remote-control.js +6 -3
- package/dist/lib/browser/service.d.ts +4 -1
- package/dist/lib/browser/service.js +7 -1
- package/dist/lib/channels/registry.d.ts +6 -0
- package/dist/lib/channels/send.d.ts +11 -2
- package/dist/lib/channels/send.js +11 -2
- package/dist/lib/cloud/rush.d.ts +10 -2
- package/dist/lib/cloud/rush.js +15 -9
- package/dist/lib/daemon/daemon.js +28 -8
- package/dist/lib/daemon/runner.js +6 -2
- package/dist/lib/exec.d.ts +2 -2
- package/dist/lib/exec.js +3 -34
- package/dist/lib/feed-broadcast.d.ts +12 -29
- package/dist/lib/feed-broadcast.js +28 -27
- package/dist/lib/hooks/install.js +0 -87
- package/dist/lib/installations/strategies.js +1 -1
- package/dist/lib/mcp-registry.js +0 -13
- package/dist/lib/mcp.js +2 -2
- package/dist/lib/model-tiers.js +1 -1
- package/dist/lib/models.js +0 -63
- package/dist/lib/notify.d.ts +11 -0
- package/dist/lib/notify.js +17 -4
- package/dist/lib/owner-message.d.ts +46 -3
- package/dist/lib/owner-message.js +26 -6
- package/dist/lib/permissions-registry.d.ts +0 -2
- package/dist/lib/permissions-registry.js +3 -50
- package/dist/lib/permissions.d.ts +3 -17
- package/dist/lib/permissions.js +4 -73
- package/dist/lib/rush-session.d.ts +19 -0
- package/dist/lib/rush-session.js +24 -0
- package/dist/lib/secrets/drivers/rush.js +2 -1
- package/dist/lib/session/cloud.js +2 -1
- package/dist/lib/sink-format.d.ts +34 -0
- package/dist/lib/sink-format.js +17 -0
- package/dist/lib/staleness/detectors/permissions.js +0 -20
- package/dist/lib/staleness/writers/commands.js +1 -1
- package/dist/lib/staleness/writers/hooks.js +2 -2
- package/dist/lib/subagents-registry.js +2 -12
- package/dist/lib/subagents.d.ts +0 -10
- package/dist/lib/subagents.js +0 -37
- package/dist/lib/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -13,6 +13,7 @@ import * as fs from 'fs';
|
|
|
13
13
|
import * as os from 'os';
|
|
14
14
|
import * as path from 'path';
|
|
15
15
|
import * as yaml from 'yaml';
|
|
16
|
+
import { isRushSessionExpired } from '../../rush-session.js';
|
|
16
17
|
const PROXY_BASE = 'https://api.prix.dev';
|
|
17
18
|
const USER_YAML = path.join(os.homedir(), '.rush', 'user.yaml');
|
|
18
19
|
const BUNDLE_ENDPOINT = '/api/v1/secrets/bundles';
|
|
@@ -27,7 +28,7 @@ function readRushToken() {
|
|
|
27
28
|
throw new Error('No session token in ~/.rush/user.yaml. Run `rush login` first.');
|
|
28
29
|
}
|
|
29
30
|
const expiresAt = data.session?.expires_at;
|
|
30
|
-
if (
|
|
31
|
+
if (isRushSessionExpired(expiresAt)) {
|
|
31
32
|
const expiredAt = new Date(expiresAt * 1000).toISOString();
|
|
32
33
|
throw new Error(`Rush session expired at ${expiredAt}. Run \`rush login\` to refresh.`);
|
|
33
34
|
}
|
|
@@ -15,6 +15,7 @@ import * as os from 'os';
|
|
|
15
15
|
import * as yaml from 'yaml';
|
|
16
16
|
import { deriveShortId } from '../text/short-id.js';
|
|
17
17
|
import { getCacheDir } from '../state.js';
|
|
18
|
+
import { isRushSessionExpired } from '../rush-session.js';
|
|
18
19
|
const PROXY_BASE = process.env.RUSH_PROXY_BASE ?? 'https://api.prix.dev';
|
|
19
20
|
const USER_YAML = path.join(os.homedir(), '.rush', 'user.yaml');
|
|
20
21
|
const CLOUD_CACHE_DIR = path.join(getCacheDir(), 'cloud-runs');
|
|
@@ -30,7 +31,7 @@ function readToken() {
|
|
|
30
31
|
throw new Error('No session token in ~/.rush/user.yaml. Run `rush login` first.');
|
|
31
32
|
}
|
|
32
33
|
const expiresAt = data.session?.expires_at;
|
|
33
|
-
if (
|
|
34
|
+
if (isRushSessionExpired(expiresAt)) {
|
|
34
35
|
const expiredAt = new Date(expiresAt * 1000).toISOString();
|
|
35
36
|
throw new Error(`Rush session expired at ${expiredAt}. Run \`rush login\` to refresh.`);
|
|
36
37
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How loudly a destination can render a link — the one decision that shapes the
|
|
3
|
+
* shared owner/broadcast `{message}` per channel (PHNX-3698).
|
|
4
|
+
*
|
|
5
|
+
* - `mrkdwn` — Slack, which renders `<url|label>` as blue tappable text. The
|
|
6
|
+
* session crumb and every ticket key the prose NAMES become inline labeled
|
|
7
|
+
* links, so nothing rides a trailing naked-URL line.
|
|
8
|
+
* - `plain` — iMessage, the owner-scoped rush message, a spawned `command:`
|
|
9
|
+
* sink, desktop banners: none can render a labeled link and a dumped naked
|
|
10
|
+
* URL reads as noise, so the message stays the human sentence with no URLs.
|
|
11
|
+
*
|
|
12
|
+
* The default is `plain`; only Slack opts into `mrkdwn`.
|
|
13
|
+
*
|
|
14
|
+
* This lives in its own tiny module because both the feed broadcast fan-out
|
|
15
|
+
* (`feed-broadcast.ts`) and the owner delivery fan-out (`notify.ts`) key on it,
|
|
16
|
+
* and those two modules already import each other — a shared symbol here keeps
|
|
17
|
+
* the format decision a single source of truth without a circular import.
|
|
18
|
+
*/
|
|
19
|
+
export type SinkMessageFormat = 'plain' | 'mrkdwn';
|
|
20
|
+
/**
|
|
21
|
+
* Only Slack renders `<url|label>`, so it is the one format that gets labeled
|
|
22
|
+
* links. iMessage / owner-scoped rush / command / desktop sinks stay `plain`
|
|
23
|
+
* (they can't turn `claude/6fc1db18` blue, and dumping the raw URL is worse than
|
|
24
|
+
* leaving the crumb unlinked — PHNX-3698).
|
|
25
|
+
*
|
|
26
|
+
* The argument is the **resolved provider name**, not a sink's declared channel:
|
|
27
|
+
* an operator can point an arbitrary channel name at the Slack provider through
|
|
28
|
+
* `notify.transports` (e.g. `eng-alerts -> slack`), and delivery keys off that
|
|
29
|
+
* resolved provider (`lookupTransport`), so the format decision must too —
|
|
30
|
+
* otherwise an aliased Slack sink would compose plain while delivering to Slack,
|
|
31
|
+
* or a name remapped AWAY from Slack would emit `<url|label>` markup a non-Slack
|
|
32
|
+
* transport shows literally.
|
|
33
|
+
*/
|
|
34
|
+
export declare function sinkMessageFormat(provider: string | undefined): SinkMessageFormat;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Only Slack renders `<url|label>`, so it is the one format that gets labeled
|
|
3
|
+
* links. iMessage / owner-scoped rush / command / desktop sinks stay `plain`
|
|
4
|
+
* (they can't turn `claude/6fc1db18` blue, and dumping the raw URL is worse than
|
|
5
|
+
* leaving the crumb unlinked — PHNX-3698).
|
|
6
|
+
*
|
|
7
|
+
* The argument is the **resolved provider name**, not a sink's declared channel:
|
|
8
|
+
* an operator can point an arbitrary channel name at the Slack provider through
|
|
9
|
+
* `notify.transports` (e.g. `eng-alerts -> slack`), and delivery keys off that
|
|
10
|
+
* resolved provider (`lookupTransport`), so the format decision must too —
|
|
11
|
+
* otherwise an aliased Slack sink would compose plain while delivering to Slack,
|
|
12
|
+
* or a name remapped AWAY from Slack would emit `<url|label>` markup a non-Slack
|
|
13
|
+
* transport shows literally.
|
|
14
|
+
*/
|
|
15
|
+
export function sinkMessageFormat(provider) {
|
|
16
|
+
return provider?.trim().toLowerCase() === 'slack' ? 'mrkdwn' : 'plain';
|
|
17
|
+
}
|
|
@@ -202,25 +202,6 @@ function buildDroidDetector() {
|
|
|
202
202
|
},
|
|
203
203
|
};
|
|
204
204
|
}
|
|
205
|
-
function buildKiroDetector() {
|
|
206
|
-
return {
|
|
207
|
-
kind: 'permissions',
|
|
208
|
-
agent: 'kiro',
|
|
209
|
-
list({ versionHome }) {
|
|
210
|
-
const permissionsPath = path.join(versionHome, '.kiro', 'settings', 'permissions.yaml');
|
|
211
|
-
if (!fs.existsSync(permissionsPath))
|
|
212
|
-
return [];
|
|
213
|
-
try {
|
|
214
|
-
const config = yaml.parse(fs.readFileSync(permissionsPath, 'utf-8'));
|
|
215
|
-
if (config && Array.isArray(config.rules) && config.rules.length > 0) {
|
|
216
|
-
return discoverPermissionGroups().map(g => g.name);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
catch { /* parse fail */ }
|
|
220
|
-
return [];
|
|
221
|
-
},
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
205
|
function buildOpenClawDetector() {
|
|
225
206
|
return {
|
|
226
207
|
kind: 'permissions',
|
|
@@ -296,7 +277,6 @@ const handlers = {
|
|
|
296
277
|
kimi: buildKimiDetector,
|
|
297
278
|
cursor: buildCursorDetector,
|
|
298
279
|
droid: buildDroidDetector,
|
|
299
|
-
kiro: buildKiroDetector,
|
|
300
280
|
openclaw: buildOpenClawDetector,
|
|
301
281
|
copilot: buildCopilotDetector,
|
|
302
282
|
hermes: buildHermesDetector,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* - native command file — `{agentDir}/<commandsSubdir>/<name>.md` (or .toml
|
|
15
15
|
* when the agent's format is toml). Standard path for Claude, Codex
|
|
16
|
-
* < 0.117.0, Cursor, OpenCode, Copilot, Amp,
|
|
16
|
+
* < 0.117.0, Cursor, OpenCode, Copilot, Amp, Roo, Antigravity.
|
|
17
17
|
*
|
|
18
18
|
* Source resolution is `resolveCommandSource` (user → system → extras —
|
|
19
19
|
* project layer intentionally excluded).
|
|
@@ -90,9 +90,9 @@ function buildHooksWriter(agent) {
|
|
|
90
90
|
// so subrule-bundled guards (absolute paths outside the central hooks/
|
|
91
91
|
// copy set) get registered into ~/.grok/hooks/hooks.json via
|
|
92
92
|
// registerHooksForGrok — file copy alone only sees top-level available.hooks
|
|
93
|
-
// names (RUSH-1353). Copilot/
|
|
93
|
+
// names (RUSH-1353). Copilot/Goose load managed *.json under their
|
|
94
94
|
// hooks dirs the same way.
|
|
95
|
-
if (agent === 'claude' || agent === 'codex' || agent === 'antigravity' || agent === 'kimi' || agent === 'droid' || agent === 'copilot' || agent === '
|
|
95
|
+
if (agent === 'claude' || agent === 'codex' || agent === 'antigravity' || agent === 'kimi' || agent === 'droid' || agent === 'copilot' || agent === 'goose' || agent === 'cursor' || agent === 'grok' || agent === 'hermes' || agent === 'muse') {
|
|
96
96
|
registerHooksToSettings(agent, versionHome);
|
|
97
97
|
}
|
|
98
98
|
return { synced, paths };
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* - `flatFile` one `<name><ext>` file, body from a `transform` fn.
|
|
17
17
|
* (claude, grok, pi, droid, codex, opencode, copilot,
|
|
18
|
-
* cursor,
|
|
18
|
+
* cursor, goose, kimi)
|
|
19
19
|
* - `dirFile` a `<name>/` directory holding one generated `<file>`.
|
|
20
20
|
* (antigravity: `<name>/agent.md`)
|
|
21
21
|
* - `dirCopy` copy the whole source directory to `<name>/`, applying
|
|
@@ -35,7 +35,7 @@ import * as TOML from 'smol-toml';
|
|
|
35
35
|
import * as yaml from 'yaml';
|
|
36
36
|
import { safeJoin } from './paths.js';
|
|
37
37
|
import { filesContentMatch, normalizeResourceContent } from './resource-content-diff.js';
|
|
38
|
-
import { parseSubagentFrontmatter, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, transformSubagentForCursor, transformSubagentForDroid, transformSubagentForGoose,
|
|
38
|
+
import { parseSubagentFrontmatter, transformSubagentForClaude, transformSubagentForCodex, transformSubagentForCopilot, transformSubagentForCursor, transformSubagentForDroid, transformSubagentForGoose, transformSubagentForOpenCode, transformSubagentForAntigravity, } from './subagents.js';
|
|
39
39
|
/** Read a file's UTF-8 content, or null when it is missing/unreadable. */
|
|
40
40
|
function readFileSafe(filePath) {
|
|
41
41
|
try {
|
|
@@ -54,7 +54,6 @@ function metaFrontmatterSkip(filePath) {
|
|
|
54
54
|
function metaFrontmatterFallback(filePath, name) {
|
|
55
55
|
return parseSubagentFrontmatter(filePath) ?? { name, description: '' };
|
|
56
56
|
}
|
|
57
|
-
/** Kiro custom-agent JSON: read name/description/model; skip on parse error. */
|
|
58
57
|
function metaJson(filePath, name) {
|
|
59
58
|
try {
|
|
60
59
|
const cfg = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
@@ -283,9 +282,6 @@ export const SUBAGENT_TARGETS = {
|
|
|
283
282
|
// Tier 1 -- flat markdown, Claude-compatible flatten.
|
|
284
283
|
claude: flatFile({ subdir: ['.claude', 'agents'], ext: '.md', transform: transformSubagentForClaude }),
|
|
285
284
|
grok: flatFile({ subdir: ['.grok', 'agents'], ext: '.md', transform: transformSubagentForClaude }),
|
|
286
|
-
// Oh My Pi discovers Claude-shaped agent markdown from ~/.omp/agent/agents/
|
|
287
|
-
// (`omp agents unpack` writes there); frontmatter name/description + body.
|
|
288
|
-
pi: flatFile({ subdir: ['.omp', 'agent', 'agents'], ext: '.md', transform: transformSubagentForClaude, readMeta: metaFrontmatterFallback }),
|
|
289
285
|
droid: flatFile({ subdir: ['.factory', 'droids'], ext: '.md', transform: transformSubagentForDroid }),
|
|
290
286
|
// Bespoke frontmatter/format, still one flat file.
|
|
291
287
|
codex: flatFile({
|
|
@@ -312,12 +308,6 @@ export const SUBAGENT_TARGETS = {
|
|
|
312
308
|
transform: transformSubagentForCursor,
|
|
313
309
|
readMeta: metaFrontmatterFallback,
|
|
314
310
|
}),
|
|
315
|
-
kiro: flatFile({
|
|
316
|
-
subdir: ['.kiro', 'agents'],
|
|
317
|
-
ext: '.json',
|
|
318
|
-
transform: transformSubagentForKiro,
|
|
319
|
-
readMeta: metaJson,
|
|
320
|
-
}),
|
|
321
311
|
goose: flatFile({
|
|
322
312
|
subdir: ['.config', 'goose', 'agents'],
|
|
323
313
|
ext: '.yaml',
|
package/dist/lib/subagents.d.ts
CHANGED
|
@@ -106,16 +106,6 @@ export declare function transformSubagentForOpenCode(subagentDir: string): strin
|
|
|
106
106
|
* https://developers.openai.com/codex/subagents (custom agents section)
|
|
107
107
|
*/
|
|
108
108
|
export declare function transformSubagentForCodex(subagentDir: string): string;
|
|
109
|
-
/**
|
|
110
|
-
* Transform a subagent into a Kiro CLI custom-agent JSON file.
|
|
111
|
-
*
|
|
112
|
-
* Kiro custom agents live in `~/.kiro/agents/<name>.json` (or `.kiro/agents/`
|
|
113
|
-
* workspace-local) and declare name, description, prompt, tools, and optional
|
|
114
|
-
* model. We flatten the AGENT.md frontmatter + body plus any sibling .md files
|
|
115
|
-
* as sections into a single `prompt`, and expose the standard built-in tool
|
|
116
|
-
* set so the subagent can actually run.
|
|
117
|
-
*/
|
|
118
|
-
export declare function transformSubagentForKiro(subagentDir: string): string;
|
|
119
109
|
/**
|
|
120
110
|
* Transform a subagent into a Goose recipe YAML file.
|
|
121
111
|
*
|
package/dist/lib/subagents.js
CHANGED
|
@@ -403,43 +403,6 @@ function flattenSubagentInstructions(subagentDir) {
|
|
|
403
403
|
}
|
|
404
404
|
return instructions;
|
|
405
405
|
}
|
|
406
|
-
/**
|
|
407
|
-
* Transform a subagent into a Kiro CLI custom-agent JSON file.
|
|
408
|
-
*
|
|
409
|
-
* Kiro custom agents live in `~/.kiro/agents/<name>.json` (or `.kiro/agents/`
|
|
410
|
-
* workspace-local) and declare name, description, prompt, tools, and optional
|
|
411
|
-
* model. We flatten the AGENT.md frontmatter + body plus any sibling .md files
|
|
412
|
-
* as sections into a single `prompt`, and expose the standard built-in tool
|
|
413
|
-
* set so the subagent can actually run.
|
|
414
|
-
*/
|
|
415
|
-
export function transformSubagentForKiro(subagentDir) {
|
|
416
|
-
const agentMd = path.join(subagentDir, 'AGENT.md');
|
|
417
|
-
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
418
|
-
const body = getSubagentBody(agentMd);
|
|
419
|
-
if (!frontmatter) {
|
|
420
|
-
throw new Error(`Invalid AGENT.md in ${subagentDir}`);
|
|
421
|
-
}
|
|
422
|
-
const files = fs.readdirSync(subagentDir)
|
|
423
|
-
.filter(f => f.endsWith('.md') && f !== 'AGENT.md')
|
|
424
|
-
.sort();
|
|
425
|
-
let prompt = body;
|
|
426
|
-
for (const file of files) {
|
|
427
|
-
const content = fs.readFileSync(path.join(subagentDir, file), 'utf-8').trim();
|
|
428
|
-
const sectionName = file.replace('.md', '');
|
|
429
|
-
const title = sectionName.charAt(0).toUpperCase() + sectionName.slice(1).toLowerCase();
|
|
430
|
-
prompt += `\n\n## ${title}\n\n${content}`;
|
|
431
|
-
}
|
|
432
|
-
const config = {
|
|
433
|
-
name: frontmatter.name,
|
|
434
|
-
description: frontmatter.description,
|
|
435
|
-
prompt,
|
|
436
|
-
tools: ['read', 'write', 'shell', 'web_search', 'web_fetch'],
|
|
437
|
-
};
|
|
438
|
-
if (frontmatter.model) {
|
|
439
|
-
config.model = frontmatter.model;
|
|
440
|
-
}
|
|
441
|
-
return JSON.stringify(config, null, 2);
|
|
442
|
-
}
|
|
443
406
|
/**
|
|
444
407
|
* Transform a subagent into a Goose recipe YAML file.
|
|
445
408
|
*
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import type { CloudProviderId } from './cloud/types.js';
|
|
9
9
|
import type { FeedBroadcastConfig } from './feed-broadcast.js';
|
|
10
10
|
/** Unique identifier for a current or legacy AI coding agent. */
|
|
11
|
-
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | '
|
|
11
|
+
export type AgentId = 'claude' | 'codex' | 'gemini' | 'cursor' | 'opencode' | 'openclaw' | 'copilot' | 'amp' | 'goose' | 'antigravity' | 'grok' | 'kimi' | 'droid' | 'hermes' | 'muse' | 'warp';
|
|
12
12
|
/** How `agents run <agent>` chooses an installed version when none is pinned. */
|
|
13
13
|
export type RunStrategy = 'pinned' | 'available' | 'balanced';
|
|
14
14
|
export type RunEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max' | 'auto';
|
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.70",
|
|
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",
|