forge-sync 0.0.0 → 0.0.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.
- package/README.md +111 -87
- package/index.d.mts +2 -0
- package/index.mjs +2 -0
- package/package.json +25 -40
- package/LICENSE +0 -21
- package/dist/chunk-3EYN2AKU.mjs +0 -1
- package/dist/chunk-UYOBIURF.mjs +0 -5
- package/dist/cli.d.mts +0 -13
- package/dist/cli.d.ts +0 -13
- package/dist/cli.js +0 -48
- package/dist/cli.mjs +0 -31
- package/dist/defu-5VPM4BZK.mjs +0 -1
- package/dist/index.d.mts +0 -31
- package/dist/index.d.ts +0 -31
- package/dist/index.js +0 -4
- package/dist/index.mjs +0 -1
- package/dist/jiti-DGVRRYDD.mjs +0 -14
package/README.md
CHANGED
|
@@ -1,126 +1,150 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @turboforge/sync
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](https://codecov.io/gh/react18-tools/turbo-forge/tree/main/packages/forge-sync)
|
|
5
|
-
[](https://www.npmjs.com/package/forge-sync)
|
|
6
|
-
[](https://www.npmjs.com/package/forge-sync)
|
|
7
|
-

|
|
3
|
+
Keep a real monorepo aligned with its upstream template after the repo has already diverged.
|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
<p className="flex gap-2">
|
|
6
|
+
<a href="https://github.com/turboforge-dev/turboforge/actions/workflows/ci.yml" rel="noopener noreferrer">
|
|
7
|
+
<img alt="CI" src="https://github.com/turboforge-dev/turboforge/actions/workflows/ci.yml/badge.svg" />
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://codecov.io/gh/turboforge-dev/turboforge/tree/main/packages/forge-sync" rel="noopener noreferrer">
|
|
10
|
+
<img alt="codecov" src="https://codecov.io/gh/turboforge-dev/turboforge/graph/badge.svg?flag=forge-sync" />
|
|
11
|
+
</a>
|
|
12
|
+
<a href="https://npmjs.com/package/forge-sync" rel="noopener noreferrer">
|
|
13
|
+
<img alt="npm version" src="https://img.shields.io/npm/v/forge-sync" />
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://npmjs.com/package/forge-sync" rel="noopener noreferrer">
|
|
16
|
+
<img alt="npm downloads" src="https://img.shields.io/npm/d18m/forge-sync" />
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://npmjs.com/package/forge-sync" rel="noopener noreferrer">
|
|
19
|
+
<img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/forge-sync" />
|
|
20
|
+
</a>
|
|
21
|
+
<img alt="license" src="https://img.shields.io/npm/l/forge-sync" />
|
|
22
|
+
</p>
|
|
11
23
|
|
|
12
|
-
|
|
24
|
+
`@turboforge/sync` exists because templates are great right up until the moment your repo becomes real. After that, every upstream improvement turns into manual diffing, selective copy-paste, and a quiet fear of breaking local customizations.
|
|
13
25
|
|
|
14
|
-
|
|
26
|
+
This package is the maintenance story inside Turboforge.
|
|
15
27
|
|
|
16
|
-
|
|
28
|
+
Part of the Turboforge system:
|
|
17
29
|
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
- **📦 Intelligent Dependency Resolution**: Special logic for `package.json` to merge dependencies using SemVer rules (e.g., picking the higher version) and resolving conflicts automatically.
|
|
21
|
-
- **🔍 Dry Run Mode**: Preview exactly what patches will be applied without making any changes.
|
|
22
|
-
- **⚙️ Flexible Configuration**: Configure via CLI flags or a persistent `forge-sync.config.json` file.
|
|
23
|
-
- **🚫 Exclusion Support**: Easily exclude specific files or directories from being overwritten (e.g., `docs/`, `examples/`).
|
|
30
|
+
- use `@turboforge/sync` to keep the repo shape current
|
|
31
|
+
- use [`@turboforge/cli-kit`](/c:/Users/G/web/open-source/turbo-forge/packages/cli-kit/README.md) to build the repo-aware commands around that workflow
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
## Highlights
|
|
34
|
+
|
|
35
|
+
- Pull upstream template changes into a repo that has already diverged.
|
|
36
|
+
- Preview upgrades before applying them.
|
|
37
|
+
- Resolve `package.json` conflicts with package-aware merge rules.
|
|
38
|
+
|
|
39
|
+
## Why It Exists
|
|
40
|
+
|
|
41
|
+
Templates stop helping once you have edited them.
|
|
42
|
+
|
|
43
|
+
From that point on, most teams choose one of two bad options:
|
|
44
|
+
|
|
45
|
+
- never pull improvements from the source template again
|
|
46
|
+
- manually replay changes and hope nothing important was missed
|
|
47
|
+
|
|
48
|
+
`@turboforge/sync` gives you a third option: treat template updates as an explicit sync workflow.
|
|
49
|
+
|
|
50
|
+
## Real Example
|
|
51
|
+
|
|
52
|
+
Your monorepo started from an internal template six months ago.
|
|
53
|
+
|
|
54
|
+
Since then, the template added:
|
|
55
|
+
|
|
56
|
+
- a stricter Biome config
|
|
57
|
+
- improved release automation
|
|
58
|
+
- better docs generation
|
|
59
|
+
|
|
60
|
+
Your repo also added custom apps, custom package scripts, and local dependency choices.
|
|
61
|
+
|
|
62
|
+
Instead of copying files by hand, `@turboforge/sync` fetches the upstream template, computes the diff from your last sync point, applies a patch, and resolves `package.json` conflicts with package-aware rules.
|
|
63
|
+
|
|
64
|
+
## When To Use It
|
|
65
|
+
|
|
66
|
+
- You maintain a repo that started from a template and still wants to inherit template improvements.
|
|
67
|
+
- You want upgrades to be repeatable, reviewable, and less dependent on one maintainer's memory.
|
|
68
|
+
- You need a system for "template drift," not just a one-time scaffold.
|
|
69
|
+
|
|
70
|
+
## When Not To Use It
|
|
71
|
+
|
|
72
|
+
- Your repo has no upstream template relationship.
|
|
73
|
+
- You want to generate a new repo from scratch; use a starter for that.
|
|
74
|
+
- You need a full project migration across unrelated architectures.
|
|
26
75
|
|
|
27
76
|
## 📦 Installation
|
|
28
77
|
|
|
29
|
-
To use it as a CLI tool in your project:
|
|
30
78
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
```
|
|
79
|
+
> [!TIP]
|
|
80
|
+
> **This package (forge-sync) is an official alias of [@turboforge/sync](https://npmjs.com/package/@turboforge/sync).**
|
|
34
81
|
|
|
35
|
-
|
|
82
|
+
<details>
|
|
83
|
+
<summary>Why does this exist?</summary>
|
|
36
84
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
```
|
|
85
|
+
We provide this package to offer shorter import paths and improved discoverability. While both packages provide identical functionality, **@turboforge/sync** is the primary source of truth.
|
|
86
|
+
</details>
|
|
40
87
|
|
|
41
|
-
|
|
88
|
+
<details>
|
|
89
|
+
<summary>Which one should I use?</summary>
|
|
42
90
|
|
|
43
|
-
|
|
91
|
+
* **Use forge-sync** if you prefer the shorter name or specific branding or ESM Only.
|
|
92
|
+
* **Use @turboforge/sync** for the most stable long-term reference and standard alignment.
|
|
44
93
|
|
|
45
|
-
|
|
94
|
+
| Feature | @turboforge/sync | forge-sync |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| **Source Code** | ✅ Primary | 🔗 Proxy |
|
|
97
|
+
| **Updates** | Immediate | Synchronized (Immediately) |
|
|
98
|
+
| **Bundle Size** | 100% | 100% (Zero overhead) |
|
|
99
|
+
| **Format** | ESM + CJS | ESM Only |
|
|
100
|
+
| **Maintenance** | ✅ Primary | 🔗 Proxy (inherits) |
|
|
101
|
+
| **Security** | ✅ Primary | 🔗 Proxy (inherits) |
|
|
46
102
|
|
|
47
|
-
|
|
48
|
-
$ pnpm forge-sync
|
|
49
|
-
```
|
|
103
|
+
</details>
|
|
50
104
|
|
|
51
|
-
|
|
105
|
+
<details>
|
|
106
|
+
<summary>Maintenance & Support</summary>
|
|
52
107
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| `--template-url <url>`| URL of the upstream template repository. | `.../forge-template.git` |
|
|
58
|
-
| `--base-ref <ref>` | Base commit/tag to calculate diffs from. Auto-detected from `.forge-meta.json`. | *Auto* |
|
|
59
|
-
| `--target-ref <ref>` | Target commit/tag/branch to update to. | `main` |
|
|
60
|
-
| `--log-level <level>` | Set logging verbosity (`debug`, `info`, `warn`, `error`). | `info` |
|
|
61
|
-
| `-i, --init` | Generate a default configuration file. | - |
|
|
108
|
+
> **Security:** Security audits are performed on the canonical package; this alias inherits all security patches automatically.
|
|
109
|
+
</details>
|
|
110
|
+
|
|
111
|
+
---
|
|
62
112
|
|
|
63
|
-
### Examples
|
|
64
113
|
|
|
65
|
-
**Simulate an update:**
|
|
66
|
-
```bash
|
|
67
|
-
forge-sync --dry-run
|
|
68
|
-
```
|
|
69
114
|
|
|
70
|
-
|
|
115
|
+
To use it as a CLI tool in your project:
|
|
116
|
+
|
|
71
117
|
```bash
|
|
72
|
-
|
|
118
|
+
pnpm add -D @turboforge/sync
|
|
73
119
|
```
|
|
74
120
|
|
|
75
|
-
|
|
121
|
+
Or run it directly with `npx`:
|
|
122
|
+
|
|
76
123
|
```bash
|
|
77
|
-
|
|
124
|
+
npx @turboforge/sync
|
|
78
125
|
```
|
|
79
126
|
|
|
80
|
-
|
|
127
|
+
## Example
|
|
81
128
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
Create a `forge-sync.config.json` file in your root directory for persistent settings:
|
|
85
|
-
|
|
86
|
-
```json
|
|
87
|
-
{
|
|
88
|
-
"templateUrl": "https://github.com/my-org/my-custom-template.git",
|
|
89
|
-
"excludePaths": [
|
|
90
|
-
"pnpm-lock.yaml",
|
|
91
|
-
"apps/web/public"
|
|
92
|
-
],
|
|
93
|
-
"postSync": [
|
|
94
|
-
"pnpm install",
|
|
95
|
-
"pnpm format"
|
|
96
|
-
],
|
|
97
|
-
"logLevel": "info"
|
|
98
|
-
}
|
|
99
|
-
```
|
|
129
|
+
Preview what changed upstream before touching the repo:
|
|
100
130
|
|
|
101
|
-
Generate this file automatically:
|
|
102
131
|
```bash
|
|
103
|
-
|
|
132
|
+
npx @turboforge/sync --dry-run
|
|
104
133
|
```
|
|
105
134
|
|
|
106
|
-
|
|
135
|
+
Exclude heavily customized paths during sync:
|
|
107
136
|
|
|
108
|
-
|
|
137
|
+
```bash
|
|
138
|
+
npx @turboforge/sync --exclude "apps/web,tooling/custom"
|
|
139
|
+
```
|
|
109
140
|
|
|
110
|
-
|
|
111
|
-
2. **Fetch**: Adds the template as a temporary remote and fetches the target reference.
|
|
112
|
-
3. **Diff**: Calculates the difference between your last sync point (stored in `.forge-meta.json`) and the target.
|
|
113
|
-
4. **Patch**: Generates and applies a git patch using a 3-way merge strategy.
|
|
114
|
-
5. **Resolve**:
|
|
115
|
-
* Standard files use git's automatic conflict markers.
|
|
116
|
-
* `package.json` files are parsed, and dependencies are merged intelligently (e.g., `^1.0.0` vs `^1.1.0` -> `^1.1.0`).
|
|
117
|
-
6. **Cleanup**: Removes temporary remotes and artifacts.
|
|
141
|
+
## Mental Model
|
|
118
142
|
|
|
119
|
-
|
|
143
|
+
`@turboforge/sync` is not a scaffolder.
|
|
120
144
|
|
|
121
|
-
|
|
145
|
+
It is a bridge between:
|
|
122
146
|
|
|
123
|
-
|
|
124
|
-
|
|
147
|
+
- the template you started from
|
|
148
|
+
- the customized repo you run today
|
|
125
149
|
|
|
126
|
-
|
|
150
|
+
That is the core Turboforge bet: monorepos need an upgrade path, not just a bootstrap command.
|
package/index.d.mts
ADDED
package/index.mjs
ADDED
package/package.json
CHANGED
|
@@ -2,49 +2,39 @@
|
|
|
2
2
|
"name": "forge-sync",
|
|
3
3
|
"author": "Mayank Kumar Chaudhari <https://mayankchaudhari.com>",
|
|
4
4
|
"private": false,
|
|
5
|
-
"version": "0.0.
|
|
6
|
-
"description": "The authoritative synchronization engine for
|
|
5
|
+
"version": "0.0.1",
|
|
6
|
+
"description": "The authoritative synchronization engine for Turboforge monorepos to align tooling, configurations, and dependencies with upstream templates.",
|
|
7
7
|
"license": "MIT",
|
|
8
|
-
"main": "./
|
|
9
|
-
"module": "./
|
|
10
|
-
"types": "./
|
|
8
|
+
"main": "./index.mjs",
|
|
9
|
+
"module": "./index.mjs",
|
|
10
|
+
"types": "./index.d.mts",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
|
-
"import":
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
},
|
|
17
|
-
"require": {
|
|
18
|
-
"types": "./dist/index.d.ts",
|
|
19
|
-
"default": "./dist/index.js"
|
|
20
|
-
}
|
|
13
|
+
"import": "./index.mjs",
|
|
14
|
+
"types": "./index.d.mts",
|
|
15
|
+
"default": "./index.mjs"
|
|
21
16
|
},
|
|
22
17
|
"./package.json": "./package.json"
|
|
23
18
|
},
|
|
24
19
|
"repository": {
|
|
25
20
|
"type": "git",
|
|
26
|
-
"url": "https://github.com/
|
|
21
|
+
"url": "https://github.com/turboforge-dev/turboforge",
|
|
27
22
|
"directory": "packages/forge-sync"
|
|
28
23
|
},
|
|
29
|
-
"bugs": "https://github.com/
|
|
30
|
-
"homepage": "https://github.com/
|
|
24
|
+
"bugs": "https://github.com/turboforge-dev/turboforge/issues",
|
|
25
|
+
"homepage": "https://github.com/turboforge-dev/turboforge/blob/main/packages/forge-sync/README.md",
|
|
31
26
|
"sideEffects": false,
|
|
32
|
-
"files": [
|
|
33
|
-
"dist/**"
|
|
34
|
-
],
|
|
35
27
|
"bin": {
|
|
36
|
-
"forge-sync": "./dist/cli.mjs"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"@types/node": "latest",
|
|
40
|
-
"tsup": "latest",
|
|
41
|
-
"typescript": "latest",
|
|
42
|
-
"@turbo-forge/cli-kit": "^0.0.0"
|
|
28
|
+
"forge-sync": "./dist/cli.mjs",
|
|
29
|
+
"sync": "./dist/cli.mjs",
|
|
30
|
+
"turboforge": "./dist/cli.mjs"
|
|
43
31
|
},
|
|
32
|
+
"scripts": {},
|
|
33
|
+
"devDependencies": {},
|
|
44
34
|
"funding": [
|
|
45
35
|
{
|
|
46
36
|
"type": "github",
|
|
47
|
-
"url": "https://github.com/sponsors/
|
|
37
|
+
"url": "https://github.com/sponsors/turboforge-dev"
|
|
48
38
|
},
|
|
49
39
|
{
|
|
50
40
|
"type": "github",
|
|
@@ -52,23 +42,18 @@
|
|
|
52
42
|
}
|
|
53
43
|
],
|
|
54
44
|
"keywords": [
|
|
55
|
-
"
|
|
56
|
-
"turbo-forge",
|
|
45
|
+
"turboforge",
|
|
57
46
|
"monorepo",
|
|
47
|
+
"sync",
|
|
58
48
|
"template-sync",
|
|
59
49
|
"codemod",
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
50
|
+
"git-patch",
|
|
51
|
+
"package-json-merge",
|
|
52
|
+
"typescript",
|
|
53
|
+
"tooling"
|
|
63
54
|
],
|
|
64
55
|
"dependencies": {
|
|
65
|
-
"
|
|
66
|
-
"git-json-resolver-semver": "^1.0.0"
|
|
56
|
+
"@turboforge/sync": "0.0.1"
|
|
67
57
|
},
|
|
68
|
-
"
|
|
69
|
-
"build": "tsup",
|
|
70
|
-
"clean": "rm -rf dist",
|
|
71
|
-
"dev": "tsup --watch",
|
|
72
|
-
"typecheck": "tsc --noEmit"
|
|
73
|
-
}
|
|
58
|
+
"type": "module"
|
|
74
59
|
}
|
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 react18-tools
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/dist/chunk-3EYN2AKU.mjs
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
var g=Object.create;var f=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var i=Object.getOwnPropertyNames;var j=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var m=(a=>typeof require!="undefined"?require:typeof Proxy!="undefined"?new Proxy(a,{get:(b,c)=>(typeof require!="undefined"?require:b)[c]}):a)(function(a){if(typeof require!="undefined")return require.apply(this,arguments);throw Error('Dynamic require of "'+a+'" is not supported')});var n=(a,b)=>()=>(b||a((b={exports:{}}).exports,b),b.exports);var l=(a,b,c,e)=>{if(b&&typeof b=="object"||typeof b=="function")for(let d of i(b))!k.call(a,d)&&d!==c&&f(a,d,{get:()=>b[d],enumerable:!(e=h(b,d))||e.enumerable});return a};var o=(a,b,c)=>(c=a!=null?g(j(a)):{},l(b||!a||!a.__esModule?f(c,"default",{value:a,enumerable:!0}):c,a));export{m as a,n as b,o as c};
|
package/dist/chunk-UYOBIURF.mjs
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import{access as re,readFile as U,writeFile as M}from"fs/promises";import{resolve as ie}from"path";import{exec as z,execFile as I}from"child_process";import R from"fs";import L from"path";import{promisify as F}from"util";var m=F(z),d=F(I),Y=(e,r)=>{let n=L.resolve(e),{root:t}=L.parse(n);for(;;){for(let o of r)if(R.existsSync(L.join(n,o)))return n;if(n===t)break;n=L.dirname(n)}return null},H=e=>{try{if(!R.existsSync(e))return null;let r=R.readFileSync(e,"utf-8");return JSON.parse(r)}catch{return null}},K=async e=>{var r;if(!R.existsSync(e))return null;try{let n=await import("./jiti-DGVRRYDD.mjs"),o=(n.createJiti?n.createJiti(process.cwd()):n.default(process.cwd()))(e);return(r=o.default)!=null?r:o}catch{try{let n=await import(e);return n.default||n}catch(n){throw/\.(ts|mts)$/.test(e)?new Error(`Failed to load TypeScript config at ${e}. Please install 'jiti' as a dev dependency to load .ts files.`):n}}},k=(e,r)=>{if(typeof e!="object"||e===null||typeof r!="object"||r===null||Array.isArray(e)&&Array.isArray(r))return r;let n={...e};for(let t of Object.keys(r))Object.hasOwn(r,t)&&(t in e?n[t]=k(e[t],r[t]):n[t]=r[t]);return n};import{appendFileSync as J}from"fs";var f="\x1B[",S={gray:e=>`${f}90m${e}${f}39m`,blue:e=>`${f}34m${e}${f}39m`,yellow:e=>`${f}33m${e}${f}39m`,red:e=>`${f}31m${e}${f}39m`},P={debug:0,info:1,warn:2,error:3},O=e=>{let r=P[e.level],n=(t,o)=>{if(P[t]<r)return;let s=`[${new Date().toISOString()}] [${t.toUpperCase()}] ${o}`,l={debug:S.gray,info:S.blue,warn:S.yellow,error:S.red},g=process.stdout.isTTY&&!process.env.NO_COLOR||!!process.env.FORCE_COLOR;console.log(g?l[t](s):s),e.logFile&&J(e.logFile,`${s}
|
|
2
|
-
`)};return{debug:t=>n("debug",t),info:t=>n("info",t),warn:t=>n("warn",t),error:t=>n("error",t)}};import{resolveConflicts as j}from"git-json-resolver";var D=()=>Promise.all([m("git diff --quiet"),m("git diff --cached --quiet")]);var C=e=>e.replace(/[^a-zA-Z0-9]/g,""),N=e=>{let r=e.replace(/\s+/g,"-").replace(/[^a-zA-Z0-9_-]/g,"");if(!r||!/^[a-zA-Z0-9_]/.test(r)||r.startsWith("-"))throw new Error(`Invalid remote name: "${e}". Remote names may only contain letters, numbers, underscore, and hyphen, and cannot start with '-'.`);return r},h=e=>e.replace(/[\r\n]/g,""),A=async({remoteName:e,baseRef:r,targetRef:n,exclusions:t,logger:o,maxRetries:c=3,errorLogs:s=[]},l=0)=>{var x;if(l>c){o.warn(`Max patch recursion reached (${c}), stopping`);return}let g=`git diff ${r} ${e}/main -- ${t.join(" ")} .`;o.debug(`Running: ${g}`);let{stdout:b}=await d("git",["diff",r,`${e}/${n}`,"--",...t,"."],{encoding:"utf8"});await M(".template.patch",b),o.debug(`Patch written to .template.patch (${b.length} chars)`);try{o.debug("Applying patch with 3-way merge"),await m("git apply --3way --ignore-space-change --ignore-whitespace .template.patch",{encoding:"utf8"}),o.debug("Patch applied successfully")}catch($){let u=(x=$.stderr)==null?void 0:x.split(`
|
|
3
|
-
`).filter(i=>i.startsWith("error"));o.debug(`Patch failed with ${u.length} errors`),u.forEach(i=>{var p;let a=(p=i.split(":")[1])==null?void 0:p.trim();a&&(t.push(`:!${a}`),o.debug(`Added to exclusions: ${h(a)}`))}),s.push("Applied patch with errors: "),s.push({errorLines:u,exclusions:t}),s.push("^^^---Applied patch with errors"),u.length&&await A({remoteName:e,baseRef:r,targetRef:n,exclusions:t,logger:o,maxRetries:c,errorLogs:s},l+1)}},T=async e=>{await j({include:["package.json"],defaultStrategy:["merge","theirs"],rules:{name:["ours"],"devDependencies.*":["ignore-removed","theirs"],"dependencies.*":["ignore-removed","theirs"]},debug:e}),await j({include:["**/package.json"],exclude:["package.json","**/dist/**","**/.next/**"],defaultStrategy:["merge","non-empty","ours"],rules:{"devDependencies.*":["semver-max"],"dependencies.*":["semver-max"]},loggerConfig:{logDir:".logs2",levels:{stdout:[]}},plugins:["git-json-resolver-semver"],pluginConfig:{"git-json-resolver-semver":{preferValid:!0}},includeNonConflicted:!0,debug:e})},ae=async e=>{try{let s=await U(e,"utf8");return JSON.parse(s).lastSyncedCommit}catch{}let[{stdout:r},{stdout:n}]=await Promise.all([m("git log --reverse --format=%ai | head -n 1",{encoding:"utf8"}),m("git log --format=%H::%ai template/main",{encoding:"utf8"})]),t=new Date(r.trim()),c=n.trim().split(`
|
|
4
|
-
`).map(s=>{let[l,g]=s.split("::");return{hash:l,date:new Date(g==null?void 0:g.trim())}}).reverse().find(s=>s.date>=t);if(c)return console.info("Applying changes from ",c.hash," dated ",c.date),c.hash};import{writeFile as q}from"fs/promises";var G={logLevel:"info",dryRun:!1,templateUrl:"https://github.com/turbo-forge/forge-template.git",excludePaths:[],remoteName:"template",maxPatchRetries:3,backupDir:".forge-backup",skipCleanCheck:!1,targetRef:"main",metaFile:".forge-meta.json",baseRef:"",postSync:["pnpm install","pnpm biome check --write --no-errors-on-unmatched $(git diff --cached --name-only --diff-filter=ACM | grep -E '\\.(ts|tsx|js|json)$' || true)"]},_=[],me=async e=>{let{logLevel:r,skipCleanCheck:n,dryRun:t,remoteName:o,templateUrl:c,backupDir:s,baseRef:l,excludePaths:g,targetRef:b,metaFile:x,postSync:$,maxPatchRetries:u}=k(G,e),i=O({level:r});if(!l){i.error("\u274C Error: Base ref is required");return}if(n)i.info("Skipping git clean check");else try{await D(),i.info("Git tree is clean")}catch{i.error("\u274C Error: Please commit or stash your changes before upgrading.");return}t&&i.info("Dry run mode - no changes will be applied");let a=N(o);try{await Promise.all([d("git",["remote","add",a,c]),m(`rm -rf ${s}`)])}catch{i.debug(`${h(a)} remote already exists`)}finally{i.debug(`Added ${h(a)} remote: ${h(c)}`)}try{await d("git",["fetch",a]),i.debug(`Fetched latest changes from ${h(a)}`);let p=C(l),y=C(b),v=[...g].map(w=>`:!${w}`);if(i.debug(`Base exclusions: ${v.length} items`),i.debug(`Generating patch from ${p} to ${y}`),i.debug(`Total exclusions: ${v.length}`),t){let{stdout:w}=await d("git",["diff",p,`${a}/${y}`,"--",...v,"."],{encoding:"utf8"});i.info("\u{1F4CB} Patch preview:"),i.info(w||"No changes to apply");return}await A({remoteName:a,baseRef:p,targetRef:y,exclusions:v,logger:i,maxRetries:u,errorLogs:_});let{stdout:E}=await d("git",["rev-parse",`${a}/${y}`],{encoding:"utf8"});await q(x,JSON.stringify({lastSyncedCommit:E.trim(),baseRef:p,targetRef:y,generatedAt:new Date().toISOString()},null,2)),await T(r==="debug"),console.log("\u2705 Upgrade applied successfully."),t||(i.info("Running post-sync commands..."),i.info($.join(`
|
|
5
|
-
`)),await Promise.all($.map(w=>m(w))))}catch(p){console.error("\u274C Upgrade failed:",p)}try{await d("git",["remote","remove",a])}catch{}};export{Y as a,H as b,K as c,k as d,ae as e,G as f,me as g};
|
package/dist/cli.d.mts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { ForgeSyncOptions } from './index.mjs';
|
|
3
|
-
|
|
4
|
-
interface CliOptions extends ForgeSyncOptions {
|
|
5
|
-
help?: boolean;
|
|
6
|
-
init?: boolean;
|
|
7
|
-
config?: string;
|
|
8
|
-
}
|
|
9
|
-
declare const parseArgs: (args: string[]) => Partial<CliOptions>;
|
|
10
|
-
declare const showHelp: () => void;
|
|
11
|
-
declare const main: (args?: string[]) => Promise<void>;
|
|
12
|
-
|
|
13
|
-
export { main, parseArgs, showHelp };
|
package/dist/cli.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { ForgeSyncOptions } from './index.js';
|
|
3
|
-
|
|
4
|
-
interface CliOptions extends ForgeSyncOptions {
|
|
5
|
-
help?: boolean;
|
|
6
|
-
init?: boolean;
|
|
7
|
-
config?: string;
|
|
8
|
-
}
|
|
9
|
-
declare const parseArgs: (args: string[]) => Partial<CliOptions>;
|
|
10
|
-
declare const showHelp: () => void;
|
|
11
|
-
declare const main: (args?: string[]) => Promise<void>;
|
|
12
|
-
|
|
13
|
-
export { main, parseArgs, showHelp };
|