rulesync 7.18.1 → 7.19.0

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.
@@ -15,6 +15,32 @@ function formatError(error) {
15
15
  return String(error);
16
16
  }
17
17
 
18
+ // src/types/json-output.ts
19
+ var ErrorCodes = {
20
+ CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND",
21
+ RULESYNC_DIR_NOT_FOUND: "RULESYNC_DIR_NOT_FOUND",
22
+ INVALID_TARGET: "INVALID_TARGET",
23
+ FETCH_FAILED: "FETCH_FAILED",
24
+ WRITE_FAILED: "WRITE_FAILED",
25
+ VALIDATION_FAILED: "VALIDATION_FAILED",
26
+ GENERATION_FAILED: "GENERATION_FAILED",
27
+ IMPORT_FAILED: "IMPORT_FAILED",
28
+ INSTALL_FAILED: "INSTALL_FAILED",
29
+ UPDATE_FAILED: "UPDATE_FAILED",
30
+ GITIGNORE_FAILED: "GITIGNORE_FAILED",
31
+ INIT_FAILED: "INIT_FAILED",
32
+ MCP_FAILED: "MCP_FAILED",
33
+ UNKNOWN_ERROR: "UNKNOWN_ERROR"
34
+ };
35
+ var CLIError = class extends Error {
36
+ constructor(message, code = ErrorCodes.UNKNOWN_ERROR, exitCode = 1) {
37
+ super(message);
38
+ this.code = code;
39
+ this.exitCode = exitCode;
40
+ this.name = "CLIError";
41
+ }
42
+ };
43
+
18
44
  // src/utils/logger.ts
19
45
  import { consola } from "consola";
20
46
 
