@alphafox/cli 0.3.11 → 0.3.12
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 +5 -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 +13 -2
- package/package.json +1 -1
- package/skills/account/SKILL.md +1 -1
- package/skills/admin/SKILL.md +1 -1
- package/skills/alphafox/SKILL.md +58 -4
- package/skills/alphafox-shared/SKILL.md +4 -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
|
@@ -86,10 +86,11 @@ skills then use public `operationId`s; an explicit local-execution skill may
|
|
|
86
86
|
call its co-versioned built-in command.
|
|
87
87
|
|
|
88
88
|
`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
|
|
89
|
+
verify the packaged Skills manifest, copy it into `~/.agents/skills`, and link
|
|
90
|
+
each Skill into `~/.claude/skills` (plus `~/.cursor/skills` / `~/.codex/skills`
|
|
91
|
+
when those agents exist). Use `alphafox skills status` to inspect missing,
|
|
92
|
+
stale, modified, or unlinked Skills and `alphafox skills sync` to repair safe
|
|
93
|
+
drift — including Claude Code links when the canonical bundle is already current.
|
|
93
94
|
|
|
94
95
|
## Docs
|
|
95
96
|
|
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.12",
|
|
5
5
|
"contractVersion": "2026-08-13",
|
|
6
|
-
"bundleHash": "
|
|
6
|
+
"bundleHash": "5129a939b6c209ec5e5d1a08ee94fe3c4999c53bd251731314c27de29f8ff5f0",
|
|
7
7
|
"skills": [
|
|
8
8
|
{
|
|
9
9
|
"name": "alphafox",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.12",
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"path": "SKILL.md",
|
|
14
|
-
"sha256": "
|
|
15
|
-
"size":
|
|
14
|
+
"sha256": "37dc3b595471e1130662a54d8aed35e12a32222d2f95d3fadf3c9f5636a52ac9",
|
|
15
|
+
"size": 7415
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
-
"hash": "
|
|
18
|
+
"hash": "87347f1a8364fa982399b5641d6ff347c85376425e589ad6581001b1d1fefaac"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "alphafox-account",
|
|
22
|
-
"version": "0.3.
|
|
22
|
+
"version": "0.3.12",
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "SKILL.md",
|
|
26
|
-
"sha256": "
|
|
26
|
+
"sha256": "c4cdac0a980106ad110c306b5248b9b8f325d9de60e50f39d412b40854238a36",
|
|
27
27
|
"size": 784
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
-
"hash": "
|
|
30
|
+
"hash": "743b0f52a8f707f568c8ba9fba28d648d67d7ed524c6b41b550b9dd8d56434a0"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "alphafox-admin",
|
|
34
|
-
"version": "0.3.
|
|
34
|
+
"version": "0.3.12",
|
|
35
35
|
"files": [
|
|
36
36
|
{
|
|
37
37
|
"path": "SKILL.md",
|
|
38
|
-
"sha256": "
|
|
38
|
+
"sha256": "6f06d16bd52b3d8651b91b0b6e4dc606d1d98de5827fc5c164f6d23705de3910",
|
|
39
39
|
"size": 788
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "ccbca03ae872a794eb950897b8cac4f398014a9c014ac956245c89ffb08bf4f0"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "alphafox-auth",
|
|
46
|
-
"version": "0.3.
|
|
46
|
+
"version": "0.3.12",
|
|
47
47
|
"files": [
|
|
48
48
|
{
|
|
49
49
|
"path": "SKILL.md",
|
|
50
|
-
"sha256": "
|
|
50
|
+
"sha256": "5985bdd0663d806e8ae8ab08d2ef2e1c1aa99b541ff5a5e72b14337eff3f22e6",
|
|
51
51
|
"size": 2371
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"hash": "
|
|
54
|
+
"hash": "a42814a37f6cddf2e21f6badd1f66254091d734d1210c87cff6e11ea17432241"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "alphafox-cache",
|
|
58
|
-
"version": "0.3.
|
|
58
|
+
"version": "0.3.12",
|
|
59
59
|
"files": [
|
|
60
60
|
{
|
|
61
61
|
"path": "SKILL.md",
|
|
62
|
-
"sha256": "
|
|
62
|
+
"sha256": "9653fe4bc132b2f587a57cebf5c646527faf4f081d51f80645c3be34e952161e",
|
|
63
63
|
"size": 1530
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
|
-
"hash": "
|
|
66
|
+
"hash": "e3c8c25d221c5b0574f17d455b2c29d8a8c075c2a007cac4302c0fa47ea1e226"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "alphafox-engine-backtest",
|
|
70
|
-
"version": "0.3.
|
|
70
|
+
"version": "0.3.12",
|
|
71
71
|
"files": [
|
|
72
72
|
{
|
|
73
73
|
"path": "SKILL.md",
|
|
74
|
-
"sha256": "
|
|
74
|
+
"sha256": "1bd19ba3222dd8ab90f69509c8c02db3e2b9ef460c0539816ad83fba396e8e64",
|
|
75
75
|
"size": 8278
|
|
76
76
|
}
|
|
77
77
|
],
|
|
78
|
-
"hash": "
|
|
78
|
+
"hash": "ff899b9199e5ac28ef77f6fc8bf582d341483d0617933f669ca4f9a40e8d5bef"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "alphafox-exchange",
|
|
82
|
-
"version": "0.3.
|
|
82
|
+
"version": "0.3.12",
|
|
83
83
|
"files": [
|
|
84
84
|
{
|
|
85
85
|
"path": "SKILL.md",
|
|
86
|
-
"sha256": "
|
|
86
|
+
"sha256": "0dd186a4f7c34b01ad19028da5ecdfe2f15a15e2dc00997e048a7caa54e9d5b2",
|
|
87
87
|
"size": 744
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "b2a0a6d2ad588da804bbadfd505b395ecace330732b3be5dcc3110f3c4d0a2eb"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"name": "alphafox-market",
|
|
94
|
-
"version": "0.3.
|
|
94
|
+
"version": "0.3.12",
|
|
95
95
|
"files": [
|
|
96
96
|
{
|
|
97
97
|
"path": "SKILL.md",
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "fba7e2e1a8a474234d984ab9bb99a91d003e8e365c10796687d6f7d8b20319ab",
|
|
99
99
|
"size": 3079
|
|
100
100
|
}
|
|
101
101
|
],
|
|
102
|
-
"hash": "
|
|
102
|
+
"hash": "9e804c4418f4745b18915a4c0b8f7b7ef1a2eb4e5263d43cb5f665523b547425"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "alphafox-notification",
|
|
106
|
-
"version": "0.3.
|
|
106
|
+
"version": "0.3.12",
|
|
107
107
|
"files": [
|
|
108
108
|
{
|
|
109
109
|
"path": "SKILL.md",
|
|
110
|
-
"sha256": "
|
|
110
|
+
"sha256": "02fc964294afa9630f220ff9bdaed283df15ddd92d52a9d9e48432072dfe87ed",
|
|
111
111
|
"size": 699
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
|
-
"hash": "
|
|
114
|
+
"hash": "acc77bfbd3f74625e80b4aeabcf2e29ff55eadb9a20a1a421f8be95ab6f2d84b"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "alphafox-shared",
|
|
118
|
-
"version": "0.3.
|
|
118
|
+
"version": "0.3.12",
|
|
119
119
|
"files": [
|
|
120
120
|
{
|
|
121
121
|
"path": "SKILL.md",
|
|
122
|
-
"sha256": "
|
|
123
|
-
"size":
|
|
122
|
+
"sha256": "3d9d42c3e63c1f3c524923c9b2c544fe948464e3bf9ea1a7ec898023f68efe7c",
|
|
123
|
+
"size": 5643
|
|
124
124
|
}
|
|
125
125
|
],
|
|
126
|
-
"hash": "
|
|
126
|
+
"hash": "68affee820b6b6d41d01c0b83cebcd9431fa70eafe975d98736e983d47059d89"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"name": "alphafox-strategy",
|
|
130
|
-
"version": "0.3.
|
|
130
|
+
"version": "0.3.12",
|
|
131
131
|
"files": [
|
|
132
132
|
{
|
|
133
133
|
"path": "SKILL.md",
|
|
134
|
-
"sha256": "
|
|
135
|
-
"size":
|
|
134
|
+
"sha256": "956198df91f79ae2976d5aed8a5842a9e22c907ecafb28378e89fe5b942ee5c2",
|
|
135
|
+
"size": 4398
|
|
136
136
|
}
|
|
137
137
|
],
|
|
138
|
-
"hash": "
|
|
138
|
+
"hash": "58e72dbd185c1fa033aa52c63a79478701e3a75c14583fca13459ad55d9b3622"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"name": "alphafox-trading",
|
|
142
|
-
"version": "0.3.
|
|
142
|
+
"version": "0.3.12",
|
|
143
143
|
"files": [
|
|
144
144
|
{
|
|
145
145
|
"path": "SKILL.md",
|
|
146
|
-
"sha256": "
|
|
146
|
+
"sha256": "09da55fd6ff864c6fdac0b79e106e62d7c3f083610ae71b4fad38439b529dd91",
|
|
147
147
|
"size": 3123
|
|
148
148
|
}
|
|
149
149
|
],
|
|
150
|
-
"hash": "
|
|
150
|
+
"hash": "5ae19801df517c9c7f73c7d1b64fe0feeb0790ea660905f0971eea5ae9f209f9"
|
|
151
151
|
}
|
|
152
152
|
]
|
|
153
153
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const CLI_NAME = "alphafox";
|
|
2
2
|
export declare const CLI_PACKAGE = "@alphafox/cli";
|
|
3
|
-
export declare const CLI_VERSION = "0.3.
|
|
3
|
+
export declare const CLI_VERSION = "0.3.12";
|
|
4
4
|
export { CATALOG_VERSION as CLI_CONTRACT_VERSION } from "./catalog/operations";
|
package/dist/version.js
CHANGED
|
@@ -3,6 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CLI_CONTRACT_VERSION = exports.CLI_VERSION = exports.CLI_PACKAGE = exports.CLI_NAME = void 0;
|
|
4
4
|
exports.CLI_NAME = "alphafox";
|
|
5
5
|
exports.CLI_PACKAGE = "@alphafox/cli";
|
|
6
|
-
exports.CLI_VERSION = "0.3.
|
|
6
|
+
exports.CLI_VERSION = "0.3.12";
|
|
7
7
|
var operations_1 = require("./catalog/operations");
|
|
8
8
|
Object.defineProperty(exports, "CLI_CONTRACT_VERSION", { enumerable: true, get: function () { return operations_1.CATALOG_VERSION; } });
|
|
@@ -24,6 +24,11 @@ npm install -g @alphafox/cli
|
|
|
24
24
|
alphafox skills sync --format json --no-input
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
`alphafox skills sync` writes the verified bundle to `~/.agents/skills` and
|
|
28
|
+
then links each Skill into `~/.claude/skills` so Claude Code can discover it.
|
|
29
|
+
Cursor (`~/.cursor/skills`) and Codex (`~/.codex/skills`) are linked when those
|
|
30
|
+
tools are already present. `alphafox skills status` reports `agentLinks`.
|
|
31
|
+
|
|
27
32
|
Do not install Skills from GitHub `main` as a fallback. The CLI verifies the
|
|
28
33
|
manifest and hashes inside the npm package before syncing. If sync fails, stop
|
|
29
34
|
and report the error rather than downloading a different Skills version.
|
|
@@ -87,8 +92,14 @@ Parse the JSON envelope: `ok === true` means success. Errors land on
|
|
|
87
92
|
## Step 4: Tell the user to restart
|
|
88
93
|
|
|
89
94
|
Ask the user to **restart the AI tool** so the new Skills are loaded.
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
|
|
96
|
+
## Step 5: New-user welcome
|
|
97
|
+
|
|
98
|
+
After restart and `alphafox auth status --verify` shows `session: active`,
|
|
99
|
+
follow skill `alphafox` **After install**: fetch the Lite square catalog
|
|
100
|
+
(`lite.catalog_config.get`, `lite.signal_sources.list`) and introduce the
|
|
101
|
+
classic strategy definitions from `trading.strategy_definitions.list`. Do not
|
|
102
|
+
invent 带单员 names. Do not create a trader until the user asks.
|
|
92
103
|
|
|
93
104
|
## Human wizard (do not run this from an Agent)
|
|
94
105
|
|
package/package.json
CHANGED
package/skills/account/SKILL.md
CHANGED
package/skills/admin/SKILL.md
CHANGED
package/skills/alphafox/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox
|
|
3
|
-
description: AlphaFox CLI entry router. Use for any AlphaFox request — install, update, login, whoami, 回测, engine backtest, 清理回测缓存 / 历史数据, strategy definitions, create/list/start/stop a running strategy (trader), ticker/标的 resolve (美股 or crypto), market data, exchange connectors, wallet, subscriptions, notifications, or admin. If a CLI command prints `[alphafox] update available`, ask the user「检测到新的版本,是否需要我帮你升级?」and only then run `alphafox update --format json --no-input`. After a large backtest, if tape cache is large, ask「回测下载的历史数据比较大,要不要我帮你清理本地缓存?」then open `alphafox-cache`. Start here, then open the routed domain skill. Do not guess alphafox-engine-backtest vs alphafox-strategy vs alphafox-trading from memory.
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: AlphaFox CLI entry router. Use for any AlphaFox request — install, update, login, whoami, 回测, engine backtest, 清理回测缓存 / 历史数据, strategy definitions, create/list/start/stop a running strategy (trader), ticker/标的 resolve (美股 or crypto), market data, exchange connectors, wallet, subscriptions, notifications, or admin. After a successful install and login, present the 新人引导 in this file (Lite square 带单员 + classic strategies). If a CLI command prints `[alphafox] update available`, ask the user「检测到新的版本,是否需要我帮你升级?」and only then run `alphafox update --format json --no-input`. After a large backtest, if tape cache is large, ask「回测下载的历史数据比较大,要不要我帮你清理本地缓存?」then open `alphafox-cache`. Start here, then open the routed domain skill. Do not guess alphafox-engine-backtest vs alphafox-strategy vs alphafox-trading from memory.
|
|
4
|
+
version: 0.3.12
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox
|
|
@@ -19,6 +19,7 @@ A **trader** is a running strategy instance (paper or live), not a person. Creat
|
|
|
19
19
|
| User intent | Skill |
|
|
20
20
|
|---|---|
|
|
21
21
|
| Install, update, Skills status/sync, doctor, version, catalog, how to call the CLI | `alphafox-shared` |
|
|
22
|
+
| 刚安装完 / 新人引导 / 热门带单员 / 经典策略介绍 | this file, **After install** |
|
|
22
23
|
| Login, logout, whoami, profile, staging vs production | `alphafox-auth` |
|
|
23
24
|
| Ticker / 标的 / 美股 / crypto / resolve a misspelled symbol | `alphafox-market` |
|
|
24
25
|
| Engine WASM backtest, experiment, `engine-backtest run`, persist a local run | `alphafox-engine-backtest` |
|
|
@@ -30,14 +31,17 @@ A **trader** is a running strategy instance (paper or live), not a person. Creat
|
|
|
30
31
|
| Notification channels | `alphafox-notification` |
|
|
31
32
|
| Admin-only operations | `alphafox-admin` |
|
|
32
33
|
|
|
33
|
-
If several rows apply, load **all** of them (typical: `alphafox-shared` + `alphafox-market` + one domain skill).
|
|
34
|
+
If several rows apply, load **all** of them (typical: `alphafox-shared` + `alphafox-market` + one domain skill).
|
|
35
|
+
|
|
36
|
+
- “帮我配/建一个网格/DCA/跟单策略” → `alphafox-strategy` (pick definition, ask knobs, validate `{common, strategy}`) **and** `alphafox-market` (resolve tickers) **and** `alphafox-trading` (create the trader). Hidden copy variants still create through `alphafox-trading`.
|
|
37
|
+
- “帮我回测这个配置” → `alphafox-strategy` (definition + config) **and** `alphafox-engine-backtest`.
|
|
34
38
|
|
|
35
39
|
## Upgrade reminder
|
|
36
40
|
|
|
37
41
|
The CLI may print this on **stderr** at most once every 24 hours:
|
|
38
42
|
|
|
39
43
|
```text
|
|
40
|
-
[alphafox] update available: 0.3.
|
|
44
|
+
[alphafox] update available: 0.3.11 -> 0.3.12. After the user confirms, run: alphafox update --format json --no-input,
|
|
41
45
|
```
|
|
42
46
|
|
|
43
47
|
If you see that notice (or `updateAvailable: true` from `alphafox update --check`):
|
|
@@ -54,6 +58,56 @@ alphafox update --format json --no-input
|
|
|
54
58
|
|
|
55
59
|
Do not install Skills from GitHub. Details and dry-run / check commands live in `alphafox-shared`.
|
|
56
60
|
|
|
61
|
+
## After install
|
|
62
|
+
|
|
63
|
+
After CLI + Skills are installed, login is `session: active`, and the AI tool has restarted, present this welcome **once**. Fetch live data first. Do not invent 带单员 names, ROI, or strategy scenarios.
|
|
64
|
+
|
|
65
|
+
Classic product names to introduce (match `trading.strategy_definitions.list` `display.label` zh-CN / `name`; then `byId.get` that row — do not hardcode definition ids):
|
|
66
|
+
|
|
67
|
+
1. 组合跟单策略
|
|
68
|
+
2. 轮动马丁策略
|
|
69
|
+
3. 网格策略
|
|
70
|
+
4. 拼盘策略
|
|
71
|
+
5. 滚仓宝策略
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
alphafox lite catalog_config get --format json --no-input
|
|
75
|
+
alphafox lite signal_sources list --format json --no-input
|
|
76
|
+
alphafox trading strategy_definitions list --format json --no-input
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Keep Lite catalog order from `featuredSourceIds`. Resolve `id` → `name` from `lite.signal_sources` `sources[]`. Take the first **3** named rows. Optional ROI:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
alphafox lite signal_source_metrics list --sourceIds <id,id,id> --window all --mode scalars --format json --no-input
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Print `roi` as returned. If the catalog or metrics call fails, skip that part and say the square catalog could not be loaded — do not substitute other signal sources.
|
|
86
|
+
|
|
87
|
+
For each classic name that matched a definition, `byId.get` and use Chinese `display.description` (fallback English `description`) as the scenario. Then one live leaderboard example:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
alphafox trader_leaderboard list --strategyDefinitionId <id> --sort roi --order desc --positiveRoi true --window 30d --limit 1 --includePaper false --format json --no-input
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Use `items[0].traderName` + `roiPercent` when present. Omit the leaderboard clause when the list is empty.
|
|
94
|
+
|
|
95
|
+
Present in the operator's language, this shape:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
安装完成!
|
|
99
|
+
以下是最近热门的一些带单员:{name}{、name}{、name}。
|
|
100
|
+
您可以直接通过组合跟单策略来跟随这些带单员,做实时自动化交易。
|
|
101
|
+
|
|
102
|
+
如果您想配置自己的交易策略,推荐先了解这些内置的经典策略。
|
|
103
|
+
{策略名}:{display.description}。排行榜上 {traderName} 近 30 日收益 {roiPercent}%。
|
|
104
|
+
…
|
|
105
|
+
|
|
106
|
+
想跟单或者运行策略,告诉我即可。或者您想先看看排行榜,也可以直接告诉我。
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Do not create a trader from this welcome. When they pick 跟单 / a classic strategy, read `alphafox-strategy` + `alphafox-trading` (+ `alphafox-market` if they name a ticker). When they ask for 排行榜, list `trader_leaderboard` (same flags, no `strategyDefinitionId` unless they named a type) and summarize — do not dump the envelope.
|
|
110
|
+
|
|
57
111
|
## Do not mix these backtest paths
|
|
58
112
|
|
|
59
113
|
- Local Engine tape + wasm + optional persist → `alphafox-engine-backtest` (`alphafox engine-backtest run`, hyphen).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-shared
|
|
3
3
|
description: Shared AlphaFox CLI rules for Agents — auth, profiles, envelopes, risk gates, and public operationIds only.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.12
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox shared Agent contract
|
|
@@ -14,7 +14,7 @@ Co-versioned with `@alphafox/cli`. Query compatibility with `alphafox version --
|
|
|
14
14
|
|
|
15
15
|
Prefer the wizard (CLI + Agent Skills) or the Agent install guide. Do not treat
|
|
16
16
|
`npm install -g @alphafox/cli` as enough for Agents — Skills must be registered
|
|
17
|
-
with `alphafox skills sync
|
|
17
|
+
with `alphafox skills sync` (canonical store plus `~/.claude/skills` links).
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
npx @alphafox/cli@latest install
|
|
@@ -24,6 +24,8 @@ npx @alphafox/cli version --format json --no-input
|
|
|
24
24
|
npx @alphafox/cli doctor --format json --no-input
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
After install, `auth status --verify` shows `session: active`, and the AI tool has restarted, follow skill `alphafox` **After install** (Lite square 带单员 + classic strategies). Do not skip that welcome.
|
|
28
|
+
|
|
27
29
|
The CLI checks npm at most once every 24 hours and only prints a notice on
|
|
28
30
|
**stderr**. It never auto-upgrades. If you see
|
|
29
31
|
`[alphafox] update available` (or `updateAvailable: true`), ask the user:
|
package/skills/auth/SKILL.md
CHANGED
package/skills/cache/SKILL.md
CHANGED
package/skills/exchange/SKILL.md
CHANGED
package/skills/market/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-market
|
|
3
3
|
description: Market data and ticker resolution for US equity perps, RWAs, and crypto on the same perp catalog. Use when the user names 美股, NVDA, AAPL, BTC, or any 标的. Keep the operator's asset class via symbolMetadata — do not rewrite NVDA into a crypto coin.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.12
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Market
|
package/skills/strategy/SKILL.md
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-strategy
|
|
3
|
-
description: Strategy definitions — list types
|
|
4
|
-
version: 0.3.
|
|
3
|
+
description: Strategy definitions — list types, read a definition's contract, and validate config. Creating a running strategy is creating a trader; use alphafox-trading for that. Local Engine backtest is alphafox-engine-backtest.
|
|
4
|
+
version: 0.3.12
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Strategy definitions
|
|
8
8
|
|
|
9
9
|
Always `--format json --no-input`. Read scopes `trading:read`; validate is `trading:write`.
|
|
10
10
|
|
|
11
|
-
A **definition** is a strategy type
|
|
11
|
+
A **definition** is a strategy type. A **trader** is one running instance. Instantiating is `alphafox-trading`. Local wasm backtest is `alphafox-engine-backtest`. This skill only discovers types and checks config.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Human-named tickers go through `alphafox resolve-symbols` (`skills/market`) before they enter a config you later validate or hand to create. 美股 are equity perps in `binance_perp_usdt` (`NVDA/USDT:USDT`, `assetClass=equity_perp`).
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
Do not enumerate engine strategy IDs in this file. Pick the definition from `list` / `byId.get`. Do not add a wizard command. Do not invent a second catalog.
|
|
16
|
+
|
|
17
|
+
## Discover
|
|
18
|
+
|
|
19
|
+
`trading.strategy_definitions.list` returns **active** rows only. Hidden types (including Hyperliquid / rebate copy) are absent from list; `byId.get` and `validate_config` still work when the operator named that id. Creation of those copy variants is `alphafox-trading` (`trading.hl_copy_traders.create` / `trading.rebate_copy_traders.create`).
|
|
16
20
|
|
|
17
21
|
```bash
|
|
18
22
|
alphafox schema trading.strategy_definitions.list --format json --no-input
|
|
@@ -20,18 +24,51 @@ alphafox api GET /api/v1/trading/strategy-definitions --format json --no-input
|
|
|
20
24
|
alphafox trading strategy_definitions byId get --definitionId <id> --format json --no-input
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
Match the name the operator used against list `id` / `name` / `display`. If they already gave an id that list omitted, `byId.get` that id. Copy / DCA / grid are catalog rows, not separate products.
|
|
28
|
+
|
|
29
|
+
`byId.get` is the operator model. Read, in order:
|
|
30
|
+
|
|
31
|
+
1. `id`, `category` (`COPY` / `DCA` / `GRID` / `TREND` / `OTHERS`), `status`
|
|
32
|
+
2. English `description` (mechanism). Prefer it over marketing `display.description`
|
|
33
|
+
3. `capabilities` and `commonModules` (event-driven vs polling, signal sources, manual sync)
|
|
34
|
+
4. `strategyConfigSchema` required fields and each field's `display` — including decision-logic enums inside this definition
|
|
35
|
+
5. `capabilities.actionDefinitions` (what a manual action changes)
|
|
36
|
+
|
|
37
|
+
Explain the type from those fields. Missing a layer → say unknown; do not fill from memory. Decision logic (`simple-long`, grid `mode` `neutral`/`long`/`short`) is an internal parameter, not a new definition id.
|
|
38
|
+
|
|
39
|
+
## Configure with the human
|
|
40
|
+
|
|
41
|
+
The human answers knobs. You write JSON.
|
|
42
|
+
|
|
43
|
+
1. Confirm the definition from `byId.get` in the operator's language (what it is, what drives it, how positions change).
|
|
44
|
+
2. From `strategyConfigSchema` plus common required fields, ask **only** values the human must choose: symbols (resolve first), direction / mode, size, signal source, leverage. Do not walk every optional key.
|
|
45
|
+
3. Write `strategy-config.json` as:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"configSchemaVersion": 4,
|
|
50
|
+
"config": {
|
|
51
|
+
"common": {},
|
|
52
|
+
"strategy": {}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`configSchemaVersion` comes from the definition (`configSchemaVersion` on `byId.get` / list). Omit it only when the schema says it is optional; when present it must match the definition. `common` is shared risk / SLTP / execution / market. `strategy` is this type's parameters and decision logic. Do not use top-level `settings`, `policyId`, or `policyParams`.
|
|
58
|
+
|
|
59
|
+
4. Keys and enums come from the definition schema, not from this skill. Do not ship a default `grid.json` / `dca.json`.
|
|
24
60
|
|
|
25
61
|
## Validate config
|
|
26
62
|
|
|
27
|
-
Read `
|
|
63
|
+
Read `alphafox schema trading.strategy_definitions.byId.validate_config` first. Catalog `request.body` may look like a free `JsonObject`; still send the envelope above. The server checks the definition schema.
|
|
28
64
|
|
|
29
65
|
```bash
|
|
30
|
-
alphafox schema trading.strategy_definitions.byId.validate_config --format json --no-input
|
|
31
66
|
alphafox trading strategy_definitions byId validate_config --definitionId <id> --config @./strategy-config.json --format json --no-input
|
|
32
67
|
```
|
|
33
68
|
|
|
34
|
-
|
|
69
|
+
`body_schema` / `body_schema_missing` (exit `64`): re-read the operation schema. Server field-path errors: fix that path. Do not retry with a different envelope.
|
|
70
|
+
|
|
71
|
+
After it validates: create with `alphafox-trading`, or backtest with `alphafox-engine-backtest`. Do not create or backtest from this skill.
|
|
35
72
|
|
|
36
73
|
## operationIds
|
|
37
74
|
|
package/skills/trading/SKILL.md
CHANGED