@hasna/instructions 0.4.39 → 0.4.43

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/mcp/index.js CHANGED
@@ -99,17 +99,17 @@ var init_retired_storage_mode = __esm(() => {
99
99
 
100
100
  // src/lib/raw-store-root.ts
101
101
  import { homedir } from "os";
102
- import { join, resolve } from "path";
102
+ import { join as join2, resolve } from "path";
103
103
  function getRawStoreRoot() {
104
- return resolve(process.env[RAW_STORE_ROOT_ENV] || join(process.env["HOME"] || homedir(), ".hasna", "instructions"));
104
+ return resolve(process.env[RAW_STORE_ROOT_ENV] || join2(process.env["HOME"] || homedir(), ".hasna", "instructions"));
105
105
  }
106
106
  var RAW_STORE_ROOT_ENV = "HASNA_CONFIGS_HOME";
107
107
  var init_raw_store_root = () => {};
108
108
 
109
109
  // src/db/database.ts
110
110
  import { Database } from "bun:sqlite";
111
- import { existsSync, mkdirSync, rmSync } from "fs";
112
- import { join as join2 } from "path";
111
+ import { existsSync as existsSync2, mkdirSync, rmSync } from "fs";
112
+ import { join as join3 } from "path";
113
113
  import { randomUUID } from "crypto";
114
114
  function getDbPath() {
115
115
  if (process.env["HASNA_INSTRUCTIONS_DB_PATH"]) {
@@ -117,7 +117,7 @@ function getDbPath() {
117
117
  }
118
118
  const dir = getRawStoreRoot();
119
119
  mkdirSync(dir, { recursive: true });
120
- return join2(dir, "instructions.db");
120
+ return join3(dir, "instructions.db");
121
121
  }
122
122
  function uuid() {
123
123
  return randomUUID();
@@ -158,7 +158,7 @@ function resetLocalDatabase() {
158
158
  if (dbPath === ":memory:")
159
159
  return;
160
160
  for (const p of [dbPath, `${dbPath}-wal`, `${dbPath}-shm`]) {
161
- if (existsSync(p))
161
+ if (existsSync2(p))
162
162
  rmSync(p);
163
163
  }
164
164
  }
@@ -527,11 +527,11 @@ var init_configs = __esm(() => {
527
527
  // src/lib/template.ts
528
528
  var exports_template = {};
529
529
  __export(exports_template, {
530
- extractTemplateVars: () => extractTemplateVars,
531
- isTemplate: () => isTemplate,
532
- parseTemplateVars: () => parseTemplateVars,
530
+ renderTemplatePreview: () => renderTemplatePreview,
533
531
  renderTemplate: () => renderTemplate,
534
- renderTemplatePreview: () => renderTemplatePreview
532
+ parseTemplateVars: () => parseTemplateVars,
533
+ isTemplate: () => isTemplate,
534
+ extractTemplateVars: () => extractTemplateVars
535
535
  });
536
536
  function parseTemplateVars(content) {
537
537
  const names = new Set;
@@ -596,8 +596,8 @@ var init_template = __esm(() => {
596
596
 
597
597
  // src/lib/machine.ts
598
598
  import { arch as currentArch, homedir as homedir2, hostname as currentHostname, type as currentOsType } from "os";
599
- import { existsSync as existsSync2 } from "fs";
600
- import { join as join3 } from "path";
599
+ import { existsSync as existsSync3 } from "fs";
600
+ import { join as join4 } from "path";
601
601
  function normalizeOsFamily(os) {
602
602
  const value = (os ?? "").trim().toLowerCase();
603
603
  if (value === "darwin" || value === "macos" || value === "mac" || value === "osx")
@@ -612,8 +612,8 @@ function detectMachineContext(overrides = {}) {
612
612
  const homeDir = overrides.home_dir ?? process.env["CONFIGS_HOME"] ?? process.env["HOME"] ?? homedir2();
613
613
  const os = overrides.os ?? currentOsType();
614
614
  const osFamily = normalizeOsFamily(os);
615
- const bunBinDir = overrides.bun_bin_dir ?? join3(homeDir, ".bun", "bin");
616
- const defaultBunPath = osFamily === "macos" && existsSync2(BREW_BUN_PATH) ? BREW_BUN_PATH : join3(bunBinDir, "bun");
615
+ const bunBinDir = overrides.bun_bin_dir ?? join4(homeDir, ".bun", "bin");
616
+ const defaultBunPath = osFamily === "macos" && existsSync3(BREW_BUN_PATH) ? BREW_BUN_PATH : join4(bunBinDir, "bun");
617
617
  return {
618
618
  id: "current-machine",
619
619
  hostname: overrides.hostname ?? currentHostname(),
@@ -623,10 +623,10 @@ function detectMachineContext(overrides = {}) {
623
623
  created_at: "",
624
624
  os_family: osFamily,
625
625
  home_dir: homeDir,
626
- workspace_root: overrides.workspace_root ?? join3(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
626
+ workspace_root: overrides.workspace_root ?? join4(homeDir, osFamily === "macos" ? "Workspace" : "workspace"),
627
627
  bun_bin_dir: bunBinDir,
628
628
  bun_path: overrides.bun_path ?? defaultBunPath,
629
- path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join3("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
629
+ path_prefix: overrides.path_prefix ?? (osFamily === "macos" ? `${join4("/opt", "homebrew", "bin")}:${bunBinDir}` : bunBinDir)
630
630
  };
631
631
  }
632
632
  function machineContextToVariables(machine) {
@@ -4777,113 +4777,113 @@ var init_types2 = __esm(() => {
4777
4777
  // ../../node_modules/.bun/zod@3.25.76/node_modules/zod/v3/external.js
4778
4778
  var exports_external = {};
4779
4779
  __export(exports_external, {
4780
- BRAND: () => BRAND,
4781
- DIRTY: () => DIRTY,
4782
- EMPTY_PATH: () => EMPTY_PATH,
4783
- INVALID: () => INVALID,
4784
- NEVER: () => NEVER,
4785
- OK: () => OK,
4786
- ParseStatus: () => ParseStatus,
4787
- Schema: () => ZodType,
4788
- ZodAny: () => ZodAny,
4789
- ZodArray: () => ZodArray,
4790
- ZodBigInt: () => ZodBigInt,
4791
- ZodBoolean: () => ZodBoolean,
4792
- ZodBranded: () => ZodBranded,
4793
- ZodCatch: () => ZodCatch,
4794
- ZodDate: () => ZodDate,
4795
- ZodDefault: () => ZodDefault,
4796
- ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
4797
- ZodEffects: () => ZodEffects,
4798
- ZodEnum: () => ZodEnum,
4799
- ZodError: () => ZodError,
4800
- ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
4801
- ZodFunction: () => ZodFunction,
4802
- ZodIntersection: () => ZodIntersection,
4803
- ZodIssueCode: () => ZodIssueCode,
4804
- ZodLazy: () => ZodLazy,
4805
- ZodLiteral: () => ZodLiteral,
4806
- ZodMap: () => ZodMap,
4807
- ZodNaN: () => ZodNaN,
4808
- ZodNativeEnum: () => ZodNativeEnum,
4809
- ZodNever: () => ZodNever,
4810
- ZodNull: () => ZodNull,
4811
- ZodNullable: () => ZodNullable,
4812
- ZodNumber: () => ZodNumber,
4813
- ZodObject: () => ZodObject,
4814
- ZodOptional: () => ZodOptional,
4815
- ZodParsedType: () => ZodParsedType,
4816
- ZodPipeline: () => ZodPipeline,
4817
- ZodPromise: () => ZodPromise,
4818
- ZodReadonly: () => ZodReadonly,
4819
- ZodRecord: () => ZodRecord,
4820
- ZodSchema: () => ZodType,
4821
- ZodSet: () => ZodSet,
4822
- ZodString: () => ZodString,
4823
- ZodSymbol: () => ZodSymbol,
4824
- ZodTransformer: () => ZodEffects,
4825
- ZodTuple: () => ZodTuple,
4826
- ZodType: () => ZodType,
4827
- ZodUndefined: () => ZodUndefined,
4828
- ZodUnion: () => ZodUnion,
4829
- ZodUnknown: () => ZodUnknown,
4830
- ZodVoid: () => ZodVoid,
4831
- addIssueToContext: () => addIssueToContext,
4832
- any: () => anyType,
4833
- array: () => arrayType,
4834
- bigint: () => bigIntType,
4835
- boolean: () => booleanType,
4836
- coerce: () => coerce,
4837
- custom: () => custom,
4838
- date: () => dateType,
4839
- datetimeRegex: () => datetimeRegex,
4840
- defaultErrorMap: () => en_default,
4841
- discriminatedUnion: () => discriminatedUnionType,
4842
- effect: () => effectsType,
4843
- enum: () => enumType,
4844
- function: () => functionType,
4845
- getErrorMap: () => getErrorMap,
4846
- getParsedType: () => getParsedType,
4847
- instanceof: () => instanceOfType,
4848
- intersection: () => intersectionType,
4849
- isAborted: () => isAborted,
4850
- isAsync: () => isAsync,
4851
- isDirty: () => isDirty,
4852
- isValid: () => isValid,
4853
- late: () => late,
4854
- lazy: () => lazyType,
4855
- literal: () => literalType,
4856
- makeIssue: () => makeIssue,
4857
- map: () => mapType,
4858
- nan: () => nanType,
4859
- nativeEnum: () => nativeEnumType,
4860
- never: () => neverType,
4861
- null: () => nullType,
4862
- nullable: () => nullableType,
4863
- number: () => numberType,
4864
- object: () => objectType,
4865
- objectUtil: () => objectUtil,
4866
- oboolean: () => oboolean,
4867
- onumber: () => onumber,
4868
- optional: () => optionalType,
4869
- ostring: () => ostring,
4870
- pipeline: () => pipelineType,
4871
- preprocess: () => preprocessType,
4872
- promise: () => promiseType,
4873
- quotelessJson: () => quotelessJson,
4874
- record: () => recordType,
4875
- set: () => setType,
4876
- setErrorMap: () => setErrorMap,
4877
- strictObject: () => strictObjectType,
4878
- string: () => stringType,
4879
- symbol: () => symbolType,
4880
- transformer: () => effectsType,
4881
- tuple: () => tupleType,
4882
- undefined: () => undefinedType,
4883
- union: () => unionType,
4884
- unknown: () => unknownType,
4780
+ void: () => voidType,
4885
4781
  util: () => util,
4886
- void: () => voidType
4782
+ unknown: () => unknownType,
4783
+ union: () => unionType,
4784
+ undefined: () => undefinedType,
4785
+ tuple: () => tupleType,
4786
+ transformer: () => effectsType,
4787
+ symbol: () => symbolType,
4788
+ string: () => stringType,
4789
+ strictObject: () => strictObjectType,
4790
+ setErrorMap: () => setErrorMap,
4791
+ set: () => setType,
4792
+ record: () => recordType,
4793
+ quotelessJson: () => quotelessJson,
4794
+ promise: () => promiseType,
4795
+ preprocess: () => preprocessType,
4796
+ pipeline: () => pipelineType,
4797
+ ostring: () => ostring,
4798
+ optional: () => optionalType,
4799
+ onumber: () => onumber,
4800
+ oboolean: () => oboolean,
4801
+ objectUtil: () => objectUtil,
4802
+ object: () => objectType,
4803
+ number: () => numberType,
4804
+ nullable: () => nullableType,
4805
+ null: () => nullType,
4806
+ never: () => neverType,
4807
+ nativeEnum: () => nativeEnumType,
4808
+ nan: () => nanType,
4809
+ map: () => mapType,
4810
+ makeIssue: () => makeIssue,
4811
+ literal: () => literalType,
4812
+ lazy: () => lazyType,
4813
+ late: () => late,
4814
+ isValid: () => isValid,
4815
+ isDirty: () => isDirty,
4816
+ isAsync: () => isAsync,
4817
+ isAborted: () => isAborted,
4818
+ intersection: () => intersectionType,
4819
+ instanceof: () => instanceOfType,
4820
+ getParsedType: () => getParsedType,
4821
+ getErrorMap: () => getErrorMap,
4822
+ function: () => functionType,
4823
+ enum: () => enumType,
4824
+ effect: () => effectsType,
4825
+ discriminatedUnion: () => discriminatedUnionType,
4826
+ defaultErrorMap: () => en_default,
4827
+ datetimeRegex: () => datetimeRegex,
4828
+ date: () => dateType,
4829
+ custom: () => custom,
4830
+ coerce: () => coerce,
4831
+ boolean: () => booleanType,
4832
+ bigint: () => bigIntType,
4833
+ array: () => arrayType,
4834
+ any: () => anyType,
4835
+ addIssueToContext: () => addIssueToContext,
4836
+ ZodVoid: () => ZodVoid,
4837
+ ZodUnknown: () => ZodUnknown,
4838
+ ZodUnion: () => ZodUnion,
4839
+ ZodUndefined: () => ZodUndefined,
4840
+ ZodType: () => ZodType,
4841
+ ZodTuple: () => ZodTuple,
4842
+ ZodTransformer: () => ZodEffects,
4843
+ ZodSymbol: () => ZodSymbol,
4844
+ ZodString: () => ZodString,
4845
+ ZodSet: () => ZodSet,
4846
+ ZodSchema: () => ZodType,
4847
+ ZodRecord: () => ZodRecord,
4848
+ ZodReadonly: () => ZodReadonly,
4849
+ ZodPromise: () => ZodPromise,
4850
+ ZodPipeline: () => ZodPipeline,
4851
+ ZodParsedType: () => ZodParsedType,
4852
+ ZodOptional: () => ZodOptional,
4853
+ ZodObject: () => ZodObject,
4854
+ ZodNumber: () => ZodNumber,
4855
+ ZodNullable: () => ZodNullable,
4856
+ ZodNull: () => ZodNull,
4857
+ ZodNever: () => ZodNever,
4858
+ ZodNativeEnum: () => ZodNativeEnum,
4859
+ ZodNaN: () => ZodNaN,
4860
+ ZodMap: () => ZodMap,
4861
+ ZodLiteral: () => ZodLiteral,
4862
+ ZodLazy: () => ZodLazy,
4863
+ ZodIssueCode: () => ZodIssueCode,
4864
+ ZodIntersection: () => ZodIntersection,
4865
+ ZodFunction: () => ZodFunction,
4866
+ ZodFirstPartyTypeKind: () => ZodFirstPartyTypeKind,
4867
+ ZodError: () => ZodError,
4868
+ ZodEnum: () => ZodEnum,
4869
+ ZodEffects: () => ZodEffects,
4870
+ ZodDiscriminatedUnion: () => ZodDiscriminatedUnion,
4871
+ ZodDefault: () => ZodDefault,
4872
+ ZodDate: () => ZodDate,
4873
+ ZodCatch: () => ZodCatch,
4874
+ ZodBranded: () => ZodBranded,
4875
+ ZodBoolean: () => ZodBoolean,
4876
+ ZodBigInt: () => ZodBigInt,
4877
+ ZodArray: () => ZodArray,
4878
+ ZodAny: () => ZodAny,
4879
+ Schema: () => ZodType,
4880
+ ParseStatus: () => ParseStatus,
4881
+ OK: () => OK,
4882
+ NEVER: () => NEVER,
4883
+ INVALID: () => INVALID,
4884
+ EMPTY_PATH: () => EMPTY_PATH,
4885
+ DIRTY: () => DIRTY,
4886
+ BRAND: () => BRAND
4887
4887
  });
4888
4888
  var init_external = __esm(() => {
4889
4889
  init_errors();
@@ -4903,11 +4903,11 @@ var init_zod = __esm(() => {
4903
4903
  // src/lib/redact.ts
4904
4904
  var exports_redact = {};
4905
4905
  __export(exports_redact, {
4906
- hasSecrets: () => hasSecrets,
4907
- isSecretVarName: () => isSecretVarName,
4908
- redactContent: () => redactContent,
4906
+ scanSecrets: () => scanSecrets,
4909
4907
  redactFormatForTarget: () => redactFormatForTarget,
4910
- scanSecrets: () => scanSecrets
4908
+ redactContent: () => redactContent,
4909
+ isSecretVarName: () => isSecretVarName,
4910
+ hasSecrets: () => hasSecrets
4911
4911
  });
4912
4912
  function redactShell(content) {
4913
4913
  const redacted = [];
@@ -5115,7 +5115,7 @@ var init_session_render_contract = __esm(() => {
5115
5115
  });
5116
5116
 
5117
5117
  // src/lib/project-context.ts
5118
- import { basename, dirname, isAbsolute, join as join4, parse, relative, resolve as resolve2 } from "path";
5118
+ import { basename, dirname as dirname2, isAbsolute, join as join5, parse, relative, resolve as resolve2 } from "path";
5119
5119
  function revisionKey(value) {
5120
5120
  const sequence = value.match(/^(?:rev-)?([0-9]+)$/);
5121
5121
  if (sequence)
@@ -5678,7 +5678,7 @@ var init_asset_plan = __esm(() => {
5678
5678
  // src/lib/cursor-authority.ts
5679
5679
  import { createHash } from "crypto";
5680
5680
  import { homedir as homedir3 } from "os";
5681
- import { join as join5, resolve as resolve3 } from "path";
5681
+ import { join as join6, resolve as resolve3 } from "path";
5682
5682
  function sha256(content) {
5683
5683
  return createHash("sha256").update(content).digest("hex");
5684
5684
  }
@@ -5686,7 +5686,7 @@ function homeDir() {
5686
5686
  return process.env["HOME"] || homedir3();
5687
5687
  }
5688
5688
  function isCursorGlobalAuthorityPath(path) {
5689
- return resolve3(path) === resolve3(join5(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
5689
+ return resolve3(path) === resolve3(join6(homeDir(), CURSOR_GLOBAL_AUTHORITY_RELATIVE_PATH));
5690
5690
  }
5691
5691
  function stampCursorGlobalAuthorityMarker(content) {
5692
5692
  if (CURSOR_GLOBAL_AUTHORITY_MARKER_PATTERN.test(content))
@@ -6030,7 +6030,12 @@ var init_instruction_graph = __esm(() => {
6030
6030
  init_asset_plan();
6031
6031
  COMMON_FALLBACKS = ["fail", "flatten", "promote-always", "omit"];
6032
6032
  DEFAULT_PROVIDER_CAPABILITIES = Object.freeze({
6033
- claude: capability("claude", ">=1.0.0", "native-import", "CLAUDE.md @ imports", { native_imports: true, asset_surface: "code" }),
6033
+ claude: capability("claude", ">=1.0.0", "native-import", "CLAUDE.md @ imports plus path-gated rules", {
6034
+ activation_modes: ["always", "glob"],
6035
+ native_imports: true,
6036
+ conditional_artifacts: true,
6037
+ asset_surface: "code"
6038
+ }),
6034
6039
  codex: capability("codex", ">=0.1.0", "flattened", "AGENTS.md", { asset_surface: "cli" }),
6035
6040
  cursor: capability("cursor", ">=1.0.0", "cursor-rule", ".cursor/rules/*.mdc", { activation_modes: ["always", "glob"], conditional_artifacts: true, asset_surface: "ide" }),
6036
6041
  opencode: capability("opencode", ">=1.0.0", "managed-fragment", "opencode.json instructions", { provider_variant: "v1-instructions", session_surface: "opencode-config-instructions" }),
@@ -6879,8 +6884,8 @@ var init_config_store = __esm(() => {
6879
6884
  });
6880
6885
 
6881
6886
  // src/lib/session-render-ownership.ts
6882
- import { existsSync as existsSync3, readFileSync, statSync } from "fs";
6883
- import { dirname as dirname2, join as join6, parse as parse2, relative as relative2, sep } from "path";
6887
+ import { existsSync as existsSync4, readFileSync as readFileSync2, statSync } from "fs";
6888
+ import { dirname as dirname3, join as join7, parse as parse2, relative as relative2, sep } from "path";
6884
6889
  function toSegments(absolutePath2) {
6885
6890
  return absolutePath2.replaceAll("\\", "/").split("/").filter(Boolean);
6886
6891
  }
@@ -6899,19 +6904,19 @@ function pathIsSessionRenderManagedDir(absolutePath2) {
6899
6904
  function readManifestRelativePaths(manifestPath) {
6900
6905
  let stats;
6901
6906
  try {
6902
- if (!existsSync3(manifestPath))
6907
+ if (!existsSync4(manifestPath))
6903
6908
  return null;
6904
6909
  stats = statSync(manifestPath);
6905
6910
  } catch {
6906
6911
  return null;
6907
6912
  }
6908
- const cached = manifestCache.get(manifestPath);
6909
- if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) {
6910
- return cached.relativePaths;
6913
+ const cached2 = manifestCache.get(manifestPath);
6914
+ if (cached2 && cached2.mtimeMs === stats.mtimeMs && cached2.size === stats.size) {
6915
+ return cached2.relativePaths;
6911
6916
  }
6912
6917
  let manifest;
6913
6918
  try {
6914
- manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
6919
+ manifest = JSON.parse(readFileSync2(manifestPath, "utf-8"));
6915
6920
  } catch {
6916
6921
  return null;
6917
6922
  }
@@ -6926,16 +6931,16 @@ function readManifestRelativePaths(manifestPath) {
6926
6931
  }
6927
6932
  function sessionRenderManifestClaimsPath(absolutePath2) {
6928
6933
  const root = parse2(absolutePath2).root;
6929
- let home = dirname2(absolutePath2);
6934
+ let home = dirname3(absolutePath2);
6930
6935
  for (let depth = 0;depth < MANIFEST_ANCESTOR_LIMIT; depth += 1) {
6931
- const manifestPath = join6(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
6936
+ const manifestPath = join7(home, ...SESSION_RENDER_MANIFEST_RELATIVE_PATH.split("/"));
6932
6937
  const relativePaths = readManifestRelativePaths(manifestPath);
6933
6938
  if (relativePaths) {
6934
6939
  const claimed = relative2(home, absolutePath2).split(sep).join("/");
6935
6940
  if (relativePaths.has(claimed))
6936
6941
  return true;
6937
6942
  }
6938
- const parent = dirname2(home);
6943
+ const parent = dirname3(home);
6939
6944
  if (parent === home || home === root)
6940
6945
  break;
6941
6946
  home = parent;
@@ -6955,16 +6960,16 @@ var init_session_render_ownership = __esm(() => {
6955
6960
  // src/lib/apply.ts
6956
6961
  var exports_apply = {};
6957
6962
  __export(exports_apply, {
6958
- applyConfig: () => applyConfig,
6959
- applyConfigs: () => applyConfigs,
6960
- applyConfigsWithReport: () => applyConfigsWithReport,
6961
- expandPath: () => expandPath,
6962
- getConfigHome: () => getConfigHome,
6963
+ previewConfigs: () => previewConfigs,
6963
6964
  normalizeTargetPath: () => normalizeTargetPath,
6964
- previewConfigs: () => previewConfigs
6965
+ getConfigHome: () => getConfigHome,
6966
+ expandPath: () => expandPath,
6967
+ applyConfigsWithReport: () => applyConfigsWithReport,
6968
+ applyConfigs: () => applyConfigs,
6969
+ applyConfig: () => applyConfig
6965
6970
  });
6966
- import { existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2, realpathSync, writeFileSync } from "fs";
6967
- import { basename as basename3, dirname as dirname3, join as join7, resolve as resolve4 } from "path";
6971
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync3, realpathSync, writeFileSync } from "fs";
6972
+ import { basename as basename3, dirname as dirname4, join as join8, resolve as resolve4 } from "path";
6968
6973
  import { homedir as homedir4 } from "os";
6969
6974
  function getConfigHome() {
6970
6975
  return process.env["CONFIGS_HOME"] || process.env["HOME"] || homedir4();
@@ -6983,14 +6988,14 @@ function normalizeTargetPath(p) {
6983
6988
  let current = expanded;
6984
6989
  const missingSegments = [];
6985
6990
  while (true) {
6986
- if (existsSync4(current)) {
6991
+ if (existsSync5(current)) {
6987
6992
  try {
6988
6993
  return resolve4(realpathSync(current), ...missingSegments);
6989
6994
  } catch {
6990
6995
  return expanded;
6991
6996
  }
6992
6997
  }
6993
- const parent = dirname3(current);
6998
+ const parent = dirname4(current);
6994
6999
  const name = basename3(current);
6995
7000
  if (parent === current)
6996
7001
  return expanded;
@@ -7014,11 +7019,11 @@ async function writeConfigResult(config, targetPath, content, opts, meta = {}) {
7014
7019
  }
7015
7020
  const path = expandPath(renderedTargetPath);
7016
7021
  const renderedForTarget = isCursorGlobalAuthorityPath(path) ? stampCursorGlobalAuthorityMarker(renderedContent) : renderedContent;
7017
- const previousContent = existsSync4(path) ? readFileSync2(path, "utf-8") : null;
7022
+ const previousContent = existsSync5(path) ? readFileSync3(path, "utf-8") : null;
7018
7023
  const changed = previousContent !== renderedForTarget;
7019
7024
  if (!opts.dryRun) {
7020
- const dir = dirname3(path);
7021
- if (!existsSync4(dir)) {
7025
+ const dir = dirname4(path);
7026
+ if (!existsSync5(dir)) {
7022
7027
  mkdirSync2(dir, { recursive: true });
7023
7028
  }
7024
7029
  if (previousContent !== null && changed) {
@@ -7052,9 +7057,9 @@ function wouldDestroyACredential(targetPath, renderedContent, format) {
7052
7057
  let current;
7053
7058
  try {
7054
7059
  const path = expandPath(targetPath);
7055
- if (!existsSync4(path))
7060
+ if (!existsSync5(path))
7056
7061
  return [];
7057
- current = readFileSync2(path, "utf-8");
7062
+ current = readFileSync3(path, "utf-8");
7058
7063
  } catch {
7059
7064
  return secretTokens;
7060
7065
  }
@@ -7142,7 +7147,7 @@ async function applyPreparedConfig(config, opts) {
7142
7147
  changed: outputResults.some((output) => output.changed)
7143
7148
  };
7144
7149
  }
7145
- if (!opts.dryRun) {
7150
+ if (!opts.dryRun && result.changed) {
7146
7151
  await store.updateConfig(config.id, { synced_at: new Date().toISOString() });
7147
7152
  }
7148
7153
  return result;
@@ -7378,7 +7383,7 @@ function sessionRendererOwnsCanonicalTarget(normalized, opts) {
7378
7383
  getConfigHome(),
7379
7384
  opts.vars?.["HOME_DIR"]
7380
7385
  ].filter((home) => typeof home === "string" && home.length > 0));
7381
- if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join7(home, ...relativePath.split("/"))))))
7386
+ if ([...homes].some((home) => SESSION_RENDER_OWNED_CONFIG_TARGETS.some((relativePath) => normalized === normalizeTargetPath(join8(home, ...relativePath.split("/"))))))
7382
7387
  return true;
7383
7388
  return sessionRenderOwnsPath(normalized);
7384
7389
  }
@@ -7398,21 +7403,21 @@ var init_apply = __esm(() => {
7398
7403
  // src/lib/sync.ts
7399
7404
  var exports_sync = {};
7400
7405
  __export(exports_sync, {
7401
- CLAUDE_PROMPT_OUTPUTS: () => CLAUDE_PROMPT_OUTPUTS,
7402
- KNOWN_CONFIGS: () => KNOWN_CONFIGS,
7403
- PROJECT_CONFIG_FILES: () => PROJECT_CONFIG_FILES,
7404
- detectAgent: () => detectAgent,
7405
- detectCategory: () => detectCategory,
7406
- detectFormat: () => detectFormat,
7407
- diffConfig: () => diffConfig,
7408
- syncFromDir: () => syncFromDir,
7409
- syncKnown: () => syncKnown,
7410
- syncProject: () => syncProject,
7406
+ syncToDisk: () => syncToDisk,
7411
7407
  syncToDir: () => syncToDir,
7412
- syncToDisk: () => syncToDisk
7408
+ syncProject: () => syncProject,
7409
+ syncKnown: () => syncKnown,
7410
+ syncFromDir: () => syncFromDir,
7411
+ diffConfig: () => diffConfig,
7412
+ detectFormat: () => detectFormat,
7413
+ detectCategory: () => detectCategory,
7414
+ detectAgent: () => detectAgent,
7415
+ PROJECT_CONFIG_FILES: () => PROJECT_CONFIG_FILES,
7416
+ KNOWN_CONFIGS: () => KNOWN_CONFIGS,
7417
+ CLAUDE_PROMPT_OUTPUTS: () => CLAUDE_PROMPT_OUTPUTS
7413
7418
  });
7414
- import { existsSync as existsSync5, readdirSync, readFileSync as readFileSync3 } from "fs";
7415
- import { basename as basename4, extname as extname2, join as join8 } from "path";
7419
+ import { existsSync as existsSync6, readdirSync, readFileSync as readFileSync4 } from "fs";
7420
+ import { basename as basename4, extname as extname2, join as join9 } from "path";
7416
7421
  function claudeRuleOutputs(fileName) {
7417
7422
  const stem = basename4(fileName, extname2(fileName));
7418
7423
  return [
@@ -7451,7 +7456,7 @@ function isGeneratedOutputTarget2(config, owners) {
7451
7456
  return !!ownerIds && !ownerIds.has(config.id);
7452
7457
  }
7453
7458
  function hasClaudePromptSource() {
7454
- return existsSync5(expandPath("~/.claude/CLAUDE.md"));
7459
+ return existsSync6(expandPath("~/.claude/CLAUDE.md"));
7455
7460
  }
7456
7461
  function hasClaudeRuleSourceForCursorTarget(targetPath) {
7457
7462
  const absoluteTargetPath = expandPath(targetPath);
@@ -7459,7 +7464,7 @@ function hasClaudeRuleSourceForCursorTarget(targetPath) {
7459
7464
  if (!absoluteTargetPath.startsWith(`${absolutePrefix}/`) || !absoluteTargetPath.endsWith(".mdc"))
7460
7465
  return false;
7461
7466
  const stem = basename4(absoluteTargetPath, ".mdc");
7462
- return existsSync5(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync5(expandPath(`~/.claude/rules/${stem}.mdc`));
7467
+ return existsSync6(expandPath(`~/.claude/rules/${stem}.md`)) || existsSync6(expandPath(`~/.claude/rules/${stem}.mdc`));
7463
7468
  }
7464
7469
  function isKnownGeneratedTargetPath(targetPath) {
7465
7470
  const normalizedTargetPath = normalizeTargetPath(targetPath);
@@ -7476,11 +7481,11 @@ async function syncProject(opts) {
7476
7481
  const allConfigs = await store.listConfigs();
7477
7482
  const machine = detectMachineContext();
7478
7483
  for (const pf of PROJECT_CONFIG_FILES) {
7479
- const abs = join8(absDir, pf.file);
7480
- if (!existsSync5(abs))
7484
+ const abs = join9(absDir, pf.file);
7485
+ if (!existsSync6(abs))
7481
7486
  continue;
7482
7487
  try {
7483
- const rawContent = readFileSync3(abs, "utf-8");
7488
+ const rawContent = readFileSync4(abs, "utf-8");
7484
7489
  if (rawContent.length > 500000) {
7485
7490
  result.skipped.push(pf.file);
7486
7491
  continue;
@@ -7509,20 +7514,20 @@ async function syncProject(opts) {
7509
7514
  }
7510
7515
  }
7511
7516
  for (const ruleDir of [
7512
- { dir: join8(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
7513
- { dir: join8(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
7514
- { dir: join8(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
7515
- { dir: join8(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
7516
- { dir: join8(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
7517
- { dir: join8(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
7518
- { dir: join8(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
7517
+ { dir: join9(absDir, ".claude", "rules"), agent: "claude", namePrefix: "rules" },
7518
+ { dir: join9(absDir, ".agents", "rules"), agent: "antigravity", namePrefix: "antigravity-rules" },
7519
+ { dir: join9(absDir, ".cursor", "rules"), agent: "cursor", namePrefix: "cursor-rules" },
7520
+ { dir: join9(absDir, ".github", "instructions"), agent: "copilot", namePrefix: "copilot-instructions" },
7521
+ { dir: join9(absDir, ".devin", "rules"), agent: "devin", namePrefix: "devin-rules" },
7522
+ { dir: join9(absDir, ".windsurf", "rules"), agent: "windsurf-legacy", namePrefix: "windsurf-rules" },
7523
+ { dir: join9(absDir, ".clinerules"), agent: "cline", namePrefix: "cline-rules" }
7519
7524
  ]) {
7520
- if (!existsSync5(ruleDir.dir))
7525
+ if (!existsSync6(ruleDir.dir))
7521
7526
  continue;
7522
7527
  const mdFiles = readdirSync(ruleDir.dir).filter((f) => f.endsWith(".md") || f.endsWith(".mdc"));
7523
7528
  for (const f of mdFiles) {
7524
- const abs = join8(ruleDir.dir, f);
7525
- const raw = readFileSync3(abs, "utf-8");
7529
+ const abs = join9(ruleDir.dir, f);
7530
+ const raw = readFileSync4(abs, "utf-8");
7526
7531
  const redacted = redactContent(raw, "markdown");
7527
7532
  const machineAware = templateizeMachineContent(redacted.content, machine);
7528
7533
  const content = machineAware.content;
@@ -7561,20 +7566,20 @@ async function syncKnown(opts = {}) {
7561
7566
  for (const known of targets) {
7562
7567
  if (known.rulesDir) {
7563
7568
  const absDir = expandPath(known.rulesDir);
7564
- if (!existsSync5(absDir)) {
7569
+ if (!existsSync6(absDir)) {
7565
7570
  result.skipped.push(known.rulesDir);
7566
7571
  continue;
7567
7572
  }
7568
7573
  const extensions = known.rulesExtensions ?? [".md", ".mdc"];
7569
7574
  const ruleFiles = readdirSync(absDir).filter((f) => extensions.some((ext) => f.endsWith(ext)));
7570
7575
  for (const f of ruleFiles) {
7571
- const abs2 = join8(absDir, f);
7576
+ const abs2 = join9(absDir, f);
7572
7577
  const targetPath = abs2.replace(home, "~");
7573
7578
  if (existingOutputOwners.has(normalizeTargetPath(targetPath)) || isKnownGeneratedTargetPath(targetPath)) {
7574
7579
  result.skipped.push(`${targetPath} (generated output)`);
7575
7580
  continue;
7576
7581
  }
7577
- const raw = readFileSync3(abs2, "utf-8");
7582
+ const raw = readFileSync4(abs2, "utf-8");
7578
7583
  const redacted = redactContent(raw, "markdown");
7579
7584
  const machineAware = templateizeMachineContent(redacted.content, machine);
7580
7585
  const content = machineAware.content;
@@ -7602,18 +7607,18 @@ async function syncKnown(opts = {}) {
7602
7607
  continue;
7603
7608
  }
7604
7609
  const abs = expandPath(known.path);
7605
- if (!existsSync5(abs)) {
7610
+ if (!existsSync6(abs)) {
7606
7611
  result.skipped.push(known.path);
7607
7612
  continue;
7608
7613
  }
7609
7614
  try {
7610
- const rawContent = normalizeKnownConfigSource(known, readFileSync3(abs, "utf-8"));
7615
+ const rawContent = normalizeKnownConfigSource(known, readFileSync4(abs, "utf-8"));
7611
7616
  if (rawContent.length > 500000) {
7612
7617
  result.skipped.push(known.path + " (too large)");
7613
7618
  continue;
7614
7619
  }
7615
7620
  const fmt = known.format ?? detectFormat(abs);
7616
- const redacted = redactContent(rawContent, fmt);
7621
+ const redacted = redactContent(rawContent, redactFormatForTarget(abs, fmt));
7617
7622
  const machineAware = templateizeMachineContent(redacted.content, machine);
7618
7623
  const content = machineAware.content;
7619
7624
  const isTemplate2 = redacted.isTemplate || machineAware.changed;
@@ -7708,9 +7713,9 @@ function storedPlaceholderIsLiteralOnDisk(storedLine, diskLine) {
7708
7713
  }
7709
7714
  function buildDiff(expectedContent, targetPath, storedFormat, showSecrets) {
7710
7715
  const path = expandPath(targetPath);
7711
- if (!existsSync5(path))
7716
+ if (!existsSync6(path))
7712
7717
  return `(file not found on disk: ${path})`;
7713
- const diskContent = readFileSync3(path, "utf-8");
7718
+ const diskContent = readFileSync4(path, "utf-8");
7714
7719
  if (diskContent === expectedContent)
7715
7720
  return "(no diff \u2014 identical)";
7716
7721
  const format = redactFormatForTarget(targetPath, storedFormat);
@@ -7938,8 +7943,8 @@ var init_sync = __esm(() => {
7938
7943
  });
7939
7944
 
7940
7945
  // src/lib/sync-dir.ts
7941
- import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
7942
- import { join as join9, relative as relative3 } from "path";
7946
+ import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
7947
+ import { join as join10, relative as relative3 } from "path";
7943
7948
  import { homedir as homedir5 } from "os";
7944
7949
  function shouldSkip(p) {
7945
7950
  return SKIP.some((s) => p.includes(s));
@@ -7947,9 +7952,9 @@ function shouldSkip(p) {
7947
7952
  async function syncFromDir(dir, opts = {}) {
7948
7953
  const store = opts.store ?? resolveConfigStore();
7949
7954
  const absDir = expandPath(dir);
7950
- if (!existsSync6(absDir))
7955
+ if (!existsSync7(absDir))
7951
7956
  return { added: 0, updated: 0, unchanged: 0, skipped: [`Not found: ${absDir}`] };
7952
- const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join9(absDir, f)).filter((f) => statSync2(f).isFile());
7957
+ const files = opts.recursive !== false ? walkDir(absDir) : readdirSync2(absDir).map((f) => join10(absDir, f)).filter((f) => statSync2(f).isFile());
7953
7958
  const result = { added: 0, updated: 0, unchanged: 0, skipped: [] };
7954
7959
  const home = homedir5();
7955
7960
  const allConfigs = await store.listConfigs();
@@ -7959,20 +7964,21 @@ async function syncFromDir(dir, opts = {}) {
7959
7964
  continue;
7960
7965
  }
7961
7966
  try {
7962
- const content = readFileSync4(file, "utf-8");
7967
+ const content = readFileSync5(file, "utf-8");
7963
7968
  if (content.length > 500000) {
7964
7969
  result.skipped.push(file + " (too large)");
7965
7970
  continue;
7966
7971
  }
7967
7972
  const targetPath = file.replace(home, "~");
7973
+ const redacted = redactContent(content, redactFormatForTarget(targetPath, detectFormat(file)));
7968
7974
  const existing = allConfigs.find((c) => c.target_path === targetPath);
7969
7975
  if (!existing) {
7970
7976
  if (!opts.dryRun)
7971
- await store.createConfig({ name: relative3(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content });
7977
+ await store.createConfig({ name: relative3(absDir, file), category: detectCategory(file), agent: detectAgent(file), target_path: targetPath, format: detectFormat(file), content: redacted.content });
7972
7978
  result.added++;
7973
- } else if (existing.content !== content) {
7979
+ } else if (existing.content !== redacted.content) {
7974
7980
  if (!opts.dryRun)
7975
- await store.updateConfig(existing.id, { content });
7981
+ await store.updateConfig(existing.id, { content: redacted.content });
7976
7982
  result.updated++;
7977
7983
  } else {
7978
7984
  result.unchanged++;
@@ -8009,7 +8015,7 @@ async function syncToDir(dir, opts = {}) {
8009
8015
  }
8010
8016
  function walkDir(dir, files = []) {
8011
8017
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
8012
- const full = join9(dir, entry.name);
8018
+ const full = join10(dir, entry.name);
8013
8019
  if (shouldSkip(full))
8014
8020
  continue;
8015
8021
  if (entry.isDirectory())
@@ -8024,14 +8030,15 @@ var init_sync_dir = __esm(() => {
8024
8030
  init_config_store();
8025
8031
  init_apply();
8026
8032
  init_sync();
8033
+ init_redact();
8027
8034
  SKIP = [".db", ".db-shm", ".db-wal", ".log", ".lock", ".DS_Store", "node_modules", ".git"];
8028
8035
  });
8029
8036
 
8030
8037
  // package.json
8031
- var require_package = __commonJS(function(exports, module) {
8038
+ var require_package = __commonJS((exports, module) => {
8032
8039
  module.exports = {
8033
8040
  name: "@hasna/instructions",
8034
- version: "0.4.39",
8041
+ version: "0.4.43",
8035
8042
  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.",
8036
8043
  type: "module",
8037
8044
  main: "dist/index.js",
@@ -8131,6 +8138,35 @@ var require_package = __commonJS(function(exports, module) {
8131
8138
  // src/mcp/index.ts
8132
8139
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8133
8140
 
8141
+ // src/lib/package-version.ts
8142
+ import { existsSync, readFileSync } from "fs";
8143
+ import { dirname, join } from "path";
8144
+ import { fileURLToPath } from "url";
8145
+ var cached = null;
8146
+ function getPackageVersion() {
8147
+ if (cached)
8148
+ return cached;
8149
+ try {
8150
+ let dir = dirname(fileURLToPath(import.meta.url));
8151
+ for (let i = 0;i < 8; i++) {
8152
+ const pkgPath = join(dir, "package.json");
8153
+ if (existsSync(pkgPath)) {
8154
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
8155
+ if (pkg.name === "@hasna/instructions" && pkg.version) {
8156
+ cached = pkg.version;
8157
+ return cached;
8158
+ }
8159
+ }
8160
+ const parent = dirname(dir);
8161
+ if (parent === dir)
8162
+ break;
8163
+ dir = parent;
8164
+ }
8165
+ } catch {}
8166
+ cached = "0.0.0";
8167
+ return cached;
8168
+ }
8169
+
8134
8170
  // src/mcp/server.ts
8135
8171
  init_config_store();
8136
8172
  init_apply();
@@ -8369,7 +8405,7 @@ function buildServer() {
8369
8405
  const allConfigs = await store.listConfigs({ kind: "file" });
8370
8406
  const { existsSync: ex, readFileSync: rf } = await import("fs");
8371
8407
  const { expandPath: expandPath2 } = await Promise.resolve().then(() => (init_apply(), exports_apply));
8372
- const { redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
8408
+ const { redactContent: redactContent2, redactFormatForTarget: redactFormatForTarget2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
8373
8409
  let drifted = 0, missing = 0, templates = 0;
8374
8410
  const driftedSlugs = [];
8375
8411
  for (const c of allConfigs) {
@@ -8383,7 +8419,7 @@ function buildServer() {
8383
8419
  continue;
8384
8420
  }
8385
8421
  const disk = rf(abs, "utf-8");
8386
- const { content: redactedDisk } = redactContent2(disk, c.format);
8422
+ const { content: redactedDisk } = redactContent2(disk, redactFormatForTarget2(c.target_path, c.format));
8387
8423
  if (redactedDisk !== c.content) {
8388
8424
  drifted++;
8389
8425
  driftedSlugs.push(c.slug);
@@ -8430,11 +8466,11 @@ function buildServer() {
8430
8466
  return ok({ rendered, config_id: config.id, slug: config.slug });
8431
8467
  }
8432
8468
  case "scan_secrets": {
8433
- const { scanSecrets: scanSecrets2, redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
8469
+ const { scanSecrets: scanSecrets2, redactContent: redactContent2, redactFormatForTarget: redactFormatForTarget2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
8434
8470
  const configs = args["id_or_slug"] ? [await store.getConfig(args["id_or_slug"])] : await store.listConfigs({ kind: "file" });
8435
8471
  const findings = [];
8436
8472
  for (const c of configs) {
8437
- const fmt = c.format;
8473
+ const fmt = redactFormatForTarget2(c.target_path ?? "", c.format);
8438
8474
  const secrets = scanSecrets2(c.content, fmt);
8439
8475
  if (secrets.length > 0) {
8440
8476
  findings.push({ slug: c.slug, secrets: secrets.length, vars: secrets.map((s) => s.varName) });
@@ -8582,6 +8618,24 @@ async function startMcpHttpServer(port) {
8582
8618
  // src/mcp/index.ts
8583
8619
  async function main() {
8584
8620
  const argv = process.argv.slice(2);
8621
+ if (argv.includes("--version") || argv.includes("-V")) {
8622
+ console.log(getPackageVersion());
8623
+ return;
8624
+ }
8625
+ if (argv.includes("--help") || argv.includes("-h")) {
8626
+ console.log(`Usage: configs-mcp [options]
8627
+
8628
+ MCP server for @hasna/instructions (Streamable HTTP by default; --stdio to select stdio).
8629
+
8630
+ Options:
8631
+ -V, --version output the version number
8632
+ -h, --help display help for command
8633
+ --claude register with Claude Code (stdio, user scope)
8634
+ --http explicitly select Streamable HTTP transport
8635
+ --stdio explicitly select stdio transport
8636
+ --port <n> HTTP port (default: 8853)`);
8637
+ return;
8638
+ }
8585
8639
  if (argv.includes("--claude")) {
8586
8640
  const proc = Bun.spawn(["claude", "mcp", "add", "--transport", "stdio", "--scope", "user", "configs", "--", "configs-mcp"], { stdout: "inherit", stderr: "inherit" });
8587
8641
  await proc.exited;