git-it-done 1.0.1 → 1.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 (46) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +1 -1
  3. package/dist/index.js +26 -29
  4. package/dist/index.js.map +1 -1
  5. package/dist/utils/checkGitStatus.d.ts +1 -1
  6. package/dist/utils/checkGitStatus.js +40 -26
  7. package/dist/utils/checkGitStatus.js.map +1 -1
  8. package/dist/utils/commitMessage.d.ts +1 -1
  9. package/dist/utils/commitMessage.js +17 -23
  10. package/dist/utils/commitMessage.js.map +1 -1
  11. package/dist/utils/diffSignals.d.ts +22 -0
  12. package/dist/utils/diffSignals.js +75 -0
  13. package/dist/utils/diffSignals.js.map +1 -0
  14. package/dist/utils/displayStatus.d.ts +1 -1
  15. package/dist/utils/displayStatus.js +10 -16
  16. package/dist/utils/displayStatus.js.map +1 -1
  17. package/dist/utils/fileStaging.d.ts +1 -1
  18. package/dist/utils/fileStaging.js +84 -44
  19. package/dist/utils/fileStaging.js.map +1 -1
  20. package/dist/utils/formatFileStatus.js +14 -14
  21. package/dist/utils/formatFileStatus.js.map +1 -1
  22. package/dist/utils/generateCommitMessage.d.ts +13 -1
  23. package/dist/utils/generateCommitMessage.js +179 -90
  24. package/dist/utils/generateCommitMessage.js.map +1 -1
  25. package/dist/utils/getFileChanges.d.ts +15 -1
  26. package/dist/utils/getFileChanges.js +60 -22
  27. package/dist/utils/getFileChanges.js.map +1 -1
  28. package/dist/utils/gitCommand.d.ts +27 -1
  29. package/dist/utils/gitCommand.js +53 -13
  30. package/dist/utils/gitCommand.js.map +1 -1
  31. package/dist/utils/performCommit.js +39 -50
  32. package/dist/utils/performCommit.js.map +1 -1
  33. package/dist/utils/process_interruption.js +23 -17
  34. package/dist/utils/process_interruption.js.map +1 -1
  35. package/dist/utils/push_to_remote.js +56 -46
  36. package/dist/utils/push_to_remote.js.map +1 -1
  37. package/dist/utils/repoRoot.d.ts +6 -0
  38. package/dist/utils/repoRoot.js +10 -0
  39. package/dist/utils/repoRoot.js.map +1 -0
  40. package/dist/utils/types/types.d.ts +11 -1
  41. package/dist/utils/types/types.js +1 -2
  42. package/package.json +39 -8
  43. package/readme.md +298 -9
  44. package/dist/utils/isGitrepo.d.ts +0 -1
  45. package/dist/utils/isGitrepo.js +0 -9
  46. package/dist/utils/isGitrepo.js.map +0 -1
