claude-code-modes 0.2.2 → 0.2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-modes",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "Behaviorally-tuned system prompts for Claude Code",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/config.ts CHANGED
@@ -3,8 +3,13 @@ import { join, dirname, resolve, isAbsolute } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import { PRESET_NAMES, BUILTIN_MODIFIER_NAMES, AXIS_BUILTINS, BUILTIN_BASE_NAMES, isBuiltinModifier, isPresetName, isBuiltinBase, isBuiltinAxisValue } from "./types.js";
5
5
 
6
- /** Matches paths that reference potentially sensitive files (SSH keys, credentials, etc.) */
7
- const SUSPICIOUS_PATH_PATTERN = /\.(ssh|env|gnupg|aws|kube|docker|pgpass)|\.npmrc|\.netrc|id_rsa|id_ed25519|id_ecdsa|credentials|secret|token|password|private/i;
6
+ /**
7
+ * Matches paths that reference potentially sensitive files (SSH keys, credentials, etc.).
8
+ * Note: bare "private" was removed — it false-positives on macOS where resolved paths
9
+ * go through /private/var/folders/... Instead we match ".private/" (hidden directory)
10
+ * and "private_key"/"private-key" (common key naming patterns).
11
+ */
12
+ const SUSPICIOUS_PATH_PATTERN = /\.(ssh|env|gnupg|aws|kube|docker|pgpass)|\.npmrc|\.netrc|id_rsa|id_ed25519|id_ecdsa|credentials|secret|token|password|\.private[/]|private[_-]?key/i;
8
13
 
9
14
  /**
10
15
  * Validates a file path defined in a config file.
package/src/inspect.ts CHANGED
@@ -5,6 +5,7 @@ import { loadConfig, resolveConfigPath, type LoadedConfig } from "./config.js";
5
5
  import { resolveConfig } from "./resolve.js";
6
6
  import { getFragmentOrder } from "./assemble.js";
7
7
  import { detectEnv, buildTemplateVars } from "./env.js";
8
+ import { EMBEDDED_PROMPTS } from "./embedded-prompts.js";
8
9
  import type { TemplateVars } from "./types.js";
9
10
 
10
11
  const PROVENANCE_VALUES = ["built-in", "config-defined", "cli-path"] as const;
@@ -43,7 +44,13 @@ interface InspectResult {
43
44
  verbose: boolean;
44
45
  }
45
46
 
46
- const SUSPICIOUS_PATTERN = /\.(ssh|env|gnupg|aws|kube|docker|pgpass)|\.npmrc|\.netrc|id_rsa|id_ed25519|id_ecdsa|credentials|secret|token|password|private/i;
47
+ /**
48
+ * Matches paths that reference potentially sensitive files (SSH keys, credentials, etc.).
49
+ * Note: bare "private" was removed — it false-positives on macOS where resolved paths
50
+ * go through /private/var/folders/... Instead we match ".private/" (hidden directory)
51
+ * and "private_key"/"private-key" (common key naming patterns).
52
+ */
53
+ const SUSPICIOUS_PATTERN = /\.(ssh|env|gnupg|aws|kube|docker|pgpass)|\.npmrc|\.netrc|id_rsa|id_ed25519|id_ecdsa|credentials|secret|token|password|\.private[/]|private[_-]?key/i;
47
54
 
48
55
  /** Builds a Set of all absolute paths that config definitions could resolve to. */
49
56
  function collectConfigDefinedPaths(loadedConfig: LoadedConfig | null): Set<string> {
@@ -118,8 +125,9 @@ function detectWarnings(
118
125
 
119
126
  for (const frag of fragments) {
120
127
  if (frag.provenance === "built-in") {
121
- // Only check existence for built-in fragments
122
- if (!existsSync(frag.resolvedPath)) {
128
+ // Built-in fragments: check embedded prompts first, then disk
129
+ const embedded = frag.path in EMBEDDED_PROMPTS;
130
+ if (!embedded && !existsSync(frag.resolvedPath)) {
123
131
  warnings.push({
124
132
  fragmentIndex: frag.index,
125
133
  fragmentPath: frag.path,
@@ -264,8 +272,12 @@ function formatInspectOutput(result: InspectResult): string {
264
272
  return lines.join("\n") + "\n";
265
273
  }
266
274
 
267
- /** Reads a fragment file, returning its content or null if missing. */
268
- function readFragmentContent(resolvedPath: string): string | null {
275
+ /** Reads a fragment, checking embedded prompts first for built-in fragments. */
276
+ function readFragmentContent(fragPath: string, resolvedPath: string): string | null {
277
+ // Built-in fragments: check embedded prompts first (required for compiled binary)
278
+ if (!isAbsolute(fragPath) && fragPath in EMBEDDED_PROMPTS) {
279
+ return EMBEDDED_PROMPTS[fragPath];
280
+ }
269
281
  try {
270
282
  return readFileSync(resolvedPath, "utf8");
271
283
  } catch {
@@ -303,7 +315,7 @@ export function runInspectCommand(argv: string[], promptsDir: string): void {
303
315
  const fragmentContents = new Map<number, string | null>();
304
316
  if (verbose) {
305
317
  for (const frag of fragments) {
306
- fragmentContents.set(frag.index, readFragmentContent(frag.resolvedPath));
318
+ fragmentContents.set(frag.index, readFragmentContent(frag.path, frag.resolvedPath));
307
319
  }
308
320
  }
309
321