@phnx-labs/agents-cli 1.20.50 → 1.20.52
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 +40 -0
- package/dist/commands/browser-picker.js +1 -18
- package/dist/commands/browser.js +215 -7
- package/dist/commands/cloud.js +7 -25
- package/dist/commands/computer.d.ts +1 -0
- package/dist/commands/computer.js +129 -8
- package/dist/commands/events.d.ts +1 -1
- package/dist/commands/events.js +2 -3
- package/dist/commands/exec.js +66 -8
- package/dist/commands/factory.js +9 -4
- package/dist/commands/feed.d.ts +9 -0
- package/dist/commands/feed.js +69 -0
- package/dist/commands/inspect.js +1 -11
- package/dist/commands/logs.d.ts +5 -1
- package/dist/commands/logs.js +248 -3
- package/dist/commands/mcp.js +9 -6
- package/dist/commands/message.js +1 -4
- package/dist/commands/profiles.js +1 -18
- package/dist/commands/repo.js +33 -14
- package/dist/commands/resource-view.d.ts +1 -0
- package/dist/commands/resource-view.js +5 -17
- package/dist/commands/secrets.d.ts +23 -0
- package/dist/commands/secrets.js +174 -70
- package/dist/commands/sessions-picker.js +1 -18
- package/dist/commands/sessions.js +6 -8
- package/dist/commands/teams-picker.js +1 -32
- package/dist/commands/teams.js +5 -27
- package/dist/commands/tmux.js +1 -3
- package/dist/commands/view.js +1 -9
- package/dist/commands/worktree.js +1 -4
- package/dist/index.js +6 -2
- package/dist/lib/agents.d.ts +0 -4
- package/dist/lib/agents.js +20 -33
- package/dist/lib/auto-dispatch-linear.d.ts +18 -0
- package/dist/lib/auto-dispatch-linear.js +107 -0
- package/dist/lib/auto-dispatch-provider.d.ts +10 -0
- package/dist/lib/auto-dispatch-provider.js +25 -0
- package/dist/lib/auto-dispatch.d.ts +87 -0
- package/dist/lib/auto-dispatch.js +142 -0
- package/dist/lib/browser/cdp.js +11 -2
- package/dist/lib/browser/drivers/ssh.d.ts +28 -10
- package/dist/lib/browser/drivers/ssh.js +57 -18
- package/dist/lib/browser/login-detection.d.ts +94 -0
- package/dist/lib/browser/login-detection.js +274 -0
- package/dist/lib/browser/profiles.d.ts +17 -8
- package/dist/lib/browser/profiles.js +27 -8
- package/dist/lib/browser/refs.js +1 -5
- package/dist/lib/browser/secret-ref.d.ts +10 -0
- package/dist/lib/browser/secret-ref.js +14 -0
- package/dist/lib/browser/service.js +14 -12
- package/dist/lib/cli-resources.d.ts +0 -2
- package/dist/lib/cli-resources.js +30 -13
- package/dist/lib/cloud/rush.d.ts +15 -24
- package/dist/lib/cloud/rush.js +7 -32
- package/dist/lib/crabbox/cli.js +4 -1
- package/dist/lib/crabbox/lease.d.ts +6 -0
- package/dist/lib/crabbox/lease.js +40 -10
- package/dist/lib/crabbox/runtimes.d.ts +38 -1
- package/dist/lib/crabbox/runtimes.js +98 -5
- package/dist/lib/daemon.d.ts +12 -9
- package/dist/lib/daemon.js +73 -17
- package/dist/lib/events.d.ts +31 -5
- package/dist/lib/events.js +288 -101
- package/dist/lib/exec.js +32 -14
- package/dist/lib/feed.d.ts +56 -0
- package/dist/lib/feed.js +251 -0
- package/dist/lib/format.d.ts +38 -0
- package/dist/lib/format.js +108 -0
- package/dist/lib/git.d.ts +21 -0
- package/dist/lib/git.js +92 -0
- package/dist/lib/hooks/cache.d.ts +9 -2
- package/dist/lib/hooks/cache.js +220 -8
- package/dist/lib/hooks.js +24 -10
- package/dist/lib/hosts/passthrough.js +1 -0
- package/dist/lib/platform/exec.d.ts +4 -1
- package/dist/lib/platform/exec.js +8 -2
- package/dist/lib/resources.d.ts +0 -8
- package/dist/lib/resources.js +0 -10
- package/dist/lib/rotate.js +2 -0
- package/dist/lib/runner.js +10 -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 +21 -0
- package/dist/lib/secrets/agent.js +63 -1
- package/dist/lib/secrets/bundles.d.ts +33 -1
- package/dist/lib/secrets/bundles.js +38 -8
- package/dist/lib/secrets/icloud-import.d.ts +70 -0
- package/dist/lib/secrets/icloud-import.js +173 -0
- package/dist/lib/secrets/index.d.ts +36 -0
- package/dist/lib/secrets/index.js +99 -9
- package/dist/lib/secrets/remote.js +1 -1
- package/dist/lib/secrets/sync.js +1 -1
- package/dist/lib/session/active.d.ts +11 -1
- package/dist/lib/session/active.js +3 -0
- package/dist/lib/session/db.d.ts +1 -4
- package/dist/lib/session/db.js +20 -25
- package/dist/lib/session/discover.d.ts +2 -2
- package/dist/lib/session/discover.js +60 -48
- package/dist/lib/session/parse.js +35 -34
- package/dist/lib/session/render.d.ts +7 -3
- package/dist/lib/session/render.js +15 -9
- package/dist/lib/session/state.d.ts +55 -0
- package/dist/lib/session/state.js +100 -11
- package/dist/lib/session/types.d.ts +9 -0
- package/dist/lib/shims.d.ts +9 -3
- package/dist/lib/shims.js +44 -8
- package/dist/lib/ssh-tunnel.d.ts +33 -2
- package/dist/lib/ssh-tunnel.js +94 -7
- package/dist/lib/staleness/types.d.ts +0 -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 +2 -0
- package/dist/lib/state.js +25 -8
- package/dist/lib/teams/agents.js +6 -3
- package/dist/lib/types.d.ts +24 -1
- package/dist/lib/versions.d.ts +0 -26
- package/dist/lib/versions.js +2 -145
- package/dist/lib/warn-unpushed.d.ts +40 -0
- package/dist/lib/warn-unpushed.js +128 -0
- package/dist/lib/whats-new.d.ts +5 -3
- package/dist/lib/whats-new.js +25 -5
- package/package.json +3 -1
- package/dist/lib/resources/index.d.ts +0 -53
- package/dist/lib/resources/index.js +0 -76
package/dist/lib/daemon.js
CHANGED
|
@@ -393,6 +393,45 @@ export async function runDaemon() {
|
|
|
393
393
|
};
|
|
394
394
|
const healInterval = setInterval(() => { void runHealCheck(); }, 6 * 60 * 60_000);
|
|
395
395
|
const healKickoff = setTimeout(() => { void runHealCheck(); }, 30_000);
|
|
396
|
+
// Auto-dispatch: for any managed project that has opted in (autoDispatch:true +
|
|
397
|
+
// maxAgents>0 in ~/.agents/factory/projects.json), pick up Linear tickets that
|
|
398
|
+
// are delegated to an agent and still in Todo, and DISPATCH each through
|
|
399
|
+
// agents-cli's own cloud-provider layer (resolveProvider().dispatch(), same as
|
|
400
|
+
// `agents cloud run`) — then mark it Doing so it isn't re-picked. Capped at
|
|
401
|
+
// maxAgents concurrent per project. No hidden Prix dependency: Rush is one
|
|
402
|
+
// provider among rush/codex/factory, pinned per-project via `provider`. OFF
|
|
403
|
+
// unless a project opts in; no opted-in project or no LINEAR_API_KEY is a clean
|
|
404
|
+
// no-op. Overlap-guarded like the probes above. ~every 3 min.
|
|
405
|
+
let autoDispatching = false;
|
|
406
|
+
const runAutoDispatch = async () => {
|
|
407
|
+
if (autoDispatching)
|
|
408
|
+
return;
|
|
409
|
+
autoDispatching = true;
|
|
410
|
+
try {
|
|
411
|
+
const { readAutoDispatchProjects, isEligible, autoDispatchTick } = await import('./auto-dispatch.js');
|
|
412
|
+
const projects = readAutoDispatchProjects();
|
|
413
|
+
if (!projects.some(isEligible))
|
|
414
|
+
return; // opt-in: nothing enabled → skip
|
|
415
|
+
const { createLinearGateway } = await import('./auto-dispatch-linear.js');
|
|
416
|
+
const linear = createLinearGateway();
|
|
417
|
+
if (!linear)
|
|
418
|
+
return; // no LINEAR_API_KEY configured → skip
|
|
419
|
+
const { createProviderDispatcher } = await import('./auto-dispatch-provider.js');
|
|
420
|
+
const dispatcher = createProviderDispatcher();
|
|
421
|
+
const dispatched = await autoDispatchTick({ projects, linear, dispatcher, log: (lvl, m) => log(lvl, m) });
|
|
422
|
+
if (dispatched.length) {
|
|
423
|
+
log('INFO', `auto-dispatch: started ${dispatched.length} delegated ticket(s): ${dispatched.map((d) => d.identifier).join(', ')}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
catch (err) {
|
|
427
|
+
log('ERROR', `auto-dispatch failed: ${err.message}`);
|
|
428
|
+
}
|
|
429
|
+
finally {
|
|
430
|
+
autoDispatching = false;
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
const autoDispatchInterval = setInterval(() => { void runAutoDispatch(); }, 3 * 60_000);
|
|
434
|
+
const autoDispatchKickoff = setTimeout(() => { void runAutoDispatch(); }, 45_000);
|
|
396
435
|
// Device probe: refresh registered devices' reachability and detect newly
|
|
397
436
|
// appeared tailnet nodes, dropping a sentinel per pending device so the
|
|
398
437
|
// menu-bar helper can surface "NEW DEVICES → Register / Ignore". Refresh mode
|
|
@@ -500,6 +539,8 @@ export async function runDaemon() {
|
|
|
500
539
|
clearInterval(syncInterval);
|
|
501
540
|
clearInterval(healInterval);
|
|
502
541
|
clearTimeout(healKickoff);
|
|
542
|
+
clearInterval(autoDispatchInterval);
|
|
543
|
+
clearTimeout(autoDispatchKickoff);
|
|
503
544
|
clearInterval(deviceProbeInterval);
|
|
504
545
|
clearTimeout(deviceProbeKickoff);
|
|
505
546
|
clearInterval(tmuxReconcileInterval);
|
|
@@ -517,15 +558,19 @@ export async function runDaemon() {
|
|
|
517
558
|
/**
|
|
518
559
|
* Read the long-lived Claude OAuth token (from `claude setup-token`) that the
|
|
519
560
|
* user stored under the `claude` secrets bundle. Resolves the bundle the same
|
|
520
|
-
* way `agents run --secrets` does
|
|
521
|
-
*
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
*
|
|
561
|
+
* way `agents run --secrets` does. Interactive starts may prompt Keychain;
|
|
562
|
+
* headless auto-starts are broker-only and return null unless the user already
|
|
563
|
+
* unlocked the bundle in the secrets agent. That keeps a background browser
|
|
564
|
+
* command from hanging on an unseen biometric prompt. Never throws: an absent
|
|
565
|
+
* token leaves the daemon on its existing interactive OAuth session.
|
|
525
566
|
*/
|
|
526
|
-
export function readDaemonClaudeOAuthToken() {
|
|
567
|
+
export function readDaemonClaudeOAuthToken(opts = {}) {
|
|
527
568
|
try {
|
|
528
|
-
const
|
|
569
|
+
const allowPrompt = opts.allowPrompt ?? Boolean(process.stdin.isTTY);
|
|
570
|
+
const { env } = readAndResolveBundleEnv(DAEMON_OAUTH_BUNDLE, {
|
|
571
|
+
caller: 'daemon',
|
|
572
|
+
agentOnly: !allowPrompt,
|
|
573
|
+
});
|
|
529
574
|
const token = (env[DAEMON_OAUTH_KEY] ?? '').trim();
|
|
530
575
|
return token.length > 0 ? token : null;
|
|
531
576
|
}
|
|
@@ -558,10 +603,9 @@ export function writeOwnerOnlyServiceManifest(filePath, content) {
|
|
|
558
603
|
fs.writeFileSync(filePath, content, { encoding: 'utf-8', mode: 0o600 });
|
|
559
604
|
}
|
|
560
605
|
/** Generate a macOS launchd plist for auto-starting the daemon. */
|
|
561
|
-
export function generateLaunchdPlist() {
|
|
606
|
+
export function generateLaunchdPlist(oauthToken = readDaemonClaudeOAuthToken()) {
|
|
562
607
|
const agentsBin = getAgentsBinPath();
|
|
563
608
|
const logPath = getLogPath();
|
|
564
|
-
const oauthToken = readDaemonClaudeOAuthToken();
|
|
565
609
|
const oauthEntry = oauthToken
|
|
566
610
|
? `
|
|
567
611
|
<key>${DAEMON_OAUTH_KEY}</key>
|
|
@@ -596,9 +640,8 @@ export function generateLaunchdPlist() {
|
|
|
596
640
|
</plist>`;
|
|
597
641
|
}
|
|
598
642
|
/** Generate a Linux systemd user unit for auto-starting the daemon. */
|
|
599
|
-
export function generateSystemdUnit() {
|
|
643
|
+
export function generateSystemdUnit(oauthToken = readDaemonClaudeOAuthToken()) {
|
|
600
644
|
const agentsBin = getAgentsBinPath();
|
|
601
|
-
const oauthToken = readDaemonClaudeOAuthToken();
|
|
602
645
|
const oauthLine = oauthToken
|
|
603
646
|
? `\nEnvironment=${DAEMON_OAUTH_KEY}=${oauthToken}`
|
|
604
647
|
: '';
|
|
@@ -616,15 +659,29 @@ Environment=PATH=/usr/local/bin:/usr/bin:/bin:${os.homedir()}/.nvm/versions/node
|
|
|
616
659
|
[Install]
|
|
617
660
|
WantedBy=default.target`;
|
|
618
661
|
}
|
|
619
|
-
function getAgentsBinPath() {
|
|
662
|
+
export function getAgentsBinPath() {
|
|
620
663
|
// Prefer the binary actively executing this code. `which agents` returns
|
|
621
664
|
// whatever happens to be first on PATH, which means a side-by-side dev
|
|
622
665
|
// build at ~/.local/bin would silently spawn the registry-installed
|
|
623
666
|
// daemon and run stale code. process.argv[1] is the absolute path of
|
|
624
667
|
// the JS entrypoint the user actually invoked.
|
|
625
668
|
const argv1 = process.argv[1];
|
|
626
|
-
if (argv1 && fs.existsSync(argv1))
|
|
669
|
+
if (argv1 && fs.existsSync(argv1)) {
|
|
670
|
+
// The package's browser/computer entrypoints are sibling shims without a
|
|
671
|
+
// `daemon` command. A daemon started as their IPC side effect must launch
|
|
672
|
+
// through the main agents entrypoint instead of replaying the shim path.
|
|
673
|
+
const entryName = path.basename(argv1);
|
|
674
|
+
const compiledShim = /^(browser|computer)\.(c|m)?js$/.test(entryName);
|
|
675
|
+
const installedShim = /^(browser|computer)$/.test(entryName);
|
|
676
|
+
if (compiledShim || installedShim) {
|
|
677
|
+
const agentsEntry = path.join(path.dirname(argv1), compiledShim ? 'index.js' : 'agents');
|
|
678
|
+
if (!fs.existsSync(agentsEntry)) {
|
|
679
|
+
throw new Error(`Cannot start agents daemon: main CLI entry not found at ${agentsEntry}`);
|
|
680
|
+
}
|
|
681
|
+
return agentsEntry;
|
|
682
|
+
}
|
|
627
683
|
return argv1;
|
|
684
|
+
}
|
|
628
685
|
try {
|
|
629
686
|
return execFileSync('which', ['agents'], { encoding: 'utf-8' }).trim();
|
|
630
687
|
}
|
|
@@ -758,12 +815,11 @@ function startDaemonLocked() {
|
|
|
758
815
|
* the daemon then passes it to every routine run it spawns. An already-set
|
|
759
816
|
* value (e.g. inherited from launchd) is left untouched.
|
|
760
817
|
*/
|
|
761
|
-
export function buildDetachedDaemonEnv(baseEnv = process.env) {
|
|
818
|
+
export function buildDetachedDaemonEnv(baseEnv = process.env, oauthToken = readDaemonClaudeOAuthToken()) {
|
|
762
819
|
const env = { ...baseEnv };
|
|
763
820
|
if (!env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
env.CLAUDE_CODE_OAUTH_TOKEN = token;
|
|
821
|
+
if (oauthToken)
|
|
822
|
+
env.CLAUDE_CODE_OAUTH_TOKEN = oauthToken;
|
|
767
823
|
}
|
|
768
824
|
return env;
|
|
769
825
|
}
|
package/dist/lib/events.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Centralized event logging for agents-cli.
|
|
3
3
|
*
|
|
4
|
-
* Structured JSONL
|
|
5
|
-
*
|
|
4
|
+
* Structured JSONL audit log at ~/.agents/events.jsonl with lossless numbered
|
|
5
|
+
* gzip rotation at 10 MB and rich metadata for debugging/auditing.
|
|
6
6
|
*
|
|
7
7
|
* Features:
|
|
8
8
|
* - Rich metadata: hostname, platform, arch, pid, timezone
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
* - Permissions: logs dir is 0700, files are 0600 (owner-only)
|
|
12
12
|
* - Performance tracking: withTiming() wrapper for any async function
|
|
13
13
|
*/
|
|
14
|
-
export type
|
|
14
|
+
export type EventLevel = 'audit' | 'warn' | 'info' | 'debug';
|
|
15
|
+
export type EventType = 'agent.run.start' | 'agent.run.end' | 'agent.spawn.start' | 'agent.spawn.end' | 'version.install' | 'version.switch' | 'version.remove' | 'skill.install' | 'skill.remove' | 'browser.launch' | 'browser.close' | 'browser.navigate' | 'browser.screenshot' | 'secrets.get' | 'secrets.set' | 'secrets.delete' | 'secrets.rename' | 'cloud.dispatch' | 'cloud.complete' | 'cloud.cancel' | 'cloud.message' | 'teams.create' | 'teams.add' | 'teams.start' | 'teams.complete' | 'teams.disband' | 'hook.fire' | 'hook.complete' | 'hook.error' | 'mcp.add' | 'mcp.remove' | 'mcp.register' | 'resource.sync' | 'rotation.resolved' | 'command.start' | 'command.end' | 'perf.timing' | 'session.start' | 'session.end' | 'error' | 'warn' | 'info' | 'debug';
|
|
16
|
+
export declare function levelFor(event: EventType): EventLevel;
|
|
15
17
|
export interface EventMeta {
|
|
16
18
|
ts: string;
|
|
17
19
|
tz: string;
|
|
@@ -22,6 +24,9 @@ export interface EventMeta {
|
|
|
22
24
|
pid: number;
|
|
23
25
|
ppid: number;
|
|
24
26
|
event: EventType;
|
|
27
|
+
level: EventLevel;
|
|
28
|
+
caller: string;
|
|
29
|
+
session?: string;
|
|
25
30
|
osUser: string;
|
|
26
31
|
transport: 'local' | 'ssh';
|
|
27
32
|
sshClientIp?: string;
|
|
@@ -67,8 +72,14 @@ export declare function redactArgs(args: string[] | undefined): string[] | undef
|
|
|
67
72
|
* Returns undefined for null/undefined input.
|
|
68
73
|
*/
|
|
69
74
|
export declare function truncate(str: string | null | undefined, maxLength?: number): string | undefined;
|
|
75
|
+
export interface CallerIdentity {
|
|
76
|
+
kind: string;
|
|
77
|
+
session?: string;
|
|
78
|
+
}
|
|
79
|
+
/** Identify the environment that invoked agents-cli, not the source callsite. */
|
|
80
|
+
export declare function detectCaller(env?: NodeJS.ProcessEnv, stdoutIsTTY?: boolean): CallerIdentity;
|
|
70
81
|
/**
|
|
71
|
-
* Emit a structured event to the
|
|
82
|
+
* Emit a structured event to the append-only audit log.
|
|
72
83
|
*
|
|
73
84
|
* @param event - The event type
|
|
74
85
|
* @param payload - Event-specific data (agent, version, cwd, etc.)
|
|
@@ -142,7 +153,7 @@ export declare function emitCommand(command: string, args?: string[], payload?:
|
|
|
142
153
|
export declare function emitError(err: Error | string, payload?: EventPayload): void;
|
|
143
154
|
/**
|
|
144
155
|
* Remove log files older than the retention period.
|
|
145
|
-
*
|
|
156
|
+
* Removes numbered gzip archives whose filesystem mtime exceeds retention.
|
|
146
157
|
*
|
|
147
158
|
* @param retentionDays - Number of days to keep (default 7, from DEFAULT_RETENTION_DAYS)
|
|
148
159
|
* @returns Number of files removed
|
|
@@ -159,7 +170,9 @@ export declare function query(options: {
|
|
|
159
170
|
startDate?: Date;
|
|
160
171
|
endDate?: Date;
|
|
161
172
|
eventTypes?: EventType[];
|
|
173
|
+
level?: EventLevel;
|
|
162
174
|
agent?: string;
|
|
175
|
+
caller?: string;
|
|
163
176
|
command?: string;
|
|
164
177
|
module?: string;
|
|
165
178
|
limit?: number;
|
|
@@ -177,4 +190,17 @@ export declare function getTimingStats(label: string, options?: {
|
|
|
177
190
|
p50Ms: number;
|
|
178
191
|
p95Ms: number;
|
|
179
192
|
} | null;
|
|
193
|
+
export interface EventStats {
|
|
194
|
+
totalEvents: number;
|
|
195
|
+
byLevel: Record<string, number>;
|
|
196
|
+
byEvent: Record<string, number>;
|
|
197
|
+
byModule: Record<string, number>;
|
|
198
|
+
byUser: Record<string, number>;
|
|
199
|
+
fileCount: number;
|
|
200
|
+
totalBytes: number;
|
|
201
|
+
}
|
|
202
|
+
export declare function stats(options?: {
|
|
203
|
+
days?: number;
|
|
204
|
+
}): EventStats;
|
|
180
205
|
export declare function getLogsPath(): string;
|
|
206
|
+
export declare function _resetForTest(overrideEventsPath?: string): void;
|