flavor-code 1.3.18 → 1.3.19

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 CHANGED
@@ -75,6 +75,14 @@ flavor --resume -p "Continue the remaining work"
75
75
 
76
76
  Non-interactive mode refuses actions that require human approval and never hangs waiting for input.
77
77
 
78
+ **4. Staying up to date**
79
+
80
+ ```bash
81
+ flavor update
82
+ ```
83
+
84
+ Flavor checks the npm registry at startup and shows an update hint on the welcome card. Run `flavor update` to upgrade the global install to the latest release, then restart Flavor.
85
+
78
86
  ## Configuring Models
79
87
 
80
88
  The fastest way is to set environment variables:
package/README.zh-CN.md CHANGED
@@ -75,6 +75,14 @@ flavor --resume -p "继续完成剩余工作"
75
75
 
76
76
  非交互模式会拒绝需要人工审批的操作,不会悬挂等待输入。
77
77
 
78
+ **4. 保持更新**
79
+
80
+ ```bash
81
+ flavor update
82
+ ```
83
+
84
+ Flavor 启动时会检查 npm registry,有新版本时在欢迎卡片中提示;运行 `flavor update` 即可一键升级到最新发行版,升级后重启 Flavor 生效。
85
+
78
86
  ## 配置模型
79
87
 
80
88
  最快的方式是设置环境变量:
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
3
3
  import {
4
+ checkForUpdate,
4
5
  statusPresentation
5
- } from "./chunk-2BF7CVWZ.js";
6
+ } from "./chunk-7OICVL2M.js";
6
7
  import {
7
8
  COMMAND_DESCRIPTIONS,
8
9
  MVP_COMMANDS,
@@ -30,16 +31,15 @@ import {
30
31
  TerminalSizeContext,
31
32
  TerminalWriteContext,
32
33
  Text,
33
- gt,
34
34
  instances_default,
35
- isValidVersion,
36
35
  osc,
37
36
  shiftAnchor,
38
37
  stripAnsi,
39
38
  useStdout,
40
39
  use_app_default,
41
40
  use_input_default
42
- } from "./chunk-36UKDXPF.js";
41
+ } from "./chunk-3HWWQV2A.js";
42
+ import "./chunk-OTYFL4AG.js";
43
43
  import {
44
44
  execFileNoThrow
45
45
  } from "./chunk-RQTYHUMK.js";
@@ -1310,41 +1310,6 @@ function comparePaths(left, right) {
1310
1310
  return left.localeCompare(right, "en");
1311
1311
  }
1312
1312
 
1313
- // src/update/check.ts
1314
- var NPM_PACKAGE_NAME = "flavor-code";
1315
- var REGISTRY_LATEST_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
1316
- var DEFAULT_TIMEOUT_MS = 3e3;
1317
- function findNewerVersion(current, latest) {
1318
- if (!isValidVersion(current) || !isValidVersion(latest)) return void 0;
1319
- return gt(latest, current) ? latest : void 0;
1320
- }
1321
- async function fetchLatestVersion(options = {}) {
1322
- const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1323
- const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
1324
- let timer;
1325
- const timeout = new Promise((resolve2) => {
1326
- timer = setTimeout(() => resolve2(void 0), timeoutMs);
1327
- timer.unref?.();
1328
- });
1329
- try {
1330
- const response = await Promise.race([
1331
- fetchImpl(REGISTRY_LATEST_URL, { signal: AbortSignal.timeout(timeoutMs) }),
1332
- timeout
1333
- ]);
1334
- if (response === void 0 || !response.ok) return void 0;
1335
- const body = await Promise.race([response.json(), timeout]);
1336
- return typeof body?.version === "string" ? body.version : void 0;
1337
- } catch {
1338
- return void 0;
1339
- } finally {
1340
- if (timer !== void 0) clearTimeout(timer);
1341
- }
1342
- }
1343
- async function checkForUpdate(current, options = {}) {
1344
- const latest = await fetchLatestVersion(options);
1345
- return latest === void 0 ? void 0 : findNewerVersion(current, latest);
1346
- }
1347
-
1348
1313
  // src/ui/welcome.tsx
1349
1314
  import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1350
1315
  var WIDE_WELCOME_COLUMNS = 72;
