flavor-code 1.4.0-beta.4 → 1.4.0-beta.6

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,7 @@ import {
10
10
  useStdout,
11
11
  use_app_default,
12
12
  use_input_default
13
- } from "./chunk-IQAZ42TM.js";
13
+ } from "./chunk-XMRKRPNC.js";
14
14
  import "./chunk-ZJCAQXA7.js";
15
15
  import "./chunk-S32JRDZK.js";
16
16
  export {
package/dist/cli-main.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from "node:module"; const require = createRequire(impor
3
3
  import {
4
4
  FlavorRpcServer,
5
5
  TraceRecorder
6
- } from "./chunk-4RR5VVX4.js";
6
+ } from "./chunk-6MXAOTIZ.js";
7
7
  import {
8
8
  staticTaskLines
9
9
  } from "./chunk-2BF7CVWZ.js";
@@ -29,10 +29,10 @@ import {
29
29
  redactErrorText,
30
30
  runDoctor,
31
31
  runPalBroker
32
- } from "./chunk-DCNUBQCH.js";
32
+ } from "./chunk-NLYZ7DMC.js";
33
33
  import {
34
34
  MEMORY_RESTART_EXIT_CODE
35
- } from "./chunk-LKQTBL3R.js";
35
+ } from "./chunk-N5MXHJKD.js";
36
36
  import {
37
37
  McpServerConfigSchema,
38
38
  McpServerNameSchema,
@@ -85,6 +85,25 @@ async function runUpdate(options = {}) {
85
85
  return exitCode === 0 ? { status: "updated", current, latest } : { status: "install-failed", current, latest, exitCode };
86
86
  }
87
87
 
88
+ // src/ui/user-timing.ts
89
+ import { performance } from "perf_hooks";
90
+ function clearUiUserTimingEntries() {
91
+ performance.clearMarks();
92
+ performance.clearMeasures();
93
+ }
94
+ function installUiUserTimingSweeper(intervalMs = 250) {
95
+ if (!Number.isSafeInteger(intervalMs) || intervalMs <= 0) {
96
+ throw new Error("User Timing sweep interval must be a positive integer");
97
+ }
98
+ clearUiUserTimingEntries();
99
+ const timer = setInterval(clearUiUserTimingEntries, intervalMs);
100
+ timer.unref();
101
+ return () => {
102
+ clearInterval(timer);
103
+ clearUiUserTimingEntries();
104
+ };
105
+ }
106
+
88
107
  // src/skills/manager.ts
89
108
  import { lstat, mkdir, readFile, readdir, realpath, rm, writeFile } from "fs/promises";
90
109
  import { homedir } from "os";
@@ -897,17 +916,22 @@ function createProgram(dependencies = {}) {
897
916
  return program;
898
917
  }
899
918
  async function runInteractiveCli(props) {
900
- const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
901
- import("./claude-ink-ECZ6QF3P.js"),
902
- import("react"),
903
- import("./app-UWIEIWBQ.js")
904
- ]);
905
- const instance = await render(createElement(
906
- AlternateScreen,
907
- { mouseTracking: true },
908
- createElement(App, props)
909
- ), { exitOnCtrlC: false });
910
- await instance.waitUntilExit();
919
+ const disposeUserTimingSweeper = installUiUserTimingSweeper();
920
+ try {
921
+ const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
922
+ import("./claude-ink-6EZHF64C.js"),
923
+ import("react"),
924
+ import("./app-6JRSYZYV.js")
925
+ ]);
926
+ const instance = await render(createElement(
927
+ AlternateScreen,
928
+ { mouseTracking: true },
929
+ createElement(App, props)
930
+ ), { exitOnCtrlC: false });
931
+ await instance.waitUntilExit();
932
+ } finally {
933
+ disposeUserTimingSweeper();
934
+ }
911
935
  }
912
936
  function parsePalAlias(value) {
913
937
  const alias = value.trim();
package/dist/cli.js CHANGED
@@ -5,22 +5,24 @@ import {
5
5
  memoryRestartArgs,
6
6
  memoryRestartMarkerPath,
7
7
  parseMemoryRestartMarker
8
- } from "./chunk-LKQTBL3R.js";
8
+ } from "./chunk-N5MXHJKD.js";
9
9
  import "./chunk-S32JRDZK.js";
10
10
 
11
11
  // src/launcher.ts
12
12
  import { spawn } from "child_process";
