@phnx-labs/agents-cli 1.20.72 → 1.20.74
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 +395 -0
- package/README.md +40 -4
- package/dist/bin/agents +0 -0
- package/dist/commands/activity.d.ts +12 -0
- package/dist/commands/activity.js +68 -0
- package/dist/commands/apply.d.ts +13 -0
- package/dist/commands/apply.js +28 -3
- package/dist/commands/browser.js +1 -1
- package/dist/commands/cloud.js +21 -11
- package/dist/commands/doctor.js +21 -5
- package/dist/commands/events.d.ts +11 -10
- package/dist/commands/events.js +30 -21
- package/dist/commands/exec.d.ts +34 -0
- package/dist/commands/exec.js +337 -39
- package/dist/commands/export.d.ts +11 -0
- package/dist/commands/export.js +215 -0
- package/dist/commands/feed.d.ts +13 -0
- package/dist/commands/feed.js +130 -29
- package/dist/commands/hq.d.ts +2 -0
- package/dist/commands/hq.js +58 -0
- package/dist/commands/import.js +51 -3
- package/dist/commands/lease.d.ts +19 -0
- package/dist/commands/lease.js +138 -11
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +123 -0
- package/dist/commands/logs.js +1 -1
- package/dist/commands/mine.d.ts +27 -0
- package/dist/commands/mine.js +207 -0
- package/dist/commands/monitors.js +79 -49
- package/dist/commands/plugins.js +1 -0
- package/dist/commands/profiles.js +158 -0
- package/dist/commands/repo.js +2 -60
- package/dist/commands/resources.d.ts +5 -0
- package/dist/commands/resources.js +95 -0
- package/dist/commands/routines.d.ts +2 -0
- package/dist/commands/routines.js +139 -37
- package/dist/commands/secrets.js +234 -47
- package/dist/commands/send.d.ts +15 -0
- package/dist/commands/send.js +62 -0
- package/dist/commands/sessions-tail.d.ts +1 -0
- package/dist/commands/sessions-tail.js +20 -9
- package/dist/commands/sessions.js +18 -3
- package/dist/commands/setup-mine.d.ts +18 -0
- package/dist/commands/setup-mine.js +106 -0
- package/dist/commands/setup-share.js +2 -2
- package/dist/commands/setup.js +9 -2
- package/dist/commands/share.d.ts +8 -1
- package/dist/commands/share.js +122 -37
- package/dist/commands/ssh.d.ts +9 -0
- package/dist/commands/ssh.js +196 -26
- package/dist/commands/sync.js +1 -1
- package/dist/commands/teams.js +11 -2
- package/dist/commands/versions.js +36 -5
- package/dist/commands/view.js +75 -27
- package/dist/index.js +80 -10
- package/dist/lib/activity.d.ts +124 -0
- package/dist/lib/activity.js +542 -0
- package/dist/lib/agents.d.ts +35 -0
- package/dist/lib/agents.js +79 -6
- package/dist/lib/artifact-actions.d.ts +1 -1
- package/dist/lib/artifact-actions.js +1 -1
- package/dist/lib/ask-classifier.d.ts +2 -1
- package/dist/lib/ask-classifier.js +3 -3
- package/dist/lib/auth-health.d.ts +32 -4
- package/dist/lib/auth-health.js +40 -1
- package/dist/lib/auto-pull.js +8 -1
- package/dist/lib/brand.d.ts +40 -0
- package/dist/lib/brand.js +122 -0
- package/dist/lib/browser/drivers/ssh.js +4 -7
- package/dist/lib/browser/service.js +6 -8
- package/dist/lib/channels/providers/index.d.ts +2 -0
- package/dist/lib/channels/providers/index.js +20 -0
- package/dist/lib/channels/providers/mailbox.d.ts +2 -0
- package/dist/lib/channels/providers/mailbox.js +26 -0
- package/dist/lib/channels/providers/openclaw-telegram.d.ts +2 -0
- package/dist/lib/channels/providers/openclaw-telegram.js +34 -0
- package/dist/lib/channels/providers/rush.d.ts +6 -0
- package/dist/lib/channels/providers/rush.js +55 -0
- package/dist/lib/channels/registry.d.ts +42 -0
- package/dist/lib/channels/registry.js +20 -0
- package/dist/lib/channels/resolve.d.ts +11 -0
- package/dist/lib/channels/resolve.js +12 -0
- package/dist/lib/cli-resources.d.ts +18 -0
- package/dist/lib/cli-resources.js +53 -4
- package/dist/lib/cloud/codex.js +6 -3
- package/dist/lib/cloud/factory.d.ts +1 -0
- package/dist/lib/cloud/factory.js +10 -4
- package/dist/lib/cloud/rush.d.ts +3 -1
- package/dist/lib/cloud/rush.js +6 -1
- package/dist/lib/cloud/types.d.ts +2 -0
- package/dist/lib/codex-home.d.ts +35 -0
- package/dist/lib/codex-home.js +136 -0
- package/dist/lib/config-transfer.d.ts +16 -0
- package/dist/lib/config-transfer.js +56 -0
- package/dist/lib/crabbox/cli.d.ts +44 -0
- package/dist/lib/crabbox/cli.js +120 -20
- package/dist/lib/crabbox/lease.d.ts +52 -1
- package/dist/lib/crabbox/lease.js +117 -16
- package/dist/lib/crabbox/progress.d.ts +31 -0
- package/dist/lib/crabbox/progress.js +76 -0
- package/dist/lib/crabbox/runtimes.d.ts +4 -0
- package/dist/lib/crabbox/runtimes.js +33 -8
- package/dist/lib/crabbox/setup-copy.d.ts +87 -0
- package/dist/lib/crabbox/setup-copy.js +127 -0
- package/dist/lib/daemon.d.ts +5 -5
- package/dist/lib/daemon.js +9 -9
- package/dist/lib/drive-sync.js +6 -3
- package/dist/lib/event-stream.d.ts +36 -0
- package/dist/lib/event-stream.js +68 -0
- package/dist/lib/events.d.ts +1 -1
- package/dist/lib/exec.d.ts +11 -0
- package/dist/lib/exec.js +23 -2
- package/dist/lib/export.d.ts +72 -0
- package/dist/lib/export.js +269 -0
- package/dist/lib/feed-policy.d.ts +1 -1
- package/dist/lib/feed-policy.js +14 -9
- package/dist/lib/feed-ranking.d.ts +32 -0
- package/dist/lib/feed-ranking.js +224 -0
- package/dist/lib/feed.d.ts +35 -2
- package/dist/lib/feed.js +66 -3
- package/dist/lib/fleet/auth-sync.d.ts +53 -0
- package/dist/lib/fleet/auth-sync.js +92 -0
- package/dist/lib/fleet/remote-login.d.ts +187 -0
- package/dist/lib/fleet/remote-login.js +556 -0
- package/dist/lib/format.d.ts +30 -3
- package/dist/lib/format.js +34 -5
- package/dist/lib/fs-atomic.d.ts +7 -2
- package/dist/lib/fs-atomic.js +8 -12
- package/dist/lib/git.d.ts +16 -0
- package/dist/lib/git.js +79 -2
- package/dist/lib/heal.js +11 -3
- package/dist/lib/hosts/progress.d.ts +28 -10
- package/dist/lib/hosts/progress.js +79 -22
- package/dist/lib/hosts/remote-cmd.js +4 -0
- package/dist/lib/hq/floor.d.ts +87 -0
- package/dist/lib/hq/floor.js +226 -0
- package/dist/lib/import.d.ts +23 -0
- package/dist/lib/import.js +74 -2
- package/dist/lib/isolation-boundary-report.d.ts +10 -0
- package/dist/lib/isolation-boundary-report.js +35 -0
- package/dist/lib/menubar/install-menubar.js +14 -20
- package/dist/lib/notify.d.ts +1 -0
- package/dist/lib/notify.js +3 -3
- package/dist/lib/open-url.d.ts +2 -0
- package/dist/lib/open-url.js +19 -0
- package/dist/lib/openclaw-keychain.d.ts +56 -0
- package/dist/lib/openclaw-keychain.js +236 -0
- package/dist/lib/overdue.js +10 -0
- package/dist/lib/permissions.d.ts +44 -1
- package/dist/lib/permissions.js +284 -7
- package/dist/lib/project-launch.d.ts +6 -12
- package/dist/lib/project-launch.js +13 -228
- package/dist/lib/project-resources.d.ts +7 -0
- package/dist/lib/project-resources.js +306 -0
- package/dist/lib/pty-client.d.ts +27 -0
- package/dist/lib/pty-client.js +136 -10
- package/dist/lib/refresh.js +14 -10
- package/dist/lib/resource-profiles.d.ts +26 -0
- package/dist/lib/resource-profiles.js +157 -0
- package/dist/lib/resources/permissions.js +7 -1
- package/dist/lib/resources/types.d.ts +1 -1
- package/dist/lib/resources.d.ts +1 -1
- package/dist/lib/resources.js +32 -3
- package/dist/lib/routines.d.ts +11 -0
- package/dist/lib/routines.js +56 -15
- package/dist/lib/runner.d.ts +1 -0
- package/dist/lib/runner.js +66 -5
- package/dist/lib/secrets/bundles.d.ts +16 -3
- package/dist/lib/secrets/bundles.js +206 -37
- package/dist/lib/secrets/icloud-import.d.ts +2 -2
- package/dist/lib/secrets/icloud-import.js +9 -6
- package/dist/lib/secrets/mcp.js +1 -1
- package/dist/lib/secrets/vault-age-helper.d.ts +1 -0
- package/dist/lib/secrets/vault-age-helper.js +34 -0
- package/dist/lib/secrets/vault.d.ts +49 -0
- package/dist/lib/secrets/vault.js +397 -0
- package/dist/lib/self-heal/checks/path.js +3 -1
- package/dist/lib/self-heal/checks/shadowing.js +10 -2
- package/dist/lib/self-heal/checks/shims.js +19 -11
- package/dist/lib/session/cloud.d.ts +2 -2
- package/dist/lib/session/cloud.js +2 -2
- package/dist/lib/session/db.d.ts +4 -0
- package/dist/lib/session/db.js +44 -7
- package/dist/lib/session/discover.d.ts +2 -0
- package/dist/lib/session/discover.js +114 -3
- package/dist/lib/session/stream-render.d.ts +3 -0
- package/dist/lib/session/stream-render.js +130 -0
- package/dist/lib/session/types.d.ts +6 -0
- package/dist/lib/share/analytics.d.ts +13 -0
- package/dist/lib/share/analytics.js +45 -0
- package/dist/lib/share/config.d.ts +19 -5
- package/dist/lib/share/config.js +44 -8
- package/dist/lib/share/provision.d.ts +58 -6
- package/dist/lib/share/provision.js +97 -22
- package/dist/lib/share/publish.d.ts +36 -13
- package/dist/lib/share/publish.js +55 -8
- package/dist/lib/share/worker-template.js +83 -17
- package/dist/lib/shims.d.ts +35 -0
- package/dist/lib/shims.js +159 -13
- package/dist/lib/ssh-exec.d.ts +14 -0
- package/dist/lib/ssh-exec.js +57 -0
- package/dist/lib/staleness/detectors/hooks.js +25 -1
- package/dist/lib/staleness/detectors/permissions.js +66 -0
- package/dist/lib/staleness/detectors/workflows.js +20 -0
- package/dist/lib/staleness/writers/hooks.js +58 -4
- package/dist/lib/staleness/writers/permissions.js +2 -2
- package/dist/lib/staleness/writers/skills.js +1 -1
- package/dist/lib/staleness/writers/sources.d.ts +10 -1
- package/dist/lib/staleness/writers/sources.js +68 -1
- package/dist/lib/star-nudge.d.ts +45 -0
- package/dist/lib/star-nudge.js +91 -0
- package/dist/lib/startup/command-registry.d.ts +7 -1
- package/dist/lib/startup/command-registry.js +19 -3
- package/dist/lib/state.d.ts +2 -0
- package/dist/lib/state.js +17 -4
- package/dist/lib/subagents-registry.d.ts +2 -0
- package/dist/lib/subagents-registry.js +3 -0
- package/dist/lib/teams/parsers.js +214 -6
- package/dist/lib/teams/supervisor.d.ts +7 -0
- package/dist/lib/teams/supervisor.js +2 -1
- package/dist/lib/template.d.ts +1 -1
- package/dist/lib/template.js +1 -1
- package/dist/lib/triggers/webhook.js +36 -3
- package/dist/lib/types.d.ts +84 -0
- package/dist/lib/uninstall.js +1 -45
- package/dist/lib/version.d.ts +40 -0
- package/dist/lib/version.js +94 -16
- package/dist/lib/versions.d.ts +24 -0
- package/dist/lib/versions.js +269 -78
- package/dist/lib/workflows.d.ts +2 -0
- package/dist/lib/workflows.js +88 -0
- package/package.json +2 -1
- package/dist/commands/daemon.d.ts +0 -10
- package/dist/commands/daemon.js +0 -121
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { AGENTS, agentConfigDirName } from './agents.js';
|
|
4
|
+
import { supports } from './capabilities.js';
|
|
5
|
+
import { buildCommandSkillContent, commandSkillName, readSkillSourceCommandMarker, shouldInstallCommandAsSkill } from './command-skills.js';
|
|
6
|
+
import { commandAppliesTo, parseCommandMetadata } from './commands.js';
|
|
7
|
+
import { markdownToToml } from './convert.js';
|
|
8
|
+
import { safeJoin } from './paths.js';
|
|
9
|
+
import { subagentTarget } from './subagents-registry.js';
|
|
10
|
+
import { parseSubagentFrontmatter } from './subagents.js';
|
|
11
|
+
import { syncWorkflowToVersion } from './workflows.js';
|
|
12
|
+
const MANIFEST_FILE = '.agents-managed.json';
|
|
13
|
+
const MANIFEST_VERSION = 1;
|
|
14
|
+
const COPY_IGNORE = new Set(['.DS_Store', '.git', '.gitignore', '.venv', '__pycache__', 'node_modules']);
|
|
15
|
+
export function projectAgentRoot(projectRoot, agent) {
|
|
16
|
+
return path.join(projectRoot, agentConfigDirName(agent));
|
|
17
|
+
}
|
|
18
|
+
export function syncProjectResourcesToAgent(agent, version, projectAgentsDir) {
|
|
19
|
+
const projectRoot = path.dirname(projectAgentsDir);
|
|
20
|
+
const agentRoot = projectAgentRoot(projectRoot, agent);
|
|
21
|
+
const manifest = loadProjectManifest(agentRoot);
|
|
22
|
+
const result = { synced: [], skipped: [] };
|
|
23
|
+
const next = new Set();
|
|
24
|
+
if (manifest) {
|
|
25
|
+
for (const rel of manifest.paths)
|
|
26
|
+
removeManagedPath(agentRoot, rel);
|
|
27
|
+
}
|
|
28
|
+
syncProjectCommands(agent, version, projectAgentsDir, agentRoot, result, next);
|
|
29
|
+
syncProjectSkills(agent, version, projectAgentsDir, agentRoot, result, next);
|
|
30
|
+
syncProjectSubagents(agent, version, projectAgentsDir, projectRoot, agentRoot, manifest, result, next);
|
|
31
|
+
syncProjectWorkflows(agent, version, projectAgentsDir, projectRoot, agentRoot, result, next);
|
|
32
|
+
if (next.size > 0 || manifest) {
|
|
33
|
+
writeProjectManifest(agentRoot, Array.from(next).sort());
|
|
34
|
+
}
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
function loadProjectManifest(agentRoot) {
|
|
38
|
+
try {
|
|
39
|
+
const raw = JSON.parse(fs.readFileSync(path.join(agentRoot, MANIFEST_FILE), 'utf-8'));
|
|
40
|
+
if (raw.v !== MANIFEST_VERSION || !Array.isArray(raw.paths))
|
|
41
|
+
return null;
|
|
42
|
+
if (!raw.paths.every((p) => typeof p === 'string' && p.length > 0))
|
|
43
|
+
return null;
|
|
44
|
+
return { ...raw, paths: raw.paths.map(toPosixRel) };
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function writeProjectManifest(agentRoot, paths) {
|
|
51
|
+
fs.mkdirSync(agentRoot, { recursive: true });
|
|
52
|
+
const p = path.join(agentRoot, MANIFEST_FILE);
|
|
53
|
+
const tmp = p + '.tmp';
|
|
54
|
+
fs.writeFileSync(tmp, JSON.stringify({ v: MANIFEST_VERSION, paths }, null, 2));
|
|
55
|
+
fs.renameSync(tmp, p);
|
|
56
|
+
}
|
|
57
|
+
function removeManagedPath(agentRoot, rel) {
|
|
58
|
+
if (path.isAbsolute(rel) || rel.includes('..'))
|
|
59
|
+
return;
|
|
60
|
+
const target = path.resolve(agentRoot, rel);
|
|
61
|
+
const root = path.resolve(agentRoot);
|
|
62
|
+
if (target !== root && !target.startsWith(root + path.sep))
|
|
63
|
+
return;
|
|
64
|
+
removePath(target);
|
|
65
|
+
}
|
|
66
|
+
function removePath(p) {
|
|
67
|
+
try {
|
|
68
|
+
const st = fs.lstatSync(p);
|
|
69
|
+
if (st.isSymbolicLink() || st.isFile())
|
|
70
|
+
fs.unlinkSync(p);
|
|
71
|
+
else if (st.isDirectory())
|
|
72
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// already absent
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function pathExists(p) {
|
|
79
|
+
try {
|
|
80
|
+
fs.lstatSync(p);
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function copyDir(src, dest) {
|
|
88
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
89
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
90
|
+
if (entry.isSymbolicLink() || COPY_IGNORE.has(entry.name))
|
|
91
|
+
continue;
|
|
92
|
+
const s = safeJoin(src, entry.name);
|
|
93
|
+
const d = safeJoin(dest, entry.name);
|
|
94
|
+
if (entry.isDirectory())
|
|
95
|
+
copyDir(s, d);
|
|
96
|
+
else if (entry.isFile())
|
|
97
|
+
fs.copyFileSync(s, d);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function projectEntries(projectAgentsDir, kind) {
|
|
101
|
+
const dir = path.join(projectAgentsDir, kind);
|
|
102
|
+
try {
|
|
103
|
+
return fs.readdirSync(dir, { withFileTypes: true }).filter((entry) => !entry.name.startsWith('.'));
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Manifest paths are persisted to `.agents-managed.json`, which lives in the
|
|
111
|
+
* version-controlled project dir and therefore travels between machines. Store
|
|
112
|
+
* them POSIX-style: `path.join` yields `skills\myskill` on Windows, and a
|
|
113
|
+
* manifest carrying that would silently fail to match — and so fail to clean up
|
|
114
|
+
* its managed files — when the same project is synced on macOS or Linux.
|
|
115
|
+
* Normalizing on both write and read also repairs manifests written by earlier
|
|
116
|
+
* Windows builds.
|
|
117
|
+
*/
|
|
118
|
+
function toPosixRel(rel) {
|
|
119
|
+
return rel.replace(/\\/g, '/');
|
|
120
|
+
}
|
|
121
|
+
function record(kind, name, relPaths, result, manifestPaths) {
|
|
122
|
+
result.synced.push(`${kind}/${name}`);
|
|
123
|
+
for (const rel of relPaths)
|
|
124
|
+
manifestPaths.add(toPosixRel(rel));
|
|
125
|
+
}
|
|
126
|
+
function skip(dest, projectRoot, result) {
|
|
127
|
+
const rel = path.relative(projectRoot, dest);
|
|
128
|
+
result.skipped.push(rel);
|
|
129
|
+
console.warn(`Skipping project resource target ${rel}: already exists and is user-owned`);
|
|
130
|
+
}
|
|
131
|
+
function syncProjectCommands(agent, version, projectAgentsDir, agentRoot, result, manifestPaths) {
|
|
132
|
+
const cfg = AGENTS[agent];
|
|
133
|
+
const commandsAsSkills = shouldInstallCommandAsSkill(agent, version);
|
|
134
|
+
const supportsCommands = supports(agent, 'commands', version).ok;
|
|
135
|
+
if (!commandsAsSkills && !supportsCommands)
|
|
136
|
+
return;
|
|
137
|
+
const projectRoot = path.dirname(projectAgentsDir);
|
|
138
|
+
for (const entry of projectEntries(projectAgentsDir, 'commands')) {
|
|
139
|
+
if (!entry.isFile() || !entry.name.endsWith('.md'))
|
|
140
|
+
continue;
|
|
141
|
+
const name = entry.name.slice(0, -'.md'.length);
|
|
142
|
+
const srcFile = path.join(projectAgentsDir, 'commands', entry.name);
|
|
143
|
+
const metadata = parseCommandMetadata(srcFile);
|
|
144
|
+
if (!commandAppliesTo(agent, version, metadata).ok)
|
|
145
|
+
continue;
|
|
146
|
+
if (commandsAsSkills) {
|
|
147
|
+
const sourceMarker = readSkillSourceCommandMarker(name, [path.join(projectAgentsDir, 'skills')]);
|
|
148
|
+
if (pathExists(path.join(projectAgentsDir, 'skills', name)) && sourceMarker !== name)
|
|
149
|
+
continue;
|
|
150
|
+
const skillName = commandSkillName(name);
|
|
151
|
+
const rel = path.join('skills', skillName);
|
|
152
|
+
const destDir = path.join(agentRoot, rel);
|
|
153
|
+
if (pathExists(destDir)) {
|
|
154
|
+
skip(destDir, projectRoot, result);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
158
|
+
fs.writeFileSync(path.join(destDir, 'SKILL.md'), buildCommandSkillContent(name, srcFile), 'utf-8');
|
|
159
|
+
record('commands', name, [rel], result, manifestPaths);
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
const ext = cfg.format === 'toml' ? '.toml' : '.md';
|
|
163
|
+
const rel = path.join(cfg.commandsSubdir, `${name}${ext}`);
|
|
164
|
+
const destFile = path.join(agentRoot, rel);
|
|
165
|
+
if (pathExists(destFile)) {
|
|
166
|
+
skip(destFile, projectRoot, result);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
fs.mkdirSync(path.dirname(destFile), { recursive: true });
|
|
170
|
+
if (cfg.format === 'toml') {
|
|
171
|
+
fs.writeFileSync(destFile, markdownToToml(name, fs.readFileSync(srcFile, 'utf-8')), 'utf-8');
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
fs.copyFileSync(srcFile, destFile);
|
|
175
|
+
}
|
|
176
|
+
record('commands', name, [rel], result, manifestPaths);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
function syncProjectSkills(agent, version, projectAgentsDir, agentRoot, result, manifestPaths) {
|
|
180
|
+
if (!supports(agent, 'skills', version).ok)
|
|
181
|
+
return;
|
|
182
|
+
const projectRoot = path.dirname(projectAgentsDir);
|
|
183
|
+
for (const entry of projectEntries(projectAgentsDir, 'skills')) {
|
|
184
|
+
if (!entry.isDirectory())
|
|
185
|
+
continue;
|
|
186
|
+
const srcDir = path.join(projectAgentsDir, 'skills', entry.name);
|
|
187
|
+
if (!fs.existsSync(path.join(srcDir, 'SKILL.md')))
|
|
188
|
+
continue;
|
|
189
|
+
const rel = path.join('skills', entry.name);
|
|
190
|
+
const destDir = path.join(agentRoot, rel);
|
|
191
|
+
if (pathExists(destDir)) {
|
|
192
|
+
skip(destDir, projectRoot, result);
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
copyDir(srcDir, destDir);
|
|
196
|
+
record('skills', entry.name, [rel], result, manifestPaths);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function readProjectSubagents(projectAgentsDir) {
|
|
200
|
+
const map = new Map();
|
|
201
|
+
for (const entry of projectEntries(projectAgentsDir, 'subagents')) {
|
|
202
|
+
if (!entry.isDirectory())
|
|
203
|
+
continue;
|
|
204
|
+
const dir = path.join(projectAgentsDir, 'subagents', entry.name);
|
|
205
|
+
const agentMd = path.join(dir, 'AGENT.md');
|
|
206
|
+
if (!fs.existsSync(agentMd))
|
|
207
|
+
continue;
|
|
208
|
+
const frontmatter = parseSubagentFrontmatter(agentMd);
|
|
209
|
+
if (!frontmatter)
|
|
210
|
+
continue;
|
|
211
|
+
const files = fs.readdirSync(dir).filter((f) => f.endsWith('.md')).sort();
|
|
212
|
+
map.set(entry.name, { name: entry.name, path: dir, files, frontmatter });
|
|
213
|
+
}
|
|
214
|
+
return map;
|
|
215
|
+
}
|
|
216
|
+
function syncProjectSubagents(agent, version, projectAgentsDir, projectRoot, agentRoot, manifest, result, manifestPaths) {
|
|
217
|
+
if (!supports(agent, 'subagents', version).ok)
|
|
218
|
+
return;
|
|
219
|
+
const target = subagentTarget(agent);
|
|
220
|
+
if (!target)
|
|
221
|
+
return;
|
|
222
|
+
const all = readProjectSubagents(projectAgentsDir);
|
|
223
|
+
const dir = target.dir(projectRoot);
|
|
224
|
+
const targetDirRel = toPosixRel(path.relative(agentRoot, dir));
|
|
225
|
+
const hadManagedTarget = manifest?.paths.some((rel) => rel === targetDirRel || rel.startsWith(targetDirRel + '/')) ?? false;
|
|
226
|
+
for (const sub of all.values()) {
|
|
227
|
+
const occupied = target.occupied(dir, sub.name);
|
|
228
|
+
const existing = occupied.find((entry) => pathExists(entry.path));
|
|
229
|
+
if (existing) {
|
|
230
|
+
skip(existing.path, projectRoot, result);
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
target.write(dir, sub);
|
|
235
|
+
record('subagents', sub.name, occupied.map((entry) => path.relative(agentRoot, entry.path)), result, manifestPaths);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// Malformed source or unsupported transform; skip this item.
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const syncedNames = result.synced
|
|
242
|
+
.filter((name) => name.startsWith('subagents/'))
|
|
243
|
+
.map((name) => name.slice('subagents/'.length))
|
|
244
|
+
.filter((name) => all.has(name))
|
|
245
|
+
.map((name) => all.get(name));
|
|
246
|
+
if (target.finalize && (syncedNames.length > 0 || hadManagedTarget)) {
|
|
247
|
+
target.finalize(dir, syncedNames);
|
|
248
|
+
for (const entry of target.finalizeOccupied?.(dir) ?? []) {
|
|
249
|
+
// Same normalization as record(): this is the one manifest write that
|
|
250
|
+
// doesn't funnel through it (the parent subagent index, e.g. Kimi's
|
|
251
|
+
// agents/_agents-cli.yaml).
|
|
252
|
+
manifestPaths.add(toPosixRel(path.relative(agentRoot, entry.path)));
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
function workflowManagedRelPaths(agent, projectRoot, name, workflowDir) {
|
|
257
|
+
if (agent === 'kimi')
|
|
258
|
+
return [path.join('.kimi-code', 'skills', name)];
|
|
259
|
+
if (agent === 'goose') {
|
|
260
|
+
const rels = [path.join('.config', 'goose', 'recipes', `${name}.yaml`)];
|
|
261
|
+
const subagentsDir = path.join(workflowDir, 'subagents');
|
|
262
|
+
let hasSubagents = false;
|
|
263
|
+
try {
|
|
264
|
+
hasSubagents = fs.readdirSync(subagentsDir).some((f) => f.endsWith('.md'));
|
|
265
|
+
}
|
|
266
|
+
catch {
|
|
267
|
+
hasSubagents = false;
|
|
268
|
+
}
|
|
269
|
+
if (hasSubagents)
|
|
270
|
+
rels.push(path.join('.config', 'goose', 'recipes', `${name}.subrecipes`));
|
|
271
|
+
return rels;
|
|
272
|
+
}
|
|
273
|
+
if (agent === 'openclaw')
|
|
274
|
+
return [path.join('.openclaw', 'workflows', `${name}.lobster`)];
|
|
275
|
+
return [path.join(agentConfigDirName(agent), 'workflows', name)];
|
|
276
|
+
}
|
|
277
|
+
function syncProjectWorkflows(agent, version, projectAgentsDir, projectRoot, agentRoot, result, manifestPaths) {
|
|
278
|
+
if (!supports(agent, 'workflows', version).ok)
|
|
279
|
+
return;
|
|
280
|
+
if (agent === 'antigravity')
|
|
281
|
+
return;
|
|
282
|
+
for (const entry of projectEntries(projectAgentsDir, 'workflows')) {
|
|
283
|
+
if (!entry.isDirectory())
|
|
284
|
+
continue;
|
|
285
|
+
const workflowDir = path.join(projectAgentsDir, 'workflows', entry.name);
|
|
286
|
+
if (!fs.existsSync(path.join(workflowDir, 'WORKFLOW.md')))
|
|
287
|
+
continue;
|
|
288
|
+
const rels = workflowManagedRelPaths(agent, projectRoot, entry.name, workflowDir);
|
|
289
|
+
const existing = rels.map((rel) => path.join(projectRoot, rel)).find((dest) => pathExists(dest));
|
|
290
|
+
if (existing) {
|
|
291
|
+
skip(existing, projectRoot, result);
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
let success = false;
|
|
295
|
+
if (agent === 'kimi' || agent === 'goose' || agent === 'openclaw') {
|
|
296
|
+
success = syncWorkflowToVersion(workflowDir, entry.name, agent, projectRoot).success;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
copyDir(workflowDir, path.join(agentRoot, 'workflows', entry.name));
|
|
300
|
+
success = true;
|
|
301
|
+
}
|
|
302
|
+
if (success) {
|
|
303
|
+
record('workflows', entry.name, rels.map((rel) => path.relative(agentRoot, path.join(projectRoot, rel))), result, manifestPaths);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
package/dist/lib/pty-client.d.ts
CHANGED
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
* Thin client that connects to the PTY sidecar server over unix socket.
|
|
5
5
|
* Each call opens a connection, sends a JSON request, reads the JSON response, and closes.
|
|
6
6
|
*/
|
|
7
|
+
export interface ServerSpawnArgs {
|
|
8
|
+
bin: string;
|
|
9
|
+
args: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface ServerExit {
|
|
12
|
+
code: number | null;
|
|
13
|
+
signal: NodeJS.Signals | null;
|
|
14
|
+
}
|
|
7
15
|
/** JSON response envelope from the PTY server. */
|
|
8
16
|
export interface PtyResponse {
|
|
9
17
|
ok: boolean;
|
|
@@ -15,6 +23,25 @@ export interface PtyResponse {
|
|
|
15
23
|
* Auto-starts the server if not running.
|
|
16
24
|
*/
|
|
17
25
|
export declare function ptyRequest(action: string, id?: string, params?: Record<string, any>): Promise<PtyResponse>;
|
|
26
|
+
export declare function getServerSpawnArgs(options?: {
|
|
27
|
+
isStandaloneExecutable?: boolean;
|
|
28
|
+
/** Physical binary path (test seam). Defaults to `process.execPath`. */
|
|
29
|
+
execPath?: string;
|
|
30
|
+
/** Locate a real `node` (test seam). Defaults to `which/where node`. */
|
|
31
|
+
resolveNode?: () => string | undefined;
|
|
32
|
+
/** File-existence check (test seam). Defaults to `fs.existsSync`. */
|
|
33
|
+
fileExists?: (p: string) => boolean;
|
|
34
|
+
}): ServerSpawnArgs;
|
|
35
|
+
export declare function isBunStandaloneExecutable(moduleUrl?: string): boolean;
|
|
36
|
+
export declare function readRecentLogLines(logPath: string, maxLines?: number): string[];
|
|
37
|
+
export declare function buildPtyStartFailureMessage(details: {
|
|
38
|
+
timeoutMs: number;
|
|
39
|
+
spawn: ServerSpawnArgs;
|
|
40
|
+
exit?: ServerExit;
|
|
41
|
+
spawnError?: Error;
|
|
42
|
+
lastReadinessError?: Error;
|
|
43
|
+
logPath: string;
|
|
44
|
+
}): string;
|
|
18
45
|
/**
|
|
19
46
|
* Parse escape sequences in user input strings.
|
|
20
47
|
* Handles: \n \r \t \e \xHH \\
|
package/dist/lib/pty-client.js
CHANGED
|
@@ -11,8 +11,10 @@ import { fileURLToPath } from 'url';
|
|
|
11
11
|
import * as path from 'path';
|
|
12
12
|
import { getSocketPath, getPtyLogPath, isPtyServerRunning } from './pty-server.js';
|
|
13
13
|
import { backgroundSpawnOptions } from './platform/process.js';
|
|
14
|
+
import { BUN_VIRTUAL_ROOT } from './cli-entry.js';
|
|
14
15
|
const CONNECT_TIMEOUT_MS = 5000;
|
|
15
16
|
const RESPONSE_TIMEOUT_MS = 30000;
|
|
17
|
+
const START_TIMEOUT_MS = 5000;
|
|
16
18
|
const IS_WINDOWS = process.platform === 'win32';
|
|
17
19
|
/**
|
|
18
20
|
* Send a request to the PTY server and return the response.
|
|
@@ -36,18 +38,44 @@ async function ensureServer() {
|
|
|
36
38
|
// Find the entry point to spawn the server
|
|
37
39
|
const { bin, args } = getServerSpawnArgs();
|
|
38
40
|
const logPath = getPtyLogPath();
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
let logFd;
|
|
42
|
+
try {
|
|
43
|
+
logFd = fs.openSync(logPath, 'a');
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
47
|
+
throw new Error([
|
|
48
|
+
'PTY server failed to start before spawning.',
|
|
49
|
+
`Spawned: ${formatCommand({ bin, args })}`,
|
|
50
|
+
`Log: ${logPath}`,
|
|
51
|
+
`Log open error: ${message}`,
|
|
52
|
+
].join('\n'));
|
|
53
|
+
}
|
|
54
|
+
let child;
|
|
55
|
+
try {
|
|
56
|
+
child = spawn(bin, args, {
|
|
57
|
+
stdio: ['ignore', logFd, logFd],
|
|
58
|
+
...backgroundSpawnOptions({ fdStdio: true }),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
finally {
|
|
62
|
+
fs.closeSync(logFd);
|
|
63
|
+
}
|
|
64
|
+
let childExit;
|
|
65
|
+
let childError;
|
|
66
|
+
let lastReadinessError;
|
|
67
|
+
child.once('exit', (code, signal) => {
|
|
68
|
+
childExit = { code, signal };
|
|
69
|
+
});
|
|
70
|
+
child.once('error', (err) => {
|
|
71
|
+
childError = err;
|
|
43
72
|
});
|
|
44
73
|
child.unref();
|
|
45
|
-
fs.closeSync(logFd);
|
|
46
74
|
// Wait for the server to become reachable. On Unix the socket file appearing is
|
|
47
75
|
// a cheap readiness signal; on Windows the named pipe is not a filesystem object
|
|
48
76
|
// (fs.existsSync always returns false), so we just attempt the ping directly.
|
|
49
77
|
const socketPath = getSocketPath();
|
|
50
|
-
const deadline = Date.now() +
|
|
78
|
+
const deadline = Date.now() + START_TIMEOUT_MS;
|
|
51
79
|
while (Date.now() < deadline) {
|
|
52
80
|
if (IS_WINDOWS || fs.existsSync(socketPath)) {
|
|
53
81
|
// Verify we can connect
|
|
@@ -55,15 +83,50 @@ async function ensureServer() {
|
|
|
55
83
|
await sendRequest({ action: 'ping' });
|
|
56
84
|
return;
|
|
57
85
|
}
|
|
58
|
-
catch {
|
|
59
|
-
|
|
86
|
+
catch (err) {
|
|
87
|
+
lastReadinessError = err instanceof Error ? err : new Error(String(err));
|
|
60
88
|
}
|
|
61
89
|
}
|
|
90
|
+
if (childError || childExit)
|
|
91
|
+
break;
|
|
62
92
|
await new Promise(r => setTimeout(r, 100));
|
|
63
93
|
}
|
|
64
|
-
throw new Error(
|
|
94
|
+
throw new Error(buildPtyStartFailureMessage({
|
|
95
|
+
timeoutMs: START_TIMEOUT_MS,
|
|
96
|
+
spawn: { bin, args },
|
|
97
|
+
exit: childExit,
|
|
98
|
+
spawnError: childError,
|
|
99
|
+
lastReadinessError,
|
|
100
|
+
logPath,
|
|
101
|
+
}));
|
|
65
102
|
}
|
|
66
|
-
function getServerSpawnArgs() {
|
|
103
|
+
export function getServerSpawnArgs(options = {}) {
|
|
104
|
+
const isStandaloneExecutable = options.isStandaloneExecutable
|
|
105
|
+
?? isBunStandaloneExecutable();
|
|
106
|
+
if (isStandaloneExecutable) {
|
|
107
|
+
// A Bun `--compile` standalone binary cannot `require()` a native addon, so
|
|
108
|
+
// running the PTY sidecar AS this binary fails to load node-pty's pty.node
|
|
109
|
+
// (fatal on macOS; see #315). Prefer a real `node` running the dist/index.js
|
|
110
|
+
// that ships beside the binary — there node-pty loads from the on-disk
|
|
111
|
+
// prebuild. We can't do `<binary> dist/index.js` (the standalone misparses a
|
|
112
|
+
// script arg as a subcommand), so a genuine `node` is required. Fall back to
|
|
113
|
+
// the binary itself only when no node / no dist is found (a bare standalone
|
|
114
|
+
// install with no Node — PTY may then be unavailable, but nothing else can
|
|
115
|
+
// load the addon anyway).
|
|
116
|
+
const node = (options.resolveNode ?? resolveNodeExecutable)();
|
|
117
|
+
const exists = options.fileExists ?? fs.existsSync;
|
|
118
|
+
const execPath = options.execPath ?? process.execPath;
|
|
119
|
+
if (node) {
|
|
120
|
+
try {
|
|
121
|
+
const distIndex = path.join(path.dirname(execPath), '..', 'index.js');
|
|
122
|
+
if (exists(distIndex)) {
|
|
123
|
+
return { bin: node, args: [distIndex, 'pty', '_server'] };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch { }
|
|
127
|
+
}
|
|
128
|
+
return { bin: process.execPath, args: ['pty', '_server'] };
|
|
129
|
+
}
|
|
67
130
|
// Prefer the dist/index.js from the same installation as this code.
|
|
68
131
|
// This avoids version mismatch when a globally installed `agents` is older.
|
|
69
132
|
try {
|
|
@@ -86,6 +149,69 @@ function getServerSpawnArgs() {
|
|
|
86
149
|
catch { }
|
|
87
150
|
return { bin: 'agents', args: ['pty', '_server'] };
|
|
88
151
|
}
|
|
152
|
+
export function isBunStandaloneExecutable(moduleUrl = import.meta.url) {
|
|
153
|
+
return BUN_VIRTUAL_ROOT.test(moduleUrl);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Locate a real `node` on PATH for running the sidecar's dist/index.js from a
|
|
157
|
+
* Bun standalone binary (which cannot itself load native addons). Returns
|
|
158
|
+
* undefined when no node is found — the caller then falls back to the binary.
|
|
159
|
+
*/
|
|
160
|
+
function resolveNodeExecutable() {
|
|
161
|
+
try {
|
|
162
|
+
const lookup = IS_WINDOWS ? 'where node' : 'which node';
|
|
163
|
+
const node = execSync(lookup, { encoding: 'utf-8' }).split(/\r?\n/)[0].trim();
|
|
164
|
+
if (node && fs.existsSync(node))
|
|
165
|
+
return node;
|
|
166
|
+
}
|
|
167
|
+
catch { }
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
export function readRecentLogLines(logPath, maxLines = 20) {
|
|
171
|
+
try {
|
|
172
|
+
if (!fs.existsSync(logPath))
|
|
173
|
+
return [];
|
|
174
|
+
return fs.readFileSync(logPath, 'utf-8')
|
|
175
|
+
.split(/\r?\n/)
|
|
176
|
+
.filter(line => line.trim().length > 0)
|
|
177
|
+
.slice(-maxLines);
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
181
|
+
return [`Unable to read PTY server log: ${message}`];
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export function buildPtyStartFailureMessage(details) {
|
|
185
|
+
const lines = [
|
|
186
|
+
`PTY server failed to start within ${Math.round(details.timeoutMs / 1000)} seconds.`,
|
|
187
|
+
`Spawned: ${formatCommand(details.spawn)}`,
|
|
188
|
+
];
|
|
189
|
+
if (details.spawnError) {
|
|
190
|
+
lines.push(`Spawn error: ${details.spawnError.message}`);
|
|
191
|
+
}
|
|
192
|
+
if (details.exit) {
|
|
193
|
+
const reason = details.exit.signal
|
|
194
|
+
? `signal ${details.exit.signal}`
|
|
195
|
+
: `code ${details.exit.code ?? 'unknown'}`;
|
|
196
|
+
lines.push(`PTY server process exited with ${reason} before listening.`);
|
|
197
|
+
}
|
|
198
|
+
if (details.lastReadinessError) {
|
|
199
|
+
lines.push(`Last readiness error: ${details.lastReadinessError.message}`);
|
|
200
|
+
}
|
|
201
|
+
lines.push(`Log: ${details.logPath}`);
|
|
202
|
+
const logLines = readRecentLogLines(details.logPath);
|
|
203
|
+
if (logLines.length > 0) {
|
|
204
|
+
lines.push('Recent PTY server log:');
|
|
205
|
+
lines.push(...logLines.map(line => ` ${line}`));
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
lines.push('No PTY server log output was written.');
|
|
209
|
+
}
|
|
210
|
+
return lines.join('\n');
|
|
211
|
+
}
|
|
212
|
+
function formatCommand(spawnArgs) {
|
|
213
|
+
return [spawnArgs.bin, ...spawnArgs.args].map((part) => JSON.stringify(part)).join(' ');
|
|
214
|
+
}
|
|
89
215
|
/**
|
|
90
216
|
* Send a JSON request over the unix socket and return the parsed response.
|
|
91
217
|
*/
|
package/dist/lib/refresh.js
CHANGED
|
@@ -16,7 +16,7 @@ import { capableAgents } from './capabilities.js';
|
|
|
16
16
|
import { AGENTS, ALL_AGENT_IDS, getAllCliStates, registerMcpToTargets, agentLabel, } from './agents.js';
|
|
17
17
|
import { readManifest, MANIFEST_FILENAME } from './manifest.js';
|
|
18
18
|
import { getUserAgentsDir } from './state.js';
|
|
19
|
-
import { installVersion, listInstalledVersions, getGlobalDefault, setGlobalDefault, getVersionHomePath, syncResourcesToVersion, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, promptResourceSelection, resolveConfiguredAgentTargets, } from './versions.js';
|
|
19
|
+
import { installVersion, listInstalledVersions, isVersionIsolated, getGlobalDefault, setGlobalDefault, getVersionHomePath, syncResourcesToVersion, getAvailableResources, getActuallySyncedResources, getNewResources, getProjectOnlyResources, hasNewResources, promptNewResourceSelection, promptResourceSelection, resolveConfiguredAgentTargets, } from './versions.js';
|
|
20
20
|
import { listCliStatus, installCli, describeMethod, describeCheck, selectInstallMethod, } from './cli-resources.js';
|
|
21
21
|
import { ensureShimCurrent, isShimsInPath, addShimsToPath, getPathSetupInstructions, switchConfigSymlink, switchHomeFileSymlinks, } from './shims.js';
|
|
22
22
|
import { parseHookManifest, registerHooksToSettings } from './hooks.js';
|
|
@@ -133,13 +133,9 @@ export async function refresh(options = {}) {
|
|
|
133
133
|
actuallySynced.plugins.length > 0;
|
|
134
134
|
try {
|
|
135
135
|
let selection;
|
|
136
|
+
let forceFullSync = false;
|
|
136
137
|
if (skipPrompts) {
|
|
137
|
-
|
|
138
|
-
selection = {
|
|
139
|
-
commands: 'all', skills: 'all', hooks: 'all', memory: 'all',
|
|
140
|
-
mcp: 'all', permissions: 'all', subagents: 'all', plugins: 'all',
|
|
141
|
-
};
|
|
142
|
-
}
|
|
138
|
+
forceFullSync = true;
|
|
143
139
|
}
|
|
144
140
|
else if (!hasAnySynced) {
|
|
145
141
|
console.log(chalk.yellow(`\n${agentLabel(agentId)}@${defaultVer} has no synced resources.`));
|
|
@@ -153,8 +149,11 @@ export async function refresh(options = {}) {
|
|
|
153
149
|
if (userSelection)
|
|
154
150
|
selection = userSelection;
|
|
155
151
|
}
|
|
156
|
-
|
|
157
|
-
|
|
152
|
+
else {
|
|
153
|
+
forceFullSync = true;
|
|
154
|
+
}
|
|
155
|
+
if (forceFullSync || (selection && Object.keys(selection).length > 0)) {
|
|
156
|
+
const syncResult = syncResourcesToVersion(agentId, defaultVer, selection, forceFullSync ? { force: true } : undefined);
|
|
158
157
|
const synced = [];
|
|
159
158
|
if (syncResult.commands)
|
|
160
159
|
synced.push('commands');
|
|
@@ -231,7 +230,12 @@ export async function refresh(options = {}) {
|
|
|
231
230
|
}
|
|
232
231
|
const selectedVersions = [];
|
|
233
232
|
for (const agentId of agentsNeedingDefault) {
|
|
234
|
-
|
|
233
|
+
// Isolated copies are not default-eligible — `agents use` refuses them and
|
|
234
|
+
// setting one here would also switch the config symlink, pointing the user's
|
|
235
|
+
// real ~/.<agent> at an isolated home. Keep them out of the picker entirely.
|
|
236
|
+
const versions = listInstalledVersions(agentId).filter((v) => !isVersionIsolated(agentId, v));
|
|
237
|
+
if (versions.length === 0)
|
|
238
|
+
continue;
|
|
235
239
|
const agent = AGENTS[agentId];
|
|
236
240
|
const shouldSwitch = await select({
|
|
237
241
|
message: `${agentLabel(agent.id)} has no default version. Set one now?`,
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level resource profiles.
|
|
3
|
+
*
|
|
4
|
+
* These are distinct from model-provider run profiles in lib/profiles.ts. A
|
|
5
|
+
* resource profile is a global mode switch stored in agents.yaml that filters
|
|
6
|
+
* the resolved DotAgents resource view and secrets bundles.
|
|
7
|
+
*/
|
|
8
|
+
import type { ResourceProfilePreset } from './types.js';
|
|
9
|
+
export type ProfiledResourceKind = 'commands' | 'skills' | 'hooks' | 'subagents' | 'plugins' | 'workflows' | 'permissions' | 'mcp' | 'memory' | 'secrets';
|
|
10
|
+
export type PatternedProfileKind = Exclude<ProfiledResourceKind, 'memory' | 'secrets'>;
|
|
11
|
+
export interface ActiveResourceProfile {
|
|
12
|
+
name: string;
|
|
13
|
+
preset: ResourceProfilePreset;
|
|
14
|
+
}
|
|
15
|
+
export declare function validateResourceProfileName(name: string): void;
|
|
16
|
+
export declare function listResourceProfileNames(): string[];
|
|
17
|
+
export declare function getResourceProfilePreset(name: string): ResourceProfilePreset | null;
|
|
18
|
+
export declare function getActiveResourceProfileName(): string | null;
|
|
19
|
+
export declare function getActiveResourceProfile(): ActiveResourceProfile | null;
|
|
20
|
+
export declare function upsertResourceProfilePreset(name: string, preset: ResourceProfilePreset): void;
|
|
21
|
+
export declare function setActiveResourceProfile(name: string | null): void;
|
|
22
|
+
export declare function patternedProfileKinds(): PatternedProfileKind[];
|
|
23
|
+
export declare function activeRulesPreset(): string | null;
|
|
24
|
+
export declare function filterNamesForActiveResourceProfile(kind: ProfiledResourceKind, names: string[], sourceMap?: Map<string, string>): string[];
|
|
25
|
+
export declare function isNameActiveInResourceProfile(kind: ProfiledResourceKind, name: string, source?: string): boolean;
|
|
26
|
+
export declare function assertNameActiveInResourceProfile(kind: ProfiledResourceKind, name: string): void;
|