@alphafox/cli 0.3.18 → 0.3.20
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/dist/catalog/generated/registry.json +1 -1
- package/dist/engine-backtest/progress.d.ts +9 -0
- package/dist/engine-backtest/progress.js +33 -0
- package/dist/engine-backtest/run-command.js +4 -12
- package/dist/engine-backtest/sweep-command.js +13 -21
- package/dist/engine-backtest/types.d.ts +1 -0
- package/dist/skills-manifest.json +40 -40
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/agents/issue-tracker.md +25 -136
- package/docs/agents/triage-labels.md +10 -13
- package/package.json +1 -1
- package/skills/account/SKILL.md +1 -1
- package/skills/admin/SKILL.md +3 -3
- package/skills/alphafox/SKILL.md +1 -1
- package/skills/alphafox-shared/SKILL.md +1 -1
- package/skills/auth/SKILL.md +1 -1
- package/skills/cache/SKILL.md +1 -1
- package/skills/engine-backtest/SKILL.md +3 -3
- 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 +1 -1
- package/skills/trading/SKILL.md +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"source": {
|
|
3
3
|
"package": "@alphafoxai/contracts",
|
|
4
4
|
"export": "public-api",
|
|
5
|
-
"contractsSha": "
|
|
5
|
+
"contractsSha": "daa775fc1e61d8416a32bd12c5301233d5ba518b",
|
|
6
6
|
"registryVersion": "3.0.0",
|
|
7
7
|
"contractVersion": "2026-08-31",
|
|
8
8
|
"scannedAt": "2026-08-31",
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const PROGRESS_MILESTONE_COUNT = 10;
|
|
2
|
+
type ProgressFormat = "json" | "jsonl" | "text";
|
|
3
|
+
type WriteLine = (value: unknown) => void;
|
|
4
|
+
/**
|
|
5
|
+
* Keeps JSONL useful for monitoring long runs without forwarding every
|
|
6
|
+
* high-frequency runtime callback to stdout.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createProgressEmitter(format: ProgressFormat, writeLine: WriteLine): (stage: string, fraction: number, detail?: string) => void;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROGRESS_MILESTONE_COUNT = void 0;
|
|
4
|
+
exports.createProgressEmitter = createProgressEmitter;
|
|
5
|
+
exports.PROGRESS_MILESTONE_COUNT = 10;
|
|
6
|
+
/**
|
|
7
|
+
* Keeps JSONL useful for monitoring long runs without forwarding every
|
|
8
|
+
* high-frequency runtime callback to stdout.
|
|
9
|
+
*/
|
|
10
|
+
function createProgressEmitter(format, writeLine) {
|
|
11
|
+
const lastMilestoneByStage = new Map();
|
|
12
|
+
const completedStages = new Set();
|
|
13
|
+
return (stage, fraction, detail) => {
|
|
14
|
+
if (format !== "jsonl")
|
|
15
|
+
return;
|
|
16
|
+
const milestone = Math.floor(fraction * exports.PROGRESS_MILESTONE_COUNT);
|
|
17
|
+
const lastMilestone = lastMilestoneByStage.get(stage);
|
|
18
|
+
const isFirstUpdate = lastMilestone === undefined;
|
|
19
|
+
const isNewMilestone = !isFirstUpdate && milestone > lastMilestone;
|
|
20
|
+
const isNewCompletion = fraction === 1 && !completedStages.has(stage);
|
|
21
|
+
if (!isFirstUpdate && !isNewMilestone && !isNewCompletion)
|
|
22
|
+
return;
|
|
23
|
+
lastMilestoneByStage.set(stage, milestone);
|
|
24
|
+
if (fraction === 1)
|
|
25
|
+
completedStages.add(stage);
|
|
26
|
+
writeLine({
|
|
27
|
+
event: "progress",
|
|
28
|
+
stage,
|
|
29
|
+
fraction,
|
|
30
|
+
...(detail ? { detail } : {}),
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -18,6 +18,7 @@ const sweep_command_1 = require("./sweep-command");
|
|
|
18
18
|
const persist_1 = require("./persist");
|
|
19
19
|
const paths_1 = require("../cache/paths");
|
|
20
20
|
const prepared_tape_1 = require("./prepared-tape");
|
|
21
|
+
const progress_1 = require("./progress");
|
|
21
22
|
const replay_timeframe_1 = require("./replay-timeframe");
|
|
22
23
|
const resolve_packages_1 = require("./resolve-packages");
|
|
23
24
|
var load_config_2 = require("./load-config");
|
|
@@ -154,16 +155,6 @@ async function loadAccountSubscriptionTier(api, profile, env) {
|
|
|
154
155
|
}
|
|
155
156
|
return tier;
|
|
156
157
|
}
|
|
157
|
-
function emitProgress(flags, writeLine, stage, fraction, detail) {
|
|
158
|
-
if (flags.format !== "jsonl")
|
|
159
|
-
return;
|
|
160
|
-
writeLine({
|
|
161
|
-
event: "progress",
|
|
162
|
-
stage,
|
|
163
|
-
fraction,
|
|
164
|
-
...(detail ? { detail } : {}),
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
158
|
async function executeEngineBacktestRun(args, flags, env = process.env, deps = {}) {
|
|
168
159
|
if (args.help) {
|
|
169
160
|
throw new errors_1.EngineBacktestError({
|
|
@@ -189,6 +180,7 @@ async function executeEngineBacktestRun(args, flags, env = process.env, deps = {
|
|
|
189
180
|
((value) => {
|
|
190
181
|
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
191
182
|
});
|
|
183
|
+
const emitProgress = (0, progress_1.createProgressEmitter)(flags.format, writeLine);
|
|
192
184
|
const persist = args.persist && !flags.dryRun;
|
|
193
185
|
const createExperiment = args.createExperiment && !flags.dryRun;
|
|
194
186
|
const needsApi = persist || createExperiment;
|
|
@@ -323,7 +315,7 @@ async function executeEngineBacktestRun(args, flags, env = process.env, deps = {
|
|
|
323
315
|
cacheDir: (0, paths_1.resolveTapeCacheDir)(env),
|
|
324
316
|
seriesConcurrency: prepared_tape_1.ENGINE_BACKTEST_TAPE_SERIES_CONCURRENCY,
|
|
325
317
|
onProgress: (progress) => {
|
|
326
|
-
emitProgress(
|
|
318
|
+
emitProgress(progress.stage || "tape", progress.fraction, progress.detail);
|
|
327
319
|
},
|
|
328
320
|
});
|
|
329
321
|
}
|
|
@@ -363,7 +355,7 @@ async function executeEngineBacktestRun(args, flags, env = process.env, deps = {
|
|
|
363
355
|
let result;
|
|
364
356
|
try {
|
|
365
357
|
result = (0, prepared_tape_1.requireCompletedPreparedRun)(await client.runPreparedBacktest(prepared.handle, scenario, (fraction) => {
|
|
366
|
-
emitProgress(
|
|
358
|
+
emitProgress("wasm", fraction);
|
|
367
359
|
}));
|
|
368
360
|
}
|
|
369
361
|
catch (error) {
|
|
@@ -15,6 +15,7 @@ const web_ui_config_defaults_1 = require("./web-ui-config-defaults");
|
|
|
15
15
|
const parse_axes_1 = require("./parse-axes");
|
|
16
16
|
const persist_1 = require("./persist");
|
|
17
17
|
const prepared_tape_1 = require("./prepared-tape");
|
|
18
|
+
const progress_1 = require("./progress");
|
|
18
19
|
const replay_timeframe_1 = require("./replay-timeframe");
|
|
19
20
|
const resolve_packages_1 = require("./resolve-packages");
|
|
20
21
|
const sweep_kernel_1 = require("./sweep-kernel");
|
|
@@ -69,6 +70,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
69
70
|
((value) => {
|
|
70
71
|
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
71
72
|
});
|
|
73
|
+
const emitProgress = (0, progress_1.createProgressEmitter)(flags.format, writeLine);
|
|
72
74
|
if (persist) {
|
|
73
75
|
requireAuth(profile, env, tokensFn);
|
|
74
76
|
}
|
|
@@ -128,7 +130,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
128
130
|
status: 400,
|
|
129
131
|
});
|
|
130
132
|
}
|
|
131
|
-
emitProgress(
|
|
133
|
+
emitProgress("planning", 0);
|
|
132
134
|
const plannedByKey = new Map();
|
|
133
135
|
const tapePlans = [];
|
|
134
136
|
for (const [index, coordinate] of standardPlan.coordinates.entries()) {
|
|
@@ -144,7 +146,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
144
146
|
if ("plan" in planned) {
|
|
145
147
|
tapePlans.push(planned.plan);
|
|
146
148
|
}
|
|
147
|
-
emitProgress(
|
|
149
|
+
emitProgress("planning", (index + 1) / standardPlan.coordinates.length);
|
|
148
150
|
}
|
|
149
151
|
let exchange;
|
|
150
152
|
try {
|
|
@@ -165,7 +167,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
165
167
|
seriesRequirements: coverage.seriesRequirements,
|
|
166
168
|
symbols: coverage.symbols,
|
|
167
169
|
});
|
|
168
|
-
emitProgress(
|
|
170
|
+
emitProgress("tape", 0);
|
|
169
171
|
let tapeResult = {
|
|
170
172
|
tape: {
|
|
171
173
|
from: "",
|
|
@@ -195,7 +197,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
195
197
|
cacheDir: (0, paths_1.resolveTapeCacheDir)(env),
|
|
196
198
|
seriesConcurrency: prepared_tape_1.ENGINE_BACKTEST_TAPE_SERIES_CONCURRENCY,
|
|
197
199
|
onProgress: (progress) => {
|
|
198
|
-
emitProgress(
|
|
200
|
+
emitProgress(progress.stage || "tape", progress.fraction, progress.detail);
|
|
199
201
|
},
|
|
200
202
|
});
|
|
201
203
|
}
|
|
@@ -217,7 +219,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
217
219
|
coverageIssues: (0, coverage_notice_1.requireTapeCoverageIssues)(tapeResult.coverageIssues),
|
|
218
220
|
};
|
|
219
221
|
}
|
|
220
|
-
emitProgress(
|
|
222
|
+
emitProgress("tape", 1);
|
|
221
223
|
while (clients.length < concurrency) {
|
|
222
224
|
const extra = wasm.createNodeBacktestClient();
|
|
223
225
|
clients.push(extra);
|
|
@@ -274,10 +276,10 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
274
276
|
? standardPlan.coordinates.length
|
|
275
277
|
: coarsePlan.coordinates.length;
|
|
276
278
|
let sweepPoints = [];
|
|
277
|
-
emitProgress(
|
|
279
|
+
emitProgress("sweep", 0);
|
|
278
280
|
const coarsePoints = await runPrepared(coarsePlan.coordinates, (done, points) => {
|
|
279
281
|
sweepPoints = points;
|
|
280
|
-
emitProgress(
|
|
282
|
+
emitProgress("sweep", done / Math.max(exactTotalEstimate, 1));
|
|
281
283
|
});
|
|
282
284
|
sweepPoints = coarsePoints;
|
|
283
285
|
let refinement = [];
|
|
@@ -294,12 +296,12 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
294
296
|
if (refinement.length > 0) {
|
|
295
297
|
const refinementPoints = await runPrepared(refinement, (done, points) => {
|
|
296
298
|
sweepPoints = [...coarsePoints, ...points];
|
|
297
|
-
emitProgress(
|
|
299
|
+
emitProgress("sweep", (coarsePlan.coordinates.length + done) /
|
|
298
300
|
(coarsePlan.coordinates.length + refinement.length));
|
|
299
301
|
});
|
|
300
302
|
sweepPoints = [...coarsePoints, ...refinementPoints];
|
|
301
303
|
}
|
|
302
|
-
emitProgress(
|
|
304
|
+
emitProgress("sweep", 1);
|
|
303
305
|
const engineVersion = (typeof client.version === "function"
|
|
304
306
|
? (await client.version()).trim()
|
|
305
307
|
: "") || "node-wasm";
|
|
@@ -317,7 +319,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
317
319
|
let clientSweepId;
|
|
318
320
|
let persisted = false;
|
|
319
321
|
if (persist && completed) {
|
|
320
|
-
emitProgress(
|
|
322
|
+
emitProgress("persist", 0);
|
|
321
323
|
if (createExperiment) {
|
|
322
324
|
const created = await postJson(api, profile, env, CREATE_EXPERIMENT_PATH, {
|
|
323
325
|
name: args.name,
|
|
@@ -397,7 +399,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
|
|
|
397
399
|
});
|
|
398
400
|
}
|
|
399
401
|
persisted = true;
|
|
400
|
-
emitProgress(
|
|
402
|
+
emitProgress("persist", 1);
|
|
401
403
|
}
|
|
402
404
|
return {
|
|
403
405
|
persisted,
|
|
@@ -767,13 +769,3 @@ function asConfigRecord(value) {
|
|
|
767
769
|
function coordinateKey(coordinate) {
|
|
768
770
|
return coordinate.values.join("\u0000");
|
|
769
771
|
}
|
|
770
|
-
function emitProgress(flags, writeLine, stage, fraction, detail) {
|
|
771
|
-
if (flags.format !== "jsonl")
|
|
772
|
-
return;
|
|
773
|
-
writeLine({
|
|
774
|
-
event: "progress",
|
|
775
|
-
stage,
|
|
776
|
-
fraction,
|
|
777
|
-
...(detail ? { detail } : {}),
|
|
778
|
-
});
|
|
779
|
-
}
|
|
@@ -115,6 +115,7 @@ export interface EngineBacktestMetrics {
|
|
|
115
115
|
readonly winRatePct: number;
|
|
116
116
|
readonly feesPaid: number;
|
|
117
117
|
readonly slippagePaid: number;
|
|
118
|
+
readonly maxLeverage?: number;
|
|
118
119
|
readonly liquidated: boolean;
|
|
119
120
|
}
|
|
120
121
|
export interface EngineBacktestResult {
|
|
@@ -1,153 +1,153 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "@alphafox/cli",
|
|
4
|
-
"packageVersion": "0.3.
|
|
4
|
+
"packageVersion": "0.3.20",
|
|
5
5
|
"contractVersion": "2026-08-31",
|
|
6
|
-
"bundleHash": "
|
|
6
|
+
"bundleHash": "ca170c6f023704493568335720fd82f73cd7b7a34dab795e39f3920cfa4d47d5",
|
|
7
7
|
"skills": [
|
|
8
8
|
{
|
|
9
9
|
"name": "alphafox",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.20",
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"path": "SKILL.md",
|
|
14
|
-
"sha256": "
|
|
14
|
+
"sha256": "87bfa86a0be66a6737282286b3def88cc15485dac3245ea26d462334a03cc686",
|
|
15
15
|
"size": 7950
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
-
"hash": "
|
|
18
|
+
"hash": "1717e3a193ebc73813d7029dc700d735bdded791a628a8d42a40245912b7effc"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "alphafox-account",
|
|
22
|
-
"version": "0.3.
|
|
22
|
+
"version": "0.3.20",
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "SKILL.md",
|
|
26
|
-
"sha256": "
|
|
26
|
+
"sha256": "cda48226d5c00160a5373a457f813f9fe9b44fe8e17a1ff9e267e507b586227a",
|
|
27
27
|
"size": 784
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
-
"hash": "
|
|
30
|
+
"hash": "271fad09bfdabbea108182f32e03ee660e30f8f69b176c128b67491c3cb95bea"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "alphafox-admin",
|
|
34
|
-
"version": "0.3.
|
|
34
|
+
"version": "0.3.20",
|
|
35
35
|
"files": [
|
|
36
36
|
{
|
|
37
37
|
"path": "SKILL.md",
|
|
38
|
-
"sha256": "
|
|
39
|
-
"size":
|
|
38
|
+
"sha256": "87c7141e1a4eb23f62ef5091a1d329d4d63926c7ffecd9f36fe2363c5ae77baa",
|
|
39
|
+
"size": 2078
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "af6a0f2e8438578ba047e5f95bb69e7ce0919f5d947634203bdd0a1aea963e39"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "alphafox-auth",
|
|
46
|
-
"version": "0.3.
|
|
46
|
+
"version": "0.3.20",
|
|
47
47
|
"files": [
|
|
48
48
|
{
|
|
49
49
|
"path": "SKILL.md",
|
|
50
|
-
"sha256": "
|
|
50
|
+
"sha256": "285ff81745bb8336af4b0d68ae1d6fb212120d357b0b70f1a090815d4b3038b2",
|
|
51
51
|
"size": 2371
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"hash": "
|
|
54
|
+
"hash": "f2dcab96b60491f9a3c18bcbd7e4a855ee645c144e2178351091b3c0d72d5830"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "alphafox-cache",
|
|
58
|
-
"version": "0.3.
|
|
58
|
+
"version": "0.3.20",
|
|
59
59
|
"files": [
|
|
60
60
|
{
|
|
61
61
|
"path": "SKILL.md",
|
|
62
|
-
"sha256": "
|
|
62
|
+
"sha256": "1bfd3487e1d155f8c250d6f1f96b555f56ca267f99691845656e60026bf98db8",
|
|
63
63
|
"size": 1530
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
|
-
"hash": "
|
|
66
|
+
"hash": "a3e23a1ec43760757473b54604aa8e6535cf4c9329884ff5e408365e77baf9e1"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "alphafox-engine-backtest",
|
|
70
|
-
"version": "0.3.
|
|
70
|
+
"version": "0.3.20",
|
|
71
71
|
"files": [
|
|
72
72
|
{
|
|
73
73
|
"path": "SKILL.md",
|
|
74
|
-
"sha256": "
|
|
75
|
-
"size":
|
|
74
|
+
"sha256": "074c54274b962267101b8b2e6d51c7054345c5d79c841299fa8ccd084e134a9d",
|
|
75
|
+
"size": 9360
|
|
76
76
|
}
|
|
77
77
|
],
|
|
78
|
-
"hash": "
|
|
78
|
+
"hash": "d43d2be349a3c4e97c45d3dd560bcaccbffcd6c3dafae9795b7bdd641352b291"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "alphafox-exchange",
|
|
82
|
-
"version": "0.3.
|
|
82
|
+
"version": "0.3.20",
|
|
83
83
|
"files": [
|
|
84
84
|
{
|
|
85
85
|
"path": "SKILL.md",
|
|
86
|
-
"sha256": "
|
|
86
|
+
"sha256": "46ee8cd0b8a4cebce8f15dfa1faec604880ea3547f2c9647b4b820e6d40f2a0a",
|
|
87
87
|
"size": 744
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "03373a84634e21bcc1325f6d2caa000063e9a6e49794c6f8368b0a1aab28b064"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"name": "alphafox-market",
|
|
94
|
-
"version": "0.3.
|
|
94
|
+
"version": "0.3.20",
|
|
95
95
|
"files": [
|
|
96
96
|
{
|
|
97
97
|
"path": "SKILL.md",
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "41ded9162c51d32c1bd4b03eaa59fa3a32fb799a27828f1ccdf16d49e449b187",
|
|
99
99
|
"size": 3079
|
|
100
100
|
}
|
|
101
101
|
],
|
|
102
|
-
"hash": "
|
|
102
|
+
"hash": "5e54514b833faa00b906424c967dee34c302ea44377c8b6cde43457e358b4a4a"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "alphafox-notification",
|
|
106
|
-
"version": "0.3.
|
|
106
|
+
"version": "0.3.20",
|
|
107
107
|
"files": [
|
|
108
108
|
{
|
|
109
109
|
"path": "SKILL.md",
|
|
110
|
-
"sha256": "
|
|
110
|
+
"sha256": "ec3682d888512bd5ce3937ca691ce66d1c6ab71bcb834bc26fa65b74baa8f7b1",
|
|
111
111
|
"size": 699
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
|
-
"hash": "
|
|
114
|
+
"hash": "f3fecdd9069200c456c3e809679d6d6bf01638aadf1be08861d4dff2fd13309b"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "alphafox-shared",
|
|
118
|
-
"version": "0.3.
|
|
118
|
+
"version": "0.3.20",
|
|
119
119
|
"files": [
|
|
120
120
|
{
|
|
121
121
|
"path": "SKILL.md",
|
|
122
|
-
"sha256": "
|
|
122
|
+
"sha256": "41284bfad66f187a3ee57a9134f9cbf341beb1ce20581dcdf5981f2a0af581af",
|
|
123
123
|
"size": 6920
|
|
124
124
|
}
|
|
125
125
|
],
|
|
126
|
-
"hash": "
|
|
126
|
+
"hash": "1595fdcb3095ad7ed55af5b2a79e043a389a06c48cb806e2e3e04dd0ab305830"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"name": "alphafox-strategy",
|
|
130
|
-
"version": "0.3.
|
|
130
|
+
"version": "0.3.20",
|
|
131
131
|
"files": [
|
|
132
132
|
{
|
|
133
133
|
"path": "SKILL.md",
|
|
134
|
-
"sha256": "
|
|
134
|
+
"sha256": "6d889ac8c1dde1f2581133975cc23f25b8e2793ee4c90b7c3ccc85ffbe2e01d8",
|
|
135
135
|
"size": 4862
|
|
136
136
|
}
|
|
137
137
|
],
|
|
138
|
-
"hash": "
|
|
138
|
+
"hash": "148851ac3cc355de419b1dafe08f684fa8d7ea98967f14c0b01d83ea0ef800b8"
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"name": "alphafox-trading",
|
|
142
|
-
"version": "0.3.
|
|
142
|
+
"version": "0.3.20",
|
|
143
143
|
"files": [
|
|
144
144
|
{
|
|
145
145
|
"path": "SKILL.md",
|
|
146
|
-
"sha256": "
|
|
146
|
+
"sha256": "bef37f59c7511127794ba8edbbdde3f56bde543d0051b6dbfe5f0360168a2698",
|
|
147
147
|
"size": 4493
|
|
148
148
|
}
|
|
149
149
|
],
|
|
150
|
-
"hash": "
|
|
150
|
+
"hash": "538a934c5e807af73da35c7ae85cd3921ee92a00f34648484a1c7e3eeb0fbc52"
|
|
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.20";
|
|
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.20";
|
|
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; } });
|
|
@@ -1,156 +1,45 @@
|
|
|
1
|
-
# Issue tracker:
|
|
1
|
+
# Issue tracker: GitHub
|
|
2
2
|
|
|
3
|
-
Issues and specs for this repo live as
|
|
4
|
-
|
|
5
|
-
List: <https://applink.feishu.cn/client/todo/task_list?guid=6d628d79-cdfe-47cc-98f7-35561944494b>
|
|
6
|
-
|
|
7
|
-
## Identifiers
|
|
8
|
-
|
|
9
|
-
An issue's identity is its **task GUID** — a UUID. There is no usable short number: the `t101420`-style id the Feishu UI shows (`task_id`, `suite_entity_num`) is **display-only** and every API rejects it, so a bare `#42` or `t101420` cannot be looked up directly.
|
|
10
|
-
|
|
11
|
-
- Prefer the task **URL** (`https://applink.feishu.cn/client/todo/detail?guid=<GUID>`) — the GUID is the `guid` query param. Every write command below also accepts the URL in place of the GUID.
|
|
12
|
-
- Given only a `t1014xx` number or a title fragment, resolve it with `lark-cli task +search --query "<title words>" --as user` and match on `summary`. Search spans **all** the user's tasks, not just this tasklist, so confirm the match before writing.
|
|
13
|
-
- When narrating to the human, refer to an issue by its **title**, not its GUID.
|
|
14
|
-
|
|
15
|
-
## Setup values
|
|
16
|
-
|
|
17
|
-
- **Tasklist GUID**: `6d628d79-cdfe-47cc-98f7-35561944494b`
|
|
18
|
-
- **`Type` field GUID**: `227d69e7-e535-40f0-b64f-4e90247149e2`
|
|
19
|
-
|
|
20
|
-
Triage roles are **sections** — a task sits in exactly one, so the state machine can't be violated. `待分类` is the default section, so anything created without a section lands there as untriaged.
|
|
21
|
-
|
|
22
|
-
| Canonical role | Section | Section GUID |
|
|
23
|
-
| -------------- | ------- | ------------ |
|
|
24
|
-
| _(untriaged)_ | `待分类` (default) | `4ca8fd68-9a08-5794-1598-8e5a394e8638` |
|
|
25
|
-
| `needs-triage` | `待评估` | `44e58692-1ced-462b-99bb-bf082a745ef3` |
|
|
26
|
-
| `needs-info` | `待补充信息` | `0cff4cf9-00b9-42bd-b482-5cd06a51b99b` |
|
|
27
|
-
| `ready-for-agent` | `可交给 Agent` | `1ce586d5-7953-4d68-b41a-d4b2851f5806` |
|
|
28
|
-
| `ready-for-human` | `需人工处理` | `8713387c-e758-4730-9de8-0b30859674ff` |
|
|
29
|
-
| `wontfix` | `不予处理` | `00d4b874-1a4a-43d8-b0cf-fcb52460f9bf` |
|
|
30
|
-
| _(wayfinder — outside the triage queue)_ | `探路图` | `bab88abf-0bf9-407d-806b-680901a86dd7` |
|
|
31
|
-
|
|
32
|
-
Every other label is an option on the single-select `Type` field. Address an option by its GUID, never by name — the skills' canonical labels use a colon (`wayfinder:map`) while the Feishu options are named with a hyphen (`wayfinder-map`), so this table is the only mapping between them:
|
|
33
|
-
|
|
34
|
-
| Label | Option GUID |
|
|
35
|
-
| ----- | ----------- |
|
|
36
|
-
| `bug` | `0eb51704-bead-4e8e-93be-dd8d02c1d20c` |
|
|
37
|
-
| `enhancement` | `ebd05bc8-ab6c-4a56-8628-6c3284d9f1f9` |
|
|
38
|
-
| `spec` | `399a640f-5d51-4dab-a4f3-da3df638ec8a` |
|
|
39
|
-
| `ticket` | `3bb7ca44-ac8c-4b75-8925-96fc457fb974` |
|
|
40
|
-
| `wayfinder:map` | `8cd13987-010e-46f0-808f-a8f289791cf5` |
|
|
41
|
-
| `wayfinder:research` | `f18b808a-d978-41cb-9bef-cd0708fecf0c` |
|
|
42
|
-
| `wayfinder:prototype` | `49126969-48dc-4297-96d4-36d176ffb8bb` |
|
|
43
|
-
| `wayfinder:grilling` | `265feb46-9ac8-4c03-afa8-9400296defe4` |
|
|
44
|
-
| `wayfinder:task` | `ed48b848-01d0-406b-ac7d-a96ce66cee0d` |
|
|
3
|
+
Issues and specs for this repo live as GitHub issues. Use the `gh` CLI for all operations.
|
|
45
4
|
|
|
46
5
|
## Conventions
|
|
47
6
|
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
|
|
51
|
-
- **
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
lark-cli task tasks create --as user --params '{"user_id_type":"open_id"}' --data '{
|
|
55
|
-
"summary": "<title>",
|
|
56
|
-
"description": "<body>",
|
|
57
|
-
"tasklists": [{"tasklist_guid": "6d628d79-cdfe-47cc-98f7-35561944494b", "section_guid": "<SECTION_GUID>"}],
|
|
58
|
-
"custom_fields": [{"guid": "227d69e7-e535-40f0-b64f-4e90247149e2", "single_select_value": "<OPTION_GUID>"}]
|
|
59
|
-
}'
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
For an untriaged issue with no label, `lark-cli task +create --tasklist-id 6d628d79-cdfe-47cc-98f7-35561944494b --summary "..." --description "..." --as user` is enough — it lands in `待分类`.
|
|
63
|
-
|
|
64
|
-
- **Read an issue** — the body and the comments are two calls:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
lark-cli task tasks get --as user --params '{"task_guid": "<GUID>", "user_id_type": "open_id"}'
|
|
68
|
-
lark-cli api GET /open-apis/task/v2/comments --as user \
|
|
69
|
-
--params '{"resource_type": "task", "resource_id": "<GUID>", "page_size": 50, "user_id_type": "open_id"}'
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
`tasks get` returns `description` (the body), `custom_fields` (the `Type` label), `tasklists[].section_guid` (the triage role), `members` (assignees), `status` (`todo`/`done`), `dependencies` (blockers) and `parent_task_guid`. Comments are **not** exposed by `lark-cli task`; the raw `api` call above is the only way to read them.
|
|
73
|
-
|
|
74
|
-
- **List a triage bucket** — one call per section, and this is the cheap path:
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
lark-cli task sections tasks --as user --params '{"section_guid": "<SECTION_GUID>", "completed": false, "page_size": 100}'
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Returns a brief per task — `guid`, `summary`, `completed_at`, `subtask_count` — which is all a queue listing needs. Pass `created_from`/`created_to` to window by age; results come oldest-first. Reading a task's `Type` or assignees means a `tasks get` per task, so don't do it while building a queue listing.
|
|
81
|
-
|
|
82
|
-
- **List every issue**: `lark-cli task tasklists tasks --as user --params '{"tasklist_guid": "6d628d79-cdfe-47cc-98f7-35561944494b", "completed": false, "page_size": 100}'`.
|
|
7
|
+
- **Create an issue**: `gh issue create --title "..." --body "..."`. Use a heredoc for multi-line bodies.
|
|
8
|
+
- **Read an issue**: `gh issue view <number> --comments`, filtering comments by `jq` and also fetching labels.
|
|
9
|
+
- **List issues**: `gh issue list --state open --json number,title,body,labels,comments --jq '[.[] | {number, title, body, labels: [.labels[].name], comments: [.comments[].body]}]'` with appropriate `--label` and `--state` filters.
|
|
10
|
+
- **Comment on an issue**: `gh issue comment <number> --body "..."`
|
|
11
|
+
- **Apply / remove labels**: `gh issue edit <number> --add-label "..."` / `--remove-label "..."`
|
|
12
|
+
- **Close**: `gh issue close <number> --comment "..."`
|
|
83
13
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
- **Apply a triage role** — move the task to that role's section. Re-adding an existing task with a new `--section-guid` moves it; there is no separate "remove from old section" step:
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
lark-cli task +tasklist-task-add --tasklist-id 6d628d79-cdfe-47cc-98f7-35561944494b --task-id <GUID> --section-guid <SECTION_GUID> --as user
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
- **Apply a `Type` label** — patch the custom field. This replaces the previous value, since the field is single-select:
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
lark-cli task tasks patch --as user --params '{"task_guid": "<GUID>"}' --data '{
|
|
96
|
-
"task": {"custom_fields": [{"guid": "227d69e7-e535-40f0-b64f-4e90247149e2", "single_select_value": "<OPTION_GUID>"}]},
|
|
97
|
-
"update_fields": ["custom_fields"]
|
|
98
|
-
}'
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
- **Edit the body**: same shape, with `{"task": {"description": "..."}, "update_fields": ["description"]}`. A patch **replaces** the description, so read it first and re-send the whole text.
|
|
102
|
-
|
|
103
|
-
- **Every markdown link in a body needs a real absolute URL.** Feishu parses `[text](target)` in `description` and validates the target, rejecting the entire write with `Invalid Param 'description', url in description is invalid` when it isn't one. A placeholder `(link)`, an empty `()`, and a repo-relative `(./src/foo.ts)` all fail. Link to an absolute `https://` URL, or drop the link syntax and name the thing in plain text. Headings, lists, bold, bare URLs and task GUIDs are all fine.
|
|
104
|
-
|
|
105
|
-
- **Close**: `lark-cli task +complete --task-id <GUID> --as user`. It takes no closing comment, so post the explanation with `+comment` first, then complete. Reopen with `lark-cli task +reopen --task-id <GUID> --as user`.
|
|
106
|
-
|
|
107
|
-
- **Assign**: `lark-cli task +assign --task-id <GUID> --add <open_id> --as user` (`--remove` to unassign). Get your own `open_id` from `lark-cli auth status --jq '.identities.user.openId'`.
|
|
14
|
+
Infer the repo from `git remote -v`; `gh` does this automatically when run inside a clone.
|
|
108
15
|
|
|
109
16
|
## Pull requests as a triage surface
|
|
110
17
|
|
|
111
18
|
**PRs as a request surface: no.** _(Set to `yes` if this repo treats external PRs as feature requests; `/triage` reads this flag.)_
|
|
112
19
|
|
|
113
|
-
|
|
20
|
+
When set to `yes`, PRs run through the same labels and states as issues, using the `gh pr` equivalents:
|
|
21
|
+
|
|
22
|
+
- **Read a PR**: `gh pr view <number> --comments` and `gh pr diff <number>` for the diff.
|
|
23
|
+
- **List external PRs for triage**: `gh pr list --state open --json number,title,body,labels,author,authorAssociation,comments` then keep only `authorAssociation` of `CONTRIBUTOR`, `FIRST_TIME_CONTRIBUTOR`, or `NONE` (drop `OWNER`/`MEMBER`/`COLLABORATOR`).
|
|
24
|
+
- **Comment / label / close**: `gh pr comment`, `gh pr edit --add-label`/`--remove-label`, `gh pr close`.
|
|
25
|
+
|
|
26
|
+
GitHub shares one number space across issues and PRs, so a bare `#42` may be either: resolve with `gh pr view 42` and fall back to `gh issue view 42`.
|
|
114
27
|
|
|
115
28
|
## When a skill says "publish to the issue tracker"
|
|
116
29
|
|
|
117
|
-
Create a
|
|
30
|
+
Create a GitHub issue.
|
|
118
31
|
|
|
119
32
|
## When a skill says "fetch the relevant ticket"
|
|
120
33
|
|
|
121
|
-
Run `
|
|
34
|
+
Run `gh issue view <number> --comments`.
|
|
122
35
|
|
|
123
36
|
## Wayfinding operations
|
|
124
37
|
|
|
125
|
-
Used by `/wayfinder`. The **map** is a
|
|
126
|
-
|
|
127
|
-
- **Map**: a task with `Type` = `wayfinder:map`, in `探路图`, holding the Destination / Notes / Decisions-so-far / Fog body in `description`.
|
|
128
|
-
- **Child ticket**: create the task, then parent it — `lark-cli task +set-ancestor --task-id <CHILD_GUID> --ancestor-id <MAP_GUID> --as user`. Parenting **keeps** the child's tasklist and section membership, so tickets stay visible in `探路图`. Label each with `Type` = `wayfinder:<type>`.
|
|
129
|
-
- **Blocking**: Feishu's **native task dependencies** — the canonical, UI-visible representation. `type: "prev"` means "blocks this task", so a child blocked by another records the blocker as `prev`:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
lark-cli api POST /open-apis/task/v2/tasks/<CHILD_GUID>/add_dependencies --as user \
|
|
133
|
-
--data '{"dependencies": [{"task_guid": "<BLOCKER_GUID>", "type": "prev"}]}'
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
The reciprocal `next` edge appears on the blocker automatically. Drop an edge with `--data '{"dependencies": [{"task_guid": "<BLOCKER_GUID>"}]}'` against `.../remove_dependencies`. Dependencies are **not** settable through `tasks create` or `tasks patch` — the raw `api` call is the only route, so tickets must exist before they can be wired, which is why charting creates first and wires second.
|
|
137
|
-
|
|
138
|
-
- **Frontier query** — one call, because `subtasks list` returns *full* task objects rather than briefs:
|
|
139
|
-
|
|
140
|
-
```bash
|
|
141
|
-
lark-cli task subtasks list --as user --params '{"task_guid": "<MAP_GUID>", "page_size": 100, "user_id_type": "open_id"}'
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
Each child carries `status`, `members`, `dependencies` and `description`. Filter locally: keep `status` of `todo`, drop any with a `members` entry whose `role` is `assignee` (claimed), and drop any whose `prev` dependencies include a task still `todo` (blocked). Blockers that are siblings on the same map are already in this response; resolve any others with `tasks get`. First in map order wins.
|
|
145
|
-
|
|
146
|
-
- **Claim**: `lark-cli task +assign --task-id <GUID> --add <your open_id> --as user` — the session's first write.
|
|
147
|
-
- **Resolve**: `+comment` with the answer, then `+complete`, then patch the map's `description` to append a context pointer to Decisions-so-far. That pointer's link must be the ticket's full applink URL — a Decisions-so-far line written as `[title](link)` is rejected by the description's URL validation, taking the whole map update with it.
|
|
148
|
-
|
|
149
|
-
## Re-reading the setup values
|
|
150
|
-
|
|
151
|
-
```bash
|
|
152
|
-
lark-cli task sections list --as user --params '{"resource_type": "tasklist", "resource_id": "6d628d79-cdfe-47cc-98f7-35561944494b", "page_size": 50}'
|
|
153
|
-
lark-cli task custom_fields list --as user --params '{"resource_type": "tasklist", "resource_id": "6d628d79-cdfe-47cc-98f7-35561944494b", "page_size": 50}'
|
|
154
|
-
```
|
|
38
|
+
Used by `/wayfinder`. The **map** is a single issue with **child** issues as tickets.
|
|
155
39
|
|
|
156
|
-
|
|
40
|
+
- **Map**: a single issue labelled `wayfinder:map`, holding the Notes / Decisions-so-far / Fog body. `gh issue create --label wayfinder:map`.
|
|
41
|
+
- **Child ticket**: an issue linked to the map as a GitHub sub-issue (`gh api` on the sub-issues endpoint). Where sub-issues aren't enabled, add the child to a task list in the map body and put `Part of #<map>` at the top of the child body. Labels: `wayfinder:<type>` (`research`/`prototype`/`grilling`/`task`). Once claimed, the ticket is assigned to the driving dev.
|
|
42
|
+
- **Blocking**: GitHub's **native issue dependencies**, the canonical, UI-visible representation. Add an edge with `gh api --method POST repos/<owner>/<repo>/issues/<child>/dependencies/blocked_by -F issue_id=<blocker-db-id>`, where `<blocker-db-id>` is the blocker's numeric **database id** (`gh api repos/<owner>/<repo>/issues/<n> --jq .id`, _not_ the `#number` or `node_id`). GitHub reports `issue_dependencies_summary.blocked_by` (open blockers only, the live gate). Where dependencies aren't available, fall back to a `Blocked by: #<n>, #<n>` line at the top of the child body. A ticket is unblocked when every blocker is closed.
|
|
43
|
+
- **Frontier query**: list the map's open children (`gh issue list --state open`, scoped to the map's sub-issues / task list), drop any with an open blocker (`issue_dependencies_summary.blocked_by > 0`, or an open issue in the `Blocked by` line) or an assignee; first in map order wins.
|
|
44
|
+
- **Claim**: `gh issue edit <n> --add-assignee @me`, the session's first write.
|
|
45
|
+
- **Resolve**: `gh issue comment <n> --body "<answer>"`, then `gh issue close <n>`, then append a context pointer (gist + link) to the map's Decisions-so-far.
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
# Triage Labels
|
|
2
2
|
|
|
3
|
-
The skills speak in terms of five canonical triage roles.
|
|
3
|
+
The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker.
|
|
4
4
|
|
|
5
|
-
| Label in mattpocock/skills |
|
|
6
|
-
| -------------------------- |
|
|
7
|
-
|
|
|
8
|
-
| `needs-
|
|
9
|
-
| `
|
|
10
|
-
| `ready-for-
|
|
11
|
-
| `
|
|
12
|
-
| `wontfix` | `不予处理` | Will not be actioned |
|
|
5
|
+
| Label in mattpocock/skills | Label in our tracker | Meaning |
|
|
6
|
+
| -------------------------- | -------------------- | ---------------------------------------- |
|
|
7
|
+
| `needs-triage` | `needs-triage` | Maintainer needs to evaluate this issue |
|
|
8
|
+
| `needs-info` | `needs-info` | Waiting on reporter for more information |
|
|
9
|
+
| `ready-for-agent` | `ready-for-agent` | Fully specified, ready for an AFK agent |
|
|
10
|
+
| `ready-for-human` | `ready-for-human` | Requires human implementation |
|
|
11
|
+
| `wontfix` | `wontfix` | Will not be actioned |
|
|
13
12
|
|
|
14
|
-
When a skill mentions a role (e.g. "apply the AFK-ready triage label"),
|
|
13
|
+
When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table.
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
Editing the right-hand column here is not enough on its own: rename a section in Feishu and its GUID stays the same, so update this table and leave `issue-tracker.md`'s GUIDs alone. Adding or removing a section is the case that changes GUIDs, and then both files need re-syncing.
|
|
15
|
+
Edit the right-hand column to match whatever vocabulary you actually use.
|
package/package.json
CHANGED
package/skills/account/SKILL.md
CHANGED
package/skills/admin/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-admin
|
|
3
3
|
description: Admin-only operations reusing Web role authorization.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Admin
|
|
@@ -16,7 +16,7 @@ High-risk cataloged admin writes: `alphafox schema <operationId>` first, then `-
|
|
|
16
16
|
|
|
17
17
|
## Passivbot paper acceptance
|
|
18
18
|
|
|
19
|
-
This Stage 1 endpoint is intentionally absent from the public Operation Registry and typed CLI catalog. The only allowed uncataloged admin path is the exact direct route below. Its JSON body is strict: `name`, `exchangeConnectorId`, and `config` are required; `configSchemaVersion`
|
|
19
|
+
This Stage 1 endpoint is intentionally absent from the public Operation Registry and typed CLI catalog. The only allowed uncataloged admin path is the exact direct route below. Its JSON body is strict: `name`, `exchangeConnectorId`, and `config` are required; `configSchemaVersion` accepts only `1` and `2`; `autoStart` is optional and defaults to `true`. Use `2` for new acceptance traders and `1` only when replaying an existing v1 config. The `config` object must match the selected version. Do not add server-owned fields.
|
|
20
20
|
|
|
21
21
|
Preview the exact raw request first. The unknown/high-risk gate must return `confirmation_required`; show the requested action and risk to the operator, wait for explicit confirmation, then rerun the same command with `--yes`.
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ The config file shape is:
|
|
|
31
31
|
{
|
|
32
32
|
"name": "Passivbot paper acceptance",
|
|
33
33
|
"exchangeConnectorId": "<internal-paper-connector-id>",
|
|
34
|
-
"configSchemaVersion":
|
|
34
|
+
"configSchemaVersion": 2,
|
|
35
35
|
"config": {},
|
|
36
36
|
"autoStart": true
|
|
37
37
|
}
|
package/skills/alphafox/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox
|
|
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 回测 or 运行策略, include the dashboard URL from the domain skill. When the user asks 排行榜, include https://www.alphafox.app/zh/dashboard/leaderboard. 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.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox
|
package/skills/auth/SKILL.md
CHANGED
package/skills/cache/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-engine-backtest
|
|
3
3
|
description: Local Engine WASM backtest (alphafox engine-backtest run|sweep) vs catalog experiment CRUD. After a persisted run, include https://www.alphafox.app/zh/dashboard/traders/backtest/{experimentId}.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Engine Backtest
|
|
@@ -56,7 +56,7 @@ alphafox engine-backtest run \
|
|
|
56
56
|
|
|
57
57
|
Also valid: `--from` / `--to` instead of `--range`. `--create-experiment --name "..."` when there is no `--experiment` (needs `strategyDefinitionId` + `strategyDefinitionDisplay` `{zh,en}`; pass `--definition-label-zh` / `--definition-label-en` or the CLI falls back to the definition id). Persisted runs use the account tier from `subscriptions.me.get`; if `--tier` is supplied, it must match. With `--no-persist`, `runs.create` is skipped and `--tier` may simulate `free|pro|pro_max` (default `pro`). `--data-quality` defaults to `basic` (soft gaps finish the run and appear as `coverageNotice`; `prefix_gap` is less severe than `internal_gap`). `--data-quality strict` still fails on any gap. `--replay-timeframe` defaults to `1m` (allowed `1m|3m|5m|15m|30m|1h|4h`); this is the replay/download bar and is merged with plan indicator timeframes so a 4h RSI grid still replays on 1m. `runs.create` is `write`, not `high-risk-write` — do not add `--yes`. Do not update or delete experiments through this command.
|
|
58
58
|
|
|
59
|
-
`--format jsonl` writes
|
|
59
|
+
`--format jsonl` writes compact progress milestones (`{event:"progress",stage,fraction}`; first update, each 10%, and completion per stage), then a final `{ok:true,data:{...}}` envelope. Use `--format json` when only the final envelope is needed.
|
|
60
60
|
|
|
61
61
|
## Local sweep
|
|
62
62
|
|
|
@@ -78,7 +78,7 @@ alphafox engine-backtest sweep \
|
|
|
78
78
|
|
|
79
79
|
`--mode` is `neighborhood|range`. `--search-mode` is `standard|fast`. `--concurrency` is 1–8; Free is always serial. After every local coordinate finishes, the command POSTs **one** `engine_backtest.experiments.byId.sweeps.create` summary (4 MiB / point-error caps). It never calls `runs.create` per coordinate and never writes Tape, curves, or full configs. `--no-persist` stays zero-write. A cancelled or incomplete search is not persisted. The same `clientSweepId` is reused if you rebuild the create body for retry; unknown write results (no Sweep id) fail instead of reporting `persisted: true`.
|
|
80
80
|
|
|
81
|
-
`--format jsonl` includes `planning`, `tape`, `sweep`, and `persist` stages. The final envelope includes counts, `elapsedMs`, best coordinate/config, `sweepId`, `persisted`, and an Experiment URL with `?tab=sweep`. After persist, include that dashboard URL in the reply (`https://www.alphafox.app/zh/dashboard/traders/backtest/{experimentId}?tab=sweep`).
|
|
81
|
+
`--format jsonl` includes compact 10% milestones for `planning`, `tape`, `sweep`, and `persist` stages. The final envelope includes counts, `elapsedMs`, best coordinate/config, `sweepId`, `persisted`, and an Experiment URL with `?tab=sweep`. After persist, include that dashboard URL in the reply (`https://www.alphafox.app/zh/dashboard/traders/backtest/{experimentId}?tab=sweep`).
|
|
82
82
|
|
|
83
83
|
Read / delete history through typed catalog commands. Delete is high-risk-write:
|
|
84
84
|
|
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.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Market
|
package/skills/strategy/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-strategy
|
|
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.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Strategy definitions
|
package/skills/trading/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-trading
|
|
3
3
|
description: Running strategies (traders) — create, list, start, and stop. A trader is a live or paper strategy instance (grid, dca, copy, …), not a person. Default Engine create uses autoStart true (创建即开始). Use autoStart false only when the user asks to create without starting. After create or start, include https://www.alphafox.app/zh/dashboard/traders/{traderId}.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.20
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Running strategies (traders)
|