@@ -1362,7 +1327,7 @@ function WelcomeCard({
1362
1327
  columns
1363
1328
  }) {
1364
1329
  const wide = Math.max(1, Math.floor(columns)) >= WIDE_WELCOME_COLUMNS;
1365
- const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ jsxs3(Text, { color: "yellow", wrap: "truncate-end", children: [
1330
+ const updateHint = updateTo === void 0 ? null : /* @__PURE__ */ jsxs3(Text, { color: "yellowBright", wrap: "truncate-end", children: [
1366
1331
  "\u25B2 ",
1367
1332
  "Update available: v",
1368
1333
  packageVersion(),
@@ -1370,8 +1335,7 @@ function WelcomeCard({
1370
1335
  "\u2192",
1371
1336
  " v",
1372
1337
  updateTo,
1373
- " \xB7 npm i -g ",
1374
- NPM_PACKAGE_NAME
1338
+ " \xB7 run: flavor update"
1375
1339
  ] });
1376
1340
  return /* @__PURE__ */ jsx4(Box_default, { width: "100%", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: wide ? /* @__PURE__ */ jsxs3(Box_default, { width: "100%", flexDirection: "row", children: [
1377
1341
  /* @__PURE__ */ jsxs3(
@@ -28547,15 +28547,6 @@ function terminalName() {
28547
28547
  }
28548
28548
  var env = { terminal: terminalName() };
28549
28549
 
28550
- // src/utils/semver.ts
28551
- import { gt as semverGt, gte as semverGte, valid as semverValid } from "semver";
28552
- function gt(a, b) {
28553
- return semverGt(a, b, { loose: true });
28554
- }
28555
- function isValidVersion(value) {
28556
- return semverValid(value, { loose: true }) !== null;
28557
- }
28558
-
28559
28550
  // src/claude-ink/clearTerminal.ts
28560
28551
  var CURSOR_HOME_WINDOWS = csi(0, "f");
28561
28552
  function isWindowsTerminal() {
@@ -35495,8 +35486,6 @@ export {
35495
35486
  stripAnsi,
35496
35487
  ScrollBox_default,
35497
35488
  instances_default,
35498
- gt,
35499
- isValidVersion,
35500
35489
  osc,
35501
35490
  OSC2 as OSC,
35502
35491
  TerminalWriteContext,
@@ -1,5 +1,44 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
3
+ import {
4
+ gt,
5
+ isValidVersion
6
+ } from "./chunk-OTYFL4AG.js";
7
+
8
+ // src/update/check.ts
9
+ var NPM_PACKAGE_NAME = "flavor-code";
10
+ var REGISTRY_LATEST_URL = `https://registry.npmjs.org/${NPM_PACKAGE_NAME}/latest`;
11
+ var DEFAULT_TIMEOUT_MS = 3e3;
12
+ function findNewerVersion(current, latest) {
13
+ if (!isValidVersion(current) || !isValidVersion(latest)) return void 0;
14
+ return gt(latest, current) ? latest : void 0;
15
+ }
16
+ async function fetchLatestVersion(options = {}) {
17
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
18
+ const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
19
+ let timer;
20
+ const timeout = new Promise((resolve) => {
21
+ timer = setTimeout(() => resolve(void 0), timeoutMs);
22
+ timer.unref?.();
23
+ });
24
+ try {
25
+ const response = await Promise.race([
26
+ fetchImpl(REGISTRY_LATEST_URL, { signal: AbortSignal.timeout(timeoutMs) }),
27
+ timeout
28
+ ]);
29
+ if (response === void 0 || !response.ok) return void 0;
30
+ const body = await Promise.race([response.json(), timeout]);
31
+ return typeof body?.version === "string" ? body.version : void 0;
32
+ } catch {
33
+ return void 0;
34
+ } finally {
35
+ if (timer !== void 0) clearTimeout(timer);
36
+ }
37
+ }
38
+ async function checkForUpdate(current, options = {}) {
39
+ const latest = await fetchLatestVersion(options);
40
+ return latest === void 0 ? void 0 : findNewerVersion(current, latest);
41
+ }
3
42
 
4
43
  // src/ui/task-progress-model.ts
5
44
  var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
@@ -116,6 +155,9 @@ function stripSubagentPrefix(text, isSubagent) {
116
155
  }
117
156
 
118
157
  export {
158
+ NPM_PACKAGE_NAME,
159
+ fetchLatestVersion,
160
+ checkForUpdate,
119
161
  staticTaskLines,
120
162
  statusPresentation
121
163
  };
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire } from "node:module"; const require = createRequire(import.meta.url);
3
+
4
+ // src/utils/semver.ts
5
+ import { gt as semverGt, gte as semverGte, valid as semverValid } from "semver";
6
+ function gt(a, b) {
7
+ return semverGt(a, b, { loose: true });
8
+ }
9
+ function isValidVersion(value) {
10
+ return semverValid(value, { loose: true }) !== null;
11
+ }
12
+
13
+ export {
14
+ gt,
15
+ isValidVersion
16
+ };
@@ -10,7 +10,8 @@ import {
10
10
  useStdout,
11
11
  use_app_default,
12
12
  use_input_default
13
- } from "./chunk-36UKDXPF.js";
13
+ } from "./chunk-3HWWQV2A.js";
14
+ import "./chunk-OTYFL4AG.js";
14
15
  import "./chunk-RQTYHUMK.js";
15
16
  import "./chunk-S32JRDZK.js";
16
17
  export {
package/dist/cli-main.js CHANGED
@@ -5,8 +5,10 @@ import {
5
5
  TraceRecorder
6
6
  } from "./chunk-6LDYDQ3P.js";
7
7
  import {
8
+ NPM_PACKAGE_NAME,
9
+ fetchLatestVersion,
8
10
  staticTaskLines
9
- } from "./chunk-2BF7CVWZ.js";
11
+ } from "./chunk-7OICVL2M.js";
10
12
  import {
11
13
  DEFAULT_MAX_OUTPUT_BYTES,
12
14
  MAX_ALIAS_LENGTH,
@@ -34,6 +36,10 @@ import {
34
36
  setProjectSkillDisabled,
35
37
  updateProtectedFile
36
38
  } from "./chunk-HJOCNKPN.js";
39
+ import {
40
+ gt,
41
+ isValidVersion
42
+ } from "./chunk-OTYFL4AG.js";
37
43
  import "./chunk-RQTYHUMK.js";
38
44
  import "./chunk-S32JRDZK.js";
39
45
 
@@ -45,6 +51,31 @@ import { posix, resolve as resolve3 } from "path";
45
51
  import { fileURLToPath } from "url";
46
52
  import { Command, Option } from "commander";
47
53
 
54
+ // src/update/apply.ts
55
+ import { spawn } from "child_process";
56
+ function npmExecutable(platform = process.platform) {
57
+ return platform === "win32" ? "npm.cmd" : "npm";
58
+ }
59
+ var defaultInstall = (command, args) => new Promise((resolve4, reject) => {
60
+ const child = spawn(command, args, { stdio: "inherit" });
61
+ child.on("error", reject);
62
+ child.on("close", (code) => resolve4(code));
63
+ });
64
+ async function runUpdate(options = {}) {
65
+ const current = options.current ?? packageVersion();
66
+ const latest = await fetchLatestVersion(options);
67
+ if (latest === void 0 || !isValidVersion(latest)) return { status: "check-failed", current };
68
+ if (!gt(latest, current)) return { status: "up-to-date", current, latest };
69
+ const install = options.install ?? defaultInstall;
70
+ let exitCode;
71
+ try {
72
+ exitCode = await install(npmExecutable(options.platform), ["install", "-g", `${NPM_PACKAGE_NAME}@${latest}`]);
73
+ } catch {
74
+ exitCode = null;
75
+ }
76
+ return exitCode === 0 ? { status: "updated", current, latest } : { status: "install-failed", current, latest, exitCode };
77
+ }
78
+
48
79
  // src/utils/crash-guard.ts
49
80
  import { mkdirSync, writeFileSync } from "fs";
50
81
  import { join } from "path";
@@ -784,6 +815,34 @@ function createProgram(dependencies = {}) {
784
815
  `);
785
816
  } catch (error) {
786
817
  process.stderr.write(`init: ${safeError(error)}
818
+ `);
819
+ process.exitCode = 1;
820
+ }
821
+ });
822
+ program.command("update").description(`Update the globally installed ${NPM_PACKAGE_NAME} to the latest npm release`).action(async () => {
823
+ try {
824
+ const outcome = await (dependencies.runUpdate ?? runUpdate)();
825
+ switch (outcome.status) {
826
+ case "up-to-date":
827
+ process.stdout.write(`${NPM_PACKAGE_NAME} is already up to date (v${outcome.current}).
828
+ `);
829
+ break;
830
+ case "updated":
831
+ process.stdout.write(`Updated ${NPM_PACKAGE_NAME} v${outcome.current} \u2192 v${outcome.latest}. Restart flavor to use it.
832
+ `);
833
+ break;
834
+ case "check-failed":
835
+ process.stderr.write("update: could not reach the npm registry to determine the latest version.\n");
836
+ process.exitCode = 1;
837
+ break;
838
+ case "install-failed":
839
+ process.stderr.write(`update: npm install failed${outcome.exitCode === null ? " (npm could not be started)" : ` with exit code ${outcome.exitCode}`}. Install manually with: npm i -g ${NPM_PACKAGE_NAME}
840
+ `);
841
+ process.exitCode = 1;
842
+ break;
843
+ }
844
+ } catch (error) {
845
+ process.stderr.write(`update: ${safeError(error)}
787
846
  `);
788
847
  process.exitCode = 1;
789
848
  }
@@ -876,9 +935,9 @@ function createProgram(dependencies = {}) {
876
935
  }
877
936
  async function runInteractiveCli(props) {
878
937
  const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
879
- import("./claude-ink-AUZBJ3BE.js"),
938
+ import("./claude-ink-3K3NG7BF.js"),
880
939
  import("react"),
881
- import("./app-LKK5RBTO.js")
940
+ import("./app-EVMUBQRE.js")
882
941
  ]);
883
942
  const instance = await render(createElement(
884
943
  AlternateScreen,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flavor-code",
3
- "version": "1.3.18",
3
+ "version": "1.3.19",
4
4
  "author": "YachuanWzh",
5
5
  "type": "module",
6
6
  "publishConfig": {