flavor-code 1.3.18 → 1.3.20

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.
@@ -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
@@ -3,10 +3,12 @@ import { createRequire } from "node:module"; const require = createRequire(impor
3
3
  import {
4
4
  FlavorRpcServer,
5
5
  TraceRecorder
6
- } from "./chunk-6LDYDQ3P.js";
6
+ } from "./chunk-VEUSROUQ.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,
@@ -19,11 +21,13 @@ import {
19
21
  createProductionRuntime,
20
22
  executeShell,
21
23
  initializeFlavor,
24
+ installCrashGuard,
22
25
  message,
23
26
  packageVersion,
27
+ prepareSpawnInvocation,
24
28
  redactErrorText,
25
29
  runPalBroker
26
- } from "./chunk-PF457XCH.js";
30
+ } from "./chunk-Z62P4LL7.js";
27
31
  import "./chunk-CIVPKHF4.js";
28
32
  import {
29
33
  McpServerConfigSchema,
@@ -33,7 +37,11 @@ import {
33
37
  readRecoverableFile,
34
38
  setProjectSkillDisabled,
35
39
  updateProtectedFile
36
- } from "./chunk-HJOCNKPN.js";
40
+ } from "./chunk-RPFWB45Y.js";
41
+ import {
42
+ gt,
43
+ isValidVersion
44
+ } from "./chunk-OTYFL4AG.js";
37
45
  import "./chunk-RQTYHUMK.js";
38
46
  import "./chunk-S32JRDZK.js";
39
47
 
@@ -45,71 +53,39 @@ import { posix, resolve as resolve3 } from "path";
45
53
  import { fileURLToPath } from "url";
46
54
  import { Command, Option } from "commander";
47
55
 
