shadow-git 1.0.3 → 1.1.1

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.
Files changed (79) hide show
  1. package/CLAUDE.md +5 -1
  2. package/README.md +13 -0
  3. package/dist/cli.js +498 -75
  4. package/package.json +1 -1
  5. package/src/cli.ts +69 -5
  6. package/src/commands/forward.ts +3 -3
  7. package/src/commands/track/add.ts +6 -4
  8. package/src/commands/track/clone.ts +16 -1
  9. package/src/commands/track/destroy.ts +5 -0
  10. package/src/commands/track/ignore.ts +2 -2
  11. package/src/commands/track/index.ts +12 -0
  12. package/src/commands/track/init.ts +5 -1
  13. package/src/commands/track/remove.ts +3 -2
  14. package/src/commands/track/swap.ts +61 -0
  15. package/src/commands/track/sync.ts +9 -6
  16. package/src/commands/track/unswap.ts +49 -0
  17. package/src/commands/track/verify.ts +11 -9
  18. package/src/core/errors.ts +31 -1
  19. package/src/core/exclude.ts +2 -2
  20. package/src/core/gitignore.ts +18 -3
  21. package/src/core/repository.ts +8 -0
  22. package/src/core/swap-mode.ts +83 -0
  23. package/src/core/update-check.ts +214 -0
  24. package/src/utils/logger.ts +20 -0
  25. package/tests/commands/forward.test.ts +6 -6
  26. package/tests/commands/track/add.test.ts +6 -6
  27. package/tests/commands/track/swap.test.ts +266 -0
  28. package/tests/commands/track/verify.test.ts +16 -16
  29. package/tests/core/exclude.test.ts +10 -10
  30. package/tests/core/gitignore.test.ts +30 -30
  31. package/tests/core/update-check.test.ts +494 -0
  32. package/tests/helpers/guard-child.mjs +2 -2
  33. package/.claude/settings.local.json +0 -43
  34. package/.temp/.sgit/COMMIT_EDITMSG +0 -1
  35. package/.temp/.sgit/HEAD +0 -1
  36. package/.temp/.sgit/config +0 -8
  37. package/.temp/.sgit/description +0 -1
  38. package/.temp/.sgit/hooks/applypatch-msg.sample +0 -15
  39. package/.temp/.sgit/hooks/commit-msg.sample +0 -24
  40. package/.temp/.sgit/hooks/fsmonitor-watchman.sample +0 -174
  41. package/.temp/.sgit/hooks/post-update.sample +0 -8
  42. package/.temp/.sgit/hooks/pre-applypatch.sample +0 -14
  43. package/.temp/.sgit/hooks/pre-commit +0 -6
  44. package/.temp/.sgit/hooks/pre-commit.sample +0 -49
  45. package/.temp/.sgit/hooks/pre-merge-commit.sample +0 -13
  46. package/.temp/.sgit/hooks/pre-push.sample +0 -53
  47. package/.temp/.sgit/hooks/pre-rebase.sample +0 -169
  48. package/.temp/.sgit/hooks/pre-receive.sample +0 -24
  49. package/.temp/.sgit/hooks/prepare-commit-msg.sample +0 -42
  50. package/.temp/.sgit/hooks/push-to-checkout.sample +0 -78
  51. package/.temp/.sgit/hooks/sendemail-validate.sample +0 -77
  52. package/.temp/.sgit/hooks/update.sample +0 -128
  53. package/.temp/.sgit/index +0 -0
  54. package/.temp/.sgit/info/exclude +0 -20
  55. package/.temp/.sgit/logs/HEAD +0 -1
  56. package/.temp/.sgit/logs/refs/heads/master +0 -1
  57. package/.temp/.sgit/objects/03/7f4e37a02573e40ab78b35dd4b442cc6110bae +0 -0
  58. package/.temp/.sgit/objects/2f/f0fd85dec20039eef6ff63ead905778a88843f +0 -0
  59. package/.temp/.sgit/objects/34/b3190a8a836593fb568a56c073a416a56fbf6d +0 -0
  60. package/.temp/.sgit/objects/70/ad6bbbfefd330d72a43dc2a810e6ef42269911 +0 -0
  61. package/.temp/.sgit/objects/90/4e09c7aadaa32d2426ab5464a975d5151ef195 +0 -0
  62. package/.temp/.sgit/objects/a4/6358feef49515d5f85d1d3a64e929182da7149 +0 -3
  63. package/.temp/.sgit/objects/c3/2432f724b666f647fe21a1ce16535cd7693f74 +0 -0
  64. package/.temp/.sgit/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  65. package/.temp/.sgit/objects/e8/0f4253888cdadda1e3d810f6a3cb3c68c20b50 +0 -0
  66. package/.temp/.sgit/objects/ee/9dd32cca3b134623d184eb4de5805704c493e3 +0 -0
  67. package/.temp/.sgit/refs/heads/master +0 -1
  68. package/.temp/.sgit.json +0 -10
  69. package/.temp/README.md +0 -0
  70. package/.temp/docs/guide.md +0 -10
  71. package/.temp/lib/__init__.py +0 -1
  72. package/.temp/lib/utils.py +0 -5
  73. package/.temp/rec1/rec2/test +0 -0
  74. package/.temp/src/config.py +0 -3
  75. package/.temp/src/main.py +0 -5
  76. package/.temp/temp/shouldnt-track +0 -0
  77. package/.temp/temp.md +0 -3
  78. package/.temp/test/1 +0 -0
  79. package/.temp/tests/test_utils.py +0 -7
