oh-my-customcode 0.16.0 → 0.16.2

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
@@ -9152,8 +9152,28 @@ function checkOutdated(tools) {
9152
9152
  }
9153
9153
  } catch {}
9154
9154
  }
9155
+ function collectToolResults(toolNames) {
9156
+ const tools = [];
9157
+ for (const toolName of toolNames) {
9158
+ const tool = getToolInfo(toolName);
9159
+ tools.push(tool);
9160
+ }
9161
+ checkOutdated(tools);
9162
+ const hasUpdates = tools.some((t) => t.updateAvailable);
9163
+ return {
9164
+ tools,
9165
+ hasUpdates,
9166
+ warnings: [],
9167
+ skipped: false
9168
+ };
9169
+ }
9155
9170
  async function runPreflightCheck(options = {}) {
9156
- const { skip = false, tools: toolNames = ["claude-code"], timeout = 5000 } = options;
9171
+ const {
9172
+ skip = false,
9173
+ tools: toolNames = ["claude-code"],
9174
+ timeout = 5000,
9175
+ _collectFn = collectToolResults
9176
+ } = options;
9157
9177
  if (skip) {
9158
9178
  return {
9159
9179
  tools: [],
@@ -9181,8 +9201,8 @@ async function runPreflightCheck(options = {}) {
9181
9201
  skipReason: "Homebrew not available"
9182
9202
  };
9183
9203
  }
9184
- return new Promise((resolve) => {
9185
- const timeoutId = setTimeout(() => {
9204
+ const timeoutPromise = new Promise((resolve) => {
9205
+ setTimeout(() => {
9186
9206
  resolve({
9187
9207
  tools: [],
9188
9208
  hasUpdates: false,
@@ -9191,34 +9211,21 @@ async function runPreflightCheck(options = {}) {
9191
9211
  skipReason: "Timeout"
9192
9212
  });
9193
9213
  }, timeout);
9194
- try {
9195
- const tools = [];
9196
- for (const toolName of toolNames) {
9197
- const tool = getToolInfo(toolName);
9198
- tools.push(tool);
9199
- }
9200
- checkOutdated(tools);
9201
- const hasUpdates = tools.some((t) => t.updateAvailable);
9202
- const warnings = [];
9203
- clearTimeout(timeoutId);
9204
- resolve({
9205
- tools,
9206
- hasUpdates,
9207
- warnings,
9208
- skipped: false
9209
- });
9210
- } catch (error) {
9211
- clearTimeout(timeoutId);
9212
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
9213
- resolve({
9214
- tools: [],
9215
- hasUpdates: false,
9216
- warnings: [`Pre-flight check failed: ${errorMessage}`],
9217
- skipped: true,
9218
- skipReason: "Error during check"
9219
- });
9220
- }
9221
9214
  });
9215
+ const collectPromise = (async () => {
9216
+ const result = await _collectFn(toolNames);
9217
+ return result;
9218
+ })().catch((error) => {
9219
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
9220
+ return {
9221
+ tools: [],
9222
+ hasUpdates: false,
9223
+ warnings: [`Pre-flight check failed: ${errorMessage}`],
9224
+ skipped: true,
9225
+ skipReason: "Error during check"
9226
+ };
9227
+ });
9228
+ return Promise.race([collectPromise, timeoutPromise]);
9222
9229
  }
9223
9230
  function formatPreflightWarnings(result) {
9224
9231
  if (!result.hasUpdates) {
@@ -12608,7 +12615,7 @@ var $visitAsync = visit.visitAsync;
12608
12615
  import { join as join3 } from "node:path";
12609
12616
 
12610
12617
  // src/utils/fs.ts
12611
- import { dirname as dirname2, isAbsolute, join as join2, normalize, relative, resolve, sep } from "node:path";
12618
+ import { dirname as dirname2, isAbsolute, join as join2, relative, resolve, sep } from "node:path";
12612
12619
  import { fileURLToPath } from "node:url";
12613
12620
  function validatePreserveFilePath(filePath, projectRoot) {
12614
12621
  if (!filePath || filePath.trim() === "") {
@@ -12623,19 +12630,12 @@ function validatePreserveFilePath(filePath, projectRoot) {
12623
12630
  reason: "Absolute paths are not allowed"
12624
12631
  };
12625
12632
  }
12626
- const normalizedPath = normalize(filePath);
12627
- if (normalizedPath.startsWith("..")) {
12628
- return {
12629
- valid: false,
12630
- reason: "Path cannot traverse outside project root"
12631
- };
12632
- }
12633
- const resolvedPath = resolve(projectRoot, normalizedPath);
12633
+ const resolvedPath = resolve(projectRoot, filePath);
12634
12634
  const relativePath = relative(projectRoot, resolvedPath);
12635
12635
  if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
12636
12636
  return {
12637
12637
  valid: false,
12638
- reason: "Resolved path escapes project root"
12638
+ reason: "Path cannot traverse outside project root"
12639
12639
  };
12640
12640
  }
12641
12641
  return { valid: true };
@@ -13000,7 +13000,6 @@ function getDefaultConfig() {
13000
13000
  lastUpdated: "",
13001
13001
  installedComponents: [],
13002
13002
  componentVersions: {},
13003
- agents: {},
13004
13003
  preferences: getDefaultPreferences(),
13005
13004
  sourceRepo: "https://github.com/baekenough/oh-my-customcode",
13006
13005
  autoUpdate: {
@@ -13091,10 +13090,10 @@ function mergeConfig(defaults, overrides, targetDir) {
13091
13090
  ...defaults.componentVersions,
13092
13091
  ...overrides.componentVersions
13093
13092
  },
13094
- agents: {
13093
+ agents: defaults.agents || overrides.agents ? {
13095
13094
  ...defaults.agents,
13096
13095
  ...overrides.agents
13097
- },
13096
+ } : undefined,
13098
13097
  preserveFiles: mergedPreserveFiles,
13099
13098
  customComponents: overrides.customComponents ? deduplicateCustomComponents([
13100
13099
  ...defaults.customComponents || [],
@@ -13732,10 +13731,7 @@ function determineWorkflowType(hasDevelop, branchPatterns, allBranches) {
13732
13731
  if (!hasDevelop && !hasFeatureBranches) {
13733
13732
  return "trunk-based";
13734
13733
  }
13735
- if (hasDevelop) {
13736
- return "git-flow";
13737
- }
13738
- return "github-flow";
13734
+ return "git-flow";
13739
13735
  }
13740
13736
  function detectGitWorkflow(cwd) {
13741
13737
  if (!isGitRepo(cwd)) {
@@ -14696,12 +14692,7 @@ async function pathExists2(targetPath) {
14696
14692
  }
14697
14693
  }
14698
14694
  function isValidUtf8Text(content) {
14699
- try {
14700
- content.toString("utf-8");
14701
- return true;
14702
- } catch {
14703
- return false;
14704
- }
14695
+ return !content.includes(0);
14705
14696
  }
14706
14697
  async function findAllFiles(dir2) {
14707
14698
  const results = [];
@@ -15194,15 +15185,7 @@ function resolveConfigPreserveFiles(options, config) {
15194
15185
  const preserveFiles = config.preserveFiles || [];
15195
15186
  const validatedPaths = [];
15196
15187
  for (const filePath of preserveFiles) {
15197
- const validation = validatePreserveFilePath(filePath, options.targetDir);
15198
- if (validation.valid) {
15199
- validatedPaths.push(filePath);
15200
- } else {
15201
- warn("preserve_files.invalid_path", {
15202
- path: filePath,
15203
- reason: validation.reason ?? "Invalid path"
15204
- });
15205
- }
15188
+ validatedPaths.push(filePath);
15206
15189
  }
15207
15190
  return validatedPaths;
15208
15191
  }
@@ -15243,11 +15226,8 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
15243
15226
  lastUpdated: new Date().toISOString()
15244
15227
  };
15245
15228
  }
15246
- if (customizations) {
15247
- customizations.preserveFiles = validatedManifestFiles;
15248
- return customizations;
15249
- }
15250
- return null;
15229
+ customizations.preserveFiles = validatedManifestFiles;
15230
+ return customizations;
15251
15231
  }
15252
15232
  async function updateEntryDoc(targetDir, config, options) {
15253
15233
  const layout = getProviderLayout();
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
5
5
  import { join as join2 } from "node:path";
6
6
 
7
7
  // src/utils/fs.ts
8
- import { dirname, isAbsolute, join, normalize, relative, resolve, sep } from "node:path";
8
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  function validatePreserveFilePath(filePath, projectRoot) {
11
11
  if (!filePath || filePath.trim() === "") {
@@ -20,19 +20,12 @@ function validatePreserveFilePath(filePath, projectRoot) {
20
20
  reason: "Absolute paths are not allowed"
21
21
  };
22
22
  }
23
- const normalizedPath = normalize(filePath);
24
- if (normalizedPath.startsWith("..")) {
25
- return {
26
- valid: false,
27
- reason: "Path cannot traverse outside project root"
28
- };
29
- }
30
- const resolvedPath = resolve(projectRoot, normalizedPath);
23
+ const resolvedPath = resolve(projectRoot, filePath);
31
24
  const relativePath = relative(projectRoot, resolvedPath);
32
25
  if (relativePath.startsWith("..") || isAbsolute(relativePath)) {
33
26
  return {
34
27
  valid: false,
35
- reason: "Resolved path escapes project root"
28
+ reason: "Path cannot traverse outside project root"
36
29
  };
37
30
  }
38
31
  return { valid: true };
@@ -388,7 +381,6 @@ function getDefaultConfig() {
388
381
  lastUpdated: "",
389
382
  installedComponents: [],
390
383
  componentVersions: {},
391
- agents: {},
392
384
  preferences: getDefaultPreferences(),
393
385
  sourceRepo: "https://github.com/baekenough/oh-my-customcode",
394
386
  autoUpdate: {
@@ -479,10 +471,10 @@ function mergeConfig(defaults, overrides, targetDir) {
479
471
  ...defaults.componentVersions,
480
472
  ...overrides.componentVersions
481
473
  },
482
- agents: {
474
+ agents: defaults.agents || overrides.agents ? {
483
475
  ...defaults.agents,
484
476
  ...overrides.agents
485
- },
477
+ } : undefined,
486
478
  preserveFiles: mergedPreserveFiles,
487
479
  customComponents: overrides.customComponents ? deduplicateCustomComponents([
488
480
  ...defaults.customComponents || [],
@@ -578,10 +570,7 @@ function determineWorkflowType(hasDevelop, branchPatterns, allBranches) {
578
570
  if (!hasDevelop && !hasFeatureBranches) {
579
571
  return "trunk-based";
580
572
  }
581
- if (hasDevelop) {
582
- return "git-flow";
583
- }
584
- return "github-flow";
573
+ return "git-flow";
585
574
  }
586
575
  function detectGitWorkflow(cwd) {
587
576
  if (!isGitRepo(cwd)) {
@@ -1233,15 +1222,7 @@ function resolveConfigPreserveFiles(options, config) {
1233
1222
  const preserveFiles = config.preserveFiles || [];
1234
1223
  const validatedPaths = [];
1235
1224
  for (const filePath of preserveFiles) {
1236
- const validation = validatePreserveFilePath(filePath, options.targetDir);
1237
- if (validation.valid) {
1238
- validatedPaths.push(filePath);
1239
- } else {
1240
- warn("preserve_files.invalid_path", {
1241
- path: filePath,
1242
- reason: validation.reason ?? "Invalid path"
1243
- });
1244
- }
1225
+ validatedPaths.push(filePath);
1245
1226
  }
1246
1227
  return validatedPaths;
1247
1228
  }
@@ -1282,11 +1263,8 @@ function resolveCustomizations(customizations, configPreserveFiles, targetDir) {
1282
1263
  lastUpdated: new Date().toISOString()
1283
1264
  };
1284
1265
  }
1285
- if (customizations) {
1286
- customizations.preserveFiles = validatedManifestFiles;
1287
- return customizations;
1288
- }
1289
- return null;
1266
+ customizations.preserveFiles = validatedManifestFiles;
1267
+ return customizations;
1290
1268
  }
1291
1269
  async function updateEntryDoc(targetDir, config, options) {
1292
1270
  const layout = getProviderLayout();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oh-my-customcode",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
4
4
  "description": "Batteries-included agent harness for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,7 +7,7 @@
7
7
  "hooks": [
8
8
  {
9
9
  "type": "command",
10
- "command": "if [ -f /tmp/.claude-dev-stage ]; then stage=$(cat /tmp/.claude-dev-stage | tr -d '[:space:]'); if [ -z \"$stage\" ]; then exit 0; fi; case \"$stage\" in plan|verify-plan|verify-impl|compound|done) echo \"⛔ BLOCKED: Write/Edit disabled in '$stage' stage. Only allowed during 'implement' stage. Use 'echo implement > /tmp/.claude-dev-stage' to transition.\"; exit 2;; esac; fi"
10
+ "command": "bash .claude/hooks/scripts/stage-blocker.sh"
11
11
  }
12
12
  ],
13
13
  "description": "Block Write/Edit tools during plan/verify/compound stages — only allow in implement stage"
@@ -0,0 +1,12 @@
1
+ #!/bin/bash
2
+ # Stage-blocking hook: blocks Write/Edit in non-implement stages
3
+ if [ -f /tmp/.claude-dev-stage ]; then
4
+ stage=$(cat /tmp/.claude-dev-stage | tr -d '[:space:]')
5
+ if [ -z "$stage" ]; then exit 0; fi
6
+ case "$stage" in
7
+ plan|verify-plan|verify-impl|compound|done)
8
+ echo "⛔ BLOCKED: Write/Edit disabled in '$stage' stage. Only allowed during 'implement' stage. Use 'echo implement > /tmp/.claude-dev-stage' to transition."
9
+ exit 2
10
+ ;;
11
+ esac
12
+ fi