flavor-code 1.3.2 → 1.3.3

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
@@ -252,10 +252,10 @@ flavor mcp disable docs
252
252
 
253
253
  A Skill is a `SKILL.md` with YAML frontmatter, placed in `.flavor/skills/<name>/` or `~/.flavor-code/skills/<name>/`. Flavor loads skills progressively based on the task, and you can invoke one explicitly with `/<skill-name>`. Skill bodies support `$ARGUMENTS`, `$ARGUMENTS[N]`, and `$N` substitutions. A running composite Skill can load a dependency through the read-only `Skill` tool; plugin-qualified names such as `superharness:test-driven-development` resolve to discovered skills.
254
254
 
255
- Plugins live in `.flavor/plugins/` and can register commands, tools, hooks, Skill roots, and model adapters. `additionalContext` returned by `SessionStart` and `UserPromptSubmit` hooks is added to the current task context, enabling reliable project-level engineering policy injection. Production plugin activation is isolated in a Worker/vm realm by default and records a content fingerprint plus declared capabilities.
255
+ Plugins live in `.flavor/plugins/` and can register commands, tools, hooks, Skill roots, and model adapters. `additionalContext` returned by `SessionStart` and `UserPromptSubmit` hooks is added to the current task context, enabling reliable project-level engineering policy injection. Plugin loads record a content fingerprint plus declared capabilities. Worker/vm isolation is available through the embedding API's `pluginSandbox: true` option; the compatibility default remains in-process because bundled and existing plugins use Node.js APIs that the isolated runtime does not yet mediate.
256
256
 
257
257
  > [!WARNING]
258
- > Sandboxing reduces ambient access but does not make untrusted instructions safe. Only install and enable plugins you trust; legacy `pluginSandbox: false` activation grants full in-process Node.js access.
258
+ > The default in-process plugin runtime grants full Node.js access. Only install and enable plugins you trust. Sandboxing reduces ambient access but does not make untrusted instructions safe, and plugins that import Node.js built-ins will not load with `pluginSandbox: true` yet.
259
259
 
260
260
  ## Sessions, Memory & Execution Records
261
261
 
package/README.zh-CN.md CHANGED
@@ -252,10 +252,10 @@ flavor mcp disable docs
252
252
 
253
253
  Skill 是带有 YAML 头信息的 `SKILL.md`,放在 `.flavor/skills/<name>/` 或 `~/.flavor-code/skills/<name>/`。Flavor 会按任务渐进加载,也支持通过 `/<skill-name>` 显式调用。Skill 正文支持 `$ARGUMENTS`、`$ARGUMENTS[N]` 和 `$N` 参数占位符;运行中的组合 Skill 可以使用只读 `Skill` 工具继续加载依赖 Skill,插件限定名称(如 `superharness:test-driven-development`)会安全解析到已发现的 Skill。
254
254
 
255
- 插件放在 `.flavor/plugins/`,可以注册命令、工具、Hook、Skill 根目录和模型适配器。`SessionStart` 与 `UserPromptSubmit` Hook 返回的 `additionalContext` 会进入当前任务上下文,可用于注入项目级工程规则。产品运行时默认在 Worker/vm 隔离环境激活插件,并记录内容指纹与声明的能力。
255
+ 插件放在 `.flavor/plugins/`,可以注册命令、工具、Hook、Skill 根目录和模型适配器。`SessionStart` 与 `UserPromptSubmit` Hook 返回的 `additionalContext` 会进入当前任务上下文,可用于注入项目级工程规则。插件加载会记录内容指纹与声明的能力。可通过嵌入 API 的 `pluginSandbox: true` 启用 Worker/vm 隔离;由于内置插件和已有插件依赖沙箱尚未代理的 Node.js API,当前兼容默认值仍为进程内运行。
256
256
 
257
257
  > [!WARNING]
258
- > 沙箱会降低环境权限,但不能让不可信指令自动变安全。只安装和启用可信插件;旧版兼容选项 `pluginSandbox: false` 会授予完整的进程内 Node.js 权限。
258
+ > 默认的进程内插件运行时拥有完整 Node.js 权限,只安装和启用你信任的插件。沙箱会降低环境权限,但不能让不可信指令自动变安全;目前导入 Node.js 内置模块的插件在 `pluginSandbox: true` 下仍无法加载。
259
259
 
