@hasna/instructions 0.3.0 → 0.3.1

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.
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
package/dist/cli/index.js CHANGED
@@ -3581,7 +3581,7 @@ var init_sync = __esm(() => {
3581
3581
  ];
3582
3582
  });
3583
3583
 
3584
- // node_modules/.pnpm/@hasna+events@0.1.13/node_modules/@hasna/events/dist/commander.js
3584
+ // node_modules/@hasna/events/dist/commander.js
3585
3585
  import { chmod, mkdir, readFile, rename, writeFile } from "fs/promises";
3586
3586
  import { existsSync } from "fs";
3587
3587
  import { homedir } from "os";
@@ -3598,83 +3598,29 @@ function getPathValue(input, path) {
3598
3598
  return;
3599
3599
  }, input);
3600
3600
  }
3601
- function getFieldValues(input, path) {
3602
- const values = [];
3603
- const push = (value) => {
3604
- if (!values.some((item) => Object.is(item, value)))
3605
- values.push(value);
3606
- };
3607
- if (path.includes(".") && path in input)
3608
- push(input[path]);
3609
- const nestedValue = getPathValue(input, path);
3610
- if (nestedValue !== undefined || !path.includes("."))
3611
- push(nestedValue);
3612
- return values;
3613
- }
3614
- function wildcardToRegExp(pattern, options = {}) {
3615
- let body = "";
3616
- for (let index = 0;index < pattern.length; index += 1) {
3617
- const char = pattern[index];
3618
- if (char === "*") {
3619
- if (pattern[index + 1] === "*") {
3620
- body += ".*";
3621
- index += 1;
3622
- } else {
3623
- body += options.segmentSafe ? "[^/]*" : ".*";
3624
- }
3625
- } else {
3626
- body += char.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
3627
- }
3628
- }
3629
- return new RegExp(`^${body}$`);
3601
+ function wildcardToRegExp(pattern) {
3602
+ const escaped = pattern.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".*");
3603
+ return new RegExp(`^${escaped}$`);
3630
3604
  }
3631
- function matchString(value, matcher, options = {}) {
3605
+ function matchString(value, matcher) {
3632
3606
  if (matcher === undefined)
3633
3607
  return true;
3634
3608
  if (value === undefined)
3635
3609
  return false;
3636
3610
  const matchers = Array.isArray(matcher) ? matcher : [matcher];
3637
- return matchers.some((item) => wildcardToRegExp(item, options).test(value));
3611
+ return matchers.some((item) => wildcardToRegExp(item).test(value));
3638
3612
  }
3639
3613
  function matchRecord(input, matcher) {
3640
3614
  if (!matcher)
3641
3615
  return true;
3642
3616
  return Object.entries(matcher).every(([path, expected]) => {
3643
- const actualValues = getFieldValues(input, path);
3644
- return matchField(actualValues, expected, path);
3617
+ const actual = getPathValue(input, path);
3618
+ if (typeof expected === "string" || Array.isArray(expected)) {
3619
+ return matchString(actual === undefined ? undefined : String(actual), expected);
3620
+ }
3621
+ return actual === expected;
3645
3622
  });
3646
3623
  }
3647
- function matchField(actualValues, expected, path) {
3648
- if (isNegativeMatcher(expected)) {
3649
- return !actualValues.some((actual) => matchPositiveField(actual, expected.not, path));
3650
- }
3651
- return actualValues.some((actual) => matchPositiveField(actual, expected, path));
3652
- }
3653
- function matchPositiveField(actual, expected, path) {
3654
- if (typeof expected === "string" || Array.isArray(expected)) {
3655
- return stringCandidates(actual).some((candidate) => matchString(candidate, expected, {
3656
- segmentSafe: path.endsWith("_path") || path.endsWith(".path")
3657
- }));
3658
- }
3659
- if (Array.isArray(actual)) {
3660
- return actual.some((item) => item === expected);
3661
- }
3662
- return actual === expected;
3663
- }
3664
- function stringCandidates(actual) {
3665
- if (actual === undefined)
3666
- return [];
3667
- if (Array.isArray(actual)) {
3668
- return actual.flatMap((item) => isPrimitiveFieldValue(item) ? [String(item)] : []);
3669
- }
3670
- return [String(actual)];
3671
- }
3672
- function isPrimitiveFieldValue(value) {
3673
- return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
3674
- }
3675
- function isNegativeMatcher(value) {
3676
- return Boolean(value && typeof value === "object" && !Array.isArray(value) && "not" in value);
3677
- }
3678
3624
  function eventMatchesFilter(event, filter) {
3679
3625
  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);
3680
3626
  }
