@alphafox/cli 0.1.5 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -4
- package/dist/auth/browser-login.d.ts +30 -0
- package/dist/auth/browser-login.js +193 -0
- package/dist/auth/loopback-callback.d.ts +32 -0
- package/dist/auth/loopback-callback.js +175 -0
- package/dist/auth/open-browser.d.ts +15 -0
- package/dist/auth/open-browser.js +54 -0
- package/dist/auth/refresh.d.ts +27 -2
- package/dist/auth/refresh.js +52 -15
- package/dist/catalog/allowlist.d.ts +20 -4
- package/dist/catalog/allowlist.js +126 -25
- package/dist/catalog/command-tree.d.ts +35 -0
- package/dist/catalog/command-tree.js +119 -0
- package/dist/catalog/compatibility.d.ts +23 -0
- package/dist/catalog/compatibility.js +58 -0
- package/dist/catalog/generated/registry.json +6137 -0
- package/dist/catalog/generated/schemas.json +31036 -0
- package/dist/catalog/operations.d.ts +76 -3
- package/dist/catalog/operations.js +87 -213
- package/dist/catalog/validate-body.d.ts +22 -0
- package/dist/catalog/validate-body.js +98 -0
- package/dist/commands/request-body.d.ts +21 -0
- package/dist/commands/request-body.js +92 -0
- package/dist/commands/run.js +283 -162
- package/dist/config/profiles.js +3 -3
- package/dist/engine-backtest/errors.d.ts +18 -0
- package/dist/engine-backtest/errors.js +26 -0
- package/dist/engine-backtest/fetch-runtime.d.ts +38 -0
- package/dist/engine-backtest/fetch-runtime.js +170 -0
- package/dist/engine-backtest/native-import.d.ts +1 -0
- package/dist/engine-backtest/native-import.js +10 -0
- package/dist/engine-backtest/parse-args.d.ts +6 -0
- package/dist/engine-backtest/parse-args.js +281 -0
- package/dist/engine-backtest/persist.d.ts +32 -0
- package/dist/engine-backtest/persist.js +94 -0
- package/dist/engine-backtest/replay-timeframe.d.ts +16 -0
- package/dist/engine-backtest/replay-timeframe.js +48 -0
- package/dist/engine-backtest/resolve-packages.d.ts +27 -0
- package/dist/engine-backtest/resolve-packages.js +288 -0
- package/dist/engine-backtest/run-command.d.ts +38 -0
- package/dist/engine-backtest/run-command.js +540 -0
- package/dist/engine-backtest/types.d.ts +249 -0
- package/dist/engine-backtest/types.js +2 -0
- package/dist/envelope.d.ts +3 -0
- package/dist/envelope.js +43 -3
- package/dist/http/client.js +18 -15
- package/dist/index.d.ts +16 -5
- package/dist/index.js +47 -1
- package/dist/install/exec.d.ts +13 -0
- package/dist/install/exec.js +73 -0
- package/dist/install/package-root.d.ts +4 -0
- package/dist/install/package-root.js +59 -0
- package/dist/install/types.d.ts +69 -0
- package/dist/install/types.js +26 -0
- package/dist/install/wizard.d.ts +21 -0
- package/dist/install/wizard.js +332 -0
- package/dist/keychain/linux-secret-service.d.ts +11 -0
- package/dist/keychain/linux-secret-service.js +93 -0
- package/dist/keychain/store.d.ts +20 -1
- package/dist/keychain/store.js +94 -6
- package/dist/keychain/windows-credential.d.ts +13 -0
- package/dist/keychain/windows-credential.js +176 -0
- package/dist/safety/confirmation.d.ts +10 -3
- package/dist/safety/confirmation.js +27 -4
- package/dist/version.d.ts +2 -2
- package/dist/version.js +3 -2
- package/docs/.nojekyll +0 -0
- package/docs/agents/domain.md +51 -0
- package/docs/agents/issue-tracker.md +156 -0
- package/docs/agents/triage-labels.md +18 -0
- package/docs/alphafox-cli-installation-guide.md +105 -0
- package/docs/e2e-staging.md +76 -6
- package/docs/favicon.svg +4 -0
- package/docs/index.html +748 -0
- package/docs/logo/alphafox-mark.svg +4 -0
- package/docs/logo/alphafox-wordmark-black-en.svg +17 -0
- package/docs/logo/alphafox-wordmark-white-en.svg +16 -0
- package/docs/release-supply-chain.md +107 -26
- package/package.json +10 -3
- package/skills/account/SKILL.md +8 -6
- package/skills/admin/SKILL.md +9 -4
- package/skills/alphafox-shared/SKILL.md +44 -14
- package/skills/auth/SKILL.md +21 -6
- package/skills/engine-backtest/SKILL.md +71 -0
- package/skills/exchange/SKILL.md +10 -3
- package/skills/market/SKILL.md +9 -4
- package/skills/notification/SKILL.md +8 -3
- package/skills/strategy/SKILL.md +23 -9
- package/skills/trading/SKILL.md +18 -5
- package/vendor/backtest-runner/NOTICE.md +1 -0
- package/vendor/backtest-runner/README.md +97 -0
- package/vendor/backtest-runner/index.d.ts +423 -0
- package/vendor/backtest-runner/index.mjs +59 -0
- package/vendor/backtest-runner/lib/abortable.mjs +23 -0
- package/vendor/backtest-runner/lib/cache.mjs +159 -0
- package/vendor/backtest-runner/lib/coverage.mjs +238 -0
- package/vendor/backtest-runner/lib/encode.mjs +28 -0
- package/vendor/backtest-runner/lib/exchanges.mjs +143 -0
- package/vendor/backtest-runner/lib/proxy.mjs +78 -0
- package/vendor/backtest-runner/lib/scenario.mjs +66 -0
- package/vendor/backtest-runner/lib/series.mjs +370 -0
- package/vendor/backtest-runner/lib/tape-loader.mjs +614 -0
- package/vendor/backtest-runner/lib/timeframes.mjs +55 -0
- package/vendor/backtest-runner/package.json +13 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
export type SubscriptionTier = "free" | "pro" | "pro_max";
|
|
2
|
+
export type DataQualityMode = "strict" | "basic";
|
|
3
|
+
export type PricePath = "ohlc_path_4" | "close_only";
|
|
4
|
+
export interface ExecutionModel {
|
|
5
|
+
readonly pricePath: PricePath;
|
|
6
|
+
readonly makerFeeRate: number;
|
|
7
|
+
readonly takerFeeRate: number;
|
|
8
|
+
readonly slippageRate: number;
|
|
9
|
+
}
|
|
10
|
+
export interface InclusiveUtcDateRange {
|
|
11
|
+
readonly rangeStart: string;
|
|
12
|
+
readonly rangeEnd: string;
|
|
13
|
+
readonly fromMs: number;
|
|
14
|
+
readonly toMs: number;
|
|
15
|
+
}
|
|
16
|
+
export interface EngineBacktestRunArgs {
|
|
17
|
+
readonly help: boolean;
|
|
18
|
+
readonly experimentId?: string;
|
|
19
|
+
readonly createExperiment: boolean;
|
|
20
|
+
readonly name?: string;
|
|
21
|
+
readonly definitionId?: string;
|
|
22
|
+
readonly definitionLabelZh?: string;
|
|
23
|
+
readonly definitionLabelEn?: string;
|
|
24
|
+
readonly configRaw?: string;
|
|
25
|
+
readonly exchange?: string;
|
|
26
|
+
readonly range?: InclusiveUtcDateRange;
|
|
27
|
+
readonly initialEquity?: number;
|
|
28
|
+
/** Explicit --tier value. Persisted runs otherwise use the account tier. */
|
|
29
|
+
readonly tier?: SubscriptionTier;
|
|
30
|
+
readonly dataQualityMode: DataQualityMode;
|
|
31
|
+
readonly configSchemaVersion?: number;
|
|
32
|
+
readonly executionModelOverride?: Partial<ExecutionModel>;
|
|
33
|
+
readonly persist: boolean;
|
|
34
|
+
/** Replay/download bar. Defaults to 1m; never finer. */
|
|
35
|
+
readonly replayTimeframe: string;
|
|
36
|
+
}
|
|
37
|
+
export interface EngineBacktestSeriesRequirement {
|
|
38
|
+
readonly symbol: string;
|
|
39
|
+
readonly timeframe: string;
|
|
40
|
+
readonly minWarmupCandles: number;
|
|
41
|
+
}
|
|
42
|
+
export interface EngineBacktestTapeSeriesRef {
|
|
43
|
+
readonly symbol: string;
|
|
44
|
+
readonly timeframe: string;
|
|
45
|
+
readonly buffer: string;
|
|
46
|
+
readonly rows: number;
|
|
47
|
+
}
|
|
48
|
+
export interface EngineBacktestTapeInput {
|
|
49
|
+
readonly from: string;
|
|
50
|
+
readonly to: string;
|
|
51
|
+
readonly baseTimeframe: string;
|
|
52
|
+
readonly markets: Readonly<Record<string, unknown>>;
|
|
53
|
+
readonly series: readonly EngineBacktestTapeSeriesRef[];
|
|
54
|
+
readonly fundingRates?: Readonly<Record<string, readonly unknown[]>>;
|
|
55
|
+
readonly lowLiquiditySymbols?: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
export interface EngineBacktestScenario {
|
|
58
|
+
readonly version: 1;
|
|
59
|
+
readonly runId: string;
|
|
60
|
+
readonly trader: {
|
|
61
|
+
readonly id?: string;
|
|
62
|
+
readonly name?: string;
|
|
63
|
+
readonly strategyDefinitionId: string;
|
|
64
|
+
readonly configSchemaVersion: number;
|
|
65
|
+
readonly subscriptionTier: SubscriptionTier;
|
|
66
|
+
readonly config: unknown;
|
|
67
|
+
};
|
|
68
|
+
readonly exchange: {
|
|
69
|
+
readonly positionSideDual: boolean;
|
|
70
|
+
readonly initialEquity: number;
|
|
71
|
+
};
|
|
72
|
+
readonly executionModel: ExecutionModel;
|
|
73
|
+
readonly tape: EngineBacktestTapeInput;
|
|
74
|
+
}
|
|
75
|
+
export interface EngineBacktestMetrics {
|
|
76
|
+
readonly initialEquity: number;
|
|
77
|
+
readonly finalEquity: number;
|
|
78
|
+
readonly netPnl: number;
|
|
79
|
+
readonly returnPct: number;
|
|
80
|
+
readonly maxDrawdownPct: number;
|
|
81
|
+
readonly sharpeRatio: number;
|
|
82
|
+
readonly orderCount: number;
|
|
83
|
+
readonly filledOrderCount: number;
|
|
84
|
+
readonly canceledOrderCount: number;
|
|
85
|
+
readonly tradeCount: number;
|
|
86
|
+
readonly winningTrades: number;
|
|
87
|
+
readonly losingTrades: number;
|
|
88
|
+
readonly winRatePct: number;
|
|
89
|
+
readonly feesPaid: number;
|
|
90
|
+
readonly slippagePaid: number;
|
|
91
|
+
readonly liquidated: boolean;
|
|
92
|
+
}
|
|
93
|
+
export interface EngineBacktestResult {
|
|
94
|
+
readonly runId: string;
|
|
95
|
+
readonly status: "completed" | "failed";
|
|
96
|
+
readonly engineVersion?: string;
|
|
97
|
+
readonly metrics: EngineBacktestMetrics;
|
|
98
|
+
readonly equityCurve?: unknown[];
|
|
99
|
+
readonly orders?: unknown[];
|
|
100
|
+
readonly openPositions?: unknown[];
|
|
101
|
+
readonly errors?: Array<{
|
|
102
|
+
code: string;
|
|
103
|
+
message: string;
|
|
104
|
+
path?: string;
|
|
105
|
+
}>;
|
|
106
|
+
readonly warnings?: string[];
|
|
107
|
+
}
|
|
108
|
+
export interface EngineBacktestSupportReason {
|
|
109
|
+
readonly code: string;
|
|
110
|
+
readonly message: string;
|
|
111
|
+
}
|
|
112
|
+
export interface EngineSupportedBacktestPlan {
|
|
113
|
+
readonly definitionId: string;
|
|
114
|
+
readonly configSchemaVersion: number;
|
|
115
|
+
readonly support: {
|
|
116
|
+
readonly status: "supported";
|
|
117
|
+
};
|
|
118
|
+
readonly effectiveConfig: Record<string, unknown>;
|
|
119
|
+
readonly universe: {
|
|
120
|
+
readonly kind: "fixed";
|
|
121
|
+
readonly symbols: string[];
|
|
122
|
+
};
|
|
123
|
+
readonly symbols: string[];
|
|
124
|
+
readonly timeframes: string[];
|
|
125
|
+
readonly seriesRequirements: EngineBacktestSeriesRequirement[];
|
|
126
|
+
readonly needsFunding: boolean;
|
|
127
|
+
readonly auxiliaryDataRequirements: Array<{
|
|
128
|
+
readonly kind: string;
|
|
129
|
+
readonly parameters?: Record<string, unknown>;
|
|
130
|
+
}>;
|
|
131
|
+
readonly configFingerprint: string;
|
|
132
|
+
}
|
|
133
|
+
export interface EngineUnsupportedBacktestPlan {
|
|
134
|
+
readonly definitionId: string;
|
|
135
|
+
readonly configSchemaVersion: number;
|
|
136
|
+
readonly support: {
|
|
137
|
+
readonly status: "unsupported";
|
|
138
|
+
readonly reason: EngineBacktestSupportReason;
|
|
139
|
+
};
|
|
140
|
+
readonly needsFunding: false;
|
|
141
|
+
}
|
|
142
|
+
export interface EngineBacktestFailure {
|
|
143
|
+
readonly status: "failed";
|
|
144
|
+
readonly errors: Array<{
|
|
145
|
+
readonly code: string;
|
|
146
|
+
readonly message: string;
|
|
147
|
+
}>;
|
|
148
|
+
}
|
|
149
|
+
export type EngineBacktestPlan = EngineSupportedBacktestPlan | EngineUnsupportedBacktestPlan;
|
|
150
|
+
export interface TapeLoadProgress {
|
|
151
|
+
readonly stage: "markets" | "ohlcv" | "validation" | string;
|
|
152
|
+
readonly detail: string;
|
|
153
|
+
readonly fraction: number;
|
|
154
|
+
}
|
|
155
|
+
export interface TapeExchangeDefinition {
|
|
156
|
+
readonly id: string;
|
|
157
|
+
readonly label: string;
|
|
158
|
+
readonly ccxtId: string;
|
|
159
|
+
readonly marketType: string;
|
|
160
|
+
readonly quoteAsset: string;
|
|
161
|
+
}
|
|
162
|
+
export interface TapeLoadResult {
|
|
163
|
+
readonly tape: EngineBacktestTapeInput;
|
|
164
|
+
readonly buffers: Record<string, ArrayBuffer>;
|
|
165
|
+
readonly coverageWarnings: readonly string[];
|
|
166
|
+
}
|
|
167
|
+
export interface BacktestClientLike {
|
|
168
|
+
init(): Promise<string>;
|
|
169
|
+
version(): Promise<string>;
|
|
170
|
+
strategyDefinitions(): Promise<{
|
|
171
|
+
readonly engineVersion: string;
|
|
172
|
+
readonly definitions: Array<Record<string, unknown> & {
|
|
173
|
+
readonly id: string;
|
|
174
|
+
readonly configSchemaVersion?: number;
|
|
175
|
+
}>;
|
|
176
|
+
}>;
|
|
177
|
+
planBacktest(request: {
|
|
178
|
+
readonly definitionId: string;
|
|
179
|
+
readonly configSchemaVersion: number;
|
|
180
|
+
readonly config: unknown;
|
|
181
|
+
}): Promise<EngineBacktestPlan | EngineBacktestFailure>;
|
|
182
|
+
runBacktest(scenario: EngineBacktestScenario, buffers: Record<string, ArrayBuffer>, onProgress?: (fraction: number) => void): Promise<EngineBacktestResult>;
|
|
183
|
+
terminate(): void;
|
|
184
|
+
}
|
|
185
|
+
export interface BacktestWasmModule {
|
|
186
|
+
createNodeBacktestClient(options?: unknown): BacktestClientLike;
|
|
187
|
+
}
|
|
188
|
+
export interface BacktestRunnerModule {
|
|
189
|
+
loadTape(request: {
|
|
190
|
+
readonly exchangeId?: string;
|
|
191
|
+
readonly exchange?: TapeExchangeDefinition;
|
|
192
|
+
readonly symbols: readonly string[];
|
|
193
|
+
readonly baseTimeframe?: string;
|
|
194
|
+
readonly timeframes: readonly string[];
|
|
195
|
+
readonly seriesRequirements?: readonly EngineBacktestSeriesRequirement[];
|
|
196
|
+
readonly needsFunding?: boolean;
|
|
197
|
+
readonly auxiliaryDataRequirements?: readonly unknown[];
|
|
198
|
+
readonly fromMs: number;
|
|
199
|
+
readonly toMs: number;
|
|
200
|
+
readonly dataQualityMode?: DataQualityMode;
|
|
201
|
+
readonly onProgress?: (progress: TapeLoadProgress) => void;
|
|
202
|
+
}, options?: unknown): Promise<TapeLoadResult>;
|
|
203
|
+
assembleScenario(input: {
|
|
204
|
+
readonly runId: string;
|
|
205
|
+
readonly definitionId: string;
|
|
206
|
+
readonly configSchemaVersion: number;
|
|
207
|
+
readonly config: unknown;
|
|
208
|
+
readonly subscriptionTier: SubscriptionTier;
|
|
209
|
+
readonly initialEquity: number;
|
|
210
|
+
readonly tape?: EngineBacktestTapeInput;
|
|
211
|
+
readonly executionModel?: Partial<ExecutionModel>;
|
|
212
|
+
}): EngineBacktestScenario;
|
|
213
|
+
resolveTapeExchange(exchangeId: string | TapeExchangeDefinition): TapeExchangeDefinition;
|
|
214
|
+
DEFAULT_EXECUTION_MODEL: ExecutionModel;
|
|
215
|
+
}
|
|
216
|
+
export interface PersistedSnapshot {
|
|
217
|
+
readonly snapshotSchemaVersion: 1;
|
|
218
|
+
readonly strategyDefinitionId: string;
|
|
219
|
+
readonly configSchemaVersion: number;
|
|
220
|
+
readonly config: unknown;
|
|
221
|
+
readonly exchangeId: string;
|
|
222
|
+
readonly rangeStart: string;
|
|
223
|
+
readonly rangeEnd: string;
|
|
224
|
+
readonly initialEquity: number;
|
|
225
|
+
readonly subscriptionTier: SubscriptionTier;
|
|
226
|
+
readonly dataQualityMode: DataQualityMode;
|
|
227
|
+
readonly symbols: string[];
|
|
228
|
+
readonly timeframes: string[];
|
|
229
|
+
readonly baseTimeframe: string;
|
|
230
|
+
readonly executionModel: ExecutionModel;
|
|
231
|
+
readonly positionSideDual: boolean;
|
|
232
|
+
readonly engineVersion: string;
|
|
233
|
+
}
|
|
234
|
+
export interface CreateRunRequestBody {
|
|
235
|
+
readonly clientRunId: string;
|
|
236
|
+
readonly snapshot: PersistedSnapshot;
|
|
237
|
+
readonly metrics: EngineBacktestMetrics;
|
|
238
|
+
readonly engineVersion: string;
|
|
239
|
+
readonly configSchemaVersion: number;
|
|
240
|
+
}
|
|
241
|
+
export interface EngineBacktestRunSuccess {
|
|
242
|
+
readonly metrics: EngineBacktestMetrics;
|
|
243
|
+
readonly engineVersion: string;
|
|
244
|
+
readonly experimentId: string;
|
|
245
|
+
readonly runId?: string;
|
|
246
|
+
readonly experimentUrl: string;
|
|
247
|
+
readonly persisted: boolean;
|
|
248
|
+
readonly coverageWarnings: readonly string[];
|
|
249
|
+
}
|
package/dist/envelope.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
1
2
|
export type ExitCode = 0 | 1 | 2 | 3 | 4 | 10 | 64 | 65 | 66 | 69 | 70 | 75 | 77 | 78;
|
|
2
3
|
export interface SuccessEnvelope<T = unknown> {
|
|
3
4
|
readonly ok: true;
|
|
@@ -28,7 +29,9 @@ export declare function writeSuccess(data: unknown, options?: {
|
|
|
28
29
|
readonly meta?: Record<string, unknown>;
|
|
29
30
|
readonly requestId?: string;
|
|
30
31
|
readonly format?: "json" | "jsonl" | "text";
|
|
32
|
+
readonly jq?: string;
|
|
31
33
|
}): void;
|
|
34
|
+
export declare function applyJqFilter(value: unknown, filter: string, spawn?: typeof spawnSync): string;
|
|
32
35
|
export declare function writeError(error: ErrorBody, options?: {
|
|
33
36
|
readonly requestId?: string;
|
|
34
37
|
readonly exitCode?: number;
|
package/dist/envelope.js
CHANGED
|
@@ -4,10 +4,12 @@ exports.newRequestId = newRequestId;
|
|
|
4
4
|
exports.successEnvelope = successEnvelope;
|
|
5
5
|
exports.errorEnvelope = errorEnvelope;
|
|
6
6
|
exports.writeSuccess = writeSuccess;
|
|
7
|
+
exports.applyJqFilter = applyJqFilter;
|
|
7
8
|
exports.writeError = writeError;
|
|
8
9
|
exports.mapErrorToExitCode = mapErrorToExitCode;
|
|
9
10
|
exports.parseJsonEnvelope = parseJsonEnvelope;
|
|
10
11
|
const node_crypto_1 = require("node:crypto");
|
|
12
|
+
const node_child_process_1 = require("node:child_process");
|
|
11
13
|
function newRequestId() {
|
|
12
14
|
return (0, node_crypto_1.randomUUID)();
|
|
13
15
|
}
|
|
@@ -28,11 +30,49 @@ function errorEnvelope(error, requestId) {
|
|
|
28
30
|
}
|
|
29
31
|
function writeSuccess(data, options = {}) {
|
|
30
32
|
const envelope = successEnvelope(data, options.meta, options.requestId);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
const rendered = options.format === "text" && data && typeof data === "object"
|
|
34
|
+
? `${JSON.stringify(envelope, null, 2)}\n`
|
|
35
|
+
: `${JSON.stringify(envelope)}\n`;
|
|
36
|
+
if (options.jq?.trim()) {
|
|
37
|
+
const filtered = applyJqFilter(envelope, options.jq.trim());
|
|
38
|
+
process.stdout.write(filtered.endsWith("\n") ? filtered : `${filtered}\n`);
|
|
33
39
|
return;
|
|
34
40
|
}
|
|
35
|
-
process.stdout.write(
|
|
41
|
+
process.stdout.write(rendered);
|
|
42
|
+
}
|
|
43
|
+
function applyJqFilter(value, filter, spawn = node_child_process_1.spawnSync) {
|
|
44
|
+
if (!filter.trim()) {
|
|
45
|
+
throw Object.assign(new Error("--jq filter must be non-empty"), {
|
|
46
|
+
type: "usage",
|
|
47
|
+
subtype: "jq_empty",
|
|
48
|
+
status: 64,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const result = spawn(process.env.ALPHAFOX_JQ?.trim() || "jq", ["-c", filter], {
|
|
52
|
+
input: JSON.stringify(value),
|
|
53
|
+
encoding: "utf8",
|
|
54
|
+
timeout: 10_000,
|
|
55
|
+
});
|
|
56
|
+
if (result.error) {
|
|
57
|
+
const code = result.error.code;
|
|
58
|
+
if (code === "ENOENT") {
|
|
59
|
+
throw Object.assign(new Error("jq is not installed; --jq requires the jq binary on PATH"), { type: "usage", subtype: "jq_not_installed", status: 64 });
|
|
60
|
+
}
|
|
61
|
+
throw Object.assign(new Error(result.error.message), {
|
|
62
|
+
type: "usage",
|
|
63
|
+
subtype: "jq_failed",
|
|
64
|
+
status: 64,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
if (result.status !== 0) {
|
|
68
|
+
const errText = (result.stderr || "jq filter failed").trim();
|
|
69
|
+
throw Object.assign(new Error(errText), {
|
|
70
|
+
type: "usage",
|
|
71
|
+
subtype: "jq_failed",
|
|
72
|
+
status: 64,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return result.stdout;
|
|
36
76
|
}
|
|
37
77
|
function writeError(error, options = {}) {
|
|
38
78
|
const envelope = errorEnvelope(error, options.requestId);
|
package/dist/http/client.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.apiRequest = apiRequest;
|
|
4
4
|
const envelope_1 = require("../envelope");
|
|
5
|
+
const version_1 = require("../version");
|
|
5
6
|
const refresh_1 = require("../auth/refresh");
|
|
6
7
|
const store_1 = require("../keychain/store");
|
|
7
8
|
const allowlist_1 = require("../catalog/allowlist");
|
|
@@ -17,15 +18,15 @@ async function apiRequest(options, env = process.env, fetchImpl = fetch) {
|
|
|
17
18
|
}
|
|
18
19
|
// Product raw API: /api/v1 only. Auth AS paths under /api/auth/oauth are allowed.
|
|
19
20
|
const isOAuthAsPath = path.startsWith("/api/auth/oauth");
|
|
20
|
-
if (!isOAuthAsPath &&
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
21
|
+
if (!isOAuthAsPath && path.startsWith("/api/")) {
|
|
22
|
+
// Unknown /api/v1/* is denied (finite facility/catalog allowlist).
|
|
23
|
+
if (!(0, allowlist_1.isFacadeAllowlistedPath)(path)) {
|
|
24
|
+
throw Object.assign(new Error(`Path is outside Public API facade: ${path}`), {
|
|
25
|
+
status: 403,
|
|
26
|
+
type: "authorization",
|
|
27
|
+
subtype: "facade_only",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
29
30
|
}
|
|
30
31
|
const requestId = options.requestId ?? (0, envelope_1.newRequestId)();
|
|
31
32
|
const base = options.profile.apiBaseUrl.replace(/\/$/, "");
|
|
@@ -46,17 +47,19 @@ async function apiRequest(options, env = process.env, fetchImpl = fetch) {
|
|
|
46
47
|
Accept: "application/json",
|
|
47
48
|
"X-Request-Id": requestId,
|
|
48
49
|
"X-Alphafox-Client": "alphafox-cli",
|
|
49
|
-
"X-Alphafox-Client-Version": env.ALPHAFOX_CLI_VERSION ??
|
|
50
|
+
"X-Alphafox-Client-Version": env.ALPHAFOX_CLI_VERSION ?? version_1.CLI_VERSION,
|
|
50
51
|
...(options.headers ?? {}),
|
|
51
52
|
};
|
|
52
53
|
if (!options.skipAuth) {
|
|
53
54
|
let tokens = (0, store_1.loadTokens)(options.profile.name, env);
|
|
54
55
|
// Proactive refresh before the access token expires (or once already expired).
|
|
55
56
|
if (tokens && (0, refresh_1.accessTokenNeedsRefresh)(tokens)) {
|
|
56
|
-
const
|
|
57
|
-
if (
|
|
58
|
-
tokens =
|
|
57
|
+
const outcome = await (0, refresh_1.refreshStoredTokens)(options.profile, env, fetchImpl, { force: true });
|
|
58
|
+
if (outcome.status === "refreshed" || outcome.status === "unchanged") {
|
|
59
|
+
tokens = outcome.tokens;
|
|
59
60
|
}
|
|
61
|
+
// On failed refresh keep prior tokens only for the request; do not treat
|
|
62
|
+
// failure as a successful renewal.
|
|
60
63
|
}
|
|
61
64
|
if (tokens) {
|
|
62
65
|
// Never send tokens to a different site than the profile audience.
|
|
@@ -110,8 +113,8 @@ async function apiRequest(options, env = process.env, fetchImpl = fetch) {
|
|
|
110
113
|
!isOAuthAsPath) {
|
|
111
114
|
const tokens = (0, store_1.loadTokens)(options.profile.name, env);
|
|
112
115
|
if (tokens?.refreshToken?.trim()) {
|
|
113
|
-
const
|
|
114
|
-
if (
|
|
116
|
+
const outcome = await (0, refresh_1.refreshStoredTokens)(options.profile, env, fetchImpl, { force: true });
|
|
117
|
+
if (outcome.status === "refreshed") {
|
|
115
118
|
return apiRequest({ ...options, requestId, _refreshRetried: true }, env, fetchImpl);
|
|
116
119
|
}
|
|
117
120
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
export { runCli, parseGlobalFlags } from "./commands/run";
|
|
2
|
-
export { successEnvelope, errorEnvelope, parseJsonEnvelope, writeSuccess, writeError, } from "./envelope";
|
|
2
|
+
export { successEnvelope, errorEnvelope, parseJsonEnvelope, writeSuccess, writeError, applyJqFilter, } from "./envelope";
|
|
3
3
|
export { resolveProfile, loadConfigFile, saveConfigFile, assertNoTokenFields, } from "./config/profiles";
|
|
4
|
-
export { saveTokens, loadTokens, deleteTokens, tokenFingerprint, } from "./keychain/store";
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
4
|
+
export { saveTokens, loadTokens, deleteTokens, tokenFingerprint, getLastTokenSaveResult, probeOsKeychain, keychainPlatform, } from "./keychain/store";
|
|
5
|
+
export { linuxSecretServiceArgs, linuxSecretToolBin, } from "./keychain/linux-secret-service";
|
|
6
|
+
export { windowsCredentialTarget, WINDOWS_CRED_MAX_BYTES, } from "./keychain/windows-credential";
|
|
7
|
+
export { isFacadeAllowlistedPath, isInternalDisallowedPath, normalizeApiPath, pathTemplateMatches, } from "./catalog/allowlist";
|
|
8
|
+
export { checkCliCompatibility, type CompatibilityRange, type CompatibilityResult, } from "./catalog/compatibility";
|
|
9
|
+
export { resolveTypedCommand } from "./catalog/command-tree";
|
|
10
|
+
export { assertHighRiskConfirmation, inferRawApiRisk, requiresHighRiskConfirmation, } from "./safety/confirmation";
|
|
11
|
+
export { refreshStoredTokens, refreshStoredTokensOrNull, accessTokenNeedsRefresh, } from "./auth/refresh";
|
|
12
|
+
export { runBrowserPkceLogin } from "./auth/browser-login";
|
|
13
|
+
export { startLoopbackCallbackServer } from "./auth/loopback-callback";
|
|
14
|
+
export { CATALOG_OPERATIONS, CATALOG_SOURCE, CATALOG_VERSION, COMPATIBILITY_RANGE, findCatalogOperation, findCatalogOperationByRoute, getOperationSchemaDocument, buildCapabilityManifest, checkGeneratedCatalogCompatibility, } from "./catalog/operations";
|
|
8
15
|
export { CLI_VERSION, CLI_PACKAGE, CLI_CONTRACT_VERSION } from "./version";
|
|
16
|
+
export { validateCatalogWriteBody } from "./catalog/validate-body";
|
|
17
|
+
export { parseRequestBodyFlags, loadJsonArg } from "./commands/request-body";
|
|
18
|
+
export { parseInstallArgs, runInstallWizard, semverLessThan, skillsListHasAlphafox, } from "./install/wizard";
|
|
19
|
+
export { AGENT_INSTALL_GUIDE_BLOB_URL, AGENT_INSTALL_GUIDE_URL, SKILLS_GITHUB_SOURCE, } from "./install/types";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CLI_CONTRACT_VERSION = exports.CLI_PACKAGE = exports.CLI_VERSION = exports.buildCapabilityManifest = exports.findCatalogOperation = exports.CATALOG_OPERATIONS = exports.assertHighRiskConfirmation = exports.normalizeApiPath = exports.isInternalDisallowedPath = exports.isFacadeAllowlistedPath = exports.tokenFingerprint = exports.deleteTokens = exports.loadTokens = exports.saveTokens = exports.assertNoTokenFields = exports.saveConfigFile = exports.loadConfigFile = exports.resolveProfile = exports.writeError = exports.writeSuccess = exports.parseJsonEnvelope = exports.errorEnvelope = exports.successEnvelope = exports.parseGlobalFlags = exports.runCli = void 0;
|
|
3
|
+
exports.validateCatalogWriteBody = exports.CLI_CONTRACT_VERSION = exports.CLI_PACKAGE = exports.CLI_VERSION = exports.checkGeneratedCatalogCompatibility = exports.buildCapabilityManifest = exports.getOperationSchemaDocument = exports.findCatalogOperationByRoute = exports.findCatalogOperation = exports.COMPATIBILITY_RANGE = exports.CATALOG_VERSION = exports.CATALOG_SOURCE = exports.CATALOG_OPERATIONS = exports.startLoopbackCallbackServer = exports.runBrowserPkceLogin = exports.accessTokenNeedsRefresh = exports.refreshStoredTokensOrNull = exports.refreshStoredTokens = exports.requiresHighRiskConfirmation = exports.inferRawApiRisk = exports.assertHighRiskConfirmation = exports.resolveTypedCommand = exports.checkCliCompatibility = exports.pathTemplateMatches = exports.normalizeApiPath = exports.isInternalDisallowedPath = exports.isFacadeAllowlistedPath = exports.WINDOWS_CRED_MAX_BYTES = exports.windowsCredentialTarget = exports.linuxSecretToolBin = exports.linuxSecretServiceArgs = exports.keychainPlatform = exports.probeOsKeychain = exports.getLastTokenSaveResult = exports.tokenFingerprint = exports.deleteTokens = exports.loadTokens = exports.saveTokens = exports.assertNoTokenFields = exports.saveConfigFile = exports.loadConfigFile = exports.resolveProfile = exports.applyJqFilter = exports.writeError = exports.writeSuccess = exports.parseJsonEnvelope = exports.errorEnvelope = exports.successEnvelope = exports.parseGlobalFlags = exports.runCli = void 0;
|
|
4
|
+
exports.SKILLS_GITHUB_SOURCE = exports.AGENT_INSTALL_GUIDE_URL = exports.AGENT_INSTALL_GUIDE_BLOB_URL = exports.skillsListHasAlphafox = exports.semverLessThan = exports.runInstallWizard = exports.parseInstallArgs = exports.loadJsonArg = exports.parseRequestBodyFlags = void 0;
|
|
4
5
|
var run_1 = require("./commands/run");
|
|
5
6
|
Object.defineProperty(exports, "runCli", { enumerable: true, get: function () { return run_1.runCli; } });
|
|
6
7
|
Object.defineProperty(exports, "parseGlobalFlags", { enumerable: true, get: function () { return run_1.parseGlobalFlags; } });
|
|
@@ -10,6 +11,7 @@ Object.defineProperty(exports, "errorEnvelope", { enumerable: true, get: functio
|
|
|
10
11
|
Object.defineProperty(exports, "parseJsonEnvelope", { enumerable: true, get: function () { return envelope_1.parseJsonEnvelope; } });
|
|
11
12
|
Object.defineProperty(exports, "writeSuccess", { enumerable: true, get: function () { return envelope_1.writeSuccess; } });
|
|
12
13
|
Object.defineProperty(exports, "writeError", { enumerable: true, get: function () { return envelope_1.writeError; } });
|
|
14
|
+
Object.defineProperty(exports, "applyJqFilter", { enumerable: true, get: function () { return envelope_1.applyJqFilter; } });
|
|
13
15
|
var profiles_1 = require("./config/profiles");
|
|
14
16
|
Object.defineProperty(exports, "resolveProfile", { enumerable: true, get: function () { return profiles_1.resolveProfile; } });
|
|
15
17
|
Object.defineProperty(exports, "loadConfigFile", { enumerable: true, get: function () { return profiles_1.loadConfigFile; } });
|
|
@@ -20,17 +22,61 @@ Object.defineProperty(exports, "saveTokens", { enumerable: true, get: function (
|
|
|
20
22
|
Object.defineProperty(exports, "loadTokens", { enumerable: true, get: function () { return store_1.loadTokens; } });
|
|
21
23
|
Object.defineProperty(exports, "deleteTokens", { enumerable: true, get: function () { return store_1.deleteTokens; } });
|
|
22
24
|
Object.defineProperty(exports, "tokenFingerprint", { enumerable: true, get: function () { return store_1.tokenFingerprint; } });
|
|
25
|
+
Object.defineProperty(exports, "getLastTokenSaveResult", { enumerable: true, get: function () { return store_1.getLastTokenSaveResult; } });
|
|
26
|
+
Object.defineProperty(exports, "probeOsKeychain", { enumerable: true, get: function () { return store_1.probeOsKeychain; } });
|
|
27
|
+
Object.defineProperty(exports, "keychainPlatform", { enumerable: true, get: function () { return store_1.keychainPlatform; } });
|
|
28
|
+
var linux_secret_service_1 = require("./keychain/linux-secret-service");
|
|
29
|
+
Object.defineProperty(exports, "linuxSecretServiceArgs", { enumerable: true, get: function () { return linux_secret_service_1.linuxSecretServiceArgs; } });
|
|
30
|
+
Object.defineProperty(exports, "linuxSecretToolBin", { enumerable: true, get: function () { return linux_secret_service_1.linuxSecretToolBin; } });
|
|
31
|
+
var windows_credential_1 = require("./keychain/windows-credential");
|
|
32
|
+
Object.defineProperty(exports, "windowsCredentialTarget", { enumerable: true, get: function () { return windows_credential_1.windowsCredentialTarget; } });
|
|
33
|
+
Object.defineProperty(exports, "WINDOWS_CRED_MAX_BYTES", { enumerable: true, get: function () { return windows_credential_1.WINDOWS_CRED_MAX_BYTES; } });
|
|
23
34
|
var allowlist_1 = require("./catalog/allowlist");
|
|
24
35
|
Object.defineProperty(exports, "isFacadeAllowlistedPath", { enumerable: true, get: function () { return allowlist_1.isFacadeAllowlistedPath; } });
|
|
25
36
|
Object.defineProperty(exports, "isInternalDisallowedPath", { enumerable: true, get: function () { return allowlist_1.isInternalDisallowedPath; } });
|
|
26
37
|
Object.defineProperty(exports, "normalizeApiPath", { enumerable: true, get: function () { return allowlist_1.normalizeApiPath; } });
|
|
38
|
+
Object.defineProperty(exports, "pathTemplateMatches", { enumerable: true, get: function () { return allowlist_1.pathTemplateMatches; } });
|
|
39
|
+
var compatibility_1 = require("./catalog/compatibility");
|
|
40
|
+
Object.defineProperty(exports, "checkCliCompatibility", { enumerable: true, get: function () { return compatibility_1.checkCliCompatibility; } });
|
|
41
|
+
var command_tree_1 = require("./catalog/command-tree");
|
|
42
|
+
Object.defineProperty(exports, "resolveTypedCommand", { enumerable: true, get: function () { return command_tree_1.resolveTypedCommand; } });
|
|
27
43
|
var confirmation_1 = require("./safety/confirmation");
|
|
28
44
|
Object.defineProperty(exports, "assertHighRiskConfirmation", { enumerable: true, get: function () { return confirmation_1.assertHighRiskConfirmation; } });
|
|
45
|
+
Object.defineProperty(exports, "inferRawApiRisk", { enumerable: true, get: function () { return confirmation_1.inferRawApiRisk; } });
|
|
46
|
+
Object.defineProperty(exports, "requiresHighRiskConfirmation", { enumerable: true, get: function () { return confirmation_1.requiresHighRiskConfirmation; } });
|
|
47
|
+
var refresh_1 = require("./auth/refresh");
|
|
48
|
+
Object.defineProperty(exports, "refreshStoredTokens", { enumerable: true, get: function () { return refresh_1.refreshStoredTokens; } });
|
|
49
|
+
Object.defineProperty(exports, "refreshStoredTokensOrNull", { enumerable: true, get: function () { return refresh_1.refreshStoredTokensOrNull; } });
|
|
50
|
+
Object.defineProperty(exports, "accessTokenNeedsRefresh", { enumerable: true, get: function () { return refresh_1.accessTokenNeedsRefresh; } });
|
|
51
|
+
var browser_login_1 = require("./auth/browser-login");
|
|
52
|
+
Object.defineProperty(exports, "runBrowserPkceLogin", { enumerable: true, get: function () { return browser_login_1.runBrowserPkceLogin; } });
|
|
53
|
+
var loopback_callback_1 = require("./auth/loopback-callback");
|
|
54
|
+
Object.defineProperty(exports, "startLoopbackCallbackServer", { enumerable: true, get: function () { return loopback_callback_1.startLoopbackCallbackServer; } });
|
|
29
55
|
var operations_1 = require("./catalog/operations");
|
|
30
56
|
Object.defineProperty(exports, "CATALOG_OPERATIONS", { enumerable: true, get: function () { return operations_1.CATALOG_OPERATIONS; } });
|
|
57
|
+
Object.defineProperty(exports, "CATALOG_SOURCE", { enumerable: true, get: function () { return operations_1.CATALOG_SOURCE; } });
|
|
58
|
+
Object.defineProperty(exports, "CATALOG_VERSION", { enumerable: true, get: function () { return operations_1.CATALOG_VERSION; } });
|
|
59
|
+
Object.defineProperty(exports, "COMPATIBILITY_RANGE", { enumerable: true, get: function () { return operations_1.COMPATIBILITY_RANGE; } });
|
|
31
60
|
Object.defineProperty(exports, "findCatalogOperation", { enumerable: true, get: function () { return operations_1.findCatalogOperation; } });
|
|
61
|
+
Object.defineProperty(exports, "findCatalogOperationByRoute", { enumerable: true, get: function () { return operations_1.findCatalogOperationByRoute; } });
|
|
62
|
+
Object.defineProperty(exports, "getOperationSchemaDocument", { enumerable: true, get: function () { return operations_1.getOperationSchemaDocument; } });
|
|
32
63
|
Object.defineProperty(exports, "buildCapabilityManifest", { enumerable: true, get: function () { return operations_1.buildCapabilityManifest; } });
|
|
64
|
+
Object.defineProperty(exports, "checkGeneratedCatalogCompatibility", { enumerable: true, get: function () { return operations_1.checkGeneratedCatalogCompatibility; } });
|
|
33
65
|
var version_1 = require("./version");
|
|
34
66
|
Object.defineProperty(exports, "CLI_VERSION", { enumerable: true, get: function () { return version_1.CLI_VERSION; } });
|
|
35
67
|
Object.defineProperty(exports, "CLI_PACKAGE", { enumerable: true, get: function () { return version_1.CLI_PACKAGE; } });
|
|
36
68
|
Object.defineProperty(exports, "CLI_CONTRACT_VERSION", { enumerable: true, get: function () { return version_1.CLI_CONTRACT_VERSION; } });
|
|
69
|
+
var validate_body_1 = require("./catalog/validate-body");
|
|
70
|
+
Object.defineProperty(exports, "validateCatalogWriteBody", { enumerable: true, get: function () { return validate_body_1.validateCatalogWriteBody; } });
|
|
71
|
+
var request_body_1 = require("./commands/request-body");
|
|
72
|
+
Object.defineProperty(exports, "parseRequestBodyFlags", { enumerable: true, get: function () { return request_body_1.parseRequestBodyFlags; } });
|
|
73
|
+
Object.defineProperty(exports, "loadJsonArg", { enumerable: true, get: function () { return request_body_1.loadJsonArg; } });
|
|
74
|
+
var wizard_1 = require("./install/wizard");
|
|
75
|
+
Object.defineProperty(exports, "parseInstallArgs", { enumerable: true, get: function () { return wizard_1.parseInstallArgs; } });
|
|
76
|
+
Object.defineProperty(exports, "runInstallWizard", { enumerable: true, get: function () { return wizard_1.runInstallWizard; } });
|
|
77
|
+
Object.defineProperty(exports, "semverLessThan", { enumerable: true, get: function () { return wizard_1.semverLessThan; } });
|
|
78
|
+
Object.defineProperty(exports, "skillsListHasAlphafox", { enumerable: true, get: function () { return wizard_1.skillsListHasAlphafox; } });
|
|
79
|
+
var types_1 = require("./install/types");
|
|
80
|
+
Object.defineProperty(exports, "AGENT_INSTALL_GUIDE_BLOB_URL", { enumerable: true, get: function () { return types_1.AGENT_INSTALL_GUIDE_BLOB_URL; } });
|
|
81
|
+
Object.defineProperty(exports, "AGENT_INSTALL_GUIDE_URL", { enumerable: true, get: function () { return types_1.AGENT_INSTALL_GUIDE_URL; } });
|
|
82
|
+
Object.defineProperty(exports, "SKILLS_GITHUB_SOURCE", { enumerable: true, get: function () { return types_1.SKILLS_GITHUB_SOURCE; } });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ExecResult, InstallRunner } from "./types";
|
|
2
|
+
export declare function wrapWindowsCommand(command: string, args: readonly string[], platform?: NodeJS.Platform): {
|
|
3
|
+
readonly file: string;
|
|
4
|
+
readonly argv: string[];
|
|
5
|
+
};
|
|
6
|
+
export declare function execCommand(command: string, args: readonly string[], options?: {
|
|
7
|
+
readonly timeoutMs?: number;
|
|
8
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
9
|
+
readonly inherit?: boolean;
|
|
10
|
+
readonly platform?: NodeJS.Platform;
|
|
11
|
+
}): Promise<ExecResult>;
|
|
12
|
+
export declare function confirmTty(message: string): Promise<boolean>;
|
|
13
|
+
export declare function createDefaultInstallRunner(env: NodeJS.ProcessEnv, searchDirs: readonly string[]): InstallRunner;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.wrapWindowsCommand = wrapWindowsCommand;
|
|
4
|
+
exports.execCommand = execCommand;
|
|
5
|
+
exports.confirmTty = confirmTty;
|
|
6
|
+
exports.createDefaultInstallRunner = createDefaultInstallRunner;
|
|
7
|
+
const node_child_process_1 = require("node:child_process");
|
|
8
|
+
const promises_1 = require("node:readline/promises");
|
|
9
|
+
const node_util_1 = require("node:util");
|
|
10
|
+
const execFileAsync = (0, node_util_1.promisify)(node_child_process_1.execFile);
|
|
11
|
+
function wrapWindowsCommand(command, args, platform = process.platform) {
|
|
12
|
+
if (platform === "win32") {
|
|
13
|
+
return { file: "cmd.exe", argv: ["/c", command, ...args] };
|
|
14
|
+
}
|
|
15
|
+
return { file: command, argv: [...args] };
|
|
16
|
+
}
|
|
17
|
+
async function execCommand(command, args, options = {}) {
|
|
18
|
+
const { file, argv } = wrapWindowsCommand(command, args, options.platform ?? process.platform);
|
|
19
|
+
const timeout = options.timeoutMs ?? 120_000;
|
|
20
|
+
if (options.inherit) {
|
|
21
|
+
await new Promise((resolve, reject) => {
|
|
22
|
+
const child = (0, node_child_process_1.spawn)(file, argv, {
|
|
23
|
+
stdio: "inherit",
|
|
24
|
+
env: options.env,
|
|
25
|
+
timeout,
|
|
26
|
+
});
|
|
27
|
+
child.on("error", reject);
|
|
28
|
+
child.on("exit", (code) => {
|
|
29
|
+
if (code === 0)
|
|
30
|
+
resolve();
|
|
31
|
+
else
|
|
32
|
+
reject(new Error(`${command} exited ${code ?? "null"}`));
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
return { stdout: "", stderr: "" };
|
|
36
|
+
}
|
|
37
|
+
const { stdout, stderr } = await execFileAsync(file, argv, {
|
|
38
|
+
timeout,
|
|
39
|
+
encoding: "utf8",
|
|
40
|
+
env: options.env,
|
|
41
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
42
|
+
});
|
|
43
|
+
return { stdout, stderr };
|
|
44
|
+
}
|
|
45
|
+
async function confirmTty(message) {
|
|
46
|
+
const rl = (0, promises_1.createInterface)({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stderr,
|
|
49
|
+
});
|
|
50
|
+
try {
|
|
51
|
+
const answer = await rl.question(`${message} [Y/n] `);
|
|
52
|
+
const token = answer.trim().toLowerCase();
|
|
53
|
+
return token === "" || token === "y" || token === "yes";
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
rl.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function createDefaultInstallRunner(env, searchDirs) {
|
|
60
|
+
return {
|
|
61
|
+
env,
|
|
62
|
+
packageSearchDirs: () => searchDirs,
|
|
63
|
+
isTty: () => Boolean(process.stdin.isTTY && process.stderr.isTTY),
|
|
64
|
+
log: (message) => {
|
|
65
|
+
process.stderr.write(`${message}\n`);
|
|
66
|
+
},
|
|
67
|
+
confirm: confirmTty,
|
|
68
|
+
exec: (command, args, options) => execCommand(command, args, { ...options, env }),
|
|
69
|
+
execInherit: async (command, args, options) => {
|
|
70
|
+
await execCommand(command, args, { ...options, env, inherit: true });
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function findAlphafoxPackageRoot(startDirs: readonly string[]): string | null;
|
|
2
|
+
export declare function packageHasSkills(packageRoot: string): boolean;
|
|
3
|
+
export declare function globalPackageRoot(npmRootGlobal: string): string;
|
|
4
|
+
export declare function globalBinPath(npmPrefixGlobal: string, platform?: NodeJS.Platform): string;
|