@mbluemer_2/gittyup 0.1.2 → 0.1.8

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.
@@ -1,206 +0,0 @@
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 () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.resolveWorktreeAddInput = resolveWorktreeAddInput;
37
- exports.resolveWorktreeRemoveInput = resolveWorktreeRemoveInput;
38
- exports.resolveTmuxLaunchInput = resolveTmuxLaunchInput;
39
- const readline = __importStar(require("node:readline/promises"));
40
- const config_1 = require("./config");
41
- const errors_1 = require("./errors");
42
- const process_1 = require("./process");
43
- const projects_1 = require("./projects");
44
- const tmux_1 = require("./tmux");
45
- function isInteractiveTerminal() {
46
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
47
- }
48
- async function promptText(message) {
49
- const terminal = readline.createInterface({
50
- input: process.stdin,
51
- output: process.stdout,
52
- });
53
- try {
54
- return (await terminal.question(message)).trim();
55
- }
56
- finally {
57
- terminal.close();
58
- }
59
- }
60
- async function selectFromList(prompt, values) {
61
- try {
62
- const selection = await (0, process_1.runCommand)('fzf', ['--prompt', prompt], {
63
- stdin: `${values.join('\n')}\n`,
64
- });
65
- return selection.trim();
66
- }
67
- catch (error) {
68
- const message = error instanceof errors_1.CliError ? error.message : '';
69
- if (message.includes('exit code 130')) {
70
- throw new errors_1.CliError('No project selected.');
71
- }
72
- throw error;
73
- }
74
- }
75
- const defaultServices = {
76
- checkFzfAvailable: tmux_1.checkFzfAvailable,
77
- discoverProjects: projects_1.discoverProjects,
78
- listProjectWorktrees: projects_1.listProjectWorktrees,
79
- isInteractive: isInteractiveTerminal,
80
- promptText,
81
- selectFromList,
82
- };
83
- async function selectProject(rootDir, services) {
84
- await services.checkFzfAvailable();
85
- const projects = await services.discoverProjects(rootDir);
86
- if (projects.length === 0) {
87
- throw new errors_1.CliError(`No projects found under ${rootDir}.`);
88
- }
89
- return services.selectFromList('project> ', projects.map((project) => project.name));
90
- }
91
- async function selectWorktree(options, services) {
92
- await services.checkFzfAvailable();
93
- const worktrees = options.projectName
94
- ? await services.listProjectWorktrees(options.rootDir, options.projectName)
95
- : (await Promise.all((await services.discoverProjects(options.rootDir)).map(async (project) => (await services.listProjectWorktrees(options.rootDir, project.name)).map((worktree) => ({
96
- ...worktree,
97
- project: project.name,
98
- }))))).flat();
99
- const filteredWorktrees = options.includeWorktree
100
- ? worktrees.filter(options.includeWorktree)
101
- : worktrees;
102
- if (filteredWorktrees.length === 0) {
103
- throw new errors_1.CliError(options.emptyMessage);
104
- }
105
- try {
106
- const selection = await services.selectFromList('worktree> ', filteredWorktrees.map((worktree) => buildWorktreeLabel(worktree, options.projectName)));
107
- const selected = filteredWorktrees.find((worktree) => buildWorktreeLabel(worktree, options.projectName) === selection);
108
- if (!selected) {
109
- throw new errors_1.CliError('Selected worktree was not found.');
110
- }
111
- const projectName = selected.project ?? options.projectName;
112
- if (!projectName) {
113
- throw new errors_1.CliError('Selected worktree did not include a project.');
114
- }
115
- return {
116
- projectName,
117
- alias: selected.alias,
118
- };
119
- }
120
- catch (error) {
121
- const message = error instanceof errors_1.CliError ? error.message : '';
122
- if (message === 'No project selected.') {
123
- throw new errors_1.CliError('No worktree selected.');
124
- }
125
- throw error;
126
- }
127
- }
128
- function buildWorktreeLabel(worktree, fallbackProject) {
129
- const project = worktree.project ?? fallbackProject;
130
- if (!project) {
131
- return worktree.alias;
132
- }
133
- return `${project}:${worktree.alias}`;
134
- }
135
- async function resolveWorktreeAddInput(options, services = defaultServices) {
136
- let { projectName, branch } = options;
137
- if (projectName && branch) {
138
- return {
139
- projectName,
140
- branch: (0, config_1.validateBranchName)(branch),
141
- };
142
- }
143
- if (!services.isInteractive()) {
144
- throw new errors_1.CliError('worktree add requires <project> and <branch>, or an interactive terminal when omitted.');
145
- }
146
- if (!projectName) {
147
- projectName = await selectProject(options.rootDir, services);
148
- }
149
- if (!branch) {
150
- branch = await services.promptText('Branch name: ');
151
- }
152
- return {
153
- projectName,
154
- branch: (0, config_1.validateBranchName)(branch),
155
- };
156
- }
157
- async function resolveWorktreeRemoveInput(options, services = defaultServices) {
158
- let { projectName, alias } = options;
159
- if (projectName && alias) {
160
- return { projectName, alias };
161
- }
162
- if (!services.isInteractive()) {
163
- throw new errors_1.CliError('worktree remove requires <project> and <alias>, or an interactive terminal when omitted.');
164
- }
165
- if (!alias) {
166
- const selection = await selectWorktree({
167
- rootDir: options.rootDir,
168
- projectName,
169
- emptyMessage: projectName
170
- ? `No linked worktrees found in project '${projectName}'.`
171
- : `No linked worktrees found under ${options.rootDir}.`,
172
- includeWorktree: (worktree) => worktree.alias !== config_1.MAIN_WORKTREE_ALIAS,
173
- }, services);
174
- projectName = selection.projectName;
175
- alias = selection.alias;
176
- }
177
- if (!projectName) {
178
- throw new errors_1.CliError('Selected worktree did not include a project.');
179
- }
180
- return { projectName, alias };
181
- }
182
- async function resolveTmuxLaunchInput(options, services = defaultServices) {
183
- const { projectName, alias } = options;
184
- if (projectName && alias) {
185
- return { projectName, alias };
186
- }
187
- if (!services.isInteractive()) {
188
- throw new errors_1.CliError('tmux launch requires <project> and [worktree], or an interactive terminal when omitted.');
189
- }
190
- if (!projectName) {
191
- const selection = await selectWorktree({
192
- rootDir: options.rootDir,
193
- emptyMessage: `No linked worktrees found under ${options.rootDir}.`,
194
- }, services);
195
- return selection;
196
- }
197
- if (!alias) {
198
- const selection = await selectWorktree({
199
- rootDir: options.rootDir,
200
- projectName,
201
- emptyMessage: `No linked worktrees found in project '${projectName}'.`,
202
- }, services);
203
- return selection;
204
- }
205
- return { projectName, alias };
206
- }
package/dist/metadata.js DELETED
@@ -1,83 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getProjectInitRecord = getProjectInitRecord;
4
- exports.setProjectInitCommand = setProjectInitCommand;
5
- exports.clearProjectInitCommand = clearProjectInitCommand;
6
- const promises_1 = require("node:fs/promises");
7
- const config_1 = require("./config");
8
- const errors_1 = require("./errors");
9
- function normalizeInitCommand(value) {
10
- if (value === undefined || value === null) {
11
- return null;
12
- }
13
- if (typeof value !== 'string') {
14
- throw new errors_1.CliError('Project init command must be a string when configured.');
15
- }
16
- const trimmed = value.trim();
17
- if (trimmed.length === 0) {
18
- throw new errors_1.CliError('Project init command cannot be empty.');
19
- }
20
- return trimmed;
21
- }
22
- async function pathExists(targetPath) {
23
- try {
24
- await (0, promises_1.access)(targetPath);
25
- return true;
26
- }
27
- catch {
28
- return false;
29
- }
30
- }
31
- async function readProjectMetadataFile(rootDir, projectName) {
32
- const project = (0, config_1.buildProjectPaths)(rootDir, projectName);
33
- if (!(await pathExists(project.metadataPath))) {
34
- return {};
35
- }
36
- let parsed;
37
- try {
38
- parsed = JSON.parse(await (0, promises_1.readFile)(project.metadataPath, 'utf8'));
39
- }
40
- catch (error) {
41
- throw new errors_1.CliError(`Project metadata at ${project.metadataPath} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`);
42
- }
43
- if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
44
- throw new errors_1.CliError(`Project metadata at ${project.metadataPath} must be a JSON object.`);
45
- }
46
- return parsed;
47
- }
48
- async function getProjectInitRecord(rootDir, projectName) {
49
- const project = (0, config_1.buildProjectPaths)(rootDir, projectName);
50
- const metadata = await readProjectMetadataFile(rootDir, projectName);
51
- return {
52
- project: project.name,
53
- initCommand: normalizeInitCommand(metadata.initCommand),
54
- };
55
- }
56
- async function writeProjectMetadataFile(rootDir, projectName, metadata) {
57
- const project = (0, config_1.buildProjectPaths)(rootDir, projectName);
58
- const tempPath = `${project.metadataPath}.tmp`;
59
- if (Object.keys(metadata).length === 0) {
60
- await (0, promises_1.rm)(project.metadataPath, { force: true });
61
- return;
62
- }
63
- await (0, promises_1.writeFile)(tempPath, `${JSON.stringify(metadata, null, 2)}
64
- `, 'utf8');
65
- await (0, promises_1.rename)(tempPath, project.metadataPath);
66
- }
67
- async function setProjectInitCommand(rootDir, projectName, command) {
68
- const project = (0, config_1.buildProjectPaths)(rootDir, projectName);
69
- const initCommand = normalizeInitCommand(command);
70
- await writeProjectMetadataFile(rootDir, project.name, { initCommand });
71
- return {
72
- project: project.name,
73
- initCommand,
74
- };
75
- }
76
- async function clearProjectInitCommand(rootDir, projectName) {
77
- const project = (0, config_1.buildProjectPaths)(rootDir, projectName);
78
- await writeProjectMetadataFile(rootDir, project.name, {});
79
- return {
80
- project: project.name,
81
- initCommand: null,
82
- };
83
- }
package/dist/output.js DELETED
@@ -1,211 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.printProjects = printProjects;
7
- exports.printProjectDiagnostics = printProjectDiagnostics;
8
- exports.printProjectInit = printProjectInit;
9
- exports.printWorktrees = printWorktrees;
10
- exports.printStatuses = printStatuses;
11
- const cli_table3_1 = __importDefault(require("cli-table3"));
12
- function printJson(value) {
13
- console.log(JSON.stringify(value, null, 2));
14
- }
15
- function getTerminalWidth() {
16
- return process.stdout.columns ?? 100;
17
- }
18
- function truncate(value, width) {
19
- if (value.length <= width) {
20
- return value;
21
- }
22
- if (width <= 1) {
23
- return value.slice(0, width);
24
- }
25
- return `${value.slice(0, width - 1)}…`;
26
- }
27
- function buildColumnWidths(headers, rows, maxWidths) {
28
- const gapWidth = 2;
29
- const terminalWidth = getTerminalWidth();
30
- const widths = headers.map((header, index) => {
31
- const longestValue = Math.max(header.length, ...rows.map((row) => row[index]?.length ?? 0));
32
- return Math.min(longestValue, maxWidths[index] ?? longestValue);
33
- });
34
- const usedWidth = widths.reduce((sum, width) => sum + width, 0) +
35
- gapWidth * (headers.length - 1);
36
- if (usedWidth <= terminalWidth) {
37
- return widths;
38
- }
39
- const overflow = usedWidth - terminalWidth;
40
- const lastColumn = widths.length - 1;
41
- widths[lastColumn] = Math.max(headers[lastColumn]?.length ?? 4, widths[lastColumn] - overflow);
42
- return widths;
43
- }
44
- function createTable(headers, colWidths) {
45
- return new cli_table3_1.default({
46
- head: headers,
47
- colWidths,
48
- wordWrap: true,
49
- style: {
50
- head: [],
51
- border: [],
52
- compact: true,
53
- 'padding-left': 0,
54
- 'padding-right': 0,
55
- },
56
- chars: {
57
- top: '',
58
- 'top-mid': '',
59
- 'top-left': '',
60
- 'top-right': '',
61
- bottom: '',
62
- 'bottom-mid': '',
63
- 'bottom-left': '',
64
- 'bottom-right': '',
65
- left: '',
66
- 'left-mid': '',
67
- mid: '',
68
- 'mid-mid': '',
69
- right: '',
70
- 'right-mid': '',
71
- middle: ' ',
72
- },
73
- });
74
- }
75
- function renderTable(headers, rows, maxWidths, detailLabel, formatRow) {
76
- const mainHeaders = headers.slice(0, -1);
77
- const mainRows = rows.map((row) => row.slice(0, -1));
78
- const colWidths = buildColumnWidths(mainHeaders, mainRows, maxWidths);
79
- const headerTable = createTable(mainHeaders, colWidths);
80
- const divider = '-'.repeat(Math.min(getTerminalWidth(), colWidths.reduce((sum, width) => sum + width, 0) +
81
- 2 * (colWidths.length - 1)));
82
- console.log(headerTable.toString());
83
- console.log(divider);
84
- for (const row of rows) {
85
- const rowTable = createTable(undefined, colWidths);
86
- const formattedRow = formatRow ? formatRow(row, colWidths) : row;
87
- const detail = row[row.length - 1] ?? '';
88
- rowTable.push(formattedRow.slice(0, -1));
89
- console.log(rowTable.toString());
90
- console.log(` ${detailLabel}: ${detail}`);
91
- console.log('');
92
- console.log(divider);
93
- }
94
- }
95
- function formatProjectRow(row, widths) {
96
- return [
97
- truncate(row[0] ?? '', widths[0] ?? 20),
98
- truncate(row[1] ?? '', widths[1] ?? 16),
99
- row[2] ?? 'no',
100
- row[3] ?? '0',
101
- row[4] ?? '',
102
- ];
103
- }
104
- function formatWorktreeRow(row, widths) {
105
- return [
106
- truncate(row[0] ?? '', widths[0] ?? 18),
107
- truncate(row[1] ?? '', widths[1] ?? 18),
108
- truncate(row[2] ?? '', widths[2] ?? 18),
109
- row[3] ?? 'no',
110
- row[4] ?? 'no',
111
- row[5] ?? '',
112
- ];
113
- }
114
- function formatStatusRow(row, widths) {
115
- return [
116
- truncate(row[0] ?? '', widths[0] ?? 18),
117
- truncate(row[1] ?? '', widths[1] ?? 18),
118
- truncate(row[2] ?? '', widths[2] ?? 18),
119
- row[3] ?? '-',
120
- row[4] ?? '0',
121
- row[5] ?? '-',
122
- row[6] ?? '',
123
- ];
124
- }
125
- function printProjects(projects, asJson) {
126
- if (asJson) {
127
- printJson(projects);
128
- return;
129
- }
130
- if (projects.length === 0) {
131
- console.log('No projects found.');
132
- return;
133
- }
134
- renderTable(['project', 'branch', 'commits', 'worktrees', 'path'], projects.map((project) => [
135
- project.name,
136
- project.defaultBranch ?? '-',
137
- project.hasCommits ? 'yes' : 'no',
138
- String(project.worktreeCount),
139
- project.rootPath,
140
- ]), [20, 16, 7, 10], 'path', formatProjectRow);
141
- }
142
- function printProjectDiagnostics(diagnostics, asJson) {
143
- if (asJson) {
144
- printJson(diagnostics);
145
- return;
146
- }
147
- if (diagnostics.length === 0) {
148
- console.log('No projects found.');
149
- return;
150
- }
151
- renderTable(['project', 'status', 'branch', 'worktrees', 'details'], diagnostics.map((entry) => {
152
- if ('gitDir' in entry) {
153
- return [
154
- entry.name,
155
- 'ok',
156
- entry.defaultBranch ?? '-',
157
- String(entry.worktreeCount),
158
- entry.rootPath,
159
- ];
160
- }
161
- return [entry.name, 'broken', '-', '-', entry.error ?? entry.rootPath];
162
- }), [20, 8, 16, 10], 'details', formatProjectRow);
163
- }
164
- function printProjectInit(init, asJson) {
165
- if (asJson) {
166
- printJson(init);
167
- return;
168
- }
169
- if (init.initCommand) {
170
- console.log(init.initCommand);
171
- return;
172
- }
173
- console.log(`No init command configured for project '${init.project}'.`);
174
- }
175
- function printWorktrees(worktrees, asJson) {
176
- if (asJson) {
177
- printJson(worktrees);
178
- return;
179
- }
180
- if (worktrees.length === 0) {
181
- console.log('No linked worktrees found.');
182
- return;
183
- }
184
- renderTable(['project', 'alias', 'branch', 'locked', 'prunable', 'path'], worktrees.map((worktree) => [
185
- worktree.project,
186
- worktree.alias,
187
- worktree.branch ?? 'detached',
188
- worktree.locked ? 'yes' : 'no',
189
- worktree.prunable ? 'yes' : 'no',
190
- worktree.path,
191
- ]), [18, 18, 18, 6, 8], 'path', formatWorktreeRow);
192
- }
193
- function printStatuses(statuses, asJson) {
194
- if (asJson) {
195
- printJson(statuses);
196
- return;
197
- }
198
- if (statuses.length === 0) {
199
- console.log('No linked worktrees found.');
200
- return;
201
- }
202
- renderTable(['project', 'alias', 'branch', 'state', 'changes', 'head', 'path'], statuses.map((status) => [
203
- status.project,
204
- status.alias,
205
- status.branch ?? 'detached',
206
- status.state,
207
- String(status.changes),
208
- status.head?.slice(0, 8) ?? '-',
209
- status.path,
210
- ]), [18, 18, 18, 7, 7, 8], 'path', formatStatusRow);
211
- }
package/dist/process.js DELETED
@@ -1,46 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runShellCommand = runShellCommand;
4
- exports.runCommand = runCommand;
5
- const node_child_process_1 = require("node:child_process");
6
- const errors_1 = require("./errors");
7
- function runShellCommand(command, options = {}) {
8
- const shell = process.env.SHELL ?? 'sh';
9
- return runCommand(shell, ['-lc', command], options);
10
- }
11
- function runCommand(command, args, options = {}) {
12
- return new Promise((resolve, reject) => {
13
- const child = (0, node_child_process_1.spawn)(command, args, {
14
- cwd: options.cwd,
15
- env: {
16
- ...process.env,
17
- ...options.env,
18
- },
19
- stdio: ['pipe', 'pipe', 'pipe'],
20
- });
21
- let stdout = '';
22
- let stderr = '';
23
- child.stdout.on('data', (chunk) => {
24
- stdout += chunk.toString();
25
- });
26
- child.stderr.on('data', (chunk) => {
27
- stderr += chunk.toString();
28
- });
29
- child.on('error', (error) => {
30
- reject(new errors_1.CliError(`Failed to run ${command}: ${error.message}`));
31
- });
32
- child.on('close', (code) => {
33
- if (code === 0) {
34
- resolve(stdout.trimEnd());
35
- return;
36
- }
37
- const message = stderr.trim() ||
38
- `${command} ${args.join(' ')} failed with exit code ${code}`;
39
- reject(new errors_1.CliError(message));
40
- });
41
- if (options.stdin) {
42
- child.stdin.write(options.stdin);
43
- }
44
- child.stdin.end();
45
- });
46
- }