@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,296 @@
|
|
|
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.registerMigrateCommand = registerMigrateCommand;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs/promises"));
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const config_1 = require("../utils/config");
|
|
41
|
+
const workspace_meta_1 = require("../utils/workspace-meta");
|
|
42
|
+
const claude_integration_1 = require("../utils/claude-integration");
|
|
43
|
+
const logger_1 = require("../utils/logger");
|
|
44
|
+
const colors_1 = require("../utils/colors");
|
|
45
|
+
const agent_config_1 = require("../utils/agent-config");
|
|
46
|
+
function registerMigrateCommand(parent) {
|
|
47
|
+
parent
|
|
48
|
+
.command('migrate')
|
|
49
|
+
.description('Migrate all workspaces to latest format (regenerate context files, update metadata)')
|
|
50
|
+
.option('--dry-run', 'Show what would be changed without making changes')
|
|
51
|
+
.action(async (opts) => {
|
|
52
|
+
await handleMigrate(opts);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function handleMigrate(opts) {
|
|
56
|
+
const dryRun = opts.dryRun ?? false;
|
|
57
|
+
if (dryRun) {
|
|
58
|
+
(0, logger_1.logInfo)('Dry run mode - no changes will be made\n');
|
|
59
|
+
}
|
|
60
|
+
const workspaces = await (0, workspace_meta_1.listWorkspaces)(false);
|
|
61
|
+
if (workspaces.length === 0) {
|
|
62
|
+
(0, logger_1.logInfo)('No workspaces found. Nothing to migrate.');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
(0, logger_1.logInfo)(`Found ${(0, colors_1.colorize)(String(workspaces.length), 'cyan')} workspaces to migrate\n`);
|
|
66
|
+
let migrated = 0;
|
|
67
|
+
let skipped = 0;
|
|
68
|
+
let errors = 0;
|
|
69
|
+
for (const ws of workspaces) {
|
|
70
|
+
const wsPath = ws.path;
|
|
71
|
+
const metadata = await (0, workspace_meta_1.loadMetadata)(wsPath);
|
|
72
|
+
if (!metadata) {
|
|
73
|
+
// No metadata file - reconstruct it by scanning git subdirectories
|
|
74
|
+
(0, logger_1.logWarning)(`${ws.name}: no metadata found - reconstructing from git repos`);
|
|
75
|
+
const reconstructed = await reconstructMetadata(ws.name, wsPath);
|
|
76
|
+
if (!reconstructed) {
|
|
77
|
+
(0, logger_1.logError)(` ${ws.name}: could not reconstruct metadata (no git repos found), skipping`);
|
|
78
|
+
skipped++;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (!dryRun) {
|
|
82
|
+
await (0, workspace_meta_1.saveMetadata)(wsPath, reconstructed);
|
|
83
|
+
(0, logger_1.logSuccess)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: metadata created (${reconstructed.repositories.length} repos detected)`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
(0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would create metadata (${reconstructed.repositories.length} repos detected)`);
|
|
87
|
+
}
|
|
88
|
+
// Regenerate context files using the reconstructed metadata.
|
|
89
|
+
const meta = reconstructed;
|
|
90
|
+
if (!dryRun) {
|
|
91
|
+
const repos = meta.repositories
|
|
92
|
+
.filter(r => r.status === 'success')
|
|
93
|
+
.map(r => ({ name: r.name, description: '', url: r.cloneUrl, owner: { login: r.owner }, sshUrl: r.cloneUrl }));
|
|
94
|
+
try {
|
|
95
|
+
await (0, claude_integration_1.generateClaudeContext)(wsPath, ws.name, repos, meta);
|
|
96
|
+
}
|
|
97
|
+
catch { /* context gen is best-effort */ }
|
|
98
|
+
}
|
|
99
|
+
migrated++;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
const dirNames = metadata.repositories
|
|
104
|
+
.filter(r => r.status === 'success')
|
|
105
|
+
.map(r => r.directoryName);
|
|
106
|
+
const contextFiles = (0, agent_config_1.getContextFileNames)();
|
|
107
|
+
// Read all existing context files first — before any writes.
|
|
108
|
+
// If any file is missing we must fall back to full regeneration;
|
|
109
|
+
// we determine this BEFORE touching anything so we never mix
|
|
110
|
+
// surgical patches with a subsequent full overwrite.
|
|
111
|
+
const existingContents = new Map();
|
|
112
|
+
let needsFullRegen = false;
|
|
113
|
+
for (const fileName of contextFiles) {
|
|
114
|
+
try {
|
|
115
|
+
existingContents.set(fileName, await fs.readFile(path.join(wsPath, fileName), 'utf-8'));
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
needsFullRegen = true;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
// Build the per-repo section (needs disk access; do once for both paths).
|
|
123
|
+
const perRepoSection = await (0, claude_integration_1.buildPerRepoContextSection)(wsPath, dirNames);
|
|
124
|
+
const repoCount = perRepoSection ? (perRepoSection.match(/^###/gm) || []).length : 0;
|
|
125
|
+
if (dryRun) {
|
|
126
|
+
if (needsFullRegen) {
|
|
127
|
+
(0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would regenerate context files from scratch (context file missing)`);
|
|
128
|
+
}
|
|
129
|
+
else if (repoCount > 0) {
|
|
130
|
+
(0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would embed per-repo context from ${repoCount} location(s) into ${contextFiles.join(', ')}`);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
(0, logger_1.logInfo)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: would update ${contextFiles.join(', ')} (no per-repo context files found — any existing section removed)`);
|
|
134
|
+
}
|
|
135
|
+
migrated++;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// Ensure lastModified is set
|
|
139
|
+
if (!metadata.lastModified) {
|
|
140
|
+
metadata.lastModified = new Date().toISOString();
|
|
141
|
+
await (0, workspace_meta_1.saveMetadata)(wsPath, metadata);
|
|
142
|
+
}
|
|
143
|
+
if (needsFullRegen) {
|
|
144
|
+
// One or more context files are missing — regenerate all from scratch.
|
|
145
|
+
const repos = metadata.repositories
|
|
146
|
+
.filter(r => r.status === 'success')
|
|
147
|
+
.map(r => ({
|
|
148
|
+
name: r.name, description: '', url: r.cloneUrl,
|
|
149
|
+
owner: { login: r.owner }, sshUrl: r.cloneUrl,
|
|
150
|
+
}));
|
|
151
|
+
await (0, claude_integration_1.generateClaudeContext)(wsPath, ws.name, repos, metadata);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// All context files exist — patch only the per-repo section in each.
|
|
155
|
+
for (const [fileName, existing] of existingContents) {
|
|
156
|
+
const updated = upsertPerRepoSection(existing, perRepoSection);
|
|
157
|
+
if (updated !== existing) {
|
|
158
|
+
await fs.writeFile(path.join(wsPath, fileName), updated, 'utf-8');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const detail = needsFullRegen
|
|
163
|
+
? ' (regenerated from scratch)'
|
|
164
|
+
: repoCount > 0
|
|
165
|
+
? ` (embedded per-repo context from ${repoCount} location(s))`
|
|
166
|
+
: ' (no per-repo context files found)';
|
|
167
|
+
(0, logger_1.logSuccess)(` ${(0, colors_1.colorize)(ws.name, 'cyan')}: migrated${detail}`);
|
|
168
|
+
migrated++;
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
172
|
+
(0, logger_1.logError)(` ${ws.name}: ${msg}`);
|
|
173
|
+
errors++;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
console.log('');
|
|
177
|
+
(0, logger_1.logInfo)(dryRun ? 'Dry run complete:' : 'Migration complete:');
|
|
178
|
+
console.log(` ${(0, colors_1.colorize)(String(migrated), 'green')} ${dryRun ? 'would migrate' : 'migrated'}`);
|
|
179
|
+
if (skipped > 0)
|
|
180
|
+
console.log(` ${(0, colors_1.colorize)(String(skipped), 'yellow')} skipped`);
|
|
181
|
+
if (errors > 0)
|
|
182
|
+
console.log(` ${(0, colors_1.colorize)(String(errors), 'red')} errors`);
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Reconstruct a WorkspaceMetadata object for a workspace that has no metadata
|
|
186
|
+
* file by scanning subdirectories for git repositories and reading their
|
|
187
|
+
* remote origin URLs.
|
|
188
|
+
*
|
|
189
|
+
* Returns null if no git repos are found in the workspace directory.
|
|
190
|
+
*/
|
|
191
|
+
async function reconstructMetadata(workspaceName, workspacePath) {
|
|
192
|
+
let entries;
|
|
193
|
+
try {
|
|
194
|
+
entries = await fs.readdir(workspacePath);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
const repositories = [];
|
|
200
|
+
for (const entry of entries) {
|
|
201
|
+
const repoPath = path.join(workspacePath, entry);
|
|
202
|
+
try {
|
|
203
|
+
const stat = await fs.stat(repoPath);
|
|
204
|
+
if (!stat.isDirectory())
|
|
205
|
+
continue;
|
|
206
|
+
// Check it's a git repo
|
|
207
|
+
await fs.access(path.join(repoPath, '.git'));
|
|
208
|
+
// Get the remote origin URL
|
|
209
|
+
let cloneUrl = '';
|
|
210
|
+
let owner = (0, config_1.getUserConfig)().githubOrg || 'your-org';
|
|
211
|
+
try {
|
|
212
|
+
cloneUrl = (0, child_process_1.execSync)('git remote get-url origin', {
|
|
213
|
+
cwd: repoPath, stdio: 'pipe', encoding: 'utf-8',
|
|
214
|
+
}).trim();
|
|
215
|
+
// Extract owner from SSH URL: git@github.com:owner/repo.git
|
|
216
|
+
const sshMatch = cloneUrl.match(/github\.com[:/]([^/]+)\//);
|
|
217
|
+
if (sshMatch)
|
|
218
|
+
owner = sshMatch[1];
|
|
219
|
+
}
|
|
220
|
+
catch { /* no remote - leave blank */ }
|
|
221
|
+
// Derive the canonical repo name from the remote URL, falling back
|
|
222
|
+
// to the directory name.
|
|
223
|
+
let repoName = entry;
|
|
224
|
+
try {
|
|
225
|
+
const urlMatch = cloneUrl.match(/\/([^/]+?)\.git$/) ||
|
|
226
|
+
cloneUrl.match(/\/([^/]+)$/);
|
|
227
|
+
if (urlMatch)
|
|
228
|
+
repoName = urlMatch[1];
|
|
229
|
+
}
|
|
230
|
+
catch { /* use directory name */ }
|
|
231
|
+
repositories.push({
|
|
232
|
+
name: repoName,
|
|
233
|
+
directoryName: entry,
|
|
234
|
+
owner,
|
|
235
|
+
clonedAt: new Date().toISOString(),
|
|
236
|
+
cloneUrl,
|
|
237
|
+
status: 'success',
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
catch { /* not accessible or not a git repo - skip */ }
|
|
241
|
+
}
|
|
242
|
+
if (repositories.length === 0)
|
|
243
|
+
return null;
|
|
244
|
+
return {
|
|
245
|
+
workspaceName,
|
|
246
|
+
createdAt: new Date().toISOString(),
|
|
247
|
+
lastModified: new Date().toISOString(),
|
|
248
|
+
repositories,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Insert or replace the '## Per-Repository Context' section in an existing
|
|
253
|
+
* workspace context file, leaving everything else (user notes, etc.) intact.
|
|
254
|
+
*
|
|
255
|
+
* Insertion order (preferred first — we want the section as early as
|
|
256
|
+
* possible so the LLM weights it heavily):
|
|
257
|
+
* 1. Before '## Common Workflows' — the new canonical position
|
|
258
|
+
* 2. Before '## Workspace Management' (older layouts)
|
|
259
|
+
* 3. Before '## AI Agent Rules' (older layouts)
|
|
260
|
+
* 4. Before '## Tips for Working' (older layouts)
|
|
261
|
+
* 5. Before '## Notes' (legacy fallback)
|
|
262
|
+
* 6. Before '## Saved Context' (legacy fallback)
|
|
263
|
+
* 7. Appended at the end (last resort)
|
|
264
|
+
*
|
|
265
|
+
* If `newSection` is null the existing section (if any) is removed so that
|
|
266
|
+
* a workspace that previously had per-repo context but no longer does gets
|
|
267
|
+
* cleaned up.
|
|
268
|
+
*/
|
|
269
|
+
function upsertPerRepoSection(content, newSection) {
|
|
270
|
+
// Match the section *including* its leading blank line(s) so removal
|
|
271
|
+
// leaves a clean join with no leftover blank lines. No 'm' flag so '$'
|
|
272
|
+
// only matches the true end-of-string.
|
|
273
|
+
const sectionRegex = /\n{1,2}## Per-Repository Context\b[\s\S]*?(?=\n## |\n#{1,2} |$)/;
|
|
274
|
+
// Only trimEnd() the very end of the file — never touch the body.
|
|
275
|
+
const base = content.replace(sectionRegex, '').trimEnd();
|
|
276
|
+
if (!newSection)
|
|
277
|
+
return base + '\n'; // section removed, nothing to add back
|
|
278
|
+
const block = `\n\n${newSection.trim()}\n`;
|
|
279
|
+
// Try anchors in order of preference — earliest first so per-repo rules
|
|
280
|
+
// are read by the LLM before generic boilerplate.
|
|
281
|
+
const anchors = [
|
|
282
|
+
'\n## Common Workflows',
|
|
283
|
+
'\n## Workspace Management',
|
|
284
|
+
'\n## AI Agent Rules',
|
|
285
|
+
'\n## Tips for Working',
|
|
286
|
+
'\n## Notes',
|
|
287
|
+
'\n## Saved Context',
|
|
288
|
+
];
|
|
289
|
+
for (const anchor of anchors) {
|
|
290
|
+
if (base.includes(anchor)) {
|
|
291
|
+
return base.replace(anchor, `${block}${anchor}`);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
// Append (last resort)
|
|
295
|
+
return base + block;
|
|
296
|
+
}
|
|
@@ -0,0 +1,217 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.registerRemoveRepoCommand = registerRemoveRepoCommand;
|
|
40
|
+
const fs = __importStar(require("fs/promises"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const config_1 = require("../utils/config");
|
|
43
|
+
const workspace_meta_1 = require("../utils/workspace-meta");
|
|
44
|
+
const claude_integration_1 = require("../utils/claude-integration");
|
|
45
|
+
const logger_1 = require("../utils/logger");
|
|
46
|
+
const colors_1 = require("../utils/colors");
|
|
47
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
48
|
+
const inquirer_autocomplete_prompt_1 = __importDefault(require("inquirer-autocomplete-prompt"));
|
|
49
|
+
const fuzzy = __importStar(require("fuzzy"));
|
|
50
|
+
const command_helpers_1 = require("../utils/command-helpers");
|
|
51
|
+
inquirer_1.default.registerPrompt('autocomplete', inquirer_autocomplete_prompt_1.default);
|
|
52
|
+
function registerRemoveRepoCommand(parent) {
|
|
53
|
+
parent
|
|
54
|
+
.command('remove-repo')
|
|
55
|
+
.alias('rr')
|
|
56
|
+
.description('Remove a repo from a workspace')
|
|
57
|
+
.option('-w, --workspace <name>', 'Workspace name')
|
|
58
|
+
.option('-r, --repos <repos>', 'Comma-separated repository directory names')
|
|
59
|
+
.action(async (opts, cmd) => {
|
|
60
|
+
const globalOpts = (0, command_helpers_1.getGlobalOpts)(cmd);
|
|
61
|
+
await handleRemoveRepo({ ...opts, ...globalOpts });
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async function handleRemoveRepo(opts) {
|
|
65
|
+
console.log('\n' + '='.repeat(60));
|
|
66
|
+
console.log((0, colors_1.colorize)('Remove Repository Instances', 'bright'));
|
|
67
|
+
console.log('='.repeat(60) + '\n');
|
|
68
|
+
try {
|
|
69
|
+
(0, logger_1.logStep)(1, 4, 'Select workspace...');
|
|
70
|
+
const workspaceName = await (0, command_helpers_1.resolveWorkspace)(opts.workspace);
|
|
71
|
+
const workspacePath = path.join(config_1.WORKSPACES_DIR, workspaceName);
|
|
72
|
+
(0, logger_1.logInfo)(`Selected workspace: ${(0, colors_1.colorize)(workspaceName, 'cyan')}`);
|
|
73
|
+
(0, logger_1.logStep)(2, 4, 'Loading repository instances...');
|
|
74
|
+
const metadata = await (0, workspace_meta_1.loadMetadata)(workspacePath);
|
|
75
|
+
const successRepos = metadata?.repositories.filter(r => r.status === 'success') ?? [];
|
|
76
|
+
const entries = await fs.readdir(workspacePath, { withFileTypes: true });
|
|
77
|
+
const diskDirs = entries
|
|
78
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.'))
|
|
79
|
+
.map(e => e.name);
|
|
80
|
+
const metaDirNames = new Set(successRepos.map(r => r.directoryName));
|
|
81
|
+
const repoEntries = [];
|
|
82
|
+
for (const repo of successRepos) {
|
|
83
|
+
repoEntries.push({
|
|
84
|
+
displayName: repo.directoryName !== repo.name
|
|
85
|
+
? `${repo.directoryName} (${repo.name})`
|
|
86
|
+
: repo.directoryName,
|
|
87
|
+
dirName: repo.directoryName,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
for (const dir of diskDirs) {
|
|
91
|
+
if (!metaDirNames.has(dir)) {
|
|
92
|
+
repoEntries.push({ displayName: `${dir} (untracked)`, dirName: dir });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (repoEntries.length === 0) {
|
|
96
|
+
(0, logger_1.logInfo)('No repositories found in this workspace.');
|
|
97
|
+
if (opts.yes) {
|
|
98
|
+
await fs.rm(workspacePath, { recursive: true, force: true });
|
|
99
|
+
(0, logger_1.logSuccess)(`Workspace "${workspaceName}" deleted.`);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const { deleteWorkspace } = await inquirer_1.default.prompt([{
|
|
103
|
+
type: 'confirm', name: 'deleteWorkspace',
|
|
104
|
+
message: `Delete the entire workspace folder "${workspaceName}"?`, default: false,
|
|
105
|
+
}]);
|
|
106
|
+
if (deleteWorkspace) {
|
|
107
|
+
await fs.rm(workspacePath, { recursive: true, force: true });
|
|
108
|
+
(0, logger_1.logSuccess)(`Workspace "${workspaceName}" deleted.`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
(0, logger_1.logInfo)('No action taken.');
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
(0, logger_1.logStep)(3, 4, 'Select instances to remove...');
|
|
117
|
+
let selectedDirs;
|
|
118
|
+
if (opts.repos) {
|
|
119
|
+
selectedDirs = (0, command_helpers_1.parseList)(opts.repos);
|
|
120
|
+
const unknownDirs = selectedDirs.filter(d => !repoEntries.some(e => e.dirName === d));
|
|
121
|
+
if (unknownDirs.length > 0) {
|
|
122
|
+
(0, logger_1.logError)(`Directories not found in workspace: ${unknownDirs.join(', ')}`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.log('\n' + (0, colors_1.colorize)('Repository Selection', 'bright'));
|
|
128
|
+
console.log('Type to search repositories. Use arrow keys to navigate, Enter to select.');
|
|
129
|
+
console.log('Type "done" when finished selecting.\n');
|
|
130
|
+
selectedDirs = [];
|
|
131
|
+
while (true) {
|
|
132
|
+
const available = repoEntries.filter(e => !selectedDirs.includes(e.dirName));
|
|
133
|
+
if (available.length === 0) {
|
|
134
|
+
console.log((0, colors_1.colorize)('All repositories selected.', 'yellow'));
|
|
135
|
+
break;
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const { repoDir } = await inquirer_1.default.prompt([{
|
|
139
|
+
type: 'autocomplete', name: 'repoDir',
|
|
140
|
+
message: `Search and select repository (${(0, colors_1.colorize)(String(selectedDirs.length), 'cyan')} selected):`,
|
|
141
|
+
source: async (_answersSoFar, input) => {
|
|
142
|
+
const searchInput = input || '';
|
|
143
|
+
const doneOption = { name: (0, colors_1.colorize)('done - Finish selection', 'green'), value: 'done' };
|
|
144
|
+
if (!searchInput || searchInput.toLowerCase().startsWith('done')) {
|
|
145
|
+
return [doneOption, ...available.map(e => ({ name: e.displayName, value: e.dirName }))];
|
|
146
|
+
}
|
|
147
|
+
const results = fuzzy.filter(searchInput, available, { extract: (e) => e.displayName });
|
|
148
|
+
return [doneOption, ...results.map(result => ({ name: result.original.displayName, value: result.original.dirName }))];
|
|
149
|
+
},
|
|
150
|
+
pageSize: 16,
|
|
151
|
+
}]);
|
|
152
|
+
if (repoDir === 'done') {
|
|
153
|
+
if (selectedDirs.length === 0) {
|
|
154
|
+
console.log((0, colors_1.colorize)('\nYou must select at least one repository\n', 'yellow'));
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
selectedDirs.push(repoDir);
|
|
160
|
+
const entry = repoEntries.find(e => e.dirName === repoDir);
|
|
161
|
+
console.log((0, colors_1.colorize)(`Added: ${entry?.displayName || repoDir}`, 'green'));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
console.log('\n');
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
console.log(`\n${(0, colors_1.colorize)(`Selected ${selectedDirs.length} repository instance${selectedDirs.length === 1 ? '' : 's'}:`, 'cyan')}`);
|
|
170
|
+
selectedDirs.forEach(dir => console.log(` - ${dir}`));
|
|
171
|
+
console.log('');
|
|
172
|
+
if (!opts.yes) {
|
|
173
|
+
const { confirm } = await inquirer_1.default.prompt([{
|
|
174
|
+
type: 'confirm', name: 'confirm',
|
|
175
|
+
message: `Remove ${selectedDirs.length} instance(s)? This will delete the directories.`, default: false,
|
|
176
|
+
}]);
|
|
177
|
+
if (!confirm) {
|
|
178
|
+
(0, logger_1.logInfo)('Removal cancelled');
|
|
179
|
+
process.exit(0);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
(0, logger_1.logStep)(4, 4, 'Removing instances...');
|
|
183
|
+
for (const dirName of selectedDirs) {
|
|
184
|
+
const dirPath = path.join(workspacePath, dirName);
|
|
185
|
+
try {
|
|
186
|
+
await fs.rm(dirPath, { recursive: true, force: true });
|
|
187
|
+
(0, logger_1.logSuccess)(`Removed: ${dirName}`);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
(0, logger_1.logError)(`Failed to remove ${dirName}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
const removedSet = new Set(selectedDirs);
|
|
194
|
+
if (metadata) {
|
|
195
|
+
metadata.repositories = metadata.repositories.filter(r => !removedSet.has(r.directoryName));
|
|
196
|
+
await (0, workspace_meta_1.saveMetadata)(workspacePath, metadata);
|
|
197
|
+
const remainingRepos = metadata.repositories
|
|
198
|
+
.filter(r => r.status === 'success')
|
|
199
|
+
.map(r => ({
|
|
200
|
+
name: r.name, url: '', sshUrl: r.cloneUrl,
|
|
201
|
+
owner: { login: r.owner }, description: '', isPrivate: true,
|
|
202
|
+
}));
|
|
203
|
+
if (remainingRepos.length > 0) {
|
|
204
|
+
await (0, claude_integration_1.generateClaudeContext)(workspacePath, workspaceName, remainingRepos, metadata);
|
|
205
|
+
}
|
|
206
|
+
console.log(`\nWorkspace now has ${(0, colors_1.colorize)(String(metadata.repositories.length), 'cyan')} repositories\n`);
|
|
207
|
+
}
|
|
208
|
+
(0, logger_1.logSuccess)('Repository instances removed successfully!');
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
(0, logger_1.logError)('Failed to remove repository instances');
|
|
212
|
+
if (error instanceof Error) {
|
|
213
|
+
(0, logger_1.logError)(error.message);
|
|
214
|
+
}
|
|
215
|
+
process.exit(1);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
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.registerReportBugCommand = registerReportBugCommand;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const logger_1 = require("../utils/logger");
|
|
40
|
+
const colors_1 = require("../utils/colors");
|
|
41
|
+
const bug_report_1 = require("../utils/bug-report");
|
|
42
|
+
function getVersion() {
|
|
43
|
+
try {
|
|
44
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json'), 'utf-8'));
|
|
45
|
+
return pkg.version ?? 'unknown';
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return 'unknown';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function registerReportBugCommand(parent) {
|
|
52
|
+
parent
|
|
53
|
+
.command('report-bug')
|
|
54
|
+
.description('File the last error (or a custom message) as a GitHub issue')
|
|
55
|
+
.option('-m, --message <message>', 'Report a custom message instead of the last captured error')
|
|
56
|
+
.option('-f, --force', 'Report even if the error looks environmental (network/auth)')
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
await handleReportBug(opts);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async function handleReportBug(opts) {
|
|
62
|
+
let captured;
|
|
63
|
+
if (opts.message) {
|
|
64
|
+
captured = {
|
|
65
|
+
command: 'w report-bug (manual)',
|
|
66
|
+
message: opts.message,
|
|
67
|
+
timestamp: new Date().toISOString(),
|
|
68
|
+
version: getVersion(),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
captured = (0, bug_report_1.readLastError)();
|
|
73
|
+
if (!captured) {
|
|
74
|
+
(0, logger_1.logError)('No recent error to report.');
|
|
75
|
+
(0, logger_1.logInfo)('Run a command that fails first, or use: w report-bug -m "describe the bug"');
|
|
76
|
+
process.exit(1);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
// Show which error we're about to report (with its age). Some failures
|
|
80
|
+
// — notably `nemus -- <prompt>` — exit without updating last-error.json, so
|
|
81
|
+
// the most recent capture could be an older crash. Surfacing the
|
|
82
|
+
// timestamp lets the user catch a stale report before filing.
|
|
83
|
+
const ageMs = Date.now() - new Date(captured.timestamp).getTime();
|
|
84
|
+
const ageMin = Math.floor(ageMs / 60000);
|
|
85
|
+
const when = Number.isFinite(ageMin)
|
|
86
|
+
? (ageMin < 1 ? 'just now' : `${ageMin} min ago`)
|
|
87
|
+
: 'unknown time';
|
|
88
|
+
(0, logger_1.logInfo)(`Last captured error (${when}): ${(0, colors_1.colorize)(captured.command, 'cyan')}`);
|
|
89
|
+
(0, logger_1.logInfo)(` ${captured.message.split('\n')[0].slice(0, 100)}`);
|
|
90
|
+
if (ageMin >= 10) {
|
|
91
|
+
(0, logger_1.logWarning)(`This error is ${ageMin} min old — make sure it's the one you mean to report.`);
|
|
92
|
+
(0, logger_1.logInfo)('Tip: pass -m "..." to report a specific message instead.');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
(0, logger_1.logInfo)(`Reporting to ${(0, colors_1.colorize)(bug_report_1.BUG_REPORT_REPO, 'cyan')}...`);
|
|
96
|
+
const result = (0, bug_report_1.reportBug)(captured, getVersion(), { force: opts.force });
|
|
97
|
+
switch (result.status) {
|
|
98
|
+
case 'created':
|
|
99
|
+
(0, logger_1.logSuccess)(`Bug issue created: ${(0, colors_1.colorize)(result.url, 'cyan')}`);
|
|
100
|
+
break;
|
|
101
|
+
case 'duplicate':
|
|
102
|
+
(0, logger_1.logInfo)(`This error was already reported: ${(0, colors_1.colorize)(result.url, 'cyan')}`);
|
|
103
|
+
(0, logger_1.logInfo)('Subscribe there for updates — no duplicate filed.');
|
|
104
|
+
break;
|
|
105
|
+
case 'skipped':
|
|
106
|
+
(0, logger_1.logWarning)(result.reason || 'Skipped.');
|
|
107
|
+
break;
|
|
108
|
+
case 'failed':
|
|
109
|
+
(0, logger_1.logError)(result.reason || 'Failed to file the bug report.');
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
}
|