@@ -3690,14 +3636,6 @@ var HASNA_EVENTS_HOME_ENV = "HASNA_EVENTS_HOME";
3690
3636
  function getEventsDataDir(override) {
3691
3637
  return override || process.env[HASNA_EVENTS_DIR_ENV] || process.env[HASNA_EVENTS_HOME_ENV] || join(homedir(), ".hasna", "events");
3692
3638
  }
3693
- function getActiveEventsDirEnv() {
3694
- if (process.env[HASNA_EVENTS_DIR_ENV])
3695
- return HASNA_EVENTS_DIR_ENV;
3696
- if (process.env[HASNA_EVENTS_HOME_ENV])
3697
- return HASNA_EVENTS_HOME_ENV;
3698
- return null;
3699
- }
3700
-
3701
3639
  class JsonEventsStore {
3702
3640
  dataDir;
3703
3641
  channelsPath;
@@ -3809,52 +3747,6 @@ class JsonEventsStore {
3809
3747
  });
3810
3748
  }
3811
3749
  }
3812
- async function getEventsStatus(dataDir) {
3813
- const store = new JsonEventsStore(dataDir);
3814
- await store.init();
3815
- const [channels, events, deliveries] = await Promise.all([
3816
- store.listChannels(),
3817
- store.listEvents(),
3818
- store.listDeliveries()
3819
- ]);
3820
- const transports = channels.reduce((counts, channel) => {
3821
- counts[channel.transport] = (counts[channel.transport] ?? 0) + 1;
3822
- return counts;
3823
- }, {});
3824
- return {
3825
- service: "events",
3826
- schemaVersion: "1.0",
3827
- dataDir: store.dataDir,
3828
- env: {
3829
- primary: HASNA_EVENTS_DIR_ENV,
3830
- fallback: HASNA_EVENTS_HOME_ENV,
3831
- active: getActiveEventsDirEnv()
3832
- },
3833
- files: {
3834
- channels: statusFile(store.dataDir, "channels.json", channels.length),
3835
- events: statusFile(store.dataDir, "events.json", events.length),
3836
- deliveries: statusFile(store.dataDir, "deliveries.json", deliveries.length)
3837
- },
3838
- counts: {
3839
- channels: channels.length,
3840
- enabledChannels: channels.filter((channel) => channel.enabled).length,
3841
- disabledChannels: channels.filter((channel) => !channel.enabled).length,
3842
- events: events.length,
3843
- deliveries: deliveries.length
3844
- },
3845
- transports,
3846
- safety: {
3847
- includesEventPayloads: false,
3848
- includesWebhookSecrets: false,
3849
- listOutputsRedactSecrets: true,
3850
- statusOutputIsMetadataOnly: true
3851
- }
3852
- };
3853
- }
3854
- function statusFile(dataDir, fileName, records) {
3855
- const path = join(dataDir, fileName);
3856
- return { path, exists: existsSync(path), records };
3857
- }
3858
3750
  var DEFAULT_SIGNATURE_TOLERANCE_MS = 5 * 60 * 1000;
3859
3751
  function buildSignatureBase(timestamp, body) {
3860
3752
  return `${timestamp}.${body}`;
@@ -4080,7 +3972,7 @@ class EventsClient {
4080
3972
  }
4081
3973
  return deliveries;
4082
3974
  }
