@trim21/personal-pi-extensions 0.0.424 → 0.0.425

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trim21/personal-pi-extensions",
3
- "version": "0.0.424",
3
+ "version": "0.0.425",
4
4
  "type": "module",
5
5
  "description": "Custom pi coding-agent extensions: bwrap sandbox, workspace guard, opencode edit, and more",
6
6
  "keywords": [
package/src/bwrap/core.ts CHANGED
@@ -9,6 +9,7 @@ import { type BashOperations, getAgentDir, getShellConfig } from "@earendil-work
9
9
  import { type Static, Type } from "typebox";
10
10
  import { Value } from "typebox/value";
11
11
 
12
+ import { parseWithSchema } from "../lib/parse-with-schema.js";
12
13
  import { expandHome } from "../lib/path.js";
13
14
  import { type ApprovalRule } from "./approval-rules.js";
14
15
  import { type NetworkStack, resolveDnsServers, startNetworkStack } from "./network-stack.js";
@@ -42,18 +43,20 @@ const bwrapConfigProperties = {
42
43
  action: StringEnum(["allow", "deny"] as const),
43
44
  pattern: Type.String({ description: '命令模式,如 "git push *"、"npm install *"' }),
44
45
  },
45
- { additionalProperties: false },
46
+ { additionalProperties: true },
46
47
  ),
47
48
  ),
48
49
  ),
49
50
  };
50
51
 
52
+ // 配置文件容忍未知字段:schema 之外的字段(如新版本扩展新增的配置)会被忽略,
53
+ // 避免整个 bwrap 配置因单个未知字段失效;已声明字段仍做类型/取值校验。
51
54
  export const bwrapConfigSchema = Type.Object(bwrapConfigProperties, {
52
- additionalProperties: false,
55
+ additionalProperties: true,
53
56
  });
54
57
 
55
58
  export const bwrapConfigFileSchema = Type.Partial(bwrapConfigSchema, {
56
- additionalProperties: false,
59
+ additionalProperties: true,
57
60
  });
58
61
 
59
62
  export type BwrapConfig = Static<typeof bwrapConfigSchema>;
@@ -151,9 +154,10 @@ function parseBwrapConfigFile(path: string): BwrapConfigFile {
151
154
  throw new Error(`Invalid bwrap configuration at ${path}: ${String(error)}`, { cause: error });
152
155
  }
153
156
  try {
154
- return Value.Parse(bwrapConfigFileSchema, raw);
157
+ return parseWithSchema(bwrapConfigFileSchema, raw);
155
158
  } catch (error) {
156
- throw new Error(`Invalid bwrap configuration at ${path}: ${String(error)}`, { cause: error });
159
+ const detail = error instanceof Error ? error.message : String(error);
160
+ throw new Error(`Invalid bwrap configuration at ${path}: ${detail}`, { cause: error });
157
161
  }
158
162
  }
159
163
 
@@ -0,0 +1,21 @@
1
+ import type { Static, TSchema } from "typebox";
2
+ import Value, { ParseError } from "typebox/value";
3
+
4
+ /**
5
+ * 用 typebox schema 解析 value。成功返回解析结果;失败抛带字段路径的 Error
6
+ * (Value.Parse 的 ParseError 错误详情在 cause.errors,默认 message 只有
7
+ * "Parse",这里拼成可读信息,供调用方包装上下文如配置文件路径)。
8
+ */
9
+ export function parseWithSchema<T extends TSchema>(schema: T, value: unknown): Static<T> {
10
+ try {
11
+ return Value.Parse(schema, value);
12
+ } catch (error) {
13
+ if (error instanceof ParseError) {
14
+ const details = error.cause.errors
15
+ .map((e) => `${e.instancePath || "(root)"}: ${e.message}`)
16
+ .join("; ");
17
+ throw new Error(details, { cause: error });
18
+ }
19
+ throw error;
20
+ }
21
+ }