codebrief 1.3.0 → 1.4.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.
package/README.md CHANGED
@@ -279,7 +279,8 @@ npx codebrief [directory] [options]
279
279
  | `--dry-run` | Preview what would be generated |
280
280
  | `--refresh-snapshot` | Re-scan source files and update just the code snapshot |
281
281
  | `--reconfigure` | Re-prompt even if `.codebrief.json` exists |
282
- | `--check` | Check if the snapshot is stale (exit 0 = fresh, 1 = stale) |
282
+ | `--check` | Check if the snapshot is stale via hash comparison (exit 0 = fresh, 1 = stale) |
283
+ | `--check=timestamp` | Timestamp-only staleness check — instant, no file hashing (for shell hooks) |
283
284
  | `--max-tokens=N` | Set the token budget for the code snapshot |
284
285
  | `--generate-skills` | Generate Claude Code skill files |
285
286
  | `-v, --verbose` | Show detailed progress output |
@@ -296,7 +297,7 @@ This finds the `<!-- CODE SNAPSHOT -->` markers in your context file, re-scans s
296
297
 
297
298
  ## Shell Integration
298
299
 
299
- Automatically detect stale snapshots when you `cd` into a project:
300
+ Automatically detect stale snapshots when you `cd` into a project. These hooks run in pure shell (no Node.js boot), so they add zero latency to your prompt:
300
301
 
301
302
  <details>
302
303
  <summary><strong>zsh</strong></summary>
@@ -305,7 +306,13 @@ Automatically detect stale snapshots when you `cd` into a project:
305
306
  # Add to ~/.zshrc
306
307
  chpwd() {
307
308
  if [[ -f .codebrief.json ]]; then
308
- npx --yes codebrief --check 2>/dev/null
309
+ local ts days stale_days
310
+ ts=$(command grep -o '"snapshotGeneratedAt":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*$')
311
+ [[ -z "$ts" ]] && return
312
+ stale_days=$(command grep -o '"staleDays":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*$')
313
+ : "${stale_days:=7}"
314
+ days=$(( ($(date +%s) - ts / 1000) / 86400 ))
315
+ (( days > stale_days )) && echo "codebrief: snapshot is ${days}d old. Run: npx codebrief --refresh-snapshot"
309
316
  fi
310
317
  }
311
318
  ```
@@ -320,7 +327,13 @@ chpwd() {
320
327
  cd() {
321
328
  builtin cd "$@" || return
322
329
  if [[ -f .codebrief.json ]]; then
323
- npx --yes codebrief --check 2>/dev/null
330
+ local ts days stale_days
331
+ ts=$(command grep -o '"snapshotGeneratedAt":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*$')
332
+ [[ -z "$ts" ]] && return
333
+ stale_days=$(command grep -o '"staleDays":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*$')
334
+ : "${stale_days:=7}"
335
+ days=$(( ($(date +%s) - ts / 1000) / 86400 ))
336
+ (( days > stale_days )) && echo "codebrief: snapshot is ${days}d old. Run: npx codebrief --refresh-snapshot"
324
337
  fi
325
338
  }
326
339
  ```
