@alphafox/cli 0.3.21 → 0.3.23

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.
Files changed (36) hide show
  1. package/dist/auth/refresh.js +3 -4
  2. package/dist/commands/run.js +2 -2
  3. package/dist/engine-backtest/fetch-runtime.d.ts +4 -0
  4. package/dist/engine-backtest/fetch-runtime.js +103 -17
  5. package/dist/engine-backtest/parse-args.js +10 -2
  6. package/dist/engine-backtest/run-command.js +4 -1
  7. package/dist/engine-backtest/sweep-command.js +2 -2
  8. package/dist/engine-backtest/types.d.ts +5 -1
  9. package/dist/http/client.js +3 -3
  10. package/dist/skills-manifest.json +45 -45
  11. package/dist/version.d.ts +1 -1
  12. package/dist/version.js +1 -1
  13. package/docs/agents/domain.md +3 -49
  14. package/docs/agents/issue-tracker.md +5 -41
  15. package/docs/agents/triage-labels.md +2 -14
  16. package/package.json +1 -1
  17. package/skills/account/SKILL.md +1 -1
  18. package/skills/admin/SKILL.md +1 -1
  19. package/skills/alphafox/SKILL.md +6 -28
  20. package/skills/alphafox-shared/SKILL.md +6 -6
  21. package/skills/auth/SKILL.md +1 -1
  22. package/skills/cache/SKILL.md +3 -3
  23. package/skills/engine-backtest/SKILL.md +3 -3
  24. package/skills/exchange/SKILL.md +1 -1
  25. package/skills/market/SKILL.md +2 -2
  26. package/skills/notification/SKILL.md +1 -1
  27. package/skills/strategy/SKILL.md +6 -4
  28. package/skills/trading/SKILL.md +2 -2
  29. package/vendor/backtest-runner/README.md +2 -0
  30. package/vendor/backtest-runner/index.d.ts +8 -2
  31. package/vendor/backtest-runner/index.mjs +5 -2
  32. package/vendor/backtest-runner/lib/series.mjs +5 -171
  33. package/vendor/backtest-runner/lib/tape-loader-concurrency.mjs +72 -0
  34. package/vendor/backtest-runner/lib/tape-loader-range-plan.mjs +77 -0
  35. package/vendor/backtest-runner/lib/tape-loader-range.mjs +222 -0
  36. package/vendor/backtest-runner/lib/tape-loader.mjs +13 -41