@@ -25,16 +51,24 @@ function isEnvTest() {
25
51
 
26
52
  // src/utils/logger.ts
27
53
  var Logger = class {
54
+ /**
55
+ * Create a new Logger instance
56
+ */
57
+ constructor(_version = "0.0.0") {
58
+ this._version = _version;
59
+ }
28
60
  _verbose = false;
29
61
  _silent = false;
62
+ _jsonMode = false;
63
+ _jsonOutputDone = false;
64
+ _commandName = "";
65
+ _jsonData = {};
30
66
  console = consola.withDefaults({
31
67
  tag: "rulesync"
32
68
  });
33
69
  /**
34
70
  * Configure logger with verbose and silent mode settings.
35
71
  * Handles conflicting flags where silent takes precedence.
36
- * @param verbose - Enable verbose logging
37
- * @param silent - Enable silent mode (suppresses all output except errors)
38
72
  */
39
73
  configure({ verbose, silent }) {
40
74
  if (verbose && silent) {
@@ -50,34 +84,120 @@ var Logger = class {
50
84
  get silent() {
51
85
  return this._silent;
52
86
  }
87
+ /**
88
+ * Enable JSON output mode
89
+ */
90
+ setJsonMode(enabled, command) {
91
+ this._jsonMode = enabled;
92
+ this._jsonOutputDone = false;
93
+ this._commandName = command;
94
+ if (enabled) {
95
+ this._jsonData = {};
96
+ }
97
+ }
98
+ /**
99
+ * Check if JSON mode is enabled
100
+ */
101
+ get jsonMode() {
102
+ return this._jsonMode;
103
+ }
104
+ /**
105
+ * Capture data for JSON output
106
+ */
107
+ captureData(key, value) {
108
+ if (this._jsonMode) {
109
+ this._jsonData[key] = value;
110
+ }
111
+ }
112
+ /**
113
+ * Get captured JSON data
114
+ */
115
+ getJsonData() {
116
+ return { ...this._jsonData };
117
+ }
118
+ /**
119
+ * Output final JSON result
120
+ */
121
+ outputJson(success, error) {
122
+ if (!this._jsonMode || this._jsonOutputDone) return;
123
+ this._jsonOutputDone = true;
124
+ const output = {
125
+ success,
126
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
127
+ command: this._commandName,
128
+ version: this._version
129
+ };
130
+ if (success) {
131
+ output.data = this._jsonData;
132
+ } else if (error) {
133
+ output.error = {
134
+ code: error.code,
135
+ message: error.message
136
+ };
137
+ if (error.details) {
138
+ output.error.details = error.details;
139
+ }
140
+ if (error.stack) {
141
+ output.error.stack = error.stack;
142
+ }
143
+ }
144
+ const jsonStr = JSON.stringify(output, null, 2);
145
+ if (success) {
146
+ console.log(jsonStr);
147
+ } else {
148
+ console.error(jsonStr);
149
+ }
150
+ }
53
151
  info(message, ...args) {
54
152
  if (isEnvTest() || this._silent) return;
153
+ if (this._jsonMode) return;
55
154
  this.console.info(message, ...args);
56
155
  }
57
- // Success (always shown unless silent)
58
156
  success(message, ...args) {
59
157
  if (isEnvTest() || this._silent) return;
158
+ if (this._jsonMode) return;
60
159
  this.console.success(message, ...args);
61
160
  }
62
- // Warning (always shown unless silent)
63
161
  warn(message, ...args) {
64
162
  if (isEnvTest() || this._silent) return;
163
+ if (this._jsonMode) return;
65
164
  this.console.warn(message, ...args);
66
165
  }
67
- // Error (always shown, even in silent mode)
68
- error(message, ...args) {
166
+ error(message, code, ...args) {
69
167
  if (isEnvTest()) return;
70
- this.console.error(message, ...args);
168
+ const errorMessage = message instanceof Error ? message.message : message;
169
+ if (this._jsonMode) {
170
+ const errorInfo = {
171
+ code: code || ErrorCodes.UNKNOWN_ERROR,
172
+ message: errorMessage
173
+ };
174
+ if (this._verbose && message instanceof Error && message.stack) {
175
+ errorInfo.stack = message.stack;
176
+ }
177
+ this.outputJson(false, errorInfo);
178
+ } else {
179
+ this.console.error(errorMessage, ...args);
180
+ }
71
181
  }
72
- // Debug level (shown only in verbose mode)
73
182
  debug(message, ...args) {
74
183
  if (isEnvTest() || this._silent) return;
184
+ if (this._jsonMode) return;
75
185
  if (this._verbose) {
76
186
  this.console.info(message, ...args);
77
187
  }
78
188
  }
189
+ /**
190
+ * Get the internal console instance (for testing only)
191
+ * @internal
192
+ */
193
+ _getConsole() {
194
+ return this.console;
195
+ }
79
196
  };
80
- var logger = new Logger();
197
+ function createLogger(version) {
198
+ return new Logger(version);
199
+ }
200
+ var logger = new Logger("0.0.0");
81
201
 
82
202
  // src/types/features.ts
83
203
  import { z } from "zod/mini";
@@ -3304,7 +3424,9 @@ var CLAUDE_HOOK_EVENTS = [
3304
3424
  "preCompact",
3305
3425
  "permissionRequest",
3306
3426
  "notification",
3307
- "setup"
3427
+ "setup",
3428
+ "worktreeCreate",
3429
+ "worktreeRemove"
3308
3430
  ];
3309
3431
  var OPENCODE_HOOK_EVENTS = [
3310
3432
  "sessionStart",
@@ -3371,7 +3493,9 @@ var CANONICAL_TO_CLAUDE_EVENT_NAMES = {
3371
3493
  preCompact: "PreCompact",
3372
3494
  permissionRequest: "PermissionRequest",
3373
3495
  notification: "Notification",
3374
- setup: "Setup"
3496
+ setup: "Setup",
3497
+ worktreeCreate: "WorktreeCreate",
3498
+ worktreeRemove: "WorktreeRemove"
3375
3499
  };
3376
3500
  var CLAUDE_TO_CANONICAL_EVENT_NAMES = Object.fromEntries(
3377
3501
  Object.entries(CANONICAL_TO_CLAUDE_EVENT_NAMES).map(([k, v]) => [v, k])
@@ -3497,7 +3621,13 @@ function canonicalToToolHooks({
3497
3621
  else byMatcher.set(key, [def]);
3498
3622
  }
3499
3623
  const entries = [];
3624
+ const isNoMatcherEvent = converterConfig.noMatcherEvents?.has(eventName) ?? false;
3500
3625
  for (const [matcherKey, defs] of byMatcher) {
3626
+ if (isNoMatcherEvent && matcherKey) {
3627
+ logger.warn(
3628
+ `matcher "${matcherKey}" on "${eventName}" hook will be ignored \u2014 this event does not support matchers`
3629
+ );
3630
+ }
3501
3631
  const hooks = defs.map((def) => {
3502
3632
  const commandText = def.command;
3503
3633
  const trimmedCommand = typeof commandText === "string" ? commandText.trimStart() : void 0;
@@ -3510,7 +3640,8 @@ function canonicalToToolHooks({
3510
3640
  ...def.prompt !== void 0 && def.prompt !== null && { prompt: def.prompt }
3511
3641
  };
3512
3642
  });
3513
- entries.push(matcherKey ? { matcher: matcherKey, hooks } : { hooks });
3643
+ const includeMatcher = matcherKey && !isNoMatcherEvent;
3644
+ entries.push(includeMatcher ? { matcher: matcherKey, hooks } : { hooks });
3514
3645
  }
3515
3646
  result[toolEventName] = entries;
3516
3647
  }
@@ -3648,12 +3779,14 @@ var ToolHooks = class extends ToolFile {
3648
3779
  };
3649
3780
 
3650
3781
  // src/features/hooks/claudecode-hooks.ts
3782
+ var CLAUDE_NO_MATCHER_EVENTS = /* @__PURE__ */ new Set(["worktreeCreate", "worktreeRemove"]);
3651
3783
  var CLAUDE_CONVERTER_CONFIG = {
3652
3784
  supportedEvents: CLAUDE_HOOK_EVENTS,
3653
3785
  canonicalToToolEventNames: CANONICAL_TO_CLAUDE_EVENT_NAMES,
3654
3786
  toolToCanonicalEventNames: CLAUDE_TO_CANONICAL_EVENT_NAMES,
3655
3787
  projectDirVar: "$CLAUDE_PROJECT_DIR",
3656
- prefixDotRelativeCommandsOnly: true
3788
+ prefixDotRelativeCommandsOnly: true,
3789
+ noMatcherEvents: CLAUDE_NO_MATCHER_EVENTS
3657
3790
  };
3658
3791
  var ClaudecodeHooks = class _ClaudecodeHooks extends ToolHooks {
3659
3792
  constructor(params) {
@@ -17154,6 +17287,9 @@ export {
17154
17287
  MAX_FILE_SIZE,
17155
17288
  FETCH_CONCURRENCY_LIMIT,
17156
17289
  formatError,
17290
+ ErrorCodes,
17291
+ CLIError,
17292
+ createLogger,
17157
17293
  logger,
17158
17294
  ensureDir,
17159
17295
  checkPathTraversal,
@@ -17172,6 +17308,7 @@ export {
17172
17308
  ALL_FEATURES,
17173
17309
  ALL_FEATURES_WITH_WILDCARD,
17174
17310
  ALL_TOOL_TARGETS,
17311
+ ALL_TOOL_TARGETS_WITH_WILDCARD,
17175
17312
  findControlCharacter,
17176
17313
  ConfigResolver,
17177
17314
  stringifyFrontmatter,