@hasna/instructions 0.4.1 → 0.4.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 CHANGED
@@ -2112,21 +2112,17 @@ var init_types = __esm(() => {
2112
2112
 
2113
2113
  // src/db/database.ts
2114
2114
  import { Database } from "bun:sqlite";
2115
- import { cpSync, existsSync as existsSync2, mkdirSync, rmSync, statSync } from "fs";
2115
+ import { existsSync as existsSync2, mkdirSync, rmSync } from "fs";
2116
2116
  import { join as join2 } from "path";
2117
2117
  import { randomUUID as randomUUID3 } from "crypto";
2118
2118
  function getDbPath() {
2119
- if (process.env["HASNA_CONFIGS_DB_PATH"]) {
2120
- return process.env["HASNA_CONFIGS_DB_PATH"];
2119
+ if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
2120
+ return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
2121
2121
  }
2122
- if (process.env["CONFIGS_DB_PATH"]) {
2123
- return process.env["CONFIGS_DB_PATH"];
2124
- }
2125
- migrateDotfile();
2126
2122
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
2127
- const dir = join2(home, ".hasna", "configs");
2123
+ const dir = join2(home, ".hasna", "instructions");
2128
2124
  mkdirSync(dir, { recursive: true });
2129
- return join2(dir, "configs.db");
2125
+ return join2(dir, "instructions.db");
2130
2126
  }
2131
2127
  function uuid() {
2132
2128
  return randomUUID3();
@@ -2212,24 +2208,6 @@ function insertFeedback(input, db) {
2212
2208
  const d = db || getDatabase();
2213
2209
  d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
2214
2210
  }
2215
- function migrateDotfile() {
2216
- const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
2217
- const oldDirs = [join2(home, ".open-configs"), join2(home, ".configs")];
2218
- const newDir = join2(home, ".hasna", "configs");
2219
- if (existsSync2(newDir))
2220
- return;
2221
- for (const oldDir of oldDirs) {
2222
- if (!existsSync2(oldDir))
2223
- continue;
2224
- try {
2225
- if (!statSync(oldDir).isDirectory())
2226
- continue;
2227
- mkdirSync(join2(home, ".hasna"), { recursive: true });
2228
- cpSync(oldDir, newDir, { recursive: true, force: false });
2229
- return;
2230
- } catch {}
2231
- }
2232
- }
2233
2211
  var MIGRATIONS, _db = null;
2234
2212
  var init_database = __esm(() => {
2235
2213
  MIGRATIONS = [
@@ -3594,7 +3572,7 @@ var init_redact = __esm(() => {
3594
3572
  });
3595
3573
 
3596
3574
  // src/lib/sync-dir.ts
3597
- import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync2, statSync as statSync2 } from "fs";
3575
+ import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync2, statSync } from "fs";
3598
3576
  import { join as join4, relative } from "path";
3599
3577
  import { homedir as homedir4 } from "os";
3600
3578
  function shouldSkip(p) {
@@ -3605,7 +3583,7 @@ async function syncFromDir(dir, opts = {}) {
3605
3583
  const absDir = expandPath(dir);
3606
3584
  if (!existsSync5(absDir))
3607
3585
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
3608
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join4(absDir, f)).filter((f) => statSync2(f).isFile());
3586
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join4(absDir, f)).filter((f) => statSync(f).isFile());
3609
3587
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
3610
3588
  const home = homedir4();
3611
3589
  const allConfigs = await store.listConfigs();
@@ -4508,7 +4486,7 @@ var init_package_manager_guard = __esm(() => {
4508
4486
  ];
4509
4487
  });
4510
4488
 
4511
- // node_modules/@hasna/events/dist/commander.js
4489
+ // node_modules/.pnpm/@hasna+events@0.1.13/node_modules/@hasna/events/dist/commander.js
4512
4490
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
4513
4491
  import { existsSync } from "fs";
4514
4492
  import { homedir } from "os";
@@ -4525,29 +4503,83 @@ function getPathValue(input, path) {
4525
4503
  return;
4526
4504
  }, input);
4527
4505
  }
4528
- function wildcardToRegExp(pattern) {
4529
- const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*");
4530
- return new RegExp(`^${escaped}$`);
4506
+ function getFieldValues(input, path) {
4507
+ const values = [];
4508
+ const push = (value) => {
4509
+ if (!values.some((item) => Object.is(item, value)))
4510
+ values.push(value);
4511
+ };
4512
+ if (path.includes(".") && path in input)
4513
+ push(input[path]);
4514
+ const nestedValue = getPathValue(input, path);
4515
+ if (nestedValue !== undefined || !path.includes("."))
4516
+ push(nestedValue);
4517
+ return values;
4518
+ }
4519
+ function wildcardToRegExp(pattern, options = {}) {
4520
+ let body = "";
4521
+ for (let index = 0;index < pattern.length; index += 1) {
4522
+ const char = pattern[index];
4523
+ if (char === "*") {
4524
+ if (pattern[index + 1] === "*") {
4525
+ body += ".*";
4526
+ index += 1;
4527
+ } else {
4528
+ body += options.segmentSafe ? "[^/]*" : ".*";
4529
+ }
4530
+ } else {
4531
+ body += char.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
4532
+ }
4533
+ }
4534
+ return new RegExp(`^${body}$`);
4531
4535
  }
4532
- function matchString(value, matcher) {
4536
+ function matchString(value, matcher, options = {}) {
4533
4537
  if (matcher === undefined)
4534
4538
  return true;
4535
4539
  if (value === undefined)
4536
4540
  return false;
4537
4541
  const matchers = Array.isArray(matcher) ? matcher : [matcher];
4538
- return matchers.some((item) => wildcardToRegExp(item).test(value));
4542
+ return matchers.some((item) => wildcardToRegExp(item, options).test(value));
4539
4543
  }
4540
4544
  function matchRecord(input, matcher) {
4541
4545
  if (!matcher)
4542
4546
  return true;
4543
4547
  return Object.entries(matcher).every(([path, expected]) => {
4544
- const actual = getPathValue(input, path);
4545
- if (typeof expected === "string" || Array.isArray(expected)) {
4546
- return matchString(actual === undefined ? undefined : String(actual), expected);
4547
- }
4548
- return actual === expected;
4548
+ const actualValues = getFieldValues(input, path);
4549
+ return matchField(actualValues, expected, path);
4549
4550
  });
4550
4551
  }
4552
+ function matchField(actualValues, expected, path) {
4553
+ if (isNegativeMatcher(expected)) {
4554
+ return !actualValues.some((actual) => matchPositiveField(actual, expected.not, path));
4555
+ }
4556
+ return actualValues.some((actual) => matchPositiveField(actual, expected, path));
4557
+ }
4558
+ function matchPositiveField(actual, expected, path) {
4559
+ if (typeof expected === "string" || Array.isArray(expected)) {
4560
+ return stringCandidates(actual).some((candidate) => matchString(candidate, expected, {
4561
+ segmentSafe: path.endsWith("_path") || path.endsWith(".path")
4562
+ }));
4563
+ }
4564
+ if (Array.isArray(actual)) {
4565
+ return actual.some((item) => item === expected);
4566
+ }
4567
+ return actual === expected;
4568
+ }
4569
+ function stringCandidates(actual) {
4570
+ if (actual === undefined)
4571
+ return [];
4572
+ if (Array.isArray(actual)) {
4573
+ return actual.flatMap((item) => isPrimitiveFieldValue(item) ? [String(item)] : []);
4574
+ }
4575
+ return [String(actual)];
4576
+ }
4577
+ function isPrimitiveFieldValue(value) {
4578
+ return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
4579
+ }
4580
+ function isNegativeMatcher(value) {
4581
+ return Boolean(value && typeof value === "object" && !Array.isArray(value) && "not" in value);
4582
+ }
4551
4583
  function eventMatchesFilter(event, filter) {
4552
4584
  return matchString(event.source, filter.source) && matchString(event.type, filter.type) && matchString(event.subject, filter.subject) && matchString(event.severity, filter.severity) && matchRecord(event.data, filter.data) && matchRecord(event.metadata, filter.metadata);
4553
4585
  }
@@ -4563,6 +4595,14 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
4563
4595
  function getEventsDataDir(override) {
4564
4596
  return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
4565
4597
  }
4598
+ function getActiveEventsDirEnv() {
4599
+ if (process.env[HASNA_EVENTS_DIR_ENV])
4600
+ return HASNA_EVENTS_DIR_ENV;
4601
+ if (process.env[HASNA_EVENTS_HOME_ENV])
4602
+ return HASNA_EVENTS_HOME_ENV;
4603
+ return null;
4604
+ }
4605
+
4566
4606
  class JsonEventsStore {
4567
4607
  dataDir;
4568
4608
  channelsPath;
@@ -4674,6 +4714,52 @@ class JsonEventsStore {
4674
4714
  });
4675
4715
  }
4676
4716
  }
4717
+ async function getEventsStatus(dataDir) {
4718
+ const store = new JsonEventsStore(dataDir);
4719
+ await store.init();
4720
+ const [channels, events, deliveries] = await Promise.all([
4721
+ store.listChannels(),
4722
+ store.listEvents(),
4723
+ store.listDeliveries()
4724
+ ]);
4725
+ const transports = channels.reduce((counts, channel) => {
4726
+ counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
4727
+ return counts;
4728
+ }, {});
4729
+ return {
4730
+ service: "events",
4731
+ schemaVersion: "1.0",
4732
+ dataDir: store.dataDir,
4733
+ env: {
4734
+ primary: HASNA_EVENTS_DIR_ENV,
4735
+ fallback: HASNA_EVENTS_HOME_ENV,
4736
+ active: getActiveEventsDirEnv()
4737
+ },
4738
+ files: {
4739
+ channels: statusFile(store.dataDir, "channels.json", channels.length),
4740
+ events: statusFile(store.dataDir, "events.json", events.length),
4741
+ deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
4742
+ },
4743
+ counts: {
4744
+ channels: channels.length,
4745
+ enabledChannels: channels.filter((channel) => channel.enabled).length,
4746
+ disabledChannels: channels.filter((channel) => !channel.enabled).length,
4747
+ events: events.length,
4748
+ deliveries: deliveries.length
4749
+ },
4750
+ transports,
4751
+ safety: {
4752
+ includesEventPayloads: false,
4753
+ includesWebhookSecrets: false,
4754
+ listOutputsRedactSecrets: true,
4755
+ statusOutputIsMetadataOnly: true
4756
+ }
4757
+ };
4758
+ }
4759
+ function statusFile(dataDir, fileName, records) {
4760
+ const path = join(dataDir, fileName);
4761
+ return { path, exists: existsSync(path), records };
4762
+ }
4677
4763
  var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
4678
4764
  function buildSignatureBase(timestamp, body) {
4679
4765
  return `${timestamp}.${body}`;
@@ -4899,7 +4985,7 @@ class EventsClient {
4899
4985
  }
4900
4986
  return deliveries;
4901
4987
  }
4902
- async testChannel(id, input = {}) {
4988
+ async matchChannel(id, input = {}) {
4903
4989
  const channel = await this.store.getChannel(id);
4904
4990
  if (!channel)
4905
4991
  throw new Error(`Channel not found: ${id}`);
@@ -4916,6 +5002,34 @@ class EventsClient {
4916
5002
  time: input.time,
4917
5003
  id: input.id
4918
5004
  });
5005
+ const matched = channelMatchesEvent(channel, event);
5006
+ return {
5007
+ channelId: channel.id,
5008
+ matched,
5009
+ event,
5010
+ filters: channel.filters,
5011
+ reason: matched ? undefined : channel.enabled ? "event did not match channel filters" : "channel is disabled"
5012
+ };
5013
+ }
5014
+ async testChannel(id, input = {}, options = {}) {
5015
+ const channel = await this.store.getChannel(id);
5016
+ if (!channel)
5017
+ throw new Error(`Channel not found: ${id}`);
5018
+ const match = await this.matchChannel(id, input);
5019
+ const event = match.event;
5020
+ if (options.honorFilters && !match.matched) {
5021
+ const timestamp = new Date().toISOString();
5022
+ const result2 = createDeliveryResult(event, channel, [{
5023
+ attempt: 1,
5024
+ status: "skipped",
5025
+ startedAt: timestamp,
5026
+ completedAt: timestamp,
5027
+ error: match.reason
5028
+ }]);
5029
+ result2.metadata = { reason: "filter_mismatch" };
5030
+ await this.store.appendDelivery(result2);
5031
+ return result2;
5032
+ }
4919
5033
  const eventForChannel = await this.applyRedaction(event, channel);
4920
5034
  const result = await this.deliverWithRetry(eventForChannel, channel);
4921
5035
  await this.store.appendDelivery(result);
@@ -5026,6 +5140,76 @@ function normalizeRetryPolicy(policy) {
5026
5140
  multiplier: Math.max(1, policy?.multiplier ?? 2)
5027
5141
  };
5028
5142
  }
5143
+ function parseFieldMatchers(values, label, typed = false) {
5144
+ if (!values?.length)
5145
+ return;
5146
+ const result = {};
5147
+ for (const value of values) {
5148
+ const parsed = parseMatcherExpression(value, label);
5149
+ const path = parsed.path;
5150
+ if (path in result)
5151
+ throw new Error(`Duplicate ${label} filter path: ${path}`);
5152
+ const matcherValue = typed ? parseTypedMatcherValue(parsed.rawValue, label) : parsed.rawValue;
5153
+ result[path] = parsed.negated ? { not: matcherValue } : matcherValue;
5154
+ }
5155
+ return result;
5156
+ }
5157
+ function parseFilterOptions(options) {
5158
+ const filter2 = {};
5159
+ if (options.source)
5160
+ filter2.source = options.source;
5161
+ if (options.type)
5162
+ filter2.type = options.type;
5163
+ if (options.subject)
5164
+ filter2.subject = options.subject;
5165
+ if (options.severity)
5166
+ filter2.severity = options.severity;
5167
+ const data = mergeMatchers(parseFieldMatchers(options.data, "data"), parseFieldMatchers(options.dataJson, "data-json", true));
5168
+ const metadata = mergeMatchers(parseFieldMatchers(options.metadata, "metadata"), parseFieldMatchers(options.metadataJson, "metadata-json", true));
5169
+ if (Object.keys(data).length > 0)
5170
+ filter2.data = data;
5171
+ if (Object.keys(metadata).length > 0)
5172
+ filter2.metadata = metadata;
5173
+ return Object.keys(filter2).length > 0 ? [filter2] : undefined;
5174
+ }
5175
+ function mergeMatchers(...records) {
5176
+ const result = {};
5177
+ for (const record of records) {
5178
+ if (!record)
5179
+ continue;
5180
+ for (const [path, value] of Object.entries(record)) {
5181
+ if (path in result)
5182
+ throw new Error(`Duplicate filter path: ${path}`);
5183
+ result[path] = value;
5184
+ }
5185
+ }
5186
+ return result;
5187
+ }
5188
+ function parseTypedMatcherValue(value, label) {
5189
+ const parsed = JSON.parse(value);
5190
+ if (parsed === null || typeof parsed === "string" || typeof parsed === "number" || typeof parsed === "boolean" || Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
5191
+ return parsed;
5192
+ }
5193
+ throw new Error(`${label} filter JSON values must be string, string[], number, boolean, or null`);
5194
+ }
5195
+ function parseMatcherExpression(value, label) {
5196
+ const negativeSeparator = value.indexOf("!=");
5197
+ if (negativeSeparator > 0) {
5198
+ return {
5199
+ path: value.slice(0, negativeSeparator),
5200
+ rawValue: value.slice(negativeSeparator + 2),
5201
+ negated: true
5202
+ };
5203
+ }
5204
+ const separator = value.indexOf("=");
5205
+ if (separator <= 0)
5206
+ throw new Error(`Invalid ${label} filter, expected path=value or path!=value: ${value}`);
5207
+ return {
5208
+ path: value.slice(0, separator),
5209
+ rawValue: value.slice(separator + 1),
5210
+ negated: false
5211
+ };
5212
+ }
5029
5213
  function parseJsonObject(value, fallback) {
5030
5214
  if (!value)
5031
5215
  return fallback;
@@ -5047,18 +5231,6 @@ function parseHeaders(values) {
5047
5231
  }
5048
5232
  return headers;
5049
5233
  }
5050
- function parseFilter(options) {
5051
- const filter2 = {};
5052
- if (options.source)
5053
- filter2.source = options.source;
5054
- if (options.type)
5055
- filter2.type = options.type;
5056
- if (options.subject)
5057
- filter2.subject = options.subject;
5058
- if (options.severity)
5059
- filter2.severity = options.severity;
5060
- return Object.keys(filter2).length > 0 ? [filter2] : undefined;
5061
- }
5062
5234
  function createClient(options) {
5063
5235
  if (options.createClient)
5064
5236
  return options.createClient();
@@ -5076,16 +5248,16 @@ function hasJsonOption(options) {
5076
5248
  function wantsJson(actionOptions, command) {
5077
5249
  return hasJsonOption(actionOptions) || hasJsonOption(command);
5078
5250
  }
5079
- function registerWebhookCommands(program, options) {
5080
- const webhooks = program.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
5081
- webhooks.command("add").description("Add or replace a webhook or command subscription").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Subscription/channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
5251
+ function registerChannelCommands(program, options) {
5252
+ const channels = program.command(options.channelsCommandName ?? "channels").description("Manage Hasna event channels");
5253
+ channels.command("add").description("Add or replace a channel").argument("<target>", "Webhook URL or command binary").requiredOption("--id <id>", "Channel identifier").option("--transport <kind>", "Transport kind: webhook or command", "webhook").option("--name <name>", "Display name").option("--type <pattern>", "Event type filter, e.g. todos.task.*").option("--source <pattern>", "Event source filter").option("--subject <pattern>", "Event subject filter").option("--severity <pattern>", "Event severity filter").option("--data <path=value...>", "Event data field filter; string values, path!=value negatives, array-member matching, dot paths, * segment wildcard, ** recursive wildcard", collectValues, []).option("--metadata <path=value...>", "Event metadata field filter; string values, path!=value negatives, array-member matching, dot paths, * segment wildcard, ** recursive wildcard", collectValues, []).option("--data-json <path=json...>", "Event data field filter with typed JSON value; path!=json negatives supported", collectValues, []).option("--metadata-json <path=json...>", "Event metadata field filter with typed JSON value; path!=json negatives supported", collectValues, []).option("--secret <secret>", "Webhook HMAC secret").option("--header <name=value...>", "Webhook header", collectValues, []).option("--arg <arg...>", "Command argument", collectValues, []).option("--timeout-ms <ms>", "Transport timeout in milliseconds", parseNumber).option("--retry-attempts <n>", "Maximum delivery attempts", parseNumber).option("--retry-backoff-ms <ms>", "Initial retry backoff in milliseconds", parseNumber).option("--redact <path...>", "Event field path to redact before delivery", collectValues, []).option("--disabled", "Create channel disabled", false).option("-j, --json", "Print JSON output", false).action(async (target, actionOptions, command) => {
5082
5254
  const timestamp = new Date().toISOString();
5083
5255
  const channel = {
5084
5256
  id: actionOptions.id,
5085
5257
  name: actionOptions.name,
5086
5258
  enabled: !actionOptions.disabled,
5087
5259
  transport: actionOptions.transport,
5088
- filters: parseFilter(actionOptions),
5260
+ filters: parseFilterOptions(actionOptions),
5089
5261
  retry: actionOptions.retryAttempts || actionOptions.retryBackoffMs ? { maxAttempts: actionOptions.retryAttempts, backoffMs: actionOptions.retryBackoffMs } : undefined,
5090
5262
  redact: actionOptions.redact?.length ? { paths: actionOptions.redact } : undefined,
5091
5263
  createdAt: timestamp,
@@ -5101,35 +5273,51 @@ function registerWebhookCommands(program, options) {
5101
5273
  const saved = await createClient(options).addChannel(channel);
5102
5274
  print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
5103
5275
  });
5104
- webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
5105
- const channels = await createClient(options).listChannels();
5276
+ channels.command("list").description("List configured channels").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
5277
+ const channels2 = await createClient(options).listChannels();
5106
5278
  if (wantsJson(actionOptions, command)) {
5107
- console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
5279
+ console.log(JSON.stringify(sanitizeChannelsForOutput(channels2), null, 2));
5108
5280
  return;
5109
5281
  }
5110
- if (!channels.length) {
5282
+ if (!channels2.length) {
5111
5283
  console.log("No channels configured.");
5112
5284
  return;
5113
5285
  }
5114
- for (const channel of channels) {
5286
+ for (const channel of channels2) {
5115
5287
  console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
5116
5288
  }
5117
5289
  });
5118
- webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
5290
+ channels.command("status").description("Show events channel storage status").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
5291
+ const status = await getEventsStatus(options.dataDir);
5292
+ print(status, wantsJson(actionOptions, command), `events dataDir: ${status.dataDir}`);
5293
+ });
5294
+ channels.command("remove").description("Remove a channel").argument("<id>", "Channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
5119
5295
  const removed = await createClient(options).removeChannel(id);
5120
5296
  print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
5121
5297
  });
5122
- webhooks.command("test").description("Send a test event to one subscription").argument("<id>", "Subscription/channel identifier").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
5298
+ channels.command("test").description("Send a test event to one channel").argument("<id>", "Channel identifier").option("--source <source>", "Event source override").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events test delivery").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("--honor-filters", "Skip delivery when the sample event does not match channel filters", false).option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
5123
5299
  const result = await createClient(options).testChannel(id, {
5124
- source: options.source,
5300
+ source: actionOptions.source ?? options.source,
5125
5301
  type: actionOptions.type,
5126
5302
  subject: actionOptions.subject ?? id,
5127
5303
  message: actionOptions.message,
5128
- data: parseJsonObject(actionOptions.data, { test: true })
5129
- });
5304
+ data: parseJsonObject(actionOptions.data, { test: true }),
5305
+ metadata: parseJsonObject(actionOptions.metadata, {})
5306
+ }, { honorFilters: actionOptions.honorFilters });
5130
5307
  print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
5131
5308
  });
