@hasna/configs 0.2.2 → 0.2.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/dist/cli/index.js +115 -22
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -2064,7 +2064,7 @@ var require_commander = __commonJS((exports) => {
|
|
|
2064
2064
|
});
|
|
2065
2065
|
|
|
2066
2066
|
// src/types/index.ts
|
|
2067
|
-
var ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError;
|
|
2067
|
+
var ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, TemplateRenderError;
|
|
2068
2068
|
var init_types = __esm(() => {
|
|
2069
2069
|
ConfigNotFoundError = class ConfigNotFoundError extends Error {
|
|
2070
2070
|
constructor(id) {
|
|
@@ -2084,6 +2084,12 @@ var init_types = __esm(() => {
|
|
|
2084
2084
|
this.name = "ConfigApplyError";
|
|
2085
2085
|
}
|
|
2086
2086
|
};
|
|
2087
|
+
TemplateRenderError = class TemplateRenderError extends Error {
|
|
2088
|
+
constructor(message) {
|
|
2089
|
+
super(message);
|
|
2090
|
+
this.name = "TemplateRenderError";
|
|
2091
|
+
}
|
|
2092
|
+
};
|
|
2087
2093
|
});
|
|
2088
2094
|
|
|
2089
2095
|
// src/db/database.ts
|
|
@@ -3015,6 +3021,61 @@ var init_sync = __esm(() => {
|
|
|
3015
3021
|
];
|
|
3016
3022
|
});
|
|
3017
3023
|
|
|
3024
|
+
// src/lib/template.ts
|
|
3025
|
+
var exports_template = {};
|
|
3026
|
+
__export(exports_template, {
|
|
3027
|
+
renderTemplate: () => renderTemplate,
|
|
3028
|
+
parseTemplateVars: () => parseTemplateVars,
|
|
3029
|
+
isTemplate: () => isTemplate,
|
|
3030
|
+
extractTemplateVars: () => extractTemplateVars
|
|
3031
|
+
});
|
|
3032
|
+
function parseTemplateVars(content) {
|
|
3033
|
+
const names = new Set;
|
|
3034
|
+
let match;
|
|
3035
|
+
VAR_PATTERN.lastIndex = 0;
|
|
3036
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
3037
|
+
names.add(match[1]);
|
|
3038
|
+
}
|
|
3039
|
+
return Array.from(names);
|
|
3040
|
+
}
|
|
3041
|
+
function extractTemplateVars(content) {
|
|
3042
|
+
const vars = new Map;
|
|
3043
|
+
let match;
|
|
3044
|
+
VAR_PATTERN.lastIndex = 0;
|
|
3045
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
3046
|
+
const name = match[1];
|
|
3047
|
+
const description = match[2] ?? null;
|
|
3048
|
+
if (!vars.has(name)) {
|
|
3049
|
+
vars.set(name, { name, description, required: true });
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
return Array.from(vars.values());
|
|
3053
|
+
}
|
|
3054
|
+
function renderTemplate(content, vars) {
|
|
3055
|
+
const missing = [];
|
|
3056
|
+
VAR_PATTERN.lastIndex = 0;
|
|
3057
|
+
let match;
|
|
3058
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
3059
|
+
const name = match[1];
|
|
3060
|
+
if (!(name in vars))
|
|
3061
|
+
missing.push(name);
|
|
3062
|
+
}
|
|
3063
|
+
if (missing.length > 0) {
|
|
3064
|
+
throw new TemplateRenderError(`Missing required template variables: ${missing.join(", ")}`);
|
|
3065
|
+
}
|
|
3066
|
+
VAR_PATTERN.lastIndex = 0;
|
|
3067
|
+
return content.replace(VAR_PATTERN, (_match, name) => vars[name] ?? "");
|
|
3068
|
+
}
|
|
3069
|
+
function isTemplate(content) {
|
|
3070
|
+
VAR_PATTERN.lastIndex = 0;
|
|
3071
|
+
return VAR_PATTERN.test(content);
|
|
3072
|
+
}
|
|
3073
|
+
var VAR_PATTERN;
|
|
3074
|
+
var init_template = __esm(() => {
|
|
3075
|
+
init_types();
|
|
3076
|
+
VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
3077
|
+
});
|
|
3078
|
+
|
|
3018
3079
|
// node_modules/commander/esm.mjs
|
|
3019
3080
|
var import__ = __toESM(require_commander(), 1);
|
|
3020
3081
|
var {
|
|
@@ -3220,24 +3281,8 @@ async function importConfigs(bundlePath, opts = {}) {
|
|
|
3220
3281
|
}
|
|
3221
3282
|
}
|
|
3222
3283
|
|
|
3223
|
-
// src/lib/template.ts
|
|
3224
|
-
init_types();
|
|
3225
|
-
var VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
3226
|
-
function extractTemplateVars(content) {
|
|
3227
|
-
const vars = new Map;
|
|
3228
|
-
let match;
|
|
3229
|
-
VAR_PATTERN.lastIndex = 0;
|
|
3230
|
-
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
3231
|
-
const name = match[1];
|
|
3232
|
-
const description = match[2] ?? null;
|
|
3233
|
-
if (!vars.has(name)) {
|
|
3234
|
-
vars.set(name, { name, description, required: true });
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
return Array.from(vars.values());
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
3284
|
// src/cli/index.tsx
|
|
3285
|
+
init_template();
|
|
3241
3286
|
import { createRequire } from "module";
|
|
3242
3287
|
var pkg = createRequire(import.meta.url)("../../package.json");
|
|
3243
3288
|
function fmtConfig(c, format) {
|
|
@@ -3307,7 +3352,7 @@ program.command("add <path>").description("Ingest a file into the config DB").op
|
|
|
3307
3352
|
}
|
|
3308
3353
|
const rawContent = readFileSync5(abs, "utf-8");
|
|
3309
3354
|
const fmt = detectFormat(abs);
|
|
3310
|
-
const { content, redacted, isTemplate } = redactContent(rawContent, fmt);
|
|
3355
|
+
const { content, redacted, isTemplate: isTemplate2 } = redactContent(rawContent, fmt);
|
|
3311
3356
|
const targetPath = abs.startsWith(homedir4()) ? abs.replace(homedir4(), "~") : abs;
|
|
3312
3357
|
const name = opts.name || filePath.split("/").pop();
|
|
3313
3358
|
const config = createConfig({
|
|
@@ -3318,7 +3363,7 @@ program.command("add <path>").description("Ingest a file into the config DB").op
|
|
|
3318
3363
|
target_path: opts.kind === "reference" ? null : targetPath,
|
|
3319
3364
|
format: fmt,
|
|
3320
3365
|
content,
|
|
3321
|
-
is_template: (opts.template ?? false) ||
|
|
3366
|
+
is_template: (opts.template ?? false) || isTemplate2
|
|
3322
3367
|
});
|
|
3323
3368
|
console.log(chalk.green("\u2713") + ` Added: ${chalk.bold(config.name)} ${chalk.dim(`(${config.slug})`)}`);
|
|
3324
3369
|
if (redacted.length > 0) {
|
|
@@ -3583,6 +3628,54 @@ templateCmd.command("vars <id>").description("Show template variables").action(a
|
|
|
3583
3628
|
process.exit(1);
|
|
3584
3629
|
}
|
|
3585
3630
|
});
|
|
3631
|
+
templateCmd.command("render <id>").description("Render a template config with variables and optionally apply to disk").option("--var <vars...>", "set variables as KEY=VALUE pairs").option("--env", "use environment variables to fill template vars").option("--apply", "write rendered output to target_path").option("--dry-run", "preview rendered output without writing").action(async (id, opts) => {
|
|
3632
|
+
try {
|
|
3633
|
+
const { renderTemplate: renderTemplate2 } = await Promise.resolve().then(() => (init_template(), exports_template));
|
|
3634
|
+
const c = getConfig(id);
|
|
3635
|
+
const vars = {};
|
|
3636
|
+
if (opts.var) {
|
|
3637
|
+
for (const kv of opts.var) {
|
|
3638
|
+
const eq = kv.indexOf("=");
|
|
3639
|
+
if (eq === -1) {
|
|
3640
|
+
console.error(chalk.red(`Invalid --var: ${kv} (expected KEY=VALUE)`));
|
|
3641
|
+
process.exit(1);
|
|
3642
|
+
}
|
|
3643
|
+
vars[kv.slice(0, eq)] = kv.slice(eq + 1);
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
if (opts.env) {
|
|
3647
|
+
const { extractTemplateVars: extractTemplateVars2 } = await Promise.resolve().then(() => (init_template(), exports_template));
|
|
3648
|
+
for (const v of extractTemplateVars2(c.content)) {
|
|
3649
|
+
if (!(v.name in vars) && process.env[v.name]) {
|
|
3650
|
+
vars[v.name] = process.env[v.name];
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
}
|
|
3654
|
+
const rendered = renderTemplate2(c.content, vars);
|
|
3655
|
+
if (opts.apply || opts.dryRun) {
|
|
3656
|
+
if (!c.target_path) {
|
|
3657
|
+
console.error(chalk.red("No target_path \u2014 cannot apply reference configs"));
|
|
3658
|
+
process.exit(1);
|
|
3659
|
+
}
|
|
3660
|
+
if (opts.dryRun) {
|
|
3661
|
+
console.log(chalk.yellow("[dry-run]") + ` Would write to ${expandPath(c.target_path)}`);
|
|
3662
|
+
console.log(rendered);
|
|
3663
|
+
} else {
|
|
3664
|
+
const { writeFileSync: writeFileSync3, mkdirSync: mkdirSync5 } = await import("fs");
|
|
3665
|
+
const { dirname: dirname3 } = await import("path");
|
|
3666
|
+
const path = expandPath(c.target_path);
|
|
3667
|
+
mkdirSync5(dirname3(path), { recursive: true });
|
|
3668
|
+
writeFileSync3(path, rendered, "utf-8");
|
|
3669
|
+
console.log(chalk.green("\u2713") + ` Rendered and applied to ${path}`);
|
|
3670
|
+
}
|
|
3671
|
+
} else {
|
|
3672
|
+
console.log(rendered);
|
|
3673
|
+
}
|
|
3674
|
+
} catch (e) {
|
|
3675
|
+
console.error(chalk.red(e instanceof Error ? e.message : String(e)));
|
|
3676
|
+
process.exit(1);
|
|
3677
|
+
}
|
|
3678
|
+
});
|
|
3586
3679
|
program.command("scan [id]").description("Scan configs for secrets. Defaults to known configs only.").option("--fix", "redact found secrets in-place").option("--all", "scan every config in the DB (slow on large DBs)").option("-c, --category <cat>", "scan only a specific category").action(async (id, opts) => {
|
|
3587
3680
|
let configs;
|
|
3588
3681
|
if (id) {
|
|
@@ -3620,8 +3713,8 @@ program.command("scan [id]").description("Scan configs for secrets. Defaults to
|
|
|
3620
3713
|
for (const s of secrets)
|
|
3621
3714
|
console.log(` line ${s.line}: ${chalk.red(s.varName)} \u2014 ${s.reason}`);
|
|
3622
3715
|
if (opts.fix) {
|
|
3623
|
-
const { content, isTemplate } = redactContent(c.content, fmt);
|
|
3624
|
-
updateConfig(c.id, { content, is_template:
|
|
3716
|
+
const { content, isTemplate: isTemplate2 } = redactContent(c.content, fmt);
|
|
3717
|
+
updateConfig(c.id, { content, is_template: isTemplate2 });
|
|
3625
3718
|
console.log(chalk.green(" \u2713 Redacted."));
|
|
3626
3719
|
}
|
|
3627
3720
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/configs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "AI coding agent configuration manager — store, version, apply, and share all your AI coding configs. CLI + MCP + REST API + Dashboard.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|