260
260
  ## 会话、记忆与执行记录
261
261
 
@@ -16,7 +16,7 @@ import {
16
16
  redactErrorText,
17
17
  transcriptReducer,
18
18
  withTimeout
19
- } from "./chunk-Q5EQ4T3F.js";
19
+ } from "./chunk-YY5H6GFN.js";
20
20
  import "./chunk-IG4Z23CL.js";
21
21
  import {
22
22
  Box_default,
@@ -4,7 +4,7 @@ import {
4
4
  message,
5
5
  redactErrorText,
6
6
  redactSecrets
7
- } from "./chunk-Q5EQ4T3F.js";
7
+ } from "./chunk-YY5H6GFN.js";
8
8
 
9
9
  // src/rpc/server.ts
10
10
  import { createInterface } from "readline";
@@ -561,7 +561,7 @@ function redactSecrets(input, secrets) {
561
561
 
562
562
  // src/init/project.ts
563
563
  import { lstat, mkdir, readdir, readFile, realpath, writeFile } from "fs/promises";
564
- import { copyFileSync, mkdirSync, readdirSync, readFileSync } from "fs";
564
+ import { copyFileSync, mkdirSync, readdirSync } from "fs";
565
565
  import { basename, dirname as dirname2, isAbsolute as isAbsolute2, join, relative as relative2, sep as sep2 } from "path";
566
566
  import { fileURLToPath } from "url";
567
567
  var GENERATED_START = "<!-- flavor-code:start -->";
@@ -1014,22 +1014,6 @@ async function createExampleFlavorConfig(cwd) {
1014
1014
  };
1015
1015
  await writeFile(configPath, JSON.stringify(example, null, 2) + "\n");
1016
1016
  }
1017
- var CODEISLAND_SRC_DIR = join(dirname2(fileURLToPath(import.meta.url)), "codeisland");
1018
- var CODEISLAND_FILES = ["flavor-plugin.json", "activate.mjs", "bridge.mjs"];
1019
- async function copyCodeIslandPlugin(cwd) {
1020
- const pluginDir = join(cwd, ".flavor", "plugins", "codeisland");
1021
- try {
1022
- await lstat(pluginDir);
1023
- return;
1024
- } catch (error) {
1025
- if (!isMissingPathError(error)) throw error;
1026
- }
1027
- await mkdir(pluginDir, { recursive: true, mode: 448 });
1028
- for (const name of CODEISLAND_FILES) {
1029
- const content = readFileSync(join(CODEISLAND_SRC_DIR, name), "utf8");
1030
- await writeFile(join(pluginDir, name), content);
1031
- }
1032
- }
1033
1017
  var ASTGRAPH_SRC_DIR = join(dirname2(fileURLToPath(import.meta.url)), "astgraph");
