@nick848/fet 1.1.4 → 1.1.5
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 +13 -0
- package/README_en.md +13 -0
- package/dist/cli/index.js +243 -57
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -50,6 +50,7 @@ fet --help
|
|
|
50
50
|
|
|
51
51
|
```sh
|
|
52
52
|
fet init
|
|
53
|
+
fet fill-context
|
|
53
54
|
fet doctor
|
|
54
55
|
```
|
|
55
56
|
|
|
@@ -95,6 +96,18 @@ fet init --lang en
|
|
|
95
96
|
| `--verbose` | 输出更多诊断信息。 | `fet doctor --verbose` |
|
|
96
97
|
| `--no-color` | 禁用终端颜色。 | `fet --no-color doctor` |
|
|
97
98
|
|
|
99
|
+
### 版本更新检查
|
|
100
|
+
|
|
101
|
+
除 `fet update` 外,FET 在执行其他命令前会检查 npm 上是否有新版本(默认缓存 6 小时)。发现新版本时会提示当前版本与最新版本;在交互式终端中可选择立即升级、跳过并继续当前任务,或取消命令。
|
|
102
|
+
|
|
103
|
+
| 环境变量 | 说明 |
|
|
104
|
+
|----------|------|
|
|
105
|
+
| `FET_UPDATE_CHECK` | `off` 关闭检查;`warn` 仅警告并继续;`confirm` 在 TTY 中交互询问(默认)。 |
|
|
106
|
+
| `FET_SKIP_UPDATE_CHECK` | 设为 `1` 时等同于 `FET_UPDATE_CHECK=off`。 |
|
|
107
|
+
| `FET_UPDATE_CHECK_TTL_MS` | 版本检查缓存时长(毫秒),默认 `21600000`(6 小时)。 |
|
|
108
|
+
|
|
109
|
+
使用 `--yes` 或 `--json` 时会跳过交互式升级询问;跳过某版本后,同一最新版本不会重复提示,直到检测到更高的新版本。
|
|
110
|
+
|
|
98
111
|
## 命令列表
|
|
99
112
|
|
|
100
113
|
| 命令 | 用法 | 说明 |
|
package/README_en.md
CHANGED
|
@@ -51,6 +51,7 @@ Run this in a project root that should use OpenSpec:
|
|
|
51
51
|
|
|
52
52
|
```sh
|
|
53
53
|
fet init
|
|
54
|
+
fet fill-context
|
|
54
55
|
fet doctor
|
|
55
56
|
```
|
|
56
57
|
|
|
@@ -96,6 +97,18 @@ fet init --lang en
|
|
|
96
97
|
| `--verbose` | Print more diagnostics. | `fet doctor --verbose` |
|
|
97
98
|
| `--no-color` | Disable terminal colors. | `fet --no-color doctor` |
|
|
98
99
|
|
|
100
|
+
### Version update check
|
|
101
|
+
|
|
102
|
+
Before most commands (except `fet update`), FET checks npm for a newer release (cached for 6 hours by default). When an update is available, it prints the current and latest versions. In an interactive terminal you can upgrade now, skip and continue the current task, or cancel the command.
|
|
103
|
+
|
|
104
|
+
| Variable | Description |
|
|
105
|
+
|----------|-------------|
|
|
106
|
+
| `FET_UPDATE_CHECK` | `off` disables checks; `warn` prints a warning and continues; `confirm` prompts in a TTY (default). |
|
|
107
|
+
| `FET_SKIP_UPDATE_CHECK` | Set to `1` to disable checks (same as `FET_UPDATE_CHECK=off`). |
|
|
108
|
+
| `FET_UPDATE_CHECK_TTL_MS` | Cache TTL in milliseconds; default `21600000` (6 hours). |
|
|
109
|
+
|
|
110
|
+
`--yes` and `--json` skip the interactive upgrade prompt. If you skip a specific latest version, FET will not prompt again for that version until a newer release appears.
|
|
111
|
+
|
|
99
112
|
## Commands
|
|
100
113
|
|
|
101
114
|
| Command | Usage | Description |
|
package/dist/cli/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "../chunk-J5WB4KAL.js";
|
|
6
6
|
|
|
7
7
|
// src/cli/index.ts
|
|
8
|
-
import { createInterface as
|
|
8
|
+
import { createInterface as createInterface3 } from "readline/promises";
|
|
9
9
|
import { Command } from "commander";
|
|
10
10
|
|
|
11
11
|
// src/commands/doctor.ts
|
|
@@ -2679,60 +2679,16 @@ async function assertVerifiedChange(ctx, changeId) {
|
|
|
2679
2679
|
}
|
|
2680
2680
|
}
|
|
2681
2681
|
|
|
2682
|
-
// src/
|
|
2682
|
+
// src/update/npm.ts
|
|
2683
2683
|
import { spawn } from "child_process";
|
|
2684
|
-
var
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
if (compareVersions(currentVersion, latestVersion) >= 0) {
|
|
2691
|
-
ctx.output.result({
|
|
2692
|
-
ok: true,
|
|
2693
|
-
command: "update",
|
|
2694
|
-
summary: ctx.language === "en" ? `FET is already up to date (${currentVersion}).` : `FET \u5DF2\u662F\u6700\u65B0\u7248 (${currentVersion})\u3002`,
|
|
2695
|
-
data: {
|
|
2696
|
-
packageName,
|
|
2697
|
-
currentVersion,
|
|
2698
|
-
latestVersion,
|
|
2699
|
-
updated: false
|
|
2700
|
-
}
|
|
2701
|
-
});
|
|
2702
|
-
return;
|
|
2703
|
-
}
|
|
2704
|
-
if (!ctx.json) {
|
|
2705
|
-
ctx.output.info(
|
|
2706
|
-
ctx.language === "en" ? `Updating FET from ${currentVersion} to ${latestVersion}...` : `\u6B63\u5728\u5C06 FET \u4ECE ${currentVersion} \u5347\u7EA7\u5230 ${latestVersion}...`
|
|
2707
|
-
);
|
|
2708
|
-
}
|
|
2709
|
-
const installArgs = ["install", "-g", `${packageName}@latest`];
|
|
2710
|
-
const result = await runNpm(npmExecutable, installArgs, {
|
|
2711
|
-
cwd: ctx.cwd,
|
|
2712
|
-
stdio: ctx.json ? "pipe" : "inherit"
|
|
2713
|
-
});
|
|
2714
|
-
if (result.exitCode !== 0) {
|
|
2715
|
-
throw new FetError({
|
|
2716
|
-
code: "UPDATE_FAILED" /* UpdateFailed */,
|
|
2717
|
-
message: ctx.language === "en" ? "FET update failed." : "FET \u5347\u7EA7\u5931\u8D25\u3002",
|
|
2718
|
-
details: result,
|
|
2719
|
-
suggestedCommand: `${npmExecutable} ${installArgs.join(" ")}`
|
|
2720
|
-
});
|
|
2721
|
-
}
|
|
2722
|
-
ctx.output.result({
|
|
2723
|
-
ok: true,
|
|
2724
|
-
command: "update",
|
|
2725
|
-
summary: ctx.language === "en" ? `FET updated from ${currentVersion} to ${latestVersion}.` : `FET \u5DF2\u4ECE ${currentVersion} \u5347\u7EA7\u5230 ${latestVersion}\u3002`,
|
|
2726
|
-
data: {
|
|
2727
|
-
packageName,
|
|
2728
|
-
currentVersion,
|
|
2729
|
-
latestVersion,
|
|
2730
|
-
updated: true,
|
|
2731
|
-
installCommand: `${npmExecutable} ${installArgs.join(" ")}`
|
|
2732
|
-
}
|
|
2733
|
-
});
|
|
2684
|
+
var DEFAULT_FET_PACKAGE_NAME = "@nick848/fet";
|
|
2685
|
+
function getFetPackageName(env = process.env) {
|
|
2686
|
+
return env.FET_UPDATE_PACKAGE_NAME?.trim() || DEFAULT_FET_PACKAGE_NAME;
|
|
2687
|
+
}
|
|
2688
|
+
function getNpmExecutable(env = process.env) {
|
|
2689
|
+
return env.FET_UPDATE_NPM_EXECUTABLE?.trim() || (process.platform === "win32" ? "npm.cmd" : "npm");
|
|
2734
2690
|
}
|
|
2735
|
-
async function
|
|
2691
|
+
async function resolveLatestFetVersion(packageName = getFetPackageName(), npmExecutable = getNpmExecutable()) {
|
|
2736
2692
|
const override = process.env.FET_UPDATE_LATEST_VERSION?.trim();
|
|
2737
2693
|
if (override) {
|
|
2738
2694
|
return override;
|
|
@@ -2759,6 +2715,32 @@ async function resolveLatestVersion(packageName, npmExecutable) {
|
|
|
2759
2715
|
}
|
|
2760
2716
|
return version;
|
|
2761
2717
|
}
|
|
2718
|
+
async function performFetUpdate(currentVersion, latestVersion, options) {
|
|
2719
|
+
const packageName = getFetPackageName();
|
|
2720
|
+
const npmExecutable = getNpmExecutable();
|
|
2721
|
+
const installArgs = ["install", "-g", `${packageName}@latest`];
|
|
2722
|
+
if (!options.json) {
|
|
2723
|
+
options.info(
|
|
2724
|
+
options.language === "en" ? `Updating FET from ${currentVersion} to ${latestVersion}...` : `\u6B63\u5728\u5C06 FET \u4ECE ${currentVersion} \u5347\u7EA7\u5230 ${latestVersion}...`
|
|
2725
|
+
);
|
|
2726
|
+
}
|
|
2727
|
+
const result = await runNpm(npmExecutable, installArgs, {
|
|
2728
|
+
cwd: options.cwd,
|
|
2729
|
+
stdio: options.json ? "pipe" : "inherit"
|
|
2730
|
+
});
|
|
2731
|
+
if (result.exitCode !== 0) {
|
|
2732
|
+
throw new FetError({
|
|
2733
|
+
code: "UPDATE_FAILED" /* UpdateFailed */,
|
|
2734
|
+
message: options.language === "en" ? "FET update failed." : "FET \u5347\u7EA7\u5931\u8D25\u3002",
|
|
2735
|
+
details: result,
|
|
2736
|
+
suggestedCommand: `${npmExecutable} ${installArgs.join(" ")}`
|
|
2737
|
+
});
|
|
2738
|
+
}
|
|
2739
|
+
return {
|
|
2740
|
+
packageName,
|
|
2741
|
+
installCommand: `${npmExecutable} ${installArgs.join(" ")}`
|
|
2742
|
+
};
|
|
2743
|
+
}
|
|
2762
2744
|
function parseNpmVersion(stdout) {
|
|
2763
2745
|
const trimmed = stdout.trim();
|
|
2764
2746
|
if (!trimmed) {
|
|
@@ -2805,9 +2787,6 @@ function runNpm(command, args, options) {
|
|
|
2805
2787
|
});
|
|
2806
2788
|
});
|
|
2807
2789
|
}
|
|
2808
|
-
function defaultNpmExecutable() {
|
|
2809
|
-
return process.platform === "win32" ? "npm.cmd" : "npm";
|
|
2810
|
-
}
|
|
2811
2790
|
function compareVersions(left, right) {
|
|
2812
2791
|
const leftVersion = parseVersion(left);
|
|
2813
2792
|
const rightVersion = parseVersion(right);
|
|
@@ -2868,6 +2847,45 @@ function comparePrereleasePart(left, right) {
|
|
|
2868
2847
|
return left.localeCompare(right);
|
|
2869
2848
|
}
|
|
2870
2849
|
|
|
2850
|
+
// src/commands/update.ts
|
|
2851
|
+
async function updateCommand(ctx) {
|
|
2852
|
+
const packageName = getFetPackageName();
|
|
2853
|
+
const latestVersion = await resolveLatestFetVersion(packageName);
|
|
2854
|
+
const currentVersion = ctx.fetVersion;
|
|
2855
|
+
if (compareVersions(currentVersion, latestVersion) >= 0) {
|
|
2856
|
+
ctx.output.result({
|
|
2857
|
+
ok: true,
|
|
2858
|
+
command: "update",
|
|
2859
|
+
summary: ctx.language === "en" ? `FET is already up to date (${currentVersion}).` : `FET \u5DF2\u662F\u6700\u65B0\u7248 (${currentVersion})\u3002`,
|
|
2860
|
+
data: {
|
|
2861
|
+
packageName,
|
|
2862
|
+
currentVersion,
|
|
2863
|
+
latestVersion,
|
|
2864
|
+
updated: false
|
|
2865
|
+
}
|
|
2866
|
+
});
|
|
2867
|
+
return;
|
|
2868
|
+
}
|
|
2869
|
+
const install = await performFetUpdate(currentVersion, latestVersion, {
|
|
2870
|
+
cwd: ctx.cwd,
|
|
2871
|
+
json: ctx.json,
|
|
2872
|
+
language: ctx.language,
|
|
2873
|
+
info: (message) => ctx.output.info(message)
|
|
2874
|
+
});
|
|
2875
|
+
ctx.output.result({
|
|
2876
|
+
ok: true,
|
|
2877
|
+
command: "update",
|
|
2878
|
+
summary: ctx.language === "en" ? `FET updated from ${currentVersion} to ${latestVersion}.` : `FET \u5DF2\u4ECE ${currentVersion} \u5347\u7EA7\u5230 ${latestVersion}\u3002`,
|
|
2879
|
+
data: {
|
|
2880
|
+
packageName,
|
|
2881
|
+
currentVersion,
|
|
2882
|
+
latestVersion,
|
|
2883
|
+
updated: true,
|
|
2884
|
+
installCommand: install.installCommand
|
|
2885
|
+
}
|
|
2886
|
+
});
|
|
2887
|
+
}
|
|
2888
|
+
|
|
2871
2889
|
// src/commands/verify.ts
|
|
2872
2890
|
import { createHash } from "crypto";
|
|
2873
2891
|
import { mkdir as mkdir7, readFile as readFile12, stat as stat5 } from "fs/promises";
|
|
@@ -5023,6 +5041,173 @@ async function createCommandContext(command, options) {
|
|
|
5023
5041
|
};
|
|
5024
5042
|
}
|
|
5025
5043
|
|
|
5044
|
+
// src/cli/update-check.ts
|
|
5045
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
5046
|
+
|
|
5047
|
+
// src/update/check.ts
|
|
5048
|
+
import { mkdir as mkdir10, readFile as readFile16, writeFile } from "fs/promises";
|
|
5049
|
+
import { homedir as homedir2 } from "os";
|
|
5050
|
+
import { dirname as dirname10, join as join21 } from "path";
|
|
5051
|
+
var DEFAULT_CACHE_TTL_MS = 6 * 60 * 60 * 1e3;
|
|
5052
|
+
function getFetUpdateCheckMode(env = process.env) {
|
|
5053
|
+
const value = env.FET_UPDATE_CHECK?.trim().toLowerCase();
|
|
5054
|
+
if (value === "off" || env.FET_SKIP_UPDATE_CHECK === "1") {
|
|
5055
|
+
return "off";
|
|
5056
|
+
}
|
|
5057
|
+
if (value === "warn") {
|
|
5058
|
+
return "warn";
|
|
5059
|
+
}
|
|
5060
|
+
if (value === "confirm") {
|
|
5061
|
+
return "confirm";
|
|
5062
|
+
}
|
|
5063
|
+
return "confirm";
|
|
5064
|
+
}
|
|
5065
|
+
function shouldCheckFetUpdateForCommand(command) {
|
|
5066
|
+
return command !== "update";
|
|
5067
|
+
}
|
|
5068
|
+
async function resolveFetUpdateAvailability(currentVersion) {
|
|
5069
|
+
const packageName = getFetPackageName();
|
|
5070
|
+
const cache = await readUpdateCheckCache();
|
|
5071
|
+
const ttlMs = Number.parseInt(process.env.FET_UPDATE_CHECK_TTL_MS ?? "", 10);
|
|
5072
|
+
const cacheTtlMs = Number.isFinite(ttlMs) && ttlMs > 0 ? ttlMs : DEFAULT_CACHE_TTL_MS;
|
|
5073
|
+
let latestVersion = cache?.latestVersion;
|
|
5074
|
+
const cacheFresh = cache?.checkedAt ? Date.now() - Date.parse(cache.checkedAt) < cacheTtlMs : false;
|
|
5075
|
+
if (!latestVersion || !cacheFresh) {
|
|
5076
|
+
try {
|
|
5077
|
+
latestVersion = await resolveLatestFetVersion(packageName);
|
|
5078
|
+
await writeUpdateCheckCache({
|
|
5079
|
+
latestVersion,
|
|
5080
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5081
|
+
dismissedLatestVersion: cache?.dismissedLatestVersion
|
|
5082
|
+
});
|
|
5083
|
+
} catch {
|
|
5084
|
+
if (cache?.latestVersion) {
|
|
5085
|
+
latestVersion = cache.latestVersion;
|
|
5086
|
+
} else {
|
|
5087
|
+
return null;
|
|
5088
|
+
}
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
if (compareVersions(currentVersion, latestVersion) >= 0) {
|
|
5092
|
+
return null;
|
|
5093
|
+
}
|
|
5094
|
+
if (cache?.dismissedLatestVersion === latestVersion) {
|
|
5095
|
+
return null;
|
|
5096
|
+
}
|
|
5097
|
+
return {
|
|
5098
|
+
packageName,
|
|
5099
|
+
currentVersion,
|
|
5100
|
+
latestVersion
|
|
5101
|
+
};
|
|
5102
|
+
}
|
|
5103
|
+
async function rememberDismissedFetUpdate(latestVersion) {
|
|
5104
|
+
const cache = await readUpdateCheckCache() ?? {
|
|
5105
|
+
latestVersion,
|
|
5106
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
5107
|
+
};
|
|
5108
|
+
await writeUpdateCheckCache({
|
|
5109
|
+
...cache,
|
|
5110
|
+
latestVersion,
|
|
5111
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5112
|
+
dismissedLatestVersion: latestVersion
|
|
5113
|
+
});
|
|
5114
|
+
}
|
|
5115
|
+
function formatFetUpdateWarning(availability, language) {
|
|
5116
|
+
if (language === "en") {
|
|
5117
|
+
return `A newer FET release is available (${availability.currentVersion} -> ${availability.latestVersion}). Run \`fet update\` or choose update when prompted.`;
|
|
5118
|
+
}
|
|
5119
|
+
return `\u68C0\u6D4B\u5230 FET \u6709\u65B0\u7248\u672C\uFF08\u5F53\u524D ${availability.currentVersion}\uFF0C\u6700\u65B0 ${availability.latestVersion}\uFF09\u3002\u53EF\u8FD0\u884C \`fet update\`\uFF0C\u6216\u5728\u63D0\u793A\u65F6\u9009\u62E9\u5347\u7EA7\u3002`;
|
|
5120
|
+
}
|
|
5121
|
+
function cachePath() {
|
|
5122
|
+
const home = process.env.FET_UPDATE_CHECK_CACHE_HOME?.trim() || homedir2();
|
|
5123
|
+
return join21(home, ".fet", "update-check-cache.json");
|
|
5124
|
+
}
|
|
5125
|
+
async function readUpdateCheckCache() {
|
|
5126
|
+
try {
|
|
5127
|
+
const raw = await readFile16(cachePath(), "utf8");
|
|
5128
|
+
const parsed = JSON.parse(raw);
|
|
5129
|
+
if (typeof parsed.latestVersion !== "string" || typeof parsed.checkedAt !== "string") {
|
|
5130
|
+
return null;
|
|
5131
|
+
}
|
|
5132
|
+
return {
|
|
5133
|
+
latestVersion: parsed.latestVersion,
|
|
5134
|
+
checkedAt: parsed.checkedAt,
|
|
5135
|
+
dismissedLatestVersion: typeof parsed.dismissedLatestVersion === "string" ? parsed.dismissedLatestVersion : void 0
|
|
5136
|
+
};
|
|
5137
|
+
} catch {
|
|
5138
|
+
return null;
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
async function writeUpdateCheckCache(cache) {
|
|
5142
|
+
const path = cachePath();
|
|
5143
|
+
await mkdir10(dirname10(path), { recursive: true });
|
|
5144
|
+
await writeFile(path, `${JSON.stringify(cache, null, 2)}
|
|
5145
|
+
`, "utf8");
|
|
5146
|
+
}
|
|
5147
|
+
|
|
5148
|
+
// src/cli/update-check.ts
|
|
5149
|
+
async function handleFetUpdateCheck(ctx) {
|
|
5150
|
+
if (!shouldCheckFetUpdateForCommand(ctx.command)) {
|
|
5151
|
+
return;
|
|
5152
|
+
}
|
|
5153
|
+
const mode = getFetUpdateCheckMode();
|
|
5154
|
+
if (mode === "off") {
|
|
5155
|
+
return;
|
|
5156
|
+
}
|
|
5157
|
+
const availability = await resolveFetUpdateAvailability(ctx.fetVersion);
|
|
5158
|
+
if (!availability) {
|
|
5159
|
+
return;
|
|
5160
|
+
}
|
|
5161
|
+
const warning = formatFetUpdateWarning(availability, ctx.language);
|
|
5162
|
+
ctx.output.warn(warning);
|
|
5163
|
+
const forceConfirm = process.env.FET_UPDATE_CHECK_FORCE_CONFIRM === "1";
|
|
5164
|
+
const interactive = mode === "confirm" && !ctx.json && !ctx.yes && (forceConfirm || process.stdin.isTTY && process.stderr.isTTY);
|
|
5165
|
+
if (!interactive) {
|
|
5166
|
+
return;
|
|
5167
|
+
}
|
|
5168
|
+
const choice = await promptFetUpdateChoice(availability, ctx.language);
|
|
5169
|
+
if (choice === "skip") {
|
|
5170
|
+
await rememberDismissedFetUpdate(availability.latestVersion);
|
|
5171
|
+
return;
|
|
5172
|
+
}
|
|
5173
|
+
if (choice === "cancel") {
|
|
5174
|
+
throw new FetError({
|
|
5175
|
+
code: "USER_CANCELLED" /* UserCancelled */,
|
|
5176
|
+
message: ctx.language === "en" ? "Command cancelled before FET update." : "\u547D\u4EE4\u5DF2\u53D6\u6D88\uFF0C\u672A\u6267\u884C FET \u5347\u7EA7\u3002",
|
|
5177
|
+
details: availability,
|
|
5178
|
+
suggestedCommand: ctx.language === "en" ? `fet update` : "fet update"
|
|
5179
|
+
});
|
|
5180
|
+
}
|
|
5181
|
+
await performFetUpdate(availability.currentVersion, availability.latestVersion, {
|
|
5182
|
+
cwd: ctx.cwd,
|
|
5183
|
+
json: ctx.json,
|
|
5184
|
+
language: ctx.language,
|
|
5185
|
+
info: (message) => ctx.output.info(message)
|
|
5186
|
+
});
|
|
5187
|
+
throw new FetError({
|
|
5188
|
+
code: "USER_CANCELLED" /* UserCancelled */,
|
|
5189
|
+
message: ctx.language === "en" ? `FET updated to ${availability.latestVersion}. Rerun this command to use the new version.` : `FET \u5DF2\u5347\u7EA7\u5230 ${availability.latestVersion}\u3002\u8BF7\u91CD\u65B0\u8FD0\u884C\u5F53\u524D\u547D\u4EE4\u4EE5\u4F7F\u7528\u65B0\u7248\u672C\u3002`,
|
|
5190
|
+
details: availability,
|
|
5191
|
+
suggestedCommand: `fet ${ctx.command}`
|
|
5192
|
+
});
|
|
5193
|
+
}
|
|
5194
|
+
async function promptFetUpdateChoice(availability, language) {
|
|
5195
|
+
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
5196
|
+
try {
|
|
5197
|
+
const question = language === "en" ? `Update FET now (${availability.currentVersion} -> ${availability.latestVersion})? [U]pdate / [S]kip / [C]ancel [s]: ` : `\u662F\u5426\u73B0\u5728\u5347\u7EA7 FET\uFF08${availability.currentVersion} -> ${availability.latestVersion}\uFF09\uFF1F[U]\u5347\u7EA7 / [S]\u8DF3\u8FC7 / [C]\u53D6\u6D88 [s]: `;
|
|
5198
|
+
const answer = (await rl.question(question)).trim().toLowerCase();
|
|
5199
|
+
if (answer === "u" || answer === "update" || answer === "\u5347\u7EA7") {
|
|
5200
|
+
return "update";
|
|
5201
|
+
}
|
|
5202
|
+
if (answer === "c" || answer === "cancel" || answer === "\u53D6\u6D88") {
|
|
5203
|
+
return "cancel";
|
|
5204
|
+
}
|
|
5205
|
+
return "skip";
|
|
5206
|
+
} finally {
|
|
5207
|
+
rl.close();
|
|
5208
|
+
}
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5026
5211
|
// src/cli/index.ts
|
|
5027
5212
|
var program = new Command();
|
|
5028
5213
|
program.name("fet").description("\u56F4\u7ED5 OpenSpec \u7684\u524D\u7AEF\u5F00\u53D1\u5DE5\u4F5C\u6D41\u7F16\u6392\u5DE5\u5177\u3002").enablePositionalOptions().version(FET_VERSION).option("--cwd <path>", "\u6307\u5B9A\u9879\u76EE\u6839\u76EE\u5F55").option("--change <id>", "\u6307\u5B9A OpenSpec change").option("--lang <language>", "\u6307\u5B9A FET \u4EA4\u4E92\u4FE1\u606F\u548C\u751F\u6210\u4EA7\u7269\u8BED\u8A00\uFF0C\u9ED8\u8BA4 zh-CN").option("--yes", "\u5BF9\u4F4E\u98CE\u9669\u786E\u8BA4\u4F7F\u7528\u9ED8\u8BA4\u540C\u610F").option("--json", "\u8F93\u51FA\u673A\u5668\u53EF\u8BFB JSON").option("--verbose", "\u8F93\u51FA\u8BCA\u65AD\u7EC6\u8282").option("--no-color", "\u7981\u7528\u7EC8\u7AEF\u989C\u8272");
|
|
@@ -5066,6 +5251,7 @@ function wrap(command, handler) {
|
|
|
5066
5251
|
const opts = isCommandLike(maybeCommand) ? { ...maybeCommand.parent?.opts(), ...maybeCommand.opts() } : program.opts();
|
|
5067
5252
|
const ctx = await createCommandContext(command, { ...opts, ...extractGlobalOptions(args) });
|
|
5068
5253
|
try {
|
|
5254
|
+
await handleFetUpdateCheck(ctx);
|
|
5069
5255
|
await handleModelPolicyRecommendation(ctx);
|
|
5070
5256
|
await warnIfContextPlaceholdersRemain(ctx);
|
|
5071
5257
|
await handler(ctx, ...args);
|
|
@@ -5087,7 +5273,7 @@ async function handleModelPolicyRecommendation(ctx) {
|
|
|
5087
5273
|
if (policyMode !== "confirm" || ctx.yes || ctx.json || !process.stdin.isTTY || !process.stderr.isTTY) {
|
|
5088
5274
|
return;
|
|
5089
5275
|
}
|
|
5090
|
-
const rl =
|
|
5276
|
+
const rl = createInterface3({ input: process.stdin, output: process.stderr });
|
|
5091
5277
|
try {
|
|
5092
5278
|
const question = ctx.language === "en" ? "Continue anyway? [y/N] " : "\u4ECD\u7136\u7EE7\u7EED\uFF1F[y/N] ";
|
|
5093
5279
|
const answer = (await rl.question(question)).trim().toLowerCase();
|