@hallaxius/forge 0.1.3 → 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.
Files changed (45) hide show
  1. package/README.md +160 -158
  2. package/bin/forge.js +2 -2
  3. package/dist/cli.js +12764 -13800
  4. package/package.json +75 -75
  5. package/src/cli.ts +80 -78
  6. package/src/commands/account.ts +80 -0
  7. package/src/commands/alias.ts +66 -66
  8. package/src/commands/branch.ts +46 -46
  9. package/src/commands/ci.ts +28 -28
  10. package/src/commands/clone.ts +100 -100
  11. package/src/commands/commit.ts +88 -88
  12. package/src/commands/config.ts +47 -48
  13. package/src/commands/diff.ts +26 -26
  14. package/src/commands/fetch.ts +20 -20
  15. package/src/commands/help.ts +58 -58
  16. package/src/commands/init.ts +32 -33
  17. package/src/commands/issue.ts +63 -63
  18. package/src/commands/log.ts +29 -29
  19. package/src/commands/merge.ts +37 -37
  20. package/src/commands/pr.ts +65 -65
  21. package/src/commands/push.ts +35 -35
  22. package/src/commands/release.ts +26 -26
  23. package/src/commands/remote.ts +107 -107
  24. package/src/commands/reset.ts +30 -30
  25. package/src/commands/setup.ts +93 -94
  26. package/src/commands/stash.ts +44 -44
  27. package/src/commands/status.ts +74 -74
  28. package/src/commands/sync.ts +20 -20
  29. package/src/commands/tag.ts +41 -41
  30. package/src/commands/undo.ts +27 -27
  31. package/src/commands/version.ts +12 -12
  32. package/src/constants/colors.ts +7 -7
  33. package/src/constants/commit-types.ts +24 -24
  34. package/src/constants/messages.ts +13 -23
  35. package/src/lib/auth.ts +172 -172
  36. package/src/lib/config.ts +108 -108
  37. package/src/lib/git.ts +543 -543
  38. package/src/lib/github.ts +202 -160
  39. package/src/lib/logger.ts +18 -31
  40. package/src/lib/ui.ts +122 -156
  41. package/src/lib/validators.ts +16 -16
  42. package/src/templates/commit-types.json +9 -9
  43. package/src/utils/files.ts +21 -21
  44. package/src/utils/strings.ts +19 -19
  45. package/src/version.const.ts +1 -1
