@nemus-cli/nemus 0.2.1
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/CHANGELOG.md +86 -0
- package/LICENSE +21 -0
- package/README.md +275 -0
- package/assets/README.md +53 -0
- package/assets/banner.png +0 -0
- package/assets/banner.svg +66 -0
- package/assets/favicon-32.png +0 -0
- package/assets/favicon-64.png +0 -0
- package/assets/icon-256.png +0 -0
- package/assets/icon.svg +23 -0
- package/assets/logo-256.png +0 -0
- package/assets/logo-512.png +0 -0
- package/assets/logo-wordmark.svg +35 -0
- package/assets/logo.svg +32 -0
- package/bin/workspace.js +130 -0
- package/dist/cli/ai-prompt.js +421 -0
- package/dist/cli/dashboard/AgentList.js +61 -0
- package/dist/cli/dashboard/DashboardSidebar.js +280 -0
- package/dist/cli/dashboard/HelpFooter.js +73 -0
- package/dist/cli/dashboard/StatusBadge.js +50 -0
- package/dist/cli/dashboard/index.js +11 -0
- package/dist/cli/dashboard/types.js +2 -0
- package/dist/cli/tui.js +48 -0
- package/dist/commands/ai-prompt.js +22 -0
- package/dist/commands/analyze-deps.js +138 -0
- package/dist/commands/archive.js +113 -0
- package/dist/commands/branch/create.js +119 -0
- package/dist/commands/branch/index.js +104 -0
- package/dist/commands/branch/merge.js +90 -0
- package/dist/commands/branch/rebase.js +84 -0
- package/dist/commands/branch/switch.js +165 -0
- package/dist/commands/cache/index.js +80 -0
- package/dist/commands/cache/manager.js +198 -0
- package/dist/commands/cleanup.js +153 -0
- package/dist/commands/configure-claude.js +55 -0
- package/dist/commands/configure.js +231 -0
- package/dist/commands/create.js +204 -0
- package/dist/commands/dashboard/hook-handler.js +162 -0
- package/dist/commands/dashboard/index.js +258 -0
- package/dist/commands/dashboard/launcher.js +40 -0
- package/dist/commands/dashboard/session-picker.js +106 -0
- package/dist/commands/dashboard/sidebar.js +39 -0
- package/dist/commands/dashboard/workspace-picker.js +95 -0
- package/dist/commands/delete.js +194 -0
- package/dist/commands/deprecated-aliases.js +44 -0
- package/dist/commands/diff.js +129 -0
- package/dist/commands/doctor.js +141 -0
- package/dist/commands/generate-docs.js +77 -0
- package/dist/commands/ghq-status.js +72 -0
- package/dist/commands/go.js +154 -0
- package/dist/commands/history.js +124 -0
- package/dist/commands/list.js +191 -0
- package/dist/commands/mcp/index.js +69 -0
- package/dist/commands/migrate.js +296 -0
- package/dist/commands/remove-repo.js +217 -0
- package/dist/commands/report-bug.js +112 -0
- package/dist/commands/run.js +147 -0
- package/dist/commands/save-context.js +171 -0
- package/dist/commands/sessions.js +129 -0
- package/dist/commands/status.js +138 -0
- package/dist/commands/suite/create.js +212 -0
- package/dist/commands/suite/delete.js +64 -0
- package/dist/commands/suite/export.js +126 -0
- package/dist/commands/suite/import.js +128 -0
- package/dist/commands/suite/index.js +94 -0
- package/dist/commands/suite/list.js +49 -0
- package/dist/commands/suite/use.js +227 -0
- package/dist/commands/sync.js +117 -0
- package/dist/commands/update.js +203 -0
- package/dist/mcp/install.js +550 -0
- package/dist/mcp/server.js +398 -0
- package/dist/mcp/tools.js +922 -0
- package/dist/pi-extensions/permission-sync.ts.template +41 -0
- package/dist/pi-extensions/permissions-gate.ts.template +69 -0
- package/dist/pi-extensions/pr-fix-trigger.ts.template +124 -0
- package/dist/pi-extensions/review-reminder.ts.template +58 -0
- package/dist/pi-extensions/workspace-input-status.ts.template +919 -0
- package/dist/program.js +136 -0
- package/dist/scripts/workspace-table.py +394 -0
- package/dist/types/dashboard.js +11 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/agent-config.js +263 -0
- package/dist/utils/agent-state.js +178 -0
- package/dist/utils/banner.js +24 -0
- package/dist/utils/branch-operations.js +232 -0
- package/dist/utils/bug-report.js +355 -0
- package/dist/utils/cache.js +168 -0
- package/dist/utils/claude-integration.js +617 -0
- package/dist/utils/claude-sessions.js +260 -0
- package/dist/utils/cleanup-operations.js +120 -0
- package/dist/utils/colors.js +26 -0
- package/dist/utils/command-helpers.js +44 -0
- package/dist/utils/config.js +150 -0
- package/dist/utils/context-file.js +33 -0
- package/dist/utils/dashboard-hooks.js +172 -0
- package/dist/utils/dependency-analyzer.js +234 -0
- package/dist/utils/diff-operations.js +80 -0
- package/dist/utils/doc-generator.js +184 -0
- package/dist/utils/ghq-integration.js +332 -0
- package/dist/utils/git-operations.js +237 -0
- package/dist/utils/git-status.js +187 -0
- package/dist/utils/github.js +68 -0
- package/dist/utils/health-checks.js +345 -0
- package/dist/utils/history.js +150 -0
- package/dist/utils/hooks.js +100 -0
- package/dist/utils/logger.js +40 -0
- package/dist/utils/permission-sync.js +681 -0
- package/dist/utils/pi-extensions.js +224 -0
- package/dist/utils/progress.js +92 -0
- package/dist/utils/prompts.js +279 -0
- package/dist/utils/repo-resolver.js +260 -0
- package/dist/utils/retry.js +65 -0
- package/dist/utils/run-operations.js +30 -0
- package/dist/utils/suite.js +159 -0
- package/dist/utils/sync-operations.js +107 -0
- package/dist/utils/tmux-dashboard.js +184 -0
- package/dist/utils/validation.js +153 -0
- package/dist/utils/version-check.js +121 -0
- package/dist/utils/workspace-meta.js +185 -0
- package/install-shell-integration.sh +532 -0
- package/install.sh +401 -0
- package/package.json +90 -0
- package/remove-shell-block.awk +44 -0
- package/scripts/postinstall.js +85 -0
- package/skills/analyze-deps.md +23 -0
- package/skills/archive-workspace.md +26 -0
- package/skills/branch-create.md +18 -0
- package/skills/create-workspace.md +39 -0
- package/skills/delete-workspace.md +37 -0
- package/skills/list-org-repos.md +26 -0
- package/skills/list-suites.md +24 -0
- package/skills/list-workspaces.md +27 -0
- package/skills/refresh-workspace-docs.md +89 -0
- package/skills/remove-repo.md +25 -0
- package/skills/run-command.md +23 -0
- package/skills/save-context.md +68 -0
- package/skills/search-repos.md +31 -0
- package/skills/snapshot-list.md +18 -0
- package/skills/snapshot-save.md +12 -0
- package/skills/switch-branch.md +18 -0
- package/skills/update-cache.md +21 -0
- package/skills/update-workspace.md +66 -0
- package/skills/workspace-cleanup.md +18 -0
- package/skills/workspace-diff.md +23 -0
- package/skills/workspace-doctor.md +23 -0
- package/skills/workspace-info.md +45 -0
- package/skills/workspace-manager/SKILL.md +201 -0
- package/skills/workspace-manager/references/ai-prompt.md +44 -0
- package/skills/workspace-manager/references/analyze-deps.md +45 -0
- package/skills/workspace-manager/references/archive-workspace.md +38 -0
- package/skills/workspace-manager/references/branch-create.md +31 -0
- package/skills/workspace-manager/references/branch-merge.md +22 -0
- package/skills/workspace-manager/references/branch-rebase.md +22 -0
- package/skills/workspace-manager/references/cache-clear.md +18 -0
- package/skills/workspace-manager/references/cache-info.md +22 -0
- package/skills/workspace-manager/references/configure-claude.md +31 -0
- package/skills/workspace-manager/references/configure.md +35 -0
- package/skills/workspace-manager/references/create-workspace.md +45 -0
- package/skills/workspace-manager/references/dashboard.md +61 -0
- package/skills/workspace-manager/references/delete-workspace.md +33 -0
- package/skills/workspace-manager/references/generate-docs.md +36 -0
- package/skills/workspace-manager/references/ghq-status.md +28 -0
- package/skills/workspace-manager/references/go.md +33 -0
- package/skills/workspace-manager/references/history.md +41 -0
- package/skills/workspace-manager/references/list-org-repos.md +26 -0
- package/skills/workspace-manager/references/list-suites.md +21 -0
- package/skills/workspace-manager/references/list-workspaces.md +27 -0
- package/skills/workspace-manager/references/mcp.md +49 -0
- package/skills/workspace-manager/references/remove-repo.md +26 -0
- package/skills/workspace-manager/references/run-command.md +44 -0
- package/skills/workspace-manager/references/search-repos.md +24 -0
- package/skills/workspace-manager/references/sessions.md +27 -0
- package/skills/workspace-manager/references/suite-create.md +22 -0
- package/skills/workspace-manager/references/suite-delete.md +21 -0
- package/skills/workspace-manager/references/suite-export.md +19 -0
- package/skills/workspace-manager/references/suite-import.md +19 -0
- package/skills/workspace-manager/references/suite-use.md +27 -0
- package/skills/workspace-manager/references/switch-branch.md +25 -0
- package/skills/workspace-manager/references/update-cache.md +22 -0
- package/skills/workspace-manager/references/update-workspace.md +50 -0
- package/skills/workspace-manager/references/workspace-cleanup.md +33 -0
- package/skills/workspace-manager/references/workspace-diff.md +27 -0
- package/skills/workspace-manager/references/workspace-doctor.md +27 -0
- package/skills/workspace-manager/references/workspace-info.md +33 -0
- package/skills/workspace-manager/references/workspace-status.md +43 -0
- package/skills/workspace-manager/references/workspace-sync.md +26 -0
- package/skills/workspace-status.md +26 -0
- package/skills/workspace-sync.md +23 -0
- package/src/cli/ai-prompt.test.ts +667 -0
- package/src/cli/ai-prompt.ts +421 -0
- package/src/cli/dashboard/AgentList.tsx +44 -0
- package/src/cli/dashboard/DashboardSidebar.tsx +291 -0
- package/src/cli/dashboard/HelpFooter.tsx +22 -0
- package/src/cli/dashboard/StatusBadge.tsx +23 -0
- package/src/cli/dashboard/index.ts +5 -0
- package/src/cli/dashboard/types.ts +16 -0
- package/src/cli/tui.tsx +51 -0
- package/src/cli/workspace-cli.test.ts +30 -0
- package/src/commands/ai-prompt.ts +21 -0
- package/src/commands/analyze-deps.ts +119 -0
- package/src/commands/archive.ts +114 -0
- package/src/commands/branch/create.ts +94 -0
- package/src/commands/branch/index.ts +74 -0
- package/src/commands/branch/merge.ts +61 -0
- package/src/commands/branch/rebase.ts +54 -0
- package/src/commands/branch/switch.ts +150 -0
- package/src/commands/cache/index.ts +51 -0
- package/src/commands/cache/manager.ts +168 -0
- package/src/commands/cleanup.ts +132 -0
- package/src/commands/configure-claude.ts +55 -0
- package/src/commands/configure.ts +204 -0
- package/src/commands/create.ts +196 -0
- package/src/commands/dashboard/hook-handler.ts +138 -0
- package/src/commands/dashboard/index.ts +248 -0
- package/src/commands/dashboard/launcher.ts +42 -0
- package/src/commands/dashboard/session-picker.ts +73 -0
- package/src/commands/dashboard/sidebar.js +39 -0
- package/src/commands/dashboard/workspace-picker.ts +62 -0
- package/src/commands/delete.test.ts +250 -0
- package/src/commands/delete.ts +171 -0
- package/src/commands/deprecated-aliases.ts +55 -0
- package/src/commands/diff.ts +106 -0
- package/src/commands/doctor.ts +110 -0
- package/src/commands/generate-docs.ts +45 -0
- package/src/commands/ghq-status.ts +70 -0
- package/src/commands/go.ts +125 -0
- package/src/commands/history.ts +136 -0
- package/src/commands/list.test.ts +219 -0
- package/src/commands/list.ts +176 -0
- package/src/commands/mcp/index.ts +39 -0
- package/src/commands/migrate.ts +277 -0
- package/src/commands/remove-repo.ts +194 -0
- package/src/commands/report-bug.ts +88 -0
- package/src/commands/run.ts +125 -0
- package/src/commands/save-context.test.ts +113 -0
- package/src/commands/save-context.ts +141 -0
- package/src/commands/sessions.ts +99 -0
- package/src/commands/status.ts +111 -0
- package/src/commands/suite/create.ts +240 -0
- package/src/commands/suite/delete.ts +65 -0
- package/src/commands/suite/export.ts +97 -0
- package/src/commands/suite/import.ts +100 -0
- package/src/commands/suite/index.ts +66 -0
- package/src/commands/suite/list.ts +54 -0
- package/src/commands/suite/use.ts +232 -0
- package/src/commands/sync.ts +97 -0
- package/src/commands/update.ts +197 -0
- package/src/mcp/install.ts +529 -0
- package/src/mcp/server.ts +579 -0
- package/src/mcp/tools.test.ts +545 -0
- package/src/mcp/tools.ts +1019 -0
- package/src/mcp/update-workspace.test.ts +220 -0
- package/src/pi-extensions/permission-sync.ts.template +41 -0
- package/src/pi-extensions/permissions-gate.ts.template +69 -0
- package/src/pi-extensions/pr-fix-trigger.ts.template +124 -0
- package/src/pi-extensions/review-reminder.ts.template +58 -0
- package/src/pi-extensions/workspace-input-status.ts.template +919 -0
- package/src/program.ts +112 -0
- package/src/scripts/workspace-table.py +394 -0
- package/src/types/dashboard.ts +29 -0
- package/src/types/index.ts +109 -0
- package/src/types/ink.d.ts +171 -0
- package/src/utils/agent-config.test.ts +303 -0
- package/src/utils/agent-config.ts +264 -0
- package/src/utils/agent-state.test.ts +166 -0
- package/src/utils/agent-state.ts +135 -0
- package/src/utils/banner.ts +24 -0
- package/src/utils/branch-operations.ts +237 -0
- package/src/utils/bug-report.test.ts +174 -0
- package/src/utils/bug-report.ts +355 -0
- package/src/utils/cache.ts +150 -0
- package/src/utils/claude-integration.test.ts +381 -0
- package/src/utils/claude-integration.ts +649 -0
- package/src/utils/claude-sessions.test.ts +262 -0
- package/src/utils/claude-sessions.ts +251 -0
- package/src/utils/cleanup-operations.ts +94 -0
- package/src/utils/colors.ts +25 -0
- package/src/utils/command-helpers.ts +46 -0
- package/src/utils/config.test.ts +203 -0
- package/src/utils/config.ts +133 -0
- package/src/utils/context-file.ts +36 -0
- package/src/utils/dashboard-hooks.test.ts +168 -0
- package/src/utils/dashboard-hooks.ts +163 -0
- package/src/utils/dependency-analyzer.ts +243 -0
- package/src/utils/diff-operations.ts +59 -0
- package/src/utils/doc-generator.ts +187 -0
- package/src/utils/ghq-integration.test.ts +195 -0
- package/src/utils/ghq-integration.ts +317 -0
- package/src/utils/git-operations.test.ts +265 -0
- package/src/utils/git-operations.ts +233 -0
- package/src/utils/git-status.ts +171 -0
- package/src/utils/github.ts +74 -0
- package/src/utils/health-checks.ts +359 -0
- package/src/utils/history.ts +140 -0
- package/src/utils/hooks.ts +92 -0
- package/src/utils/logger.ts +37 -0
- package/src/utils/permission-sync.test.ts +593 -0
- package/src/utils/permission-sync.ts +720 -0
- package/src/utils/pi-extensions.test.ts +182 -0
- package/src/utils/pi-extensions.ts +226 -0
- package/src/utils/progress.ts +73 -0
- package/src/utils/prompts.test.ts +169 -0
- package/src/utils/prompts.ts +296 -0
- package/src/utils/repo-resolver.test.ts +313 -0
- package/src/utils/repo-resolver.ts +294 -0
- package/src/utils/retry.test.ts +124 -0
- package/src/utils/retry.ts +85 -0
- package/src/utils/run-operations.ts +38 -0
- package/src/utils/suite.test.ts +256 -0
- package/src/utils/suite.ts +144 -0
- package/src/utils/sync-operations.ts +87 -0
- package/src/utils/tmux-dashboard.ts +193 -0
- package/src/utils/validation.test.ts +139 -0
- package/src/utils/validation.ts +128 -0
- package/src/utils/version-check.test.ts +108 -0
- package/src/utils/version-check.ts +96 -0
- package/src/utils/workspace-meta.ts +173 -0
- package/sync-permissions.sh +137 -0
- package/tsconfig.json +20 -0
- package/uninstall.sh +162 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { listWorkspaces, archiveWorkspace, unarchiveWorkspace } from '../utils/workspace-meta';
|
|
3
|
+
import { promptMultiWorkspaceSelection } from '../utils/prompts';
|
|
4
|
+
import { logInfo, logSuccess, logError } from '../utils/logger';
|
|
5
|
+
import { colorize } from '../utils/colors';
|
|
6
|
+
import inquirer from 'inquirer';
|
|
7
|
+
import { getGlobalOpts, parseList } from '../utils/command-helpers';
|
|
8
|
+
|
|
9
|
+
export function registerArchiveCommand(parent: Command) {
|
|
10
|
+
parent
|
|
11
|
+
.command('archive')
|
|
12
|
+
.alias('a')
|
|
13
|
+
.description('Archive a workspace (30-day expiry)')
|
|
14
|
+
.option('-w, --workspace <names>', 'Comma-separated workspace names')
|
|
15
|
+
.option('--unarchive', 'Unarchive a previously archived workspace')
|
|
16
|
+
.action(async (opts, cmd) => {
|
|
17
|
+
const globalOpts = getGlobalOpts(cmd);
|
|
18
|
+
await handleArchive({ ...opts, ...globalOpts });
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async function handleArchive(opts: {
|
|
23
|
+
workspace?: string;
|
|
24
|
+
unarchive?: boolean;
|
|
25
|
+
yes: boolean;
|
|
26
|
+
forceRefresh: boolean;
|
|
27
|
+
}) {
|
|
28
|
+
const isUnarchive = opts.unarchive ?? false;
|
|
29
|
+
const title = isUnarchive ? 'Unarchive Workspace' : 'Archive Workspace';
|
|
30
|
+
console.log('\n' + '='.repeat(60));
|
|
31
|
+
console.log(colorize(title, 'bright'));
|
|
32
|
+
console.log('='.repeat(60) + '\n');
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
if (isUnarchive) {
|
|
36
|
+
const allWorkspaces = await listWorkspaces(true);
|
|
37
|
+
const archivedWorkspaces = allWorkspaces.filter(ws => ws.metadata?.archivedAt);
|
|
38
|
+
|
|
39
|
+
if (archivedWorkspaces.length === 0) {
|
|
40
|
+
logInfo('No archived workspaces found');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
let selectedNames: string[];
|
|
45
|
+
|
|
46
|
+
if (opts.workspace) {
|
|
47
|
+
selectedNames = parseList(opts.workspace);
|
|
48
|
+
} else {
|
|
49
|
+
selectedNames = await promptMultiWorkspaceSelection(archivedWorkspaces);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (!opts.yes) {
|
|
53
|
+
const { confirmed } = await inquirer.prompt([{
|
|
54
|
+
type: 'confirm', name: 'confirmed',
|
|
55
|
+
message: selectedNames.length === 1
|
|
56
|
+
? `Unarchive workspace ${selectedNames[0]}?`
|
|
57
|
+
: `Unarchive these ${selectedNames.length} workspaces?`,
|
|
58
|
+
default: true,
|
|
59
|
+
}]);
|
|
60
|
+
if (!confirmed) return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
for (const name of selectedNames) {
|
|
64
|
+
try {
|
|
65
|
+
await unarchiveWorkspace(name);
|
|
66
|
+
logSuccess(`Unarchived "${colorize(name, 'cyan')}"`);
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logError(`Failed to unarchive "${name}"`);
|
|
69
|
+
if (error instanceof Error) logError(error.message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
const workspaces = await listWorkspaces(false);
|
|
74
|
+
|
|
75
|
+
if (workspaces.length === 0) {
|
|
76
|
+
logInfo('No active workspaces found');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let selectedNames: string[];
|
|
81
|
+
|
|
82
|
+
if (opts.workspace) {
|
|
83
|
+
selectedNames = parseList(opts.workspace);
|
|
84
|
+
} else {
|
|
85
|
+
selectedNames = await promptMultiWorkspaceSelection(workspaces);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!opts.yes) {
|
|
89
|
+
const { confirmed } = await inquirer.prompt([{
|
|
90
|
+
type: 'confirm', name: 'confirmed',
|
|
91
|
+
message: selectedNames.length === 1
|
|
92
|
+
? `Archive workspace ${selectedNames[0]}? It will be auto-deleted in 30 days.`
|
|
93
|
+
: `Archive these ${selectedNames.length} workspaces? They will be auto-deleted in 30 days.`,
|
|
94
|
+
default: true,
|
|
95
|
+
}]);
|
|
96
|
+
if (!confirmed) return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const name of selectedNames) {
|
|
100
|
+
try {
|
|
101
|
+
await archiveWorkspace(name);
|
|
102
|
+
logSuccess(`Archived "${colorize(name, 'cyan')}" - will be auto-deleted in 30 days`);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
logError(`Failed to archive "${name}"`);
|
|
105
|
+
if (error instanceof Error) logError(error.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch (error) {
|
|
110
|
+
logError(`Failed to ${isUnarchive ? 'unarchive' : 'archive'} workspace`);
|
|
111
|
+
if (error instanceof Error) { logError(error.message); }
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { listWorkspaces, loadMetadata } from '../../utils/workspace-meta';
|
|
4
|
+
import { promptWorkspaceSelection } from '../../utils/prompts';
|
|
5
|
+
import { createBranch } from '../../utils/branch-operations';
|
|
6
|
+
import { logError, logInfo, logStep, logSuccess, logWarning } from '../../utils/logger';
|
|
7
|
+
import { colorize } from '../../utils/colors';
|
|
8
|
+
import { WORKSPACES_DIR } from '../../utils/config';
|
|
9
|
+
import inquirer from 'inquirer';
|
|
10
|
+
|
|
11
|
+
export interface BranchCreateOpts {
|
|
12
|
+
workspace?: string;
|
|
13
|
+
branch?: string;
|
|
14
|
+
base?: string;
|
|
15
|
+
force?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const main = async (opts?: BranchCreateOpts) => {
|
|
19
|
+
try {
|
|
20
|
+
let workspaceName = opts?.workspace;
|
|
21
|
+
let branchName = opts?.branch;
|
|
22
|
+
const baseBranch = opts?.base;
|
|
23
|
+
const force = opts?.force ?? false;
|
|
24
|
+
|
|
25
|
+
// Resolve workspace interactively if needed
|
|
26
|
+
if (!workspaceName) {
|
|
27
|
+
if (!process.stdout.isTTY) {
|
|
28
|
+
logError('Missing required option: --workspace');
|
|
29
|
+
logError('Usage: w branch create --workspace <name> --branch <branch>');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
const workspaces = await listWorkspaces();
|
|
33
|
+
workspaceName = await promptWorkspaceSelection(workspaces);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Resolve branch interactively if needed
|
|
37
|
+
if (!branchName) {
|
|
38
|
+
if (!process.stdout.isTTY) {
|
|
39
|
+
logError('Missing required option: --branch');
|
|
40
|
+
logError('Usage: w branch create --workspace <name> --branch <branch>');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const { branch } = await inquirer.prompt([
|
|
44
|
+
{
|
|
45
|
+
type: 'input',
|
|
46
|
+
name: 'branch',
|
|
47
|
+
message: 'New branch name:',
|
|
48
|
+
validate: (input: string) => input.trim() ? true : 'Branch name cannot be empty',
|
|
49
|
+
},
|
|
50
|
+
]);
|
|
51
|
+
branchName = branch;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const workspacePath = path.join(WORKSPACES_DIR, workspaceName!);
|
|
55
|
+
const metadata = await loadMetadata(workspacePath);
|
|
56
|
+
|
|
57
|
+
if (!metadata) {
|
|
58
|
+
logError(`Workspace not found: ${workspaceName}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
logStep(`Creating branch ${colorize(branchName!, 'cyan')} across all repositories...`);
|
|
63
|
+
|
|
64
|
+
const results = [];
|
|
65
|
+
for (const repo of metadata.repositories) {
|
|
66
|
+
const repoPath = path.join(workspacePath, repo.directoryName);
|
|
67
|
+
const result = await createBranch(repoPath, repo.directoryName, branchName!, baseBranch, force);
|
|
68
|
+
results.push(result);
|
|
69
|
+
|
|
70
|
+
if (result.success) {
|
|
71
|
+
logSuccess(`${repo.directoryName}: ${result.message}`);
|
|
72
|
+
} else {
|
|
73
|
+
logWarning(`${repo.directoryName}: ${result.message}`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const successful = results.filter(r => r.success).length;
|
|
78
|
+
const failed = results.filter(r => !r.success).length;
|
|
79
|
+
|
|
80
|
+
console.log('');
|
|
81
|
+
logInfo(`Created branches in ${successful}/${results.length} repositories`);
|
|
82
|
+
if (failed > 0) {
|
|
83
|
+
logWarning(`${failed} repositories were skipped or failed`);
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logError('Failed to create branches');
|
|
87
|
+
if (error instanceof Error) {
|
|
88
|
+
logError(error.message);
|
|
89
|
+
}
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
if (require.main === module) main();
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getGlobalOpts } from '../../utils/command-helpers';
|
|
3
|
+
|
|
4
|
+
export function registerBranchCommands(parent: Command) {
|
|
5
|
+
const branch = parent
|
|
6
|
+
.command('branch')
|
|
7
|
+
.description('Branch management');
|
|
8
|
+
|
|
9
|
+
branch
|
|
10
|
+
.command('switch')
|
|
11
|
+
.description('Switch all repos to a specific branch')
|
|
12
|
+
.option('-w, --workspace <name>', 'Workspace name')
|
|
13
|
+
.option('-b, --branch <name>', 'Branch name')
|
|
14
|
+
.action(async (opts, cmd) => {
|
|
15
|
+
const globalOpts = getGlobalOpts(cmd);
|
|
16
|
+
const { main } = await import('./switch');
|
|
17
|
+
await main({
|
|
18
|
+
workspace: opts.workspace,
|
|
19
|
+
branch: opts.branch,
|
|
20
|
+
yes: globalOpts.yes,
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
branch
|
|
25
|
+
.command('create')
|
|
26
|
+
.description('Create branches across all repos')
|
|
27
|
+
.argument('[workspace]', 'Workspace name')
|
|
28
|
+
.argument('[branch]', 'Branch name')
|
|
29
|
+
.option('-w, --workspace <name>', 'Workspace name (flag alternative)')
|
|
30
|
+
.option('-b, --branch <name>', 'Branch name (flag alternative)')
|
|
31
|
+
.option('--base <branch>', 'Base branch')
|
|
32
|
+
.option('--force', 'Force create')
|
|
33
|
+
.action(async (workspaceArg, branchArg, opts) => {
|
|
34
|
+
const { main } = await import('./create');
|
|
35
|
+
await main({
|
|
36
|
+
workspace: opts.workspace || workspaceArg,
|
|
37
|
+
branch: opts.branch || branchArg,
|
|
38
|
+
base: opts.base,
|
|
39
|
+
force: opts.force,
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
branch
|
|
44
|
+
.command('merge')
|
|
45
|
+
.description('Merge branches across all repos')
|
|
46
|
+
.argument('<workspace>', 'Workspace name')
|
|
47
|
+
.argument('<source>', 'Source branch')
|
|
48
|
+
.argument('<target>', 'Target branch')
|
|
49
|
+
.option('--no-ff', 'No fast-forward')
|
|
50
|
+
.option('--ff-only', 'Fast-forward only')
|
|
51
|
+
.option('--squash', 'Squash merge')
|
|
52
|
+
.action(async (workspace, source, target, opts) => {
|
|
53
|
+
const { main } = await import('./merge');
|
|
54
|
+
await main({
|
|
55
|
+
workspace,
|
|
56
|
+
source,
|
|
57
|
+
target,
|
|
58
|
+
// Commander's --no-ff sets opts.ff = false
|
|
59
|
+
noFf: opts.ff === false,
|
|
60
|
+
ffOnly: opts.ffOnly,
|
|
61
|
+
squash: opts.squash,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
branch
|
|
66
|
+
.command('rebase')
|
|
67
|
+
.description('Rebase branches across all repos')
|
|
68
|
+
.argument('<workspace>', 'Workspace name')
|
|
69
|
+
.argument('<base>', 'Base branch')
|
|
70
|
+
.action(async (workspace, base) => {
|
|
71
|
+
const { main } = await import('./rebase');
|
|
72
|
+
await main({ workspace, base });
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { WORKSPACES_DIR } from '../../utils/config';
|
|
4
|
+
import { loadMetadata } from '../../utils/workspace-meta';
|
|
5
|
+
import { mergeBranch } from '../../utils/branch-operations';
|
|
6
|
+
import { logError, logInfo, logStep, logSuccess, logWarning } from '../../utils/logger';
|
|
7
|
+
import { colorize } from '../../utils/colors';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export const main = async (opts?: { workspace?: string; source?: string; target?: string; noFf?: boolean; ffOnly?: boolean; squash?: boolean }) => {
|
|
11
|
+
try {
|
|
12
|
+
const workspaceName = opts?.workspace ?? process.argv[2];
|
|
13
|
+
const sourceBranch = opts?.source ?? process.argv[3];
|
|
14
|
+
const targetBranch = opts?.target ?? process.argv[4];
|
|
15
|
+
|
|
16
|
+
if (!workspaceName || !sourceBranch || !targetBranch) {
|
|
17
|
+
logError('Usage: workspace branch-merge <workspace> <source-branch> <target-branch> [--no-ff|--ff-only|--squash]');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const workspacePath = path.join(WORKSPACES_DIR, workspaceName);
|
|
22
|
+
const metadata = await loadMetadata(workspacePath);
|
|
23
|
+
|
|
24
|
+
if (!metadata) {
|
|
25
|
+
logError(`Workspace not found: ${workspaceName}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const options = {
|
|
30
|
+
noFf: opts?.noFf ?? process.argv.includes('--no-ff'),
|
|
31
|
+
ffOnly: opts?.ffOnly ?? process.argv.includes('--ff-only'),
|
|
32
|
+
squash: opts?.squash ?? process.argv.includes('--squash'),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
logStep(`Merging ${colorize(sourceBranch, 'cyan')} into ${colorize(targetBranch, 'cyan')}...`);
|
|
36
|
+
|
|
37
|
+
const results = [];
|
|
38
|
+
for (const repo of metadata.repositories) {
|
|
39
|
+
const repoPath = path.join(workspacePath, repo.name);
|
|
40
|
+
const result = await mergeBranch(repoPath, repo.name, sourceBranch, targetBranch, options);
|
|
41
|
+
results.push(result);
|
|
42
|
+
|
|
43
|
+
if (result.success) {
|
|
44
|
+
logSuccess(`${repo.name}: ${result.message}`);
|
|
45
|
+
} else {
|
|
46
|
+
logWarning(`${repo.name}: ${result.message} - ${result.error || ''}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const successful = results.filter(r => r.success).length;
|
|
51
|
+
logInfo(`Merged successfully in ${successful}/${results.length} repositories`);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logError('Failed to merge branches');
|
|
54
|
+
if (error instanceof Error) {
|
|
55
|
+
logError(error.message);
|
|
56
|
+
}
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (require.main === module) main();
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import { WORKSPACES_DIR } from '../../utils/config';
|
|
4
|
+
import { loadMetadata } from '../../utils/workspace-meta';
|
|
5
|
+
import { rebaseBranch } from '../../utils/branch-operations';
|
|
6
|
+
import { logError, logInfo, logStep, logSuccess, logWarning } from '../../utils/logger';
|
|
7
|
+
import { colorize } from '../../utils/colors';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export const main = async (opts?: { workspace?: string; base?: string }) => {
|
|
11
|
+
try {
|
|
12
|
+
const workspaceName = opts?.workspace ?? process.argv[2];
|
|
13
|
+
const targetBranch = opts?.base ?? process.argv[3];
|
|
14
|
+
|
|
15
|
+
if (!workspaceName || !targetBranch) {
|
|
16
|
+
logError('Usage: workspace branch-rebase <workspace> <target-branch>');
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const workspacePath = path.join(WORKSPACES_DIR, workspaceName);
|
|
21
|
+
const metadata = await loadMetadata(workspacePath);
|
|
22
|
+
|
|
23
|
+
if (!metadata) {
|
|
24
|
+
logError(`Workspace not found: ${workspaceName}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
logStep(`Rebasing onto ${colorize(targetBranch, 'cyan')}...`);
|
|
29
|
+
|
|
30
|
+
const results = [];
|
|
31
|
+
for (const repo of metadata.repositories) {
|
|
32
|
+
const repoPath = path.join(workspacePath, repo.name);
|
|
33
|
+
const result = await rebaseBranch(repoPath, repo.name, targetBranch);
|
|
34
|
+
results.push(result);
|
|
35
|
+
|
|
36
|
+
if (result.success) {
|
|
37
|
+
logSuccess(`${repo.name}: ${result.message}`);
|
|
38
|
+
} else {
|
|
39
|
+
logWarning(`${repo.name}: ${result.message} - ${result.error || ''}`);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const successful = results.filter(r => r.success).length;
|
|
44
|
+
logInfo(`Rebased successfully in ${successful}/${results.length} repositories`);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
logError('Failed to rebase branches');
|
|
47
|
+
if (error instanceof Error) {
|
|
48
|
+
logError(error.message);
|
|
49
|
+
}
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (require.main === module) main();
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#!/usr/bin/env ts-node
|
|
2
|
+
|
|
3
|
+
import { WORKSPACES_DIR } from '../../utils/config';
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
import { listWorkspaces, loadMetadata } from '../../utils/workspace-meta';
|
|
6
|
+
import { promptWorkspaceSelection } from '../../utils/prompts';
|
|
7
|
+
import { logInfo, logSuccess, logError, logWarning } from '../../utils/logger';
|
|
8
|
+
import { colorize } from '../../utils/colors';
|
|
9
|
+
import { switchBranch, BranchSwitchResult } from '../../utils/branch-operations';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
11
|
+
|
|
12
|
+
export interface BranchSwitchOpts {
|
|
13
|
+
workspace?: string;
|
|
14
|
+
branch?: string;
|
|
15
|
+
yes?: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function main(opts?: BranchSwitchOpts) {
|
|
19
|
+
console.log('\n' + '='.repeat(60));
|
|
20
|
+
console.log(colorize('Bulk Branch Switch', 'bright'));
|
|
21
|
+
console.log('='.repeat(60) + '\n');
|
|
22
|
+
|
|
23
|
+
const yes = opts?.yes ?? false;
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Select workspace
|
|
27
|
+
let workspaceName: string;
|
|
28
|
+
|
|
29
|
+
if (opts?.workspace) {
|
|
30
|
+
workspaceName = opts.workspace;
|
|
31
|
+
} else {
|
|
32
|
+
if (!process.stdout.isTTY) {
|
|
33
|
+
logError('Missing required option: --workspace');
|
|
34
|
+
logError('Usage: w branch switch --workspace <name> --branch <branch>');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const workspaces = await listWorkspaces();
|
|
38
|
+
workspaceName = await promptWorkspaceSelection(workspaces);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const workspacePath = path.join(WORKSPACES_DIR, workspaceName);
|
|
42
|
+
logInfo(`Selected workspace: ${colorize(workspaceName, 'cyan')}`);
|
|
43
|
+
|
|
44
|
+
const metadata = await loadMetadata(workspacePath);
|
|
45
|
+
if (!metadata) {
|
|
46
|
+
logError('No metadata found for this workspace');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const repos = metadata.repositories.filter(r => r.status === 'success');
|
|
51
|
+
console.log(`\nFound ${repos.length} repositories\n`);
|
|
52
|
+
|
|
53
|
+
// Determine target branch
|
|
54
|
+
let targetBranch: string;
|
|
55
|
+
|
|
56
|
+
if (opts?.branch) {
|
|
57
|
+
targetBranch = opts.branch;
|
|
58
|
+
} else {
|
|
59
|
+
if (!process.stdout.isTTY) {
|
|
60
|
+
logError('Missing required option: --branch');
|
|
61
|
+
logError('Usage: w branch switch --workspace <name> --branch <branch>');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const { branch } = await inquirer.prompt([
|
|
65
|
+
{
|
|
66
|
+
type: 'input',
|
|
67
|
+
name: 'branch',
|
|
68
|
+
message: 'Target branch name:',
|
|
69
|
+
default: 'main',
|
|
70
|
+
validate: (input: string) => {
|
|
71
|
+
if (!input || input.trim().length === 0) {
|
|
72
|
+
return 'Branch name cannot be empty';
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
]);
|
|
78
|
+
targetBranch = branch;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
logWarning(`This will switch all repositories to branch: ${colorize(targetBranch, 'cyan')}`);
|
|
82
|
+
|
|
83
|
+
// Skip confirmation when --yes flag is provided
|
|
84
|
+
if (!yes && process.stdout.isTTY) {
|
|
85
|
+
const { confirmed } = await inquirer.prompt([
|
|
86
|
+
{
|
|
87
|
+
type: 'confirm',
|
|
88
|
+
name: 'confirmed',
|
|
89
|
+
message: 'Proceed with bulk branch switch?',
|
|
90
|
+
default: true,
|
|
91
|
+
},
|
|
92
|
+
]);
|
|
93
|
+
|
|
94
|
+
if (!confirmed) {
|
|
95
|
+
logInfo('Branch switch cancelled');
|
|
96
|
+
process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
console.log('');
|
|
101
|
+
const results: BranchSwitchResult[] = [];
|
|
102
|
+
for (const repo of repos) {
|
|
103
|
+
const repoPath = path.join(workspacePath, repo.directoryName);
|
|
104
|
+
const displayName = repo.directoryName !== repo.name
|
|
105
|
+
? `${repo.directoryName} (${repo.name})`
|
|
106
|
+
: repo.name;
|
|
107
|
+
const result = await switchBranch(repoPath, displayName, targetBranch);
|
|
108
|
+
results.push(result);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('\n' + '='.repeat(60));
|
|
112
|
+
console.log('Branch Switch Results Summary');
|
|
113
|
+
console.log('='.repeat(60));
|
|
114
|
+
|
|
115
|
+
const successful = results.filter(r => r.status === 'success');
|
|
116
|
+
const failed = results.filter(r => r.status === 'failed');
|
|
117
|
+
const skipped = results.filter(r => r.status === 'skipped');
|
|
118
|
+
|
|
119
|
+
console.log(`${colorize('✓', 'green')} Switched: ${successful.length}`);
|
|
120
|
+
console.log(`${colorize('✗', 'red')} Failed: ${failed.length}`);
|
|
121
|
+
console.log(`${colorize('○', 'yellow')} Skipped: ${skipped.length}`);
|
|
122
|
+
console.log('='.repeat(60));
|
|
123
|
+
|
|
124
|
+
if (failed.length > 0) {
|
|
125
|
+
console.log('\nFailed repositories:');
|
|
126
|
+
failed.forEach(result => {
|
|
127
|
+
console.log(` ${colorize('✗', 'red')} ${result.repo}: ${result.message}`);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (skipped.length > 0) {
|
|
132
|
+
console.log('\nSkipped repositories:');
|
|
133
|
+
skipped.forEach(result => {
|
|
134
|
+
console.log(` ${colorize('○', 'yellow')} ${result.repo}: ${result.message}`);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
console.log('');
|
|
139
|
+
logSuccess('Bulk branch switch complete!');
|
|
140
|
+
|
|
141
|
+
} catch (error) {
|
|
142
|
+
logError('Failed to switch branches');
|
|
143
|
+
if (error instanceof Error) {
|
|
144
|
+
logError(error.message);
|
|
145
|
+
}
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (require.main === module) main();
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getGlobalOpts } from '../../utils/command-helpers';
|
|
3
|
+
|
|
4
|
+
export function registerCacheCommands(parent: Command) {
|
|
5
|
+
const cache = parent
|
|
6
|
+
.command('cache')
|
|
7
|
+
.description('Cache management');
|
|
8
|
+
|
|
9
|
+
cache
|
|
10
|
+
.command('info')
|
|
11
|
+
.description('View cache statistics')
|
|
12
|
+
.action(async () => {
|
|
13
|
+
const { cacheInfo } = await import('./manager');
|
|
14
|
+
await cacheInfo();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
cache
|
|
18
|
+
.command('refresh')
|
|
19
|
+
.description('Force refresh from GitHub')
|
|
20
|
+
.action(async () => {
|
|
21
|
+
const { cacheRefresh } = await import('./manager');
|
|
22
|
+
await cacheRefresh();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
cache
|
|
26
|
+
.command('clear')
|
|
27
|
+
.description('Clear the cache')
|
|
28
|
+
.action(async () => {
|
|
29
|
+
const { cacheClear } = await import('./manager');
|
|
30
|
+
await cacheClear();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
cache
|
|
34
|
+
.command('search')
|
|
35
|
+
.description('Search org repos by name or description')
|
|
36
|
+
.argument('<query>', 'Search query')
|
|
37
|
+
.option('--limit <n>', 'Max results', '20')
|
|
38
|
+
.action(async (query, opts) => {
|
|
39
|
+
const { cacheSearch } = await import('./manager');
|
|
40
|
+
await cacheSearch(query, parseInt(opts.limit) || 20);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
cache
|
|
44
|
+
.command('list')
|
|
45
|
+
.description('List all org repos')
|
|
46
|
+
.action(async (opts, cmd) => {
|
|
47
|
+
const globalOpts = getGlobalOpts(cmd);
|
|
48
|
+
const { cacheList } = await import('./manager');
|
|
49
|
+
await cacheList(globalOpts.forceRefresh);
|
|
50
|
+
});
|
|
51
|
+
}
|