48
- // src/utils/crash-guard.ts
49
- import { mkdirSync, writeFileSync } from "fs";
50
- import { join } from "path";
51
- var installed = false;
52
- function installCrashGuard(options = {}) {
53
- if (installed) return;
54
- installed = true;
55
- const crashLogDir = () => {
56
- try {
57
- return join((options.workspace ?? process.cwd)(), ".flavor");
58
- } catch {
59
- return process.cwd();
60
- }
61
- };
62
- const writeCrashLog = (kind, detail) => {
63
- try {
64
- const dir = crashLogDir();
65
- mkdirSync(dir, { recursive: true });
66
- const path = join(dir, `crash-${(/* @__PURE__ */ new Date()).toISOString().replace(/[^0-9]/g, "")}-${process.pid}.log`);
67
- writeFileSync(path, [
68
- `kind: ${kind}`,
69
- `version: ${process.version}`,
70
- `platform: ${process.platform}`,
71
- `time: ${(/* @__PURE__ */ new Date()).toISOString()}`,
72
- "",
73
- detail
74
- ].join("\n"), { encoding: "utf8", mode: 384 });
75
- return path;
76
- } catch {
77
- return void 0;
78
- }
79
- };
80
- const restoreTerminal = () => {
81
- try {
82
- if (process.stdout.isTTY === true) process.stdout.write("\x1B[?25h\x1B[?1049l");
83
- } catch {
84
- }
85
- };
86
- const describe = (reason) => {
87
- if (reason instanceof Error) return `${reason.name}: ${reason.message}
88
- ${reason.stack ?? ""}`;
89
- return String(reason);
90
- };
91
- const crash = (kind, reason) => {
92
- const detail = describe(reason);
93
- const logPath = writeCrashLog(kind, detail);
94
- restoreTerminal();
95
- try {
96
- const safe = redactErrorText(detail.split("\n").slice(0, 3).join("\n"));
97
- process.stderr.write(`flavor crashed (${kind}): ${safe}
98
- `);
99
- if (logPath !== void 0) process.stderr.write(`crash log: ${logPath}
100
- `);
101
- } catch {
102
- }
103
- process.exit(1);
104
- };
105
- process.on("unhandledRejection", (reason) => crash("unhandledRejection", reason));
106
- process.on("uncaughtException", (error) => crash("uncaughtException", error));
56
+ // src/update/apply.ts
57
+ import { spawn } from "child_process";
58
+ function npmExecutable(platform = process.platform) {
59
+ return platform === "win32" ? "npm.cmd" : "npm";
60
+ }
61
+ var defaultInstall = (command, args) => new Promise((resolve4, reject) => {
62
+ const invocation = prepareSpawnInvocation(command, args);
63
+ const child = spawn(invocation.command, invocation.args, {
64
+ stdio: "inherit",
65
+ ...invocation.windowsVerbatimArguments === void 0 ? {} : { windowsVerbatimArguments: invocation.windowsVerbatimArguments }
66
+ });
67
+ child.on("error", reject);
68
+ child.on("close", (code) => resolve4(code));
69
+ });
70
+ async function runUpdate(options = {}) {
71
+ const current = options.current ?? packageVersion();
72
+ const latest = await fetchLatestVersion(options);
73
+ if (latest === void 0 || !isValidVersion(latest)) return { status: "check-failed", current };
74
+ if (!gt(latest, current)) return { status: "up-to-date", current, latest };
75
+ const install = options.install ?? defaultInstall;
76
+ let exitCode;
77
+ try {
78
+ exitCode = await install(npmExecutable(options.platform), ["install", "-g", `${NPM_PACKAGE_NAME}@${latest}`]);
79
+ } catch {
80
+ exitCode = null;
81
+ }
82
+ return exitCode === 0 ? { status: "updated", current, latest } : { status: "install-failed", current, latest, exitCode };
107
83
  }
108
84
 
109
85
  // src/skills/manager.ts
110
86
  import { lstat, mkdir, readFile, readdir, realpath, rm, writeFile } from "fs/promises";
111
87
  import { homedir } from "os";
112
- import { isAbsolute, join as join2, relative, resolve, sep } from "path";
88
+ import { isAbsolute, join, relative, resolve, sep } from "path";
113
89
  import { stringify } from "yaml";
114
90
  var SkillManager = class {
115
91
  #workspace;
@@ -132,7 +108,7 @@ var SkillManager = class {
132
108
  async create(draft) {
133
109
  const value = parseDraft(draft);
134
110
  const projectRoot = this.#projectRoot();
135
- const directory = join2(projectRoot, value.name);
111
+ const directory = join(projectRoot, value.name);
136
112
  await mkdir(projectRoot, { recursive: true, mode: 448 });
137
113
  try {
138
114
  await mkdir(directory, { mode: 448 });
@@ -141,7 +117,7 @@ var SkillManager = class {
141
117
  throw error;
142
118
  }
143
119
  try {
144
- await writeFile(join2(directory, "SKILL.md"), renderSkill(value), { encoding: "utf8", flag: "wx", mode: 384 });
120
+ await writeFile(join(directory, "SKILL.md"), renderSkill(value), { encoding: "utf8", flag: "wx", mode: 384 });
145
121
  await this.#persistEnabled(value.name, true);
146
122
  return this.get(value.name);
147
123
  } catch (error) {
@@ -159,7 +135,7 @@ var SkillManager = class {
159
135
  throw error;
160
136
  });
161
137
  if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`Project skill path is not a real directory: ${validName}`);
162
- const skillFile = join2(directory, "SKILL.md");
138
+ const skillFile = join(directory, "SKILL.md");
163
139
  const fileInfo = await lstat(skillFile);
164
140
  if (!fileInfo.isFile() || fileInfo.isSymbolicLink()) throw new Error(`Project skill file is not a real file: ${validName}`);
165
141
  await writeFile(skillFile, renderSkill(value), { encoding: "utf8", mode: 384 });
@@ -191,12 +167,12 @@ var SkillManager = class {
191
167
  async #registry() {
192
168
  const loaded = await loadConfig({ cwd: this.#workspace, home: this.#home });
193
169
  const [globalPluginRoots, projectPluginRoots] = await Promise.all([
194
- discoverPluginSkillRoots(join2(this.#home, ".flavor-code", "plugins")),
195
- discoverPluginSkillRoots(join2(this.#workspace, ".flavor", "plugins"))
170
+ discoverPluginSkillRoots(join(this.#home, ".flavor-code", "plugins")),
171
+ discoverPluginSkillRoots(join(this.#workspace, ".flavor", "plugins"))
196
172
  ]);
197
173
  return {
198
174
  registry: new SkillRegistry({
199
- globalRoots: [join2(this.#home, ".flavor-code", "skills"), ...globalPluginRoots],
175
+ globalRoots: [join(this.#home, ".flavor-code", "skills"), ...globalPluginRoots],
200
176
  projectRoots: [this.#projectRoot(), ...projectPluginRoots]
201
177
  }),
202
178
  disabled: new Set(loaded.config.skills.disabled)
@@ -212,10 +188,10 @@ var SkillManager = class {
212
188
  };
213
189
  }
214
190
  #projectRoot() {
215
- return join2(this.#workspace, ".flavor", "skills");
191
+ return join(this.#workspace, ".flavor", "skills");
216
192
  }
217
193
  #projectSkillDirectory(name) {
218
- return join2(this.#projectRoot(), name);
194
+ return join(this.#projectRoot(), name);
219
195
  }
220
196
  };
221
197
  function parseName(value) {
@@ -256,9 +232,9 @@ async function discoverPluginSkillRoots(directory) {
256
232
  const roots = [];
257
233
  for (const entry of entries) {
258
234
  if (!entry.isDirectory() || entry.isSymbolicLink()) continue;
259
- const pluginRoot = await realpath(join2(directory, entry.name));
235
+ const pluginRoot = await realpath(join(directory, entry.name));
260
236
  try {
261
- const manifest = PluginManifestSchema.parse(JSON.parse(await readFile(join2(pluginRoot, "flavor-plugin.json"), "utf8")));
237
+ const manifest = PluginManifestSchema.parse(JSON.parse(await readFile(join(pluginRoot, "flavor-plugin.json"), "utf8")));
262
238
  for (const contribution of manifest.contributes.skillRoots) {
263
239
  const candidate = resolve(pluginRoot, contribution.path);
264
240
  const info = await lstat(candidate);
@@ -390,11 +366,11 @@ function parseMemoryType(value) {
390
366
  }
391
367
 
392
368
  // src/mcp/config-manager.ts
393
- import { join as join3 } from "path";
369
+ import { join as join2 } from "path";
394
370
  var ProjectMcpConfigManager = class {
395
371
  path;
396
372
  constructor(workspace) {
397
- this.path = join3(workspace, ".flavor", "flavor.json");
373
+ this.path = join2(workspace, ".flavor", "flavor.json");
398
374
  }
399
375
  async list() {
400
376
  const document = await readRecoverableFile(this.path, (raw) => parseDocument(this.path, raw));
@@ -751,7 +727,7 @@ async function runEvaluationFile(path, outputPath) {
751
727
  })),
752
728
  ...parsed.maxTokens === void 0 ? {} : { maxTokens: parsed.maxTokens }
753
729
  };
754
- const configured = await import("./load-DELQW42K.js").then(({ loadConfig: loadConfig2 }) => loadConfig2({ cwd: workspace, home: process.env.USERPROFILE ?? process.env.HOME ?? workspace }));
730
+ const configured = await import("./load-4FWNXE6F.js").then(({ loadConfig: loadConfig2 }) => loadConfig2({ cwd: workspace, home: process.env.USERPROFILE ?? process.env.HOME ?? workspace }));
755
731
  const environment = createExecutionEnvironment(workspace, configured.config.execution) ?? new LocalExecutionEnvironment();
756
732
  let report;
757
733
  try {
@@ -784,6 +760,34 @@ function createProgram(dependencies = {}) {
784
760
  `);
785
761
  } catch (error) {
786
762
  process.stderr.write(`init: ${safeError(error)}
763
+ `);
764
+ process.exitCode = 1;
765
+ }
766
+ });
767
+ program.command("update").description(`Update the globally installed ${NPM_PACKAGE_NAME} to the latest npm release`).action(async () => {
768
+ try {
769
+ const outcome = await (dependencies.runUpdate ?? runUpdate)();
770
+ switch (outcome.status) {
771
+ case "up-to-date":
772
+ process.stdout.write(`${NPM_PACKAGE_NAME} is already up to date (v${outcome.current}).
773
+ `);
774
+ break;
775
+ case "updated":
776
+ process.stdout.write(`Updated ${NPM_PACKAGE_NAME} v${outcome.current} \u2192 v${outcome.latest}. Restart flavor to use it.
777
+ `);
778
+ break;
779
+ case "check-failed":
780
+ process.stderr.write("update: could not reach the npm registry to determine the latest version.\n");
781
+ process.exitCode = 1;
782
+ break;
783
+ case "install-failed":
784
+ 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}
785
+ `);
786
+ process.exitCode = 1;
787
+ break;
788
+ }
789
+ } catch (error) {
790
+ process.stderr.write(`update: ${safeError(error)}
787
791
  `);
788
792
  process.exitCode = 1;
789
793
  }
@@ -876,9 +880,9 @@ function createProgram(dependencies = {}) {
876
880
  }
877
881
  async function runInteractiveCli(props) {
878
882
  const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
879
- import("./claude-ink-AUZBJ3BE.js"),
883
+ import("./claude-ink-3K3NG7BF.js"),
880
884
  import("react"),
881
- import("./app-LKK5RBTO.js")
885
+ import("./app-EGG3BYQQ.js")
882
886
  ]);
883
887
  const instance = await render(createElement(
884
888
  AlternateScreen,
@@ -124,7 +124,7 @@ export declare const FlavorConfigSchema: z.ZodObject<{
124
124
  autoStoreThreshold: z.ZodDefault<z.ZodNumber>;
125
125
  ignoreStreakLimit: z.ZodDefault<z.ZodNumber>;
126
126
  reviewAutoDismissSeconds: z.ZodDefault<z.ZodNumber>;
127
- maxCandidatesPerTask: z.ZodDefault<z.ZodNumber>;
127
+ maxCandidatesPerTask: z.ZodDefault<z.ZodLiteral<1>>;
128
128
  retrievalTopK: z.ZodDefault<z.ZodNumber>;
129
129
  maxEntries: z.ZodDefault<z.ZodNumber>;
130
130
  maxEntryChars: z.ZodDefault<z.ZodNumber>;