@realvendex/pi-config 1.0.0
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 +71 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +12 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +52 -0
- package/dist/loader.js.map +1 -0
- package/dist/merger.d.ts +15 -0
- package/dist/merger.d.ts.map +1 -0
- package/dist/merger.js +50 -0
- package/dist/merger.js.map +1 -0
- package/dist/schema.d.ts +37 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +56 -0
- package/dist/schema.js.map +1 -0
- package/dist/validator.d.ts +10 -0
- package/dist/validator.d.ts.map +1 -0
- package/dist/validator.js +81 -0
- package/dist/validator.js.map +1 -0
- package/extensions/index.d.ts +1 -0
- package/extensions/index.js +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# @realvendex/pi-config
|
|
2
|
+
|
|
3
|
+
> Configuration management and schema validation for pi.dev extensions.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pi install npm:@realvendex/pi-config
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## What It Does
|
|
12
|
+
|
|
13
|
+
Provides three tools for managing extension configurations:
|
|
14
|
+
|
|
15
|
+
- **Schema validation** — validate config objects against TypeBox-compatible schemas
|
|
16
|
+
- **Multi-format loading** — load configs from JSON, YAML, and TOML files with auto-detection
|
|
17
|
+
- **Precedence merging** — merge config layers with clear priority: defaults < file < env < CLI args
|
|
18
|
+
|
|
19
|
+
## Tools
|
|
20
|
+
|
|
21
|
+
### `validate-config`
|
|
22
|
+
|
|
23
|
+
Validate a configuration object against a TypeBox-compatible schema.
|
|
24
|
+
|
|
25
|
+
**Parameters:**
|
|
26
|
+
- `config` (object, required) — Configuration object to validate
|
|
27
|
+
- `schema` (object, required) — TypeBox-compatible schema definition
|
|
28
|
+
- `strict` (boolean, optional) — Reject unknown properties (default: false)
|
|
29
|
+
|
|
30
|
+
**Example:**
|
|
31
|
+
```
|
|
32
|
+
Use validate-config with config={"port": 3000} and schema={"type":"object","properties":{"port":{"type":"number"}}}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### `load-config`
|
|
36
|
+
|
|
37
|
+
Load configuration from a file with auto-detect or explicit format.
|
|
38
|
+
|
|
39
|
+
**Parameters:**
|
|
40
|
+
- `path` (string, required) — Path to config file (.json, .yaml, .yml, .toml)
|
|
41
|
+
- `format` (string, optional) — Override auto-detection: "json", "yaml", or "toml"
|
|
42
|
+
|
|
43
|
+
**Example:**
|
|
44
|
+
```
|
|
45
|
+
Use load-config with path="./config.yaml"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### `merge-config`
|
|
49
|
+
|
|
50
|
+
Merge multiple config layers with precedence: defaults < file < env < CLI args.
|
|
51
|
+
|
|
52
|
+
**Parameters:**
|
|
53
|
+
- `defaults` (object, optional) — Default values (lowest priority)
|
|
54
|
+
- `file` (object, optional) — File-based configuration
|
|
55
|
+
- `env` (object, optional) — Environment variable overrides
|
|
56
|
+
- `args` (object, optional) — CLI argument overrides (highest priority)
|
|
57
|
+
|
|
58
|
+
**Example:**
|
|
59
|
+
```
|
|
60
|
+
Use merge-config with defaults={"port":3000} and args={"port":8080}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Resources
|
|
64
|
+
|
|
65
|
+
- [npm](https://www.npmjs.com/package/@realvendex/pi-config)
|
|
66
|
+
- [GitHub](https://github.com/ZachDreamZ/pi-config)
|
|
67
|
+
- [pi.dev](https://pi.dev/packages/@realvendex/pi-config)
|
|
68
|
+
|
|
69
|
+
## License
|
|
70
|
+
|
|
71
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAMpE,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA6HvD"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { loadConfig } from "./loader.js";
|
|
3
|
+
import { mergeConfig } from "./merger.js";
|
|
4
|
+
import { validateConfig } from "./validator.js";
|
|
5
|
+
export default function register(pi) {
|
|
6
|
+
// ─── validate-config ───────────────────────────────────────────────────────
|
|
7
|
+
pi.registerTool({
|
|
8
|
+
name: "validate-config",
|
|
9
|
+
label: "Validate Config",
|
|
10
|
+
description: "Validate a configuration object against a TypeBox-compatible schema. Reports errors with JSON-pointer paths.",
|
|
11
|
+
parameters: Type.Object({
|
|
12
|
+
config: Type.Record(Type.String(), Type.Unknown(), {
|
|
13
|
+
description: "Configuration object to validate",
|
|
14
|
+
}),
|
|
15
|
+
schema: Type.Record(Type.String(), Type.Unknown(), {
|
|
16
|
+
description: "TypeBox-compatible schema definition",
|
|
17
|
+
}),
|
|
18
|
+
strict: Type.Optional(Type.Boolean({
|
|
19
|
+
description: "If true, reject unknown properties (default: false)",
|
|
20
|
+
})),
|
|
21
|
+
}),
|
|
22
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
23
|
+
const { config, schema, strict } = params;
|
|
24
|
+
const result = validateConfig(config, schema, strict ?? false);
|
|
25
|
+
const text = result.valid
|
|
26
|
+
? "Config is valid."
|
|
27
|
+
: `Config validation failed:\n${result.errors.map((e) => ` - ${e}`).join("\n")}`;
|
|
28
|
+
return {
|
|
29
|
+
content: [{ type: "text", text }],
|
|
30
|
+
details: result,
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
// ─── load-config ───────────────────────────────────────────────────────────
|
|
35
|
+
pi.registerTool({
|
|
36
|
+
name: "load-config",
|
|
37
|
+
label: "Load Config",
|
|
38
|
+
description: "Load configuration from a file. Auto-detects format from extension (.json, .yaml, .yml, .toml) or use explicit format override.",
|
|
39
|
+
parameters: Type.Object({
|
|
40
|
+
path: Type.String({
|
|
41
|
+
description: "Path to config file (.json, .yaml, .yml, .toml)",
|
|
42
|
+
}),
|
|
43
|
+
format: Type.Optional(Type.Union([Type.Literal("json"), Type.Literal("yaml"), Type.Literal("toml")], { description: "Override auto-detection from file extension" })),
|
|
44
|
+
}),
|
|
45
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
46
|
+
const { path: filePath, format } = params;
|
|
47
|
+
try {
|
|
48
|
+
const result = loadConfig(filePath, format);
|
|
49
|
+
const text = `Loaded ${result.format.toUpperCase()} config from ${result.path} (${Object.keys(result.config).length} keys)`;
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text }],
|
|
52
|
+
details: result,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
57
|
+
return {
|
|
58
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
59
|
+
details: { error: message },
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
// ─── merge-config ──────────────────────────────────────────────────────────
|
|
65
|
+
pi.registerTool({
|
|
66
|
+
name: "merge-config",
|
|
67
|
+
label: "Merge Config",
|
|
68
|
+
description: "Merge multiple config layers with precedence: defaults (lowest) < file < env < CLI args (highest). Deep-merges nested objects.",
|
|
69
|
+
parameters: Type.Object({
|
|
70
|
+
defaults: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
71
|
+
description: "Default values (lowest priority)",
|
|
72
|
+
})),
|
|
73
|
+
file: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
74
|
+
description: "File-based configuration",
|
|
75
|
+
})),
|
|
76
|
+
env: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
77
|
+
description: "Environment variable overrides",
|
|
78
|
+
})),
|
|
79
|
+
args: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
80
|
+
description: "CLI argument overrides (highest priority)",
|
|
81
|
+
})),
|
|
82
|
+
}),
|
|
83
|
+
async execute(_toolCallId, params, _signal, _onUpdate, _ctx) {
|
|
84
|
+
const input = params;
|
|
85
|
+
const result = mergeConfig(input);
|
|
86
|
+
const text = `Merged config from ${result.sources.length} sources (${result.sources.join(" < ")}). Result has ${Object.keys(result.merged).length} keys.`;
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: "text", text }],
|
|
89
|
+
details: result,
|
|
90
|
+
};
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type ConfigFormat = "json" | "yaml" | "toml";
|
|
2
|
+
export interface LoadConfigResult {
|
|
3
|
+
config: Record<string, unknown>;
|
|
4
|
+
format: ConfigFormat;
|
|
5
|
+
path: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Load a config file with auto-detect or explicit format.
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadConfig(filePath: string, formatOverride?: ConfigFormat): LoadConfigResult;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAKA,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,YAAY,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;CACb;AAkCD;;GAEG;AACH,wBAAgB,UAAU,CACzB,QAAQ,EAAE,MAAM,EAChB,cAAc,CAAC,EAAE,YAAY,GAC3B,gBAAgB,CAiBlB"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { parse as parseToml } from "smol-toml";
|
|
4
|
+
import * as YAML from "yaml";
|
|
5
|
+
/**
|
|
6
|
+
* Auto-detect config format from file extension.
|
|
7
|
+
*/
|
|
8
|
+
function detectFormat(filePath) {
|
|
9
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
10
|
+
if (ext === ".json")
|
|
11
|
+
return "json";
|
|
12
|
+
if (ext === ".yaml" || ext === ".yml")
|
|
13
|
+
return "yaml";
|
|
14
|
+
if (ext === ".toml")
|
|
15
|
+
return "toml";
|
|
16
|
+
throw new Error(`Cannot detect format from extension "${ext}". Supported: .json, .yaml, .yml, .toml`);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Parse config content based on format.
|
|
20
|
+
*/
|
|
21
|
+
function parseContent(content, format) {
|
|
22
|
+
switch (format) {
|
|
23
|
+
case "json":
|
|
24
|
+
return JSON.parse(content);
|
|
25
|
+
case "yaml":
|
|
26
|
+
return YAML.parse(content);
|
|
27
|
+
case "toml":
|
|
28
|
+
return parseToml(content);
|
|
29
|
+
default:
|
|
30
|
+
throw new Error(`Unsupported format: ${format}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Load a config file with auto-detect or explicit format.
|
|
35
|
+
*/
|
|
36
|
+
export function loadConfig(filePath, formatOverride) {
|
|
37
|
+
const resolvedPath = path.resolve(filePath);
|
|
38
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
39
|
+
throw new Error(`Config file not found: ${resolvedPath}`);
|
|
40
|
+
}
|
|
41
|
+
const format = formatOverride ?? detectFormat(resolvedPath);
|
|
42
|
+
const content = fs.readFileSync(resolvedPath, "utf-8");
|
|
43
|
+
try {
|
|
44
|
+
const config = parseContent(content, format);
|
|
45
|
+
return { config, format, path: resolvedPath };
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49
|
+
throw new Error(`Failed to parse ${format} config: ${message}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAU7B;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACjD,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,GAAG,KAAK,OAAO,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACrD,IAAI,GAAG,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IACnC,MAAM,IAAI,KAAK,CACd,wCAAwC,GAAG,yCAAyC,CACpF,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CACpB,OAAe,EACf,MAAoB;IAEpB,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,MAAM;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;QACvD,KAAK,MAAM;YACV,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;QACvD,KAAK,MAAM;YACV,OAAO,SAAS,CAAC,OAAO,CAA4B,CAAC;QACtD;YACC,MAAM,IAAI,KAAK,CAAC,uBAAuB,MAAM,EAAE,CAAC,CAAC;IACnD,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CACzB,QAAgB,EAChB,cAA6B;IAE7B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE5C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,IAAI,YAAY,CAAC,YAAY,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IAEvD,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;IAC/C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,mBAAmB,MAAM,YAAY,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;AACF,CAAC"}
|
package/dist/merger.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface MergeConfigInput {
|
|
2
|
+
defaults?: Record<string, unknown>;
|
|
3
|
+
file?: Record<string, unknown>;
|
|
4
|
+
env?: Record<string, unknown>;
|
|
5
|
+
args?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface MergeConfigResult {
|
|
8
|
+
merged: Record<string, unknown>;
|
|
9
|
+
sources: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Merge configs with precedence: defaults < file < env < args.
|
|
13
|
+
*/
|
|
14
|
+
export declare function mergeConfig(input: MergeConfigInput): MergeConfigResult;
|
|
15
|
+
//# sourceMappingURL=merger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.d.ts","sourceRoot":"","sources":["../src/merger.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,iBAAiB,CA6BtE"}
|
package/dist/merger.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge two objects. Source values override target values.
|
|
3
|
+
* Nested objects are merged recursively; primitives and arrays are replaced.
|
|
4
|
+
*/
|
|
5
|
+
function deepMerge(target, source) {
|
|
6
|
+
const result = { ...target };
|
|
7
|
+
for (const key of Object.keys(source)) {
|
|
8
|
+
const sourceVal = source[key];
|
|
9
|
+
const targetVal = result[key];
|
|
10
|
+
if (isPlainObject(sourceVal) && isPlainObject(targetVal)) {
|
|
11
|
+
result[key] = deepMerge(targetVal, sourceVal);
|
|
12
|
+
}
|
|
13
|
+
else if (sourceVal !== undefined) {
|
|
14
|
+
result[key] = sourceVal;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return result;
|
|
18
|
+
}
|
|
19
|
+
function isPlainObject(val) {
|
|
20
|
+
return typeof val === "object" && val !== null && !Array.isArray(val);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Merge configs with precedence: defaults < file < env < args.
|
|
24
|
+
*/
|
|
25
|
+
export function mergeConfig(input) {
|
|
26
|
+
const sources = [];
|
|
27
|
+
let result = {};
|
|
28
|
+
// Layer 1: defaults (lowest priority)
|
|
29
|
+
if (input.defaults && isPlainObject(input.defaults)) {
|
|
30
|
+
result = deepMerge(result, input.defaults);
|
|
31
|
+
sources.push("defaults");
|
|
32
|
+
}
|
|
33
|
+
// Layer 2: file config
|
|
34
|
+
if (input.file && isPlainObject(input.file)) {
|
|
35
|
+
result = deepMerge(result, input.file);
|
|
36
|
+
sources.push("file");
|
|
37
|
+
}
|
|
38
|
+
// Layer 3: env vars
|
|
39
|
+
if (input.env && isPlainObject(input.env)) {
|
|
40
|
+
result = deepMerge(result, input.env);
|
|
41
|
+
sources.push("env");
|
|
42
|
+
}
|
|
43
|
+
// Layer 4: CLI args (highest priority)
|
|
44
|
+
if (input.args && isPlainObject(input.args)) {
|
|
45
|
+
result = deepMerge(result, input.args);
|
|
46
|
+
sources.push("args");
|
|
47
|
+
}
|
|
48
|
+
return { merged: result, sources };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=merger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merger.js","sourceRoot":"","sources":["../src/merger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,SAAS,SAAS,CACjB,MAA+B,EAC/B,MAA+B;IAE/B,MAAM,MAAM,GAA4B,EAAE,GAAG,MAAM,EAAE,CAAC;IAEtD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAE9B,IAAI,aAAa,CAAC,SAAS,CAAC,IAAI,aAAa,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1D,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACtB,SAAoC,EACpC,SAAoC,CACpC,CAAC;QACH,CAAC;aAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;QACzB,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IAClC,OAAO,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AACvE,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAuB;IAClD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,MAAM,GAA4B,EAAE,CAAC;IAEzC,sCAAsC;IACtC,IAAI,KAAK,CAAC,QAAQ,IAAI,aAAa,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC1B,CAAC;IAED,uBAAuB;IACvB,IAAI,KAAK,CAAC,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,oBAAoB;IACpB,IAAI,KAAK,CAAC,GAAG,IAAI,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,uCAAuC;IACvC,IAAI,KAAK,CAAC,IAAI,IAAI,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACvC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AACpC,CAAC"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Static, Type } from "typebox";
|
|
2
|
+
export declare const ValidateConfigInput: Type.TObject<{
|
|
3
|
+
config: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
4
|
+
schema: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
5
|
+
strict: Type.TOptional<Type.TBoolean>;
|
|
6
|
+
}>;
|
|
7
|
+
export type TValidateConfigInput = Static<typeof ValidateConfigInput>;
|
|
8
|
+
export declare const ValidateConfigOutput: Type.TObject<{
|
|
9
|
+
valid: Type.TBoolean;
|
|
10
|
+
errors: Type.TArray<Type.TString>;
|
|
11
|
+
config: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
12
|
+
}>;
|
|
13
|
+
export type TValidateConfigOutput = Static<typeof ValidateConfigOutput>;
|
|
14
|
+
export declare const LoadConfigInput: Type.TObject<{
|
|
15
|
+
path: Type.TString;
|
|
16
|
+
format: Type.TOptional<Type.TUnion<[Type.TLiteral<"json">, Type.TLiteral<"yaml">, Type.TLiteral<"toml">]>>;
|
|
17
|
+
}>;
|
|
18
|
+
export type TLoadConfigInput = Static<typeof LoadConfigInput>;
|
|
19
|
+
export declare const LoadConfigOutput: Type.TObject<{
|
|
20
|
+
config: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
21
|
+
format: Type.TUnion<[Type.TLiteral<"json">, Type.TLiteral<"yaml">, Type.TLiteral<"toml">]>;
|
|
22
|
+
path: Type.TString;
|
|
23
|
+
}>;
|
|
24
|
+
export type TLoadConfigOutput = Static<typeof LoadConfigOutput>;
|
|
25
|
+
export declare const MergeConfigInput: Type.TObject<{
|
|
26
|
+
defaults: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
27
|
+
file: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
28
|
+
env: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
29
|
+
args: Type.TOptional<Type.TRecord<"^.*$", Type.TUnknown>>;
|
|
30
|
+
}>;
|
|
31
|
+
export type TMergeConfigInput = Static<typeof MergeConfigInput>;
|
|
32
|
+
export declare const MergeConfigOutput: Type.TObject<{
|
|
33
|
+
merged: Type.TRecord<"^.*$", Type.TUnknown>;
|
|
34
|
+
sources: Type.TArray<Type.TString>;
|
|
35
|
+
}>;
|
|
36
|
+
export type TMergeConfigOutput = Static<typeof MergeConfigOutput>;
|
|
37
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAI5C,eAAO,MAAM,mBAAmB;;;;EAY9B,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEtE,eAAO,MAAM,oBAAoB;;;;EAI/B,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,MAAM,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAIxE,eAAO,MAAM,eAAe;;;EAY1B,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,MAAM,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D,eAAO,MAAM,gBAAgB;;;;EAQ3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAIhE,eAAO,MAAM,gBAAgB;;;;;EAqB3B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAEhE,eAAO,MAAM,iBAAiB;;;EAG5B,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
// ─── validate-config ─────────────────────────────────────────────────────────
|
|
3
|
+
export const ValidateConfigInput = Type.Object({
|
|
4
|
+
config: Type.Record(Type.String(), Type.Unknown(), {
|
|
5
|
+
description: "Configuration object to validate",
|
|
6
|
+
}),
|
|
7
|
+
schema: Type.Record(Type.String(), Type.Unknown(), {
|
|
8
|
+
description: "TypeBox-compatible schema definition",
|
|
9
|
+
}),
|
|
10
|
+
strict: Type.Optional(Type.Boolean({
|
|
11
|
+
description: "If true, reject unknown properties (default: false)",
|
|
12
|
+
})),
|
|
13
|
+
});
|
|
14
|
+
export const ValidateConfigOutput = Type.Object({
|
|
15
|
+
valid: Type.Boolean(),
|
|
16
|
+
errors: Type.Array(Type.String()),
|
|
17
|
+
config: Type.Optional(Type.Record(Type.String(), Type.Unknown())),
|
|
18
|
+
});
|
|
19
|
+
// ─── load-config ─────────────────────────────────────────────────────────────
|
|
20
|
+
export const LoadConfigInput = Type.Object({
|
|
21
|
+
path: Type.String({
|
|
22
|
+
description: "Path to config file (.json, .yaml, .yml, .toml)",
|
|
23
|
+
}),
|
|
24
|
+
format: Type.Optional(Type.Union([Type.Literal("json"), Type.Literal("yaml"), Type.Literal("toml")], {
|
|
25
|
+
description: "Override auto-detection from file extension",
|
|
26
|
+
})),
|
|
27
|
+
});
|
|
28
|
+
export const LoadConfigOutput = Type.Object({
|
|
29
|
+
config: Type.Record(Type.String(), Type.Unknown()),
|
|
30
|
+
format: Type.Union([
|
|
31
|
+
Type.Literal("json"),
|
|
32
|
+
Type.Literal("yaml"),
|
|
33
|
+
Type.Literal("toml"),
|
|
34
|
+
]),
|
|
35
|
+
path: Type.String(),
|
|
36
|
+
});
|
|
37
|
+
// ─── merge-config ────────────────────────────────────────────────────────────
|
|
38
|
+
export const MergeConfigInput = Type.Object({
|
|
39
|
+
defaults: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
40
|
+
description: "Default values (lowest priority)",
|
|
41
|
+
})),
|
|
42
|
+
file: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
43
|
+
description: "File-based configuration",
|
|
44
|
+
})),
|
|
45
|
+
env: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
46
|
+
description: "Environment variable overrides",
|
|
47
|
+
})),
|
|
48
|
+
args: Type.Optional(Type.Record(Type.String(), Type.Unknown(), {
|
|
49
|
+
description: "CLI argument overrides (highest priority)",
|
|
50
|
+
})),
|
|
51
|
+
});
|
|
52
|
+
export const MergeConfigOutput = Type.Object({
|
|
53
|
+
merged: Type.Record(Type.String(), Type.Unknown()),
|
|
54
|
+
sources: Type.Array(Type.String()),
|
|
55
|
+
});
|
|
56
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate a config object against a TypeBox-compatible schema.
|
|
3
|
+
* Returns validation result with error details.
|
|
4
|
+
*/
|
|
5
|
+
export declare function validateConfig(config: Record<string, unknown>, schema: Record<string, unknown>, strict?: boolean): {
|
|
6
|
+
valid: boolean;
|
|
7
|
+
errors: string[];
|
|
8
|
+
config?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,cAAc,CAC7B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,UAAQ,GACZ;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,CA0CxE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { Value } from "typebox/value";
|
|
3
|
+
/**
|
|
4
|
+
* Validate a config object against a TypeBox-compatible schema.
|
|
5
|
+
* Returns validation result with error details.
|
|
6
|
+
*/
|
|
7
|
+
export function validateConfig(config, schema, strict = false) {
|
|
8
|
+
const errors = [];
|
|
9
|
+
try {
|
|
10
|
+
// Reconstruct a TypeBox schema from the plain object
|
|
11
|
+
const tbSchema = reconstructSchema(schema);
|
|
12
|
+
// Check for unknown properties in strict mode
|
|
13
|
+
if (strict &&
|
|
14
|
+
tbSchema &&
|
|
15
|
+
typeof tbSchema === "object" &&
|
|
16
|
+
"properties" in tbSchema) {
|
|
17
|
+
const schemaProps = tbSchema.properties;
|
|
18
|
+
for (const key of Object.keys(config)) {
|
|
19
|
+
if (!(key in schemaProps)) {
|
|
20
|
+
errors.push(`Unknown property: "${key}"`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Validate using TypeBox Value.Check
|
|
25
|
+
const checkResult = Value.Check(tbSchema, config);
|
|
26
|
+
if (!checkResult) {
|
|
27
|
+
// Collect errors from Value.Errors
|
|
28
|
+
const errorsIter = Value.Errors(tbSchema, config);
|
|
29
|
+
for (const err of errorsIter) {
|
|
30
|
+
const path = err.instancePath || "/";
|
|
31
|
+
errors.push(`${path}: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (errors.length === 0) {
|
|
35
|
+
return { valid: true, errors: [], config };
|
|
36
|
+
}
|
|
37
|
+
return { valid: false, errors };
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41
|
+
errors.push(`Schema error: ${message}`);
|
|
42
|
+
return { valid: false, errors };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Reconstruct a TypeBox TSchema from a plain object representation.
|
|
47
|
+
* Handles { type: "object", properties: {...}, required: [...] } format.
|
|
48
|
+
*/
|
|
49
|
+
function reconstructSchema(obj) {
|
|
50
|
+
if (typeof obj !== "object" || obj === null) {
|
|
51
|
+
return Type.Unknown();
|
|
52
|
+
}
|
|
53
|
+
const type = obj.type;
|
|
54
|
+
if (type === "object") {
|
|
55
|
+
const properties = obj.properties ?? {};
|
|
56
|
+
const required = obj.required ?? [];
|
|
57
|
+
const reconstructedProps = {};
|
|
58
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
59
|
+
reconstructedProps[key] = reconstructSchema(value);
|
|
60
|
+
}
|
|
61
|
+
if (required.length > 0) {
|
|
62
|
+
return Type.Object(reconstructedProps, { required });
|
|
63
|
+
}
|
|
64
|
+
return Type.Object(reconstructedProps);
|
|
65
|
+
}
|
|
66
|
+
if (type === "string")
|
|
67
|
+
return Type.String();
|
|
68
|
+
if (type === "number")
|
|
69
|
+
return Type.Number();
|
|
70
|
+
if (type === "boolean")
|
|
71
|
+
return Type.Boolean();
|
|
72
|
+
if (type === "integer")
|
|
73
|
+
return Type.Integer();
|
|
74
|
+
if (type === "array") {
|
|
75
|
+
const items = obj.items;
|
|
76
|
+
return Type.Array(items ? reconstructSchema(items) : Type.Unknown());
|
|
77
|
+
}
|
|
78
|
+
// Fallback: treat as record
|
|
79
|
+
return Type.Record(Type.String(), Type.Unknown());
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../dist/index.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "../dist/index.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@realvendex/pi-config",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Configuration management and schema validation for pi.dev extensions",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": ["dist", "extensions"],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"lint": "biome check .",
|
|
13
|
+
"lint:fix": "biome check --write ."
|
|
14
|
+
},
|
|
15
|
+
"keywords": ["pi-package", "pi", "config", "validation", "schema"],
|
|
16
|
+
"author": "realvendex",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"typebox": "^1.0.0",
|
|
20
|
+
"yaml": "^2.7.0",
|
|
21
|
+
"smol-toml": "^1.3.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@earendil-works/pi-ai": "*",
|
|
25
|
+
"@earendil-works/pi-agent-core": "*",
|
|
26
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
27
|
+
"@earendil-works/pi-tui": "*",
|
|
28
|
+
"typebox": "*"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@biomejs/biome": "^1.9.0",
|
|
32
|
+
"typescript": "^5.5.0",
|
|
33
|
+
"vitest": "^2.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|