@@ -1,26 +1,26 @@
1
- import type { Command } from "commander";
2
- import { createRelease } from "../lib/github.js";
3
- import { error, success } from "../lib/logger.js";
4
- import { input, withSpinner } from "../lib/ui.js";
5
-
6
- export default function register(program: Command): void {
7
- program
8
- .command("release")
9
- .description("Create a GitHub release")
10
- .argument("<tag>", "Git tag name")
11
- .option("-n, --name <name>", "Release name")
12
- .action(async (tag, options) => {
13
- try {
14
- const name = options.name || (await input("Release name", tag));
15
- const body = await input("Release description (optional)");
16
- const result = await withSpinner("Creating release...", () =>
17
- createRelease(tag, name, body),
18
- );
19
- success(`Release created: ${result.url}`);
20
- } catch (err) {
21
- error(
22
- `Release creation failed: ${err instanceof Error ? err.message : String(err)}`,
23
- );
24
- }
25
- });
26
- }
1
+ import type { Command } from "commander";
2
+ import { createRelease } from "../lib/github.js";
3
+ import { error, text } from "../lib/logger.js";
4
+ import { input, withSpinner } from "../lib/ui.js";
5
+
6
+ export default function register(program: Command): void {
7
+ program
8
+ .command("release")
9
+ .description("Create a GitHub release")
10
+ .argument("<tag>", "Git tag name")
11
+ .option("-n, --name <name>", "Release name")
12
+ .action(async (tag, options) => {
13
+ try {
14
+ const name = options.name || (await input("Release name", tag));
15
+ const body = await input("Release description (optional)");
16
+ const result = await withSpinner("Creating release...", () =>
17
+ createRelease(tag, name, body),
18
+ );
19
+ text(`Release created: ${result.url}`);
20
+ } catch (err) {
21
+ error(
22
+ `Release creation failed: ${err instanceof Error ? err.message : String(err)}`,
23
+ );
24
+ }
25
+ });
26
+ }
@@ -1,107 +1,107 @@
1
- import type { Command } from "commander";
2
- import * as git from "../lib/git.js";
3
- import { error, info, success } from "../lib/logger.js";
4
- import { confirm, createTable } from "../lib/ui.js";
5
-
6
- export default function register(program: Command): void {
7
- const remote = program.command("remote").description("Manage remotes");
8
-
9
- remote
10
- .command("add <name> <url>")
11
- .description("Add a new remote")
12
- .action(async (name, url) => {
13
- try {
14
- await git.remoteAdd(name, url);
15
- success(`Remote '${name}' added (${url}).`);
16
- } catch (err) {
17
- error(
18
- `Failed to add remote: ${err instanceof Error ? err.message : String(err)}`,
19
- );
20
- }
21
- });
22
-
23
- remote
24
- .command("remove <name>")
25
- .description("Remove a remote")
26
- .action(async (name) => {
27
- try {
28
- const confirmed = await confirm(
29
- `Are you sure you want to remove remote '${name}'?`,
30
- false,
31
- );
32
-
33
- if (!confirmed) {
34
- info("Canceled.");
35
- return;
36
- }
37
-
38
- await git.remoteRemove(name);
39
- success(`Remote '${name}' removed.`);
40
- } catch (err) {
41
- error(
42
- `Failed to remove remote: ${err instanceof Error ? err.message : String(err)}`,
43
- );
44
- }
45
- });
46
-
47
- remote
48
- .command("set-url <name> <new-url>")
49
- .description("Change a remote URL")
50
- .action(async (name, newUrl) => {
51
- try {
52
- await git.remoteSetUrl(name, newUrl);
53
- success(`Remote '${name}' URL updated to ${newUrl}.`);
54
- } catch (err) {
55
- error(
56
- `Failed to update remote URL: ${err instanceof Error ? err.message : String(err)}`,
57
- );
58
- }
59
- });
60
-
61
- remote
62
- .command("rename <old-name> <new-name>")
63
- .description("Rename a remote")
64
- .action(async (oldName, newName) => {
65
- try {
66
- await git.remoteRename(oldName, newName);
67
- success(`Remote '${oldName}' renamed to '${newName}'.`);
68
- } catch (err) {
69
- error(
70
- `Failed to rename remote: ${err instanceof Error ? err.message : String(err)}`,
71
- );
72
- }
73
- });
74
-
75
- remote
76
- .command("get-url <name>")
77
- .description("Get the URL of a remote")
78
- .action(async (name) => {
79
- try {
80
- const url = await git.remoteGetUrl(name);
81
- info(`Remote '${name}': ${url}`);
82
- } catch (err) {
83
- error(
84
- `Failed to get remote URL: ${err instanceof Error ? err.message : String(err)}`,
85
- );
86
- }
87
- });
88
-
89
- remote.action(async () => {
90
- try {
91
- const remotes = await git.remoteList();
92
-
93
- if (remotes.length === 0) {
94
- info("No remotes configured.");
95
- return;
96
- }
97
-
98
- const rows = remotes.map((r) => [r.name, r.url]);
99
- info("Remotes:");
100
- console.log(createTable(["Name", "URL"], rows));
101
- } catch (err) {
102
- error(
103
- `Failed to list remotes: ${err instanceof Error ? err.message : String(err)}`,
104
- );
105
- }
106
- });
107
- }
1
+ import type { Command } from "commander";
2
+ import * as git from "../lib/git.js";
3
+ import { error, text } from "../lib/logger.js";
4
+ import { confirm, createTable } from "../lib/ui.js";
5
+
6
+ export default function register(program: Command): void {
7
+ const remote = program.command("remote").description("Manage remotes");
8
+
9
+ remote
10
+ .command("add <name> <url>")
11
+ .description("Add a new remote")
12
+ .action(async (name, url) => {
13
+ try {
14
+ await git.remoteAdd(name, url);
15
+ text(`Remote '${name}' added (${url}).`);
16
+ } catch (err) {
17
+ error(
18
+ `Failed to add remote: ${err instanceof Error ? err.message : String(err)}`,
19
+ );
20
+ }
21
+ });
22
+
23
+ remote
24
+ .command("remove <name>")
25
+ .description("Remove a remote")
26
+ .action(async (name) => {
27
+ try {
28
+ const confirmed = await confirm(
29
+ `Are you sure you want to remove remote '${name}'?`,
30
+ false,
31
+ );
32
+
33
+ if (!confirmed) {
34
+ text("Canceled.");
35
+ return;
36
+ }
37
+
38
+ await git.remoteRemove(name);
39
+ text(`Remote '${name}' removed.`);
40
+ } catch (err) {
41
+ error(
42
+ `Failed to remove remote: ${err instanceof Error ? err.message : String(err)}`,
43
+ );
44
+ }
45
+ });
46
+
47
+ remote
48
+ .command("set-url <name> <new-url>")
49
+ .description("Change a remote URL")
50
+ .action(async (name, newUrl) => {
51
+ try {
52
+ await git.remoteSetUrl(name, newUrl);
53
+ text(`Remote '${name}' URL updated to ${newUrl}.`);
54
+ } catch (err) {
55
+ error(
56
+ `Failed to update remote URL: ${err instanceof Error ? err.message : String(err)}`,
57
+ );
58
+ }
59
+ });
60
+
61
+ remote
62
+ .command("rename <old-name> <new-name>")
63
+ .description("Rename a remote")
64
+ .action(async (oldName, newName) => {
65
+ try {
66
+ await git.remoteRename(oldName, newName);
67
+ text(`Remote '${oldName}' renamed to '${newName}'.`);
68
+ } catch (err) {
69
+ error(
70
+ `Failed to rename remote: ${err instanceof Error ? err.message : String(err)}`,
71
+ );
72
+ }
73
+ });
74
+
75
+ remote
76
+ .command("get-url <name>")
77
+ .description("Get the URL of a remote")
78
+ .action(async (name) => {
79
+ try {
80
+ const url = await git.remoteGetUrl(name);
81
+ text(`Remote '${name}': ${url}`);
82
+ } catch (err) {
83
+ error(
84
+ `Failed to get remote URL: ${err instanceof Error ? err.message : String(err)}`,
85
+ );
86
+ }
87
+ });
88
+
89
+ remote.action(async () => {
90
+ try {
91
+ const remotes = await git.remoteList();
92
+
93
+ if (remotes.length === 0) {
94
+ text("No remotes configured.");
95
+ return;
96
+ }
97
+
98
+ const rows = remotes.map((r) => [r.name, r.url]);
99
+ text("Remotes:");
100
+ text(createTable(["Name", "URL"], rows));
101
+ } catch (err) {
102
+ error(
103
+ `Failed to list remotes: ${err instanceof Error ? err.message : String(err)}`,
104
+ );
105
+ }
106
+ });
107
+ }
@@ -1,30 +1,30 @@
1
- import type { Command } from "commander";
2
- import { ConfigManager } from "../lib/config.js";
3
- import { error, info, success, warning } from "../lib/logger.js";
4
- import { confirm } from "../lib/ui.js";
5
-
6
- export default function register(program: Command): void {
7
- program
8
- .command("reset")
9
- .description("Reset all configuration")
10
- .action(async () => {
11
- try {
12
- warning("This will delete all Forge configuration.");
13
- const proceed = await confirm(
14
- "Are you sure? This will delete all configuration",
15
- );
16
- if (!proceed) {
17
- info("Reset cancelled.");
18
- return;
19
- }
20
-
21
- const config = new ConfigManager();
22
- config.clear();
23
- success("Configuration reset successfully.");
24
- } catch (err) {
25
- error(
26
- `Reset failed: ${err instanceof Error ? err.message : String(err)}`,
27
- );
28
- }
29
- });
30
- }
1
+ import type { Command } from "commander";
2
+ import { ConfigManager } from "../lib/config.js";
3
+ import { error, text, warning } from "../lib/logger.js";
4
+ import { confirm } from "../lib/ui.js";
5
+
6
+ export default function register(program: Command): void {
7
+ program
8
+ .command("reset")
9
+ .description("Reset all configuration")
10
+ .action(async () => {
11
+ try {
12
+ warning("This will delete all Forge configuration.");
13
+ const proceed = await confirm(
14
+ "Are you sure? This will delete all configuration",
15
+ );
16
+ if (!proceed) {
17
+ text("Reset cancelled.");
18
+ return;
19
+ }
20
+
21
+ const config = new ConfigManager();
22
+ config.clear();
23
+ text("Configuration reset successfully.");
24
+ } catch (err) {
25
+ error(
26
+ `Reset failed: ${err instanceof Error ? err.message : String(err)}`,
27
+ );
28
+ }
29
+ });
30
+ }
@@ -1,94 +1,93 @@
1
- import type { Command } from "commander";
2
- import { encryptToken, generateMachineKey } from "../lib/auth.js";
3
- import { ConfigManager } from "../lib/config.js";
4
- import { error, info, newline, success, warning } from "../lib/logger.js";
5
- import { confirm, input, password, showBox } from "../lib/ui.js";
6
- import { validateEmail } from "../lib/validators.js";
7
-
8
- export default function register(program: Command): void {
9
- program
10
- .command("setup")
11
- .description("Interactive setup wizard")
12
- .action(async () => {
13
- try {
14
- const config = new ConfigManager();
15
-
16
- if (config.isConfigured()) {
17
- warning("Forge is already configured. You are about to reconfigure.");
18
- const proceed = await confirm("Continue with reconfiguration?");
19
- if (!proceed) {
20
- info("Setup cancelled.");
21
- return;
22
- }
23
- }
24
-
25
- newline();
26
- info("Starting setup...");
27
- newline();
28
-
29
- const name = await input("Your name");
30
-
31
- let email = await input("Your email");
32
- while (!validateEmail(email)) {
33
- error("Invalid email format.");
34
- email = await input("Your email");
35
- }
36
-
37
- const rawToken = await input(
38
- "GitHub token (required for remote operations)",
39
- );
40
- if (!rawToken) {
41
- error(
42
- "GitHub token is required. Get one at https://github.com/settings/tokens",
43
- );
44
- return;
45
- }
46
-
47
- const useMasterPassword = await confirm(
48
- "Protect token with a master password? (recommended)",
49
- true,
50
- );
51
-
52
- const machineKey = generateMachineKey();
53
- let hasMasterPassword = false;
54
-
55
- if (useMasterPassword) {
56
- const mp = await password("Master password:");
57
- const encryptedKey = await encryptToken(machineKey, mp);
58
- config.set("auth.machineKey", encryptedKey);
59
- config.set("auth.hasMasterPassword", true);
60
- hasMasterPassword = true;
61
- } else {
62
- config.set("auth.machineKey", machineKey);
63
- config.set("auth.hasMasterPassword", false);
64
- }
65
-
66
- const encryptedToken = await encryptToken(rawToken, machineKey);
67
- config.set("github.encryptedToken", encryptedToken);
68
-
69
- config.set("user", { name, email });
70
- config.set("preferences", {
71
- autoPush: false,
72
- commitTemplate: "",
73
- editor: process.env.EDITOR || "vim",
74
- });
75
-
76
- newline();
77
- showBox(
78
- "Configuration Complete",
79
- [
80
- `User: ${name} <${email}>`,
81
- `Token: Set (encrypted)`,
82
- `Security: ${hasMasterPassword ? "Master password protected" : "Machine key"}`,
83
- `Config: ${config.getPath()}`,
84
- ].join("\n"),
85
- );
86
-
87
- success("Forge is ready to use!");
88
- } catch (err) {
89
- error(
90
- `Setup failed: ${err instanceof Error ? err.message : String(err)}`,
91
- );
92
- }
93
- });
94
- }
1
+ import type { Command } from "commander";
2
+ import { encryptToken, generateMachineKey } from "../lib/auth.js";
3
+ import { ConfigManager } from "../lib/config.js";
4
+ import { error, newline, text, warning } from "../lib/logger.js";
5
+ import { confirm, input, password } from "../lib/ui.js";
6
+ import { validateEmail } from "../lib/validators.js";
7
+
8
+ export default function register(program: Command): void {
9
+ program
10
+ .command("setup")
11
+ .description("Interactive setup wizard")
12
+ .action(async () => {
13
+ try {
14
+ const config = new ConfigManager();
15
+
16
+ if (config.isConfigured()) {
17
+ warning("Forge is already configured. You are about to reconfigure.");
18
+ const proceed = await confirm("Continue with reconfiguration?");
19
+ if (!proceed) {
20
+ text("Setup cancelled.");
21
+ return;
22
+ }
23
+ }
24
+
25
+ newline();
26
+ text("Starting setup...");
27
+ newline();
28
+
29
+ const name = await input("Your name");
30
+
31
+ let email = await input("Your email");
32
+ while (!validateEmail(email)) {
33
+ error("Invalid email format.");
34
+ email = await input("Your email");
35
+ }
36
+
37
+ const rawToken = await input(
38
+ "GitHub token (required for remote operations)",
39
+ );
40
+ if (!rawToken) {
41
+ error(
42
+ "GitHub token is required. Get one at https://github.com/settings/tokens",
43
+ );
44
+ return;
45
+ }
46
+
47
+ const useMasterPassword = await confirm(
48
+ "Protect token with a master password? (recommended)",
49
+ true,
50
+ );
51
+
52
+ const machineKey = generateMachineKey();
53
+ let hasMasterPassword = false;
54
+
55
+ if (useMasterPassword) {
56
+ const mp = await password("Master password:");
57
+ const encryptedKey = await encryptToken(machineKey, mp);
58
+ config.set("auth.machineKey", encryptedKey);
59
+ config.set("auth.hasMasterPassword", true);
60
+ hasMasterPassword = true;
61
+ } else {
62
+ config.set("auth.machineKey", machineKey);
63
+ config.set("auth.hasMasterPassword", false);
64
+ }
65
+
66
+ const encryptedToken = await encryptToken(rawToken, machineKey);
67
+ config.set("github.encryptedToken", encryptedToken);
68
+
69
+ config.set("user", { name, email });
70
+ config.set("preferences", {
71
+ autoPush: false,
72
+ commitTemplate: "",
73
+ editor: process.env.EDITOR || "vim",
74
+ });
75
+
76
+ newline();
77
+ text(
78
+ [
79
+ `User: ${name} <${email}>`,
80
+ `Token: Set (encrypted)`,
81
+ `Security: ${hasMasterPassword ? "Master password protected" : "Machine key"}`,
82
+ `Config: ${config.getPath()}`,
83
+ ].join("\n"),
84
+ );
85
+
86
+ text("Forge is ready to use!");
87
+ } catch (err) {
88
+ error(
89
+ `Setup failed: ${err instanceof Error ? err.message : String(err)}`,
90
+ );
91
+ }
92
+ });
93
+ }
@@ -1,44 +1,44 @@
1
- import type { Command } from "commander";
2
- import * as git from "../lib/git.js";
3
- import { error, info, success } from "../lib/logger.js";
4
- import { createTable, input, withSpinner } from "../lib/ui.js";
5
-
6
- export default function register(program: Command): void {
7
- program
8
- .command("stash")
9
- .description("Manage stashes")
10
- .option("--pop", "Apply and remove latest stash")
11
- .option("--list", "List all stashes")
12
- .action(async (options) => {
13
- try {
14
- if (options.pop) {
15
- const result = await withSpinner("Applying stash...", () =>
16
- git.stashPop(),
17
- );
18
- success(`Stash popped: ${result}`);
19
- return;
20
- }
21
-
22
- if (options.list) {
23
- const stashes = await git.stashList();
24
- if (stashes.length === 0) {
25
- info("No stashes found.");
26
- return;
27
- }
28
-
29
- const rows = stashes.map((s) => [String(s.index), s.description]);
30
- info("Stashes:");
31
- console.log(createTable(["#", "Description"], rows));
32
- return;
33
- }
34
-
35
- const _message = await input("Stash message (optional)");
36
- const result = await withSpinner("Stashing...", () => git.stash());
37
- success(`Stash saved: ${result}`);
38
- } catch (err) {
39
- error(
40
- `Stash operation failed: ${err instanceof Error ? err.message : String(err)}`,
41
- );
42
- }
43
- });
44
- }
1
+ import type { Command } from "commander";
2
+ import * as git from "../lib/git.js";
3
+ import { error, text } from "../lib/logger.js";
4
+ import { createTable, input, withSpinner } from "../lib/ui.js";
5
+
6
+ export default function register(program: Command): void {
7
+ program
8
+ .command("stash")
9
+ .description("Manage stashes")
10
+ .option("--pop", "Apply and remove latest stash")
11
+ .option("--list", "List all stashes")
12
+ .action(async (options) => {
13
+ try {
14
+ if (options.pop) {
15
+ const result = await withSpinner("Applying stash...", () =>
16
+ git.stashPop(),
17
+ );
18
+ text(`Stash popped: ${result}`);
19
+ return;
20
+ }
21
+
22
+ if (options.list) {
23
+ const stashes = await git.stashList();
24
+ if (stashes.length === 0) {
25
+ text("No stashes found.");
26
+ return;
27
+ }
28
+
29
+ const rows = stashes.map((s) => [String(s.index), s.description]);
30
+ text("Stashes:");
31
+ text(createTable(["#", "Description"], rows));
32
+ return;
33
+ }
34
+
35
+ const _message = await input("Stash message (optional)");
36
+ const result = await withSpinner("Stashing...", () => git.stash());
37
+ text(`Stash saved: ${result}`);
38
+ } catch (err) {
39
+ error(
40
+ `Stash operation failed: ${err instanceof Error ? err.message : String(err)}`,
41
+ );
42
+ }
43
+ });
44
+ }