@gitwand/cli 1.6.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/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/cli.d.ts +34 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +87 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/resolve.d.ts +20 -0
- package/dist/commands/resolve.d.ts.map +1 -0
- package/dist/commands/resolve.js +139 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +76 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/concurrency.d.ts +28 -0
- package/dist/concurrency.d.ts.map +1 -0
- package/dist/concurrency.js +49 -0
- package/dist/concurrency.js.map +1 -0
- package/dist/git.d.ts +19 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +33 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/partial-content.d.ts +24 -0
- package/dist/partial-content.d.ts.map +1 -0
- package/dist/partial-content.js +57 -0
- package/dist/partial-content.js.map +1 -0
- package/dist/reporting.d.ts +92 -0
- package/dist/reporting.d.ts.map +1 -0
- package/dist/reporting.js +97 -0
- package/dist/reporting.js.map +1 -0
- package/dist/ui.d.ts +30 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +34 -0
- package/dist/ui.js.map +1 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Laurent Guitton
|
|
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/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# @gitwand/cli
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@gitwand/cli)
|
|
4
|
+
[](../../LICENSE)
|
|
5
|
+
|
|
6
|
+
**Auto-resolve trivial Git merge conflicts from your terminal or CI.**
|
|
7
|
+
|
|
8
|
+
Part of [GitWand](https://github.com/devlint/GitWand). `@gitwand/cli` wraps the same conflict resolution engine as the desktop app and MCP server, exposing it as a single binary you can drop into any shell or pipeline.
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
# One-shot (no install)
|
|
14
|
+
npx @gitwand/cli resolve
|
|
15
|
+
|
|
16
|
+
# Global install
|
|
17
|
+
npm install -g @gitwand/cli
|
|
18
|
+
gitwand resolve
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Requires Node.js ≥ 18.
|
|
22
|
+
|
|
23
|
+
## Quickstart
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Mid-merge, from the repo root:
|
|
27
|
+
gitwand resolve # Resolve every conflicted file GitWand can handle
|
|
28
|
+
gitwand resolve --dry-run # Preview without touching files
|
|
29
|
+
gitwand status # List conflicted files with auto-resolvability
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
### `gitwand resolve [files...]`
|
|
35
|
+
|
|
36
|
+
Auto-resolves trivial conflicts. With no arguments, it picks up every conflicted file from `git diff --name-only --diff-filter=U`. Pass specific paths to scope the run.
|
|
37
|
+
|
|
38
|
+
**Flags**
|
|
39
|
+
- `--dry-run` — analyze without writing files
|
|
40
|
+
- `--verbose` — print the decision trace for each hunk
|
|
41
|
+
- `--no-whitespace` — skip whitespace-only resolutions
|
|
42
|
+
- `--concurrency=N` — parallel file workers (default: CPU count, min 1)
|
|
43
|
+
- `--ci` — CI mode: JSON output + semantic exit codes
|
|
44
|
+
- `--json` — force JSON output (implies `--ci` semantics)
|
|
45
|
+
|
|
46
|
+
**Exit codes**
|
|
47
|
+
- `0` — all conflicts resolved
|
|
48
|
+
- `1` — conflicts remain (in `--ci` / `--json` mode)
|
|
49
|
+
- `2` — internal error
|
|
50
|
+
|
|
51
|
+
### `gitwand status`
|
|
52
|
+
|
|
53
|
+
Lists conflicted files with per-file counts, detected pattern types, and the share GitWand can handle automatically.
|
|
54
|
+
|
|
55
|
+
### `gitwand --help`
|
|
56
|
+
|
|
57
|
+
Full help text.
|
|
58
|
+
|
|
59
|
+
## CI usage
|
|
60
|
+
|
|
61
|
+
The `--ci` flag emits a structured JSON report and uses semantic exit codes, so you can wire it into any pipeline:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
# .github/workflows/merge-check.yml
|
|
65
|
+
- name: Auto-resolve trivial conflicts
|
|
66
|
+
run: |
|
|
67
|
+
git merge origin/main || true
|
|
68
|
+
npx @gitwand/cli resolve --ci
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Exit `0` → everything auto-resolved, safe to continue. Exit `1` → there are complex conflicts that need human or LLM attention; the JSON output lists them with ours/theirs/base content.
|
|
72
|
+
|
|
73
|
+
## JSON output shape
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"version": "1.6.0",
|
|
78
|
+
"timestamp": "2026-05-20T12:00:00.000Z",
|
|
79
|
+
"summary": {
|
|
80
|
+
"files": 2,
|
|
81
|
+
"totalConflicts": 5,
|
|
82
|
+
"autoResolved": 4,
|
|
83
|
+
"remaining": 1,
|
|
84
|
+
"allResolved": false
|
|
85
|
+
},
|
|
86
|
+
"files": [
|
|
87
|
+
{
|
|
88
|
+
"path": "src/config.ts",
|
|
89
|
+
"totalConflicts": 3,
|
|
90
|
+
"autoResolved": 3,
|
|
91
|
+
"resolutions": [
|
|
92
|
+
{
|
|
93
|
+
"line": 15,
|
|
94
|
+
"type": "one_side_change",
|
|
95
|
+
"resolved": true,
|
|
96
|
+
"confidence": { "score": 95, "label": "certain" },
|
|
97
|
+
"trace": { "selected": "theirs", "summary": "..." }
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"pendingHunks": []
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The `pendingHunks` array gives you everything needed for a downstream LLM or human review: ours/theirs/base content, classification trace, confidence breakdown.
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
Drop a `.gitwandrc` at the repo root:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"policy": "prefer-merge",
|
|
115
|
+
"patternOverrides": {
|
|
116
|
+
"*.lock": "prefer-theirs",
|
|
117
|
+
"CHANGELOG.md": "prefer-ours"
|
|
118
|
+
},
|
|
119
|
+
"generatedFiles": ["src/generated/**", "**/*.pb.ts"]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Policies: `prefer-ours`, `prefer-theirs`, `prefer-safety`, `prefer-merge`, `strict`.
|
|
124
|
+
|
|
125
|
+
## What gets auto-resolved
|
|
126
|
+
|
|
127
|
+
GitWand only resolves when it's certain. It classifies each hunk against a registry of patterns (`same_change`, `one_side_change`, `non_overlapping`, `whitespace_only`, `reorder_only`, `insertion_at_boundary`, `value_only_change`, `generated_file`). Overlapping edits are flagged `complex` and never touched.
|
|
128
|
+
|
|
129
|
+
Format-aware resolvers apply to JSON, Markdown, YAML, Vue SFC, CSS, and lockfiles before pure text matching.
|
|
130
|
+
|
|
131
|
+
## Also available
|
|
132
|
+
|
|
133
|
+
- **[@gitwand/mcp](https://www.npmjs.com/package/@gitwand/mcp)** — same engine as an MCP server for Claude, Cursor, Windsurf.
|
|
134
|
+
- **[GitWand desktop app](https://github.com/devlint/GitWand#desktop-app)** — full Git client with built-in resolution, merge preview, and inline code review.
|
|
135
|
+
|
|
136
|
+
## Links
|
|
137
|
+
|
|
138
|
+
- 📖 [Documentation](https://github.com/devlint/GitWand#cli)
|
|
139
|
+
- 🐛 [Issue tracker](https://github.com/devlint/GitWand/issues)
|
|
140
|
+
- 🌐 [Website](https://devlint.github.io/GitWand/)
|
|
141
|
+
- 📜 [License — MIT](../../LICENSE)
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser de CLI + dispatcher de commandes.
|
|
3
|
+
*
|
|
4
|
+
* Ce module isole la partie « front » du CLI :
|
|
5
|
+
* - parse `process.argv` en `{ command, positional, flags }`,
|
|
6
|
+
* - imprime l'aide (`printHelp`),
|
|
7
|
+
* - dispatch vers `commands/resolve` ou `commands/status`.
|
|
8
|
+
*
|
|
9
|
+
* Les commandes et la mécanique de parallélisation vivent dans des
|
|
10
|
+
* modules dédiés. Ici on reste volontairement léger — c'est le point
|
|
11
|
+
* d'entrée lisible du binaire `gitwand`.
|
|
12
|
+
*
|
|
13
|
+
* Parser de flags :
|
|
14
|
+
* - `--key` → `flags.key = true`
|
|
15
|
+
* - `--key=value` → `flags.key = value` (requis pour `--concurrency=N`)
|
|
16
|
+
*
|
|
17
|
+
* Tout token ne commençant pas par `--` est considéré comme positionnel.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Parse `process.argv` (les args utilisateur, sans `node` ni le script) en
|
|
21
|
+
* `{ command, positional, flags }`. Supporte `--flag` et `--key=value`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseArgs(argv: string[]): {
|
|
24
|
+
command: string | undefined;
|
|
25
|
+
positional: string[];
|
|
26
|
+
flags: Record<string, boolean | string>;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Point d'entrée logique du CLI. Lit `process.argv`, parse et dispatch.
|
|
30
|
+
* Ne fait jamais de `process.exit` hors des commandes elles-mêmes : le
|
|
31
|
+
* wrapper (`index.ts`) gère les erreurs non rattrapées.
|
|
32
|
+
*/
|
|
33
|
+
export declare function main(): Promise<void>;
|
|
34
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAwBH;;;GAGG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG;IACzC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC;CACzC,CAoBA;AAED;;;;GAIG;AACH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAe1C"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parser de CLI + dispatcher de commandes.
|
|
3
|
+
*
|
|
4
|
+
* Ce module isole la partie « front » du CLI :
|
|
5
|
+
* - parse `process.argv` en `{ command, positional, flags }`,
|
|
6
|
+
* - imprime l'aide (`printHelp`),
|
|
7
|
+
* - dispatch vers `commands/resolve` ou `commands/status`.
|
|
8
|
+
*
|
|
9
|
+
* Les commandes et la mécanique de parallélisation vivent dans des
|
|
10
|
+
* modules dédiés. Ici on reste volontairement léger — c'est le point
|
|
11
|
+
* d'entrée lisible du binaire `gitwand`.
|
|
12
|
+
*
|
|
13
|
+
* Parser de flags :
|
|
14
|
+
* - `--key` → `flags.key = true`
|
|
15
|
+
* - `--key=value` → `flags.key = value` (requis pour `--concurrency=N`)
|
|
16
|
+
*
|
|
17
|
+
* Tout token ne commençant pas par `--` est considéré comme positionnel.
|
|
18
|
+
*/
|
|
19
|
+
import { c, printBanner } from "./ui.js";
|
|
20
|
+
import { DEFAULT_CONCURRENCY } from "./concurrency.js";
|
|
21
|
+
import { cmdResolve } from "./commands/resolve.js";
|
|
22
|
+
import { cmdStatus } from "./commands/status.js";
|
|
23
|
+
function printHelp() {
|
|
24
|
+
printBanner();
|
|
25
|
+
console.log(`${c.bold}Usage:${c.reset}`);
|
|
26
|
+
console.log(` gitwand resolve [files...] Auto-resolve trivial conflicts`);
|
|
27
|
+
console.log(` gitwand status Show conflict status`);
|
|
28
|
+
console.log(` gitwand --help Show this help`);
|
|
29
|
+
console.log();
|
|
30
|
+
console.log(`${c.bold}Options:${c.reset}`);
|
|
31
|
+
console.log(` --dry-run Analyze without writing files`);
|
|
32
|
+
console.log(` --verbose Show details for each resolution`);
|
|
33
|
+
console.log(` --no-whitespace Don't resolve whitespace-only conflicts`);
|
|
34
|
+
console.log(` --concurrency=N Parallel file workers (default ${DEFAULT_CONCURRENCY}, min 1)`);
|
|
35
|
+
console.log(` --ci CI mode: JSON output + exit code 1 if unresolved`);
|
|
36
|
+
console.log(` --json Output results as JSON (implies --ci behavior)`);
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Parse `process.argv` (les args utilisateur, sans `node` ni le script) en
|
|
41
|
+
* `{ command, positional, flags }`. Supporte `--flag` et `--key=value`.
|
|
42
|
+
*/
|
|
43
|
+
export function parseArgs(argv) {
|
|
44
|
+
const command = argv[0];
|
|
45
|
+
const flags = {};
|
|
46
|
+
const positional = [];
|
|
47
|
+
for (const arg of argv.slice(1)) {
|
|
48
|
+
if (arg.startsWith("--")) {
|
|
49
|
+
const body = arg.slice(2);
|
|
50
|
+
const eq = body.indexOf("=");
|
|
51
|
+
if (eq >= 0) {
|
|
52
|
+
flags[body.slice(0, eq)] = body.slice(eq + 1);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
flags[body] = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
positional.push(arg);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { command, positional, flags };
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Point d'entrée logique du CLI. Lit `process.argv`, parse et dispatch.
|
|
66
|
+
* Ne fait jamais de `process.exit` hors des commandes elles-mêmes : le
|
|
67
|
+
* wrapper (`index.ts`) gère les erreurs non rattrapées.
|
|
68
|
+
*/
|
|
69
|
+
export async function main() {
|
|
70
|
+
const args = process.argv.slice(2);
|
|
71
|
+
const { command, positional, flags } = parseArgs(args);
|
|
72
|
+
if (!command || command === "--help" || command === "-h") {
|
|
73
|
+
printHelp();
|
|
74
|
+
}
|
|
75
|
+
else if (command === "resolve") {
|
|
76
|
+
await cmdResolve(positional, flags);
|
|
77
|
+
}
|
|
78
|
+
else if (command === "status") {
|
|
79
|
+
await cmdStatus(flags);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.error(`${c.red}Unknown command: ${command}${c.reset}`);
|
|
83
|
+
printHelp();
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande `gitwand resolve` — boucle de résolution principale.
|
|
3
|
+
*
|
|
4
|
+
* Flux (P1.3 — parallèle) :
|
|
5
|
+
* 1. découverte des fichiers (args positionnels, sinon `git diff`),
|
|
6
|
+
* 2. pool concurrent borné par `--concurrency=N` (défaut 8),
|
|
7
|
+
* 3. chaque worker : lit le fichier, appelle `resolve()`, écrit le résultat
|
|
8
|
+
* (partiel ou complet) sauf en `--dry-run`,
|
|
9
|
+
* 4. flush ordonné des lignes d'affichage et du rapport JSON CI.
|
|
10
|
+
*
|
|
11
|
+
* Notes importantes :
|
|
12
|
+
* - `verbose: false` est toujours passé à `resolve()` pour éviter que des
|
|
13
|
+
* `console.log` internes s'interleavent entre workers. On ré-imprime
|
|
14
|
+
* nous-mêmes un résumé plus riche (incluant `trace.summary`) en verbose.
|
|
15
|
+
* - L'ordre des résultats (affichage + JSON) est garanti par `runPool` —
|
|
16
|
+
* les workers écrivent dans un tableau indexé par position d'entrée.
|
|
17
|
+
* - Pas de write-race possible : chaque fichier n'a qu'un seul writer.
|
|
18
|
+
*/
|
|
19
|
+
export declare function cmdResolve(files: string[], flags: Record<string, boolean | string>): Promise<void>;
|
|
20
|
+
//# sourceMappingURL=resolve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/commands/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAoJf"}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande `gitwand resolve` — boucle de résolution principale.
|
|
3
|
+
*
|
|
4
|
+
* Flux (P1.3 — parallèle) :
|
|
5
|
+
* 1. découverte des fichiers (args positionnels, sinon `git diff`),
|
|
6
|
+
* 2. pool concurrent borné par `--concurrency=N` (défaut 8),
|
|
7
|
+
* 3. chaque worker : lit le fichier, appelle `resolve()`, écrit le résultat
|
|
8
|
+
* (partiel ou complet) sauf en `--dry-run`,
|
|
9
|
+
* 4. flush ordonné des lignes d'affichage et du rapport JSON CI.
|
|
10
|
+
*
|
|
11
|
+
* Notes importantes :
|
|
12
|
+
* - `verbose: false` est toujours passé à `resolve()` pour éviter que des
|
|
13
|
+
* `console.log` internes s'interleavent entre workers. On ré-imprime
|
|
14
|
+
* nous-mêmes un résumé plus riche (incluant `trace.summary`) en verbose.
|
|
15
|
+
* - L'ordre des résultats (affichage + JSON) est garanti par `runPool` —
|
|
16
|
+
* les workers écrivent dans un tableau indexé par position d'entrée.
|
|
17
|
+
* - Pas de write-race possible : chaque fichier n'a qu'un seul writer.
|
|
18
|
+
*/
|
|
19
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
20
|
+
import { resolve as resolvePath } from "node:path";
|
|
21
|
+
import { resolve } from "@gitwand/core";
|
|
22
|
+
import { c, printBanner, WAND } from "../ui.js";
|
|
23
|
+
import { getConflictedFiles } from "../git.js";
|
|
24
|
+
import { parseConcurrency, runPool } from "../concurrency.js";
|
|
25
|
+
import { buildPartialContent } from "../partial-content.js";
|
|
26
|
+
import { buildCIReport } from "../reporting.js";
|
|
27
|
+
export async function cmdResolve(files, flags) {
|
|
28
|
+
const isCIMode = flags.ci || flags.json;
|
|
29
|
+
const verbose = !isCIMode && (flags.verbose === true || typeof flags.verbose === "string");
|
|
30
|
+
const resolveWhitespace = !(flags["no-whitespace"] === true);
|
|
31
|
+
const concurrency = parseConcurrency(flags.concurrency);
|
|
32
|
+
if (!isCIMode) {
|
|
33
|
+
printBanner();
|
|
34
|
+
}
|
|
35
|
+
// If no files specified, discover from git
|
|
36
|
+
if (files.length === 0) {
|
|
37
|
+
files = getConflictedFiles();
|
|
38
|
+
if (files.length === 0) {
|
|
39
|
+
if (isCIMode) {
|
|
40
|
+
console.log(JSON.stringify({ version: "0.0.1", summary: { files: 0, totalConflicts: 0, autoResolved: 0, remaining: 0, allResolved: true }, files: [] }, null, 2));
|
|
41
|
+
process.exit(0);
|
|
42
|
+
}
|
|
43
|
+
console.log(`${c.green}No conflicted files detected.${c.reset}`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!isCIMode) {
|
|
47
|
+
console.log(`${c.cyan}${files.length} conflicted file(s) detected${c.reset}\n`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
const outcomes = await runPool(files, concurrency, async (file) => {
|
|
51
|
+
const filePath = resolvePath(file);
|
|
52
|
+
let content;
|
|
53
|
+
try {
|
|
54
|
+
content = await readFile(filePath, "utf-8");
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {
|
|
58
|
+
file,
|
|
59
|
+
result: null,
|
|
60
|
+
printLines: isCIMode ? [] : [`${c.red} \u2717 ${file} — file not found${c.reset}`],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
const result = resolve(content, file, {
|
|
64
|
+
verbose: false,
|
|
65
|
+
resolveWhitespace,
|
|
66
|
+
});
|
|
67
|
+
// Écriture sur disque (sauf dry-run). L'écriture est concurrente entre
|
|
68
|
+
// fichiers distincts, mais chaque fichier n'a qu'un seul writer — il n'y
|
|
69
|
+
// a donc pas de write-race possible tant que les chemins sont distincts.
|
|
70
|
+
if (!flags["dry-run"] && result.stats.autoResolved > 0) {
|
|
71
|
+
const newContent = result.mergedContent ?? buildPartialContent(content, result.resolutions);
|
|
72
|
+
await writeFile(filePath, newContent, "utf-8");
|
|
73
|
+
}
|
|
74
|
+
const printLines = [];
|
|
75
|
+
if (!isCIMode) {
|
|
76
|
+
if (result.stats.totalConflicts === 0) {
|
|
77
|
+
printLines.push(`${c.dim} \u25CB ${file} — no conflicts${c.reset}`);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
const icon = result.stats.remaining === 0 ? "\u2713" : "\u25D0";
|
|
81
|
+
const color = result.stats.remaining === 0 ? c.green : c.yellow;
|
|
82
|
+
printLines.push(`${color} ${icon} ${file} — ${result.stats.autoResolved}/${result.stats.totalConflicts} resolved${c.reset}`);
|
|
83
|
+
if (verbose) {
|
|
84
|
+
for (const res of result.resolutions) {
|
|
85
|
+
const status = res.autoResolved
|
|
86
|
+
? `${c.green}auto${c.reset}`
|
|
87
|
+
: `${c.red}manual${c.reset}`;
|
|
88
|
+
printLines.push(`${c.dim} L${res.hunk.startLine} [${res.hunk.type}] ${status} — ${res.hunk.explanation}${c.reset}`);
|
|
89
|
+
printLines.push(`${c.dim} trace: ${res.hunk.trace.summary}${c.reset}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return { file, result, printLines };
|
|
95
|
+
});
|
|
96
|
+
// Flush ordonné (ordre de `files`, pas ordre de complétion).
|
|
97
|
+
if (!isCIMode) {
|
|
98
|
+
for (const outcome of outcomes) {
|
|
99
|
+
for (const line of outcome.printLines) {
|
|
100
|
+
console.log(line);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const results = [];
|
|
105
|
+
let totalResolved = 0;
|
|
106
|
+
let totalRemaining = 0;
|
|
107
|
+
let totalConflicts = 0;
|
|
108
|
+
for (const outcome of outcomes) {
|
|
109
|
+
if (outcome.result === null)
|
|
110
|
+
continue;
|
|
111
|
+
results.push({ file: outcome.file, result: outcome.result });
|
|
112
|
+
totalConflicts += outcome.result.stats.totalConflicts;
|
|
113
|
+
totalResolved += outcome.result.stats.autoResolved;
|
|
114
|
+
totalRemaining += outcome.result.stats.remaining;
|
|
115
|
+
}
|
|
116
|
+
// CI mode: JSON output
|
|
117
|
+
if (isCIMode) {
|
|
118
|
+
const report = buildCIReport(results);
|
|
119
|
+
console.log(JSON.stringify(report, null, 2));
|
|
120
|
+
if (report.summary.remaining > 0) {
|
|
121
|
+
process.exit(1);
|
|
122
|
+
}
|
|
123
|
+
process.exit(0);
|
|
124
|
+
}
|
|
125
|
+
// Human-readable summary
|
|
126
|
+
console.log(`\n${c.bold}\u2500\u2500\u2500 Summary \u2500\u2500\u2500${c.reset}`);
|
|
127
|
+
console.log(`${c.bold}${WAND} ${totalResolved}${c.reset} conflict(s) auto-resolved out of ${c.bold}${totalConflicts}${c.reset}`);
|
|
128
|
+
if (totalRemaining > 0) {
|
|
129
|
+
console.log(`${c.yellow}${totalRemaining} conflict(s) remaining — manual resolution needed${c.reset}`);
|
|
130
|
+
}
|
|
131
|
+
else if (totalConflicts > 0) {
|
|
132
|
+
console.log(`${c.green}${c.bold}All conflicts resolved! ${WAND}${c.reset}`);
|
|
133
|
+
}
|
|
134
|
+
if (flags["dry-run"]) {
|
|
135
|
+
console.log(`\n${c.dim}(dry-run — no files modified)${c.reset}`);
|
|
136
|
+
}
|
|
137
|
+
console.log();
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/commands/resolve.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande `gitwand status` — aperçu des conflits sans écriture.
|
|
3
|
+
*
|
|
4
|
+
* Lit chaque fichier en conflit, le passe à `resolve()` en lecture seule
|
|
5
|
+
* pour estimer le ratio `resolvable/total`, puis affiche un résumé par
|
|
6
|
+
* fichier (ou un JSON en mode CI).
|
|
7
|
+
*
|
|
8
|
+
* Comme pour `resolve`, la boucle est parallélisée (P1.3) avec `runPool`
|
|
9
|
+
* et l'affichage est ordonné à l'identique de la liste des fichiers en
|
|
10
|
+
* conflit retournée par Git.
|
|
11
|
+
*/
|
|
12
|
+
export declare function cmdStatus(flags: Record<string, boolean | string>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,wBAAsB,SAAS,CAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAAC,GACtC,OAAO,CAAC,IAAI,CAAC,CAkEf"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Commande `gitwand status` — aperçu des conflits sans écriture.
|
|
3
|
+
*
|
|
4
|
+
* Lit chaque fichier en conflit, le passe à `resolve()` en lecture seule
|
|
5
|
+
* pour estimer le ratio `resolvable/total`, puis affiche un résumé par
|
|
6
|
+
* fichier (ou un JSON en mode CI).
|
|
7
|
+
*
|
|
8
|
+
* Comme pour `resolve`, la boucle est parallélisée (P1.3) avec `runPool`
|
|
9
|
+
* et l'affichage est ordonné à l'identique de la liste des fichiers en
|
|
10
|
+
* conflit retournée par Git.
|
|
11
|
+
*/
|
|
12
|
+
import { readFile } from "node:fs/promises";
|
|
13
|
+
import { resolve as resolvePath } from "node:path";
|
|
14
|
+
import { resolve } from "@gitwand/core";
|
|
15
|
+
import { c, printBanner } from "../ui.js";
|
|
16
|
+
import { getConflictedFiles } from "../git.js";
|
|
17
|
+
import { parseConcurrency, runPool } from "../concurrency.js";
|
|
18
|
+
export async function cmdStatus(flags) {
|
|
19
|
+
const isCIMode = flags.ci || flags.json;
|
|
20
|
+
const concurrency = parseConcurrency(flags.concurrency);
|
|
21
|
+
if (!isCIMode) {
|
|
22
|
+
printBanner();
|
|
23
|
+
}
|
|
24
|
+
const files = getConflictedFiles();
|
|
25
|
+
if (files.length === 0) {
|
|
26
|
+
if (isCIMode) {
|
|
27
|
+
console.log(JSON.stringify({ files: 0, conflicts: [] }, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(`${c.green}No conflicted files.${c.reset}\n`);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
if (!isCIMode) {
|
|
34
|
+
console.log(`${c.cyan}${files.length} conflicted file(s):${c.reset}\n`);
|
|
35
|
+
}
|
|
36
|
+
const outcomes = await runPool(files, concurrency, async (file) => {
|
|
37
|
+
const filePath = resolvePath(file);
|
|
38
|
+
try {
|
|
39
|
+
const content = await readFile(filePath, "utf-8");
|
|
40
|
+
const result = resolve(content, file);
|
|
41
|
+
const resolvable = result.stats.autoResolved;
|
|
42
|
+
const total = result.stats.totalConflicts;
|
|
43
|
+
const pct = total > 0 ? Math.round((resolvable / total) * 100) : 0;
|
|
44
|
+
const entry = { path: file, total, resolvable, percentage: pct };
|
|
45
|
+
if (isCIMode)
|
|
46
|
+
return { entry, printLine: null };
|
|
47
|
+
const color = pct === 100 ? c.green : pct > 0 ? c.yellow : c.red;
|
|
48
|
+
return {
|
|
49
|
+
entry,
|
|
50
|
+
printLine: ` ${color}${file}${c.reset} — ${resolvable}/${total} resolvable (${pct}%)`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return {
|
|
55
|
+
entry: null,
|
|
56
|
+
printLine: isCIMode ? null : ` ${c.red}${file}${c.reset} — read error`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
const statusEntries = outcomes
|
|
61
|
+
.map((o) => o.entry)
|
|
62
|
+
.filter((e) => e !== null);
|
|
63
|
+
if (!isCIMode) {
|
|
64
|
+
for (const outcome of outcomes) {
|
|
65
|
+
if (outcome.printLine !== null)
|
|
66
|
+
console.log(outcome.printLine);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (isCIMode) {
|
|
70
|
+
console.log(JSON.stringify({ files: files.length, conflicts: statusEntries }, null, 2));
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pool de concurrence borné — primitive de parallélisation (P1.3).
|
|
3
|
+
*
|
|
4
|
+
* Le CLI n'a volontairement aucune dépendance runtime hors `@gitwand/core`.
|
|
5
|
+
* Plutôt que d'ajouter `p-limit`/`p-queue`, on expose ici un petit pool
|
|
6
|
+
* indexé qui préserve l'ordre des résultats (chaque worker écrit son
|
|
7
|
+
* `results[i]` à la position d'origine de l'item) — garantie importante
|
|
8
|
+
* pour rester déterministe vis-à-vis de l'affichage utilisateur et du
|
|
9
|
+
* rapport JSON CI.
|
|
10
|
+
*/
|
|
11
|
+
/** Borne par défaut sur le nombre de fichiers traités en parallèle. */
|
|
12
|
+
export declare const DEFAULT_CONCURRENCY = 8;
|
|
13
|
+
/**
|
|
14
|
+
* Petit pool de workers avec concurrence bornée.
|
|
15
|
+
*
|
|
16
|
+
* @param items — items à traiter (liste indexée)
|
|
17
|
+
* @param concurrency — plafond de workers en vol (min = 1, clampé à `items.length`)
|
|
18
|
+
* @param worker — fonction appelée par item, async autorisée
|
|
19
|
+
* @returns tableau de résultats dans l'ordre des `items` d'entrée
|
|
20
|
+
*/
|
|
21
|
+
export declare function runPool<In, Out>(items: In[], concurrency: number, worker: (item: In, index: number) => Promise<Out>): Promise<Out[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Extrait une concurrence entière positive depuis un flag stringifié
|
|
24
|
+
* (`--concurrency=12`). Retourne `DEFAULT_CONCURRENCY` pour toute valeur
|
|
25
|
+
* non parseable ou ≤ 0, afin de ne jamais casser l'invocation.
|
|
26
|
+
*/
|
|
27
|
+
export declare function parseConcurrency(flag: boolean | string | undefined): number;
|
|
28
|
+
//# sourceMappingURL=concurrency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.d.ts","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,uEAAuE;AACvE,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,EAAE,EAAE,GAAG,EACnC,KAAK,EAAE,EAAE,EAAE,EACX,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,GAAG,CAAC,GAChD,OAAO,CAAC,GAAG,EAAE,CAAC,CAehB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAK3E"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pool de concurrence borné — primitive de parallélisation (P1.3).
|
|
3
|
+
*
|
|
4
|
+
* Le CLI n'a volontairement aucune dépendance runtime hors `@gitwand/core`.
|
|
5
|
+
* Plutôt que d'ajouter `p-limit`/`p-queue`, on expose ici un petit pool
|
|
6
|
+
* indexé qui préserve l'ordre des résultats (chaque worker écrit son
|
|
7
|
+
* `results[i]` à la position d'origine de l'item) — garantie importante
|
|
8
|
+
* pour rester déterministe vis-à-vis de l'affichage utilisateur et du
|
|
9
|
+
* rapport JSON CI.
|
|
10
|
+
*/
|
|
11
|
+
/** Borne par défaut sur le nombre de fichiers traités en parallèle. */
|
|
12
|
+
export const DEFAULT_CONCURRENCY = 8;
|
|
13
|
+
/**
|
|
14
|
+
* Petit pool de workers avec concurrence bornée.
|
|
15
|
+
*
|
|
16
|
+
* @param items — items à traiter (liste indexée)
|
|
17
|
+
* @param concurrency — plafond de workers en vol (min = 1, clampé à `items.length`)
|
|
18
|
+
* @param worker — fonction appelée par item, async autorisée
|
|
19
|
+
* @returns tableau de résultats dans l'ordre des `items` d'entrée
|
|
20
|
+
*/
|
|
21
|
+
export async function runPool(items, concurrency, worker) {
|
|
22
|
+
const results = new Array(items.length);
|
|
23
|
+
const width = Math.max(1, Math.min(concurrency, items.length));
|
|
24
|
+
let nextIndex = 0;
|
|
25
|
+
const runOne = async () => {
|
|
26
|
+
while (true) {
|
|
27
|
+
const i = nextIndex++;
|
|
28
|
+
if (i >= items.length)
|
|
29
|
+
return;
|
|
30
|
+
results[i] = await worker(items[i], i);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
await Promise.all(Array.from({ length: width }, runOne));
|
|
34
|
+
return results;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Extrait une concurrence entière positive depuis un flag stringifié
|
|
38
|
+
* (`--concurrency=12`). Retourne `DEFAULT_CONCURRENCY` pour toute valeur
|
|
39
|
+
* non parseable ou ≤ 0, afin de ne jamais casser l'invocation.
|
|
40
|
+
*/
|
|
41
|
+
export function parseConcurrency(flag) {
|
|
42
|
+
if (typeof flag !== "string")
|
|
43
|
+
return DEFAULT_CONCURRENCY;
|
|
44
|
+
const n = Number.parseInt(flag, 10);
|
|
45
|
+
if (!Number.isFinite(n) || n <= 0)
|
|
46
|
+
return DEFAULT_CONCURRENCY;
|
|
47
|
+
return n;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=concurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../src/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,uEAAuE;AACvE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAW,EACX,WAAmB,EACnB,MAAiD;IAEjD,MAAM,OAAO,GAAU,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,KAAK,CAAC,MAAM;gBAAE,OAAO;YAC9B,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACzD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAkC;IACjE,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,mBAAmB,CAAC;IACzD,MAAM,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,mBAAmB,CAAC;IAC9D,OAAO,CAAC,CAAC;AACX,CAAC"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intégration Git — découverte des fichiers en conflit.
|
|
3
|
+
*
|
|
4
|
+
* `execSync` est volontairement utilisé (vs un appel asynchrone) car cet
|
|
5
|
+
* appel est effectué une seule fois au démarrage d'une commande, avant
|
|
6
|
+
* tout travail en parallèle. Un échec (hors repo git, binaire absent…)
|
|
7
|
+
* est tolérant : on retourne une liste vide plutôt que de faire crasher
|
|
8
|
+
* le CLI, ce qui laisse le comportement « aucun conflit détecté » prendre
|
|
9
|
+
* le relais.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Retourne la liste des fichiers en conflit dans le dépôt Git courant.
|
|
13
|
+
*
|
|
14
|
+
* S'appuie sur `git diff --name-only --diff-filter=U` (U = unmerged).
|
|
15
|
+
* Retourne un tableau vide si Git est indisponible, si on n'est pas dans
|
|
16
|
+
* un dépôt, ou si la commande échoue pour toute autre raison.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getConflictedFiles(): string[];
|
|
19
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;;GAMG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAY7C"}
|
package/dist/git.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intégration Git — découverte des fichiers en conflit.
|
|
3
|
+
*
|
|
4
|
+
* `execSync` est volontairement utilisé (vs un appel asynchrone) car cet
|
|
5
|
+
* appel est effectué une seule fois au démarrage d'une commande, avant
|
|
6
|
+
* tout travail en parallèle. Un échec (hors repo git, binaire absent…)
|
|
7
|
+
* est tolérant : on retourne une liste vide plutôt que de faire crasher
|
|
8
|
+
* le CLI, ce qui laisse le comportement « aucun conflit détecté » prendre
|
|
9
|
+
* le relais.
|
|
10
|
+
*/
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
/**
|
|
13
|
+
* Retourne la liste des fichiers en conflit dans le dépôt Git courant.
|
|
14
|
+
*
|
|
15
|
+
* S'appuie sur `git diff --name-only --diff-filter=U` (U = unmerged).
|
|
16
|
+
* Retourne un tableau vide si Git est indisponible, si on n'est pas dans
|
|
17
|
+
* un dépôt, ou si la commande échoue pour toute autre raison.
|
|
18
|
+
*/
|
|
19
|
+
export function getConflictedFiles() {
|
|
20
|
+
try {
|
|
21
|
+
const output = execSync("git diff --name-only --diff-filter=U", {
|
|
22
|
+
encoding: "utf-8",
|
|
23
|
+
});
|
|
24
|
+
return output
|
|
25
|
+
.trim()
|
|
26
|
+
.split("\n")
|
|
27
|
+
.filter((f) => f.length > 0);
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=git.js.map
|
package/dist/git.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,sCAAsC,EAAE;YAC9D,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,OAAO,MAAM;aACV,IAAI,EAAE;aACN,KAAK,CAAC,IAAI,CAAC;aACX,MAAM,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GitWand CLI — point d'entrée binaire.
|
|
4
|
+
*
|
|
5
|
+
* Le shebang + ce fichier sont ce que `package.json.bin.gitwand` pointe
|
|
6
|
+
* (`dist/index.js`). Toute la logique est déléguée à `cli.ts` (parser
|
|
7
|
+
* + dispatcher) et aux sous-modules (`commands/*`, `ui`, `git`, …).
|
|
8
|
+
*
|
|
9
|
+
* Ce wrapper a une seule responsabilité : rattraper les erreurs qui
|
|
10
|
+
* auraient échappé aux commandes et garantir un `exit(2)` propre, afin
|
|
11
|
+
* qu'un job CI distingue les cas normaux (0 = tout résolu, 1 = conflits
|
|
12
|
+
* restants) du cas crash interne du CLI.
|
|
13
|
+
*
|
|
14
|
+
* Usage :
|
|
15
|
+
* gitwand resolve [files...] Auto-resolve trivial conflicts
|
|
16
|
+
* gitwand status Show conflict status for the repo
|
|
17
|
+
* gitwand --help Show help
|
|
18
|
+
*
|
|
19
|
+
* CI mode :
|
|
20
|
+
* gitwand resolve --ci JSON output + exit code 1 if conflicts remain
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* npx gitwand resolve
|
|
24
|
+
* npx gitwand resolve src/app.ts src/config.ts
|
|
25
|
+
* npx gitwand resolve --ci --dry-run
|
|
26
|
+
*/
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* GitWand CLI — point d'entrée binaire.
|
|
4
|
+
*
|
|
5
|
+
* Le shebang + ce fichier sont ce que `package.json.bin.gitwand` pointe
|
|
6
|
+
* (`dist/index.js`). Toute la logique est déléguée à `cli.ts` (parser
|
|
7
|
+
* + dispatcher) et aux sous-modules (`commands/*`, `ui`, `git`, …).
|
|
8
|
+
*
|
|
9
|
+
* Ce wrapper a une seule responsabilité : rattraper les erreurs qui
|
|
10
|
+
* auraient échappé aux commandes et garantir un `exit(2)` propre, afin
|
|
11
|
+
* qu'un job CI distingue les cas normaux (0 = tout résolu, 1 = conflits
|
|
12
|
+
* restants) du cas crash interne du CLI.
|
|
13
|
+
*
|
|
14
|
+
* Usage :
|
|
15
|
+
* gitwand resolve [files...] Auto-resolve trivial conflicts
|
|
16
|
+
* gitwand status Show conflict status for the repo
|
|
17
|
+
* gitwand --help Show help
|
|
18
|
+
*
|
|
19
|
+
* CI mode :
|
|
20
|
+
* gitwand resolve --ci JSON output + exit code 1 if conflicts remain
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* npx gitwand resolve
|
|
24
|
+
* npx gitwand resolve src/app.ts src/config.ts
|
|
25
|
+
* npx gitwand resolve --ci --dry-run
|
|
26
|
+
*/
|
|
27
|
+
import { main } from "./cli.js";
|
|
28
|
+
import { c } from "./ui.js";
|
|
29
|
+
main().catch((err) => {
|
|
30
|
+
console.error(`${c.red}Fatal: ${err instanceof Error ? err.message : String(err)}${c.reset}`);
|
|
31
|
+
process.exit(2);
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,CAAC,EAAE,MAAM,SAAS,CAAC;AAE5B,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconstruction d'un fichier partiellement résolu.
|
|
3
|
+
*
|
|
4
|
+
* Lorsque tous les hunks d'un fichier sont résolus, `@gitwand/core`
|
|
5
|
+
* retourne `mergedContent` directement. Mais si certains hunks restent
|
|
6
|
+
* non résolus, `mergedContent` est `null` — on doit alors reconstruire
|
|
7
|
+
* le fichier à la main : remplacer les blocs résolus par leurs lignes
|
|
8
|
+
* finales, et laisser intacts les blocs non résolus (avec leurs
|
|
9
|
+
* marqueurs `<<<<<<<`, `=======`, `>>>>>>>`).
|
|
10
|
+
*
|
|
11
|
+
* Cette fonction est volontairement simple (un scan linéaire du fichier)
|
|
12
|
+
* et s'appuie sur l'ordre des `resolutions` : il doit correspondre à
|
|
13
|
+
* l'ordre d'apparition des conflits dans le fichier — invariant garanti
|
|
14
|
+
* par `@gitwand/core`.
|
|
15
|
+
*/
|
|
16
|
+
import type { MergeResult } from "@gitwand/core";
|
|
17
|
+
/**
|
|
18
|
+
* Construit le contenu d'un fichier dans lequel seules les résolutions
|
|
19
|
+
* réussies ont été appliquées. Les blocs non résolus sont laissés tels
|
|
20
|
+
* quels (marqueurs de conflit inclus), pour que l'utilisateur puisse
|
|
21
|
+
* terminer le merge manuellement.
|
|
22
|
+
*/
|
|
23
|
+
export declare function buildPartialContent(content: string, resolutions: MergeResult["resolutions"]): string;
|
|
24
|
+
//# sourceMappingURL=partial-content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partial-content.d.ts","sourceRoot":"","sources":["../src/partial-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,GACtC,MAAM,CAgCR"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconstruction d'un fichier partiellement résolu.
|
|
3
|
+
*
|
|
4
|
+
* Lorsque tous les hunks d'un fichier sont résolus, `@gitwand/core`
|
|
5
|
+
* retourne `mergedContent` directement. Mais si certains hunks restent
|
|
6
|
+
* non résolus, `mergedContent` est `null` — on doit alors reconstruire
|
|
7
|
+
* le fichier à la main : remplacer les blocs résolus par leurs lignes
|
|
8
|
+
* finales, et laisser intacts les blocs non résolus (avec leurs
|
|
9
|
+
* marqueurs `<<<<<<<`, `=======`, `>>>>>>>`).
|
|
10
|
+
*
|
|
11
|
+
* Cette fonction est volontairement simple (un scan linéaire du fichier)
|
|
12
|
+
* et s'appuie sur l'ordre des `resolutions` : il doit correspondre à
|
|
13
|
+
* l'ordre d'apparition des conflits dans le fichier — invariant garanti
|
|
14
|
+
* par `@gitwand/core`.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Construit le contenu d'un fichier dans lequel seules les résolutions
|
|
18
|
+
* réussies ont été appliquées. Les blocs non résolus sont laissés tels
|
|
19
|
+
* quels (marqueurs de conflit inclus), pour que l'utilisateur puisse
|
|
20
|
+
* terminer le merge manuellement.
|
|
21
|
+
*/
|
|
22
|
+
export function buildPartialContent(content, resolutions) {
|
|
23
|
+
const lines = content.split("\n");
|
|
24
|
+
const result = [];
|
|
25
|
+
let conflictIdx = 0;
|
|
26
|
+
let inConflict = false;
|
|
27
|
+
let conflictBuffer = [];
|
|
28
|
+
for (const line of lines) {
|
|
29
|
+
if (line.startsWith("<<<<<<<")) {
|
|
30
|
+
inConflict = true;
|
|
31
|
+
conflictBuffer = [line];
|
|
32
|
+
}
|
|
33
|
+
else if (line.startsWith(">>>>>>>") && inConflict) {
|
|
34
|
+
conflictBuffer.push(line);
|
|
35
|
+
const resolution = resolutions[conflictIdx];
|
|
36
|
+
if (resolution?.autoResolved && resolution.resolvedLines) {
|
|
37
|
+
// Replace this conflict with the auto-resolved content
|
|
38
|
+
result.push(...resolution.resolvedLines);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
// Keep unresolved conflict markers intact
|
|
42
|
+
result.push(...conflictBuffer);
|
|
43
|
+
}
|
|
44
|
+
conflictIdx++;
|
|
45
|
+
inConflict = false;
|
|
46
|
+
conflictBuffer = [];
|
|
47
|
+
}
|
|
48
|
+
else if (inConflict) {
|
|
49
|
+
conflictBuffer.push(line);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
result.push(line);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result.join("\n");
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=partial-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partial-content.js","sourceRoot":"","sources":["../src/partial-content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,OAAe,EACf,WAAuC;IAEvC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,cAAc,GAAa,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC/B,UAAU,GAAG,IAAI,CAAC;YAClB,cAAc,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,UAAU,EAAE,CAAC;YACpD,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1B,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YAC5C,IAAI,UAAU,EAAE,YAAY,IAAI,UAAU,CAAC,aAAa,EAAE,CAAC;gBACzD,uDAAuD;gBACvD,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;YAC3C,CAAC;iBAAM,CAAC;gBACN,0CAA0C;gBAC1C,MAAM,CAAC,IAAI,CAAC,GAAG,cAAc,CAAC,CAAC;YACjC,CAAC;YACD,WAAW,EAAE,CAAC;YACd,UAAU,GAAG,KAAK,CAAC;YACnB,cAAc,GAAG,EAAE,CAAC;QACtB,CAAC;aAAM,IAAI,UAAU,EAAE,CAAC;YACtB,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rapport JSON pour le mode CI.
|
|
3
|
+
*
|
|
4
|
+
* Ce module expose le type `CIReport` (contrat public du `--ci` / `--json`)
|
|
5
|
+
* et la fonction `buildCIReport` qui projette un tableau de `MergeResult`
|
|
6
|
+
* en cette structure stable.
|
|
7
|
+
*
|
|
8
|
+
* La forme du JSON est considérée comme un contrat avec les CI existantes
|
|
9
|
+
* des utilisateurs — toute évolution doit être versionnée via le champ
|
|
10
|
+
* `version`.
|
|
11
|
+
*/
|
|
12
|
+
import type { MergeResult } from "@gitwand/core";
|
|
13
|
+
/** Forme stable du rapport JSON émis par `gitwand resolve --ci`. */
|
|
14
|
+
export interface CIReport {
|
|
15
|
+
version: string;
|
|
16
|
+
timestamp: string;
|
|
17
|
+
summary: {
|
|
18
|
+
files: number;
|
|
19
|
+
totalConflicts: number;
|
|
20
|
+
autoResolved: number;
|
|
21
|
+
remaining: number;
|
|
22
|
+
allResolved: boolean;
|
|
23
|
+
};
|
|
24
|
+
files: Array<{
|
|
25
|
+
path: string;
|
|
26
|
+
totalConflicts: number;
|
|
27
|
+
autoResolved: number;
|
|
28
|
+
remaining: number;
|
|
29
|
+
validation: {
|
|
30
|
+
isValid: boolean;
|
|
31
|
+
hasResidualMarkers: boolean;
|
|
32
|
+
syntaxError: string | null;
|
|
33
|
+
};
|
|
34
|
+
resolutions: Array<{
|
|
35
|
+
line: number;
|
|
36
|
+
type: string;
|
|
37
|
+
resolved: boolean;
|
|
38
|
+
explanation: string;
|
|
39
|
+
confidence: {
|
|
40
|
+
overall: number;
|
|
41
|
+
typeClassification: number;
|
|
42
|
+
dataRisk: number;
|
|
43
|
+
scopeImpact: number;
|
|
44
|
+
};
|
|
45
|
+
trace: {
|
|
46
|
+
selected: string;
|
|
47
|
+
hasBase: boolean;
|
|
48
|
+
summary: string;
|
|
49
|
+
steps: Array<{
|
|
50
|
+
type: string;
|
|
51
|
+
passed: boolean;
|
|
52
|
+
reason: string;
|
|
53
|
+
}>;
|
|
54
|
+
};
|
|
55
|
+
}>;
|
|
56
|
+
pendingHunks: Array<{
|
|
57
|
+
line: number;
|
|
58
|
+
type: string;
|
|
59
|
+
explanation: string;
|
|
60
|
+
ours: string;
|
|
61
|
+
theirs: string;
|
|
62
|
+
base: string;
|
|
63
|
+
confidence: {
|
|
64
|
+
overall: number;
|
|
65
|
+
typeClassification: number;
|
|
66
|
+
dataRisk: number;
|
|
67
|
+
scopeImpact: number;
|
|
68
|
+
};
|
|
69
|
+
trace: {
|
|
70
|
+
selected: string;
|
|
71
|
+
hasBase: boolean;
|
|
72
|
+
summary: string;
|
|
73
|
+
steps: Array<{
|
|
74
|
+
type: string;
|
|
75
|
+
passed: boolean;
|
|
76
|
+
reason: string;
|
|
77
|
+
}>;
|
|
78
|
+
};
|
|
79
|
+
}>;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Projette une liste de résultats de merge en un `CIReport`.
|
|
84
|
+
*
|
|
85
|
+
* @param results — paires `{ file, result }` dans l'ordre d'affichage.
|
|
86
|
+
* Les fichiers non trouvés doivent être exclus en amont.
|
|
87
|
+
*/
|
|
88
|
+
export declare function buildCIReport(results: Array<{
|
|
89
|
+
file: string;
|
|
90
|
+
result: MergeResult;
|
|
91
|
+
}>): CIReport;
|
|
92
|
+
//# sourceMappingURL=reporting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporting.d.ts","sourceRoot":"","sources":["../src/reporting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,oEAAoE;AACpE,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,KAAK,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,UAAU,EAAE;YACV,OAAO,EAAE,OAAO,CAAC;YACjB,kBAAkB,EAAE,OAAO,CAAC;YAC5B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;SAC5B,CAAC;QACF,WAAW,EAAE,KAAK,CAAC;YACjB,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,QAAQ,EAAE,OAAO,CAAC;YAClB,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE;gBACV,OAAO,EAAE,MAAM,CAAC;gBAChB,kBAAkB,EAAE,MAAM,CAAC;gBAC3B,QAAQ,EAAE,MAAM,CAAC;gBACjB,WAAW,EAAE,MAAM,CAAC;aACrB,CAAC;YACF,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM,CAAC;gBACjB,OAAO,EAAE,OAAO,CAAC;gBACjB,OAAO,EAAE,MAAM,CAAC;gBAChB,KAAK,EAAE,KAAK,CAAC;oBACX,IAAI,EAAE,MAAM,CAAC;oBACb,MAAM,EAAE,OAAO,CAAC;oBAChB,MAAM,EAAE,MAAM,CAAC;iBAChB,CAAC,CAAC;aACJ,CAAC;SACH,CAAC,CAAC;QACH,YAAY,EAAE,KAAK,CAAC;YAClB,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;YACb,WAAW,EAAE,MAAM,CAAC;YACpB,IAAI,EAAE,MAAM,CAAC;YACb,MAAM,EAAE,MAAM,CAAC;YACf,IAAI,EAAE,MAAM,CAAC;YACb,UAAU,EAAE;gBACV,OAAO,EAAE,MAAM,CAAC;gBAChB,kBAAkB,EAAE,MAAM,CAAC;gBAC3B,QAAQ,EAAE,MAAM,CAAC;gBACjB,WAAW,EAAE,MAAM,CAAC;aACrB,CAAC;YACF,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM,CAAC;gBACjB,OAAO,EAAE,OAAO,CAAC;gBACjB,OAAO,EAAE,MAAM,CAAC;gBAChB,KAAK,EAAE,KAAK,CAAC;oBACX,IAAI,EAAE,MAAM,CAAC;oBACb,MAAM,EAAE,OAAO,CAAC;oBAChB,MAAM,EAAE,MAAM,CAAC;iBAChB,CAAC,CAAC;aACJ,CAAC;SACH,CAAC,CAAC;KACJ,CAAC,CAAC;CACJ;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,GACpD,QAAQ,CAiFV"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rapport JSON pour le mode CI.
|
|
3
|
+
*
|
|
4
|
+
* Ce module expose le type `CIReport` (contrat public du `--ci` / `--json`)
|
|
5
|
+
* et la fonction `buildCIReport` qui projette un tableau de `MergeResult`
|
|
6
|
+
* en cette structure stable.
|
|
7
|
+
*
|
|
8
|
+
* La forme du JSON est considérée comme un contrat avec les CI existantes
|
|
9
|
+
* des utilisateurs — toute évolution doit être versionnée via le champ
|
|
10
|
+
* `version`.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Projette une liste de résultats de merge en un `CIReport`.
|
|
14
|
+
*
|
|
15
|
+
* @param results — paires `{ file, result }` dans l'ordre d'affichage.
|
|
16
|
+
* Les fichiers non trouvés doivent être exclus en amont.
|
|
17
|
+
*/
|
|
18
|
+
export function buildCIReport(results) {
|
|
19
|
+
let totalConflicts = 0;
|
|
20
|
+
let totalResolved = 0;
|
|
21
|
+
const files = results.map(({ file, result }) => {
|
|
22
|
+
totalConflicts += result.stats.totalConflicts;
|
|
23
|
+
totalResolved += result.stats.autoResolved;
|
|
24
|
+
return {
|
|
25
|
+
path: file,
|
|
26
|
+
totalConflicts: result.stats.totalConflicts,
|
|
27
|
+
autoResolved: result.stats.autoResolved,
|
|
28
|
+
remaining: result.stats.remaining,
|
|
29
|
+
validation: {
|
|
30
|
+
isValid: result.validation.isValid,
|
|
31
|
+
hasResidualMarkers: result.validation.hasResidualMarkers,
|
|
32
|
+
syntaxError: result.validation.syntaxError,
|
|
33
|
+
},
|
|
34
|
+
resolutions: result.resolutions.map((r) => ({
|
|
35
|
+
line: r.hunk.startLine,
|
|
36
|
+
type: r.hunk.type,
|
|
37
|
+
resolved: r.autoResolved,
|
|
38
|
+
explanation: r.hunk.explanation,
|
|
39
|
+
confidence: {
|
|
40
|
+
overall: r.hunk.confidence.score,
|
|
41
|
+
typeClassification: r.hunk.confidence.dimensions.typeClassification,
|
|
42
|
+
dataRisk: r.hunk.confidence.dimensions.dataRisk,
|
|
43
|
+
scopeImpact: r.hunk.confidence.dimensions.scopeImpact,
|
|
44
|
+
},
|
|
45
|
+
trace: {
|
|
46
|
+
selected: r.hunk.trace.selected,
|
|
47
|
+
hasBase: r.hunk.trace.hasBase,
|
|
48
|
+
summary: r.hunk.trace.summary,
|
|
49
|
+
steps: r.hunk.trace.steps.map((s) => ({
|
|
50
|
+
type: s.type,
|
|
51
|
+
passed: s.passed,
|
|
52
|
+
reason: s.reason,
|
|
53
|
+
})),
|
|
54
|
+
},
|
|
55
|
+
})),
|
|
56
|
+
pendingHunks: result.resolutions
|
|
57
|
+
.filter((r) => !r.autoResolved)
|
|
58
|
+
.map((r) => ({
|
|
59
|
+
line: r.hunk.startLine,
|
|
60
|
+
type: r.hunk.type,
|
|
61
|
+
explanation: r.hunk.explanation,
|
|
62
|
+
ours: r.hunk.oursLines.join("\n"),
|
|
63
|
+
theirs: r.hunk.theirsLines.join("\n"),
|
|
64
|
+
base: r.hunk.baseLines.join("\n"),
|
|
65
|
+
confidence: {
|
|
66
|
+
overall: r.hunk.confidence.score,
|
|
67
|
+
typeClassification: r.hunk.confidence.dimensions.typeClassification,
|
|
68
|
+
dataRisk: r.hunk.confidence.dimensions.dataRisk,
|
|
69
|
+
scopeImpact: r.hunk.confidence.dimensions.scopeImpact,
|
|
70
|
+
},
|
|
71
|
+
trace: {
|
|
72
|
+
selected: r.hunk.trace.selected,
|
|
73
|
+
hasBase: r.hunk.trace.hasBase,
|
|
74
|
+
summary: r.hunk.trace.summary,
|
|
75
|
+
steps: r.hunk.trace.steps.map((s) => ({
|
|
76
|
+
type: s.type,
|
|
77
|
+
passed: s.passed,
|
|
78
|
+
reason: s.reason,
|
|
79
|
+
})),
|
|
80
|
+
},
|
|
81
|
+
})),
|
|
82
|
+
};
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
version: "0.0.1",
|
|
86
|
+
timestamp: new Date().toISOString(),
|
|
87
|
+
summary: {
|
|
88
|
+
files: results.length,
|
|
89
|
+
totalConflicts,
|
|
90
|
+
autoResolved: totalResolved,
|
|
91
|
+
remaining: totalConflicts - totalResolved,
|
|
92
|
+
allResolved: totalConflicts - totalResolved === 0,
|
|
93
|
+
},
|
|
94
|
+
files,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=reporting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporting.js","sourceRoot":"","sources":["../src/reporting.ts"],"names":[],"mappings":"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"}
|
package/dist/ui.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sortie console — couleurs ANSI, bannière, détection CI/no-color.
|
|
3
|
+
*
|
|
4
|
+
* Isolé du reste du CLI pour que `printHelp` (dans `cli.ts`) et les
|
|
5
|
+
* commandes (`commands/*.ts`) partagent une même palette et un même
|
|
6
|
+
* comportement d'absence de couleur (CI + NO_COLOR).
|
|
7
|
+
*/
|
|
8
|
+
/** Vrai si on tourne sous un runner CI (variable `CI` à 1/true). */
|
|
9
|
+
export declare const isCI: boolean;
|
|
10
|
+
/** Vrai si on doit désactiver les couleurs (CI ou `NO_COLOR` défini). */
|
|
11
|
+
export declare const noColor: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Palette ANSI. Lorsque `noColor` est actif, chaque clé vaut `""`, ce qui
|
|
14
|
+
* permet d'utiliser les templates `${c.green}…${c.reset}` sans branchement
|
|
15
|
+
* à chaque appel.
|
|
16
|
+
*/
|
|
17
|
+
export declare const c: {
|
|
18
|
+
reset: string;
|
|
19
|
+
bold: string;
|
|
20
|
+
dim: string;
|
|
21
|
+
green: string;
|
|
22
|
+
yellow: string;
|
|
23
|
+
red: string;
|
|
24
|
+
cyan: string;
|
|
25
|
+
magenta: string;
|
|
26
|
+
};
|
|
27
|
+
/** Étincelle utilisée comme logo — remplacée par `*` en mode no-color. */
|
|
28
|
+
export declare const WAND: string;
|
|
29
|
+
export declare function printBanner(): void;
|
|
30
|
+
//# sourceMappingURL=ui.d.ts.map
|
package/dist/ui.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oEAAoE;AACpE,eAAO,MAAM,IAAI,SAAsD,CAAC;AACxE,yEAAyE;AACzE,eAAO,MAAM,OAAO,SAA6C,CAAC;AAElE;;;;GAIG;AACH,eAAO,MAAM,CAAC;;;;;;;;;CAWT,CAAC;AAEN,0EAA0E;AAC1E,eAAO,MAAM,IAAI,QAA2B,CAAC;AAE7C,wBAAgB,WAAW,IAAI,IAAI,CAIlC"}
|
package/dist/ui.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sortie console — couleurs ANSI, bannière, détection CI/no-color.
|
|
3
|
+
*
|
|
4
|
+
* Isolé du reste du CLI pour que `printHelp` (dans `cli.ts`) et les
|
|
5
|
+
* commandes (`commands/*.ts`) partagent une même palette et un même
|
|
6
|
+
* comportement d'absence de couleur (CI + NO_COLOR).
|
|
7
|
+
*/
|
|
8
|
+
/** Vrai si on tourne sous un runner CI (variable `CI` à 1/true). */
|
|
9
|
+
export const isCI = process.env.CI === "true" || process.env.CI === "1";
|
|
10
|
+
/** Vrai si on doit désactiver les couleurs (CI ou `NO_COLOR` défini). */
|
|
11
|
+
export const noColor = isCI || process.env.NO_COLOR !== undefined;
|
|
12
|
+
/**
|
|
13
|
+
* Palette ANSI. Lorsque `noColor` est actif, chaque clé vaut `""`, ce qui
|
|
14
|
+
* permet d'utiliser les templates `${c.green}…${c.reset}` sans branchement
|
|
15
|
+
* à chaque appel.
|
|
16
|
+
*/
|
|
17
|
+
export const c = noColor
|
|
18
|
+
? { reset: "", bold: "", dim: "", green: "", yellow: "", red: "", cyan: "", magenta: "" }
|
|
19
|
+
: {
|
|
20
|
+
reset: "\x1b[0m",
|
|
21
|
+
bold: "\x1b[1m",
|
|
22
|
+
dim: "\x1b[2m",
|
|
23
|
+
green: "\x1b[32m",
|
|
24
|
+
yellow: "\x1b[33m",
|
|
25
|
+
red: "\x1b[31m",
|
|
26
|
+
cyan: "\x1b[36m",
|
|
27
|
+
magenta: "\x1b[35m",
|
|
28
|
+
};
|
|
29
|
+
/** Étincelle utilisée comme logo — remplacée par `*` en mode no-color. */
|
|
30
|
+
export const WAND = noColor ? "*" : "\u2728";
|
|
31
|
+
export function printBanner() {
|
|
32
|
+
console.log(`\n${c.magenta}${c.bold} ${WAND} GitWand${c.reset} ${c.dim}— Git's magic wand${c.reset}\n`);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=ui.js.map
|
package/dist/ui.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui.js","sourceRoot":"","sources":["../src/ui.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,oEAAoE;AACpE,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC;AACxE,yEAAyE;AACzE,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC;AAElE;;;;GAIG;AACH,MAAM,CAAC,MAAM,CAAC,GAAG,OAAO;IACtB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;IACzF,CAAC,CAAC;QACE,KAAK,EAAE,SAAS;QAChB,IAAI,EAAE,SAAS;QACf,GAAG,EAAE,SAAS;QACd,KAAK,EAAE,UAAU;QACjB,MAAM,EAAE,UAAU;QAClB,GAAG,EAAE,UAAU;QACf,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,UAAU;KACpB,CAAC;AAEN,0EAA0E;AAC1E,MAAM,CAAC,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AAE7C,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,WAAW,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,qBAAqB,CAAC,CAAC,KAAK,IAAI,CAC5F,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gitwand/cli",
|
|
3
|
+
"version": "1.6.0",
|
|
4
|
+
"description": "GitWand CLI — resolve Git conflicts from your terminal or CI pipeline",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"gitwand": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"keywords": [
|
|
15
|
+
"git",
|
|
16
|
+
"merge",
|
|
17
|
+
"conflict",
|
|
18
|
+
"conflict-resolution",
|
|
19
|
+
"cli",
|
|
20
|
+
"ci",
|
|
21
|
+
"devtools",
|
|
22
|
+
"gitwand"
|
|
23
|
+
],
|
|
24
|
+
"homepage": "https://github.com/devlint/GitWand#cli",
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/devlint/GitWand/issues"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/devlint/GitWand.git",
|
|
31
|
+
"directory": "packages/cli"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@gitwand/core": "1.6.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^25.5.0",
|
|
41
|
+
"typescript": "^5.4.0"
|
|
42
|
+
},
|
|
43
|
+
"author": "Laurent Guitton <lb.guitton@gmail.com>",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"clean": "rm -rf dist"
|
|
48
|
+
}
|
|
49
|
+
}
|