1034
1018
  async function copyAstgraphPlugin(cwd) {
1035
1019
  const pluginDir = join(cwd, ".flavor", "plugins", "astgraph");
@@ -1052,7 +1036,6 @@ function copyDirectory(from, to) {
1052
1036
  }
1053
1037
  async function initializeFlavor(cwd) {
1054
1038
  await ensureFlavorDirectories(cwd);
1055
- await copyCodeIslandPlugin(cwd);
1056
1039
  await copyAstgraphPlugin(cwd);
1057
1040
  await createExampleFlavorConfig(cwd);
1058
1041
  const facts = await inspectProject(cwd);
@@ -1074,7 +1057,7 @@ async function initializeFlavor(cwd) {
1074
1057
  }
1075
1058
 
1076
1059
  // src/utils/version.ts
1077
- import { readFileSync as readFileSync2 } from "fs";
1060
+ import { readFileSync } from "fs";
1078
1061
  import { dirname as dirname3, join as join2 } from "path";
1079
1062
  import { fileURLToPath as fileURLToPath2 } from "url";
1080
1063
  var cached;
@@ -1083,7 +1066,7 @@ function packageVersion() {
1083
1066
  let directory = dirname3(fileURLToPath2(import.meta.url));
1084
1067
  for (; ; ) {
1085
1068
  try {
1086
- const manifest = JSON.parse(readFileSync2(join2(directory, "package.json"), "utf8"));
1069
+ const manifest = JSON.parse(readFileSync(join2(directory, "package.json"), "utf8"));
1087
1070
  if (typeof manifest.version === "string" && manifest.version.length > 0) {
1088
1071
  cached = manifest.version;
1089
1072
  return cached;
@@ -8002,7 +7985,7 @@ function toModelTool(tool) {
8002
7985
 
8003
7986
  // src/harness/journal.ts
8004
7987
  import { createHash as createHash6, randomUUID as randomUUID8 } from "crypto";
8005
- import { closeSync, constants, existsSync as existsSync2, fsyncSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync3, realpathSync as realpathSync2, statSync, truncateSync, writeSync } from "fs";
7988
+ import { closeSync, constants, existsSync as existsSync2, fsyncSync, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, realpathSync as realpathSync2, statSync, truncateSync, writeSync } from "fs";
8006
7989
  import { join as join8, relative as relative7, resolve as resolve8, sep as sep7 } from "path";
8007
7990
  import { z as z10 } from "zod";
8008
7991
 
@@ -8220,7 +8203,7 @@ var HarnessJournal = class {
8220
8203
  const metadata = statSync(this.#path);
8221
8204
  if (!metadata.isFile()) throw new Error("Harness journal path is not a regular file");
8222
8205
  if (metadata.size > this.#maxBytes) throw new Error(`Harness journal exceeds ${this.#maxBytes} bytes`);
8223
- const raw = readFileSync3(this.#path, "utf8");
8206
+ const raw = readFileSync2(this.#path, "utf8");
8224
8207
  const committed = raw.endsWith("\n") ? raw : raw.slice(0, Math.max(0, raw.lastIndexOf("\n") + 1));
8225
8208
  if (committed.length !== raw.length) truncateSync(this.#path, Buffer.byteLength(committed));
8226
8209
  const lines = committed.split("\n").filter(Boolean);
@@ -20524,7 +20507,10 @@ async function createProductionRuntime(options) {
20524
20507
  globalPluginDirs: [join24(home, ".flavor-code", "plugins")],
20525
20508
  projectPluginDirs: [join24(workspace, ".flavor", "plugins")],
20526
20509
  config,
20527
- sandbox: options.pluginSandbox ?? true,
20510
+ // Existing project plugins (including astgraph and superharness) use Node.js
20511
+ // built-ins. The Worker/vm sandbox deliberately blocks those imports, so it
20512
+ // must stay opt-in until equivalent mediated capabilities are available.
20513
+ sandbox: options.pluginSandbox ?? false,
20528
20514
  registrations: {
20529
20515
  command(name, handler, description) {
20530
20516
  if (typeof handler !== "function") throw new Error(`Plugin command "${name}" must be a function.`);
package/dist/cli.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-DFSMJ5SX.js";
6
+ } from "./chunk-JKJOQRAL.js";
7
7
  import {
8
8
  staticTaskLines
9
9
  } from "./chunk-KKIBYDJI.js";
@@ -23,7 +23,7 @@ import {
23
23
  packageVersion,
24
24
  redactErrorText,
25
25
  runPalBroker
26
- } from "./chunk-Q5EQ4T3F.js";
26
+ } from "./chunk-YY5H6GFN.js";
27
27
  import {
28
28
  McpServerConfigSchema,
29
29
  McpServerNameSchema,
@@ -877,7 +877,7 @@ async function runInteractiveCli(props) {
877
877
  const [{ render, AlternateScreen }, { createElement }, { App }] = await Promise.all([
878
878
  import("./claude-ink-ORUA7GWG.js"),
879
879
  import("react"),
880
- import("./app-F6FEEF46.js")
880
+ import("./app-NXOGWGSI.js")
881
881
  ]);
882
882
  const instance = await render(createElement(
883
883
  AlternateScreen,
@@ -10294,7 +10294,7 @@ ${result.stderr.slice(-4e3)}` : ""}`;
10294
10294
 
10295
10295
  // src/init/project.ts
10296
10296
  import { lstat as lstat4, mkdir as mkdir9, readdir as readdir4, readFile as readFile9, realpath as realpath7, writeFile as writeFile8 } from "fs/promises";
10297
- import { copyFileSync, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2 } from "fs";
10297
+ import { copyFileSync, mkdirSync as mkdirSync2, readdirSync } from "fs";
10298
10298
  import { basename as basename4, dirname as dirname9, isAbsolute as isAbsolute7, join as join12, relative as relative8, sep as sep8 } from "path";
10299
10299
  import { fileURLToPath } from "url";
10300
10300
  var GENERATED_START = "<!-- flavor-code:start -->";
@@ -10747,22 +10747,6 @@ async function createExampleFlavorConfig(cwd) {
10747
10747
  };
10748
10748
  await writeFile8(configPath, JSON.stringify(example, null, 2) + "\n");
10749
10749
  }
10750
- var CODEISLAND_SRC_DIR = join12(dirname9(fileURLToPath(import.meta.url)), "codeisland");
10751
- var CODEISLAND_FILES = ["flavor-plugin.json", "activate.mjs", "bridge.mjs"];
10752
- async function copyCodeIslandPlugin(cwd) {
10753
- const pluginDir = join12(cwd, ".flavor", "plugins", "codeisland");
10754
- try {
10755
- await lstat4(pluginDir);
10756
- return;
10757
- } catch (error) {
10758
- if (!isMissingPathError(error)) throw error;
10759
- }
10760
- await mkdir9(pluginDir, { recursive: true, mode: 448 });
10761
- for (const name of CODEISLAND_FILES) {
10762
- const content = readFileSync2(join12(CODEISLAND_SRC_DIR, name), "utf8");
10763
- await writeFile8(join12(pluginDir, name), content);
10764
- }
10765
- }
10766
10750
  var ASTGRAPH_SRC_DIR = join12(dirname9(fileURLToPath(import.meta.url)), "astgraph");
10767
10751
  async function copyAstgraphPlugin(cwd) {
10768
10752
  const pluginDir = join12(cwd, ".flavor", "plugins", "astgraph");
@@ -10785,7 +10769,6 @@ function copyDirectory(from, to) {
10785
10769
  }
10786
10770
  async function initializeFlavor(cwd) {
10787
10771
  await ensureFlavorDirectories(cwd);
10788
- await copyCodeIslandPlugin(cwd);
10789
10772
  await copyAstgraphPlugin(cwd);
10790
10773
  await createExampleFlavorConfig(cwd);
10791
10774
  const facts = await inspectProject(cwd);
@@ -13686,7 +13669,7 @@ import {
13686
13669
  } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
13687
13670
 
13688
13671
  // src/utils/version.ts
13689
- import { readFileSync as readFileSync3 } from "fs";
13672
+ import { readFileSync as readFileSync2 } from "fs";
13690
13673
  import { dirname as dirname13, join as join20 } from "path";
13691
13674
  import { fileURLToPath as fileURLToPath2 } from "url";
13692
13675
  var cached;
@@ -13695,7 +13678,7 @@ function packageVersion() {
13695
13678
  let directory = dirname13(fileURLToPath2(import.meta.url));
13696
13679
  for (; ; ) {
13697
13680
  try {
13698
- const manifest = JSON.parse(readFileSync3(join20(directory, "package.json"), "utf8"));
13681
+ const manifest = JSON.parse(readFileSync2(join20(directory, "package.json"), "utf8"));
13699
13682
  if (typeof manifest.version === "string" && manifest.version.length > 0) {
13700
13683
  cached = manifest.version;
13701
13684
  return cached;
@@ -24309,7 +24292,10 @@ async function createProductionRuntime(options) {
24309
24292
  globalPluginDirs: [join31(home, ".flavor-code", "plugins")],
24310
24293
  projectPluginDirs: [join31(workspace, ".flavor", "plugins")],
24311
24294
  config,
24312
- sandbox: options.pluginSandbox ?? true,
24295
+ // Existing project plugins (including astgraph and superharness) use Node.js
24296
+ // built-ins. The Worker/vm sandbox deliberately blocks those imports, so it
24297
+ // must stay opt-in until equivalent mediated capabilities are available.
24298
+ sandbox: options.pluginSandbox ?? false,
24313
24299
  registrations: {
24314
24300
  command(name, handler, description) {
24315
24301
  if (typeof handler !== "function") throw new Error(`Plugin command "${name}" must be a function.`);