5132
- return webhooks;
5309
+ channels.command("match").description("Check whether a sample event matches one channel without delivering").argument("<id>", "Channel identifier").option("--source <source>", "Event source override").option("--type <type>", "Event type", "events.test").option("--subject <subject>", "Event subject").option("--message <message>", "Event message", "Hasna events match preview").option("--data <json>", "Event data JSON object").option("--metadata <json>", "Event metadata JSON object").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
5310
+ const result = await createClient(options).matchChannel(id, {
5311
+ source: actionOptions.source ?? options.source,
5312
+ type: actionOptions.type,
5313
+ subject: actionOptions.subject ?? id,
5314
+ message: actionOptions.message,
5315
+ data: parseJsonObject(actionOptions.data, { test: true }),
5316
+ metadata: parseJsonObject(actionOptions.metadata, {})
5317
+ });
5318
+ print(result, wantsJson(actionOptions, command), `${result.matched ? "matched" : "skipped"}: ${result.channelId}`);
5319
+ });
5320
+ return channels;
5133
5321
  }
5134
5322
  function registerEventCommands(program, options) {
5135
5323
  const events = program.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
@@ -5177,7 +5365,7 @@ function registerEventCommands(program, options) {
5177
5365
  return events;
5178
5366
  }
5179
5367
  function registerEventsCommands(program, options) {
5180
- registerWebhookCommands(program, options);
5368
+ registerChannelCommands(program, options);
5181
5369
  registerEventCommands(program, options);
5182
5370
  }
5183
5371
  function parseNumber(value) {
@@ -5345,7 +5533,7 @@ import { dirname as dirname3, isAbsolute as isAbsolute2, join as join9, parse as
5345
5533
 
5346
5534
  // src/lib/session-render.ts
5347
5535
  import { createHash } from "crypto";
5348
- import { existsSync as existsSync9, readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync3 } from "fs";
5536
+ import { existsSync as existsSync9, readFileSync as readFileSync5, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
5349
5537
  import { homedir as homedir5 } from "os";
5350
5538
  import { basename as basename4, dirname as dirname2, extname as extname3, isAbsolute, join as join8, parse, posix, relative as relative2, resolve as resolve4 } from "path";
5351
5539
  var CODEWITH_NATIVE_IMPORTS_ENV = "HASNA_CONFIGS_CODEWITH_NATIVE_IMPORTS";
@@ -6111,7 +6299,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
6111
6299
  }
6112
6300
  return;
6113
6301
  }
6114
- const stat = statSync3(resolvedPath);
6302
+ const stat = statSync2(resolvedPath);
6115
6303
  if (!stat.isFile()) {
6116
6304
  throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
6117
6305
  }
@@ -6748,14 +6936,12 @@ import { existsSync as existsSync11, readFileSync as readFileSync7 } from "fs";
6748
6936
  var PACKAGE_NAME = "@hasna/instructions";
6749
6937
  var PACKAGE_VERSION = "0.3.0";
6750
6938
  function activeDatabaseEnv() {
6751
- if (process.env["HASNA_CONFIGS_DB_PATH"])
6752
- return "HASNA_CONFIGS_DB_PATH";
6753
- if (process.env["CONFIGS_DB_PATH"])
6754
- return "CONFIGS_DB_PATH";
6939
+ if (process.env["HASNA_INSTRUCTIONS_DB_PATH"])
6940
+ return "HASNA_INSTRUCTIONS_DB_PATH";
6755
6941
  return null;
6756
6942
  }
6757
6943
  function configuredDatabaseKind() {
6758
- const value = process.env["HASNA_CONFIGS_DB_PATH"] ?? process.env["CONFIGS_DB_PATH"] ?? "";
6944
+ const value = process.env["HASNA_INSTRUCTIONS_DB_PATH"] ?? "";
6759
6945
  return value === ":memory:" || value.startsWith("file::memory:") ? "memory" : "file";
6760
6946
  }
6761
6947
  function countBy(items, getValue) {
@@ -6829,8 +7015,7 @@ async function getConfigsStatus(store = resolveConfigStore()) {
6829
7015
  },
6830
7016
  env: {
6831
7017
  database: {
6832
- primary: "HASNA_CONFIGS_DB_PATH",
6833
- fallback: "CONFIGS_DB_PATH",
7018
+ primary: "HASNA_INSTRUCTIONS_DB_PATH",
6834
7019
  active: activeDatabaseEnv(),
6835
7020
  kind: configuredDatabaseKind()
6836
7021
  }
@@ -7123,14 +7308,14 @@ program.command("list").alias("ls").description("List stored configs").option("-
7123
7308
  tags: opts.tag ? [opts.tag] : undefined,
7124
7309
  search: opts.search
7125
7310
  });
7126
- if (configs.length === 0) {
7127
- console.log(chalk.dim("No configs found."));
7128
- return;
7129
- }
7130
7311
  if (fmt === "json") {
7131
7312
  printJson(configs);
7132
7313
  return;
7133
7314
  }
7315
+ if (configs.length === 0) {
7316
+ console.log(chalk.dim("No configs found."));
7317
+ return;
7318
+ }
7134
7319
  const page = paginate(configs, { limit: opts.limit, cursor: opts.cursor });
7135
7320
  if (fmt === "compact") {
7136
7321
  printConfigRows(page.items);
@@ -7333,9 +7518,9 @@ program.command("import <file>").description("Import configs from a tar.gz bundl
7333
7518
  });
7334
7519
  program.command("whoami").description("Show setup summary").action(async () => {
7335
7520
  const store = resolveConfigStore();
7336
- const dbPath = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["CONFIGS_DB_PATH"] || join11(homedir7(), ".hasna", "configs", "configs.db");
7521
+ const dbPath = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join11(homedir7(), ".hasna", "instructions", "instructions.db");
7337
7522
  const stats = await store.getConfigStats();
7338
- console.log(chalk.bold("@hasna/configs") + chalk.dim(" v" + pkg.version));
7523
+ console.log(chalk.bold("@hasna/instructions") + chalk.dim(" v" + pkg.version));
7339
7524
  console.log(chalk.cyan(isCloudMode() ? "API:" : "DB:") + " " + dbPath);
7340
7525
  console.log(chalk.cyan("Total configs:") + " " + (stats["total"] || 0));
7341
7526
  console.log();
@@ -7359,14 +7544,14 @@ profileCmd.command("list").description("List all profiles").option("--brief", "c
7359
7544
  const fmt = opts.json ? "json" : opts.verbose ? "table" : opts.brief ? "compact" : opts.format;
7360
7545
  const store = resolveConfigStore();
7361
7546
  const profiles = await store.listProfiles();
7362
- if (profiles.length === 0) {
7363
- console.log(chalk.dim("No profiles."));
7364
- return;
7365
- }
7366
7547
  if (fmt === "json") {
7367
7548
  printJson(profiles);
7368
7549
  return;
7369
7550
  }
7551
+ if (profiles.length === 0) {
7552
+ console.log(chalk.dim("No profiles."));
7553
+ return;
7554
+ }
7370
7555
  const page = paginate(profiles, { limit: opts.limit, cursor: opts.cursor });
7371
7556
  if (fmt === "compact")
7372
7557
  console.log(`${pad("slug", 28)} ${pad("configs", 8)} ${pad("match", 36)} vars`);
@@ -7798,7 +7983,7 @@ program.command("package-manager-scan [paths...]").description("Scan package-man
7798
7983
  }
7799
7984
  });
7800
7985
  var mcpCmd = program.command("mcp").description("Install/remove MCP server for AI agents");
7801
- 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) => {
7986
+ 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 INSTRUCTIONS_PROFILE (minimal|standard|full)", "standard").action(async (opts) => {
7802
7987
  const targets = opts.all ? ["claude", "codex", "gemini"] : [
7803
7988
  ...opts.claude ? ["claude"] : [],
7804
7989
  ...opts.codex ? ["codex"] : [],
@@ -7813,7 +7998,7 @@ mcpCmd.command("install").alias("add").description("Install configs MCP server i
7813
7998
  const { vars } = await getMachineProfileContext({}, resolveConfigStore());
7814
7999
  const mcpBinary = `${vars["BUN_BIN_DIR"]}/configs-mcp`;
7815
8000
  if (target === "claude") {
7816
- const cmd = opts.profile && opts.profile !== "full" ? ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "env", `CONFIGS_PROFILE=${opts.profile}`, mcpBinary] : ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", mcpBinary];
8001
+ const cmd = opts.profile && opts.profile !== "full" ? ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "env", `INSTRUCTIONS_PROFILE=${opts.profile}`, mcpBinary] : ["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", mcpBinary];
7817
8002
  const proc = Bun.spawn(cmd, { stdout: "inherit", stderr: "inherit" });
7818
8003
  await proc.exited;
7819
8004
  console.log(chalk.green("\u2713") + " Installed into Claude Code");
@@ -7870,7 +8055,7 @@ program.command("init").description("First-time setup: sync all known configs, c
7870
8055
  await store.reset();
7871
8056
  console.log(chalk.dim("Reset local store."));
7872
8057
  }
7873
- console.log(chalk.bold(`@hasna/configs \u2014 initializing
8058
+ console.log(chalk.bold(`@hasna/instructions \u2014 initializing
7874
8059
  `));
7875
8060
  const result = await syncKnown({ store });
7876
8061
  console.log(chalk.green("\u2713") + ` Synced: +${result.added} updated:${result.updated} unchanged:${result.unchanged}`);
@@ -7914,7 +8099,7 @@ DB stats:`));
7914
8099
  if (count > 0)
7915
8100
  console.log(` ${key.padEnd(18)} ${count}`);
7916
8101
  }
7917
- const location = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["CONFIGS_DB_PATH"] || join11(homedir7(), ".hasna", "configs", "configs.db");
8102
+ const location = isCloudMode() ? `${process.env["HASNA_INSTRUCTIONS_API_URL"]}/v1 (self_hosted)` : process.env["HASNA_INSTRUCTIONS_DB_PATH"] || join11(homedir7(), ".hasna", "instructions", "instructions.db");
7918
8103
  console.log(chalk.dim(`
7919
8104
  ${isCloudMode() ? "API" : "DB"}: ${location}`));
7920
8105
  });
@@ -7924,7 +8109,7 @@ program.command("status").description("Health check: total configs, drift from d
7924
8109
  printJson(status);
7925
8110
  return;
7926
8111
  }
7927
- console.log(chalk.bold("@hasna/configs") + chalk.dim(` v${pkg.version}`));
8112
+ console.log(chalk.bold("@hasna/instructions") + chalk.dim(` v${pkg.version}`));
7928
8113
  console.log(chalk.cyan("Database:") + ` ${status.env.database.kind} (${status.env.database.active ?? "default"})`);
7929
8114
  console.log(chalk.cyan("Total:") + ` ${status.counts.configs.total} configs
7930
8115
  `);
@@ -7935,7 +8120,7 @@ program.command("status").description("Health check: total configs, drift from d
7935
8120
  });
7936
8121
  program.command("backup").description("Export configs to a timestamped backup file").action(async () => {
7937
8122
  const { mkdirSync: mk } = await import("fs");
7938
- const backupDir = join11(homedir7(), ".hasna", "configs", "backups");
8123
+ const backupDir = join11(homedir7(), ".hasna", "instructions", "backups");
7939
8124
  mk(backupDir, { recursive: true });
7940
8125
  const ts = new Date().toISOString().replace(/[:.]/g, "-").replace("T", "-").slice(0, 19);
7941
8126
  const outPath = join11(backupDir, `configs-${ts}.tar.gz`);
@@ -8086,7 +8271,7 @@ program.command("watch").description("Watch known config files for changes and a
8086
8271
  const interval = Number(opts.interval);
8087
8272
  const { statSync: st } = await import("fs");
8088
8273
  const { expandPath: expandPath2 } = await Promise.resolve().then(() => (init_apply(), exports_apply));
8089
- console.log(chalk.bold("@hasna/configs watch") + chalk.dim(` \u2014 polling every ${interval}ms`));
8274
+ console.log(chalk.bold("@hasna/instructions watch") + chalk.dim(` \u2014 polling every ${interval}ms`));
8090
8275
  console.log(chalk.dim(`Watching known config files for changes\u2026
8091
8276
  `));
8092
8277
  const mtimes = new Map;
@@ -8246,7 +8431,7 @@ program.command("bootstrap").description("Install the full @hasna ecosystem: CLI
8246
8431
  { name: "@hasna/assistants", bin: "assistants", mcp: "assistants-mcp" },
8247
8432
  { name: "@hasna/brains", bin: "brains", mcp: "brains-mcp" }
8248
8433
  ];
8249
- console.log(chalk.bold("@hasna/configs bootstrap") + chalk.dim(` \u2014 installing ${packages.length} ecosystem packages
8434
+ console.log(chalk.bold("@hasna/instructions bootstrap") + chalk.dim(` \u2014 installing ${packages.length} ecosystem packages
8250
8435
  `));
8251
8436
  console.log(chalk.cyan("Installing CLI tools:"));
8252
8437
  for (const pkg2 of packages) {
@@ -8306,7 +8491,7 @@ program.command("push").description("Alias for sync --to-disk (write DB configs
8306
8491
  });
8307
8492
  program.command("update").description("Check for updates and install latest version").option("--check", "only check, don't install").action(async (opts) => {
8308
8493
  try {
8309
- const proc = Bun.spawn(["npm", "view", "@hasna/configs", "version"], { stdout: "pipe", stderr: "pipe" });
8494
+ const proc = Bun.spawn(["npm", "view", "@hasna/instructions", "version"], { stdout: "pipe", stderr: "pipe" });
8310
8495
  const latest = (await new Response(proc.stdout).text()).trim();
8311
8496
  await proc.exited;
8312
8497
  if (latest === pkg.version) {
@@ -8315,7 +8500,7 @@ program.command("update").description("Check for updates and install latest vers
8315
8500
  console.log(`Current: ${chalk.dim(pkg.version)} \u2192 Latest: ${chalk.green(latest)}`);
8316
8501
  if (!opts.check) {
8317
8502
  console.log(chalk.dim("Installing..."));
8318
- const install = Bun.spawn(["bun", "install", "-g", `@hasna/configs@${latest}`], { stdout: "inherit", stderr: "inherit" });
8503
+ const install = Bun.spawn(["bun", "install", "-g", `@hasna/instructions@${latest}`], { stdout: "inherit", stderr: "inherit" });
8319
8504
  await install.exited;
8320
8505
  console.log(chalk.green("\u2713") + ` Updated to ${latest}`);
8321
8506
  }
@@ -7,7 +7,7 @@ export declare function resetDatabase(): void;
7
7
  /**
8
8
  * Destroy the on-disk local database: close the handle and delete the db file
9
9
  * plus its WAL/SHM sidecars. Used by `init --force`. Resolves the path from the
10
- * db module (honoring HASNA_CONFIGS_DB_PATH / CONFIGS_DB_PATH); a no-op for the
10
+ * db module (honoring HASNA_INSTRUCTIONS_DB_PATH); a no-op for the
11
11
  * in-memory (`:memory:`) database. Local-only — the CloudConfigStore never calls
12
12
  * this (destroying the shared cloud store from a client is forbidden).
13
13
  */
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAmBtC,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5C;AAyED,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAqBnD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAsDD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAMxE"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/db/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAetC,wBAAgB,IAAI,IAAI,MAAM,CAE7B;AAED,wBAAgB,GAAG,IAAI,MAAM,CAE5B;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAK5C;AAyED,wBAAgB,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,QAAQ,CAqBnD;AAED,wBAAgB,aAAa,IAAI,IAAI,CAKpC;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAOzC;AAsDD,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,IAAI,CAMxE"}
package/dist/index.js CHANGED
@@ -73,21 +73,17 @@ import { randomUUID as randomUUID2 } from "crypto";
73
73
 
74
74
  // src/db/database.ts
75
75
  import { Database } from "bun:sqlite";
76
- import { cpSync, existsSync, mkdirSync, rmSync, statSync } from "fs";
76
+ import { existsSync, mkdirSync, rmSync } from "fs";
77
77
  import { join } from "path";
78
78
  import { randomUUID } from "crypto";
79
79
  function getDbPath() {
80
- if (process.env["HASNA_CONFIGS_DB_PATH"]) {
81
- return process.env["HASNA_CONFIGS_DB_PATH"];
80
+ if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
81
+ return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
82
82
  }
83
- if (process.env["CONFIGS_DB_PATH"]) {
84
- return process.env["CONFIGS_DB_PATH"];
85
- }
86
- migrateDotfile();
87
83
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
88
- const dir = join(home, ".hasna", "configs");
84
+ const dir = join(home, ".hasna", "instructions");
89
85
  mkdirSync(dir, { recursive: true });
90
- return join(dir, "configs.db");
86
+ return join(dir, "instructions.db");
91
87
  }
92
88
  function uuid() {
93
89
  return randomUUID();
@@ -242,24 +238,6 @@ function insertFeedback(input, db) {
242
238
  const d = db || getDatabase();
243
239
  d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
244
240
  }
245
- function migrateDotfile() {
246
- const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
247
- const oldDirs = [join(home, ".open-configs"), join(home, ".configs")];
248
- const newDir = join(home, ".hasna", "configs");
249
- if (existsSync(newDir))
250
- return;
251
- for (const oldDir of oldDirs) {
252
- if (!existsSync(oldDir))
253
- continue;
254
- try {
255
- if (!statSync(oldDir).isDirectory())
256
- continue;
257
- mkdirSync(join(home, ".hasna"), { recursive: true });
258
- cpSync(oldDir, newDir, { recursive: true, force: false });
259
- return;
260
- } catch {}
261
- }
262
- }
263
241
 
264
242
  // src/db/configs.ts
265
243
  function rowToConfig(row) {
@@ -1510,14 +1488,12 @@ function hasSecrets(content, format) {
1510
1488
  var PACKAGE_NAME = "@hasna/instructions";
1511
1489
  var PACKAGE_VERSION = "0.3.0";
1512
1490
  function activeDatabaseEnv() {
1513
- if (process.env["HASNA_CONFIGS_DB_PATH"])
1514
- return "HASNA_CONFIGS_DB_PATH";
1515
- if (process.env["CONFIGS_DB_PATH"])
1516
- return "CONFIGS_DB_PATH";
1491
+ if (process.env["HASNA_INSTRUCTIONS_DB_PATH"])
1492
+ return "HASNA_INSTRUCTIONS_DB_PATH";
1517
1493
  return null;
1518
1494
  }
1519
1495
  function configuredDatabaseKind() {
1520
- const value = process.env["HASNA_CONFIGS_DB_PATH"] ?? process.env["CONFIGS_DB_PATH"] ?? "";
1496
+ const value = process.env["HASNA_INSTRUCTIONS_DB_PATH"] ?? "";
1521
1497
  return value === ":memory:" || value.startsWith("file::memory:") ? "memory" : "file";
1522
1498
  }
1523
1499
  function countBy(items, getValue) {
@@ -1591,8 +1567,7 @@ async function getConfigsStatus(store = resolveConfigStore()) {
1591
1567
  },
1592
1568
  env: {
1593
1569
  database: {
1594
- primary: "HASNA_CONFIGS_DB_PATH",
1595
- fallback: "CONFIGS_DB_PATH",
1570
+ primary: "HASNA_INSTRUCTIONS_DB_PATH",
1596
1571
  active: activeDatabaseEnv(),
1597
1572
  kind: configuredDatabaseKind()
1598
1573
  }
@@ -1697,7 +1672,7 @@ var PG_MIGRATIONS = [
1697
1672
  ];
1698
1673
  // src/lib/session-render.ts
1699
1674
  import { createHash } from "crypto";
1700
- import { existsSync as existsSync5, readFileSync as readFileSync3, realpathSync as realpathSync2, statSync as statSync2 } from "fs";
1675
+ import { existsSync as existsSync5, readFileSync as readFileSync3, realpathSync as realpathSync2, statSync } from "fs";
1701
1676
  import { homedir as homedir3 } from "os";
1702
1677
  import { basename as basename3, dirname as dirname2, extname as extname2, isAbsolute, join as join3, parse, posix, relative, resolve as resolve2 } from "path";
1703
1678
  var CODEWITH_NATIVE_IMPORTS_ENV = "HASNA_CONFIGS_CODEWITH_NATIVE_IMPORTS";
@@ -2463,7 +2438,7 @@ function readIdentitySourcePath(sourcePath, baseDir, sourceId) {
2463
2438
  }
2464
2439
  return;
2465
2440
  }
2466
- const stat = statSync2(resolvedPath);
2441
+ const stat = statSync(resolvedPath);
2467
2442
  if (!stat.isFile()) {
2468
2443
  throw new Error(`Identity instruction source path is not a file for ${sourceId}: ${sourcePath.path}`);
2469
2444
  }
@@ -3101,7 +3076,7 @@ import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as
3101
3076
  import { basename as basename4, extname as extname3, join as join6 } from "path";
3102
3077
 
3103
3078
  // src/lib/sync-dir.ts
3104
- import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync5, statSync as statSync3 } from "fs";
3079
+ import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3105
3080
  import { join as join5, relative as relative3 } from "path";
3106
3081
  import { homedir as homedir4 } from "os";
3107
3082
  var SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
@@ -3113,7 +3088,7 @@ async function syncFromDir(dir, opts = {}) {
3113
3088
  const absDir = expandPath(dir);
3114
3089
  if (!existsSync7(absDir))
3115
3090
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
3116
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join5(absDir, f)).filter((f) => statSync3(f).isFile());
3091
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync(absDir).map((f) => join5(absDir, f)).filter((f) => statSync2(f).isFile());
3117
3092
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
3118
3093
  const home = homedir4();
3119
3094
  const allConfigs = await store.listConfigs();
package/dist/mcp/index.js CHANGED
@@ -49,21 +49,17 @@ var init_types = __esm(() => {
49
49
 
50
50
  // src/db/database.ts
51
51
  import { Database } from "bun:sqlite";
52
- import { cpSync, existsSync, mkdirSync, rmSync, statSync } from "fs";
52
+ import { existsSync, mkdirSync, rmSync } from "fs";
53
53
  import { join } from "path";
54
54
  import { randomUUID } from "crypto";
55
55
  function getDbPath() {
56
- if (process.env["HASNA_CONFIGS_DB_PATH"]) {
57
- return process.env["HASNA_CONFIGS_DB_PATH"];
56
+ if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
57
+ return process.env["HASNA_INSTRUCTIONS_DB_PATH"];
58
58
  }
59
- if (process.env["CONFIGS_DB_PATH"]) {
60
- return process.env["CONFIGS_DB_PATH"];
61
- }
62
- migrateDotfile();
63
59
  const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
64
- const dir = join(home, ".hasna", "configs");
60
+ const dir = join(home, ".hasna", "instructions");
65
61
  mkdirSync(dir, { recursive: true });
66
- return join(dir, "configs.db");
62
+ return join(dir, "instructions.db");
67
63
  }
68
64
  function uuid() {
69
65
  return randomUUID();
@@ -149,24 +145,6 @@ function insertFeedback(input, db) {
149
145
  const d = db || getDatabase();
150
146
  d.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [input.message, input.email ?? null, input.category ?? "general", input.version ?? null]);
151
147
  }
152
- function migrateDotfile() {
153
- const home = process.env["HOME"] || process.env["USERPROFILE"] || "~";
154
- const oldDirs = [join(home, ".open-configs"), join(home, ".configs")];
155
- const newDir = join(home, ".hasna", "configs");
156
- if (existsSync(newDir))
157
- return;
158
- for (const oldDir of oldDirs) {
159
- if (!existsSync(oldDir))
160
- continue;
161
- try {
162
- if (!statSync(oldDir).isDirectory())
163
- continue;
164
- mkdirSync(join(home, ".hasna"), { recursive: true });
165
- cpSync(oldDir, newDir, { recursive: true, force: false });
166
- return;
167
- } catch {}
168
- }
169
- }
170
148
  var MIGRATIONS, _db = null;
171
149
  var init_database = __esm(() => {
172
150
  MIGRATIONS = [
@@ -1974,7 +1952,7 @@ var init_sync = __esm(() => {
1974
1952
  });
1975
1953
 
1976
1954
  // src/lib/sync-dir.ts
1977
- import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
1955
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync3, statSync } from "fs";
1978
1956
  import { join as join4, relative } from "path";
1979
1957
  import { homedir as homedir3 } from "os";
1980
1958
  function shouldSkip(p) {
@@ -1985,7 +1963,7 @@ async function syncFromDir(dir, opts = {}) {
1985
1963
  const absDir = expandPath(dir);
1986
1964
  if (!existsSync5(absDir))
1987
1965
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
1988
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join4(absDir, f)).filter((f) => statSync2(f).isFile());
1966
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join4(absDir, f)).filter((f) => statSync(f).isFile());
1989
1967
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
1990
1968
  const home = homedir3();
1991
1969
  const allConfigs = await store.listConfigs();
@@ -2062,7 +2040,7 @@ var init_sync_dir = __esm(() => {
2062
2040
  var require_package = __commonJS((exports, module) => {
2063
2041
  module.exports = {
2064
2042
  name: "@hasna/instructions",
2065
- version: "0.4.1",
2043
+ version: "0.4.3",
2066
2044
  description: "AI coding agent instruction & configuration manager \u2014 store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
2067
2045
  type: "module",
2068
2046
  main: "dist/index.js",
@@ -2286,7 +2264,7 @@ var PROFILES = {
2286
2264
  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"],
2287
2265
  full: []
2288
2266
  };
2289
- var activeProfile = process.env["CONFIGS_PROFILE"] || "full";
2267
+ var activeProfile = process.env["INSTRUCTIONS_PROFILE"] || "full";
2290
2268
  var profileFilter = PROFILES[activeProfile];
2291
2269
  var ALL_LEAN_TOOLS = [
2292
2270
  { name: "list_configs", inputSchema: { type: "object", properties: { category: { type: "string" }, agent: { type: "string" }, kind: { type: "string" }, search: { type: "string" }, limit: { type: "number" }, cursor: { type: "number" }, verbose: { type: "boolean" } } } },
@@ -2466,7 +2444,7 @@ function buildServer() {
2466
2444
  drifted,
2467
2445
  drifted_configs: driftedSlugs.slice(0, 5),
2468
2446
  missing,
2469
- db_path: process.env["CONFIGS_DB_PATH"] || "~/.hasna/configs/configs.db"
2447
+ db_path: process.env["HASNA_INSTRUCTIONS_DB_PATH"] || "~/.hasna/instructions/instructions.db"
2470
2448
  });
2471
2449
  }
2472
2450
  case "sync_known": {
@@ -2,7 +2,7 @@
2
2
  // @bun
3
3
  var __require = import.meta.require;
4
4
 
5
- // node_modules/hono/dist/compose.js
5
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/compose.js
6
6
  var compose = (middleware, onError, onNotFound) => {
7
7
  return (context, next) => {
8
8
  let index = -1;
@@ -46,21 +46,39 @@ var compose = (middleware, onError, onNotFound) => {
46
46
  };
47
47
  };
48
48
 
49
- // node_modules/hono/dist/request/constants.js
49
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/request/constants.js
50
50
  var GET_MATCH_RESULT = /* @__PURE__ */ Symbol();
51
51
 
52
- // node_modules/hono/dist/utils/body.js
52
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/utils/buffer.js
53
+ var bufferToFormData = (arrayBuffer, contentType) => {
54
+ const response = new Response(arrayBuffer, {
55
+ headers: {
56
+ "Content-Type": contentType.replace(/^[^;]+/, (mediaType) => mediaType.toLowerCase())
57
+ }
58
+ });
59
+ return response.formData();
60
+ };
61
+
62
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/utils/body.js
63
+ var isRawRequest = (request) => ("headers" in request);
53
64
  var parseBody = async (request, options = /* @__PURE__ */ Object.create(null)) => {
54
65
  const { all = false, dot = false } = options;
55
- const headers = request instanceof HonoRequest ? request.raw.headers : request.headers;
66
+ const headers = isRawRequest(request) ? request.headers : request.raw.headers;
56
67
  const contentType = headers.get("Content-Type");
57
- if (contentType?.startsWith("multipart/form-data") || contentType?.startsWith("application/x-www-form-urlencoded")) {
68
+ const mediaType = contentType?.split(";")[0].trim().toLowerCase();
69
+ if (mediaType === "multipart/form-data" || mediaType === "application/x-www-form-urlencoded") {
58
70
  return parseFormData(request, { all, dot });
59
71
  }
60
72
  return {};
61
73
  };
62
74
  async function parseFormData(request, options) {
63
- const formData = await request.formData();
75
+ const headers = isRawRequest(request) ? request.headers : request.raw.headers;
76
+ const arrayBuffer = await request.arrayBuffer();
77
+ const formDataPromise = bufferToFormData(arrayBuffer, headers.get("Content-Type") || "");
78
+ if (!isRawRequest(request)) {
79
+ request.bodyCache.formData = formDataPromise;
80
+ }
81
+ const formData = await formDataPromise;
64
82
  if (formData) {
65
83
  return convertFormDataToBodyData(formData, options);
66
84
  }
@@ -120,7 +138,7 @@ var handleParsingNestedValues = (form, key, value) => {
120
138
  });
121
139
  };
122
140
 
123
- // node_modules/hono/dist/utils/url.js
141
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/utils/url.js
124
142
  var splitPath = (path) => {
125
143
  const paths = path.split("/");
126
144
  if (paths[0] === "") {
@@ -320,7 +338,7 @@ var getQueryParams = (url, key) => {
320
338
  };
321
339
  var decodeURIComponent_ = decodeURIComponent;
322
340
 
323
- // node_modules/hono/dist/request.js
341
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/request.js
324
342
  var tryDecodeURIComponent = (str) => tryDecode(str, decodeURIComponent_);
325
343
  var HonoRequest = class {
326
344
  raw;
@@ -402,6 +420,9 @@ var HonoRequest = class {
402
420
  arrayBuffer() {
403
421
  return this.#cachedBody("arrayBuffer");
404
422
  }
423
+ bytes() {
424
+ return this.#cachedBody("arrayBuffer").then((buffer) => new Uint8Array(buffer));
425
+ }
405
426
  blob() {
406
427
  return this.#cachedBody("blob");
407
428
  }
@@ -431,7 +452,7 @@ var HonoRequest = class {
431
452
  }
432
453
  };
433
454
 
434
- // node_modules/hono/dist/utils/html.js
455
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/utils/html.js
435
456
  var HtmlEscapedCallbackPhase = {
436
457
  Stringify: 1,
437
458
  BeforeStream: 2,
@@ -469,7 +490,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
469
490
  }
470
491
  };
471
492
 
472
- // node_modules/hono/dist/context.js
493
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/context.js
473
494
  var TEXT_PLAIN = "text/plain; charset=UTF-8";
474
495
  var setDefaultContentType = (contentType, headers) => {
475
496
  return {
@@ -636,7 +657,7 @@ var Context = class {
636
657
  };
637
658
  };
638
659
 
639
- // node_modules/hono/dist/router.js
660
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router.js
640
661
  var METHOD_NAME_ALL = "ALL";
641
662
  var METHOD_NAME_ALL_LOWERCASE = "all";
642
663
  var METHODS = ["get", "post", "put", "delete", "options", "patch"];
@@ -644,10 +665,10 @@ var MESSAGE_MATCHER_IS_ALREADY_BUILT = "Can not add a route since the matcher is
644
665
  var UnsupportedPathError = class extends Error {
645
666
  };
646
667
 
647
- // node_modules/hono/dist/utils/constants.js
668
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/utils/constants.js
648
669
  var COMPOSED_HANDLER = "__COMPOSED_HANDLER";
649
670
 
650
- // node_modules/hono/dist/hono-base.js
671
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/hono-base.js
651
672
  var notFoundHandler = (c) => {
652
673
  return c.text("404 Not Found", 404);
653
674
  };
@@ -738,7 +759,7 @@ var Hono = class _Hono {
738
759
  handler = async (c, next) => (await compose([], app.errorHandler)(c, () => r.handler(c, next))).res;
739
760
  handler[COMPOSED_HANDLER] = r.handler;
740
761
  }
741
- subApp.#addRoute(r.method, r.path, handler);
762
+ subApp.#addRoute(r.method, r.path, handler, r.basePath);
742
763
  });
743
764
  return this;
744
765
  }
@@ -785,7 +806,7 @@ var Hono = class _Hono {
785
806
  const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
786
807
  return (request) => {
787
808
  const url = new URL(request.url);
788
- url.pathname = url.pathname.slice(pathPrefixLength) || "/";
809
+ url.pathname = this.getPath(request).slice(pathPrefixLength) || "/";
789
810
  return new Request(url, request);
790
811
  };
791
812
  })();
@@ -799,10 +820,15 @@ var Hono = class _Hono {
799
820
  this.#addRoute(METHOD_NAME_ALL, mergePath(path, "*"), handler);
800
821
  return this;
801
822
  }
802
- #addRoute(method, path, handler) {
823
+ #addRoute(method, path, handler, baseRoutePath) {
803
824
  method = method.toUpperCase();
804
825
  path = mergePath(this._basePath, path);
805
- const r = { basePath: this._basePath, path, method, handler };
826
+ const r = {
827
+ basePath: baseRoutePath !== undefined ? mergePath(this._basePath, baseRoutePath) : this._basePath,
828
+ path,
829
+ method,
830
+ handler
831
+ };
806
832
  this.router.add(method, path, [handler, r]);
807
833
  this.routes.push(r);
808
834
  }
@@ -866,7 +892,7 @@ var Hono = class _Hono {
866
892
  };
867
893
  };
868
894
 
869
- // node_modules/hono/dist/router/reg-exp-router/matcher.js
895
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/reg-exp-router/matcher.js
870
896
  var emptyParam = [];
871
897
  function match(method, path) {
872
898
  const matchers = this.buildAllMatchers();
@@ -887,7 +913,7 @@ function match(method, path) {
887
913
  return match2(method, path);
888
914
  }
889
915
 
890
- // node_modules/hono/dist/router/reg-exp-router/node.js
916
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/reg-exp-router/node.js
891
917
  var LABEL_REG_EXP_STR = "[^/]+";
892
918
  var ONLY_WILDCARD_REG_EXP_STR = ".*";
893
919
  var TAIL_WILDCARD_REG_EXP_STR = "(?:|/.*)";
@@ -991,7 +1017,7 @@ var Node = class _Node {
991
1017
  }
992
1018
  };
993
1019
 
994
- // node_modules/hono/dist/router/reg-exp-router/trie.js
1020
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/reg-exp-router/trie.js
995
1021
  var Trie = class {
996
1022
  #context = { varIndex: 0 };
997
1023
  #root = new Node;
@@ -1047,7 +1073,7 @@ var Trie = class {
1047
1073
  }
1048
1074
  };
1049
1075
 
1050
- // node_modules/hono/dist/router/reg-exp-router/router.js
1076
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/reg-exp-router/router.js
1051
1077
  var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
1052
1078
  var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
1053
1079
  function buildWildcardRegExp(path) {
@@ -1212,7 +1238,7 @@ var RegExpRouter = class {
1212
1238
  }
1213
1239
  };
1214
1240
 
1215
- // node_modules/hono/dist/router/reg-exp-router/prepared-router.js
1241
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/reg-exp-router/prepared-router.js
1216
1242
  var PreparedRegExpRouter = class {
1217
1243
  name = "PreparedRegExpRouter";
1218
1244
  #matchers;
@@ -1284,7 +1310,7 @@ var PreparedRegExpRouter = class {
1284
1310
  match = match;
1285
1311
  };
1286
1312
 
1287
- // node_modules/hono/dist/router/smart-router/router.js
1313
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/smart-router/router.js
1288
1314
  var SmartRouter = class {
1289
1315
  name = "SmartRouter";
1290
1316
  #routers = [];
@@ -1339,7 +1365,7 @@ var SmartRouter = class {
1339
1365
  }
1340
1366
  };
1341
1367
 
1342
- // node_modules/hono/dist/router/trie-router/node.js
1368
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/trie-router/node.js
1343
1369
  var emptyParams = /* @__PURE__ */ Object.create(null);
1344
1370
  var hasChildren = (children) => {
1345
1371
  for (const _ in children) {
@@ -1508,7 +1534,7 @@ var Node2 = class _Node2 {
1508
1534
  }
1509
1535
  };
1510
1536
 
1511
- // node_modules/hono/dist/router/trie-router/router.js
1537
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/router/trie-router/router.js
1512
1538
  var TrieRouter = class {
1513
1539
  name = "TrieRouter";
1514
1540
  #node;
@@ -1530,7 +1556,7 @@ var TrieRouter = class {
1530
1556
  }
1531
1557
  };
1532
1558
 
1533
- // node_modules/hono/dist/hono.js
1559
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/hono.js
1534
1560
  var Hono2 = class extends Hono {
1535
1561
  constructor(options = {}) {
1536
1562
  super(options);
@@ -1540,24 +1566,18 @@ var Hono2 = class extends Hono {
1540
1566
  }
1541
1567
  };
1542
1568
 
1543
- // node_modules/hono/dist/middleware/cors/index.js
1569
+ // node_modules/.pnpm/hono@4.12.28/node_modules/hono/dist/middleware/cors/index.js
1544
1570
  var cors = (options) => {
1545
- const defaults = {
1571
+ const opts = {
1546
1572
  origin: "*",
1547
1573
  allowMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "PATCH"],
1548
1574
  allowHeaders: [],
1549
- exposeHeaders: []
1550
- };
1551
- const opts = {
1552
- ...defaults,
1575
+ exposeHeaders: [],
1553
1576
  ...options
1554
1577
  };
1555
1578
  const findAllowOrigin = ((optsOrigin) => {
1556
1579
  if (typeof optsOrigin === "string") {
1557
1580
  if (optsOrigin === "*") {
1558
- if (opts.credentials) {
1559
- return (origin) => origin || null;
1560
- }
1561
1581
  return () => optsOrigin;
1562
1582
  } else {
1563
1583
  return (origin) => optsOrigin === origin ? origin : null;
@@ -1592,7 +1612,7 @@ var cors = (options) => {
1592
1612
  set("Access-Control-Expose-Headers", opts.exposeHeaders.join(","));
1593
1613
  }
1594
1614
  if (c.req.method === "OPTIONS") {
1595
- if (opts.origin !== "*" || opts.credentials) {
1615
+ if (opts.origin !== "*") {
1596
1616
  set("Vary", "Origin");
1597
1617
  }
1598
1618
  if (opts.maxAge != null) {
@@ -1622,7 +1642,7 @@ var cors = (options) => {
1622
1642
  });
1623
1643
  }
1624
1644
  await next();
1625
- if (opts.origin !== "*" || opts.credentials) {
1645
+ if (opts.origin !== "*") {
1626
1646
  c.header("Vary", "Origin", { append: true });
1627
1647
  }
1628
1648
  };
@@ -3199,7 +3219,7 @@ if (process.argv.includes("--version") || process.argv.includes("-V")) {
3199
3219
  console.log(getPackageVersion());
3200
3220
  process.exit(0);
3201
3221
  }
3202
- var PORT = Number(process.env["PORT"] ?? process.env["INSTRUCTIONS_PORT"] ?? process.env["CONFIGS_PORT"] ?? 3457);
3222
+ var PORT = Number(process.env["PORT"] ?? process.env["INSTRUCTIONS_PORT"] ?? 3457);
3203
3223
  var app = new Hono2;
3204
3224
  app.use("*", cors());
3205
3225
  function serviceMode() {
@@ -3268,7 +3288,7 @@ if (dashDir) {
3268
3288
  });
3269
3289
  });
3270
3290
  }
3271
- var HOST = process.env["HOST"] ?? process.env["INSTRUCTIONS_HOST"] ?? process.env["CONFIGS_HOST"] ?? "localhost";
3291
+ var HOST = process.env["HOST"] ?? process.env["INSTRUCTIONS_HOST"] ?? "localhost";
3272
3292
  console.log(`instructions-serve listening on http://${HOST}:${PORT} (mode: ${serviceMode()})${dashDir ? " (dashboard: /)" : " (no dashboard)"}`);
3273
3293
  var server_default = { port: PORT, hostname: HOST, fetch: app.fetch };
3274
3294
  export {
package/dist/status.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { type ConfigStore } from "./data/config-store.js";
2
- type ActiveDbEnv = "HASNA_CONFIGS_DB_PATH" | "CONFIGS_DB_PATH" | null;
2
+ type ActiveDbEnv = "HASNA_INSTRUCTIONS_DB_PATH" | null;
3
3
  type DatabaseKind = "memory" | "file";
4
4
  type ContractStatus = "ok" | "warn";
5
5
  export interface ConfigsStatusContract {
@@ -11,8 +11,7 @@ export interface ConfigsStatusContract {
11
11
  };
12
12
  env: {
13
13
  database: {
14
- primary: "HASNA_CONFIGS_DB_PATH";
15
- fallback: "CONFIGS_DB_PATH";
14
+ primary: "HASNA_INSTRUCTIONS_DB_PATH";
16
15
  active: ActiveDbEnv;
17
16
  kind: DatabaseKind;
18
17
  };
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQ9E,KAAK,WAAW,GAAG,uBAAuB,GAAG,iBAAiB,GAAG,IAAI,CAAC;AACtE,KAAK,YAAY,GAAG,QAAQ,GAAG,MAAM,CAAC;AACtC,KAAK,cAAc,GAAG,IAAI,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,CAAC;IACnB,aAAa,EAAE,KAAK,CAAC;IACrB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,EAAE;QACH,QAAQ,EAAE;YACR,OAAO,EAAE,uBAAuB,CAAC;YACjC,QAAQ,EAAE,iBAAiB,CAAC;YAC5B,MAAM,EAAE,WAAW,CAAC;YACpB,IAAI,EAAE,YAAY,CAAC;SACpB,CAAC;KACH,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;QACF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,cAAc,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,wBAAwB,EAAE,MAAM,CAAC;QACjC,QAAQ,EAAE,OAAO,CAAC;QAClB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,oBAAoB,EAAE,OAAO,CAAC;KAC/B,CAAC;IACF,MAAM,EAAE;QACN,oBAAoB,EAAE,KAAK,CAAC;QAC5B,oBAAoB,EAAE,KAAK,CAAC;QAC5B,iBAAiB,EAAE,KAAK,CAAC;QACzB,oBAAoB,EAAE,KAAK,CAAC;QAC5B,0BAA0B,EAAE,IAAI,CAAC;KAClC,CAAC;CACH;AAuBD,wBAAsB,gBAAgB,CACpC,KAAK,GAAE,WAAkC,GACxC,OAAO,CAAC,qBAAqB,CAAC,CAkHhC"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAQ9E,KAAK,WAAW,GAAG,4BAA4B,GAAG,IAAI,CAAC;AACvD,KAAK,YAAY,GAAG,QAAQ,GAAG,MAAM,CAAC;AACtC,KAAK,cAAc,GAAG,IAAI,GAAG,MAAM,CAAC;AAEpC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,SAAS,CAAC;IACnB,aAAa,EAAE,KAAK,CAAC;IACrB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,GAAG,EAAE;QACH,QAAQ,EAAE;YACR,OAAO,EAAE,4BAA4B,CAAC;YACtC,MAAM,EAAE,WAAW,CAAC;YACpB,IAAI,EAAE,YAAY,CAAC;SACpB,CAAC;KACH,CAAC;IACF,MAAM,EAAE;QACN,OAAO,EAAE;YACP,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,SAAS,EAAE,MAAM,CAAC;YAClB,SAAS,EAAE,MAAM,CAAC;SACnB,CAAC;QACF,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAChC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,EAAE;QACN,MAAM,EAAE,cAAc,CAAC;QACvB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,wBAAwB,EAAE,MAAM,CAAC;QACjC,QAAQ,EAAE,OAAO,CAAC;QAClB,iBAAiB,EAAE,OAAO,CAAC;QAC3B,oBAAoB,EAAE,OAAO,CAAC;KAC/B,CAAC;IACF,MAAM,EAAE;QACN,oBAAoB,EAAE,KAAK,CAAC;QAC5B,oBAAoB,EAAE,KAAK,CAAC;QAC5B,iBAAiB,EAAE,KAAK,CAAC;QACzB,oBAAoB,EAAE,KAAK,CAAC;QAC5B,0BAA0B,EAAE,IAAI,CAAC;KAClC,CAAC;CACH;AAsBD,wBAAsB,gBAAgB,CACpC,KAAK,GAAE,WAAkC,GACxC,OAAO,CAAC,qBAAqB,CAAC,CAiHhC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/instructions",
3
- "version": "0.4.1",
3
+ "version": "0.4.3",
4
4
  "description": "AI coding agent instruction & configuration manager — store, version, apply, and share all your AI coding configs. CLI + MCP + HTTP API (instructions-serve) + generated SDK + Dashboard.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",