@@ -257,10 +257,9 @@ async function fetchFollowingSameSiteRedirects(fetchImpl, startUrl, init, maxHop
257
257
  const nextUrl = new URL(location, url).toString();
258
258
  if (!sameAuthSite(originOf(url), originOf(nextUrl)))
259
259
  break;
260
- if (response.status === 303 ||
261
- ((response.status === 301 || response.status === 302) &&
262
- method !== "GET" &&
263
- method !== "HEAD")) {
260
+ // 303 is the only redirect that switches to GET. Apex→www is Cloudflare 301;
261
+ // converting POST to GET drops the OAuth body and the AS returns 405.
262
+ if (response.status === 303) {
264
263
  method = "GET";
265
264
  body = undefined;
266
265
  }
@@ -101,8 +101,8 @@ async function runCli(argv, env = process.env) {
101
101
  "alphafox schema [operationId]",
102
102
  "alphafox catalog",
103
103
  "alphafox api METHOD PATH [--body JSON|--config @file]",
104
- "alphafox engine-backtest run --experiment <uuid> --definition <id> --config @file --exchange <id> --range FROM..TO --initial-equity N",
105
- "alphafox engine-backtest sweep --experiment <uuid> --definition <id> --config @file --axes @file --exchange <id> --range FROM..TO --initial-equity N --no-persist",
104
+ "alphafox engine-backtest run --experiment <uuid> --definition <id> --config @file --exchange <id> --range FROM..TO --initial-equity N [--verbose]",
105
+ "alphafox engine-backtest sweep --experiment <uuid> --definition <id> --config @file --axes @file --exchange <id> --range FROM..TO --initial-equity N --no-persist [--verbose]",
106
106
  "alphafox cache status|clean [--tape|--runtime|--all]",
107
107
  "alphafox resolve-symbols <query...> [--exchange binance] [--asset-class equity_perp]",
108
108
  "alphafox <domain> <resource> <action> [flags]",
@@ -8,6 +8,8 @@ export declare const BLOB_RUNTIME_FILES: {
8
8
  readonly node: "node.mjs";
9
9
  readonly nodeWorker: "worker-node.mjs";
10
10
  readonly nodeWorkerPath: "worker-node-path.mjs";
11
+ readonly passivbotKernel: "passivbot_kernel.wasm";
12
+ readonly passivbotKernelModule: "passivbot-kernel.mjs";
11
13
  };
12
14
  export type BlobRuntimeFileKey = keyof typeof BLOB_RUNTIME_FILES;
13
15
  export interface EngineBacktestBlobManifest {
@@ -23,6 +25,8 @@ export interface EngineBacktestBlobManifest {
23
25
  readonly node: string;
24
26
  readonly nodeWorker: string;
25
27
  readonly nodeWorkerPath: string;
28
+ readonly passivbotKernel: string;
29
+ readonly passivbotKernelModule: string;
26
30
  }
27
31
  export interface FetchRuntimeHooks {
28
32
  readonly fetch?: typeof fetch;
@@ -5,12 +5,13 @@ exports.resolveBacktestWasmManifestUrl = resolveBacktestWasmManifestUrl;
5
5
  exports.resolveRuntimeCacheDir = resolveRuntimeCacheDir;
6
6
  exports.parseEngineBacktestBlobManifest = parseEngineBacktestBlobManifest;
7
7
  exports.ensureBlobRuntime = ensureBlobRuntime;
8
+ const node_crypto_1 = require("node:crypto");
8
9
  const node_fs_1 = require("node:fs");
9
10
  const promises_1 = require("node:fs/promises");
10
11
  const node_os_1 = require("node:os");
11
12
  const node_path_1 = require("node:path");
12
- const promises_2 = require("node:stream/promises");
13
13
  const node_stream_1 = require("node:stream");
14
+ const promises_2 = require("node:stream/promises");
14
15
  const errors_1 = require("./errors");
15
16
  exports.BACKTEST_RUNTIME_PROTOCOL = 1;
16
17
  exports.DEFAULT_BACKTEST_WASM_MANIFEST_URL = "https://zwggllrrna54e2d6.public.blob.vercel-storage.com/engine-backtest/latest.json";
@@ -22,7 +23,20 @@ exports.BLOB_RUNTIME_FILES = {
22
23
  node: "node.mjs",
23
24
  nodeWorker: "worker-node.mjs",
24
25
  nodeWorkerPath: "worker-node-path.mjs",
26
+ passivbotKernel: "passivbot_kernel.wasm",
27
+ passivbotKernelModule: "passivbot-kernel.mjs",
25
28
  };
29
+ const HASHED_BLOB_RUNTIME_FILES = [
30
+ exports.BLOB_RUNTIME_FILES.wasm,
31
+ exports.BLOB_RUNTIME_FILES.passivbotKernel,
32
+ exports.BLOB_RUNTIME_FILES.wasmExec,
33
+ exports.BLOB_RUNTIME_FILES.worker,
34
+ exports.BLOB_RUNTIME_FILES.passivbotKernelModule,
35
+ exports.BLOB_RUNTIME_FILES.client,
36
+ exports.BLOB_RUNTIME_FILES.node,
37
+ exports.BLOB_RUNTIME_FILES.nodeWorker,
38
+ exports.BLOB_RUNTIME_FILES.nodeWorkerPath,
39
+ ];
26
40
  function resolveBacktestWasmManifestUrl(env = process.env) {
27
41
  return (env.ALPHAFOX_BACKTEST_WASM_MANIFEST_URL?.trim() ||
28
42
  exports.DEFAULT_BACKTEST_WASM_MANIFEST_URL);
@@ -51,9 +65,19 @@ function parseEngineBacktestBlobManifest(value) {
51
65
  message: `Backtest runtime protocol is incompatible (got ${String(record.protocol)}, expected ${exports.BACKTEST_RUNTIME_PROTOCOL}).`,
52
66
  });
53
67
  }
68
+ const hash = readRequiredString(record.hash, "hash");
69
+ if (!/^[0-9a-f]{16}$/.test(hash)) {
70
+ throw new errors_1.EngineBacktestError({
71
+ type: "runtime",
72
+ subtype: "runtime_manifest_invalid",
73
+ message: "Backtest runtime manifest hash must be 16 lowercase hex characters.",
74
+ });
75
+ }
76
+ const passivbotKernel = readRequiredHttps(record.passivbotKernel, "passivbotKernel");
77
+ const passivbotKernelModule = readRequiredHttps(record.passivbotKernelModule, "passivbotKernelModule");
54
78
  return {
55
79
  version: readRequiredString(record.version, "version"),
56
- hash: readRequiredString(record.hash, "hash"),
80
+ hash,
57
81
  protocol: exports.BACKTEST_RUNTIME_PROTOCOL,
58
82
  engineSha: readOptionalString(record.engineSha),
59
83
  packageVersion: readOptionalString(record.packageVersion),
@@ -64,6 +88,8 @@ function parseEngineBacktestBlobManifest(value) {
64
88
  node: readRequiredHttps(record.node, "node"),
65
89
  nodeWorker: readRequiredHttps(record.nodeWorker, "nodeWorker"),
66
90
  nodeWorkerPath: readRequiredHttps(record.nodeWorkerPath, "nodeWorkerPath"),
91
+ passivbotKernel,
92
+ passivbotKernelModule,
67
93
  };
68
94
  }
69
95
  async function ensureBlobRuntime(env = process.env, hooks) {
@@ -93,20 +119,66 @@ async function ensureBlobRuntime(env = process.env, hooks) {
93
119
  }
94
120
  const manifest = parseEngineBacktestBlobManifest(await response.json());
95
121
  const directory = hooks?.cacheDir ?? resolveRuntimeCacheDir(manifest.hash, env);
96
- await (0, promises_1.mkdir)(directory, { recursive: true });
97
- for (const key of Object.keys(exports.BLOB_RUNTIME_FILES)) {
98
- const fileName = exports.BLOB_RUNTIME_FILES[key];
99
- const target = (0, node_path_1.join)(directory, fileName);
100
- if (await fileExists(target)) {
101
- continue;
122
+ if (await runtimeMatchesHash(directory, manifest.hash)) {
123
+ return {
124
+ manifest,
125
+ directory,
126
+ nodeEntry: (0, node_path_1.join)(directory, exports.BLOB_RUNTIME_FILES.node),
127
+ };
128
+ }
129
+ await (0, promises_1.mkdir)((0, node_path_1.dirname)(directory), { recursive: true });
130
+ let actualHash = "";
131
+ for (let attempt = 0; attempt < 2; attempt += 1) {
132
+ const staging = `${directory}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`;
133
+ await (0, promises_1.mkdir)(staging, { recursive: true });
134
+ try {
135
+ for (const key of Object.keys(exports.BLOB_RUNTIME_FILES)) {
136
+ await downloadFile(fetchImpl, manifest[key], (0, node_path_1.join)(staging, exports.BLOB_RUNTIME_FILES[key]));
137
+ }
138
+ if (!(await allRuntimeFilesExist(staging))) {
139
+ continue;
140
+ }
141
+ actualHash = await hashBlobRuntime(staging);
142
+ if (actualHash !== manifest.hash) {
143
+ continue;
144
+ }
145
+ await (0, promises_1.mkdir)(directory, { recursive: true });
146
+ for (const fileName of Object.values(exports.BLOB_RUNTIME_FILES)) {
147
+ await (0, promises_1.rename)((0, node_path_1.join)(staging, fileName), (0, node_path_1.join)(directory, fileName));
148
+ }
149
+ if (await runtimeMatchesHash(directory, manifest.hash)) {
150
+ return {
151
+ manifest,
152
+ directory,
153
+ nodeEntry: (0, node_path_1.join)(directory, exports.BLOB_RUNTIME_FILES.node),
154
+ };
155
+ }
156
+ }
157
+ finally {
158
+ await (0, promises_1.rm)(staging, { force: true, recursive: true });
102
159
  }
103
- await downloadFile(fetchImpl, manifest[key], target);
104
160
  }
105
- return {
106
- manifest,
107
- directory,
108
- nodeEntry: (0, node_path_1.join)(directory, exports.BLOB_RUNTIME_FILES.node),
109
- };
161
+ throw new errors_1.EngineBacktestError({
162
+ type: "runtime",
163
+ subtype: "runtime_integrity_failed",
164
+ message: `Backtest runtime hash mismatch: expected ${manifest.hash}, received ${actualHash}.`,
165
+ hint: "Retry the download; no unverified runtime was cached.",
166
+ details: { expectedHash: manifest.hash, actualHash, directory },
167
+ });
168
+ }
169
+ async function runtimeMatchesHash(directory, expectedHash) {
170
+ if (!(await allRuntimeFilesExist(directory))) {
171
+ return false;
172
+ }
173
+ try {
174
+ return (await hashBlobRuntime(directory)) === expectedHash;
175
+ }
176
+ catch {
177
+ return false;
178
+ }
179
+ }
180
+ async function allRuntimeFilesExist(directory) {
181
+ return (await Promise.all(Object.values(exports.BLOB_RUNTIME_FILES).map((fileName) => fileExists((0, node_path_1.join)(directory, fileName))))).every(Boolean);
110
182
  }
111
183
  async function downloadFile(fetchImpl, url, target) {
112
184
  let response;
@@ -127,9 +199,23 @@ async function downloadFile(fetchImpl, url, target) {
127
199
  message: `Backtest runtime file unavailable (${url} HTTP ${response.status}).`,
128
200
  });
129
201
  }
130
- const tmp = `${target}.tmp`;
131
- await (0, promises_2.pipeline)(node_stream_1.Readable.fromWeb(response.body), (0, node_fs_1.createWriteStream)(tmp));
132
- await (0, promises_1.rename)(tmp, target);
202
+ const tmp = `${target}.${process.pid}.${(0, node_crypto_1.randomUUID)()}.tmp`;
203
+ try {
204
+ await (0, promises_2.pipeline)(node_stream_1.Readable.fromWeb(response.body), (0, node_fs_1.createWriteStream)(tmp));
205
+ await (0, promises_1.rename)(tmp, target);
206
+ }
207
+ finally {
208
+ await (0, promises_1.rm)(tmp, { force: true });
209
+ }
210
+ }
211
+ async function hashBlobRuntime(directory) {
212
+ const digest = (0, node_crypto_1.createHash)("sha256");
213
+ for (const fileName of HASHED_BLOB_RUNTIME_FILES) {
214
+ for await (const chunk of (0, node_fs_1.createReadStream)((0, node_path_1.join)(directory, fileName))) {
215
+ digest.update(chunk);
216
+ }
217
+ }
218
+ return digest.digest("hex").slice(0, 16);
133
219
  }
134
220
  async function fileExists(path) {
135
221
  try {
@@ -16,11 +16,11 @@ const TIERS = new Set(["free", "pro", "pro_max"]);
16
16
  const DATA_QUALITY = new Set(["strict", "basic"]);
17
17
  const PRICE_PATHS = new Set(["ohlc_path_4", "close_only"]);
18
18
  exports.ENGINE_BACKTEST_RUN_USAGE = [
19
- "alphafox engine-backtest run --experiment <uuid> --definition <id> --config @file.json --exchange <id> --range YYYY-MM-DD..YYYY-MM-DD --initial-equity N [--replay-timeframe 1m]",
19
+ "alphafox engine-backtest run --experiment <uuid> --definition <id> --config @file.json --exchange <id> --range YYYY-MM-DD..YYYY-MM-DD --initial-equity N [--replay-timeframe 1m] [--verbose]",
20
20
  "alphafox engine-backtest run --create-experiment --name <name> --definition <id> --config @file.json --exchange <id> --from YYYY-MM-DD --to YYYY-MM-DD --initial-equity N",
21
21
  ];
22
22
  exports.ENGINE_BACKTEST_SWEEP_USAGE = [
23
- "alphafox engine-backtest sweep --experiment <uuid> --definition <id> --config @file.json --axes @axes.json --exchange <id> --range YYYY-MM-DD..YYYY-MM-DD --initial-equity N [--no-persist] [--mode neighborhood|range] [--search-mode standard|fast] [--concurrency N]",
23
+ "alphafox engine-backtest sweep --experiment <uuid> --definition <id> --config @file.json --axes @axes.json --exchange <id> --range YYYY-MM-DD..YYYY-MM-DD --initial-equity N [--no-persist] [--mode neighborhood|range] [--search-mode standard|fast] [--concurrency N] [--verbose]",
24
24
  ];
25
25
  const SWEEP_MODES = new Set(["neighborhood", "range"]);
26
26
  const SEARCH_MODES = new Set(["standard", "fast"]);
@@ -112,6 +112,7 @@ function parseEngineBacktestRunArgs(args) {
112
112
  let configSchemaVersion;
113
113
  let executionModelOverride;
114
114
  let persist = true;
115
+ let verbose = false;
115
116
  let help = false;
116
117
  let replayTimeframe = replay_timeframe_1.ENGINE_BACKTEST_DEFAULT_REPLAY_TIMEFRAME;
117
118
  for (let i = 0; i < args.length; i += 1) {
@@ -128,6 +129,10 @@ function parseEngineBacktestRunArgs(args) {
128
129
  persist = false;
129
130
  continue;
130
131
  }
132
+ if (a === "--verbose") {
133
+ verbose = true;
134
+ continue;
135
+ }
131
136
  if (!a.startsWith("--")) {
132
137
  usage(`Unexpected argument: ${a}`, "unexpected_arg");
133
138
  }
@@ -227,6 +232,7 @@ function parseEngineBacktestRunArgs(args) {
227
232
  tier,
228
233
  dataQualityMode,
229
234
  persist,
235
+ verbose,
230
236
  replayTimeframe,
231
237
  };
232
238
  }
@@ -284,6 +290,7 @@ function parseEngineBacktestRunArgs(args) {
284
290
  configSchemaVersion,
285
291
  executionModelOverride,
286
292
  persist,
293
+ verbose,
287
294
  replayTimeframe,
288
295
  };
289
296
  }
@@ -346,6 +353,7 @@ function parseEngineBacktestSweepArgs(args) {
346
353
  createExperiment: false,
347
354
  dataQualityMode: types_1.DEFAULT_DATA_QUALITY_MODE,
348
355
  persist: true,
356
+ verbose: false,
349
357
  replayTimeframe: replay_timeframe_1.ENGINE_BACKTEST_DEFAULT_REPLAY_TIMEFRAME,
350
358
  axesRaw,
351
359
  mode,
@@ -222,7 +222,9 @@ async function executeEngineBacktestRun(args, flags, env = process.env, deps = {
222
222
  wasm = wasmLoaded.module;
223
223
  runner = runnerLoaded.module;
224
224
  }
225
- const client = wasm.createNodeBacktestClient();
225
+ const client = wasm.createNodeBacktestClient({
226
+ verbose: args.verbose,
227
+ });
226
228
  try {
227
229
  if (typeof client.init === "function") {
228
230
  await client.init();
@@ -449,6 +451,7 @@ function engineBacktestHelpData() {
449
451
  "runs.create is write (not high-risk-write); --yes is not required",
450
452
  "Do not pass --token; use alphafox auth login",
451
453
  "--replay-timeframe defaults to 1m (min 1m). Indicator series still download their native plan timeframes.",
454
+ "Raw Engine worker logs, including per-trade output, are hidden by default. Use --verbose to forward them.",
452
455
  "--data-quality defaults to basic: hard tape failures still stop, soft gaps finish the run and appear as coverageNotice (prefix_gap less severe, internal_gap more severe). Use --data-quality strict to fail on any gap.",
453
456
  ],
454
457
  };
@@ -85,7 +85,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
85
85
  const { wasm, runner } = await loadRuntime(deps, env);
86
86
  const clients = [];
87
87
  try {
88
- const client = wasm.createNodeBacktestClient();
88
+ const client = wasm.createNodeBacktestClient({ verbose: args.verbose });
89
89
  clients.push(client);
90
90
  if (typeof client.init === "function") {
91
91
  await client.init();
@@ -221,7 +221,7 @@ async function executeEngineBacktestSweep(args, flags, env = process.env, deps =
221
221
  }
222
222
  emitProgress("tape", 1);
223
223
  while (clients.length < concurrency) {
224
- const extra = wasm.createNodeBacktestClient();
224
+ const extra = wasm.createNodeBacktestClient({ verbose: args.verbose });
225
225
  clients.push(extra);
226
226
  if (typeof extra.init === "function") {
227
227
  await extra.init();
@@ -50,6 +50,8 @@ export interface EngineBacktestRunArgs {
50
50
  readonly configSchemaVersion?: number;
51
51
  readonly executionModelOverride?: Partial<ExecutionModel>;
52
52
  readonly persist: boolean;
53
+ /** Forward raw Engine WASM worker stdout/stderr. Disabled by default. */
54
+ readonly verbose: boolean;
53
55
  /** Replay/download bar. Defaults to 1m; never finer. */
54
56
  readonly replayTimeframe: string;
55
57
  }
@@ -256,7 +258,9 @@ export interface BacktestClientLike {
256
258
  terminate(): void;
257
259
  }
258
260
  export interface BacktestWasmModule {
259
- createNodeBacktestClient(options?: unknown): BacktestClientLike;
261
+ createNodeBacktestClient(options?: {
262
+ readonly verbose?: boolean;
263
+ }): BacktestClientLike;
260
264
  }
261
265
  export interface BacktestRunnerModule {
262
266
  loadTape(request: {
@@ -146,9 +146,9 @@ async function fetchFollowingAuthRedirects(fetchImpl, startUrl, init, maxHops =
146
146
  if (!sameAuthSite(originOf(url), originOf(nextUrl))) {
147
147
  break;
148
148
  }
149
- // 303 switches to GET without body; 301/302 historically do for non-GET.
150
- if (response.status === 303 ||
151
- ((response.status === 301 || response.status === 302) && method !== "GET" && method !== "HEAD")) {
149
+ // 303 is the only redirect that switches to GET. Apex→www is Cloudflare 301;
150
+ // converting POST to GET drops the OAuth body and the AS returns 405.
151
+ if (response.status === 303) {
152
152
  method = "GET";
153
153
  body = undefined;
154
154
  }
@@ -1,153 +1,153 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
3
  "packageName": "@alphafox/cli",
4
- "packageVersion": "0.3.21",
4
+ "packageVersion": "0.3.23",
5
5
  "contractVersion": "2026-08-31",
6
- "bundleHash": "3b1e1c9968daa5b78e782cdb9a3e824b9fd69dfe20c90fd81fe457dd5b051f53",
6
+ "bundleHash": "cefb5f2b4c977a754941282a46780e64143978f21d4ad1db4da9fed993455094",
7
7
  "skills": [
8
8
  {
9
9
  "name": "alphafox",
10
- "version": "0.3.21",
10
+ "version": "0.3.23",
11
11
  "files": [
12
12
  {
13
13
  "path": "SKILL.md",
14
- "sha256": "2152cddf61791a680d9a12e561afa858f70ae862fe938ffdda8c9224f186664e",
15
- "size": 7950
14
+ "sha256": "ad970465cc7a8b6db68253cd6c6b375e824c32c197bd10cdd4735052a9dc54e6",
15
+ "size": 6711
16
16
  }
17
17
  ],
18
- "hash": "1cebc25d526364cf90f859407485d7431fb04921e7b7f2102c3f2cc1c52ae1f6"
18
+ "hash": "57b1b2996a4cb8e22ee36ccacae56ff36bcd64ac7203e528ccbca4b898f39a07"
19
19
  },
20
20
  {
21
21
  "name": "alphafox-account",
22
- "version": "0.3.21",
22
+ "version": "0.3.23",
23
23
  "files": [
24
24
  {
25
25
  "path": "SKILL.md",
26
- "sha256": "9897b6cdc67bc3b439d0ee8d20a73b1b195f434282f443cdd4b386da64926148",
26
+ "sha256": "23a35e3a3d6ac9e7da639b9383750f66e9de4dbbe049861da78f7912e9076512",
27
27
  "size": 784
28
28
  }
29
29
  ],
30
- "hash": "c11aaaa4a6fff64003f2ed6f842eb2879da9de82d90bb86e7b95224b958621f0"
30
+ "hash": "9b604ef9fc3c097333cf55b5e5fadb4c0179ad15c0dc05b3f76805abb4179be3"
31
31
  },
32
32
  {
33
33
  "name": "alphafox-admin",
34
- "version": "0.3.21",
34
+ "version": "0.3.23",
35
35
  "files": [
36
36
  {
37
37
  "path": "SKILL.md",
38
- "sha256": "bc94cab7004cb17c8b87c4af22d3dfe95bf51c4bdde3bd84cdaebbc056584322",
38
+ "sha256": "d53090a8e0ac05b5d8d753d52086389ed0ee0f9d405c3adfb120d06d3a17841e",
39
39
  "size": 2078
40
40
  }
41
41
  ],
42
- "hash": "073a7e1cc246b0c77a376e279ba09d7e049639c8e63074415fcfe26198ee1903"
42
+ "hash": "f8c047c2c4f1a49c13d5fe92c1676108fe31bcfdb3eebfb49fbe7719586944bb"
43
43
  },
44
44
  {
45
45
  "name": "alphafox-auth",
46
- "version": "0.3.21",
46
+ "version": "0.3.23",
47
47
  "files": [
48
48
  {
49
49
  "path": "SKILL.md",
50
- "sha256": "c576ef7a5ac20933def1bc334e3347b0951ad0692ff4b4ea92fe89a4052b5ee4",
50
+ "sha256": "a563b8c330fcee564b9dae3ab177b36e6612a5e6e28c0dcc2770ebe699f45181",
51
51
  "size": 2371
52
52
  }
53
53
  ],
54
- "hash": "41c831e8be2311f3abf393a9a502b2bbe6f79a383dfa9ee125a6b6f70e38e2f4"
54
+ "hash": "f6e8ac98bca895fb0e5afb0f7f915645267404aa77cc85724475287866619d68"
55
55
  },
56
56
  {
57
57
  "name": "alphafox-cache",
58
- "version": "0.3.21",
58
+ "version": "0.3.23",
59
59
  "files": [
60
60
  {
61
61
  "path": "SKILL.md",
62
- "sha256": "7b068ca3e06f221ea9306d441c56468852dfbb965e07f1675f1c423587520ca8",
63
- "size": 1530
62
+ "sha256": "9858b145e37f91082af9f9ed07d7f89c63f51365de3e1d04925b4bf476fe11c9",
63
+ "size": 1762
64
64
  }
65
65
  ],
66
- "hash": "8d97f1d8c423dbdabdf6aaf66e2d129d76319b0d4b803690cfe454239e237088"
66
+ "hash": "dd38538eb6a66500361406acba11818ef333c50c119735f8dc4e846d20aaee51"
67
67
  },
68
68
  {
69
69
  "name": "alphafox-engine-backtest",
70
- "version": "0.3.21",
70
+ "version": "0.3.23",
71
71
  "files": [
72
72
  {
73
73
  "path": "SKILL.md",
74
- "sha256": "a957f0785e76a077b6d1f9f1fa80d43e4a1474ea65d7b2960677c42cdb6f66e2",
75
- "size": 9792
74
+ "sha256": "feded42f5db1201ea13dca0fdcff0eb8a210024440b9e253f6b2b213065f45bb",
75
+ "size": 9862
76
76
  }
77
77
  ],
78
- "hash": "a046f3ef1386b5649d4a019458a790adc978c5e9a69b03a58e64a262bf545f1b"
78
+ "hash": "9071605d37c982f7741fe533671fb10d97d17d0265db0712d8b784f4562334ad"
79
79
  },
80
80
  {
81
81
  "name": "alphafox-exchange",
82
- "version": "0.3.21",
82
+ "version": "0.3.23",
83
83
  "files": [
84
84
  {
85
85
  "path": "SKILL.md",
86
- "sha256": "9d11b9c68da4d6948c00b1f2449e170a3ef387f07ccce36db1037d0871b0842a",
86
+ "sha256": "ed25e4487435552e7d2fb647a7c4ab0dcd96c11e65f6fd0076e841095497a412",
87
87
  "size": 744
88
88
  }
89
89
  ],
90
- "hash": "53b02a31ef1891bbcbb513dae2af48e8978003f3c41585ebab62d940bd8bad07"
90
+ "hash": "9dcbabf7b94c11901b35f3cf9f2f980a718ce675534df44e406ef0fb4ace9082"
91
91
  },
92
92
  {
93
93
  "name": "alphafox-market",
94
- "version": "0.3.21",
94
+ "version": "0.3.23",
95
95
  "files": [
96
96
  {
97
97
  "path": "SKILL.md",
98
- "sha256": "3131b98faddf4a85c87a2a4b0b7fb9c0b6c97159bf38dfc61a1c2a2367fc0020",
99
- "size": 3079
98
+ "sha256": "3e5835e3d4d658b43265ecb2d062bf2440e8f76f112104b0e66d4ee4a4362738",
99
+ "size": 3208
100
100
  }
101
101
  ],
102
- "hash": "df030475f2d0c4b53312bc1be8f1c3555062076074c0c207e3d8cd7a223d4f05"
102
+ "hash": "ff13c2cf880c6a7e0a8c20da2fffcdfc32f05737e1d860c3d76c3b1883a70d9d"
103
103
  },
104
104
  {
105
105
  "name": "alphafox-notification",
106
- "version": "0.3.21",
106
+ "version": "0.3.23",
107
107
  "files": [
108
108
  {
109
109
  "path": "SKILL.md",
110
- "sha256": "163a697d7c107152dc0a20dcabd06f1d9eb5b9395289e940b228cf599e7e901e",
110
+ "sha256": "684c29d65ef408836fe6841d272ac9c3cbf725ee9763deb886fad2e1076c07a2",
111
111
  "size": 699
112
112
  }
113
113
  ],
114
- "hash": "eab1329002b3e97d8a71800de23595a1df35cd0db3e7751382820df5244c9865"
114
+ "hash": "318099f64c6952496f21a7046723e4c5c9edfedb2f2687930cb5b80678ae22db"
115
115
  },
116
116
  {
117
117
  "name": "alphafox-shared",
118
- "version": "0.3.21",
118
+ "version": "0.3.23",
119
119
  "files": [
120
120
  {
121
121
  "path": "SKILL.md",
122
- "sha256": "95c311b9b091d5c6c21928c499568bba7d78bbf48ffc78204f54560c828213b8",
123
- "size": 6920
122
+ "sha256": "247c5f488e14c2ad1996d9a7167c69c593da31cb340f09bb1e52a572031db550",
123
+ "size": 7819
124
124
  }
125
125
  ],
126
- "hash": "5b84d0c16f8d1e0b2b5caefa6a5683650450249615fe186d48e987d42eebd264"
126
+ "hash": "5834e09bc8fdd24240c35233f8b5035b362a9d289a7f0f7698aac7480d1ef429"
127
127
  },
128
128
  {
129
129
  "name": "alphafox-strategy",
130
- "version": "0.3.21",
130
+ "version": "0.3.23",
131
131
  "files": [
132
132
  {
133
133
  "path": "SKILL.md",
134
- "sha256": "b61a5d3b32c0caaa29280676d0a38c32d895b13991056b8adbde584baeb751d2",
135
- "size": 7185
134
+ "sha256": "cf1e0c364de027cdf63113848ae9eb2194e1efc8025c3224da3fd86cf6990adc",
135
+ "size": 8039
136
136
  }
137
137
  ],
138
- "hash": "fa63c05d477ffb58e32c8c8e301189135d78e1a80bcb57cd7997a8533869f5f7"
138
+ "hash": "a17d382e02007479b66f2b879d38c7eaaa802738dc679e2e96bf42ed7d9eeb4b"
139
139
  },
140
140
  {
141
141
  "name": "alphafox-trading",
142
- "version": "0.3.21",
142
+ "version": "0.3.23",
143
143
  "files": [
144
144
  {
145
145
  "path": "SKILL.md",
146
- "sha256": "2142e880981ec69bcc4e2605e1f7fd950b0b058ea70d47e7f67b5147c0e6313b",
147
- "size": 4921
146
+ "sha256": "70b4ad0b01e29102024141337f28bda4fb6cdf38292cd5001411908830a8a747",
147
+ "size": 4920
148
148
  }
149
149
  ],
150
- "hash": "cd4386cd59f54ca31eac44cc6fa17eb9b74d0be925f06087d083d9d2370481bd"
150
+ "hash": "b12154ddcc48a9b0248548f935bcae940b9d514b5c233f7c5e5590ef449ac329"
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.21";
3
+ export declare const CLI_VERSION = "0.3.23";
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.21";
6
+ exports.CLI_VERSION = "0.3.23";
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,51 +1,5 @@
1
- # Domain Docs
1
+ # Domain references
2
2
 
3
- How the engineering skills should consume this repo's domain documentation when exploring the codebase.
3
+ For a task that changes domain terminology, behavior across contexts, or architecture, locate the relevant entry in root `CONTEXT-MAP.md` (if present), otherwise `CONTEXT.md`, and read only the relevant glossary sections and ADRs. Ordinary documentation, formatting and isolated mechanical edits do not require a domain-document tour.
4
4
 
5
- ## Before exploring, read these
6
-
7
- - **`CONTEXT.md`** at the repo root, or
8
- - **`CONTEXT-MAP.md`** at the repo root if it exists — it points at one `CONTEXT.md` per context. Read each one relevant to the topic.
9
- - **`docs/adr/`** — read ADRs that touch the area you're about to work in. In multi-context repos, also check `src/<context>/docs/adr/` for context-scoped decisions.
10
-
11
- If any of these files don't exist, **proceed silently**. Don't flag their absence; don't suggest creating them upfront. The `/domain-modeling` skill (reached via `/grill-with-docs` and `/improve-codebase-architecture`) creates them lazily when terms or decisions actually get resolved.
12
-
13
- ## File structure
14
-
15
- Single-context repo (most repos):
16
-
17
- ```
18
- /
19
- ├── CONTEXT.md
20
- ├── docs/adr/
21
- │ ├── 0001-event-sourced-orders.md
22
- │ └── 0002-postgres-for-write-model.md
23
- └── src/
24
- ```
25
-
26
- Multi-context repo (presence of `CONTEXT-MAP.md` at the root):
27
-
28
- ```
29
- /
30
- ├── CONTEXT-MAP.md
31
- ├── docs/adr/ ← system-wide decisions
32
- └── src/
33
- ├── ordering/
34
- │ ├── CONTEXT.md
35
- │ └── docs/adr/ ← context-specific decisions
36
- └── billing/
37
- ├── CONTEXT.md
38
- └── docs/adr/
39
- ```
40
-
41
- ## Use the glossary's vocabulary
42
-
43
- When your output names a domain concept (in an issue title, a refactor proposal, a hypothesis, a test name), use the term as defined in `CONTEXT.md`. Don't drift to synonyms the glossary explicitly avoids.
44
-
45
- If the concept you need isn't in the glossary yet, that's a signal — either you're inventing language the project doesn't use (reconsider) or there's a real gap (note it for `/domain-modeling`).
46
-
47
- ## Flag ADR conflicts
48
-
49
- If your output contradicts an existing ADR, surface it explicitly rather than silently overriding:
50
-
51
- > _Contradicts ADR-0007 (event-sourced orders) — but worth reopening because…_
5
+ Use established terms and surface an actual conflict with an existing ADR before changing the decision. Missing files are not a setup blocker. Add glossary entries or ADRs only when the task resolves a durable ambiguity or decision, not for every edit. Reuse unchanged material within the task.