13
- import { realpathSync, readFileSync } from "fs";
13
+ import { mkdirSync, realpathSync, readFileSync, rmSync } from "fs";
14
14
  import { totalmem } from "os";
15
+ import { join } from "path";
15
16
  import { fileURLToPath } from "url";
16
17
  function needsRelaunch(runtime) {
17
18
  if (!runtime.execArgv.some((argument) => argument === "--report-on-fatalerror")) return true;
18
19
  if (!runtime.execArgv.some((argument) => argument.startsWith("--heapsnapshot-near-heap-limit"))) return true;
20
+ if (!runtime.execArgv.some((argument) => argument === "--heap-prof")) return true;
19
21
  return !runtime.execArgv.some((argument) => argument === "--expose-gc");
20
22
  }
21
23
  var HEAP_HEADROOM_MB = 8192;
22
24
  var HEAP_HEADROOM_MIN_TOTALMEM = 12 * 1024 * 1024 * 1024;
23
- function cliMainArguments(mainPath, argv) {
25
+ function cliMainArguments(mainPath, argv, heapProfile) {
24
26
  const flags = [
25
27
  // Fatal V8 errors (heap OOM, native crashes) bypass crash-guard.ts and
26
28
  // leave only an unusable native stack. Ask Node to dump a diagnostic
@@ -31,11 +33,20 @@ function cliMainArguments(mainPath, argv) {
31
33
  // Capture one heap snapshot as the heap nears its limit so the next
32
34
  // crash leaves a .heapsnapshot retainer trail next to the report.
33
35
  "--heapsnapshot-near-heap-limit=1",
36
+ // A full snapshot is intentionally reserved for a hard OOM. Sparse
37
+ // allocation sampling has much lower overhead and still records the
38
+ // allocating call stacks responsible for a controlled watermark
39
+ // restart, where --heapsnapshot-near-heap-limit never fires.
40
+ "--heap-prof",
41
+ "--heap-prof-interval=1048576",
34
42
  // The heap watermarks are GC-verified: heapUsed counts uncollected
35
43
  // garbage, and stopping turns or rotating on garbage alone would waste
36
44
  // work. Exposing gc lets the watermark measure the live set instead.
37
45
  "--expose-gc"
38
46
  ];
47
+ if (heapProfile !== void 0) {
48
+ flags.push(`--heap-prof-dir=${heapProfile.directory}`, `--heap-prof-name=${heapProfile.name}`);
49
+ }
39
50
  const processHeapFlag = process.execArgv.find((argument) => argument.startsWith("--max-old-space-size"));
40
51
  const argvHeapFlag = argv.find((argument) => argument.startsWith("--max-old-space-size"));
41
52
  const userHeapFlag = processHeapFlag ?? argvHeapFlag;
@@ -62,8 +73,19 @@ async function launchCli() {
62
73
  }
63
74
  const mainPath = fileURLToPath(mainUrl);
64
75
  let argv = process.argv.slice(2);
76
+ let childSequence = 0;
65
77
  for (; ; ) {
66
- const code = await spawnAndWait(mainPath, argv);
78
+ const profileDirectory = join(process.cwd(), ".flavor", "tmp");
79
+ mkdirSync(profileDirectory, { recursive: true });
80
+ const profileName = `heap-profile-${Date.now()}-${process.pid}-${childSequence++}.heapprofile`;
81
+ const profilePath = join(profileDirectory, profileName);
82
+ const code = await spawnAndWait(mainPath, argv, { directory: profileDirectory, name: profileName });
83
+ if (code === 0) {
84
+ rmSync(profilePath, { force: true });
85
+ } else {
86
+ process.stderr.write(`flavor launcher: retained allocation profile ${profilePath}
87
+ `);
88
+ }
67
89
  if (code === MEMORY_RESTART_EXIT_CODE) {
68
90
  let marker;
69
91
  try {
@@ -86,8 +108,11 @@ async function launchCli() {
86
108
  return;
87
109
  }
88
110
  }
89
- async function spawnAndWait(mainPath, argv) {
90
- const child = spawn(process.execPath, cliMainArguments(mainPath, argv), { stdio: "inherit" });
111
+ async function spawnAndWait(mainPath, argv, heapProfile) {
112
+ const child = spawn(process.execPath, cliMainArguments(mainPath, argv, heapProfile), {
113
+ stdio: "inherit",
114
+ env: { ...process.env, NODE_ENV: "production" }
115
+ });
91
116
  const ignoreSignal = () => {
92
117
  };
93
118
  process.on("SIGINT", ignoreSignal);