4083
- async matchChannel(id, input = {}) {
3975
+ async testChannel(id, input = {}) {
4084
3976
  const channel = await this.store.getChannel(id);
4085
3977
  if (!channel)
4086
3978
  throw new Error(`Channel not found: ${id}`);
@@ -4097,34 +3989,6 @@ class EventsClient {
4097
3989
  time: input.time,
4098
3990
  id: input.id
4099
3991
  });
4100
- const matched = channelMatchesEvent(channel, event);
4101
- return {
4102
- channelId: channel.id,
4103
- matched,
4104
- event,
4105
- filters: channel.filters,
4106
- reason: matched ? undefined : channel.enabled ? "event did not match channel filters" : "channel is disabled"
4107
- };
4108
- }
4109
- async testChannel(id, input = {}, options = {}) {
4110
- const channel = await this.store.getChannel(id);
4111
- if (!channel)
4112
- throw new Error(`Channel not found: ${id}`);
4113
- const match = await this.matchChannel(id, input);
4114
- const event = match.event;
4115
- if (options.honorFilters && !match.matched) {
4116
- const timestamp = new Date().toISOString();
4117
- const result2 = createDeliveryResult(event, channel, [{
4118
- attempt: 1,
4119
- status: "skipped",
4120
- startedAt: timestamp,
4121
- completedAt: timestamp,
4122
- error: match.reason
4123
- }]);
4124
- result2.metadata = { reason: "filter_mismatch" };
4125
- await this.store.appendDelivery(result2);
4126
- return result2;
4127
- }
4128
3992
  const eventForChannel = await this.applyRedaction(event, channel);
4129
3993
  const result = await this.deliverWithRetry(eventForChannel, channel);
4130
3994
  await this.store.appendDelivery(result);
@@ -4235,76 +4099,6 @@ function normalizeRetryPolicy(policy) {
4235
4099
  multiplier: Math.max(1, policy?.multiplier ?? 2)
4236
4100
  };
4237
4101
  }
4238
- function parseFieldMatchers(values, label, typed = false) {
4239
- if (!values?.length)
4240
- return;
4241
- const result = {};
4242
- for (const value of values) {
4243
- const parsed = parseMatcherExpression(value, label);
4244
- const path = parsed.path;
4245
- if (path in result)
4246
- throw new Error(`Duplicate ${label} filter path: ${path}`);
4247
- const matcherValue = typed ? parseTypedMatcherValue(parsed.rawValue, label) : parsed.rawValue;
4248
- result[path] = parsed.negated ? { not: matcherValue } : matcherValue;
4249
- }
4250
- return result;
4251
- }
4252
- function parseFilterOptions(options) {
4253
- const filter2 = {};
4254
- if (options.source)
4255
- filter2.source = options.source;
4256
- if (options.type)
4257
- filter2.type = options.type;
4258
- if (options.subject)
4259
- filter2.subject = options.subject;
4260
- if (options.severity)
4261
- filter2.severity = options.severity;
4262
- const data = mergeMatchers(parseFieldMatchers(options.data, "data"), parseFieldMatchers(options.dataJson, "data-json", true));
4263
- const metadata = mergeMatchers(parseFieldMatchers(options.metadata, "metadata"), parseFieldMatchers(options.metadataJson, "metadata-json", true));
4264
- if (Object.keys(data).length > 0)
4265
- filter2.data = data;
4266
- if (Object.keys(metadata).length > 0)
4267
- filter2.metadata = metadata;
4268
- return Object.keys(filter2).length > 0 ? [filter2] : undefined;
4269
- }
4270
- function mergeMatchers(...records) {
4271
- const result = {};
4272
- for (const record of records) {
4273
- if (!record)
4274
- continue;
4275
- for (const [path, value] of Object.entries(record)) {
4276
- if (path in result)
4277
- throw new Error(`Duplicate filter path: ${path}`);
4278
- result[path] = value;
4279
- }
4280
- }
4281
- return result;
4282
- }
4283
- function parseTypedMatcherValue(value, label) {
4284
- const parsed = JSON.parse(value);
4285
- if (parsed === null || typeof parsed === "string" || typeof parsed === "number" || typeof parsed === "boolean" || Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
4286
- return parsed;
4287
- }
4288
- throw new Error(`${label} filter JSON values must be string, string[], number, boolean, or null`);
4289
- }
4290
- function parseMatcherExpression(value, label) {
4291
- const negativeSeparator = value.indexOf("!=");
4292
- if (negativeSeparator > 0) {
4293
- return {
4294
- path: value.slice(0, negativeSeparator),
4295
- rawValue: value.slice(negativeSeparator + 2),
4296
- negated: true
4297
- };
4298
- }
4299
- const separator = value.indexOf("=");
4300
- if (separator <= 0)
4301
- throw new Error(`Invalid ${label} filter, expected path=value or path!=value: ${value}`);
4302
- return {
4303
- path: value.slice(0, separator),
4304
- rawValue: value.slice(separator + 1),
4305
- negated: false
4306
- };
4307
- }
4308
4102
  function parseJsonObject(value, fallback) {
4309
4103
  if (!value)
4310
4104
  return fallback;
@@ -4326,6 +4120,18 @@ function parseHeaders(values) {
4326
4120
  }
4327
4121
  return headers;
4328
4122
  }
