Files
oh-my-pi/packages/git-tool/src/errors.ts
T
can1357 56e760f2bc feat(git-tool): added git-tool package with 22 operations and safety guards
- Added new @oh-my-pi/pi-git-tool package with 22 git operations, safety guards, caching, and GitHub CLI integration.
- Added /wt slash command for git worktree management with create, list, merge, remove, spawn, and parallel operations.
- Added worktree library with collapse strategies (simple, merge-base, rebase) and session tracking for agent tasks.
- Added structured git tool with TypeBox schema exposing gitTool and createGitTool from SDK.
- Added safety policies blocking force push to protected branches and warning on destructive operations.
2026-01-05 15:37:44 +01:00

85 lines
3.2 KiB
TypeScript

export enum GitErrorCode {
NOT_A_REPO = "NOT_A_REPO",
CONFLICT = "CONFLICT",
UNCOMMITTED_CHANGES = "UNCOMMITTED_CHANGES",
BRANCH_NOT_FOUND = "BRANCH_NOT_FOUND",
REF_NOT_FOUND = "REF_NOT_FOUND",
REMOTE_REJECTED = "REMOTE_REJECTED",
AUTH_FAILED = "AUTH_FAILED",
MERGE_CONFLICT = "MERGE_CONFLICT",
REBASE_CONFLICT = "REBASE_CONFLICT",
NOTHING_TO_COMMIT = "NOTHING_TO_COMMIT",
DETACHED_HEAD = "DETACHED_HEAD",
HOOK_FAILED = "HOOK_FAILED",
GH_NOT_INSTALLED = "GH_NOT_INSTALLED",
GH_AUTH_REQUIRED = "GH_AUTH_REQUIRED",
UNKNOWN = "UNKNOWN",
}
export class GitError extends Error {
code: GitErrorCode;
details?: Record<string, unknown>;
constructor(message: string, code: GitErrorCode, details?: Record<string, unknown>) {
super(message);
this.name = "GitError";
this.code = code;
this.details = details;
}
}
export function detectGitError(stderr: string, exitCode: number): GitError | null {
if (exitCode === 0) return null;
const normalized = stderr.toLowerCase();
if (normalized.includes("not a git repository")) {
return new GitError("Not a git repository", GitErrorCode.NOT_A_REPO);
}
if (normalized.includes("authentication failed") || normalized.includes("fatal: authentication")) {
return new GitError("Authentication failed", GitErrorCode.AUTH_FAILED);
}
if (normalized.includes("permission denied") || normalized.includes("access denied")) {
return new GitError("Authentication failed", GitErrorCode.AUTH_FAILED);
}
if (normalized.includes("nothing to commit")) {
return new GitError("Nothing to commit", GitErrorCode.NOTHING_TO_COMMIT);
}
if (normalized.includes("detached head")) {
return new GitError("Detached HEAD", GitErrorCode.DETACHED_HEAD);
}
if (normalized.includes("merge conflict") || normalized.includes("conflict")) {
return new GitError("Merge conflict", GitErrorCode.MERGE_CONFLICT);
}
if (normalized.includes("rebase")) {
return new GitError("Rebase conflict", GitErrorCode.REBASE_CONFLICT);
}
if (normalized.includes("unknown revision") || normalized.includes("bad revision")) {
return new GitError("Ref not found", GitErrorCode.REF_NOT_FOUND);
}
if (normalized.includes("pathspec") && normalized.includes("did not match")) {
return new GitError("Ref not found", GitErrorCode.REF_NOT_FOUND);
}
if (normalized.includes("hook") && normalized.includes("failed")) {
return new GitError("Hook failed", GitErrorCode.HOOK_FAILED);
}
if (normalized.includes("remote rejected") || normalized.includes("rejected")) {
return new GitError("Remote rejected", GitErrorCode.REMOTE_REJECTED);
}
return new GitError(stderr.trim() || "Unknown git error", GitErrorCode.UNKNOWN);
}
export function detectGhError(stderr: string, exitCode: number): GitError | null {
if (exitCode === 0) return null;
const normalized = stderr.toLowerCase();
if (normalized.includes("not logged") || normalized.includes("authentication required")) {
return new GitError("GitHub CLI authentication required", GitErrorCode.GH_AUTH_REQUIRED);
}
if (normalized.includes("gh: not found") || normalized.includes("gh: command not found")) {
return new GitError("GitHub CLI is not installed", GitErrorCode.GH_NOT_INSTALLED);
}
return new GitError(stderr.trim() || "GitHub CLI error", GitErrorCode.UNKNOWN);
}