@hasna/configs 0.2.22 → 0.2.24

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 CHANGED
@@ -4119,6 +4119,53 @@ program.command("watch").description("Watch known config files for changes and a
4119
4119
  setInterval(tick, interval);
4120
4120
  await new Promise(() => {});
4121
4121
  });
4122
+ program.command("report").description("Summary of stored configs, drift, and ecosystem health").option("--json", "output as JSON").option("--markdown", "output as markdown").action(async () => {
4123
+ const stats = getConfigStats();
4124
+ const allConfigs = listConfigs();
4125
+ const fileConfigs = allConfigs.filter((c) => c.kind === "file");
4126
+ const refConfigs = allConfigs.filter((c) => c.kind === "reference");
4127
+ const templates = allConfigs.filter((c) => c.is_template);
4128
+ const profiles = listProfiles();
4129
+ let drifted = 0, missing = 0;
4130
+ for (const c of fileConfigs) {
4131
+ if (!c.target_path)
4132
+ continue;
4133
+ const abs = expandPath(c.target_path);
4134
+ if (!existsSync7(abs)) {
4135
+ missing++;
4136
+ continue;
4137
+ }
4138
+ const disk = readFileSync5(abs, "utf-8");
4139
+ const { content: redactedDisk } = redactContent(disk, c.format);
4140
+ if (redactedDisk !== c.content)
4141
+ drifted++;
4142
+ }
4143
+ const byAgent = {};
4144
+ for (const c of allConfigs)
4145
+ byAgent[c.agent] = (byAgent[c.agent] || 0) + 1;
4146
+ const projectConfigs = allConfigs.filter((c) => c.target_path && !c.target_path.startsWith("~/."));
4147
+ console.log(chalk.bold(`configs report
4148
+ `));
4149
+ console.log(` Total: ${allConfigs.length} configs (${fileConfigs.length} files, ${refConfigs.length} references)`);
4150
+ console.log(` Templates: ${templates.length} (with {{VAR}} placeholders)`);
4151
+ console.log(` Profiles: ${profiles.length}`);
4152
+ console.log(` Drift: ${drifted === 0 ? chalk.green("0 \u2713") : chalk.yellow(String(drifted))} drifted, ${missing} missing`);
4153
+ console.log(` Secrets: ${chalk.green("0 \u2713")} (redacted on ingest)
4154
+ `);
4155
+ console.log(chalk.cyan(" By agent:"));
4156
+ for (const [agent, count] of Object.entries(byAgent).sort((a, b) => b[1] - a[1])) {
4157
+ console.log(` ${agent.padEnd(10)} ${count}`);
4158
+ }
4159
+ console.log(chalk.cyan(`
4160
+ By category:`));
4161
+ for (const [cat, count] of Object.entries(stats).filter(([k]) => k !== "total").sort((a, b) => b[1] - a[1])) {
4162
+ console.log(` ${cat.padEnd(16)} ${count}`);
4163
+ }
4164
+ if (projectConfigs.length > 0) {
4165
+ console.log(chalk.cyan(`
4166
+ Project configs: ${projectConfigs.length}`));
4167
+ }
4168
+ });
4122
4169
  program.command("clean").description("Remove configs from DB whose target files no longer exist on disk").option("--dry-run", "show what would be removed").action(async (opts) => {
4123
4170
  const configs = listConfigs({ kind: "file" });
4124
4171
  let removed = 0;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=apply-batch.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-batch.test.d.ts","sourceRoot":"","sources":["../../src/lib/apply-batch.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sync-dir.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-dir.test.d.ts","sourceRoot":"","sources":["../../src/lib/sync-dir.test.ts"],"names":[],"mappings":""}
package/dist/mcp/index.js CHANGED
@@ -177,6 +177,16 @@ var init_database = __esm(() => {
177
177
  });
178
178
 
179
179
  // src/db/configs.ts
180
+ var exports_configs = {};
181
+ __export(exports_configs, {
182
+ updateConfig: () => updateConfig,
183
+ listConfigs: () => listConfigs,
184
+ getConfigStats: () => getConfigStats,
185
+ getConfigById: () => getConfigById,
186
+ getConfig: () => getConfig,
187
+ deleteConfig: () => deleteConfig,
188
+ createConfig: () => createConfig
189
+ });
180
190
  function rowToConfig(row) {
181
191
  return {
182
192
  ...row,
@@ -327,6 +337,11 @@ function updateConfig(idOrSlug, input, db) {
327
337
  d.run(`UPDATE configs SET ${updates.join(", ")} WHERE id = ?`, params);
328
338
  return getConfigById(existing.id, d);
329
339
  }
340
+ function deleteConfig(idOrSlug, db) {
341
+ const d = db || getDatabase();
342
+ const existing = getConfig(idOrSlug, d);
343
+ d.run("DELETE FROM configs WHERE id = ?", [existing.id]);
344
+ }
330
345
  function getConfigStats(db) {
331
346
  const d = db || getDatabase();
332
347
  const rows = d.query("SELECT category, COUNT(*) as count FROM configs GROUP BY category").all();
@@ -997,7 +1012,7 @@ var init_sync = __esm(() => {
997
1012
  var require_package = __commonJS((exports, module) => {
998
1013
  module.exports = {
999
1014
  name: "@hasna/configs",
1000
- version: "0.2.22",
1015
+ version: "0.2.24",
1001
1016
  description: "AI coding agent configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + REST API + Dashboard.",
1002
1017
  type: "module",
1003
1018
  main: "dist/index.js",
@@ -1200,6 +1215,7 @@ var ALL_LEAN_TOOLS = [
1200
1215
  { name: "get_config", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" } }, required: ["id_or_slug"] } },
1201
1216
  { name: "create_config", inputSchema: { type: "object", properties: { name: { type: "string" }, content: { type: "string" }, category: { type: "string" }, agent: { type: "string" }, target_path: { type: "string" }, kind: { type: "string" }, format: { type: "string" }, tags: { type: "array", items: { type: "string" } }, description: { type: "string" }, is_template: { type: "boolean" } }, required: ["name", "content", "category"] } },
1202
1217
  { name: "update_config", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" }, content: { type: "string" }, name: { type: "string" }, tags: { type: "array", items: { type: "string" } }, description: { type: "string" }, category: { type: "string" }, agent: { type: "string" }, target_path: { type: "string" } }, required: ["id_or_slug"] } },
1218
+ { name: "delete_config", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" } }, required: ["id_or_slug"] } },
1203
1219
  { name: "apply_config", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" }, dry_run: { type: "boolean" } }, required: ["id_or_slug"] } },
1204
1220
  { name: "sync_directory", inputSchema: { type: "object", properties: { dir: { type: "string" }, direction: { type: "string" } }, required: ["dir"] } },
1205
1221
  { name: "list_profiles", inputSchema: { type: "object", properties: {} } },
@@ -1266,6 +1282,11 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1266
1282
  });
1267
1283
  return ok({ id: c.id, slug: c.slug, version: c.version });
1268
1284
  }
1285
+ case "delete_config": {
1286
+ const { deleteConfig: deleteConfig2 } = await Promise.resolve().then(() => (init_configs(), exports_configs));
1287
+ deleteConfig2(args["id_or_slug"]);
1288
+ return ok({ deleted: true });
1289
+ }
1269
1290
  case "apply_config": {
1270
1291
  const config = getConfig(args["id_or_slug"]);
1271
1292
  const result = await applyConfig(config, { dryRun: args["dry_run"] });
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;AAkSA,wBAAgE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":";;;;;;AAsVA,wBAAgE"}