4123
+ function parseFilter(options) {
4124
+ const filter2 = {};
4125
+ if (options.source)
4126
+ filter2.source = options.source;
4127
+ if (options.type)
4128
+ filter2.type = options.type;
4129
+ if (options.subject)
4130
+ filter2.subject = options.subject;
4131
+ if (options.severity)
4132
+ filter2.severity = options.severity;
4133
+ return Object.keys(filter2).length > 0 ? [filter2] : undefined;
4134
+ }
4329
4135
  function createClient(options) {
4330
4136
  if (options.createClient)
4331
4137
  return options.createClient();
@@ -4343,16 +4149,16 @@ function hasJsonOption(options) {
4343
4149
  function wantsJson(actionOptions, command) {
4344
4150
  return hasJsonOption(actionOptions) || hasJsonOption(command);
4345
4151
  }
4346
- function registerChannelCommands(program, options) {
4347
- const channels = program.command(options.channelsCommandName ?? "channels").description("Manage Hasna event channels");
4348
- 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) => {
4152
+ function registerWebhookCommands(program, options) {
4153
+ const webhooks = program.command(options.webhooksCommandName ?? "webhooks").description("Manage Hasna event webhook subscriptions");
4154
+ 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) => {
4349
4155
  const timestamp = new Date().toISOString();
4350
4156
  const channel = {
4351
4157
  id: actionOptions.id,
4352
4158
  name: actionOptions.name,
4353
4159
  enabled: !actionOptions.disabled,
4354
4160
  transport: actionOptions.transport,
4355
- filters: parseFilterOptions(actionOptions),
4161
+ filters: parseFilter(actionOptions),
4356
4162
  retry: actionOptions.retryAttempts || actionOptions.retryBackoffMs ? { maxAttempts: actionOptions.retryAttempts, backoffMs: actionOptions.retryBackoffMs } : undefined,
4357
4163
  redact: actionOptions.redact?.length ? { paths: actionOptions.redact } : undefined,
4358
4164
  createdAt: timestamp,
@@ -4368,51 +4174,35 @@ function registerChannelCommands(program, options) {
4368
4174
  const saved = await createClient(options).addChannel(channel);
4369
4175
  print(sanitizeChannelForOutput(saved), wantsJson(actionOptions, command), `Added ${saved.transport} channel ${saved.id}`);
4370
4176
  });
4371
- channels.command("list").description("List configured channels").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
4372
- const channels2 = await createClient(options).listChannels();
4177
+ webhooks.command("list").description("List configured subscriptions").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
4178
+ const channels = await createClient(options).listChannels();
4373
4179
  if (wantsJson(actionOptions, command)) {
4374
- console.log(JSON.stringify(sanitizeChannelsForOutput(channels2), null, 2));
4180
+ console.log(JSON.stringify(sanitizeChannelsForOutput(channels), null, 2));
4375
4181
  return;
4376
4182
  }
4377
- if (!channels2.length) {
4183
+ if (!channels.length) {
4378
4184
  console.log("No channels configured.");
4379
4185
  return;
4380
4186
  }
4381
- for (const channel of channels2) {
4187
+ for (const channel of channels) {
4382
4188
  console.log(`${channel.id} ${channel.enabled ? "enabled" : "disabled"} ${channel.transport} ${channel.webhook?.url ?? channel.command?.command ?? channel.transport}`);
4383
4189
  }
4384
4190
  });
4385
- channels.command("status").description("Show events channel storage status").option("-j, --json", "Print JSON output", false).action(async (actionOptions, command) => {
4386
- const status = await getEventsStatus(options.dataDir);
4387
- print(status, wantsJson(actionOptions, command), `events dataDir: ${status.dataDir}`);
4388
- });
4389
- channels.command("remove").description("Remove a channel").argument("<id>", "Channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
4191
+ webhooks.command("remove").description("Remove a subscription").argument("<id>", "Subscription/channel identifier").option("-j, --json", "Print JSON output", false).action(async (id, actionOptions, command) => {
4390
4192
  const removed = await createClient(options).removeChannel(id);
4391
4193
  print({ removed }, wantsJson(actionOptions, command), removed ? `Removed ${id}` : `Channel not found: ${id}`);
4392
4194
  });
4393
- 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) => {
4195
+ 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) => {
4394
4196
  const result = await createClient(options).testChannel(id, {
4395
- source: actionOptions.source ?? options.source,
4396
- type: actionOptions.type,
4397
- subject: actionOptions.subject ?? id,
4398
- message: actionOptions.message,
4399
- data: parseJsonObject(actionOptions.data, { test: true }),
4400
- metadata: parseJsonObject(actionOptions.metadata, {})
4401
- }, { honorFilters: actionOptions.honorFilters });
4402
- print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
4403
- });
4404
- 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) => {
4405
- const result = await createClient(options).matchChannel(id, {
4406
- source: actionOptions.source ?? options.source,
4197
+ source: options.source,
4407
4198
  type: actionOptions.type,
4408
4199
  subject: actionOptions.subject ?? id,
4409
4200
  message: actionOptions.message,
4410
- data: parseJsonObject(actionOptions.data, { test: true }),
4411
- metadata: parseJsonObject(actionOptions.metadata, {})
4201
+ data: parseJsonObject(actionOptions.data, { test: true })
4412
4202
  });
4413
- print(result, wantsJson(actionOptions, command), `${result.matched ? "matched" : "skipped"}: ${result.channelId}`);
4203
+ print(result, wantsJson(actionOptions, command), `${result.status}: ${result.channelId}`);
4414
4204
  });
4415
- return channels;
4205
+ return webhooks;
4416
4206
  }
