@udondan/avanti 0.1.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.
Files changed (67) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.prettierignore +2 -0
  3. package/LICENSE +21 -0
  4. package/README.md +169 -0
  5. package/dist/cli.d.ts +3 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +16 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/diff.d.ts +3 -0
  10. package/dist/commands/diff.d.ts.map +1 -0
  11. package/dist/commands/diff.js +76 -0
  12. package/dist/commands/diff.js.map +1 -0
  13. package/dist/commands/pull.d.ts +3 -0
  14. package/dist/commands/pull.d.ts.map +1 -0
  15. package/dist/commands/pull.js +115 -0
  16. package/dist/commands/pull.js.map +1 -0
  17. package/dist/config.d.ts +4 -0
  18. package/dist/config.d.ts.map +1 -0
  19. package/dist/config.js +181 -0
  20. package/dist/config.js.map +1 -0
  21. package/dist/diff.d.ts +13 -0
  22. package/dist/diff.d.ts.map +1 -0
  23. package/dist/diff.js +83 -0
  24. package/dist/diff.js.map +1 -0
  25. package/dist/processors/post.d.ts +2 -0
  26. package/dist/processors/post.d.ts.map +1 -0
  27. package/dist/processors/post.js +20 -0
  28. package/dist/processors/post.js.map +1 -0
  29. package/dist/processors/replace.d.ts +3 -0
  30. package/dist/processors/replace.d.ts.map +1 -0
  31. package/dist/processors/replace.js +25 -0
  32. package/dist/processors/replace.js.map +1 -0
  33. package/dist/sources/exec.d.ts +2 -0
  34. package/dist/sources/exec.d.ts.map +1 -0
  35. package/dist/sources/exec.js +17 -0
  36. package/dist/sources/exec.js.map +1 -0
  37. package/dist/sources/github.d.ts +5 -0
  38. package/dist/sources/github.d.ts.map +1 -0
  39. package/dist/sources/github.js +90 -0
  40. package/dist/sources/github.js.map +1 -0
  41. package/dist/sources/gitlab.d.ts +6 -0
  42. package/dist/sources/gitlab.d.ts.map +1 -0
  43. package/dist/sources/gitlab.js +105 -0
  44. package/dist/sources/gitlab.js.map +1 -0
  45. package/dist/sources/http.d.ts +3 -0
  46. package/dist/sources/http.d.ts.map +1 -0
  47. package/dist/sources/http.js +66 -0
  48. package/dist/sources/http.js.map +1 -0
  49. package/dist/sources/index.d.ts +6 -0
  50. package/dist/sources/index.d.ts.map +1 -0
  51. package/dist/sources/index.js +105 -0
  52. package/dist/sources/index.js.map +1 -0
  53. package/dist/sources/local.d.ts +5 -0
  54. package/dist/sources/local.d.ts.map +1 -0
  55. package/dist/sources/local.js +64 -0
  56. package/dist/sources/local.js.map +1 -0
  57. package/dist/types.d.ts +34 -0
  58. package/dist/types.d.ts.map +1 -0
  59. package/dist/types.js +3 -0
  60. package/dist/types.js.map +1 -0
  61. package/dist/writer.d.ts +7 -0
  62. package/dist/writer.d.ts.map +1 -0
  63. package/dist/writer.js +57 -0
  64. package/dist/writer.js.map +1 -0
  65. package/eslint.config.mjs +25 -0
  66. package/package.json +45 -0
  67. package/prettier.config.mjs +5 -0
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(bun run *)",
5
+ "Bash(git fetch *)",
6
+ "Bash(git rebase *)"
7
+ ]
8
+ }
9
+ }
@@ -0,0 +1,2 @@
1
+ dist/
2
+ CHANGELOG.md
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Daniel Schroeder
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,169 @@
1
+ # avanti
2
+
3
+ Assemble local files from any source via a declarative YAML spec.
4
+
5
+ ## Features
6
+
7
+ - Fetch files from **HTTP/HTTPS**, **local paths**, **GitLab** (via `glab`), **GitHub** (via `gh`), or **shell commands**
8
+ - **Multi-source entries** — combine multiple sources into a single file by providing `src` as a list
9
+ - **Atomic writes** — all files are staged to a temp dir first; targets are only written if everything succeeds
10
+ - **Diff preview** — see exactly what will change before applying
11
+ - **Post-processing** — apply text replacements (string or regex) and/or pipe content through a shell script
12
+ - **Directory sync** — recursively sync directories from GitLab/GitHub/local sources
13
+
14
+ ## Requirements
15
+
16
+ - Node.js 18+
17
+ - `glab` CLI (for GitLab sources) — [install](https://gitlab.com/gitlab-org/cli)
18
+ - `gh` CLI (for GitHub sources) — [install](https://cli.github.com)
19
+
20
+ ## Install
21
+
22
+ ```sh
23
+ npm install -g @udondan/avanti
24
+ ```
25
+
26
+ Or run directly:
27
+
28
+ ```sh
29
+ npx @udondan/avanti --help
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ```
35
+ avanti [options] [command]
36
+
37
+ Options:
38
+ -c, --config <path> path to config file (default: auto-detected)
39
+
40
+ Commands:
41
+ diff Show diff between remote sources and local files
42
+ pull [--yes] Pull remote sources and write to local files
43
+ ```
44
+
45
+ ### `avanti diff`
46
+
47
+ Shows a colored git-diff-like output of what would change. Exits `0` if no changes, `1` if changes detected.
48
+
49
+ ### `avanti pull`
50
+
51
+ Fetches all sources, shows the diff, and prompts for confirmation before writing. Use `--yes` to skip the prompt.
52
+
53
+ ## Configuration
54
+
55
+ Create one of the following files in your project root (searched in this order, case-insensitive):
56
+
57
+ - `.avanti.yml`
58
+ - `.avanti.yaml`
59
+ - `avanti.yml`
60
+ - `avanti.yaml`
61
+
62
+ Example:
63
+
64
+ ```yaml
65
+ files:
66
+ - src: http://www.example.com/example.yml
67
+ target: my-example.yml
68
+ replace:
69
+ - from: '{EMAIL}'
70
+ to: you@example.com
71
+ - from: /\d+/
72
+ to: number
73
+
74
+ - src: ~/some/local/file.sh
75
+ target: file.sh
76
+ mode: '0777'
77
+
78
+ - src:
79
+ exec: glab api "projects/group%2Fproject/repository/files/some-file.yaml/raw?ref=main"
80
+ target: some-file.yml
81
+ post: sed -e 's/v3/v4/g'
82
+
83
+ - src:
84
+ gitlab:
85
+ project: group/project
86
+ file: renovate.json
87
+ ref: $latest
88
+ # target omitted → renovate.json
89
+
90
+ - src:
91
+ github:
92
+ repo: org/repo
93
+ file: scripts/
94
+ ref: main
95
+ target: local-scripts/
96
+ ```
97
+
98
+ ### File Entry Fields
99
+
100
+ | Field | Required | Description |
101
+ | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------- |
102
+ | `src` | Yes | Source (see below). May be a single source or a **list** of sources to concatenate. |
103
+ | `target` | Conditional | Local path to write to. Required for `exec:` sources and when `src` is a list. May be omitted when filename is inferable. |
104
+ | `ref` | No | Branch, tag, or `$latest` (resolves to latest tag). GitLab/GitHub only. |
105
+ | `mode` | No | File permission mode, e.g. `"0755"` |
106
+ | `replace` | No | List of `{from, to}` replacement rules. `from` may be a plain string or `/pattern/flags` regex. |
107
+ | `post` | No | Shell script. Content is piped via stdin; stdout is used as the result. Runs after `replace`. |
108
+
109
+ ### Source Types
110
+
111
+ **Plain string** — HTTP/HTTPS URL or local path:
112
+
113
+ ```yaml
114
+ src: https://example.com/file.txt
115
+ src: ~/templates/file.txt
116
+ src: /absolute/path/file.txt
117
+ ```
118
+
119
+ **Map** — for exec, gitlab, github:
120
+
121
+ ```yaml
122
+ src:
123
+ exec: <shell command> # stdout becomes file content; target required
124
+
125
+ src:
126
+ gitlab:
127
+ project: group/repo # GitLab project path
128
+ file: path/to/file.txt # file or directory in repo
129
+ ref: main # branch, tag, or $latest (optional)
130
+
131
+ src:
132
+ github:
133
+ repo: owner/repo # GitHub owner/repo
134
+ file: path/to/file.txt # file or directory in repo
135
+ ref: main # branch or tag (optional)
136
+ ```
137
+
138
+ **List** — combine multiple sources into one file (all source types supported; `target` required):
139
+
140
+ ```yaml
141
+ src:
142
+ - https://example.com/header.txt
143
+ - exec: echo "# generated"
144
+ - gitlab:
145
+ project: org/repo
146
+ file: footer.txt
147
+ ref: main
148
+ target: combined.txt
149
+ ```
150
+
151
+ Sources are fetched in order and joined with a newline. Post-processing (`replace`, `post`) is applied to the combined result. If any source fails, the entire entry is aborted.
152
+
153
+ ## Exit Codes
154
+
155
+ | Code | Meaning |
156
+ | ---- | ------------------------------- |
157
+ | `0` | Success / no changes |
158
+ | `1` | Changes detected (diff command) |
159
+ | `2` | Error |
160
+
161
+ ## Development
162
+
163
+ ```sh
164
+ git clone ...
165
+ npm install
166
+ npm run dev -- --help # run via tsx
167
+ npm test # run tests
168
+ npm run build # compile to dist/
169
+ ```
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const diff_1 = require("./commands/diff");
6
+ const pull_1 = require("./commands/pull");
7
+ const program = new commander_1.Command();
8
+ program
9
+ .name('avanti')
10
+ .description('Assemble local files from any source via a declarative YAML spec')
11
+ .version('0.1.0')
12
+ .option('-c, --config <path>', 'path to config file');
13
+ program.addCommand((0, diff_1.diffCommand)());
14
+ program.addCommand((0, pull_1.pullCommand)());
15
+ program.parse(process.argv);
16
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;AACA,yCAAoC;AACpC,0CAA8C;AAC9C,0CAA8C;AAE9C,MAAM,OAAO,GAAG,IAAI,mBAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CACV,kEAAkE,CACnE;KACA,OAAO,CAAC,OAAO,CAAC;KAChB,MAAM,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;AAExD,OAAO,CAAC,UAAU,CAAC,IAAA,kBAAW,GAAE,CAAC,CAAC;AAClC,OAAO,CAAC,UAAU,CAAC,IAAA,kBAAW,GAAE,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function diffCommand(): Command;
3
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,wBAAgB,WAAW,IAAI,OAAO,CA4CrC"}
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.diffCommand = void 0;
27
+ const commander_1 = require("commander");
28
+ const path = __importStar(require("path"));
29
+ const config_1 = require("../config");
30
+ const sources_1 = require("../sources");
31
+ const replace_1 = require("../processors/replace");
32
+ const post_1 = require("../processors/post");
33
+ const diff_1 = require("../diff");
34
+ function diffCommand() {
35
+ return new commander_1.Command('diff')
36
+ .description('Show diff between remote sources and local files')
37
+ .action(async (_options, cmd) => {
38
+ const configPath = (0, config_1.resolveConfigPath)(cmd.parent?.opts().config);
39
+ let config;
40
+ try {
41
+ config = (0, config_1.loadConfig)(configPath);
42
+ }
43
+ catch (err) {
44
+ console.error(err.message);
45
+ process.exit(2);
46
+ }
47
+ const baseDir = path.dirname(configPath);
48
+ const allDiffs = [];
49
+ let hasError = false;
50
+ for (const entry of config.files) {
51
+ try {
52
+ const result = await (0, sources_1.fetchSource)(entry);
53
+ for (const [relPath, rawContent] of result.files) {
54
+ let content = rawContent;
55
+ if (entry.replace?.length)
56
+ content = (0, replace_1.applyReplace)(content, entry.replace);
57
+ if (entry.post)
58
+ content = (0, post_1.applyPost)(content, entry.post);
59
+ const targetPath = (0, diff_1.resolveTargetPath)(entry, relPath, baseDir);
60
+ allDiffs.push((0, diff_1.computeDiff)(targetPath, content));
61
+ }
62
+ }
63
+ catch (err) {
64
+ console.error(`Error processing ${JSON.stringify(entry.src)}: ${err.message}`);
65
+ hasError = true;
66
+ }
67
+ }
68
+ (0, diff_1.printDiffs)(allDiffs);
69
+ const hasChanges = allDiffs.some((d) => d.hasChanges);
70
+ if (hasError)
71
+ process.exit(2);
72
+ process.exit(hasChanges ? 1 : 0);
73
+ });
74
+ }
75
+ exports.diffCommand = diffCommand;
76
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/commands/diff.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAAoC;AACpC,2CAA6B;AAC7B,sCAA0D;AAC1D,wCAAyC;AACzC,mDAAqD;AACrD,6CAA+C;AAC/C,kCAAqE;AAGrE,SAAgB,WAAW;IACzB,OAAO,IAAI,mBAAO,CAAC,MAAM,CAAC;SACvB,WAAW,CAAC,kDAAkD,CAAC;SAC/D,MAAM,CAAC,KAAK,EAAE,QAAiB,EAAE,GAAY,EAAE,EAAE;QAChD,MAAM,UAAU,GAAG,IAAA,0BAAiB,EAClC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,MAA4B,CAChD,CAAC;QACF,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,IAAA,mBAAU,EAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAe,EAAE,CAAC;QAChC,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAW,EAAC,KAAK,CAAC,CAAC;gBACxC,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjD,IAAI,OAAO,GAAG,UAAU,CAAC;oBACzB,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM;wBACvB,OAAO,GAAG,IAAA,sBAAY,EAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBACjD,IAAI,KAAK,CAAC,IAAI;wBAAE,OAAO,GAAG,IAAA,gBAAS,EAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBACzD,MAAM,UAAU,GAAG,IAAA,wBAAiB,EAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC9D,QAAQ,CAAC,IAAI,CAAC,IAAA,kBAAW,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;gBAClD,CAAC;YACH,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CACX,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,GAAa,CAAC,OAAO,EAAE,CAC3E,CAAC;gBACF,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAA,iBAAU,EAAC,QAAQ,CAAC,CAAC;QAErB,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACtD,IAAI,QAAQ;YAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;AACP,CAAC;AA5CD,kCA4CC"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function pullCommand(): Command;
3
+ //# sourceMappingURL=pull.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2BpC,wBAAgB,WAAW,IAAI,OAAO,CAuErC"}
@@ -0,0 +1,115 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.pullCommand = void 0;
27
+ const commander_1 = require("commander");
28
+ const path = __importStar(require("path"));
29
+ const readline = __importStar(require("readline"));
30
+ const config_1 = require("../config");
31
+ const sources_1 = require("../sources");
32
+ const replace_1 = require("../processors/replace");
33
+ const post_1 = require("../processors/post");
34
+ const diff_1 = require("../diff");
35
+ const writer_1 = require("../writer");
36
+ async function confirm(question) {
37
+ const rl = readline.createInterface({
38
+ input: process.stdin,
39
+ output: process.stdout,
40
+ });
41
+ return new Promise((resolve) => {
42
+ rl.question(question, (answer) => {
43
+ rl.close();
44
+ resolve(answer.trim().toLowerCase() === 'y' ||
45
+ answer.trim().toLowerCase() === 'yes');
46
+ });
47
+ });
48
+ }
49
+ function pullCommand() {
50
+ return new commander_1.Command('pull')
51
+ .description('Pull remote sources and write to local files')
52
+ .option('-y, --yes', 'skip confirmation prompt')
53
+ .action(async (options, cmd) => {
54
+ const configPath = (0, config_1.resolveConfigPath)(cmd.parent?.opts().config);
55
+ let config;
56
+ try {
57
+ config = (0, config_1.loadConfig)(configPath);
58
+ }
59
+ catch (err) {
60
+ console.error(err.message);
61
+ process.exit(2);
62
+ }
63
+ const baseDir = path.dirname(configPath);
64
+ const allDiffs = [];
65
+ const writeTargets = [];
66
+ let hasError = false;
67
+ for (const entry of config.files) {
68
+ try {
69
+ const result = await (0, sources_1.fetchSource)(entry);
70
+ for (const [relPath, rawContent] of result.files) {
71
+ let content = rawContent;
72
+ if (entry.replace?.length)
73
+ content = (0, replace_1.applyReplace)(content, entry.replace);
74
+ if (entry.post)
75
+ content = (0, post_1.applyPost)(content, entry.post);
76
+ const targetPath = (0, diff_1.resolveTargetPath)(entry, relPath, baseDir);
77
+ allDiffs.push((0, diff_1.computeDiff)(targetPath, content));
78
+ writeTargets.push({ targetPath, content, mode: entry.mode });
79
+ }
80
+ }
81
+ catch (err) {
82
+ console.error(`Error processing ${JSON.stringify(entry.src)}: ${err.message}`);
83
+ hasError = true;
84
+ }
85
+ }
86
+ if (hasError) {
87
+ console.error('Aborting due to errors.');
88
+ process.exit(2);
89
+ }
90
+ const hasChanges = allDiffs.some((d) => d.hasChanges);
91
+ (0, diff_1.printDiffs)(allDiffs);
92
+ if (!hasChanges) {
93
+ console.log('Nothing to do.');
94
+ process.exit(0);
95
+ }
96
+ const yes = options.yes ?? false;
97
+ if (!yes) {
98
+ const ok = await confirm('Apply changes? [y/N] ');
99
+ if (!ok) {
100
+ console.log('Aborted.');
101
+ process.exit(0);
102
+ }
103
+ }
104
+ try {
105
+ (0, writer_1.atomicWrite)(writeTargets);
106
+ console.log(`Wrote ${writeTargets.length} file(s).`);
107
+ }
108
+ catch (err) {
109
+ console.error(`Write failed: ${err.message}`);
110
+ process.exit(2);
111
+ }
112
+ });
113
+ }
114
+ exports.pullCommand = pullCommand;
115
+ //# sourceMappingURL=pull.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../src/commands/pull.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,yCAAoC;AACpC,2CAA6B;AAC7B,mDAAqC;AACrC,sCAA0D;AAC1D,wCAAyC;AACzC,mDAAqD;AACrD,6CAA+C;AAC/C,kCAAqE;AACrE,sCAAqD;AAGrD,KAAK,UAAU,OAAO,CAAC,QAAgB;IACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;QAClC,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IACH,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE;YAC/B,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CACL,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,GAAG;gBACjC,MAAM,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CACxC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,WAAW;IACzB,OAAO,IAAI,mBAAO,CAAC,MAAM,CAAC;SACvB,WAAW,CAAC,8CAA8C,CAAC;SAC3D,MAAM,CAAC,WAAW,EAAE,0BAA0B,CAAC;SAC/C,MAAM,CAAC,KAAK,EAAE,OAAgB,EAAE,GAAY,EAAE,EAAE;QAC/C,MAAM,UAAU,GAAG,IAAA,0BAAiB,EAClC,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,MAA4B,CAChD,CAAC;QACF,IAAI,MAAM,CAAC;QACX,IAAI,CAAC;YACH,MAAM,GAAG,IAAA,mBAAU,EAAC,UAAU,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;YACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QACzC,MAAM,QAAQ,GAAe,EAAE,CAAC;QAChC,MAAM,YAAY,GAAkB,EAAE,CAAC;QACvC,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAA,qBAAW,EAAC,KAAK,CAAC,CAAC;gBACxC,KAAK,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;oBACjD,IAAI,OAAO,GAAG,UAAU,CAAC;oBACzB,IAAI,KAAK,CAAC,OAAO,EAAE,MAAM;wBACvB,OAAO,GAAG,IAAA,sBAAY,EAAC,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;oBACjD,IAAI,KAAK,CAAC,IAAI;wBAAE,OAAO,GAAG,IAAA,gBAAS,EAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;oBACzD,MAAM,UAAU,GAAG,IAAA,wBAAiB,EAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;oBAC9D,QAAQ,CAAC,IAAI,CAAC,IAAA,kBAAW,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;oBAChD,YAAY,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC/D,CAAC;YACH,CAAC;YAAC,OAAO,GAAY,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CACX,oBAAoB,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,KAAM,GAAa,CAAC,OAAO,EAAE,CAC3E,CAAC;gBACF,QAAQ,GAAG,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;YACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QACtD,IAAA,iBAAU,EAAC,QAAQ,CAAC,CAAC;QAErB,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,GAAG,GAAa,OAA6B,CAAC,GAAG,IAAI,KAAK,CAAC;QACjE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,EAAE,GAAG,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;YAClD,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBACxB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;QACH,CAAC;QAED,IAAI,CAAC;YACH,IAAA,oBAAW,EAAC,YAAY,CAAC,CAAC;YAC1B,OAAO,CAAC,GAAG,CAAC,SAAS,YAAY,CAAC,MAAM,WAAW,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,iBAAkB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC;AAvED,kCAuEC"}
@@ -0,0 +1,4 @@
1
+ import { FileFerryConfig } from "./types";
2
+ export declare function resolveConfigPath(explicit?: string): string;
3
+ export declare function loadConfig(configPath: string): FileFerryConfig;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAmC,MAAM,SAAS,CAAC;AAS3E,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAa3D;AAED,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,eAAe,CAmE9D"}
package/dist/config.js ADDED
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.loadConfig = exports.resolveConfigPath = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const yaml = __importStar(require("js-yaml"));
30
+ const CONFIG_CANDIDATES = [
31
+ ".avanti.yml",
32
+ ".avanti.yaml",
33
+ "avanti.yml",
34
+ "avanti.yaml",
35
+ ];
36
+ function resolveConfigPath(explicit) {
37
+ if (explicit)
38
+ return path.resolve(explicit);
39
+ const cwd = process.cwd();
40
+ const entries = fs.readdirSync(cwd);
41
+ const lowerEntries = entries.map((e) => e.toLowerCase());
42
+ for (const candidate of CONFIG_CANDIDATES) {
43
+ const idx = lowerEntries.indexOf(candidate);
44
+ if (idx !== -1)
45
+ return path.resolve(cwd, entries[idx]);
46
+ }
47
+ return path.resolve(cwd, CONFIG_CANDIDATES[0]);
48
+ }
49
+ exports.resolveConfigPath = resolveConfigPath;
50
+ function loadConfig(configPath) {
51
+ if (!fs.existsSync(configPath)) {
52
+ throw new Error(`Config file not found: ${configPath}`);
53
+ }
54
+ let raw;
55
+ try {
56
+ const content = fs.readFileSync(configPath, "utf8");
57
+ raw = yaml.load(content);
58
+ }
59
+ catch (err) {
60
+ const msg = err instanceof Error ? err.message : String(err);
61
+ throw new Error(`Failed to parse config file: ${msg}`, { cause: err });
62
+ }
63
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
64
+ throw new Error("Config must be a YAML object");
65
+ }
66
+ const obj = raw;
67
+ if (!Array.isArray(obj["files"])) {
68
+ throw new Error('Config must have a "files" array');
69
+ }
70
+ const files = obj["files"].map((entry, i) => {
71
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
72
+ throw new Error(`files[${i}]: must be an object`);
73
+ }
74
+ const e = entry;
75
+ if (e["src"] === undefined || e["src"] === null) {
76
+ throw new Error(`files[${i}]: "src" is required`);
77
+ }
78
+ const src = Array.isArray(e["src"])
79
+ ? e["src"].map((item, j) => parseSingleSrc(item, i, j))
80
+ : parseSingleSrc(e["src"], i, undefined);
81
+ // list src must have an explicit target
82
+ if (Array.isArray(src) && !e["target"]) {
83
+ throw new Error(`files[${i}]: "target" is required when "src" is a list`);
84
+ }
85
+ // exec sources must have a target
86
+ if (!Array.isArray(src) && isExecSrc(src) && !e["target"]) {
87
+ throw new Error(`files[${i}]: "target" is required for exec sources`);
88
+ }
89
+ const fileEntry = { src };
90
+ if (typeof e["target"] === "string")
91
+ fileEntry.target = e["target"];
92
+ if (typeof e["mode"] === "string")
93
+ fileEntry.mode = e["mode"];
94
+ if (typeof e["post"] === "string")
95
+ fileEntry.post = e["post"];
96
+ if (e["replace"] !== undefined) {
97
+ if (!Array.isArray(e["replace"])) {
98
+ throw new Error(`files[${i}]: "replace" must be an array`);
99
+ }
100
+ fileEntry.replace = e["replace"].map((r, j) => parseReplaceRule(r, i, j));
101
+ }
102
+ return fileEntry;
103
+ });
104
+ return { files };
105
+ }
106
+ exports.loadConfig = loadConfig;
107
+ function parseSingleSrc(raw, i, j) {
108
+ const loc = j !== undefined ? `files[${i}].src[${j}]` : `files[${i}].src`;
109
+ // Plain string → http/https URL or local path
110
+ if (typeof raw === "string") {
111
+ return raw;
112
+ }
113
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
114
+ throw new Error(`${loc}: must be a string or a map with one of: exec, gitlab, github`);
115
+ }
116
+ const obj = raw;
117
+ if ("exec" in obj) {
118
+ if (typeof obj["exec"] !== "string" || !obj["exec"]) {
119
+ throw new Error(`${loc}.exec: must be a non-empty string`);
120
+ }
121
+ return { exec: obj["exec"] };
122
+ }
123
+ if ("gitlab" in obj) {
124
+ const gl = obj["gitlab"];
125
+ if (!gl || typeof gl !== "object" || Array.isArray(gl)) {
126
+ throw new Error(`${loc}.gitlab: must be an object`);
127
+ }
128
+ const g = gl;
129
+ if (typeof g["project"] !== "string" || !g["project"]) {
130
+ throw new Error(`${loc}.gitlab.project: required string`);
131
+ }
132
+ if (typeof g["file"] !== "string" || !g["file"]) {
133
+ throw new Error(`${loc}.gitlab.file: required string`);
134
+ }
135
+ return {
136
+ gitlab: {
137
+ project: g["project"],
138
+ file: g["file"],
139
+ ref: typeof g["ref"] === "string" ? g["ref"] : undefined,
140
+ },
141
+ };
142
+ }
143
+ if ("github" in obj) {
144
+ const gh = obj["github"];
145
+ if (!gh || typeof gh !== "object" || Array.isArray(gh)) {
146
+ throw new Error(`${loc}.github: must be an object`);
147
+ }
148
+ const g = gh;
149
+ if (typeof g["repo"] !== "string" || !g["repo"]) {
150
+ throw new Error(`${loc}.github.repo: required string`);
151
+ }
152
+ if (typeof g["file"] !== "string" || !g["file"]) {
153
+ throw new Error(`${loc}.github.file: required string`);
154
+ }
155
+ return {
156
+ github: {
157
+ repo: g["repo"],
158
+ file: g["file"],
159
+ ref: typeof g["ref"] === "string" ? g["ref"] : undefined,
160
+ },
161
+ };
162
+ }
163
+ throw new Error(`${loc}: unknown source type. Must be a string or map with exec/gitlab/github`);
164
+ }
165
+ function isExecSrc(src) {
166
+ return typeof src === "object" && "exec" in src;
167
+ }
168
+ function parseReplaceRule(r, i, j) {
169
+ if (!r || typeof r !== "object" || Array.isArray(r)) {
170
+ throw new Error(`files[${i}].replace[${j}]: must be an object`);
171
+ }
172
+ const rule = r;
173
+ if (typeof rule["from"] !== "string") {
174
+ throw new Error(`files[${i}].replace[${j}]: "from" must be a string`);
175
+ }
176
+ if (typeof rule["to"] !== "string") {
177
+ throw new Error(`files[${i}].replace[${j}]: "to" must be a string`);
178
+ }
179
+ return { from: rule["from"], to: rule["to"] };
180
+ }
181
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}