package/CLAUDE.md CHANGED
@@ -43,6 +43,7 @@ src/
43
43
  hooks.ts # Install/uninstall pre-commit hooks
44
44
  errors.ts # Custom error classes (SgitError hierarchy)
45
45
  gitignore.ts # Disable/enable .gitignore files during sgit operations
46
+ update-check.ts # Daily npm registry check (detached worker) and update notice
46
47
  utils/
47
48
  logger.ts # Color-coded stdout/stderr logging
48
49
  process.ts # Child process execution
@@ -56,4 +57,7 @@ src/
56
57
  - Shadow repo exclude uses a deny-all + allow-list pattern (`*` then `!path`)
57
58
  - Error classes extend `SgitError`; the CLI catches these and prints the message
58
59
  - Hidden `debug` commands (`sgit debug <cmd>`) are registered with `{ hidden: true }` so they don't appear in `sgit --help`. They are only visible via `sgit debug --help`. Debug commands manage their own gitignore guard (the CLI-level guard is skipped for them). No tests are written for debug commands.
59
- - **HARD RULE — gitignore revert guarantee:** `.gitignore` files inside sgit-tracked directories are temporarily renamed to `.gitignore-sgit.bat` during sgit command execution (via `setupGitignoreGuard` in `src/core/gitignore.ts`). **The rename MUST always be reverted** when the command ends — whether it succeeds, fails, is cancelled (Ctrl+C), or receives SIGTERM. The guard uses `try/finally`, signal handlers, and `process.on('exit')` to ensure this. Any new code that executes sgit operations must use the guard or equivalent cleanup guarantees. Pre-commit hooks verify no `.gitignore-sgit.bat` files exist at commit time.
60
+ - **Update check:** `setupUpdateNotifier` (`src/core/update-check.ts`) runs at the start of every interactive invocation — stdout and stderr must both be TTYs; it is skipped for the hook-driven `track verify` and when `NO_UPDATE_NOTIFIER` is set. The command's own process never touches the network: when the last successful check is more than a day old, the CLI re-spawns itself detached with the `__update-check` argument, and that worker writes the registry's `latest` version to `update-check.json` in `$XDG_CACHE_HOME/shadow-git` (default `~/.cache/shadow-git`). The notice is printed from a `process.on('exit')` listener on every run for as long as the cached `latest` is newer than the installed version; only the registry check is limited to once a day. sgit processes started underneath another sgit (the shadow hooks run `sgit track sync`) see `SGIT_UPDATE_NOTICE_HANDLED` in their environment and stay quiet, so one command prints the notice once. Everything on this path fails silently: a failed check records nothing, so the next invocation tries again, and the exit listener must never throw — a throwing `'exit'` listener keeps later ones (the gitignore guard's cleanup) from running.
61
+ - The CLI version (`sgit --version`, and the "current" side of the update notice) is read at runtime from `package.json` by `readVersion` in `src/cli.ts` — it is not hardcoded anywhere.
62
+ - **HARD RULE — gitignore revert guarantee:** `.gitignore` files inside sgit-tracked directories are temporarily renamed to `.gitignore.sgit-parked` during sgit command execution (via `setupGitignoreGuard` in `src/core/gitignore.ts`). **The rename MUST always be reverted** when the command ends — whether it succeeds, fails, is cancelled (Ctrl+C), or receives SIGTERM. The guard uses `try/finally`, signal handlers, and `process.on('exit')` to ensure this. Any new code that executes sgit operations must use the guard or equivalent cleanup guarantees. Pre-commit hooks verify no `.gitignore.sgit-parked` files exist at commit time.
63
+ - **Swap-mode exception to the gitignore revert rule:** while swap mode is active (marker `.git.sgit-parked` present), `.gitignore.sgit-parked` files are **expected to persist** across commands — they stay disabled from `sgit track swap` until `sgit track unswap`. To prevent drift, `disableGitignores`, `enableGitignores`, and `setupGitignoreGuard` refuse to run (throwing `SwapModeActiveError`) whenever `isSwapModeSync(root)` is true. The swap and unswap commands call these helpers only outside the swap window (swap calls `disableGitignores` before creating the marker; unswap calls `enableGitignores` after removing it), so the refusal never blocks the legitimate transitions. The CLI-level gitignore guard is already skipped for `swap`/`unswap` and whenever swap mode is active.
package/README.md CHANGED
@@ -54,6 +54,19 @@ Any non-track command is forwarded to git using the shadow repository (e.g. `sgi
54
54
  - **`.sgit/info/exclude`** — Configured to only see shadow-tracked files
55
55
  - **Pre-commit hooks** — Verify that staged files belong to the correct repository
56
56
 
57
+ ## Update Notifications
58
+
59
+ Once a day, `sgit` checks the npm registry for a newer version of shadow-git. When one is available, a short note is printed after your command's output:
60
+
61
+ ```
62
+ Update available: shadow-git 1.1.0 → 1.2.0
63
+ Please run 'npm install -g shadow-git' to update.
64
+ ```
65
+
66
+ It is only a note — nothing is installed or blocked. It is shown on every run until you update. The check runs in a background process, so commands never wait on the network. If the registry cannot be reached, the check fails silently and is tried again the next time you run `sgit`.
67
+
68
+ All of this happens only in an interactive terminal: nothing is checked or printed when output is piped or redirected. To turn the check off entirely, set `NO_UPDATE_NOTIFIER=1`.
69
+
57
70
  ## License
58
71
 
59
72
  MIT