@alphafox/cli 0.3.7 → 0.3.8
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/auth/refresh.d.ts +3 -0
- package/dist/auth/refresh.js +98 -12
- package/dist/commands/run.js +30 -2
- package/dist/skills-manifest.json +37 -37
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/skills/account/SKILL.md +1 -1
- package/skills/admin/SKILL.md +1 -1
- package/skills/alphafox/SKILL.md +2 -2
- package/skills/alphafox-shared/SKILL.md +3 -2
- package/skills/auth/SKILL.md +8 -5
- 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 +1 -1
- package/skills/trading/SKILL.md +1 -1
package/dist/auth/refresh.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import type { ProfileConfig } from "../config/profiles";
|
|
|
8
8
|
import { type StoredTokens } from "../keychain/store";
|
|
9
9
|
/** Refresh when access token expires within this window. */
|
|
10
10
|
export declare const ACCESS_TOKEN_REFRESH_SKEW_MS = 60000;
|
|
11
|
+
/** Drop a stale inter-process refresh lock after this long. */
|
|
12
|
+
export declare const REFRESH_LOCK_STALE_MS = 30000;
|
|
11
13
|
export type RefreshOutcome = {
|
|
12
14
|
readonly status: "refreshed";
|
|
13
15
|
readonly tokens: StoredTokens;
|
|
@@ -40,5 +42,6 @@ export declare function refreshStoredTokensOrNull(profile: ProfileConfig, env?:
|
|
|
40
42
|
readonly now?: number;
|
|
41
43
|
readonly force?: boolean;
|
|
42
44
|
}): Promise<StoredTokens | null>;
|
|
45
|
+
export declare function refreshLockFilePath(profile: string, env?: NodeJS.ProcessEnv): string;
|
|
43
46
|
/** Test helper: clear in-flight map between cases. */
|
|
44
47
|
export declare function clearRefreshInflightForTests(): void;
|
package/dist/auth/refresh.js
CHANGED
|
@@ -6,15 +6,21 @@
|
|
|
6
6
|
* Outcomes are explicit: callers must not treat a failed refresh as a healthy session.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.ACCESS_TOKEN_REFRESH_SKEW_MS = void 0;
|
|
9
|
+
exports.REFRESH_LOCK_STALE_MS = exports.ACCESS_TOKEN_REFRESH_SKEW_MS = void 0;
|
|
10
10
|
exports.accessTokenNeedsRefresh = accessTokenNeedsRefresh;
|
|
11
11
|
exports.refreshStoredTokens = refreshStoredTokens;
|
|
12
12
|
exports.refreshStoredTokensOrNull = refreshStoredTokensOrNull;
|
|
13
|
+
exports.refreshLockFilePath = refreshLockFilePath;
|
|
13
14
|
exports.clearRefreshInflightForTests = clearRefreshInflightForTests;
|
|
15
|
+
const node_fs_1 = require("node:fs");
|
|
16
|
+
const node_path_1 = require("node:path");
|
|
17
|
+
const node_os_1 = require("node:os");
|
|
14
18
|
const version_1 = require("../version");
|
|
15
19
|
const store_1 = require("../keychain/store");
|
|
16
20
|
/** Refresh when access token expires within this window. */
|
|
17
21
|
exports.ACCESS_TOKEN_REFRESH_SKEW_MS = 60_000;
|
|
22
|
+
/** Drop a stale inter-process refresh lock after this long. */
|
|
23
|
+
exports.REFRESH_LOCK_STALE_MS = 30_000;
|
|
18
24
|
/** In-flight refresh promises so concurrent API calls share one rotation. */
|
|
19
25
|
const inflightByProfile = new Map();
|
|
20
26
|
function accessTokenNeedsRefresh(tokens, now = Date.now()) {
|
|
@@ -36,20 +42,38 @@ async function refreshStoredTokens(profile, env = process.env, fetchImpl = fetch
|
|
|
36
42
|
tokens: null,
|
|
37
43
|
};
|
|
38
44
|
}
|
|
39
|
-
|
|
40
|
-
|
|
45
|
+
const now = options.now ?? Date.now();
|
|
46
|
+
if (!options.force && !accessTokenNeedsRefresh(existing, now)) {
|
|
41
47
|
return { status: "unchanged", tokens: existing };
|
|
42
48
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
return withRefreshLock(profile.name, env, async () => {
|
|
50
|
+
const latest = (0, store_1.loadTokens)(profile.name, env) ?? existing;
|
|
51
|
+
if (!latest?.refreshToken?.trim()) {
|
|
52
|
+
return {
|
|
53
|
+
status: "no_session",
|
|
54
|
+
reason: "no_refresh_token",
|
|
55
|
+
tokens: null,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const someoneElseRefreshed = latest.refreshToken !== existing.refreshToken ||
|
|
59
|
+
latest.expiresAt > existing.expiresAt;
|
|
60
|
+
if (someoneElseRefreshed && !accessTokenNeedsRefresh(latest, now)) {
|
|
61
|
+
return { status: "unchanged", tokens: latest };
|
|
62
|
+
}
|
|
63
|
+
if (!options.force && !accessTokenNeedsRefresh(latest, now)) {
|
|
64
|
+
return { status: "unchanged", tokens: latest };
|
|
65
|
+
}
|
|
66
|
+
const key = profile.name;
|
|
67
|
+
const pending = inflightByProfile.get(key);
|
|
68
|
+
if (pending) {
|
|
69
|
+
return pending;
|
|
70
|
+
}
|
|
71
|
+
const work = performRefresh(profile, latest, env, fetchImpl).finally(() => {
|
|
72
|
+
inflightByProfile.delete(key);
|
|
73
|
+
});
|
|
74
|
+
inflightByProfile.set(key, work);
|
|
75
|
+
return work;
|
|
50
76
|
});
|
|
51
|
-
inflightByProfile.set(key, work);
|
|
52
|
-
return work;
|
|
53
77
|
}
|
|
54
78
|
/**
|
|
55
79
|
* Convenience for callers that only need tokens on successful refresh/unchanged.
|
|
@@ -62,6 +86,68 @@ async function refreshStoredTokensOrNull(profile, env = process.env, fetchImpl =
|
|
|
62
86
|
}
|
|
63
87
|
return null;
|
|
64
88
|
}
|
|
89
|
+
function refreshLockFilePath(profile, env = process.env) {
|
|
90
|
+
const base = env.ALPHAFOX_KEYCHAIN_DIR?.trim() ||
|
|
91
|
+
(0, node_path_1.join)((0, node_os_1.homedir)(), ".config", "alphafox", "keychain");
|
|
92
|
+
return (0, node_path_1.join)(base, `${profile}.refresh.lock`);
|
|
93
|
+
}
|
|
94
|
+
async function withRefreshLock(profile, env, work) {
|
|
95
|
+
const path = refreshLockFilePath(profile, env);
|
|
96
|
+
(0, node_fs_1.mkdirSync)((0, node_path_1.dirname)(path), { recursive: true });
|
|
97
|
+
const started = Date.now();
|
|
98
|
+
while (true) {
|
|
99
|
+
try {
|
|
100
|
+
const fd = (0, node_fs_1.openSync)(path, node_fs_1.constants.O_CREAT | node_fs_1.constants.O_EXCL | node_fs_1.constants.O_WRONLY);
|
|
101
|
+
try {
|
|
102
|
+
(0, node_fs_1.writeFileSync)(fd, `${process.pid}\n${Date.now()}\n`);
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
(0, node_fs_1.closeSync)(fd);
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
return await work();
|
|
109
|
+
}
|
|
110
|
+
finally {
|
|
111
|
+
try {
|
|
112
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// another process stole a stale lock
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
const code = err.code;
|
|
121
|
+
if (code !== "EEXIST") {
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
if (Date.now() - (0, node_fs_1.statSync)(path).mtimeMs > exports.REFRESH_LOCK_STALE_MS) {
|
|
126
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
// lock disappeared; retry acquire
|
|
132
|
+
}
|
|
133
|
+
if (Date.now() - started > exports.REFRESH_LOCK_STALE_MS + 5_000) {
|
|
134
|
+
try {
|
|
135
|
+
(0, node_fs_1.unlinkSync)(path);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
// raced
|
|
139
|
+
}
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
await sleep(50);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function sleep(ms) {
|
|
147
|
+
return new Promise((resolve) => {
|
|
148
|
+
setTimeout(resolve, ms);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
65
151
|
async function performRefresh(profile, existing, env, fetchImpl) {
|
|
66
152
|
const origin = profile.apiBaseUrl.replace(/\/$/, "").replace(/\/api\/v1$/, "");
|
|
67
153
|
const url = `${origin}/api/auth/oauth/token`;
|
package/dist/commands/run.js
CHANGED
|
@@ -9,6 +9,7 @@ const allowlist_1 = require("../catalog/allowlist");
|
|
|
9
9
|
const profiles_1 = require("../config/profiles");
|
|
10
10
|
const envelope_1 = require("../envelope");
|
|
11
11
|
const browser_login_1 = require("../auth/browser-login");
|
|
12
|
+
const refresh_1 = require("../auth/refresh");
|
|
12
13
|
const client_1 = require("../http/client");
|
|
13
14
|
const store_1 = require("../keychain/store");
|
|
14
15
|
const confirmation_1 = require("../safety/confirmation");
|
|
@@ -351,15 +352,30 @@ async function cmdAuth(args, flags, env) {
|
|
|
351
352
|
});
|
|
352
353
|
if (sub === "status") {
|
|
353
354
|
const verify = args.includes("--verify");
|
|
354
|
-
|
|
355
|
+
let tokens = (0, store_1.loadTokens)(profile.name, env);
|
|
355
356
|
if (!tokens) {
|
|
356
357
|
(0, envelope_1.writeSuccess)({
|
|
357
358
|
authenticated: false,
|
|
359
|
+
session: "none",
|
|
358
360
|
profile: profile.name,
|
|
359
361
|
verified: false,
|
|
362
|
+
refresh: "no_session",
|
|
363
|
+
accessTokenExpired: null,
|
|
364
|
+
hasRefreshToken: false,
|
|
360
365
|
}, { format: flags.format, jq: flags.jq });
|
|
361
366
|
return 0;
|
|
362
367
|
}
|
|
368
|
+
let refresh = "skipped";
|
|
369
|
+
if ((0, refresh_1.accessTokenNeedsRefresh)(tokens)) {
|
|
370
|
+
const outcome = await (0, refresh_1.refreshStoredTokens)(profile, env);
|
|
371
|
+
refresh = outcome.status;
|
|
372
|
+
if (outcome.status === "refreshed" || outcome.status === "unchanged") {
|
|
373
|
+
tokens = outcome.tokens;
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
tokens = (0, store_1.loadTokens)(profile.name, env) ?? tokens;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
363
379
|
let verified = null;
|
|
364
380
|
let whoami = null;
|
|
365
381
|
if (verify) {
|
|
@@ -370,9 +386,18 @@ async function cmdAuth(args, flags, env) {
|
|
|
370
386
|
}, env);
|
|
371
387
|
verified = res.status >= 200 && res.status < 300;
|
|
372
388
|
whoami = verified ? res.json : { status: res.status, body: res.json };
|
|
389
|
+
tokens = (0, store_1.loadTokens)(profile.name, env) ?? tokens;
|
|
373
390
|
}
|
|
391
|
+
const accessTokenExpired = tokens.expiresAt <= Date.now();
|
|
392
|
+
const hasRefreshToken = Boolean(tokens.refreshToken?.trim());
|
|
393
|
+
const session = !accessTokenExpired
|
|
394
|
+
? "active"
|
|
395
|
+
: refresh === "failed"
|
|
396
|
+
? "refresh_failed"
|
|
397
|
+
: "expired";
|
|
374
398
|
(0, envelope_1.writeSuccess)({
|
|
375
|
-
authenticated:
|
|
399
|
+
authenticated: session === "active",
|
|
400
|
+
session,
|
|
376
401
|
profile: profile.name,
|
|
377
402
|
environment: tokens.environment,
|
|
378
403
|
issuer: tokens.issuer,
|
|
@@ -381,6 +406,9 @@ async function cmdAuth(args, flags, env) {
|
|
|
381
406
|
scopes: tokens.scopes,
|
|
382
407
|
accessTokenFingerprint: (0, store_1.tokenFingerprint)(tokens.accessToken),
|
|
383
408
|
expiresAt: tokens.expiresAt,
|
|
409
|
+
accessTokenExpired,
|
|
410
|
+
hasRefreshToken,
|
|
411
|
+
refresh,
|
|
384
412
|
verified,
|
|
385
413
|
whoami,
|
|
386
414
|
}, { format: flags.format, jq: flags.jq });
|
|
@@ -1,141 +1,141 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"packageName": "@alphafox/cli",
|
|
4
|
-
"packageVersion": "0.3.
|
|
4
|
+
"packageVersion": "0.3.8",
|
|
5
5
|
"contractVersion": "2026-08-13",
|
|
6
|
-
"bundleHash": "
|
|
6
|
+
"bundleHash": "cd05f4eb6f9e1a7c9188ac5770196698c6f2c9ff6aaebfbfbaba3581ef08d226",
|
|
7
7
|
"skills": [
|
|
8
8
|
{
|
|
9
9
|
"name": "alphafox",
|
|
10
|
-
"version": "0.3.
|
|
10
|
+
"version": "0.3.8",
|
|
11
11
|
"files": [
|
|
12
12
|
{
|
|
13
13
|
"path": "SKILL.md",
|
|
14
|
-
"sha256": "
|
|
14
|
+
"sha256": "e8eadf96f36f6aa124b36d15a912465e839389e5228dbf9dfd9ad2f1ec86f65a",
|
|
15
15
|
"size": 3553
|
|
16
16
|
}
|
|
17
17
|
],
|
|
18
|
-
"hash": "
|
|
18
|
+
"hash": "fb41a55fcd363231cb69e30e4c0fe7b1ad2e17b12e2bb90cfda7d6e9ccd2f02c"
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
"name": "alphafox-account",
|
|
22
|
-
"version": "0.3.
|
|
22
|
+
"version": "0.3.8",
|
|
23
23
|
"files": [
|
|
24
24
|
{
|
|
25
25
|
"path": "SKILL.md",
|
|
26
|
-
"sha256": "
|
|
26
|
+
"sha256": "9925573bf644b998ea683df7a20276a835d33cb83b0548ee0d1c43429ad99582",
|
|
27
27
|
"size": 783
|
|
28
28
|
}
|
|
29
29
|
],
|
|
30
|
-
"hash": "
|
|
30
|
+
"hash": "934bcd76d1bea875324673ffcc3d1c52e3f4065f776c4958ffc230cf911bac21"
|
|
31
31
|
},
|
|
32
32
|
{
|
|
33
33
|
"name": "alphafox-admin",
|
|
34
|
-
"version": "0.3.
|
|
34
|
+
"version": "0.3.8",
|
|
35
35
|
"files": [
|
|
36
36
|
{
|
|
37
37
|
"path": "SKILL.md",
|
|
38
|
-
"sha256": "
|
|
38
|
+
"sha256": "e9ae0b433cead54e9c284f0ea8859dd9e96123f842788938319404b96bc085e7",
|
|
39
39
|
"size": 787
|
|
40
40
|
}
|
|
41
41
|
],
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "1346e798f18582c16cfbb887667272406f170e775d3027131d3d88e1f1a656e3"
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
"name": "alphafox-auth",
|
|
46
|
-
"version": "0.3.
|
|
46
|
+
"version": "0.3.8",
|
|
47
47
|
"files": [
|
|
48
48
|
{
|
|
49
49
|
"path": "SKILL.md",
|
|
50
|
-
"sha256": "
|
|
51
|
-
"size":
|
|
50
|
+
"sha256": "8ec9f081d9a1d40606ac7c18cba5dae9f1b6144ddc0079005b16af54be8f2f46",
|
|
51
|
+
"size": 2370
|
|
52
52
|
}
|
|
53
53
|
],
|
|
54
|
-
"hash": "
|
|
54
|
+
"hash": "854910a6792aa6d0a8b9cd796afb41753a34cef79df95c5b50de432f03a4e67a"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
57
57
|
"name": "alphafox-engine-backtest",
|
|
58
|
-
"version": "0.3.
|
|
58
|
+
"version": "0.3.8",
|
|
59
59
|
"files": [
|
|
60
60
|
{
|
|
61
61
|
"path": "SKILL.md",
|
|
62
|
-
"sha256": "
|
|
62
|
+
"sha256": "e5f37b8541c510a27f84cbf9eea7524efe0b8f9c60c4faf17521b6cac298f92b",
|
|
63
63
|
"size": 7584
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
|
-
"hash": "
|
|
66
|
+
"hash": "efb614f145763f514c33d02e112657bd42868cc746f13dbcb3cceaa0ecb770e4"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"name": "alphafox-exchange",
|
|
70
|
-
"version": "0.3.
|
|
70
|
+
"version": "0.3.8",
|
|
71
71
|
"files": [
|
|
72
72
|
{
|
|
73
73
|
"path": "SKILL.md",
|
|
74
|
-
"sha256": "
|
|
74
|
+
"sha256": "118141754916741f4f8b449cf307a89cdfa11f234302726ba4d6b58e396327b5",
|
|
75
75
|
"size": 743
|
|
76
76
|
}
|
|
77
77
|
],
|
|
78
|
-
"hash": "
|
|
78
|
+
"hash": "3933f12a2d8c55db465d4a11cf1f7d40f90fff81b3931f398e2fe3bcaf064d62"
|
|
79
79
|
},
|
|
80
80
|
{
|
|
81
81
|
"name": "alphafox-market",
|
|
82
|
-
"version": "0.3.
|
|
82
|
+
"version": "0.3.8",
|
|
83
83
|
"files": [
|
|
84
84
|
{
|
|
85
85
|
"path": "SKILL.md",
|
|
86
|
-
"sha256": "
|
|
86
|
+
"sha256": "0e77dcc697fe60f742e1075986685db5018d9d659a4d8f44f9cc343117c1c74b",
|
|
87
87
|
"size": 3078
|
|
88
88
|
}
|
|
89
89
|
],
|
|
90
|
-
"hash": "
|
|
90
|
+
"hash": "710c45c6124583d3fa9c9584f67bbc665bad35c9e6d1294c7416f493b8a6b184"
|
|
91
91
|
},
|
|
92
92
|
{
|
|
93
93
|
"name": "alphafox-notification",
|
|
94
|
-
"version": "0.3.
|
|
94
|
+
"version": "0.3.8",
|
|
95
95
|
"files": [
|
|
96
96
|
{
|
|
97
97
|
"path": "SKILL.md",
|
|
98
|
-
"sha256": "
|
|
98
|
+
"sha256": "712aa6a4de8090bb7ee57373d35dd95c62bad7a24e443747afa4f11fb6e79b68",
|
|
99
99
|
"size": 698
|
|
100
100
|
}
|
|
101
101
|
],
|
|
102
|
-
"hash": "
|
|
102
|
+
"hash": "5f2feef0e17912a593bafae0961f983e3f781d12800e4808c136004897321ab2"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
105
105
|
"name": "alphafox-shared",
|
|
106
|
-
"version": "0.3.
|
|
106
|
+
"version": "0.3.8",
|
|
107
107
|
"files": [
|
|
108
108
|
{
|
|
109
109
|
"path": "SKILL.md",
|
|
110
|
-
"sha256": "
|
|
111
|
-
"size":
|
|
110
|
+
"sha256": "c6bab01f9c8369f9c2a29eebf7b46462887f14d3bec7ad00e2a159d395346508",
|
|
111
|
+
"size": 5385
|
|
112
112
|
}
|
|
113
113
|
],
|
|
114
|
-
"hash": "
|
|
114
|
+
"hash": "2b78fe080877af19b659964a8c965720e5ab731dd157ced10d2ee598b8c574a0"
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"name": "alphafox-strategy",
|
|
118
|
-
"version": "0.3.
|
|
118
|
+
"version": "0.3.8",
|
|
119
119
|
"files": [
|
|
120
120
|
{
|
|
121
121
|
"path": "SKILL.md",
|
|
122
|
-
"sha256": "
|
|
122
|
+
"sha256": "03f1d1c6d048d7b0a23d725c6585d1d019445579be9779dc93095ebafb3fcf5a",
|
|
123
123
|
"size": 1826
|
|
124
124
|
}
|
|
125
125
|
],
|
|
126
|
-
"hash": "
|
|
126
|
+
"hash": "ebf375c6eeaf13c971a3090d05beda7037f253325ee2236c35b26ad540922827"
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"name": "alphafox-trading",
|
|
130
|
-
"version": "0.3.
|
|
130
|
+
"version": "0.3.8",
|
|
131
131
|
"files": [
|
|
132
132
|
{
|
|
133
133
|
"path": "SKILL.md",
|
|
134
|
-
"sha256": "
|
|
134
|
+
"sha256": "4b597f23ff6c8ce384e8fd56fab73c6128d373741285bac6df0b061e7ee50242",
|
|
135
135
|
"size": 3122
|
|
136
136
|
}
|
|
137
137
|
],
|
|
138
|
-
"hash": "
|
|
138
|
+
"hash": "d7e818482ec3ba9aeab50af72e72f990288f0e2e6714e1227cba441db05fa75a"
|
|
139
139
|
}
|
|
140
140
|
]
|
|
141
141
|
}
|
package/dist/version.d.ts
CHANGED
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.8";
|
|
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; } });
|
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
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`. 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.8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox
|
|
@@ -36,7 +36,7 @@ If several rows apply, load **all** of them (typical: `alphafox-shared` + `alpha
|
|
|
36
36
|
The CLI may print this on **stderr** at most once every 24 hours:
|
|
37
37
|
|
|
38
38
|
```text
|
|
39
|
-
[alphafox] update available: 0.3.
|
|
39
|
+
[alphafox] update available: 0.3.7 -> 0.3.8. After the user confirms, run: alphafox update --format json --no-input,
|
|
40
40
|
```
|
|
41
41
|
|
|
42
42
|
If you see that notice (or `updateAvailable: true` from `alphafox update --check`):
|
|
@@ -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.8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# AlphaFox shared Agent contract
|
|
@@ -67,9 +67,10 @@ alphafox auth login --no-wait --format json --no-input
|
|
|
67
67
|
# show verification_uri / user_code to the human, then:
|
|
68
68
|
alphafox auth login --device-code <device_code> --format json --no-input
|
|
69
69
|
alphafox auth status --verify --format json --no-input
|
|
70
|
-
alphafox whoami --format json --no-input
|
|
71
70
|
```
|
|
72
71
|
|
|
72
|
+
Access tokens last ~10 minutes; the CLI refreshes them. After idle, run **one** `auth status --verify` — not `whoami` in parallel. `session: active` means logged in. A past `expiresAt` is not logout. Re-login only when `session` is `none` or `refresh_failed`.
|
|
73
|
+
|
|
73
74
|
Local browser: `alphafox auth login --browser --format json --no-input` (loopback 127.0.0.1). If the browser cannot open, copy `authorizeUrl` from the error; do not invent a Device Flow retry unless the operator is headless.
|
|
74
75
|
|
|
75
76
|
Wrong environment / missing permission / missing `--yes`: stop. Do not retry with a different profile.
|
package/skills/auth/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: alphafox-auth
|
|
3
3
|
description: Login, status, logout, whoami, and environment isolation for AlphaFox CLI.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Auth Skill
|
|
@@ -19,23 +19,26 @@ Always `--format json --no-input`. Never `--token`.
|
|
|
19
19
|
1. `alphafox auth login --no-wait --format json --no-input`
|
|
20
20
|
2. Present `verification_uri` / `user_code` to the human.
|
|
21
21
|
3. After approval: `alphafox auth login --device-code <device_code> --format json --no-input`
|
|
22
|
-
4. `alphafox
|
|
22
|
+
4. `alphafox auth status --verify --format json --no-input` (do not also run `whoami` in parallel)
|
|
23
23
|
|
|
24
24
|
### Browser loopback (human, local machine)
|
|
25
25
|
|
|
26
26
|
1. `alphafox auth login --browser --format json --no-input`
|
|
27
27
|
2. CLI binds `127.0.0.1` and opens the system browser. Do not copy codes or verifiers.
|
|
28
|
-
3. After the localhost callback, `alphafox
|
|
28
|
+
3. After the localhost callback, `alphafox auth status --verify --format json --no-input`
|
|
29
29
|
4. If the browser cannot open, the error includes a copyable `authorizeUrl`. Do not retry as Device Flow unless the human is headless.
|
|
30
30
|
|
|
31
31
|
### Status / logout
|
|
32
32
|
|
|
33
|
-
- `alphafox auth status --verify --format json --no-input`
|
|
33
|
+
- `alphafox auth status --verify --format json --no-input` is enough. Do **not** also run `whoami` in parallel — concurrent refresh can kill the session.
|
|
34
|
+
- Access tokens last ~10 minutes. The CLI refreshes them automatically. A past `expiresAt` is **not** logout.
|
|
35
|
+
- Logged in: `session` is `active` (or `authenticated: true` after status). Re-login only when `session` is `none` or `refresh_failed`.
|
|
34
36
|
- `alphafox auth logout --format json --no-input` (server revoke + local keychain clear). If `remoteRevoke` is `failed`, local tokens are still cleared but exit is non-zero — do not claim a full logout.
|
|
35
37
|
|
|
36
38
|
### Recovery
|
|
37
39
|
|
|
38
|
-
- `
|
|
40
|
+
- `session: refresh_failed` / refresh grant `invalid_grant`: re-run Device Flow or browser login. Do not reuse a token from another profile.
|
|
41
|
+
- Do not treat a short idle or an expired access token as a missing login.
|
|
39
42
|
- Cross-env: production tokens are rejected on staging/local. Switch `--profile` only with explicit operator intent.
|
|
40
43
|
|
|
41
44
|
## Safety
|
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.8
|
|
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 (grid, dca, copy, …) and validate config. Creating a running strategy is creating a trader; use alphafox-trading for that.
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.8
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Strategy definitions
|
package/skills/trading/SKILL.md
CHANGED