4417
4207
  function registerEventCommands(program, options) {
4418
4208
  const events = program.command(options.eventsCommandName ?? "events").description("Emit, list, and replay Hasna events");
@@ -4460,7 +4250,7 @@ function registerEventCommands(program, options) {
4460
4250
  return events;
4461
4251
  }
4462
4252
  function registerEventsCommands(program, options) {
4463
- registerChannelCommands(program, options);
4253
+ registerWebhookCommands(program, options);
4464
4254
  registerEventCommands(program, options);
4465
4255
  }
4466
4256
  function parseNumber(value) {
@@ -1,4 +1,4 @@
1
- export declare const KIT_VERSION = "0.4.1";
1
+ export declare const KIT_VERSION = "0.4.2";
2
2
  export * from "./mode.js";
3
3
  export * from "./tls.js";
4
4
  export * from "./query.js";
package/dist/mcp/index.js CHANGED
@@ -1549,7 +1549,7 @@ var init_sync_dir = __esm(() => {
1549
1549
  var require_package = __commonJS((exports, module) => {
1550
1550
  module.exports = {
1551
1551
  name: "@hasna/instructions",
1552
- version: "0.3.0",
1552
+ version: "0.3.1",
1553
1553
  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.",
1554
1554
  type: "module",
1555
1555
  main: "dist/index.js",
@@ -1625,7 +1625,7 @@ var require_package = __commonJS((exports, module) => {
1625
1625
  author: "Andrei Hasna <andrei@hasna.com>",
1626
1626
  license: "Apache-2.0",
1627
1627
  dependencies: {
1628
- "@hasna/contracts": "^0.4.1",
1628
+ "@hasna/contracts": "0.4.2",
1629
1629
  "@hasna/events": "^0.1.6",
1630
1630
  "@modelcontextprotocol/sdk": "^1.12.1",
1631
1631
  chalk: "^5.4.1",