@@ -334,13 +347,20 @@ cd() {
334
347
  # Add to ~/.config/fish/conf.d/codebrief.fish
335
348
  function __codebrief_check --on-variable PWD
336
349
  if test -f .codebrief.json
337
- npx --yes codebrief --check 2>/dev/null
350
+ set -l ts (command grep -o '"snapshotGeneratedAt":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*\$')
351
+ test -z "$ts"; and return
352
+ set -l stale_days (command grep -o '"staleDays":[0-9]*' .codebrief.json 2>/dev/null | command grep -o '[0-9]*\$')
353
+ test -z "$stale_days"; and set stale_days 7
354
+ set -l days (math "( "(date +%s)" - $ts / 1000) / 86400")
355
+ test $days -gt $stale_days; and echo "codebrief: snapshot is "$days"d old. Run: npx codebrief --refresh-snapshot"
338
356
  end
339
357
  end
340
358
  ```
341
359
 
342
360
  </details>
343
361
 
362
+ > **Tip:** Set `"staleDays": 14` in `.codebrief.json` to customize the threshold. For CI/pre-commit use the hash-based `--check` instead.
363
+
344
364
  ## Config File
345
365
 
346
366
  On first run, codebrief saves your answers to `.codebrief.json`:
package/dist/index.js CHANGED
@@ -3411,11 +3411,13 @@ async function loadConfig(rootDir) {
3411
3411
  generatePerPackage: cfg.generatePerPackage ?? false,
3412
3412
  snapshotHash: cfg.snapshotHash,
3413
3413
  snapshotGeneratedAt: cfg.snapshotGeneratedAt,
3414
- language: cfg.language
3414
+ language: cfg.language,
3415
+ staleDays: cfg.staleDays
3415
3416
  };
3416
3417
  }
3417
3418
  async function saveConfig(rootDir, answers, snapshotHash, language) {
3418
3419
  const configPath = path6.join(rootDir, CONFIG_FILENAME);
3420
+ const existing = await readJsonFile(configPath);
3419
3421
  const cfg = {
3420
3422
  _version: CONFIG_VERSION,
3421
3423
  ides: answers.ides,
@@ -3427,7 +3429,8 @@ async function saveConfig(rootDir, answers, snapshotHash, language) {
3427
3429
  stackCorrections: answers.stackCorrections,
3428
3430
  generatePerPackage: answers.generatePerPackage,
3429
3431
  ...snapshotHash ? { snapshotHash, snapshotGeneratedAt: Date.now() } : {},
3430
- ...language ? { language } : {}
3432
+ ...language ? { language } : {},
3433
+ ...existing?.staleDays != null ? { staleDays: existing.staleDays } : {}
3431
3434
  };
3432
3435
  await writeFileSafe(configPath, JSON.stringify(cfg, null, 2) + "\n");
3433
3436
  }
@@ -3585,6 +3588,11 @@ async function refreshSnapshot(rootDir) {
3585
3588
  updated = content.slice(0, startIdx) + newBlock + content.slice(endIdx);
3586
3589
  }
3587
3590
  await writeFileSafe(absPath, updated);
3591
+ if (config) {
3592
+ const answers = configToAnswers(config);
3593
+ const newHash = await computeSnapshotHash(rootDir, config.language ?? detected.language);
3594
+ await saveConfig(rootDir, answers, newHash, config.language ?? detected.language);
3595
+ }
3588
3596
  p3.log.success(`Updated snapshot in ${theme.accent(found.path)}`);
3589
3597
  }
3590
3598
 
@@ -3773,7 +3781,7 @@ async function animateCommunities(communityCount) {
3773
3781
  }
3774
3782
 
3775
3783
  // src/index.ts
3776
- var VERSION = true ? "1.3.0" : "0.0.0-dev";
3784
+ var VERSION = true ? "1.4.0" : "0.0.0-dev";
3777
3785
  var NAME = true ? "codebrief" : "codebrief";
3778
3786
  var DESCRIPTION = true ? "Bootstrap optimized AI context files for any project. Auto-detect stack, generate code snapshots, produce config for Claude Code, Cursor, Copilot, Windsurf, Cline, Continue, Aider, and more." : "";
3779
3787
  function printHelp() {
@@ -3790,7 +3798,8 @@ function printHelp() {
3790
3798
  console.log(` ${theme.accent("--dry-run")} Preview what would be generated`);
3791
3799
  console.log(` ${theme.accent("--reconfigure")} Re-prompt even if .codebrief.json exists`);
3792
3800
  console.log(` ${theme.accent("--refresh-snapshot")} Re-scan source files, update code snapshot only`);
3793
- console.log(` ${theme.accent("--check")} Exit 0 if snapshot is fresh, 1 if stale`);
3801
+ console.log(` ${theme.accent("--check")} Exit 0 if snapshot is fresh, 1 if stale (hash-based)`);
3802
+ console.log(` ${theme.accent("--check=timestamp")} Exit 0/1 based on age only (no Node.js needed in shell hooks)`);
3794
3803
  console.log(` ${theme.accent("--max-tokens=N")} Set the token budget for the code snapshot`);
3795
3804
  console.log(` ${theme.accent("--generate-skills")} Generate Claude Code skill files`);
3796
3805
  console.log(` ${theme.accent("-v, --verbose")} Show detailed progress output`);
@@ -3817,7 +3826,9 @@ async function main() {
3817
3826
  const dryRun = args.includes("--dry-run");
3818
3827
  const refresh = args.includes("--refresh-snapshot");
3819
3828
  const reconfigure = args.includes("--reconfigure");
3820
- const check = args.includes("--check");
3829
+ const checkArg = args.find((a) => a === "--check" || a.startsWith("--check="));
3830
+ const check = !!checkArg;
3831
+ const checkTimestamp = checkArg === "--check=timestamp";
3821
3832
  const verbose = args.includes("--verbose") || args.includes("-v");
3822
3833
  const generateSkills = args.includes("--generate-skills");
3823
3834
  const maxTokensArg = args.find((a) => a.startsWith("--max-tokens="));
@@ -3842,6 +3853,20 @@ async function main() {
3842
3853
  };
3843
3854
  if (check) {
3844
3855
  const config = await loadConfig(rootDir);
3856
+ if (checkTimestamp) {
3857
+ if (!config?.snapshotGeneratedAt) {
3858
+ process.exit(0);
3859
+ }
3860
+ const staleDays = config.staleDays ?? 7;
3861
+ const daysSince = Math.floor(
3862
+ (Date.now() - config.snapshotGeneratedAt) / (1e3 * 60 * 60 * 24)
3863
+ );
3864
+ if (daysSince > staleDays) {
3865
+ console.log(`codebrief: snapshot is ${daysSince}d old. Run: npx codebrief --refresh-snapshot`);
3866
+ process.exit(1);
3867
+ }
3868
+ process.exit(0);
3869
+ }
3845
3870
  if (!config?.snapshotHash) {
3846
3871
  process.exit(0);
3847
3872
  }