@phnx-labs/agents-cli 1.20.91 → 1.20.93
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 +276 -0
- package/README.md +1 -1
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +72 -6
- package/dist/commands/activity.js +198 -49
- package/dist/commands/beta.js +1 -0
- package/dist/commands/doctor.js +4 -2
- package/dist/commands/events.js +91 -1
- package/dist/commands/exec.d.ts +14 -0
- package/dist/commands/exec.js +144 -14
- package/dist/commands/projects.d.ts +22 -0
- package/dist/commands/projects.js +539 -0
- package/dist/commands/secrets.d.ts +17 -0
- package/dist/commands/secrets.js +198 -7
- package/dist/commands/send.d.ts +14 -12
- package/dist/commands/send.js +105 -35
- package/dist/commands/sessions-picker.d.ts +15 -0
- package/dist/commands/sessions-picker.js +37 -12
- package/dist/commands/sessions-resume.d.ts +2 -0
- package/dist/commands/sessions-resume.js +9 -1
- package/dist/commands/sessions.d.ts +10 -5
- package/dist/commands/sessions.js +65 -27
- package/dist/commands/sync.js +9 -3
- package/dist/commands/view.js +4 -0
- package/dist/index.js +18 -1
- package/dist/lib/activity.d.ts +77 -12
- package/dist/lib/activity.js +424 -74
- package/dist/lib/beta.d.ts +1 -1
- package/dist/lib/beta.js +1 -1
- package/dist/lib/channels/send.d.ts +83 -0
- package/dist/lib/channels/send.js +112 -0
- package/dist/lib/devices/registry.d.ts +14 -0
- package/dist/lib/devices/registry.js +37 -0
- package/dist/lib/events-ingest.d.ts +46 -0
- package/dist/lib/events-ingest.js +182 -0
- package/dist/lib/events.d.ts +15 -3
- package/dist/lib/events.js +55 -3
- package/dist/lib/feed-post.js +8 -2
- package/dist/lib/hosts/remote-cmd.js +4 -0
- package/dist/lib/linear-project-counts.d.ts +62 -0
- package/dist/lib/linear-project-counts.js +122 -0
- package/dist/lib/linear-projects.d.ts +50 -0
- package/dist/lib/linear-projects.js +114 -0
- package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
- package/dist/lib/menubar/install-menubar.d.ts +14 -4
- package/dist/lib/menubar/install-menubar.js +20 -6
- package/dist/lib/menubar/notify-desktop.d.ts +17 -2
- package/dist/lib/menubar/notify-desktop.js +8 -2
- package/dist/lib/project-key.d.ts +44 -0
- package/dist/lib/project-key.js +79 -0
- package/dist/lib/project-probe.d.ts +75 -0
- package/dist/lib/project-probe.js +160 -0
- package/dist/lib/project-resources.d.ts +8 -0
- package/dist/lib/project-resources.js +31 -3
- package/dist/lib/project-root.js +16 -0
- package/dist/lib/project-status.d.ts +100 -0
- package/dist/lib/project-status.js +182 -0
- package/dist/lib/projects.d.ts +144 -0
- package/dist/lib/projects.js +313 -0
- package/dist/lib/remote-agents-json.d.ts +9 -0
- package/dist/lib/remote-agents-json.js +11 -5
- package/dist/lib/routine-notify.d.ts +11 -0
- package/dist/lib/routine-notify.js +22 -0
- package/dist/lib/run-notify.js +3 -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/audit.d.ts +1 -1
- package/dist/lib/secrets/audit.js +53 -10
- package/dist/lib/secrets/list-filter.d.ts +20 -5
- package/dist/lib/secrets/list-filter.js +22 -6
- package/dist/lib/secrets/usage-db.d.ts +106 -0
- package/dist/lib/secrets/usage-db.js +236 -0
- package/dist/lib/session/bash-command.d.ts +53 -0
- package/dist/lib/session/bash-command.js +364 -0
- package/dist/lib/session/digest.d.ts +6 -0
- package/dist/lib/session/digest.js +19 -0
- package/dist/lib/session/relative-time.d.ts +23 -0
- package/dist/lib/session/relative-time.js +60 -8
- package/dist/lib/session/remote-active.d.ts +5 -1
- package/dist/lib/session/remote-active.js +4 -1
- package/dist/lib/session/remote-list.js +5 -2
- package/dist/lib/session/render.d.ts +2 -9
- package/dist/lib/session/render.js +25 -56
- package/dist/lib/sqlite.js +28 -1
- package/dist/lib/ssh-exec.d.ts +6 -0
- package/dist/lib/ssh-exec.js +10 -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 +14 -0
- package/dist/lib/state.js +19 -0
- package/dist/lib/terminal/backends/index.d.ts +10 -2
- package/dist/lib/terminal/backends/index.js +14 -2
- package/dist/lib/terminal/backends/terminal-app.d.ts +13 -0
- package/dist/lib/terminal/backends/terminal-app.js +73 -0
- package/dist/lib/terminal/index.d.ts +2 -1
- package/dist/lib/terminal/index.js +2 -1
- package/dist/lib/terminal/preferred.d.ts +89 -0
- package/dist/lib/terminal/preferred.js +87 -0
- package/dist/lib/terminal/run-surface.d.ts +82 -0
- package/dist/lib/terminal/run-surface.js +146 -0
- package/dist/lib/terminal/types.d.ts +1 -1
- package/dist/lib/types.d.ts +6 -5
- package/dist/lib/versions.d.ts +6 -0
- package/dist/lib/versions.js +6 -4
- package/package.json +2 -1
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `agents run … --terminal` — re-open this exact run as a tab in a real terminal.
|
|
3
|
+
*
|
|
4
|
+
* A GUI caller (the menu bar's "New Session") cannot host a TUI, so it has to
|
|
5
|
+
* hand the run to a terminal. It used to do that by hardcoding AppleScript at
|
|
6
|
+
* Terminal.app; now it appends `--terminal` and the CLI decides WHICH terminal
|
|
7
|
+
* from the user's own live sessions (preferred.ts) and opens the tab through the
|
|
8
|
+
* launch engine — the same engine `sessions resume` and `sessions focus` use.
|
|
9
|
+
*
|
|
10
|
+
* The re-invocation is the caller's own argv with the `--terminal` flag removed,
|
|
11
|
+
* so every other flag (`--mode`, `--cwd`, a `--` passthrough) rides along
|
|
12
|
+
* untouched and there is no second place that knows how to spell a run.
|
|
13
|
+
*/
|
|
14
|
+
import type { Backend, EngineContext } from './types.js';
|
|
15
|
+
import type { ActiveSession } from '../session/active.js';
|
|
16
|
+
import { type LaunchBackendChoice, type SessionHostSample } from './preferred.js';
|
|
17
|
+
/** Backends a user may name in `--terminal <backend>`. */
|
|
18
|
+
export declare const TERMINAL_FLAG_BACKENDS: Backend[];
|
|
19
|
+
/**
|
|
20
|
+
* Validate a `--terminal <value>`. Returns the backend, or an error message
|
|
21
|
+
* naming the valid ids — never a silent fallback to auto-detection, which would
|
|
22
|
+
* open a terminal the user did not ask for.
|
|
23
|
+
*/
|
|
24
|
+
export declare function parseTerminalFlag(value: unknown): {
|
|
25
|
+
backend?: Backend;
|
|
26
|
+
error?: string;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The argv to re-invoke, with `--terminal` (and the value commander consumed for
|
|
30
|
+
* it) removed. `consumedValue` is the parsed option value when it is a string —
|
|
31
|
+
* that is the only token after the flag that belongs to it, so a prompt or a
|
|
32
|
+
* following flag is never eaten.
|
|
33
|
+
*/
|
|
34
|
+
export declare function stripTerminalFlag(argv: string[], consumedValue?: string): string[];
|
|
35
|
+
/** `agents run …` as a shell-safe command line for the surface to exec. */
|
|
36
|
+
export declare function buildRunCommand(argv: string[]): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Turn live sessions into the samples the resolver reads, filling in the app
|
|
39
|
+
* each tmux-hosted session is currently VIEWED in.
|
|
40
|
+
*
|
|
41
|
+
* This step is what makes detection work for the common case: `agents run`
|
|
42
|
+
* wraps interactive runs in tmux, so a session the user started in Ghostty is
|
|
43
|
+
* attributed `host: 'tmux'` on the discovery path and would otherwise name no
|
|
44
|
+
* terminal at all. `resolveViewingIn` walks the attached tmux client's pid up to
|
|
45
|
+
* its host app — the same resolver `agents sessions` uses to print
|
|
46
|
+
* "viewing in Ghostty tab 2". Sessions that are detached (no client attached)
|
|
47
|
+
* legitimately have no viewer and keep their `tmux` host.
|
|
48
|
+
*
|
|
49
|
+
* One inherited nuance: `resolveViewingIn` labels a client whose app it cannot
|
|
50
|
+
* identify `'terminal'` (viewing-in.ts:87), so a tmux session viewed from an
|
|
51
|
+
* unrecognized emulator resolves to Terminal.app rather than falling through.
|
|
52
|
+
* That lands on the same every-Mac floor the fallback chain ends at anyway, so
|
|
53
|
+
* it costs nothing here — but it is a default, not a detection.
|
|
54
|
+
*
|
|
55
|
+
* Best-effort: any probe failure degrades to the plain host, never throws.
|
|
56
|
+
*/
|
|
57
|
+
export declare function toHostSamples(sessions: ActiveSession[]): Promise<SessionHostSample[]>;
|
|
58
|
+
export interface OpenRunSurfaceParams {
|
|
59
|
+
/** This process's argv after the program name (i.e. `['run','claude',…]`). */
|
|
60
|
+
argv: string[];
|
|
61
|
+
/** The parsed `--terminal` value, when the user named a backend. */
|
|
62
|
+
forced?: Backend;
|
|
63
|
+
/** The value commander consumed for `--terminal`, so it can be stripped. */
|
|
64
|
+
consumedValue?: string;
|
|
65
|
+
cwd: string;
|
|
66
|
+
/** Live sessions, used to detect the terminal the user actually works in. */
|
|
67
|
+
sessions: SessionHostSample[];
|
|
68
|
+
ctx: EngineContext;
|
|
69
|
+
}
|
|
70
|
+
export interface OpenRunSurfaceResult {
|
|
71
|
+
ok: boolean;
|
|
72
|
+
choice?: LaunchBackendChoice;
|
|
73
|
+
/** Human line describing the terminal that was chosen. */
|
|
74
|
+
description?: string;
|
|
75
|
+
error?: string;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Open the run as a tab in the resolved terminal. Never throws — a failure comes
|
|
79
|
+
* back as `ok: false` with the reason, so the caller can tell the user rather
|
|
80
|
+
* than exiting silently.
|
|
81
|
+
*/
|
|
82
|
+
export declare function openRunInTerminal(params: OpenRunSurfaceParams): Promise<OpenRunSurfaceResult>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { BACKENDS } from './backends/index.js';
|
|
2
|
+
import { openSurface } from './engine.js';
|
|
3
|
+
import { getCliLaunch } from '../cli-entry.js';
|
|
4
|
+
import { shellQuote } from './quote.js';
|
|
5
|
+
import { resolveLaunchBackend, describeBackendChoice, } from './preferred.js';
|
|
6
|
+
/** Backends a user may name in `--terminal <backend>`. */
|
|
7
|
+
export const TERMINAL_FLAG_BACKENDS = Object.keys(BACKENDS);
|
|
8
|
+
/**
|
|
9
|
+
* Validate a `--terminal <value>`. Returns the backend, or an error message
|
|
10
|
+
* naming the valid ids — never a silent fallback to auto-detection, which would
|
|
11
|
+
* open a terminal the user did not ask for.
|
|
12
|
+
*/
|
|
13
|
+
export function parseTerminalFlag(value) {
|
|
14
|
+
if (value === undefined || value === true || value === '')
|
|
15
|
+
return {};
|
|
16
|
+
const raw = String(value);
|
|
17
|
+
if (TERMINAL_FLAG_BACKENDS.includes(raw))
|
|
18
|
+
return { backend: raw };
|
|
19
|
+
// `--terminal [backend]` takes an OPTIONAL value, and commander assigns the
|
|
20
|
+
// next non-option token to it — so `agents run claude --terminal "fix the bug"`
|
|
21
|
+
// lands the prompt here. Say that, or the user just sees their prompt called a
|
|
22
|
+
// bad backend name and has no idea why.
|
|
23
|
+
const looksLikeAPrompt = /\s/.test(raw) || raw.length > 24;
|
|
24
|
+
const hint = looksLikeAPrompt
|
|
25
|
+
? ` That looks like a prompt: put it BEFORE the flag — agents run <agent> "${raw.length > 40 ? `${raw.slice(0, 40)}…` : raw}" --terminal.`
|
|
26
|
+
: '';
|
|
27
|
+
return {
|
|
28
|
+
error: `Unknown --terminal backend '${raw}'. Use one of: ${TERMINAL_FLAG_BACKENDS.join(', ')} (or pass --terminal alone to auto-detect).${hint}`,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* The argv to re-invoke, with `--terminal` (and the value commander consumed for
|
|
33
|
+
* it) removed. `consumedValue` is the parsed option value when it is a string —
|
|
34
|
+
* that is the only token after the flag that belongs to it, so a prompt or a
|
|
35
|
+
* following flag is never eaten.
|
|
36
|
+
*/
|
|
37
|
+
export function stripTerminalFlag(argv, consumedValue) {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (let i = 0; i < argv.length; i++) {
|
|
40
|
+
const tok = argv[i];
|
|
41
|
+
// Everything past a bare `--` is forwarded verbatim to the agent's own CLI
|
|
42
|
+
// (`agents run kimi -- --terminal`), so it is not ours to rewrite.
|
|
43
|
+
if (tok === '--') {
|
|
44
|
+
out.push(...argv.slice(i));
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
if (tok === '--terminal') {
|
|
48
|
+
if (consumedValue !== undefined && argv[i + 1] === consumedValue)
|
|
49
|
+
i++;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (tok.startsWith('--terminal='))
|
|
53
|
+
continue;
|
|
54
|
+
out.push(tok);
|
|
55
|
+
}
|
|
56
|
+
return out;
|
|
57
|
+
}
|
|
58
|
+
/** `agents run …` as a shell-safe command line for the surface to exec. */
|
|
59
|
+
export function buildRunCommand(argv) {
|
|
60
|
+
const { command, args } = getCliLaunch(argv);
|
|
61
|
+
return [command, ...args].map(shellQuote);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Turn live sessions into the samples the resolver reads, filling in the app
|
|
65
|
+
* each tmux-hosted session is currently VIEWED in.
|
|
66
|
+
*
|
|
67
|
+
* This step is what makes detection work for the common case: `agents run`
|
|
68
|
+
* wraps interactive runs in tmux, so a session the user started in Ghostty is
|
|
69
|
+
* attributed `host: 'tmux'` on the discovery path and would otherwise name no
|
|
70
|
+
* terminal at all. `resolveViewingIn` walks the attached tmux client's pid up to
|
|
71
|
+
* its host app — the same resolver `agents sessions` uses to print
|
|
72
|
+
* "viewing in Ghostty tab 2". Sessions that are detached (no client attached)
|
|
73
|
+
* legitimately have no viewer and keep their `tmux` host.
|
|
74
|
+
*
|
|
75
|
+
* One inherited nuance: `resolveViewingIn` labels a client whose app it cannot
|
|
76
|
+
* identify `'terminal'` (viewing-in.ts:87), so a tmux session viewed from an
|
|
77
|
+
* unrecognized emulator resolves to Terminal.app rather than falling through.
|
|
78
|
+
* That lands on the same every-Mac floor the fallback chain ends at anyway, so
|
|
79
|
+
* it costs nothing here — but it is a default, not a detection.
|
|
80
|
+
*
|
|
81
|
+
* Best-effort: any probe failure degrades to the plain host, never throws.
|
|
82
|
+
*/
|
|
83
|
+
export async function toHostSamples(sessions) {
|
|
84
|
+
const samples = sessions.map((s) => ({
|
|
85
|
+
host: s.host,
|
|
86
|
+
lastActivityMs: s.lastActivityMs,
|
|
87
|
+
startedAtMs: s.startedAtMs,
|
|
88
|
+
}));
|
|
89
|
+
const tmuxIdx = sessions
|
|
90
|
+
.map((s, i) => ({ s, i }))
|
|
91
|
+
.filter(({ s }) => s.provenance?.mux?.kind === 'tmux' && s.provenance.mux.pane);
|
|
92
|
+
if (tmuxIdx.length === 0)
|
|
93
|
+
return samples;
|
|
94
|
+
try {
|
|
95
|
+
const { enumerateGhosttyTabs } = await import('../session/ghostty-tabs.js');
|
|
96
|
+
const { mapPanesToTargets, listClients } = await import('../tmux/session.js');
|
|
97
|
+
const { resolveViewingIn } = await import('../session/viewing-in.js');
|
|
98
|
+
// One Ghostty enumeration shared across sockets, as the sessions renderer does.
|
|
99
|
+
const ghosttySurfaces = await enumerateGhosttyTabs();
|
|
100
|
+
const sockets = new Set(tmuxIdx.map(({ s }) => s.provenance.mux.socket));
|
|
101
|
+
for (const socket of sockets) {
|
|
102
|
+
const paneToTarget = await mapPanesToTargets(socket);
|
|
103
|
+
if (paneToTarget.size === 0)
|
|
104
|
+
continue;
|
|
105
|
+
const clients = await listClients(socket);
|
|
106
|
+
for (const { s, i } of tmuxIdx) {
|
|
107
|
+
if (s.provenance.mux.socket !== socket)
|
|
108
|
+
continue;
|
|
109
|
+
const viewing = await resolveViewingIn(s, clients, { paneToTarget, ghosttySurfaces });
|
|
110
|
+
if (viewing)
|
|
111
|
+
samples[i].viewingApp = viewing.app;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
// tmux/Ghostty probes are best-effort; fall back to the plain host values.
|
|
117
|
+
}
|
|
118
|
+
return samples;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Open the run as a tab in the resolved terminal. Never throws — a failure comes
|
|
122
|
+
* back as `ok: false` with the reason, so the caller can tell the user rather
|
|
123
|
+
* than exiting silently.
|
|
124
|
+
*/
|
|
125
|
+
export async function openRunInTerminal(params) {
|
|
126
|
+
const choice = params.forced
|
|
127
|
+
? { backend: params.forced, source: 'forced' }
|
|
128
|
+
: resolveLaunchBackend(params.ctx, params.sessions);
|
|
129
|
+
if (!choice) {
|
|
130
|
+
return {
|
|
131
|
+
ok: false,
|
|
132
|
+
error: 'No terminal this machine can drive (need iTerm, Ghostty, Terminal.app, VSCodium, or a tmux session). Run without --terminal.',
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (params.forced && !BACKENDS[choice.backend].isAvailable(params.ctx)) {
|
|
136
|
+
return { ok: false, error: `--terminal ${choice.backend} is not available here.` };
|
|
137
|
+
}
|
|
138
|
+
const command = buildRunCommand(stripTerminalFlag(params.argv, params.consumedValue));
|
|
139
|
+
const result = await openSurface({
|
|
140
|
+
backend: choice.backend,
|
|
141
|
+
layout: 'tab',
|
|
142
|
+
cwd: params.cwd,
|
|
143
|
+
command,
|
|
144
|
+
});
|
|
145
|
+
return { ok: result.ok, choice, description: describeBackendChoice(choice), error: result.error };
|
|
146
|
+
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* is attended and live. See docs/terminal-engine.md.
|
|
9
9
|
*/
|
|
10
10
|
/** An interactive terminal backend the engine can drive. */
|
|
11
|
-
export type Backend = 'iterm' | 'ghostty' | 'tmux' | 'vscodium-agent';
|
|
11
|
+
export type Backend = 'iterm' | 'ghostty' | 'tmux' | 'vscodium-agent' | 'terminal';
|
|
12
12
|
/** Which way a split pane grows. `right` = side-by-side; `down` = stacked. */
|
|
13
13
|
export type SplitDirection = 'right' | 'down';
|
|
14
14
|
/** Where a surface lands: a new tab, or a split of the current pane. */
|
package/dist/lib/types.d.ts
CHANGED
|
@@ -62,7 +62,7 @@ export interface BudgetConfig {
|
|
|
62
62
|
require_confirm_over?: number;
|
|
63
63
|
}
|
|
64
64
|
/** Preview features that users can opt into via `agents beta`. */
|
|
65
|
-
export type BetaFeatureName = 'drive' | 'factory' | 'session-sync';
|
|
65
|
+
export type BetaFeatureName = 'drive' | 'factory' | 'session-sync' | 'projects';
|
|
66
66
|
/** Subset of chalk color names used for agent-specific terminal output. */
|
|
67
67
|
export type ChalkColor = 'magenta' | 'green' | 'blue' | 'cyan' | 'yellowBright' | 'redBright' | 'whiteBright' | 'blueBright' | 'greenBright' | 'magentaBright' | 'cyanBright';
|
|
68
68
|
/** Static configuration for a single agent -- paths, capabilities, and format conventions. */
|
|
@@ -873,10 +873,11 @@ export interface Meta {
|
|
|
873
873
|
};
|
|
874
874
|
/**
|
|
875
875
|
* Owner/channel notification config for `agents send` / `agents notify`.
|
|
876
|
-
* `owner` is the
|
|
877
|
-
* `transports` maps a user-facing channel name to the
|
|
878
|
-
* delivers it — explicit, one provider per channel,
|
|
879
|
-
* default to name-identity (channel `slack` ->
|
|
876
|
+
* `owner` is the address expanded by `--to owner` and by `agents notify`
|
|
877
|
+
* (channel + target). `transports` maps a user-facing channel name to the
|
|
878
|
+
* provider that actually delivers it — explicit, one provider per channel,
|
|
879
|
+
* no fallback. Omitted keys default to name-identity (channel `slack` ->
|
|
880
|
+
* provider `slack`).
|
|
880
881
|
*/
|
|
881
882
|
notify?: {
|
|
882
883
|
owner?: {
|
package/dist/lib/versions.d.ts
CHANGED
|
@@ -464,6 +464,12 @@ export interface SyncResult {
|
|
|
464
464
|
subagents: string[];
|
|
465
465
|
plugins: string[];
|
|
466
466
|
workflows: string[];
|
|
467
|
+
/**
|
|
468
|
+
* Project files the sync left alone because the workspace already has them
|
|
469
|
+
* (repo-relative). Reported once, grouped, by the command that rendered the
|
|
470
|
+
* sync — never one line per file from down here.
|
|
471
|
+
*/
|
|
472
|
+
projectSkipped: string[];
|
|
467
473
|
}
|
|
468
474
|
/**
|
|
469
475
|
* Enumerate the DotAgent repo names that resources can be scoped to:
|
package/dist/lib/versions.js
CHANGED
|
@@ -2420,7 +2420,7 @@ export function mergeRepoScopedSelections(repos, cwd = process.cwd()) {
|
|
|
2420
2420
|
*/
|
|
2421
2421
|
export function syncResourcesToVersion(agent, version, selection, options = {}) {
|
|
2422
2422
|
if (isAgentHardDeprecated(agent)) {
|
|
2423
|
-
return { commands: false, skills: false, hooks: false, memory: [], permissions: false, mcp: [], subagents: [], plugins: [], workflows: [] };
|
|
2423
|
+
return { commands: false, skills: false, hooks: false, memory: [], permissions: false, mcp: [], subagents: [], plugins: [], workflows: [], projectSkipped: [] };
|
|
2424
2424
|
}
|
|
2425
2425
|
const agentConfig = AGENTS[agent];
|
|
2426
2426
|
const versionHome = getVersionHomePath(agent, version);
|
|
@@ -2431,7 +2431,7 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2431
2431
|
// care about the ORIGINAL intent: a caller passing no selection means
|
|
2432
2432
|
// "full sync; persist the staleness manifest after."
|
|
2433
2433
|
const userPassedSelection = selection !== undefined;
|
|
2434
|
-
const result = { commands: false, skills: false, hooks: false, memory: [], permissions: false, mcp: [], subagents: [], plugins: [], workflows: [] };
|
|
2434
|
+
const result = { commands: false, skills: false, hooks: false, memory: [], permissions: false, mcp: [], subagents: [], plugins: [], workflows: [], projectSkipped: [] };
|
|
2435
2435
|
const cwd = options.cwd || process.cwd();
|
|
2436
2436
|
const projectAgentsDir = options.projectDir || getProjectAgentsDir(cwd);
|
|
2437
2437
|
const userAgentsDir = getUserAgentsDir();
|
|
@@ -2499,7 +2499,7 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2499
2499
|
}
|
|
2500
2500
|
}
|
|
2501
2501
|
if (projectAgentsDir) {
|
|
2502
|
-
syncProjectResourcesToAgent(agent, version, projectAgentsDir);
|
|
2502
|
+
result.projectSkipped = syncProjectResourcesToAgent(agent, version, projectAgentsDir).skipped;
|
|
2503
2503
|
}
|
|
2504
2504
|
// Fast guard: skip the entire sync when the caller requested a full sync and
|
|
2505
2505
|
// nothing has changed since the last full sync. Pattern-derived selections
|
|
@@ -2508,7 +2508,9 @@ export function syncResourcesToVersion(agent, version, selection, options = {})
|
|
|
2508
2508
|
if (!userPassedSelection && !options.force) {
|
|
2509
2509
|
const manifest = loadManifest(agent, version);
|
|
2510
2510
|
if (manifest && !isStale(manifest, agent, version, cwd)) {
|
|
2511
|
-
|
|
2511
|
+
// Nothing synced, but the project sync above already ran — carry its
|
|
2512
|
+
// skipped files out so the caller can still report them.
|
|
2513
|
+
return { ...result };
|
|
2512
2514
|
}
|
|
2513
2515
|
}
|
|
2514
2516
|
// Helper: remove a path (symlink or real) if it exists
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@phnx-labs/agents-cli",
|
|
3
|
-
"version": "1.20.
|
|
3
|
+
"version": "1.20.93",
|
|
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",
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
"marked-terminal": "7.3.0",
|
|
100
100
|
"ora": "9.4.1",
|
|
101
101
|
"proper-lockfile": "4.1.2",
|
|
102
|
+
"shlex": "3.0.0",
|
|
102
103
|
"simple-git": "3.36.0",
|
|
103
104
|
"smol-toml": "1.7.0",
|
|
104
105
|
"ws": "^8.21.0",
|