@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,187 @@
|
|
|
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.isGitRepository = exports.hasUncommittedChanges = exports.getAllReposStatus = exports.getAheadBehindCounts = exports.getUncommittedChanges = exports.getCurrentBranch = exports.getGitStatus = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const util_1 = require("util");
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
41
|
+
const GIT_TIMEOUT = 10000; // 10 seconds per git operation
|
|
42
|
+
const getGitStatus = async (repoPath, repoName) => {
|
|
43
|
+
try {
|
|
44
|
+
const results = await Promise.allSettled([
|
|
45
|
+
(0, exports.getCurrentBranch)(repoPath),
|
|
46
|
+
(0, exports.getUncommittedChanges)(repoPath),
|
|
47
|
+
(0, exports.getAheadBehindCounts)(repoPath),
|
|
48
|
+
]);
|
|
49
|
+
const branch = results[0].status === 'fulfilled' ? results[0].value : 'unknown';
|
|
50
|
+
const changes = results[1].status === 'fulfilled' ? results[1].value : { clean: false, modifiedFiles: 0, untrackedFiles: 0 };
|
|
51
|
+
const tracking = results[2].status === 'fulfilled' ? results[2].value : { ahead: 0, behind: 0, hasRemote: false };
|
|
52
|
+
return {
|
|
53
|
+
repo: repoName,
|
|
54
|
+
branch,
|
|
55
|
+
clean: changes.clean,
|
|
56
|
+
ahead: tracking.ahead,
|
|
57
|
+
behind: tracking.behind,
|
|
58
|
+
modifiedFiles: changes.modifiedFiles,
|
|
59
|
+
untrackedFiles: changes.untrackedFiles,
|
|
60
|
+
hasRemote: tracking.hasRemote,
|
|
61
|
+
detachedHead: branch.startsWith('HEAD detached'),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
// Return error state
|
|
66
|
+
return {
|
|
67
|
+
repo: repoName,
|
|
68
|
+
branch: 'unknown',
|
|
69
|
+
clean: false,
|
|
70
|
+
ahead: 0,
|
|
71
|
+
behind: 0,
|
|
72
|
+
modifiedFiles: 0,
|
|
73
|
+
untrackedFiles: 0,
|
|
74
|
+
hasRemote: false,
|
|
75
|
+
detachedHead: false,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
exports.getGitStatus = getGitStatus;
|
|
80
|
+
const getCurrentBranch = async (repoPath) => {
|
|
81
|
+
try {
|
|
82
|
+
const { stdout } = await execAsync('git rev-parse --abbrev-ref HEAD', {
|
|
83
|
+
cwd: repoPath,
|
|
84
|
+
timeout: GIT_TIMEOUT,
|
|
85
|
+
});
|
|
86
|
+
const branch = stdout.trim();
|
|
87
|
+
// Check for detached HEAD
|
|
88
|
+
if (branch === 'HEAD') {
|
|
89
|
+
const { stdout: commitHash } = await execAsync('git rev-parse --short HEAD', {
|
|
90
|
+
cwd: repoPath,
|
|
91
|
+
timeout: GIT_TIMEOUT,
|
|
92
|
+
});
|
|
93
|
+
return `HEAD detached at ${commitHash.trim()}`;
|
|
94
|
+
}
|
|
95
|
+
return branch;
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
return 'unknown';
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
exports.getCurrentBranch = getCurrentBranch;
|
|
102
|
+
const getUncommittedChanges = async (repoPath) => {
|
|
103
|
+
try {
|
|
104
|
+
const { stdout } = await execAsync('git status --porcelain', {
|
|
105
|
+
cwd: repoPath,
|
|
106
|
+
timeout: GIT_TIMEOUT,
|
|
107
|
+
});
|
|
108
|
+
if (!stdout.trim()) {
|
|
109
|
+
return { clean: true, modifiedFiles: 0, untrackedFiles: 0 };
|
|
110
|
+
}
|
|
111
|
+
const lines = stdout.trim().split('\n');
|
|
112
|
+
let modifiedFiles = 0;
|
|
113
|
+
let untrackedFiles = 0;
|
|
114
|
+
for (const line of lines) {
|
|
115
|
+
const status = line.substring(0, 2);
|
|
116
|
+
if (status.includes('?')) {
|
|
117
|
+
untrackedFiles++;
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
modifiedFiles++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return { clean: false, modifiedFiles, untrackedFiles };
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
return { clean: false, modifiedFiles: 0, untrackedFiles: 0 };
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
exports.getUncommittedChanges = getUncommittedChanges;
|
|
130
|
+
const getAheadBehindCounts = async (repoPath) => {
|
|
131
|
+
try {
|
|
132
|
+
// First check if there's a remote tracking branch
|
|
133
|
+
const { stdout: upstreamBranch } = await execAsync('git rev-parse --abbrev-ref @{upstream}', {
|
|
134
|
+
cwd: repoPath,
|
|
135
|
+
timeout: GIT_TIMEOUT,
|
|
136
|
+
});
|
|
137
|
+
if (!upstreamBranch.trim()) {
|
|
138
|
+
return { ahead: 0, behind: 0, hasRemote: false };
|
|
139
|
+
}
|
|
140
|
+
// Get ahead/behind counts
|
|
141
|
+
const { stdout } = await execAsync('git rev-list --count --left-right @{upstream}...HEAD', {
|
|
142
|
+
cwd: repoPath,
|
|
143
|
+
timeout: GIT_TIMEOUT,
|
|
144
|
+
});
|
|
145
|
+
const counts = stdout.trim().split('\t');
|
|
146
|
+
const behind = parseInt(counts[0], 10) || 0;
|
|
147
|
+
const ahead = parseInt(counts[1], 10) || 0;
|
|
148
|
+
return { ahead, behind, hasRemote: true };
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
// No remote tracking branch
|
|
152
|
+
return { ahead: 0, behind: 0, hasRemote: false };
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
exports.getAheadBehindCounts = getAheadBehindCounts;
|
|
156
|
+
const getAllReposStatus = async (workspacePath, repoNames, concurrency = 3) => {
|
|
157
|
+
const results = [];
|
|
158
|
+
// Process in chunks for controlled parallelism
|
|
159
|
+
for (let i = 0; i < repoNames.length; i += concurrency) {
|
|
160
|
+
const chunk = repoNames.slice(i, i + concurrency);
|
|
161
|
+
const chunkResults = await Promise.all(chunk.map(repoName => {
|
|
162
|
+
const repoPath = path.join(workspacePath, repoName);
|
|
163
|
+
return (0, exports.getGitStatus)(repoPath, repoName);
|
|
164
|
+
}));
|
|
165
|
+
results.push(...chunkResults);
|
|
166
|
+
}
|
|
167
|
+
return results;
|
|
168
|
+
};
|
|
169
|
+
exports.getAllReposStatus = getAllReposStatus;
|
|
170
|
+
const hasUncommittedChanges = async (repoPath) => {
|
|
171
|
+
const { clean } = await (0, exports.getUncommittedChanges)(repoPath);
|
|
172
|
+
return !clean;
|
|
173
|
+
};
|
|
174
|
+
exports.hasUncommittedChanges = hasUncommittedChanges;
|
|
175
|
+
const isGitRepository = async (repoPath) => {
|
|
176
|
+
try {
|
|
177
|
+
await execAsync('git rev-parse --git-dir', {
|
|
178
|
+
cwd: repoPath,
|
|
179
|
+
timeout: GIT_TIMEOUT,
|
|
180
|
+
});
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
exports.isGitRepository = isGitRepository;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.displayAuthInstructions = exports.fetchOrgRepos = exports.verifyGhAuth = void 0;
|
|
4
|
+
const child_process_1 = require("child_process");
|
|
5
|
+
const util_1 = require("util");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
const cache_1 = require("./cache");
|
|
8
|
+
const config_1 = require("./config");
|
|
9
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
10
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
11
|
+
const verifyGhAuth = async () => {
|
|
12
|
+
try {
|
|
13
|
+
const { stdout } = await execAsync('gh auth status');
|
|
14
|
+
return stdout.includes('Logged in') || stdout.includes('✓');
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
exports.verifyGhAuth = verifyGhAuth;
|
|
21
|
+
const fetchOrgRepos = async (options = {}) => {
|
|
22
|
+
const { forceRefresh = false } = options;
|
|
23
|
+
try {
|
|
24
|
+
const { githubOrg } = (0, config_1.getUserConfig)();
|
|
25
|
+
// Try to get cached repos first
|
|
26
|
+
if (!forceRefresh) {
|
|
27
|
+
const cachedRepos = await (0, cache_1.getCachedRepos)({ org: githubOrg });
|
|
28
|
+
if (cachedRepos) {
|
|
29
|
+
return cachedRepos.sort((a, b) => a.name.localeCompare(b.name));
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
(0, logger_1.logInfo)(githubOrg
|
|
33
|
+
? `Fetching ${githubOrg} repositories from GitHub...`
|
|
34
|
+
: 'Fetching your GitHub repositories... (set an org with `nemus configure` to list an organization)');
|
|
35
|
+
// With no configured org, `gh repo list` (no positional) lists the
|
|
36
|
+
// authenticated user's own repos. With an org, it lists that org's repos.
|
|
37
|
+
const args = [
|
|
38
|
+
'repo', 'list',
|
|
39
|
+
...(githubOrg ? [githubOrg] : []),
|
|
40
|
+
'--limit', '1000',
|
|
41
|
+
'--json', 'name,url,sshUrl,owner,description,isPrivate',
|
|
42
|
+
];
|
|
43
|
+
const { stdout } = await execFileAsync('gh', args);
|
|
44
|
+
const repos = JSON.parse(stdout);
|
|
45
|
+
(0, logger_1.logInfo)(`Found ${repos.length} repositories`);
|
|
46
|
+
// Cache the results (24 hour TTL)
|
|
47
|
+
await (0, cache_1.setCachedRepos)(repos, 86400000, githubOrg);
|
|
48
|
+
return repos.sort((a, b) => a.name.localeCompare(b.name));
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
(0, logger_1.logError)('Failed to fetch repositories from GitHub');
|
|
52
|
+
if (error instanceof Error) {
|
|
53
|
+
(0, logger_1.logError)(error.message);
|
|
54
|
+
}
|
|
55
|
+
throw new Error('Unable to fetch repositories. Please ensure gh CLI is authenticated.');
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
exports.fetchOrgRepos = fetchOrgRepos;
|
|
59
|
+
const displayAuthInstructions = () => {
|
|
60
|
+
console.log('\n' + '='.repeat(60));
|
|
61
|
+
console.log('GitHub CLI Authentication Required');
|
|
62
|
+
console.log('='.repeat(60));
|
|
63
|
+
console.log('\nPlease authenticate with GitHub CLI by running:');
|
|
64
|
+
console.log('\n gh auth login\n');
|
|
65
|
+
console.log('Then try running this command again.');
|
|
66
|
+
console.log('='.repeat(60) + '\n');
|
|
67
|
+
};
|
|
68
|
+
exports.displayAuthInstructions = displayAuthInstructions;
|
|
@@ -0,0 +1,345 @@
|
|
|
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.calculateHealthScore = exports.runAllHealthChecks = exports.checkGhqInstalled = exports.checkMetadataIntegrity = exports.checkDiskSpace = exports.checkDependencies = exports.checkAuthentication = exports.checkUncommittedChanges = exports.checkGitHealth = exports.checkMissingRepositories = void 0;
|
|
37
|
+
const child_process_1 = require("child_process");
|
|
38
|
+
const util_1 = require("util");
|
|
39
|
+
const fs = __importStar(require("fs/promises"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const git_status_1 = require("./git-status");
|
|
42
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
43
|
+
const checkMissingRepositories = async (workspacePath, metadata) => {
|
|
44
|
+
const missingRepos = [];
|
|
45
|
+
for (const repo of metadata.repositories) {
|
|
46
|
+
const repoPath = path.join(workspacePath, repo.directoryName);
|
|
47
|
+
try {
|
|
48
|
+
await fs.access(repoPath);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
missingRepos.push(repo.directoryName);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (missingRepos.length === 0) {
|
|
55
|
+
return {
|
|
56
|
+
category: 'Missing Repositories',
|
|
57
|
+
status: 'healthy',
|
|
58
|
+
message: 'All repositories are present',
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
category: 'Missing Repositories',
|
|
63
|
+
status: 'error',
|
|
64
|
+
message: `${missingRepos.length} repository(ies) missing`,
|
|
65
|
+
details: missingRepos.join(', '),
|
|
66
|
+
actionable: `Run 'workspace sync ${metadata.workspaceName}' to clone missing repositories`,
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
exports.checkMissingRepositories = checkMissingRepositories;
|
|
70
|
+
const checkGitHealth = async (workspacePath, repoNames) => {
|
|
71
|
+
const issues = [];
|
|
72
|
+
for (const repoName of repoNames) {
|
|
73
|
+
const repoPath = path.join(workspacePath, repoName);
|
|
74
|
+
try {
|
|
75
|
+
await fs.access(repoPath);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
continue; // Skip missing repos (handled by checkMissingRepositories)
|
|
79
|
+
}
|
|
80
|
+
const isRepo = await (0, git_status_1.isGitRepository)(repoPath);
|
|
81
|
+
if (!isRepo) {
|
|
82
|
+
issues.push(`${repoName}: not a git repository`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
// Check for corrupted repo
|
|
86
|
+
try {
|
|
87
|
+
await execAsync('git fsck --no-progress', {
|
|
88
|
+
cwd: repoPath,
|
|
89
|
+
timeout: 30000,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
issues.push(`${repoName}: repository may be corrupted`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (issues.length === 0) {
|
|
97
|
+
return {
|
|
98
|
+
category: 'Git Health',
|
|
99
|
+
status: 'healthy',
|
|
100
|
+
message: 'All repositories are healthy',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
category: 'Git Health',
|
|
105
|
+
status: 'error',
|
|
106
|
+
message: `${issues.length} repository(ies) have issues`,
|
|
107
|
+
details: issues.join('\n'),
|
|
108
|
+
actionable: 'Check repository integrity and consider re-cloning problematic repos',
|
|
109
|
+
};
|
|
110
|
+
};
|
|
111
|
+
exports.checkGitHealth = checkGitHealth;
|
|
112
|
+
const checkUncommittedChanges = async (workspacePath, repoNames) => {
|
|
113
|
+
const dirtyRepos = [];
|
|
114
|
+
for (const repoName of repoNames) {
|
|
115
|
+
const repoPath = path.join(workspacePath, repoName);
|
|
116
|
+
try {
|
|
117
|
+
await fs.access(repoPath);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
const hasChanges = await (0, git_status_1.hasUncommittedChanges)(repoPath);
|
|
123
|
+
if (hasChanges) {
|
|
124
|
+
dirtyRepos.push(repoName);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (dirtyRepos.length === 0) {
|
|
128
|
+
return {
|
|
129
|
+
category: 'Uncommitted Changes',
|
|
130
|
+
status: 'healthy',
|
|
131
|
+
message: 'No uncommitted changes',
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
category: 'Uncommitted Changes',
|
|
136
|
+
status: 'warning',
|
|
137
|
+
message: `${dirtyRepos.length} repository(ies) have uncommitted changes`,
|
|
138
|
+
details: dirtyRepos.join(', '),
|
|
139
|
+
actionable: `Review and commit or stash changes before switching branches`,
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
exports.checkUncommittedChanges = checkUncommittedChanges;
|
|
143
|
+
const checkAuthentication = async () => {
|
|
144
|
+
const issues = [];
|
|
145
|
+
// Check GitHub CLI
|
|
146
|
+
try {
|
|
147
|
+
await execAsync('gh auth status', { timeout: 5000 });
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
issues.push('GitHub CLI (gh) not authenticated');
|
|
151
|
+
}
|
|
152
|
+
// Check SSH keys
|
|
153
|
+
try {
|
|
154
|
+
await execAsync('ssh -T git@github.com', { timeout: 5000 });
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
const errorMessage = error instanceof Error ? error.message : '';
|
|
158
|
+
if (!errorMessage.includes('successfully authenticated')) {
|
|
159
|
+
issues.push('SSH key not configured for GitHub');
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (issues.length === 0) {
|
|
163
|
+
return {
|
|
164
|
+
category: 'Authentication',
|
|
165
|
+
status: 'healthy',
|
|
166
|
+
message: 'Authentication configured correctly',
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
category: 'Authentication',
|
|
171
|
+
status: 'warning',
|
|
172
|
+
message: 'Authentication issues detected',
|
|
173
|
+
details: issues.join('\n'),
|
|
174
|
+
actionable: 'Run "gh auth login" or configure SSH keys',
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
exports.checkAuthentication = checkAuthentication;
|
|
178
|
+
const checkDependencies = async (workspacePath, repoNames) => {
|
|
179
|
+
const missingDeps = [];
|
|
180
|
+
for (const repoName of repoNames) {
|
|
181
|
+
const repoPath = path.join(workspacePath, repoName);
|
|
182
|
+
try {
|
|
183
|
+
await fs.access(repoPath);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
// Check for package.json
|
|
189
|
+
const packageJsonPath = path.join(repoPath, 'package.json');
|
|
190
|
+
try {
|
|
191
|
+
await fs.access(packageJsonPath);
|
|
192
|
+
// Check if node_modules exists
|
|
193
|
+
const nodeModulesPath = path.join(repoPath, 'node_modules');
|
|
194
|
+
try {
|
|
195
|
+
await fs.access(nodeModulesPath);
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
missingDeps.push(`${repoName}: missing node_modules`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// No package.json, skip
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (missingDeps.length === 0) {
|
|
206
|
+
return {
|
|
207
|
+
category: 'Dependencies',
|
|
208
|
+
status: 'healthy',
|
|
209
|
+
message: 'All dependencies installed',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
category: 'Dependencies',
|
|
214
|
+
status: 'warning',
|
|
215
|
+
message: `${missingDeps.length} repository(ies) missing dependencies`,
|
|
216
|
+
details: missingDeps.join('\n'),
|
|
217
|
+
actionable: 'Run "npm install" or "yarn install" in affected repositories',
|
|
218
|
+
};
|
|
219
|
+
};
|
|
220
|
+
exports.checkDependencies = checkDependencies;
|
|
221
|
+
const checkDiskSpace = async (workspacePath) => {
|
|
222
|
+
try {
|
|
223
|
+
// Get disk usage for workspace
|
|
224
|
+
const { stdout } = await execAsync(`du -sh "${workspacePath}"`, { timeout: 30000 });
|
|
225
|
+
const sizeStr = stdout.trim().split('\t')[0];
|
|
226
|
+
// Parse size (rough check for > 10GB)
|
|
227
|
+
const sizeValue = parseFloat(sizeStr);
|
|
228
|
+
const unit = sizeStr.replace(/[0-9.]/g, '').trim();
|
|
229
|
+
const isLarge = (unit === 'G' && sizeValue > 10) || unit === 'T';
|
|
230
|
+
if (isLarge) {
|
|
231
|
+
return {
|
|
232
|
+
category: 'Disk Space',
|
|
233
|
+
status: 'warning',
|
|
234
|
+
message: `Workspace is large (${sizeStr})`,
|
|
235
|
+
actionable: 'Consider running "workspace cleanup" to free up space',
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
category: 'Disk Space',
|
|
240
|
+
status: 'healthy',
|
|
241
|
+
message: `Workspace size: ${sizeStr}`,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
245
|
+
return {
|
|
246
|
+
category: 'Disk Space',
|
|
247
|
+
status: 'warning',
|
|
248
|
+
message: 'Could not calculate disk usage',
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
exports.checkDiskSpace = checkDiskSpace;
|
|
253
|
+
const checkMetadataIntegrity = async (workspacePath, metadata) => {
|
|
254
|
+
const issues = [];
|
|
255
|
+
// Check required fields
|
|
256
|
+
if (!metadata.workspaceName) {
|
|
257
|
+
issues.push('Missing workspace name');
|
|
258
|
+
}
|
|
259
|
+
if (!metadata.createdAt) {
|
|
260
|
+
issues.push('Missing creation timestamp');
|
|
261
|
+
}
|
|
262
|
+
if (!metadata.repositories || metadata.repositories.length === 0) {
|
|
263
|
+
issues.push('No repositories in metadata');
|
|
264
|
+
}
|
|
265
|
+
// Check for duplicate directory names
|
|
266
|
+
const dirNames = metadata.repositories.map(r => r.directoryName);
|
|
267
|
+
const uniqueDirNames = new Set(dirNames);
|
|
268
|
+
if (dirNames.length !== uniqueDirNames.size) {
|
|
269
|
+
issues.push('Duplicate directory names in metadata');
|
|
270
|
+
}
|
|
271
|
+
// Check for extra directories not in metadata
|
|
272
|
+
try {
|
|
273
|
+
const entries = await fs.readdir(workspacePath, { withFileTypes: true });
|
|
274
|
+
const directories = entries.filter(e => e.isDirectory()).map(e => e.name);
|
|
275
|
+
const metadataDirNames = new Set(dirNames);
|
|
276
|
+
const extraDirs = directories.filter(dir => !metadataDirNames.has(dir) && !dir.startsWith('.'));
|
|
277
|
+
if (extraDirs.length > 0) {
|
|
278
|
+
issues.push(`${extraDirs.length} directories not tracked in metadata: ${extraDirs.join(', ')}`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
// Ignore read errors
|
|
283
|
+
}
|
|
284
|
+
if (issues.length === 0) {
|
|
285
|
+
return {
|
|
286
|
+
category: 'Metadata Integrity',
|
|
287
|
+
status: 'healthy',
|
|
288
|
+
message: 'Metadata is valid',
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
category: 'Metadata Integrity',
|
|
293
|
+
status: 'warning',
|
|
294
|
+
message: 'Metadata issues detected',
|
|
295
|
+
details: issues.join('\n'),
|
|
296
|
+
actionable: 'Review workspace metadata file',
|
|
297
|
+
};
|
|
298
|
+
};
|
|
299
|
+
exports.checkMetadataIntegrity = checkMetadataIntegrity;
|
|
300
|
+
const checkGhqInstalled = async () => {
|
|
301
|
+
try {
|
|
302
|
+
await execAsync('which ghq', { timeout: 5000 });
|
|
303
|
+
return {
|
|
304
|
+
category: 'ghq',
|
|
305
|
+
status: 'healthy',
|
|
306
|
+
message: 'ghq is installed (fast cached clones enabled)',
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
return {
|
|
311
|
+
category: 'ghq',
|
|
312
|
+
status: 'warning',
|
|
313
|
+
message: 'ghq is not installed',
|
|
314
|
+
details: 'Without ghq, repos are cloned directly with git — slower, no shared cache, and large repos can hit clone timeouts.',
|
|
315
|
+
actionable: 'Install ghq: brew install ghq (macOS) — https://github.com/x-motemen/ghq#installation',
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
exports.checkGhqInstalled = checkGhqInstalled;
|
|
320
|
+
const runAllHealthChecks = async (workspacePath, metadata) => {
|
|
321
|
+
const repoNames = metadata.repositories.map(r => r.directoryName);
|
|
322
|
+
const checks = await Promise.all([
|
|
323
|
+
(0, exports.checkMissingRepositories)(workspacePath, metadata),
|
|
324
|
+
(0, exports.checkGitHealth)(workspacePath, repoNames),
|
|
325
|
+
(0, exports.checkUncommittedChanges)(workspacePath, repoNames),
|
|
326
|
+
(0, exports.checkAuthentication)(),
|
|
327
|
+
(0, exports.checkGhqInstalled)(),
|
|
328
|
+
(0, exports.checkDependencies)(workspacePath, repoNames),
|
|
329
|
+
(0, exports.checkDiskSpace)(workspacePath),
|
|
330
|
+
(0, exports.checkMetadataIntegrity)(workspacePath, metadata),
|
|
331
|
+
]);
|
|
332
|
+
return checks;
|
|
333
|
+
};
|
|
334
|
+
exports.runAllHealthChecks = runAllHealthChecks;
|
|
335
|
+
const calculateHealthScore = (results) => {
|
|
336
|
+
const weights = {
|
|
337
|
+
healthy: 100,
|
|
338
|
+
warning: 60,
|
|
339
|
+
error: 0,
|
|
340
|
+
};
|
|
341
|
+
const totalWeight = results.reduce((sum, result) => sum + weights[result.status], 0);
|
|
342
|
+
const maxWeight = results.length * 100;
|
|
343
|
+
return Math.round((totalWeight / maxWeight) * 100);
|
|
344
|
+
};
|
|
345
|
+
exports.calculateHealthScore = calculateHealthScore;
|