@hasna/configs 0.2.11 → 0.2.13
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 +3 -2
- package/dist/mcp/index.js +82 -4
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -3756,7 +3756,7 @@ Run with --fix to redact in-place.`));
|
|
|
3756
3756
|
}
|
|
3757
3757
|
});
|
|
3758
3758
|
var mcpCmd = program.command("mcp").description("Install/remove MCP server for AI agents");
|
|
3759
|
-
mcpCmd.command("install").alias("add").description("Install configs MCP server into an agent").option("--claude", "install into Claude Code").option("--codex", "install into Codex").option("--gemini", "install into Gemini").option("--all", "install into all agents").action(async (opts) => {
|
|
3759
|
+
mcpCmd.command("install").alias("add").description("Install configs MCP server into an agent").option("--claude", "install into Claude Code").option("--codex", "install into Codex").option("--gemini", "install into Gemini").option("--all", "install into all agents").option("--profile <level>", "set CONFIGS_PROFILE (minimal|standard|full)", "standard").action(async (opts) => {
|
|
3760
3760
|
const targets = opts.all ? ["claude", "codex", "gemini"] : [
|
|
3761
3761
|
...opts.claude ? ["claude"] : [],
|
|
3762
3762
|
...opts.codex ? ["codex"] : [],
|
|
@@ -3769,7 +3769,8 @@ mcpCmd.command("install").alias("add").description("Install configs MCP server i
|
|
|
3769
3769
|
for (const target of targets) {
|
|
3770
3770
|
try {
|
|
3771
3771
|
if (target === "claude") {
|
|
3772
|
-
const
|
|
3772
|
+
const cmd = opts.profile && opts.profile !== "full" ? ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "env", `CONFIGS_PROFILE=${opts.profile}`, "configs-mcp"] : ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "configs-mcp"];
|
|
3773
|
+
const proc = Bun.spawn(cmd, { stdout: "inherit", stderr: "inherit" });
|
|
3773
3774
|
await proc.exited;
|
|
3774
3775
|
console.log(chalk.green("\u2713") + " Installed into Claude Code");
|
|
3775
3776
|
} else if (target === "codex") {
|
package/dist/mcp/index.js
CHANGED
|
@@ -13,7 +13,7 @@ var __export = (target, all) => {
|
|
|
13
13
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
14
14
|
|
|
15
15
|
// src/types/index.ts
|
|
16
|
-
var ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError;
|
|
16
|
+
var ConfigNotFoundError, ProfileNotFoundError, ConfigApplyError, TemplateRenderError;
|
|
17
17
|
var init_types = __esm(() => {
|
|
18
18
|
ConfigNotFoundError = class ConfigNotFoundError extends Error {
|
|
19
19
|
constructor(id) {
|
|
@@ -33,6 +33,12 @@ var init_types = __esm(() => {
|
|
|
33
33
|
this.name = "ConfigApplyError";
|
|
34
34
|
}
|
|
35
35
|
};
|
|
36
|
+
TemplateRenderError = class TemplateRenderError extends Error {
|
|
37
|
+
constructor(message) {
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = "TemplateRenderError";
|
|
40
|
+
}
|
|
41
|
+
};
|
|
36
42
|
});
|
|
37
43
|
|
|
38
44
|
// src/db/database.ts
|
|
@@ -964,6 +970,61 @@ var init_sync = __esm(() => {
|
|
|
964
970
|
];
|
|
965
971
|
});
|
|
966
972
|
|
|
973
|
+
// src/lib/template.ts
|
|
974
|
+
var exports_template = {};
|
|
975
|
+
__export(exports_template, {
|
|
976
|
+
renderTemplate: () => renderTemplate,
|
|
977
|
+
parseTemplateVars: () => parseTemplateVars,
|
|
978
|
+
isTemplate: () => isTemplate,
|
|
979
|
+
extractTemplateVars: () => extractTemplateVars
|
|
980
|
+
});
|
|
981
|
+
function parseTemplateVars(content) {
|
|
982
|
+
const names = new Set;
|
|
983
|
+
let match;
|
|
984
|
+
VAR_PATTERN.lastIndex = 0;
|
|
985
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
986
|
+
names.add(match[1]);
|
|
987
|
+
}
|
|
988
|
+
return Array.from(names);
|
|
989
|
+
}
|
|
990
|
+
function extractTemplateVars(content) {
|
|
991
|
+
const vars = new Map;
|
|
992
|
+
let match;
|
|
993
|
+
VAR_PATTERN.lastIndex = 0;
|
|
994
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
995
|
+
const name = match[1];
|
|
996
|
+
const description = match[2] ?? null;
|
|
997
|
+
if (!vars.has(name)) {
|
|
998
|
+
vars.set(name, { name, description, required: true });
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
return Array.from(vars.values());
|
|
1002
|
+
}
|
|
1003
|
+
function renderTemplate(content, vars) {
|
|
1004
|
+
const missing = [];
|
|
1005
|
+
VAR_PATTERN.lastIndex = 0;
|
|
1006
|
+
let match;
|
|
1007
|
+
while ((match = VAR_PATTERN.exec(content)) !== null) {
|
|
1008
|
+
const name = match[1];
|
|
1009
|
+
if (!(name in vars))
|
|
1010
|
+
missing.push(name);
|
|
1011
|
+
}
|
|
1012
|
+
if (missing.length > 0) {
|
|
1013
|
+
throw new TemplateRenderError(`Missing required template variables: ${missing.join(", ")}`);
|
|
1014
|
+
}
|
|
1015
|
+
VAR_PATTERN.lastIndex = 0;
|
|
1016
|
+
return content.replace(VAR_PATTERN, (_match, name) => vars[name] ?? "");
|
|
1017
|
+
}
|
|
1018
|
+
function isTemplate(content) {
|
|
1019
|
+
VAR_PATTERN.lastIndex = 0;
|
|
1020
|
+
return VAR_PATTERN.test(content);
|
|
1021
|
+
}
|
|
1022
|
+
var VAR_PATTERN;
|
|
1023
|
+
var init_template = __esm(() => {
|
|
1024
|
+
init_types();
|
|
1025
|
+
VAR_PATTERN = /\{\{([A-Z0-9_]+)(?::([^}]*))?\}\}/g;
|
|
1026
|
+
});
|
|
1027
|
+
|
|
967
1028
|
// src/mcp/index.ts
|
|
968
1029
|
init_configs();
|
|
969
1030
|
init_apply();
|
|
@@ -1014,6 +1075,7 @@ var TOOL_DOCS = {
|
|
|
1014
1075
|
apply_profile: "Apply all configs in a profile to disk. Params: id_or_slug, dry_run?. Returns array of apply results.",
|
|
1015
1076
|
get_snapshot: "Get snapshot(s) for a config. Params: config_id_or_slug, version?. Returns latest snapshot or specific version.",
|
|
1016
1077
|
get_status: "Single-call orientation. Returns: total configs, counts by category, templates, DB path.",
|
|
1078
|
+
render_template: "Render a template config with variable substitution. Params: id_or_slug, vars? (object of KEY:VALUE), use_env? (fill from env vars). Returns rendered content.",
|
|
1017
1079
|
scan_secrets: "Scan configs for unredacted secrets. Params: id_or_slug? (omit for all known), fix? (true to redact in-place). Returns findings.",
|
|
1018
1080
|
sync_known: "Sync all known config files from disk into DB. Params: agent?, category?. Replaces sync_directory for standard use.",
|
|
1019
1081
|
search_tools: "Search tool descriptions. Params: query. Returns matching tool names and descriptions.",
|
|
@@ -1021,7 +1083,7 @@ var TOOL_DOCS = {
|
|
|
1021
1083
|
};
|
|
1022
1084
|
var PROFILES = {
|
|
1023
1085
|
minimal: ["get_status", "get_config", "sync_known"],
|
|
1024
|
-
standard: ["list_configs", "get_config", "create_config", "update_config", "apply_config", "sync_known", "get_status", "scan_secrets", "list_profiles", "apply_profile", "search_tools", "describe_tools"],
|
|
1086
|
+
standard: ["list_configs", "get_config", "create_config", "update_config", "apply_config", "sync_known", "get_status", "render_template", "scan_secrets", "list_profiles", "apply_profile", "search_tools", "describe_tools"],
|
|
1025
1087
|
full: []
|
|
1026
1088
|
};
|
|
1027
1089
|
var activeProfile = process.env["CONFIGS_PROFILE"] || "full";
|
|
@@ -1038,6 +1100,7 @@ var ALL_LEAN_TOOLS = [
|
|
|
1038
1100
|
{ name: "get_snapshot", inputSchema: { type: "object", properties: { config_id_or_slug: { type: "string" }, version: { type: "number" } }, required: ["config_id_or_slug"] } },
|
|
1039
1101
|
{ name: "get_status", inputSchema: { type: "object", properties: {} } },
|
|
1040
1102
|
{ name: "sync_known", inputSchema: { type: "object", properties: { agent: { type: "string" }, category: { type: "string" } } } },
|
|
1103
|
+
{ name: "render_template", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" }, vars: { type: "object" }, use_env: { type: "boolean" } }, required: ["id_or_slug"] } },
|
|
1041
1104
|
{ name: "scan_secrets", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" }, fix: { type: "boolean" } } } },
|
|
1042
1105
|
{ name: "search_tools", inputSchema: { type: "object", properties: { query: { type: "string" } }, required: ["query"] } },
|
|
1043
1106
|
{ name: "describe_tools", inputSchema: { type: "object", properties: { names: { type: "array", items: { type: "string" } } } } }
|
|
@@ -1146,6 +1209,21 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1146
1209
|
});
|
|
1147
1210
|
return ok(result);
|
|
1148
1211
|
}
|
|
1212
|
+
case "render_template": {
|
|
1213
|
+
const { renderTemplate: renderTemplate2 } = await Promise.resolve().then(() => (init_template(), exports_template));
|
|
1214
|
+
const config = getConfig(args["id_or_slug"]);
|
|
1215
|
+
const vars = args["vars"] || {};
|
|
1216
|
+
if (args["use_env"]) {
|
|
1217
|
+
const { extractTemplateVars: extractTemplateVars2 } = await Promise.resolve().then(() => (init_template(), exports_template));
|
|
1218
|
+
for (const v of extractTemplateVars2(config.content)) {
|
|
1219
|
+
if (!(v.name in vars) && process.env[v.name]) {
|
|
1220
|
+
vars[v.name] = process.env[v.name];
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
const rendered = renderTemplate2(config.content, vars);
|
|
1225
|
+
return ok({ rendered, config_id: config.id, slug: config.slug });
|
|
1226
|
+
}
|
|
1149
1227
|
case "scan_secrets": {
|
|
1150
1228
|
const { scanSecrets: scanSecrets2, redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
|
|
1151
1229
|
const configs = args["id_or_slug"] ? [getConfig(args["id_or_slug"])] : listConfigs({ kind: "file" });
|
|
@@ -1156,8 +1234,8 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
1156
1234
|
if (secrets.length > 0) {
|
|
1157
1235
|
findings.push({ slug: c.slug, secrets: secrets.length, vars: secrets.map((s) => s.varName) });
|
|
1158
1236
|
if (args["fix"]) {
|
|
1159
|
-
const { content, isTemplate } = redactContent2(c.content, fmt);
|
|
1160
|
-
updateConfig(c.id, { content, is_template:
|
|
1237
|
+
const { content, isTemplate: isTemplate2 } = redactContent2(c.content, fmt);
|
|
1238
|
+
updateConfig(c.id, { content, is_template: isTemplate2 });
|
|
1161
1239
|
}
|
|
1162
1240
|
}
|
|
1163
1241
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/configs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.13",
|
|
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",
|