@alphafox/cli 0.3.11 → 0.3.13
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/README.md +31 -4
- package/dist/index.d.ts +1 -0
- package/dist/install/types.d.ts +2 -0
- package/dist/install/wizard.js +3 -26
- package/dist/skills/agent-links.d.ts +29 -0
- package/dist/skills/agent-links.js +217 -0
- package/dist/skills/manager.d.ts +8 -0
- package/dist/skills/manager.js +1 -0
- package/dist/skills/run-command.js +23 -6
- package/dist/skills-manifest.json +41 -41
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/alphafox-cli-installation-guide.md +29 -2
- package/docs/release-supply-chain.md +4 -4
- package/package.json +2 -1
- package/scripts/uninstall.cjs +438 -0
- package/skills/account/SKILL.md +1 -1
- package/skills/admin/SKILL.md +1 -1
- package/skills/alphafox/SKILL.md +59 -5
- package/skills/alphafox-shared/SKILL.md +11 -2
- package/skills/auth/SKILL.md +1 -1
- package/skills/cache/SKILL.md +1 -1
- package/skills/engine-backtest/SKILL.md +1 -1
- package/skills/exchange/SKILL.md +1 -1
- package/skills/market/SKILL.md +1 -1
- package/skills/notification/SKILL.md +1 -1
- package/skills/strategy/SKILL.md +46 -9
- package/skills/trading/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,32 @@ Locally modified Skills are reported and preserved; use
|
|
|
54
54
|
`alphafox skills sync --force --yes` only when you intend to replace them.
|
|
55
55
|
Restart the AI tool after a sync.
|
|
56
56
|
|
|
57
|
+
## Uninstall
|
|
58
|
+
|
|
59
|
+
This is **not** an `alphafox` subcommand. The script removes the global npm
|
|
60
|
+
package, Agent Skills (including Claude / Cursor / Codex / Grok links), local
|
|
61
|
+
config, login tokens, and Engine backtest caches. It does **not** delete
|
|
62
|
+
server-side traders or account data.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
curl -fsSL https://raw.githubusercontent.com/alphafoxai/alphafox-cli/main/scripts/uninstall.cjs | node -- --yes
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Preview first:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
curl -fsSL https://raw.githubusercontent.com/alphafoxai/alphafox-cli/main/scripts/uninstall.cjs | node -- --dry-run
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
From a git checkout:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
node scripts/uninstall.cjs --dry-run
|
|
78
|
+
node scripts/uninstall.cjs --yes
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Restart AI tools afterwards so Skills unload.
|
|
82
|
+
|
|
57
83
|
## Quick start
|
|
58
84
|
|
|
59
85
|
After Method 1 or 2:
|
|
@@ -86,10 +112,11 @@ skills then use public `operationId`s; an explicit local-execution skill may
|
|
|
86
112
|
call its co-versioned built-in command.
|
|
87
113
|
|
|
88
114
|
`alphafox install` (and the [Agent install guide](docs/alphafox-cli-installation-guide.md))
|
|
89
|
-
verify the packaged Skills manifest
|
|
90
|
-
|
|
91
|
-
Use `alphafox skills status` to inspect missing,
|
|
92
|
-
`alphafox skills sync` to repair safe
|
|
115
|
+
verify the packaged Skills manifest, copy it into `~/.agents/skills`, and link
|
|
116
|
+
each Skill into `~/.claude/skills` (plus `~/.cursor/skills` / `~/.codex/skills`
|
|
117
|
+
when those agents exist). Use `alphafox skills status` to inspect missing,
|
|
118
|
+
stale, modified, or unlinked Skills and `alphafox skills sync` to repair safe
|
|
119
|
+
drift — including Claude Code links when the canonical bundle is already current.
|
|
93
120
|
|
|
94
121
|
## Docs
|
|
95
122
|
|
package/dist/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export { parseRequestBodyFlags, loadJsonArg } from "./commands/request-body";
|
|
|
18
18
|
export { parseInstallArgs, runInstallWizard, semverLessThan, skillsListHasAlphafox, } from "./install/wizard";
|
|
19
19
|
export { AGENT_INSTALL_GUIDE_BLOB_URL, AGENT_INSTALL_GUIDE_URL, SKILLS_GITHUB_SOURCE, } from "./install/types";
|
|
20
20
|
export { buildSkillsManifest, inspectSkills, loadAndVerifySkillsManifest, loadSkillsState, syncSkills, writeSkillsManifest, } from "./skills/manager";
|
|
21
|
+
export type { AgentSkillLinkStatus } from "./skills/manager";
|
|
21
22
|
export { inspectCurrentSkills, installedSkillsRoot, skillsStatePath, syncCurrentSkills, } from "./skills/run-command";
|
|
22
23
|
export { executeCliUpdate, parseUpdateArgs, } from "./update/run-command";
|
|
23
24
|
export { formatUpdateNotice, maybeNotifyCliUpdate, shouldSkipUpdateCheck, } from "./update/notify";
|
package/dist/install/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { AgentSkillLinkStatus } from "../skills/manager";
|
|
1
2
|
/** @deprecated AlphaFox Skills updates must use the verified npm package bundle. */
|
|
2
3
|
export declare const SKILLS_GITHUB_SOURCE = "alphafoxai/alphafox-cli";
|
|
3
4
|
export declare const SKILLS_NAME_PREFIX = "alphafox-";
|
|
@@ -22,6 +23,7 @@ export interface InstallSkillsStep {
|
|
|
22
23
|
readonly removed?: readonly string[];
|
|
23
24
|
readonly blocked?: readonly string[];
|
|
24
25
|
readonly backupDir?: string;
|
|
26
|
+
readonly agentLinks?: readonly AgentSkillLinkStatus[];
|
|
25
27
|
readonly restartRequired?: boolean;
|
|
26
28
|
}
|
|
27
29
|
export interface InstallAuthStep {
|
package/dist/install/wizard.js
CHANGED
|
@@ -17,7 +17,6 @@ const exec_1 = require("./exec");
|
|
|
17
17
|
const package_root_1 = require("./package-root");
|
|
18
18
|
const types_1 = require("./types");
|
|
19
19
|
const NPM_TIMEOUT_MS = 120_000;
|
|
20
|
-
const SKILLS_TIMEOUT_MS = 120_000;
|
|
21
20
|
function parseInstallArgs(args) {
|
|
22
21
|
let noAuth = false;
|
|
23
22
|
let help = false;
|
|
@@ -58,7 +57,7 @@ function nextSteps(input) {
|
|
|
58
57
|
if (input.auth.action === "skipped" || input.auth.action === "planned") {
|
|
59
58
|
steps.push("alphafox auth login --browser --format json --no-input", "alphafox auth login --no-wait --format json --no-input");
|
|
60
59
|
}
|
|
61
|
-
steps.push("alphafox doctor --format json --no-input", `Agent 安装指南:${types_1.AGENT_INSTALL_GUIDE_BLOB_URL}
|
|
60
|
+
steps.push("alphafox doctor --format json --no-input", `Agent 安装指南:${types_1.AGENT_INSTALL_GUIDE_BLOB_URL}`, "登录并重启后,按 alphafox skill 的 After install 向用户展示新人引导。");
|
|
62
61
|
if (input.dryRun) {
|
|
63
62
|
steps.unshift("这是 --dry-run,去掉该参数再运行才会真正安装。");
|
|
64
63
|
}
|
|
@@ -218,30 +217,7 @@ async function stepInstallSkills(flags, runner) {
|
|
|
218
217
|
? `将同步 Skills ${manifest.packageVersion}(${source})`
|
|
219
218
|
: `正在同步 AI Skills ${manifest.packageVersion}…`);
|
|
220
219
|
try {
|
|
221
|
-
const result = await (0,
|
|
222
|
-
manifest,
|
|
223
|
-
packageRoot: source,
|
|
224
|
-
installedRoot: (0, run_command_1.installedSkillsRoot)(runner.env),
|
|
225
|
-
statePath: (0, run_command_1.skillsStatePath)(runner.env),
|
|
226
|
-
dryRun: flags.dryRun,
|
|
227
|
-
force: false,
|
|
228
|
-
}, {
|
|
229
|
-
install: async (names) => {
|
|
230
|
-
await runner.exec("npx", [
|
|
231
|
-
"-y",
|
|
232
|
-
"skills",
|
|
233
|
-
"add",
|
|
234
|
-
source,
|
|
235
|
-
"-y",
|
|
236
|
-
"-g",
|
|
237
|
-
"--skill",
|
|
238
|
-
...names,
|
|
239
|
-
], { timeoutMs: SKILLS_TIMEOUT_MS });
|
|
240
|
-
},
|
|
241
|
-
remove: async (names) => {
|
|
242
|
-
await runner.exec("npx", ["-y", "skills", "remove", ...names, "-y", "-g"], { timeoutMs: SKILLS_TIMEOUT_MS });
|
|
243
|
-
},
|
|
244
|
-
});
|
|
220
|
+
const result = await (0, run_command_1.syncCurrentSkills)({ force: false, dryRun: flags.dryRun }, runner.env, { runner, packageRoot: source });
|
|
245
221
|
const action = result.blocked.length > 0
|
|
246
222
|
? "blocked"
|
|
247
223
|
: result.action === "planned"
|
|
@@ -268,6 +244,7 @@ async function stepInstallSkills(flags, runner) {
|
|
|
268
244
|
removed: result.removed,
|
|
269
245
|
blocked: result.blocked,
|
|
270
246
|
backupDir: result.backupDir,
|
|
247
|
+
agentLinks: result.status.agentLinks,
|
|
271
248
|
restartRequired: result.restartRequired,
|
|
272
249
|
};
|
|
273
250
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type AgentSkillLinkStatus, type SkillsStatus, type SkillsSyncResult } from "./manager";
|
|
2
|
+
export interface AgentSkillTarget {
|
|
3
|
+
readonly id: "claude-code" | "cursor" | "codex";
|
|
4
|
+
readonly required: boolean;
|
|
5
|
+
readonly home: string;
|
|
6
|
+
readonly skillsDir: string;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentLinkChange {
|
|
9
|
+
readonly agent: AgentSkillTarget["id"];
|
|
10
|
+
readonly name: string;
|
|
11
|
+
}
|
|
12
|
+
export interface AgentLinkInput {
|
|
13
|
+
readonly canonicalRoot: string;
|
|
14
|
+
readonly skillNames: readonly string[];
|
|
15
|
+
readonly homeDir: string;
|
|
16
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
17
|
+
}
|
|
18
|
+
export declare function agentHomeDir(env?: NodeJS.ProcessEnv): string;
|
|
19
|
+
export declare function resolveAgentSkillTargets(homeDir: string, env?: NodeJS.ProcessEnv): readonly AgentSkillTarget[];
|
|
20
|
+
export declare function inspectAgentLinks(input: AgentLinkInput): readonly AgentSkillLinkStatus[];
|
|
21
|
+
export declare function ensureAgentLinks(input: AgentLinkInput): readonly AgentLinkChange[];
|
|
22
|
+
export declare function removeAgentLinks(input: AgentLinkInput): void;
|
|
23
|
+
export declare function attachAgentLinks(status: SkillsStatus, env?: NodeJS.ProcessEnv): SkillsStatus;
|
|
24
|
+
export declare function applyAgentLinkPass(result: SkillsSyncResult, input: {
|
|
25
|
+
readonly dryRun: boolean;
|
|
26
|
+
readonly env: NodeJS.ProcessEnv;
|
|
27
|
+
readonly canonicalRoot: string;
|
|
28
|
+
}): SkillsSyncResult;
|
|
29
|
+
export declare function agentLinksNeedWork(agentLinks: readonly AgentSkillLinkStatus[]): boolean;
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.agentHomeDir = agentHomeDir;
|
|
4
|
+
exports.resolveAgentSkillTargets = resolveAgentSkillTargets;
|
|
5
|
+
exports.inspectAgentLinks = inspectAgentLinks;
|
|
6
|
+
exports.ensureAgentLinks = ensureAgentLinks;
|
|
7
|
+
exports.removeAgentLinks = removeAgentLinks;
|
|
8
|
+
exports.attachAgentLinks = attachAgentLinks;
|
|
9
|
+
exports.applyAgentLinkPass = applyAgentLinkPass;
|
|
10
|
+
exports.agentLinksNeedWork = agentLinksNeedWork;
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_os_1 = require("node:os");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const manager_1 = require("./manager");
|
|
15
|
+
function agentHomeDir(env = process.env) {
|
|
16
|
+
return env.ALPHAFOX_AGENT_HOME?.trim() || (0, node_os_1.homedir)();
|
|
17
|
+
}
|
|
18
|
+
function resolveAgentSkillTargets(homeDir, env = process.env) {
|
|
19
|
+
const claudeHome = env.CLAUDE_CONFIG_DIR?.trim() || (0, node_path_1.join)(homeDir, ".claude");
|
|
20
|
+
const cursorHome = (0, node_path_1.join)(homeDir, ".cursor");
|
|
21
|
+
const codexHome = env.CODEX_HOME?.trim() || (0, node_path_1.join)(homeDir, ".codex");
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
id: "claude-code",
|
|
25
|
+
required: true,
|
|
26
|
+
home: claudeHome,
|
|
27
|
+
skillsDir: (0, node_path_1.join)(claudeHome, "skills"),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: "cursor",
|
|
31
|
+
required: false,
|
|
32
|
+
home: cursorHome,
|
|
33
|
+
skillsDir: (0, node_path_1.join)(cursorHome, "skills"),
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: "codex",
|
|
37
|
+
required: false,
|
|
38
|
+
home: codexHome,
|
|
39
|
+
skillsDir: (0, node_path_1.join)(codexHome, "skills"),
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
function inspectAgentLinks(input) {
|
|
44
|
+
return activeTargets(input).map((target) => classifyTarget(target, input));
|
|
45
|
+
}
|
|
46
|
+
function ensureAgentLinks(input) {
|
|
47
|
+
const created = [];
|
|
48
|
+
for (const status of inspectAgentLinks(input)) {
|
|
49
|
+
if (status.missing.length === 0)
|
|
50
|
+
continue;
|
|
51
|
+
(0, node_fs_1.mkdirSync)(status.skillsDir, { recursive: true });
|
|
52
|
+
for (const name of status.missing) {
|
|
53
|
+
linkSkillDir((0, node_path_1.join)(input.canonicalRoot, name), (0, node_path_1.join)(status.skillsDir, name));
|
|
54
|
+
created.push({ agent: status.id, name });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return created;
|
|
58
|
+
}
|
|
59
|
+
function removeAgentLinks(input) {
|
|
60
|
+
for (const target of activeTargets(input)) {
|
|
61
|
+
for (const name of input.skillNames) {
|
|
62
|
+
const dest = (0, node_path_1.join)(target.skillsDir, name);
|
|
63
|
+
if (!lexists(dest))
|
|
64
|
+
continue;
|
|
65
|
+
if (!isOurAgentLink(dest, (0, node_path_1.join)(input.canonicalRoot, name)))
|
|
66
|
+
continue;
|
|
67
|
+
(0, node_fs_1.unlinkSync)(dest);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function attachAgentLinks(status, env = process.env) {
|
|
72
|
+
const skillNames = status.skills
|
|
73
|
+
.filter((skill) => skill.status !== "missing")
|
|
74
|
+
.map((skill) => skill.name);
|
|
75
|
+
const agentLinks = inspectAgentLinks({
|
|
76
|
+
canonicalRoot: status.installedRoot,
|
|
77
|
+
skillNames,
|
|
78
|
+
homeDir: agentHomeDir(env),
|
|
79
|
+
env,
|
|
80
|
+
});
|
|
81
|
+
return {
|
|
82
|
+
...status,
|
|
83
|
+
agentLinks,
|
|
84
|
+
restartRequired: status.restartRequired || agentLinksNeedWork(agentLinks),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
function applyAgentLinkPass(result, input) {
|
|
88
|
+
const skillNames = result.status.skills
|
|
89
|
+
.filter((skill) => skill.status !== "missing")
|
|
90
|
+
.map((skill) => skill.name);
|
|
91
|
+
const linkInput = {
|
|
92
|
+
canonicalRoot: input.canonicalRoot,
|
|
93
|
+
skillNames,
|
|
94
|
+
homeDir: agentHomeDir(input.env),
|
|
95
|
+
env: input.env,
|
|
96
|
+
};
|
|
97
|
+
const created = input.dryRun ? [] : ensureAgentLinks(linkInput);
|
|
98
|
+
const status = attachAgentLinks(result.status, input.env);
|
|
99
|
+
if (!input.dryRun && agentLinksNeedWork(status.agentLinks)) {
|
|
100
|
+
throw Object.assign(new Error(`Failed to link Skills into Agent directories: ${missingAgentSummary(status.agentLinks)}`), {
|
|
101
|
+
type: "install",
|
|
102
|
+
subtype: "skills_agent_link_failed",
|
|
103
|
+
details: status.agentLinks.filter((item) => item.missing.length > 0),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const linked = created.length > 0 || agentLinksNeedWork(status.agentLinks);
|
|
107
|
+
return {
|
|
108
|
+
...result,
|
|
109
|
+
status,
|
|
110
|
+
action: nextSyncAction(result.action, linked, input.dryRun),
|
|
111
|
+
restartRequired: result.restartRequired || linked,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function agentLinksNeedWork(agentLinks) {
|
|
115
|
+
return agentLinks.some((item) => item.missing.length > 0);
|
|
116
|
+
}
|
|
117
|
+
function activeTargets(input) {
|
|
118
|
+
return resolveAgentSkillTargets(input.homeDir, input.env ?? {}).filter((target) => target.required || (0, node_fs_1.existsSync)(target.home));
|
|
119
|
+
}
|
|
120
|
+
function classifyTarget(target, input) {
|
|
121
|
+
const linked = [];
|
|
122
|
+
const missing = [];
|
|
123
|
+
const blocked = [];
|
|
124
|
+
for (const name of input.skillNames) {
|
|
125
|
+
const state = classifyLink((0, node_path_1.join)(input.canonicalRoot, name), (0, node_path_1.join)(target.skillsDir, name));
|
|
126
|
+
if (state === "linked")
|
|
127
|
+
linked.push(name);
|
|
128
|
+
else if (state === "blocked")
|
|
129
|
+
blocked.push(name);
|
|
130
|
+
else
|
|
131
|
+
missing.push(name);
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
id: target.id,
|
|
135
|
+
skillsDir: target.skillsDir,
|
|
136
|
+
linked,
|
|
137
|
+
missing,
|
|
138
|
+
blocked,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
function classifyLink(canonical, dest) {
|
|
142
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(canonical, "SKILL.md")))
|
|
143
|
+
return "missing";
|
|
144
|
+
if ((0, node_path_1.resolve)(canonical) === (0, node_path_1.resolve)(dest))
|
|
145
|
+
return "linked";
|
|
146
|
+
if (!lexists(dest) || isBrokenSymlink(dest))
|
|
147
|
+
return "missing";
|
|
148
|
+
if (isOurAgentLink(dest, canonical))
|
|
149
|
+
return "linked";
|
|
150
|
+
return "blocked";
|
|
151
|
+
}
|
|
152
|
+
function isOurAgentLink(dest, canonical) {
|
|
153
|
+
if (pointsAtCanonical(dest, canonical))
|
|
154
|
+
return true;
|
|
155
|
+
try {
|
|
156
|
+
const stat = (0, node_fs_1.lstatSync)(dest);
|
|
157
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
158
|
+
return false;
|
|
159
|
+
if (!(0, node_fs_1.existsSync)((0, node_path_1.join)(dest, "SKILL.md")))
|
|
160
|
+
return false;
|
|
161
|
+
return (0, manager_1.hashSkillDirectory)(dest) === (0, manager_1.hashSkillDirectory)(canonical);
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function pointsAtCanonical(dest, canonical) {
|
|
168
|
+
try {
|
|
169
|
+
if ((0, node_fs_1.lstatSync)(dest).isSymbolicLink()) {
|
|
170
|
+
const resolved = (0, node_path_1.resolve)((0, node_path_1.dirname)(dest), (0, node_fs_1.readlinkSync)(dest));
|
|
171
|
+
if ((0, node_path_1.resolve)(resolved) === (0, node_path_1.resolve)(canonical))
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Compare real paths below when the symlink metadata is unreadable.
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
return (0, node_fs_1.realpathSync)(dest) === (0, node_fs_1.realpathSync)(canonical);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
function linkSkillDir(canonical, dest) {
|
|
186
|
+
if (isBrokenSymlink(dest))
|
|
187
|
+
(0, node_fs_1.unlinkSync)(dest);
|
|
188
|
+
(0, node_fs_1.symlinkSync)(canonical, dest, process.platform === "win32" ? "junction" : undefined);
|
|
189
|
+
}
|
|
190
|
+
function lexists(path) {
|
|
191
|
+
try {
|
|
192
|
+
(0, node_fs_1.lstatSync)(path);
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function isBrokenSymlink(path) {
|
|
200
|
+
try {
|
|
201
|
+
return (0, node_fs_1.lstatSync)(path).isSymbolicLink() && !(0, node_fs_1.existsSync)(path);
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
function nextSyncAction(action, linked, dryRun) {
|
|
208
|
+
if (!linked || action !== "skipped")
|
|
209
|
+
return action;
|
|
210
|
+
return dryRun ? "planned" : "synced";
|
|
211
|
+
}
|
|
212
|
+
function missingAgentSummary(agentLinks) {
|
|
213
|
+
return agentLinks
|
|
214
|
+
.filter((item) => item.missing.length > 0)
|
|
215
|
+
.map((item) => `${item.id} (${item.missing.join(", ")})`)
|
|
216
|
+
.join("; ");
|
|
217
|
+
}
|
package/dist/skills/manager.d.ts
CHANGED
|
@@ -39,6 +39,13 @@ export interface InspectedSkill {
|
|
|
39
39
|
readonly status: SkillStatus;
|
|
40
40
|
readonly managed: boolean;
|
|
41
41
|
}
|
|
42
|
+
export interface AgentSkillLinkStatus {
|
|
43
|
+
readonly id: "claude-code" | "cursor" | "codex";
|
|
44
|
+
readonly skillsDir: string;
|
|
45
|
+
readonly linked: readonly string[];
|
|
46
|
+
readonly missing: readonly string[];
|
|
47
|
+
readonly blocked: readonly string[];
|
|
48
|
+
}
|
|
42
49
|
export interface SkillsStatus {
|
|
43
50
|
readonly bundleVersion: string;
|
|
44
51
|
readonly contractVersion: string;
|
|
@@ -52,6 +59,7 @@ export interface SkillsStatus {
|
|
|
52
59
|
readonly modified: boolean;
|
|
53
60
|
}[];
|
|
54
61
|
readonly summary: Readonly<Record<SkillStatus, number>>;
|
|
62
|
+
readonly agentLinks: readonly AgentSkillLinkStatus[];
|
|
55
63
|
readonly restartRequired: boolean;
|
|
56
64
|
}
|
|
57
65
|
export interface SkillsSyncResult {
|
package/dist/skills/manager.js
CHANGED
|
@@ -12,6 +12,7 @@ const profiles_1 = require("../config/profiles");
|
|
|
12
12
|
const envelope_1 = require("../envelope");
|
|
13
13
|
const exec_1 = require("../install/exec");
|
|
14
14
|
const package_root_1 = require("../install/package-root");
|
|
15
|
+
const agent_links_1 = require("./agent-links");
|
|
15
16
|
const manager_1 = require("./manager");
|
|
16
17
|
const SKILLS_TIMEOUT_MS = 120_000;
|
|
17
18
|
function installedSkillsRoot(env = process.env) {
|
|
@@ -33,25 +34,34 @@ function resolveCurrentSkillsPackageRoot(searchDirs = [__dirname, process.cwd()]
|
|
|
33
34
|
}
|
|
34
35
|
function inspectCurrentSkills(env = process.env, packageRoot = resolveCurrentSkillsPackageRoot()) {
|
|
35
36
|
const manifest = (0, manager_1.loadAndVerifySkillsManifest)(packageRoot);
|
|
36
|
-
return (0, manager_1.inspectSkills)({
|
|
37
|
+
return (0, agent_links_1.attachAgentLinks)((0, manager_1.inspectSkills)({
|
|
37
38
|
manifest,
|
|
38
39
|
installedRoot: installedSkillsRoot(env),
|
|
39
40
|
state: (0, manager_1.loadSkillsState)(skillsStatePath(env)),
|
|
40
|
-
});
|
|
41
|
+
}), env);
|
|
41
42
|
}
|
|
42
43
|
async function syncCurrentSkills(input, env = process.env, deps = {}) {
|
|
43
44
|
const packageRoot = deps.packageRoot ?? resolveCurrentSkillsPackageRoot();
|
|
44
45
|
const runner = deps.runner ??
|
|
45
46
|
(0, exec_1.createDefaultInstallRunner)(env, [__dirname, process.cwd()]);
|
|
47
|
+
const canonicalRoot = installedSkillsRoot(env);
|
|
46
48
|
const manifest = (0, manager_1.loadAndVerifySkillsManifest)(packageRoot);
|
|
47
|
-
|
|
49
|
+
const result = await (0, manager_1.syncSkills)({
|
|
48
50
|
manifest,
|
|
49
51
|
packageRoot,
|
|
50
|
-
installedRoot:
|
|
52
|
+
installedRoot: canonicalRoot,
|
|
51
53
|
statePath: skillsStatePath(env),
|
|
52
54
|
dryRun: input.dryRun,
|
|
53
55
|
force: input.force,
|
|
54
|
-
},
|
|
56
|
+
}, skillsBundleDeps(runner, packageRoot, canonicalRoot, env));
|
|
57
|
+
return (0, agent_links_1.applyAgentLinkPass)(result, {
|
|
58
|
+
dryRun: input.dryRun,
|
|
59
|
+
env,
|
|
60
|
+
canonicalRoot,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function skillsBundleDeps(runner, packageRoot, canonicalRoot, env) {
|
|
64
|
+
return {
|
|
55
65
|
install: async (names) => {
|
|
56
66
|
await runner.exec("npx", [
|
|
57
67
|
"-y",
|
|
@@ -66,8 +76,14 @@ async function syncCurrentSkills(input, env = process.env, deps = {}) {
|
|
|
66
76
|
},
|
|
67
77
|
remove: async (names) => {
|
|
68
78
|
await runner.exec("npx", ["-y", "skills", "remove", ...names, "-y", "-g"], { timeoutMs: SKILLS_TIMEOUT_MS });
|
|
79
|
+
(0, agent_links_1.removeAgentLinks)({
|
|
80
|
+
canonicalRoot,
|
|
81
|
+
skillNames: names,
|
|
82
|
+
homeDir: (0, agent_links_1.agentHomeDir)(env),
|
|
83
|
+
env,
|
|
84
|
+
});
|
|
69
85
|
},
|
|
70
|
-
}
|
|
86
|
+
};
|
|
71
87
|
}
|
|
72
88
|
async function cmdSkills(args, flags, env = process.env, deps = {}) {
|
|
73
89
|
const parsed = parseSkillsArgs(args);
|
|
@@ -81,6 +97,7 @@ async function cmdSkills(args, flags, env = process.env, deps = {}) {
|
|
|
81
97
|
],
|
|
82
98
|
notes: [
|
|
83
99
|
"Skills are synced only from the verified bundle inside the installed @alphafox/cli package",
|
|
100
|
+
"Sync also links Skills into ~/.claude/skills (and ~/.cursor/skills, ~/.codex/skills when those agents are present)",
|
|
84
101
|
"Modified Skills are preserved unless --force --yes is explicit",
|
|
85
102
|
"Restart the AI tool after a successful sync",
|
|
86
103
|
],
|
|
@@ -1,153 +1,153 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "@alphafox/cli",
|
|
4
|
-
"packageVersion": "0.3.
|
|
4
|
+
"packageVersion": "0.3.13",
|
|
5
5
|
"contractVersion": "2026-08-13",
|
|
6
|
-
"bundleHash": "
|
|
6
|
+
"bundleHash": "6957fd9e293dff1afdc94922f9947590398cff0743f99eba5a2b2abb215df12c",
|
|
7
7
|
"skills": [
|
|
8
8
|
{
|
|
9
9
|
"name": "alphafox",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.13",
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"path": "SKILL.md",
|
|
14
|
-
"sha256": "
|
|
15
|
-
"size":
|
|
14
|
+
"sha256": "9662240fd4497442711c155723e94ae60a9de84d2f433bbfac81a25d11caf9bd",
|
|
15
|
+
"size": 7426
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
-
"hash": "
|
|
18
|
+
"hash": "8d4578a474c6063ff13ea22c45f9e2d75c1ab518567e077d838bd1bef6ec566e"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "alphafox-account",
|
|
22
|
-
"version": "0.3.
|
|
22
|
+
"version": "0.3.13",
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "SKILL.md",
|
|
26
|
-
"sha256": "
|
|
26
|
+
"sha256": "74fa3573aa94a54d995f8f78412a06269fc3ef903009f8b7b590f87a23ef2271",
|
|
27
27
|
"size": 784
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
-
"hash": "
|
|
30
|
+
"hash": "3f2644be04b0e3b1b4f4bc9c6f47708cb7576c715d50a8ac6d3ccc7143c75565"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "alphafox-admin",
|
|
34
|
-
"version": "0.3.
|
|
34
|
+
"version": "0.3.13",
|
|
35
35
|
"files": [
|
|
36
36
|
{
|
|
37
37
|
"path": "SKILL.md",
|
|
38
|
-
"sha256": "
|
|
38
|
+
"sha256": "7fe8f8aa9f0031c46e3b0f5989eb5964fe0d64fc4be3d3ea187ebd11f8fde729",
|
|
39
39
|
"size": 788
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "c0bf71914f23455168a3d7e0471a107f8d92de8c2edb958c4749d61ed413d418"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "alphafox-auth",
|
|
46
|
-
"version": "0.3.
|
|
46
|
+
"version": "0.3.13",
|
|
47
47
|
"files": [
|
|
48
48
|
{
|
|
49
49
|
"path": "SKILL.md",
|
|
50
|
-
"sha256": "
|
|
50
|
+
"sha256": "f76da1d4e97f3bc7d71afe9487de0e87258afc0e5de85e3cee588b656dfcfef7",
|
|
51
51
|
"size": 2371
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"hash": "
|
|
54
|
+
"hash": "d2fafe541e2be36e4672ad9ee9473113d8f4f4649247148ff5daacc2dfaefd21"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "alphafox-cache",
|
|
58
|
-
"version": "0.3.
|
|
58
|
+
"version": "0.3.13",
|
|
59
59
|
"files": [
|
|
60
60
|
{
|
|
61
61
|
"path": "SKILL.md",
|
|
62
|
-
"sha256": "
|
|
62
|
+
"sha256": "da4cd692abb0e5a62a892b8e8c30cb39c0c77c14ec5f388bdfccf3a692a06d0b",
|
|
63
63
|
"size": 1530
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
|
-
"hash": "
|
|
66
|
+
"hash": "bb6ee2004dc699d0392fedefd046520db202fffae856bc665bf6d79b21c2d26f"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "alphafox-engine-backtest",
|
|
70
|
-
"version": "0.3.
|
|
70
|
+
"version": "0.3.13",
|
|
71
71
|
"files": [
|
|
72
72
|
{
|
|
73
73
|
"path": "SKILL.md",
|
|
74
|
-
"sha256": "
|
|
74
|
+
"sha256": "fbdf4e90837243fa7c4385e2078b4b80f6a8e0b1df97f5477ef69a9dfb340fef",
|
|
75
75
|
"size": 8278
|
|
76
76
|
}
|
|
77
77
|
],
|
|
78
|
-
"hash": "
|
|
78
|
+
"hash": "d0222abf0dbced2551c049483d8381ff85f8ab36e9b89f44dca65adbaaf301d9"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "alphafox-exchange",
|
|
82
|
-
"version": "0.3.
|
|
82
|
+
"version": "0.3.13",
|
|
83
83
|
"files": [
|
|
84
84
|
{
|
|
85
85
|
"path": "SKILL.md",
|
|
86
|
-
"sha256": "
|
|
86
|
+
"sha256": "a82200ac4fd9b1ebb07f2be560f484e4cc39a5b6365b1cf8f09da237206b3b9f",
|
|
87
87
|
"size": 744
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "49168e1b6cf992d1a357dd2e86a1cc2a41466aa3cb0c17cc058ef75027d309bb"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"name": "alphafox-market",
|
|
94
|
-
"version": "0.3.
|
|
94
|
+
"version": "0.3.13",
|
|
95
95
|
"files": [
|
|
96
96
|
{
|
|
97
97
|
"path": "SKILL.md",
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "a824b1a49a29cb36f0a9c1d74187420f570137566f3a74f1685a38f7c1023032",
|
|
99
99
|
"size": 3079
|
|
100
100
|
}
|
|
101
101
|
],
|
|
102
|
-
"hash": "
|
|
102
|
+
"hash": "4d5fb1a2e765811c504decf024ab6260969486776b42da1534f977e238ca399b"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "alphafox-notification",
|
|
106
|
-
"version": "0.3.
|
|
106
|
+
"version": "0.3.13",
|
|
107
107
|
"files": [
|
|
108
108
|
{
|
|
109
109
|
"path": "SKILL.md",
|
|
110
|
-
"sha256": "
|
|
110
|
+
"sha256": "2425c81589f89db06eb361f61d3bcf817ed862a42d00174d31005385b736b681",
|
|
111
111
|
"size": 699
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
|
-
"hash": "
|
|
114
|
+
"hash": "1d2d4243dba2410517c0d5add310709f20a3642bc5206e777bccd200d2fcb7ad"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "alphafox-shared",
|
|
118
|
-
"version": "0.3.
|
|
118
|
+
"version": "0.3.13",
|
|
119
119
|
"files": [
|
|
120
120
|
{
|
|
121
121
|
"path": "SKILL.md",
|
|
122
|
-
"sha256": "
|
|
123
|
-
"size":
|
|
122
|
+
"sha256": "895d98df84caa7813ed4083d23124bbb9572a93036578fdbaacb02574c29317d",
|
|
123
|
+
"size": 5960
|
|
124
124
|
}
|
|
125
125
|
],
|
|
126
|
-
"hash": "
|
|
126
|
+
"hash": "df50ec696f3b3e4f58cc2f66b2ded0d4dd5b898e2a6aa822eb779f978d04062d"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"name": "alphafox-strategy",
|
|
130
|
-
"version": "0.3.
|
|
130
|
+
"version": "0.3.13",
|
|
131
131
|
"files": [
|
|
132
132
|
{
|
|
133
133
|
"path": "SKILL.md",
|
|
134
|
-
"sha256": "
|
|
135
|
-
"size":
|
|
134
|
+
"sha256": "ebf636f9d4656f98e9c5ba3ba7c00f0816d5e564dece2fbab3242ccd1138f325",
|
|
135
|
+
"size": 4398
|
|
136
136
|
}
|
|
137
137
|
],
|
|
138
|
-
"hash": "
|
|
138
|
+
"hash": "4b4fcc5c20337ab2c50499bd58c33c5c0bf3eb167c48f2a53aa48ab06cedba5a"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"name": "alphafox-trading",
|
|
142
|
-
"version": "0.3.
|
|
142
|
+
"version": "0.3.13",
|
|
143
143
|
"files": [
|
|
144
144
|
{
|
|
145
145
|
"path": "SKILL.md",
|
|
146
|
-
"sha256": "
|
|
146
|
+
"sha256": "da1c8504eafcd201b8b0d6a06ab2c3ac19185c03a60c723ef8cb7e1d06213ca8",
|
|
147
147
|
"size": 3123
|
|
148
148
|
}
|
|
149
149
|
],
|
|
150
|
-
"hash": "
|
|
150
|
+
"hash": "154e7456e7abceacff29feeb082365fd81ed528004ebcb7899485a2dfef37f51"
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
}
|