@@ -1,28 +1,66 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getChanges = getChanges;
4
- const gitCommand_1 = require("./gitCommand");
5
- // Get file changes
6
- function parseGitStatus(output, defaultStatus = '') {
7
- return output
8
- .split('\n')
9
- .filter(Boolean)
10
- .map(line => {
11
- if (defaultStatus) {
12
- return { status: defaultStatus, file: line };
1
+ import { gitCommand } from './gitCommand.js';
2
+ /**
3
+ * Parse `git diff --name-status -z` output.
4
+ *
5
+ * With `-z` every field is its own NUL-terminated record:
6
+ * `M\0path\0` for ordinary changes
7
+ * `R100\0oldPath\0newPath\0` for renames (and `C###` for copies)
8
+ *
9
+ * The similarity score is stripped from the status and the destination path is
10
+ * used for renames/copies, so downstream code never sees `R100` or a bogus
11
+ * `old\tnew` path.
12
+ */
13
+ export function parseNameStatusZ(output) {
14
+ const tokens = output.split('\0').filter(token => token.length > 0);
15
+ const changes = [];
16
+ for (let i = 0; i < tokens.length;) {
17
+ const raw = tokens[i++];
18
+ const status = raw.charAt(0).toUpperCase();
19
+ if (status === 'R' || status === 'C') {
20
+ const from = tokens[i++];
21
+ const to = tokens[i++];
22
+ if (from === undefined || to === undefined)
23
+ break;
24
+ changes.push({ status, file: to, from });
25
+ }
26
+ else {
27
+ const file = tokens[i++];
28
+ if (file === undefined)
29
+ break;
30
+ changes.push({ status, file });
13
31
  }
14
- const [status, ...fileParts] = line.split('\t');
15
- return { status, file: fileParts.join('\t') };
16
- });
32
+ }
33
+ return changes;
34
+ }
35
+ /** Parse a NUL-separated list of paths (e.g. `git ls-files -z`). */
36
+ export function parseNulList(output, status) {
37
+ return output
38
+ .split('\0')
39
+ .filter(file => file.length > 0)
40
+ .map(file => ({ status, file }));
41
+ }
42
+ function nameStatus(args) {
43
+ const result = gitCommand(args);
44
+ return result.ok ? parseNameStatusZ(result.stdout) : [];
17
45
  }
18
- function getChanges() {
19
- const stagedOutput = (0, gitCommand_1.gitCommand)('diff --cached --name-status') || '';
20
- const unstagedOutput = (0, gitCommand_1.gitCommand)('diff --name-status') || '';
21
- const untrackedOutput = (0, gitCommand_1.gitCommand)('ls-files --others --exclude-standard') || '';
46
+ export function getChanges() {
47
+ const staged = nameStatus(['diff', '--cached', '--name-status', '--find-renames', '-z']);
48
+ const unstaged = nameStatus(['diff', '--name-status', '--find-renames', '-z']);
49
+ // `--full-name` + `:/` keep untracked paths repo-root-relative like the diff
50
+ // output above, even when the tool is invoked from a subdirectory.
51
+ const untrackedResult = gitCommand([
52
+ 'ls-files',
53
+ '--others',
54
+ '--exclude-standard',
55
+ '--full-name',
56
+ '-z',
57
+ '--',
58
+ ':/'
59
+ ]);
22
60
  return {
23
- staged: parseGitStatus(stagedOutput),
24
- unstaged: parseGitStatus(unstagedOutput),
25
- untracked: parseGitStatus(untrackedOutput, '??')
61
+ staged,
62
+ unstaged,
63
+ untracked: untrackedResult.ok ? parseNulList(untrackedResult.stdout, '??') : []
26
64
  };
27
65
  }
28
66
  //# sourceMappingURL=getFileChanges.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"getFileChanges.js","sourceRoot":"","sources":["../../src/utils/getFileChanges.ts"],"names":[],"mappings":";;AAiBA,gCAUC;AA3BD,6CAA0C;AAG1C,mBAAmB;AACnB,SAAS,cAAc,CAAC,MAAc,EAAE,aAAa,GAAG,EAAE;IACxD,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,IAAI,CAAC,EAAE;QACV,IAAI,aAAa,EAAE,CAAC;YAClB,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QAC/C,CAAC;QACD,MAAM,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAChD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;AACP,CAAC;AAED,SAAgB,UAAU;IACxB,MAAM,YAAY,GAAG,IAAA,uBAAU,EAAC,6BAA6B,CAAC,IAAI,EAAE,CAAC;IACrE,MAAM,cAAc,GAAG,IAAA,uBAAU,EAAC,oBAAoB,CAAC,IAAI,EAAE,CAAC;IAC9D,MAAM,eAAe,GAAG,IAAA,uBAAU,EAAC,sCAAsC,CAAC,IAAI,EAAE,CAAC;IAEjF,OAAO;QACL,MAAM,EAAE,cAAc,CAAC,YAAY,CAAC;QACpC,QAAQ,EAAE,cAAc,CAAC,cAAc,CAAC;QACxC,SAAS,EAAE,cAAc,CAAC,eAAe,EAAE,IAAI,CAAC;KACjD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"getFileChanges.js","sourceRoot":"","sources":["../../src/utils/getFileChanges.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACpE,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,GAAI,CAAC;QACpC,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;QACxB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QAE3C,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;YACvB,IAAI,IAAI,KAAK,SAAS,IAAI,EAAE,KAAK,SAAS;gBAAE,MAAM;YAClD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,IAAI,IAAI,KAAK,SAAS;gBAAE,MAAM;YAC9B,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,MAAc;IACzD,OAAO,MAAM;SACV,KAAK,CAAC,IAAI,CAAC;SACX,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SAC/B,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,UAAU,CAAC,IAAc;IAChC,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAChC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,eAAe,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC;IACzF,MAAM,QAAQ,GAAG,UAAU,CAAC,CAAC,MAAM,EAAE,eAAe,EAAE,gBAAgB,EAAE,IAAI,CAAC,CAAC,CAAC;IAE/E,6EAA6E;IAC7E,mEAAmE;IACnE,MAAM,eAAe,GAAG,UAAU,CAAC;QACjC,UAAU;QACV,UAAU;QACV,oBAAoB;QACpB,aAAa;QACb,IAAI;QACJ,IAAI;QACJ,IAAI;KACL,CAAC,CAAC;IAEH,OAAO;QACL,MAAM;QACN,QAAQ;QACR,SAAS,EAAE,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,eAAe,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;KAChF,CAAC;AACJ,CAAC"}
@@ -1 +1,27 @@
1
- export declare function gitCommand(command: string): string | null;
1
+ export interface GitResult {
2
+ /** True when git exited with status 0. */
3
+ ok: boolean;
4
+ stdout: string;
5
+ stderr: string;
6
+ status: number | null;
7
+ /** True when the output exceeded `maxBuffer` and was therefore truncated. */
8
+ oversized: boolean;
9
+ }
10
+ export interface GitOptions {
11
+ /** Defaults to 64 MiB (Node's default of 1 MiB truncates large diffs). */
12
+ maxBuffer?: number;
13
+ cwd?: string;
14
+ input?: string;
15
+ }
16
+ /** 64 MiB — big enough for realistic diffs, small enough to stay a guard rail. */
17
+ export declare const DEFAULT_MAX_BUFFER: number;
18
+ /**
19
+ * Run git with an argv array. Never goes through a shell, so file names and
20
+ * commit messages containing `$`, backticks, `!`, quotes or newlines are passed
21
+ * through verbatim instead of being interpreted by /bin/sh.
22
+ */
23
+ export declare function gitCommand(args: string[], options?: GitOptions): GitResult;
24
+ /** Convenience wrapper for the common "give me the trimmed stdout" case. */
25
+ export declare function gitOutput(args: string[], options?: GitOptions): string | null;
26
+ /** Best-effort explanation of a failed git invocation, for display to the user. */
27
+ export declare function gitErrorText(result: GitResult): string;
@@ -1,17 +1,57 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.gitCommand = gitCommand;
4
- const child_process_1 = require("child_process");
5
- // Utility function to execute git commands with better error handling
6
- function gitCommand(command) {
7
- try {
8
- return (0, child_process_1.execSync)(`git ${command}`, {
9
- encoding: 'utf-8',
10
- stdio: 'pipe'
11
- }).trim();
1
+ import { spawnSync } from 'child_process';
2
+ /** 64 MiB — big enough for realistic diffs, small enough to stay a guard rail. */
3
+ export const DEFAULT_MAX_BUFFER = 64 * 1024 * 1024;
4
+ /**
5
+ * Run git with an argv array. Never goes through a shell, so file names and
6
+ * commit messages containing `$`, backticks, `!`, quotes or newlines are passed
7
+ * through verbatim instead of being interpreted by /bin/sh.
8
+ */
9
+ export function gitCommand(args, options = {}) {
10
+ var _a, _b, _c;
11
+ const result = spawnSync('git', args, {
12
+ encoding: 'utf-8',
13
+ maxBuffer: (_a = options.maxBuffer) !== null && _a !== void 0 ? _a : DEFAULT_MAX_BUFFER,
14
+ cwd: options.cwd,
15
+ input: options.input
16
+ });
17
+ const stdout = (_b = result.stdout) !== null && _b !== void 0 ? _b : '';
18
+ const stderr = (_c = result.stderr) !== null && _c !== void 0 ? _c : '';
19
+ if (result.error) {
20
+ const code = result.error.code;
21
+ return {
22
+ ok: false,
23
+ stdout,
24
+ stderr: stderr || result.error.message,
25
+ status: result.status,
26
+ oversized: code === 'ENOBUFS'
27
+ };
12
28
  }
13
- catch (_a) {
14
- return null;
29
+ return {
30
+ ok: result.status === 0,
31
+ stdout,
32
+ stderr,
33
+ status: result.status,
34
+ oversized: false
35
+ };
36
+ }
37
+ /** Convenience wrapper for the common "give me the trimmed stdout" case. */
38
+ export function gitOutput(args, options = {}) {
39
+ const result = gitCommand(args, options);
40
+ return result.ok ? result.stdout.trim() : null;
41
+ }
42
+ /** Best-effort explanation of a failed git invocation, for display to the user. */
43
+ export function gitErrorText(result) {
44
+ var _a;
45
+ const text = [result.stderr, result.stdout]
46
+ .map(part => part.trim())
47
+ .filter(Boolean)
48
+ .join('\n');
49
+ if (text) {
50
+ return text;
51
+ }
52
+ if (result.oversized) {
53
+ return 'git produced more output than could be buffered';
15
54
  }
55
+ return `git exited with status ${(_a = result.status) !== null && _a !== void 0 ? _a : 'unknown'}`;
16
56
  }
17
57
  //# sourceMappingURL=gitCommand.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"gitCommand.js","sourceRoot":"","sources":["../../src/utils/gitCommand.ts"],"names":[],"mappings":";;AAGA,gCASC;AAZD,iDAAyC;AAEzC,sEAAsE;AACtE,SAAgB,UAAU,CAAC,OAAe;IACxC,IAAI,CAAC;QACH,OAAO,IAAA,wBAAQ,EAAC,OAAO,OAAO,EAAE,EAAE;YAChC,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM;SACd,CAAC,CAAC,IAAI,EAAE,CAAC;IACZ,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"gitCommand.js","sourceRoot":"","sources":["../../src/utils/gitCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAmB1C,kFAAkF;AAClF,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEnD;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAc,EAAE,UAAsB,EAAE;;IACjE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE;QACpC,QAAQ,EAAE,OAAO;QACjB,SAAS,EAAE,MAAA,OAAO,CAAC,SAAS,mCAAI,kBAAkB;QAClD,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,MAAM,mCAAI,EAAE,CAAC;IACnC,MAAM,MAAM,GAAG,MAAA,MAAM,CAAC,MAAM,mCAAI,EAAE,CAAC;IAEnC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,MAAM,IAAI,GAAI,MAAM,CAAC,KAA+B,CAAC,IAAI,CAAC;QAC1D,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM;YACN,MAAM,EAAE,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,OAAO;YACtC,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,SAAS,EAAE,IAAI,KAAK,SAAS;SAC9B,CAAC;IACJ,CAAC;IAED,OAAO;QACL,EAAE,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QACvB,MAAM;QACN,MAAM;QACN,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,SAAS,EAAE,KAAK;KACjB,CAAC;AACJ,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,SAAS,CAAC,IAAc,EAAE,UAAsB,EAAE;IAChE,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,YAAY,CAAC,MAAiB;;IAC5C,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;SACxC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SACxB,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACrB,OAAO,iDAAiD,CAAC;IAC3D,CAAC;IACD,OAAO,0BAA0B,MAAA,MAAM,CAAC,MAAM,mCAAI,SAAS,EAAE,CAAC;AAChE,CAAC"}
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,72 +7,62 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
8
  });
10
9
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.performCommit = performCommit;
16
- const prompts_1 = require("@clack/prompts");
17
- const chalk_1 = __importDefault(require("chalk"));
18
- const gitCommand_1 = require("./gitCommand");
19
- function performCommit(commitMessage) {
10
+ import { confirm, spinner, cancel, isCancel } from '@clack/prompts';
11
+ import chalk from 'chalk';
12
+ import { gitCommand, gitErrorText, gitOutput } from './gitCommand.js';
13
+ export function performCommit(commitMessage) {
20
14
  return __awaiter(this, void 0, void 0, function* () {
21
15
  // Confirm commit
22
- const shouldCommit = yield (0, prompts_1.confirm)({
16
+ const shouldCommit = yield confirm({
23
17
  message: `Commit with message: "${commitMessage}"?`
24
18
  });
25
- if ((0, prompts_1.isCancel)(shouldCommit) || !shouldCommit) {
26
- (0, prompts_1.cancel)('Commit cancelled');
19
+ if (isCancel(shouldCommit) || !shouldCommit) {
20
+ cancel('Commit cancelled');
27
21
  return false;
28
22
  }
29
23
  // Execute commit
30
- const s = (0, prompts_1.spinner)();
24
+ const s = spinner();
31
25
  s.start('Committing changes...');
32
- try {
33
- const success = executeCommit(commitMessage);
34
- if (!success) {
35
- s.stop('❌ Commit failed');
36
- (0, prompts_1.cancel)('Failed to commit changes. Please check your git status.');
37
- return false;
38
- }
39
- // Verify commit was created
40
- const lastCommit = (0, gitCommand_1.gitCommand)('log -1 --oneline');
41
- if (!lastCommit) {
42
- s.stop('⚠️ Commit status unclear');
43
- console.log(chalk_1.default.yellow('Commit may not have been created. Please check git status manually.'));
44
- return false;
45
- }
46
- else {
47
- s.stop('✅ Changes committed successfully!');
48
- console.log(chalk_1.default.dim(`Last commit: ${lastCommit}`));
49
- return true;
50
- }
51
- }
52
- catch (error) {
26
+ // The message is passed as a single argv entry — no shell, so `$(id)`,
27
+ // backticks and `!` reach git verbatim.
28
+ const result = gitCommand(['commit', '-m', commitMessage]);
29
+ if (!result.ok) {
53
30
  s.stop('❌ Commit failed');
54
- handleCommitError(error);
31
+ handleCommitError(result);
32
+ return false;
33
+ }
34
+ // Verify commit was created
35
+ const lastCommit = gitOutput(['log', '-1', '--oneline']);
36
+ if (!lastCommit) {
37
+ s.stop('⚠️ Commit status unclear');
38
+ console.log(chalk.yellow('Commit may not have been created. Please check git status manually.'));
55
39
  return false;
56
40
  }
41
+ s.stop('✅ Changes committed successfully!');
42
+ console.log(chalk.dim(`Last commit: ${lastCommit}`));
43
+ return true;
57
44
  });
58
45
  }
59
- function executeCommit(commitMessage) {
60
- const escapedMessage = JSON.stringify(commitMessage);
61
- const result = (0, gitCommand_1.gitCommand)(`commit -m ${escapedMessage}`);
62
- return result !== null;
63
- }
64
- function handleCommitError(error) {
65
- const msg = error.message || '';
66
- if (msg.includes('nothing to commit')) {
67
- (0, prompts_1.cancel)('Nothing to commit - working tree clean');
46
+ function handleCommitError(result) {
47
+ const details = gitErrorText(result);
48
+ // Always surface git's own output — pre-commit hook rejections and commitlint
49
+ // failures only ever explain themselves there.
50
+ console.log(chalk.red('\nGit reported:'));
51
+ console.log(chalk.dim(details));
52
+ if (/nothing to commit|no changes added to commit/i.test(details)) {
53
+ cancel('Nothing to commit - working tree clean');
54
+ }
55
+ else if (/Please tell me who you are/i.test(details)) {
56
+ cancel('Git user not configured. Run: git config --global user.email "you@example.com"');
68
57
  }
69
- else if (msg.includes('Please tell me who you are')) {
70
- (0, prompts_1.cancel)('Git user not configured. Run: git config --global user.email "you@example.com"');
58
+ else if (/not a git repository/i.test(details)) {
59
+ cancel('Not in a git repository');
71
60
  }
72
- else if (msg.includes('not a git repository')) {
73
- (0, prompts_1.cancel)('Not in a git repository');
61
+ else if (result.status === 1 && /hook|husky|commitlint/i.test(details)) {
62
+ cancel('A git hook rejected the commit (see output above)');
74
63
  }
75
64
  else {
76
- (0, prompts_1.cancel)(`Failed to commit: ${msg}`);
65
+ cancel('Failed to commit changes (see output above)');
77
66
  }
78
67
  }
79
68
  //# sourceMappingURL=performCommit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"performCommit.js","sourceRoot":"","sources":["../../src/utils/performCommit.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAIA,sCAyCC;AA7CD,4CAAoE;AACpE,kDAA0B;AAC1B,6CAA0C;AAE1C,SAAsB,aAAa,CAAC,aAAqB;;QACvD,iBAAiB;QACjB,MAAM,YAAY,GAAG,MAAM,IAAA,iBAAO,EAAC;YACjC,OAAO,EAAE,yBAAyB,aAAa,IAAI;SACpD,CAAC,CAAC;QAEH,IAAI,IAAA,kBAAQ,EAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC5C,IAAA,gBAAM,EAAC,kBAAkB,CAAC,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,iBAAiB;QACjB,MAAM,CAAC,GAAG,IAAA,iBAAO,GAAE,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAEjC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;YAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;gBAC1B,IAAA,gBAAM,EAAC,yDAAyD,CAAC,CAAC;gBAClE,OAAO,KAAK,CAAC;YACf,CAAC;YAED,4BAA4B;YAC5B,MAAM,UAAU,GAAG,IAAA,uBAAU,EAAC,kBAAkB,CAAC,CAAC;YAClD,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;gBACpC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,qEAAqE,CAAC,CAAC,CAAC;gBACjG,OAAO,KAAK,CAAC;YACf,CAAC;iBAAM,CAAC;gBACN,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC,CAAC;gBACrD,OAAO,IAAI,CAAC;YACd,CAAC;QAEH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC1B,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACzB,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CAAA;AAED,SAAS,aAAa,CAAC,aAAqB;IAC1C,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,IAAA,uBAAU,EAAC,aAAa,cAAc,EAAE,CAAC,CAAC;IACzD,OAAO,MAAM,KAAK,IAAI,CAAC;AACzB,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAU;IACnC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC;IAEhC,IAAI,GAAG,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACtC,IAAA,gBAAM,EAAC,wCAAwC,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,CAAC;QACtD,IAAA,gBAAM,EAAC,gFAAgF,CAAC,CAAC;IAC3F,CAAC;SAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE,CAAC;QAChD,IAAA,gBAAM,EAAC,yBAAyB,CAAC,CAAC;IACpC,CAAC;SAAM,CAAC;QACN,IAAA,gBAAM,EAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;IACrC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"performCommit.js","sourceRoot":"","sources":["../../src/utils/performCommit.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAa,MAAM,iBAAiB,CAAC;AAEjF,MAAM,UAAgB,aAAa,CAAC,aAAqB;;QACvD,iBAAiB;QACjB,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC;YACjC,OAAO,EAAE,yBAAyB,aAAa,IAAI;SACpD,CAAC,CAAC;QAEH,IAAI,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YAC5C,MAAM,CAAC,kBAAkB,CAAC,CAAC;YAC3B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,iBAAiB;QACjB,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;QACpB,CAAC,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC;QAEjC,uEAAuE;QACvE,wCAAwC;QACxC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC;QAE3D,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAC1B,iBAAiB,CAAC,MAAM,CAAC,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4BAA4B;QAC5B,MAAM,UAAU,GAAG,SAAS,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,CAAC,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,qEAAqE,CAAC,CAAC,CAAC;YACjG,OAAO,KAAK,CAAC;QACf,CAAC;QAED,CAAC,CAAC,IAAI,CAAC,mCAAmC,CAAC,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,UAAU,EAAE,CAAC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC;IACd,CAAC;CAAA;AAED,SAAS,iBAAiB,CAAC,MAAiB;IAC1C,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAErC,8EAA8E;IAC9E,+CAA+C;IAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IAEhC,IAAI,+CAA+C,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QAClE,MAAM,CAAC,wCAAwC,CAAC,CAAC;IACnD,CAAC;SAAM,IAAI,6BAA6B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,MAAM,CAAC,gFAAgF,CAAC,CAAC;IAC3F,CAAC;SAAM,IAAI,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjD,MAAM,CAAC,yBAAyB,CAAC,CAAC;IACpC,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,wBAAwB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACzE,MAAM,CAAC,mDAAmD,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,MAAM,CAAC,6CAA6C,CAAC,CAAC;IACxD,CAAC;AACH,CAAC"}
@@ -1,20 +1,26 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = start;
4
- const prompts_1 = require("@clack/prompts");
5
- function start(main) {
6
- process.on('SIGINT', () => {
7
- (0, prompts_1.cancel)('Operation cancelled by user');
8
- process.exit(0);
9
- });
10
- process.on('SIGTERM', () => {
11
- (0, prompts_1.cancel)('Operation terminated');
12
- process.exit(0);
13
- });
14
- main().catch((error) => {
15
- (0, prompts_1.cancel)('An unexpected error occurred');
1
+ import { cancel } from '@clack/prompts';
2
+ const SHOW_CURSOR = '\u001B[?25h';
3
+ /** clack hides the cursor while a prompt/spinner is active; bring it back. */
4
+ function restoreCursor() {
5
+ if (process.stdout.isTTY) {
6
+ process.stdout.write(SHOW_CURSOR);
7
+ }
8
+ }
9
+ function exitWith(code, message, error) {
10
+ restoreCursor();
11
+ cancel(message);
12
+ if (error !== undefined) {
16
13
  console.error(error instanceof Error ? error.stack || error.message : error);
17
- process.exit(1);
18
- });
14
+ }
15
+ process.exit(code);
16
+ }
17
+ export default function start(main) {
18
+ // 128 + signal number, so CI wrappers do not read Ctrl+C as success.
19
+ process.on('SIGINT', () => exitWith(130, 'Operation cancelled by user'));
20
+ process.on('SIGTERM', () => exitWith(143, 'Operation terminated'));
21
+ process.on('unhandledRejection', (reason) => exitWith(1, 'An unexpected error occurred (unhandled rejection)', reason));
22
+ process.on('uncaughtException', (error) => exitWith(1, 'An unexpected error occurred (uncaught exception)', error));
23
+ process.on('exit', restoreCursor);
24
+ main().catch((error) => exitWith(1, 'An unexpected error occurred', error));
19
25
  }
20
26
  //# sourceMappingURL=process_interruption.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"process_interruption.js","sourceRoot":"","sources":["../../src/utils/process_interruption.ts"],"names":[],"mappings":";;AAEA,wBAgBC;AAlBD,4CAAwC;AAExC,SAAwB,KAAK,CAAC,IAAyB;IACrD,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,IAAA,gBAAM,EAAC,6BAA6B,CAAC,CAAC;QACtC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;QACzB,IAAA,gBAAM,EAAC,sBAAsB,CAAC,CAAC;QAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC9B,IAAA,gBAAM,EAAC,8BAA8B,CAAC,CAAC;QACvC,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC7E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"process_interruption.js","sourceRoot":"","sources":["../../src/utils/process_interruption.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAExC,MAAM,WAAW,GAAG,aAAa,CAAC;AAElC,8EAA8E;AAC9E,SAAS,aAAa;IACpB,IAAI,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY,EAAE,OAAe,EAAE,KAAe;IAC9D,aAAa,EAAE,CAAC;IAChB,MAAM,CAAC,OAAO,CAAC,CAAC;IAChB,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,IAAyB;IACrD,qEAAqE;IACrE,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,6BAA6B,CAAC,CAAC,CAAC;IACzE,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAEnE,OAAO,CAAC,EAAE,CAAC,oBAAoB,EAAE,CAAC,MAAe,EAAE,EAAE,CACnD,QAAQ,CAAC,CAAC,EAAE,oDAAoD,EAAE,MAAM,CAAC,CAC1E,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,mBAAmB,EAAE,CAAC,KAAc,EAAE,EAAE,CACjD,QAAQ,CAAC,CAAC,EAAE,mDAAmD,EAAE,KAAK,CAAC,CACxE,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAElC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,8BAA8B,EAAE,KAAK,CAAC,CAAC,CAAC;AACvF,CAAC"}
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
2
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
3
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -8,61 +7,72 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
8
  });
10
9
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.handlePushToRemote = handlePushToRemote;
16
- const prompts_1 = require("@clack/prompts");
17
- const chalk_1 = __importDefault(require("chalk"));
18
- const gitCommand_1 = require("./gitCommand");
19
- function handlePushToRemote() {
10
+ import { confirm, spinner, isCancel } from '@clack/prompts';
11
+ import chalk from 'chalk';
12
+ import { gitCommand, gitErrorText, gitOutput } from './gitCommand.js';
13
+ const PROTECTED_BRANCHES = new Set(['main', 'master', 'production', 'release']);
14
+ export function handlePushToRemote() {
20
15
  return __awaiter(this, void 0, void 0, function* () {
21
- const shouldPush = yield (0, prompts_1.confirm)({
22
- message: 'Push to remote repository?'
23
- });
24
- if ((0, prompts_1.isCancel)(shouldPush) || !shouldPush) {
16
+ var _a;
17
+ const remotes = ((_a = gitOutput(['remote'])) !== null && _a !== void 0 ? _a : '').split('\n').filter(Boolean);
18
+ if (remotes.length === 0) {
19
+ console.log(chalk.yellow('⚠️ No remote repository configured. Skipping push.'));
25
20
  return;
26
21
  }
27
- yield executePush();
28
- });
29
- }
30
- function executePush() {
31
- return __awaiter(this, void 0, void 0, function* () {
32
- const pushSpinner = (0, prompts_1.spinner)();
33
- pushSpinner.start('Pushing to remote...');
34
- // Check if remote exists
35
- const remotes = (0, gitCommand_1.gitCommand)('remote');
36
- if (!remotes) {
37
- pushSpinner.stop('⚠️ No remote repository configured');
38
- console.log(chalk_1.default.yellow('No remote repository found. Skipping push.'));
22
+ const branch = gitOutput(['rev-parse', '--abbrev-ref', 'HEAD']);
23
+ if (!branch || branch === 'HEAD') {
24
+ console.log(chalk.yellow('⚠️ HEAD is detached — not pushing. Create a branch first.'));
39
25
  return;
40
26
  }
41
- try {
42
- const pushResult = (0, gitCommand_1.gitCommand)('push');
43
- if (pushResult !== null) {
44
- pushSpinner.stop('🚀 Changes pushed successfully!');
45
- }
46
- else {
47
- pushSpinner.stop('❌ Push failed');
48
- handlePushFailure();
49
- }
27
+ const upstream = gitOutput(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}']);
28
+ const remote = upstream ? upstream.split('/')[0] : remotes.includes('origin') ? 'origin' : remotes[0];
29
+ const target = { branch, remote, upstream };
30
+ if (PROTECTED_BRANCHES.has(branch.toLowerCase())) {
31
+ console.log(chalk.yellow.bold(`\n⚠️ You are about to push directly to "${branch}".`));
32
+ }
33
+ if (!upstream) {
34
+ console.log(chalk.yellow(`ℹ️ "${branch}" has no upstream; it will be created as ${remote}/${branch}.`));
50
35
  }
51
- catch (error) {
52
- pushSpinner.stop('❌ Push failed');
53
- console.log(chalk_1.default.red('Failed to push. Error details:'));
54
- console.log(chalk_1.default.dim(error.message));
36
+ const shouldPush = yield confirm({
37
+ message: upstream
38
+ ? `Push to ${upstream}?`
39
+ : `Push to ${remote}/${branch} and set it as upstream?`
40
+ });
41
+ if (isCancel(shouldPush) || !shouldPush) {
42
+ return;
55
43
  }
44
+ executePush(target);
56
45
  });
57
46
  }
58
- function handlePushFailure() {
59
- console.log(chalk_1.default.red('Failed to push. You may need to set upstream branch.'));
60
- const branch = (0, gitCommand_1.gitCommand)('rev-parse --abbrev-ref HEAD');
61
- if (branch) {
62
- console.log(chalk_1.default.dim(`Try: git push --set-upstream origin ${branch}`));
47
+ function executePush(target) {
48
+ const pushSpinner = spinner();
49
+ pushSpinner.start(`Pushing to ${target.remote}/${target.branch}...`);
50
+ const args = target.upstream
51
+ ? ['push']
52
+ : ['push', '--set-upstream', target.remote, target.branch];
53
+ const result = gitCommand(args);
54
+ if (result.ok) {
55
+ pushSpinner.stop('🚀 Changes pushed successfully!');
56
+ const summary = gitErrorText(result);
57
+ if (summary) {
58
+ console.log(chalk.dim(summary));
59
+ }
60
+ return;
61
+ }
62
+ pushSpinner.stop('❌ Push failed');
63
+ handlePushFailure(target, gitErrorText(result));
64
+ }
65
+ function handlePushFailure(target, details) {
66
+ console.log(chalk.red('\nGit reported:'));
67
+ console.log(chalk.dim(details));
68
+ if (/non-fast-forward|fetch first|behind its remote/i.test(details)) {
69
+ console.log(chalk.yellow(`Remote has commits you don't. Try: git pull --rebase ${target.remote} ${target.branch}`));
70
+ }
71
+ else if (/Authentication failed|could not read Username|Permission denied|403/i.test(details)) {
72
+ console.log(chalk.yellow('Authentication failed — check your credentials or SSH key.'));
63
73
  }
64
- else {
65
- console.log(chalk_1.default.dim('Try: git push --set-upstream origin <branch-name>'));
74
+ else if (/protected branch|pre-receive hook declined/i.test(details)) {
75
+ console.log(chalk.yellow('The remote rejected the push (protected branch or server-side hook).'));
66
76
  }
67
77
  }
68
78
  //# sourceMappingURL=push_to_remote.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"push_to_remote.js","sourceRoot":"","sources":["../../src/utils/push_to_remote.ts"],"names":[],"mappings":";;;;;;;;;;;;;;AAIA,gDAUC;AAdD,4CAA4D;AAC5D,kDAA0B;AAC1B,6CAA0C;AAE1C,SAAsB,kBAAkB;;QACtC,MAAM,UAAU,GAAG,MAAM,IAAA,iBAAO,EAAC;YAC/B,OAAO,EAAE,4BAA4B;SACtC,CAAC,CAAC;QAEH,IAAI,IAAA,kBAAQ,EAAC,UAAU,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACxC,OAAO;QACT,CAAC;QAED,MAAM,WAAW,EAAE,CAAC;IACtB,CAAC;CAAA;AAED,SAAe,WAAW;;QACxB,MAAM,WAAW,GAAG,IAAA,iBAAO,GAAE,CAAC;QAC9B,WAAW,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAE1C,yBAAyB;QACzB,MAAM,OAAO,GAAG,IAAA,uBAAU,EAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,WAAW,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;YACxD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,4CAA4C,CAAC,CAAC,CAAC;YACxE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,IAAA,uBAAU,EAAC,MAAM,CAAC,CAAC;YAEtC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;gBACxB,WAAW,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;gBAClC,iBAAiB,EAAE,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC,CAAC;YACzD,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;CAAA;AAED,SAAS,iBAAiB;IACxB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC,CAAC;IAE/E,MAAM,MAAM,GAAG,IAAA,uBAAU,EAAC,6BAA6B,CAAC,CAAC;IACzD,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,uCAAuC,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1E,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,GAAG,CAAC,mDAAmD,CAAC,CAAC,CAAC;IAC9E,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"push_to_remote.js","sourceRoot":"","sources":["../../src/utils/push_to_remote.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Absolute path of the repository root, or null when it cannot be resolved.
3
+ * Used so staging operates on the same (repo-root-relative) set of paths that
4
+ * the status display shows, no matter which subdirectory the tool was run from.
5
+ */
6
+ export declare function getRepoRoot(): string | null;
@@ -0,0 +1,10 @@
1
+ import { gitOutput } from './gitCommand.js';
2
+ /**
3
+ * Absolute path of the repository root, or null when it cannot be resolved.
4
+ * Used so staging operates on the same (repo-root-relative) set of paths that
5
+ * the status display shows, no matter which subdirectory the tool was run from.
6
+ */
7
+ export function getRepoRoot() {
8
+ return gitOutput(['rev-parse', '--show-toplevel']);
9
+ }
10
+ //# sourceMappingURL=repoRoot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoRoot.js","sourceRoot":"","sources":["../../src/utils/repoRoot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC;AACrD,CAAC"}
@@ -1,6 +1,10 @@
1
1
  export interface FileChange {
2
+ /** Single-letter git status: A, M, D, R, C, T, U or `??` for untracked. */
2
3
  status: string;
4
+ /** Repo-root-relative path. For renames/copies this is the destination. */
3
5
  file: string;
6
+ /** Source path, present only for renames and copies. */
7
+ from?: string;
4
8
  }
5
9
  export interface GitChanges {
6
10
  staged: FileChange[];
@@ -10,8 +14,14 @@ export interface GitChanges {
10
14
  export interface GitStatus {
11
15
  valid: boolean;
12
16
  reason?: string;
17
+ /** Non-fatal problems worth shouting about (e.g. detached HEAD). */
18
+ warnings?: string[];
13
19
  }
14
- export type CommitType = 'feat' | 'fix' | 'docs' | 'style' | 'refactor' | 'test' | 'chore' | 'deps' | 'config' | 'remove';
20
+ /**
21
+ * Conventional Commits types only — anything outside this list is rejected by a
22
+ * standard commitlint `commit-msg` hook.
23
+ */
24
+ export type CommitType = 'feat' | 'fix' | 'docs' | 'style' | 'refactor' | 'perf' | 'test' | 'build' | 'ci' | 'chore' | 'revert';
15
25
  export interface CommitInfo {
16
26
  type: CommitType;
17
27
  scope?: string;
@@ -1,3 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
3
2
  //# sourceMappingURL=types.js.map