appmaker-git-remote-origin-fixer 0.1.0 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -20
- package/dist/cli.js +6 -0
- package/dist/git.d.ts +15 -0
- package/dist/git.js +51 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +64 -23
- package/dist/ui.d.ts +7 -1
- package/dist/ui.js +31 -1
- package/migrations.json +2 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,17 +3,22 @@
|
|
|
3
3
|
A small recovery CLI that repairs a local git `origin` remote after a GitHub
|
|
4
4
|
**organization migration**.
|
|
5
5
|
|
|
6
|
-
When repositories are
|
|
7
|
-
then deleted
|
|
8
|
-
old remote
|
|
9
|
-
push, and it repoints `origin` at the new organization for you.
|
|
6
|
+
When repositories are moved from one GitHub organization to another — and the old
|
|
7
|
+
copy is then **deleted** or **archived** — every developer's local clone still
|
|
8
|
+
points at the old remote, so `git push` fails. Run this tool once, after that
|
|
9
|
+
first failed push, and it repoints `origin` at the new organization for you.
|
|
10
10
|
|
|
11
11
|
```
|
|
12
|
-
git push # ❌ fails — repo
|
|
12
|
+
git push # ❌ fails — repo was moved out of the old org
|
|
13
13
|
appmaker-git-remote-origin-fixer # 🔧 diagnoses and fixes origin
|
|
14
14
|
git push # ✅ works
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
+
> **Who this is for:** the package ships with **Appmaker.xyz**'s migration
|
|
18
|
+
> configuration by default, so Appmaker developers can just install and run it.
|
|
19
|
+
> It is not Appmaker-specific, though — the migration rules are pure data, so any
|
|
20
|
+
> team can reuse it by supplying their own config (see [Configuration](#configuration)).
|
|
21
|
+
|
|
17
22
|
## Install
|
|
18
23
|
|
|
19
24
|
```bash
|
|
@@ -31,6 +36,8 @@ appmaker-git-remote-origin-fixer [options]
|
|
|
31
36
|
|
|
32
37
|
-c, --config <path> Use a specific migrations config file
|
|
33
38
|
-n, --dry-run Diagnose only; do not modify the remote
|
|
39
|
+
-f, --force Rewrite origin to the destination unconditionally,
|
|
40
|
+
without checking the source or destination
|
|
34
41
|
-h, --help Show help
|
|
35
42
|
-v, --version Show version
|
|
36
43
|
```
|
|
@@ -44,25 +51,46 @@ Read origin URL → parse org + repo
|
|
|
44
51
|
Is the org a "source" in the migration config?
|
|
45
52
|
│ no → "No migration configured" → exit
|
|
46
53
|
▼ yes
|
|
47
|
-
|
|
48
|
-
├─
|
|
49
|
-
├─
|
|
50
|
-
└─ not found ↓
|
|
51
|
-
|
|
54
|
+
What state is the repo in the SOURCE org?
|
|
55
|
+
├─ healthy (push works) → "still exists, nothing to do"
|
|
56
|
+
├─ archived (read-only) → migrate ↓
|
|
57
|
+
└─ deleted (not found) → migrate ↓
|
|
58
|
+
│
|
|
59
|
+
▼
|
|
60
|
+
Is the repo reachable in the DESTINATION org? (git ls-remote)
|
|
52
61
|
├─ reachable → rewrite origin → "run git push"
|
|
53
62
|
├─ no permission → "exists, contact admin" (remote left unchanged)
|
|
54
63
|
└─ not found → "not found in either org"
|
|
55
64
|
```
|
|
56
65
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
66
|
+
Detection uses your **existing git credentials** — no GitHub token or API access:
|
|
67
|
+
|
|
68
|
+
- **Existence** is checked with `git ls-remote` (a read).
|
|
69
|
+
- **Archived/read-only** is detected with a `git push --dry-run` probe: it sends
|
|
70
|
+
nothing and creates nothing, but the server still reports if the repo is
|
|
71
|
+
archived. (An archived repo reads fine, so a read alone can't detect it.)
|
|
72
|
+
|
|
73
|
+
The remote is only rewritten once the destination is confirmed reachable —
|
|
74
|
+
**except** under `--force` (see below).
|
|
75
|
+
|
|
76
|
+
> **Note:** detection is most reliable with **SSH remotes**
|
|
77
|
+
> (`git@github.com:Org/repo.git`), where GitHub returns clear messages. Over
|
|
78
|
+
> HTTPS without cached credentials git may be unable to determine state; in that
|
|
79
|
+
> case the tool leaves your remote untouched.
|
|
80
|
+
|
|
81
|
+
### `--force`
|
|
82
|
+
|
|
83
|
+
GitHub reports a **private repo you don't have access to** exactly like a
|
|
84
|
+
missing one ("Repository not found") — so the destination check can't see it,
|
|
85
|
+
and the tool would refuse to switch. If you *know* the repo was migrated and you
|
|
86
|
+
will get access, run with `--force`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
appmaker-git-remote-origin-fixer --force
|
|
90
|
+
```
|
|
60
91
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
> "Repository not found" for missing repos. Over HTTPS without cached
|
|
64
|
-
> credentials, git may be unable to determine existence; in that case the tool
|
|
65
|
-
> reports that it could not verify and leaves your remote untouched.
|
|
92
|
+
`--force` rewrites `origin` to the destination **unconditionally**, skipping both
|
|
93
|
+
the source and destination checks. The next `git push` is then the real test.
|
|
66
94
|
|
|
67
95
|
## Configuration
|
|
68
96
|
|
|
@@ -82,9 +110,10 @@ The config is resolved in this order (first found wins):
|
|
|
82
110
|
1. `--config <path>`
|
|
83
111
|
2. `./migrations.json` (current directory)
|
|
84
112
|
3. `~/.appmaker-git-remote-origin-fixer.json` (per-user override)
|
|
85
|
-
4. the `migrations.json` bundled with the package
|
|
113
|
+
4. the `migrations.json` bundled with the package (Appmaker.xyz's mappings)
|
|
86
114
|
|
|
87
|
-
To support a new migration, update the config — no code change needed.
|
|
115
|
+
To support a new migration, update the config — no code change needed. Other
|
|
116
|
+
teams can use the tool by overriding the config via any of options 1–3 above.
|
|
88
117
|
|
|
89
118
|
## Development
|
|
90
119
|
|
package/dist/cli.js
CHANGED
|
@@ -30,6 +30,10 @@ USAGE
|
|
|
30
30
|
OPTIONS
|
|
31
31
|
-c, --config <path> Use a specific migrations config file.
|
|
32
32
|
-n, --dry-run Diagnose only; do not modify the remote.
|
|
33
|
+
-f, --force Rewrite origin to the destination unconditionally,
|
|
34
|
+
without checking the source or destination. Use when
|
|
35
|
+
the source is archived, or the destination is private
|
|
36
|
+
and you do not have access yet.
|
|
33
37
|
-h, --help Show this help.
|
|
34
38
|
-v, --version Show the version.
|
|
35
39
|
`;
|
|
@@ -40,6 +44,7 @@ function main() {
|
|
|
40
44
|
options: {
|
|
41
45
|
config: { type: "string", short: "c" },
|
|
42
46
|
"dry-run": { type: "boolean", short: "n" },
|
|
47
|
+
force: { type: "boolean", short: "f" },
|
|
43
48
|
help: { type: "boolean", short: "h" },
|
|
44
49
|
version: { type: "boolean", short: "v" },
|
|
45
50
|
},
|
|
@@ -64,6 +69,7 @@ function main() {
|
|
|
64
69
|
return run({
|
|
65
70
|
configPath: values.config,
|
|
66
71
|
dryRun: values["dry-run"],
|
|
72
|
+
force: values.force,
|
|
67
73
|
});
|
|
68
74
|
}
|
|
69
75
|
catch (err) {
|
package/dist/git.d.ts
CHANGED
|
@@ -25,3 +25,18 @@ export declare function setOriginUrl(url: string): void;
|
|
|
25
25
|
* can distinguish "missing" from "no permission".
|
|
26
26
|
*/
|
|
27
27
|
export declare function probeRemote(url: string): ProbeResult;
|
|
28
|
+
export type PushStatus = "writable" | "archived" | "forbidden" | "not_found" | "unknown";
|
|
29
|
+
export interface PushProbeResult {
|
|
30
|
+
status: PushStatus;
|
|
31
|
+
detail: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Probe whether the current repo could PUSH to `url`, without actually pushing.
|
|
35
|
+
*
|
|
36
|
+
* A `git push --dry-run` of the current commit to a throwaway ref sends nothing
|
|
37
|
+
* and creates nothing, but GitHub still enforces archived/permission checks
|
|
38
|
+
* during negotiation — so this distinguishes a writable repo from one that is
|
|
39
|
+
* archived (read-only). Requires a local commit to push; if HEAD is unborn the
|
|
40
|
+
* probe is inconclusive ("unknown").
|
|
41
|
+
*/
|
|
42
|
+
export declare function probePushable(url: string): PushProbeResult;
|
package/dist/git.js
CHANGED
|
@@ -87,3 +87,54 @@ export function probeRemote(url) {
|
|
|
87
87
|
process.env.GIT_TERMINAL_PROMPT = prevPrompt;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Probe whether the current repo could PUSH to `url`, without actually pushing.
|
|
92
|
+
*
|
|
93
|
+
* A `git push --dry-run` of the current commit to a throwaway ref sends nothing
|
|
94
|
+
* and creates nothing, but GitHub still enforces archived/permission checks
|
|
95
|
+
* during negotiation — so this distinguishes a writable repo from one that is
|
|
96
|
+
* archived (read-only). Requires a local commit to push; if HEAD is unborn the
|
|
97
|
+
* probe is inconclusive ("unknown").
|
|
98
|
+
*/
|
|
99
|
+
export function probePushable(url) {
|
|
100
|
+
if (!runGit(["rev-parse", "--verify", "HEAD"]).ok) {
|
|
101
|
+
return { status: "unknown", detail: "no local commit to probe with" };
|
|
102
|
+
}
|
|
103
|
+
const prevPrompt = process.env.GIT_TERMINAL_PROMPT;
|
|
104
|
+
process.env.GIT_TERMINAL_PROMPT = "0";
|
|
105
|
+
try {
|
|
106
|
+
const result = runGit([
|
|
107
|
+
"push",
|
|
108
|
+
"--dry-run",
|
|
109
|
+
url,
|
|
110
|
+
"HEAD:refs/heads/__appmaker_origin_fixer_probe__",
|
|
111
|
+
]);
|
|
112
|
+
if (result.ok)
|
|
113
|
+
return { status: "writable", detail: "" };
|
|
114
|
+
const stderr = result.stderr.toLowerCase();
|
|
115
|
+
// Check archived first: GitHub's archived error also contains phrases that
|
|
116
|
+
// match the not_found patterns below.
|
|
117
|
+
if (stderr.includes("archived") || stderr.includes("read-only") || stderr.includes("read only")) {
|
|
118
|
+
return { status: "archived", detail: result.stderr };
|
|
119
|
+
}
|
|
120
|
+
if (stderr.includes("permission") ||
|
|
121
|
+
stderr.includes("denied") ||
|
|
122
|
+
stderr.includes("not authorized") ||
|
|
123
|
+
stderr.includes("authentication failed") ||
|
|
124
|
+
stderr.includes("403")) {
|
|
125
|
+
return { status: "forbidden", detail: result.stderr };
|
|
126
|
+
}
|
|
127
|
+
if (stderr.includes("repository not found") ||
|
|
128
|
+
stderr.includes("not found") ||
|
|
129
|
+
stderr.includes("does not exist")) {
|
|
130
|
+
return { status: "not_found", detail: result.stderr };
|
|
131
|
+
}
|
|
132
|
+
return { status: "unknown", detail: result.stderr };
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
if (prevPrompt === undefined)
|
|
136
|
+
delete process.env.GIT_TERMINAL_PROMPT;
|
|
137
|
+
else
|
|
138
|
+
process.env.GIT_TERMINAL_PROMPT = prevPrompt;
|
|
139
|
+
}
|
|
140
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,12 @@ export interface RunOptions {
|
|
|
12
12
|
configPath?: string;
|
|
13
13
|
/** Diagnose only; never modify the remote. */
|
|
14
14
|
dryRun?: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Skip the "does the source still exist?" check and switch to the
|
|
17
|
+
* destination regardless of source state (e.g. when the source repo is
|
|
18
|
+
* archived and read-only). The destination is still verified first.
|
|
19
|
+
*/
|
|
20
|
+
force?: boolean;
|
|
15
21
|
}
|
|
16
22
|
/** Returns a process exit code. */
|
|
17
23
|
export declare function run(options?: RunOptions): number;
|
package/dist/index.js
CHANGED
|
@@ -8,9 +8,37 @@
|
|
|
8
8
|
* 5. Probe destination -> found -> rewrite origin; else explain
|
|
9
9
|
*/
|
|
10
10
|
import { loadConfig } from "./config.js";
|
|
11
|
-
import { getOriginUrl, isGitRepo, probeRemote, setOriginUrl, } from "./git.js";
|
|
11
|
+
import { getOriginUrl, isGitRepo, probePushable, probeRemote, setOriginUrl, } from "./git.js";
|
|
12
12
|
import { parseRemote, rewriteOrg } from "./remote-url.js";
|
|
13
13
|
import * as ui from "./ui.js";
|
|
14
|
+
/**
|
|
15
|
+
* Verify the destination repo is reachable and, if so, rewrite origin to it.
|
|
16
|
+
* Shared by the normal flow and --force. Returns a process exit code.
|
|
17
|
+
*/
|
|
18
|
+
function switchToDestination(parsed, destOrg, originUrl, dryRun) {
|
|
19
|
+
const destUrl = rewriteOrg(parsed, destOrg);
|
|
20
|
+
const dest = probeRemote(destUrl);
|
|
21
|
+
if (dest.status === "reachable") {
|
|
22
|
+
if (dryRun) {
|
|
23
|
+
ui.info("(dry run) Would update origin:");
|
|
24
|
+
ui.info(` ${originUrl} -> ${destUrl}`);
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
setOriginUrl(destUrl);
|
|
28
|
+
ui.updated(destOrg, originUrl, destUrl);
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
if (dest.status === "forbidden") {
|
|
32
|
+
ui.permissionDenied(destOrg, parsed.repo);
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
if (dest.status === "unknown") {
|
|
36
|
+
ui.probeFailed(destUrl, dest.detail);
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
// not_found
|
|
40
|
+
return -1; // caller decides the message (differs for force vs normal flow)
|
|
41
|
+
}
|
|
14
42
|
/** Returns a process exit code. */
|
|
15
43
|
export function run(options = {}) {
|
|
16
44
|
if (!isGitRepo()) {
|
|
@@ -33,10 +61,39 @@ export function run(options = {}) {
|
|
|
33
61
|
ui.noMigration(parsed.org);
|
|
34
62
|
return 0; // Not an error — just nothing to do.
|
|
35
63
|
}
|
|
64
|
+
// --force: rewrite origin to the destination unconditionally, without
|
|
65
|
+
// probing either the source or the destination. Useful when the source is
|
|
66
|
+
// archived, or when the destination is private and the user has no access
|
|
67
|
+
// yet (GitHub reports those as "not found"). The destination is NOT verified.
|
|
68
|
+
if (options.force) {
|
|
69
|
+
const destUrl = rewriteOrg(parsed, destOrg);
|
|
70
|
+
if (options.dryRun) {
|
|
71
|
+
ui.info("(dry run) Would update origin:");
|
|
72
|
+
ui.info(` ${originUrl} -> ${destUrl}`);
|
|
73
|
+
return 0;
|
|
74
|
+
}
|
|
75
|
+
setOriginUrl(destUrl);
|
|
76
|
+
ui.forcedUpdate(destOrg, originUrl, destUrl);
|
|
77
|
+
return 0;
|
|
78
|
+
}
|
|
36
79
|
// Step 4 — is the repo still in the source org?
|
|
37
80
|
const source = probeRemote(originUrl);
|
|
38
81
|
if (source.status === "reachable") {
|
|
39
|
-
|
|
82
|
+
// Readable — but an archived repo also reads fine. Probe push capability to
|
|
83
|
+
// tell a healthy repo from an archived (read-only) one.
|
|
84
|
+
const push = probePushable(originUrl);
|
|
85
|
+
if (push.status === "archived") {
|
|
86
|
+
ui.archivedSource(parsed.org, parsed.repo, destOrg);
|
|
87
|
+
const code = switchToDestination(parsed, destOrg, originUrl, !!options.dryRun);
|
|
88
|
+
if (code === -1) {
|
|
89
|
+
// Archived source, but destination not reachable (e.g. private/no access).
|
|
90
|
+
ui.archivedDestNotFound(destOrg, parsed.repo);
|
|
91
|
+
return 1;
|
|
92
|
+
}
|
|
93
|
+
return code;
|
|
94
|
+
}
|
|
95
|
+
// Writable or inconclusive — treat as genuinely present, nothing to do.
|
|
96
|
+
ui.stillExists(parsed.org, parsed.repo, destOrg);
|
|
40
97
|
return 0;
|
|
41
98
|
}
|
|
42
99
|
if (source.status === "forbidden") {
|
|
@@ -49,27 +106,11 @@ export function run(options = {}) {
|
|
|
49
106
|
}
|
|
50
107
|
// status === "not_found" -> continue to the destination.
|
|
51
108
|
// Step 5 — is the repo in the destination org?
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
ui.info("(dry run) Would update origin:");
|
|
57
|
-
ui.info(` ${originUrl} -> ${destUrl}`);
|
|
58
|
-
return 0;
|
|
59
|
-
}
|
|
60
|
-
setOriginUrl(destUrl);
|
|
61
|
-
ui.updated(destOrg, originUrl, destUrl);
|
|
62
|
-
return 0;
|
|
63
|
-
}
|
|
64
|
-
if (dest.status === "forbidden") {
|
|
65
|
-
ui.permissionDenied(destOrg, parsed.repo);
|
|
66
|
-
return 1;
|
|
67
|
-
}
|
|
68
|
-
if (dest.status === "unknown") {
|
|
69
|
-
ui.probeFailed(destUrl, dest.detail);
|
|
109
|
+
const code = switchToDestination(parsed, destOrg, originUrl, !!options.dryRun);
|
|
110
|
+
if (code === -1) {
|
|
111
|
+
// Not found in either org.
|
|
112
|
+
ui.notFoundAnywhere(parsed.repo, [parsed.org, destOrg]);
|
|
70
113
|
return 1;
|
|
71
114
|
}
|
|
72
|
-
|
|
73
|
-
ui.notFoundAnywhere(parsed.repo, [parsed.org, destOrg]);
|
|
74
|
-
return 1;
|
|
115
|
+
return code;
|
|
75
116
|
}
|
package/dist/ui.d.ts
CHANGED
|
@@ -14,7 +14,13 @@ export declare function unparseableRemote(url: string): void;
|
|
|
14
14
|
/** Step 2: no migration configured for this org. */
|
|
15
15
|
export declare function noMigration(org: string): void;
|
|
16
16
|
/** Step 3: repository still exists in the source org. */
|
|
17
|
-
export declare function stillExists(org: string, repo: string): void;
|
|
17
|
+
export declare function stillExists(org: string, repo: string, destOrg: string): void;
|
|
18
|
+
/** Auto-detected: source repo is archived (read-only); migrating. */
|
|
19
|
+
export declare function archivedSource(org: string, repo: string, destOrg: string): void;
|
|
20
|
+
/** Auto-detected archived source, but the destination could not be reached. */
|
|
21
|
+
export declare function archivedDestNotFound(destOrg: string, repo: string): void;
|
|
22
|
+
/** --force: origin rewritten without verifying the destination. */
|
|
23
|
+
export declare function forcedUpdate(destOrg: string, from: string, to: string): void;
|
|
18
24
|
/** Step 3/4: permission denied on a repository. */
|
|
19
25
|
export declare function permissionDenied(org: string, repo: string): void;
|
|
20
26
|
/** Step 4: found in destination -> updated. */
|
package/dist/ui.js
CHANGED
|
@@ -41,9 +41,39 @@ export function noMigration(org) {
|
|
|
41
41
|
info(`No migration configured for organization:\n\n ${bold(org)}`);
|
|
42
42
|
}
|
|
43
43
|
/** Step 3: repository still exists in the source org. */
|
|
44
|
-
export function stillExists(org, repo) {
|
|
44
|
+
export function stillExists(org, repo, destOrg) {
|
|
45
45
|
info(`${CHECK} Repository ${bold(`${org}/${repo}`)} still exists.`);
|
|
46
46
|
info("No changes required.");
|
|
47
|
+
info("");
|
|
48
|
+
info(dim(`If your push still fails (e.g. the repo was archived), re-run with ` +
|
|
49
|
+
`--force to switch to ${destOrg} anyway.`));
|
|
50
|
+
}
|
|
51
|
+
/** Auto-detected: source repo is archived (read-only); migrating. */
|
|
52
|
+
export function archivedSource(org, repo, destOrg) {
|
|
53
|
+
info(`${yellow("!")} Repository ${bold(`${org}/${repo}`)} is archived (read-only).`);
|
|
54
|
+
info(`Migrating origin to ${bold(destOrg)}...`);
|
|
55
|
+
info("");
|
|
56
|
+
}
|
|
57
|
+
/** Auto-detected archived source, but the destination could not be reached. */
|
|
58
|
+
export function archivedDestNotFound(destOrg, repo) {
|
|
59
|
+
error(`Source is archived, but ${bold(`${destOrg}/${repo}`)} was not found.`);
|
|
60
|
+
info("It may be private and you may not have access yet.");
|
|
61
|
+
info(dim("If you are sure it exists there, re-run with --force to switch anyway."));
|
|
62
|
+
}
|
|
63
|
+
/** --force: origin rewritten without verifying the destination. */
|
|
64
|
+
export function forcedUpdate(destOrg, from, to) {
|
|
65
|
+
info(`${CHECK} Updated origin to ${bold(destOrg)} ${dim("(forced — destination not verified)")}.`);
|
|
66
|
+
info("");
|
|
67
|
+
info(dim(` ${from}`));
|
|
68
|
+
info(dim(" ↓"));
|
|
69
|
+
info(` ${green(to)}`);
|
|
70
|
+
info("");
|
|
71
|
+
info(yellow("Note: the destination was not checked. If the repository does not"));
|
|
72
|
+
info(yellow("exist there, or you do not have access yet, your next push will fail."));
|
|
73
|
+
info("");
|
|
74
|
+
info("Please run:");
|
|
75
|
+
info("");
|
|
76
|
+
info(bold(" git push"));
|
|
47
77
|
}
|
|
48
78
|
/** Step 3/4: permission denied on a repository. */
|
|
49
79
|
export function permissionDenied(org, repo) {
|
package/migrations.json
CHANGED
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "appmaker-git-remote-origin-fixer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Recovery CLI that repairs a local git origin remote after a GitHub organization migration.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"appmaker-git-remote-origin-fixer": "
|
|
7
|
+
"appmaker-git-remote-origin-fixer": "dist/cli.js"
|
|
8
8
|
},
|
|
9
9
|
"files": [
|
|
10
10
|
"dist",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"node": ">=18"
|
|
15
15
|
},
|
|
16
16
|
"scripts": {
|
|
17
|
-
"build": "tsc",
|
|
17
|
+
"build": "tsc && chmod +x dist/cli.js",
|
|
18
18
|
"dev": "tsc --watch",
|
|
19
19
|
"start": "node dist/cli.js",
|
|
20
20
|
"prepublishOnly": "npm run build"
|