@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
package/dist/program.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
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.program = void 0;
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const colors_1 = require("./utils/colors");
|
|
41
|
+
// Read version from package.json
|
|
42
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
43
|
+
const g = colors_1.colors.green;
|
|
44
|
+
const d = colors_1.colors.dim;
|
|
45
|
+
const b = colors_1.colors.bright;
|
|
46
|
+
const r = colors_1.colors.reset;
|
|
47
|
+
const INNER = 38;
|
|
48
|
+
const titleLine = `>_ Nemus`;
|
|
49
|
+
const titlePad = ' '.repeat(Math.max(0, INNER - 2 - titleLine.length));
|
|
50
|
+
const versionLine = `v${pkg.version} · multi-repo workspaces`;
|
|
51
|
+
const versionPad = ' '.repeat(Math.max(0, INNER - 7 - versionLine.length));
|
|
52
|
+
const bar = '─'.repeat(INNER);
|
|
53
|
+
const bannerText = `
|
|
54
|
+
${d} ╭${bar}╮${r}
|
|
55
|
+
${d} │${r} ${g}>_${r} ${b}Nemus${r}${titlePad}${d}│${r}
|
|
56
|
+
${d} │${r} ${d}${versionLine}${r}${versionPad}${d}│${r}
|
|
57
|
+
${d} ╰${bar}╯${r}
|
|
58
|
+
`;
|
|
59
|
+
exports.program = new commander_1.Command();
|
|
60
|
+
exports.program
|
|
61
|
+
.name('workspace')
|
|
62
|
+
.description('Multi-repo workspace manager')
|
|
63
|
+
.version(pkg.version, '-V, --version')
|
|
64
|
+
.option('-f, --force-refresh', 'Force refresh GitHub repos (skip cache)')
|
|
65
|
+
.option('-y, --yes', 'Skip confirmations')
|
|
66
|
+
.addHelpText('before', bannerText);
|
|
67
|
+
// Register top-level commands
|
|
68
|
+
const create_1 = require("./commands/create");
|
|
69
|
+
const list_1 = require("./commands/list");
|
|
70
|
+
const update_1 = require("./commands/update");
|
|
71
|
+
const delete_1 = require("./commands/delete");
|
|
72
|
+
const sync_1 = require("./commands/sync");
|
|
73
|
+
const status_1 = require("./commands/status");
|
|
74
|
+
const diff_1 = require("./commands/diff");
|
|
75
|
+
const run_1 = require("./commands/run");
|
|
76
|
+
const go_1 = require("./commands/go");
|
|
77
|
+
const doctor_1 = require("./commands/doctor");
|
|
78
|
+
const analyze_deps_1 = require("./commands/analyze-deps");
|
|
79
|
+
const history_1 = require("./commands/history");
|
|
80
|
+
const cleanup_1 = require("./commands/cleanup");
|
|
81
|
+
const remove_repo_1 = require("./commands/remove-repo");
|
|
82
|
+
const archive_1 = require("./commands/archive");
|
|
83
|
+
const sessions_1 = require("./commands/sessions");
|
|
84
|
+
const generate_docs_1 = require("./commands/generate-docs");
|
|
85
|
+
const configure_1 = require("./commands/configure");
|
|
86
|
+
const configure_claude_1 = require("./commands/configure-claude");
|
|
87
|
+
const ghq_status_1 = require("./commands/ghq-status");
|
|
88
|
+
const save_context_1 = require("./commands/save-context");
|
|
89
|
+
const migrate_1 = require("./commands/migrate");
|
|
90
|
+
const report_bug_1 = require("./commands/report-bug");
|
|
91
|
+
(0, create_1.registerCreateCommand)(exports.program);
|
|
92
|
+
(0, list_1.registerListCommand)(exports.program);
|
|
93
|
+
(0, update_1.registerUpdateCommand)(exports.program);
|
|
94
|
+
(0, delete_1.registerDeleteCommand)(exports.program);
|
|
95
|
+
(0, sync_1.registerSyncCommand)(exports.program);
|
|
96
|
+
(0, status_1.registerStatusCommand)(exports.program);
|
|
97
|
+
(0, diff_1.registerDiffCommand)(exports.program);
|
|
98
|
+
(0, run_1.registerRunCommand)(exports.program);
|
|
99
|
+
(0, go_1.registerGoCommand)(exports.program);
|
|
100
|
+
(0, doctor_1.registerDoctorCommand)(exports.program);
|
|
101
|
+
(0, analyze_deps_1.registerAnalyzeDepsCommand)(exports.program);
|
|
102
|
+
(0, history_1.registerHistoryCommand)(exports.program);
|
|
103
|
+
(0, cleanup_1.registerCleanupCommand)(exports.program);
|
|
104
|
+
(0, remove_repo_1.registerRemoveRepoCommand)(exports.program);
|
|
105
|
+
(0, archive_1.registerArchiveCommand)(exports.program);
|
|
106
|
+
(0, sessions_1.registerSessionsCommand)(exports.program);
|
|
107
|
+
(0, generate_docs_1.registerGenerateDocsCommand)(exports.program);
|
|
108
|
+
(0, configure_1.registerConfigureCommand)(exports.program);
|
|
109
|
+
(0, configure_claude_1.registerConfigureClaudeCommand)(exports.program);
|
|
110
|
+
(0, ghq_status_1.registerGhqStatusCommand)(exports.program);
|
|
111
|
+
(0, save_context_1.registerSaveContextCommand)(exports.program);
|
|
112
|
+
(0, migrate_1.registerMigrateCommand)(exports.program);
|
|
113
|
+
(0, report_bug_1.registerReportBugCommand)(exports.program);
|
|
114
|
+
// Register TUI (delegates to existing Ink/React implementation)
|
|
115
|
+
exports.program
|
|
116
|
+
.command('tui')
|
|
117
|
+
.description('Launch interactive terminal UI')
|
|
118
|
+
.action(async () => {
|
|
119
|
+
const { main } = await Promise.resolve().then(() => __importStar(require('./cli/tui')));
|
|
120
|
+
await main();
|
|
121
|
+
});
|
|
122
|
+
// Register dashboard command
|
|
123
|
+
const dashboard_1 = require("./commands/dashboard");
|
|
124
|
+
(0, dashboard_1.registerDashboardCommand)(exports.program);
|
|
125
|
+
// Register grouped commands
|
|
126
|
+
const suite_1 = require("./commands/suite");
|
|
127
|
+
const branch_1 = require("./commands/branch");
|
|
128
|
+
const cache_1 = require("./commands/cache");
|
|
129
|
+
const mcp_1 = require("./commands/mcp");
|
|
130
|
+
(0, suite_1.registerSuiteCommands)(exports.program);
|
|
131
|
+
(0, branch_1.registerBranchCommands)(exports.program);
|
|
132
|
+
(0, cache_1.registerCacheCommands)(exports.program);
|
|
133
|
+
(0, mcp_1.registerMcpCommands)(exports.program);
|
|
134
|
+
// Register deprecated aliases
|
|
135
|
+
const deprecated_aliases_1 = require("./commands/deprecated-aliases");
|
|
136
|
+
(0, deprecated_aliases_1.registerDeprecatedAliases)(exports.program);
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
workspace-table.py — Workspace Manager status-line extension for Claude Code
|
|
4
|
+
(auto-generated by workspace-manager)
|
|
5
|
+
|
|
6
|
+
Outputs ONLY the workspace repo table (branch · PR · CI · dirty state).
|
|
7
|
+
Claude Code already renders model / cost / context itself, so this script
|
|
8
|
+
adds only what it doesn't show.
|
|
9
|
+
|
|
10
|
+
Configure in ~/.claude/settings.json:
|
|
11
|
+
"statusLine": {
|
|
12
|
+
"type": "command",
|
|
13
|
+
"command": "~/.workspace-manager-table.py",
|
|
14
|
+
"padding": 0
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Claude Code passes session data as JSON on stdin.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import hashlib
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import subprocess
|
|
24
|
+
import sys
|
|
25
|
+
import time
|
|
26
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
27
|
+
from pathlib import Path
|
|
28
|
+
|
|
29
|
+
# ─── Cache ───────────────────────────────────────────────────────────────────
|
|
30
|
+
CACHE_FILE = Path.home() / ".workspace-manager-cache" / "pr-status.json"
|
|
31
|
+
CACHE_TTL = 300 # seconds
|
|
32
|
+
|
|
33
|
+
# ─── ANSI helpers ─────────────────────────────────────────────────────────────
|
|
34
|
+
RESET = "\033[0m"
|
|
35
|
+
BOLD = "\033[1m"
|
|
36
|
+
DIM = "\033[2m"
|
|
37
|
+
CYAN = "\033[38;5;87m"
|
|
38
|
+
BLUE = "\033[38;5;75m"
|
|
39
|
+
MAGENTA = "\033[38;5;213m"
|
|
40
|
+
GREEN = "\033[38;5;120m"
|
|
41
|
+
YELLOW = "\033[38;5;221m"
|
|
42
|
+
RED = "\033[38;5;203m"
|
|
43
|
+
GRAY = "\033[38;5;245m"
|
|
44
|
+
PURPLE = "\033[38;5;141m"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def color(text: str, c: str) -> str:
|
|
48
|
+
return f"{c}{text}{RESET}"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def hyperlink(text: str, url: str | None) -> str:
|
|
52
|
+
if not url:
|
|
53
|
+
return text
|
|
54
|
+
return f"\033]8;;{url}\033\\{text}\033]8;;\033\\"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
# ─── Cache helpers ────────────────────────────────────────────────────────────
|
|
58
|
+
def load_cache() -> dict:
|
|
59
|
+
try:
|
|
60
|
+
return json.loads(CACHE_FILE.read_text())
|
|
61
|
+
except Exception:
|
|
62
|
+
return {}
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def save_cache(cache: dict) -> None:
|
|
66
|
+
try:
|
|
67
|
+
CACHE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
CACHE_FILE.write_text(json.dumps(cache))
|
|
69
|
+
except Exception:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# ─── Git / PR helpers ─────────────────────────────────────────────────────────
|
|
74
|
+
def repo_web_url(cwd: str) -> str | None:
|
|
75
|
+
try:
|
|
76
|
+
r = subprocess.run(
|
|
77
|
+
["git", "-C", cwd, "remote", "get-url", "origin"],
|
|
78
|
+
capture_output=True, text=True, timeout=0.3,
|
|
79
|
+
)
|
|
80
|
+
if r.returncode != 0:
|
|
81
|
+
return None
|
|
82
|
+
url = r.stdout.strip()
|
|
83
|
+
if url.startswith("git@"):
|
|
84
|
+
host, path = url[4:].split(":", 1)
|
|
85
|
+
url = f"https://{host}/{path}"
|
|
86
|
+
if url.endswith(".git"):
|
|
87
|
+
url = url[:-4]
|
|
88
|
+
return url
|
|
89
|
+
except Exception:
|
|
90
|
+
return None
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def pr_info(cwd: str, branch: str) -> dict:
|
|
94
|
+
"""Return cached PR info, firing a background refresh if stale."""
|
|
95
|
+
repo_url = repo_web_url(cwd)
|
|
96
|
+
if not repo_url:
|
|
97
|
+
return {"url": None, "fallback": None, "number": None,
|
|
98
|
+
"state": None, "isDraft": None, "ci": None}
|
|
99
|
+
key = hashlib.sha1(f"{repo_url}@{branch}".encode()).hexdigest()
|
|
100
|
+
cache = load_cache()
|
|
101
|
+
entry = cache.get(key)
|
|
102
|
+
now = time.time()
|
|
103
|
+
fresh = entry and now - entry.get("ts", 0) < CACHE_TTL
|
|
104
|
+
fallback = f"{repo_url}/tree/{branch}"
|
|
105
|
+
if not fresh:
|
|
106
|
+
try:
|
|
107
|
+
subprocess.Popen(
|
|
108
|
+
[sys.executable, str(Path(__file__).resolve()), "--refresh-pr", key, cwd, branch],
|
|
109
|
+
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
|
|
110
|
+
stdin=subprocess.DEVNULL, start_new_session=True,
|
|
111
|
+
)
|
|
112
|
+
except Exception:
|
|
113
|
+
pass
|
|
114
|
+
e = entry or {}
|
|
115
|
+
return {
|
|
116
|
+
"url": e.get("url"),
|
|
117
|
+
"fallback": fallback,
|
|
118
|
+
"number": e.get("number"),
|
|
119
|
+
"state": e.get("state"),
|
|
120
|
+
"isDraft": e.get("isDraft"),
|
|
121
|
+
"ci": e.get("ci"),
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def refresh_pr(key: str, cwd: str, branch: str) -> None:
|
|
126
|
+
info: dict = {"url": None, "number": None, "state": None,
|
|
127
|
+
"isDraft": None, "ci": None}
|
|
128
|
+
try:
|
|
129
|
+
r = subprocess.run(
|
|
130
|
+
["gh", "pr", "view", "--json",
|
|
131
|
+
"url,number,state,isDraft,statusCheckRollup"],
|
|
132
|
+
capture_output=True, text=True, timeout=10, cwd=cwd,
|
|
133
|
+
)
|
|
134
|
+
if r.returncode == 0 and r.stdout.strip():
|
|
135
|
+
data = json.loads(r.stdout)
|
|
136
|
+
info["url"] = data.get("url")
|
|
137
|
+
info["number"] = data.get("number")
|
|
138
|
+
info["state"] = data.get("state")
|
|
139
|
+
info["isDraft"] = data.get("isDraft")
|
|
140
|
+
# Summarise CI rollup
|
|
141
|
+
rollup = data.get("statusCheckRollup") or []
|
|
142
|
+
info["ci"] = _rollup_ci(rollup)
|
|
143
|
+
except Exception:
|
|
144
|
+
pass
|
|
145
|
+
cache = load_cache()
|
|
146
|
+
cache[key] = {**info, "ts": time.time()}
|
|
147
|
+
save_cache(cache)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _rollup_ci(rollup: list) -> str | None:
|
|
151
|
+
if not rollup:
|
|
152
|
+
return None
|
|
153
|
+
has_fail = has_pending = False
|
|
154
|
+
for c in rollup:
|
|
155
|
+
s = (c.get("state") or c.get("conclusion") or c.get("status") or "").upper()
|
|
156
|
+
if s in ("FAILURE", "TIMED_OUT", "CANCELLED", "ERROR"):
|
|
157
|
+
has_fail = True
|
|
158
|
+
elif s in ("PENDING", "IN_PROGRESS", "QUEUED", "", "EXPECTED"):
|
|
159
|
+
has_pending = True
|
|
160
|
+
if has_fail:
|
|
161
|
+
return "failure"
|
|
162
|
+
if has_pending:
|
|
163
|
+
return "pending"
|
|
164
|
+
return "success"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def git_info(cwd: str) -> tuple[str, int | None] | None:
|
|
168
|
+
try:
|
|
169
|
+
r = subprocess.run(
|
|
170
|
+
["git", "-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"],
|
|
171
|
+
capture_output=True, text=True, timeout=1.0,
|
|
172
|
+
)
|
|
173
|
+
if r.returncode != 0:
|
|
174
|
+
return None
|
|
175
|
+
branch = r.stdout.strip()
|
|
176
|
+
except Exception:
|
|
177
|
+
return None
|
|
178
|
+
dirty: int | None = None
|
|
179
|
+
try:
|
|
180
|
+
s = subprocess.run(
|
|
181
|
+
["git", "-C", cwd, "status", "--porcelain"],
|
|
182
|
+
capture_output=True, text=True, timeout=2.0,
|
|
183
|
+
)
|
|
184
|
+
if s.returncode == 0:
|
|
185
|
+
dirty = len([l for l in s.stdout.splitlines() if l.strip()])
|
|
186
|
+
except Exception:
|
|
187
|
+
pass
|
|
188
|
+
return branch, dirty
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# ─── Workspace discovery ───────────────────────────────────────────────────────
|
|
192
|
+
DEFAULT_BRANCHES = {"main", "master", "develop", "production", "trunk"}
|
|
193
|
+
|
|
194
|
+
CI_ICON = {"success": "✓", "failure": "✗", "pending": "◌"}
|
|
195
|
+
CI_COLOR = {"success": GREEN, "failure": RED, "pending": YELLOW}
|
|
196
|
+
PR_ICONS = {
|
|
197
|
+
"open": "\ue725", # nf-cod-git_pull_request
|
|
198
|
+
"draft": "\uea64", # nf-oct-git_pull_request_draft
|
|
199
|
+
"merged": "\uea6a", # nf-oct-git_merge
|
|
200
|
+
"closed": "\ue729", # nf-cod-git_pull_request_closed
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def find_workspace(cwd: str) -> tuple[Path, dict] | None:
|
|
205
|
+
p = Path(cwd).resolve()
|
|
206
|
+
for candidate in [p, *p.parents]:
|
|
207
|
+
meta = candidate / ".workspace-meta.json"
|
|
208
|
+
if meta.is_file():
|
|
209
|
+
try:
|
|
210
|
+
data = json.loads(meta.read_text())
|
|
211
|
+
return candidate, data
|
|
212
|
+
except Exception:
|
|
213
|
+
return None
|
|
214
|
+
return None
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def gather_repo_row(repo_path: Path, is_active: bool) -> dict:
|
|
218
|
+
cwd_str = str(repo_path)
|
|
219
|
+
g = git_info(cwd_str)
|
|
220
|
+
name = repo_path.name
|
|
221
|
+
if not g:
|
|
222
|
+
return {"active": is_active, "name": name, "branch": None,
|
|
223
|
+
"branch_url": None, "pr": None, "dirty": None, "no_git": True}
|
|
224
|
+
branch, dirty = g
|
|
225
|
+
pi = pr_info(cwd_str, branch)
|
|
226
|
+
return {
|
|
227
|
+
"active": is_active,
|
|
228
|
+
"name": name,
|
|
229
|
+
"branch": branch,
|
|
230
|
+
"branch_url": pi.get("url") or pi.get("fallback"),
|
|
231
|
+
"pr_num": pi.get("number"),
|
|
232
|
+
"pr_url": pi.get("url"),
|
|
233
|
+
"pr_state": pi.get("state"),
|
|
234
|
+
"pr_draft": pi.get("isDraft"),
|
|
235
|
+
"pr_ci": pi.get("ci"),
|
|
236
|
+
"dirty": dirty,
|
|
237
|
+
"no_git": False,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# ─── Cell renderers ────────────────────────────────────────────────────────────
|
|
242
|
+
def pr_plain(row: dict) -> str:
|
|
243
|
+
if row["no_git"] or not row.get("pr_num"):
|
|
244
|
+
return "—" if not row["no_git"] and row.get("branch") else ""
|
|
245
|
+
s = f"#{row['pr_num']}"
|
|
246
|
+
if row.get("pr_draft"): s += " draft"
|
|
247
|
+
elif row.get("pr_state") == "MERGED": s += " merged"
|
|
248
|
+
elif row.get("pr_state") == "CLOSED": s += " closed"
|
|
249
|
+
ci = row.get("pr_ci")
|
|
250
|
+
if ci:
|
|
251
|
+
s += f" {CI_ICON.get(ci, '')}"
|
|
252
|
+
return s
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def pr_styled(row: dict) -> str:
|
|
256
|
+
if row["no_git"] or not row.get("pr_num"):
|
|
257
|
+
return color("—", GRAY) if not row["no_git"] and row.get("branch") else ""
|
|
258
|
+
num = f"#{row['pr_num']}"
|
|
259
|
+
draft = row.get("pr_draft")
|
|
260
|
+
state = row.get("pr_state", "OPEN")
|
|
261
|
+
icon = PR_ICONS.get("draft" if draft else state.lower(), PR_ICONS["open"])
|
|
262
|
+
if draft: c = GRAY
|
|
263
|
+
elif state == "MERGED": c = PURPLE
|
|
264
|
+
elif state == "CLOSED": c = RED
|
|
265
|
+
else: c = GREEN
|
|
266
|
+
label = f"{icon} {num} {'draft' if draft else state.lower()}"
|
|
267
|
+
ci = row.get("pr_ci")
|
|
268
|
+
ci_part = f" {color(CI_ICON.get(ci,''), CI_COLOR.get(ci, GRAY))}" if ci else ""
|
|
269
|
+
return hyperlink(color(label, c), row.get("pr_url")) + ci_part
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def dirty_plain(row: dict) -> str:
|
|
273
|
+
if row["no_git"]: return "(no git)"
|
|
274
|
+
if row["dirty"] is None: return "*?"
|
|
275
|
+
return f"*{row['dirty']}" if row["dirty"] > 0 else ""
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def dirty_styled(row: dict) -> str:
|
|
279
|
+
if row["no_git"]: return color("(no git)", GRAY)
|
|
280
|
+
if row["dirty"] is None: return color("*?", GRAY)
|
|
281
|
+
return color(f"*{row['dirty']}", RED) if row["dirty"] > 0 else ""
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
# ─── Table renderer ────────────────────────────────────────────────────────────
|
|
285
|
+
def render_repo_table(rows: list[dict]) -> list[str]:
|
|
286
|
+
headers = ("REPO", "BRANCH", "PR", "DIRTY")
|
|
287
|
+
plain_rows = [(r["name"], r.get("branch") or "", pr_plain(r), dirty_plain(r))
|
|
288
|
+
for r in rows]
|
|
289
|
+
plain_rows.insert(0, headers)
|
|
290
|
+
widths = [max(len(p[i]) for p in plain_rows) for i in range(4)]
|
|
291
|
+
|
|
292
|
+
def pad(s: str, w: int) -> str:
|
|
293
|
+
return s + " " * (w - len(s))
|
|
294
|
+
|
|
295
|
+
header = " " + " ".join(
|
|
296
|
+
color(pad(h, widths[i]), DIM + GRAY) for i, h in enumerate(headers)
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
result = [header]
|
|
300
|
+
for r in rows:
|
|
301
|
+
marker = color("▸ ", PURPLE) if r["active"] else " "
|
|
302
|
+
name_c = PURPLE + BOLD if r["active"] else BLUE
|
|
303
|
+
name_cell = color(r["name"], name_c if not r["no_git"] else DIM + GRAY)
|
|
304
|
+
name_cell += " " * (widths[0] - len(r["name"]))
|
|
305
|
+
|
|
306
|
+
br_plain = r.get("branch") or ""
|
|
307
|
+
br_styled = (hyperlink(color(br_plain, MAGENTA), r.get("branch_url"))
|
|
308
|
+
if br_plain else "")
|
|
309
|
+
br_cell = br_styled + " " * (widths[1] - len(br_plain))
|
|
310
|
+
|
|
311
|
+
pp = pr_plain(r)
|
|
312
|
+
pr_cell = pr_styled(r) + " " * (widths[2] - len(pp))
|
|
313
|
+
|
|
314
|
+
dp = dirty_plain(r)
|
|
315
|
+
d_cell = dirty_styled(r) + " " * (widths[3] - len(dp))
|
|
316
|
+
|
|
317
|
+
result.append(f"{marker}{name_cell} {br_cell} {pr_cell} {d_cell}".rstrip())
|
|
318
|
+
return result
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
# ─── Main ─────────────────────────────────────────────────────────────────────
|
|
322
|
+
def main() -> None:
|
|
323
|
+
"""
|
|
324
|
+
Claude Code calls this script and shows whatever we write to stdout
|
|
325
|
+
as the statusLine — an *additional* line shown below the editor.
|
|
326
|
+
Claude Code's own header (model · tokens · cost) is always shown
|
|
327
|
+
regardless of what we output here.
|
|
328
|
+
|
|
329
|
+
Behaviour contract:
|
|
330
|
+
- Not in a workspace → output nothing (CC shows its default footer)
|
|
331
|
+
- In workspace, all repos on default branch → output nothing
|
|
332
|
+
- In workspace with feature-branch repos → output the repo table only
|
|
333
|
+
|
|
334
|
+
We NEVER output model info, cost, or anything that duplicates CC's
|
|
335
|
+
own display. We NEVER modify the user's existing styling.
|
|
336
|
+
"""
|
|
337
|
+
try:
|
|
338
|
+
data = json.load(sys.stdin)
|
|
339
|
+
except Exception:
|
|
340
|
+
data = {}
|
|
341
|
+
|
|
342
|
+
cwd = (data.get("workspace") or {}).get("current_dir") or os.getcwd()
|
|
343
|
+
ws = find_workspace(cwd)
|
|
344
|
+
|
|
345
|
+
if not ws:
|
|
346
|
+
# Not in a workspace — output nothing so CC's default footer is shown unchanged.
|
|
347
|
+
return
|
|
348
|
+
|
|
349
|
+
ws_path, ws_meta = ws
|
|
350
|
+
|
|
351
|
+
# Find which repo (if any) is currently active
|
|
352
|
+
active_repo: str | None = None
|
|
353
|
+
try:
|
|
354
|
+
rel = Path(cwd).resolve().relative_to(ws_path)
|
|
355
|
+
if rel.parts:
|
|
356
|
+
active_repo = rel.parts[0]
|
|
357
|
+
except ValueError:
|
|
358
|
+
pass
|
|
359
|
+
|
|
360
|
+
repo_tasks = []
|
|
361
|
+
for repo in ws_meta.get("repositories") or []:
|
|
362
|
+
dir_name = repo.get("directoryName") or repo.get("name")
|
|
363
|
+
if not dir_name:
|
|
364
|
+
continue
|
|
365
|
+
repo_path = ws_path / dir_name
|
|
366
|
+
if not repo_path.is_dir():
|
|
367
|
+
continue
|
|
368
|
+
repo_tasks.append((repo_path, dir_name == active_repo))
|
|
369
|
+
|
|
370
|
+
if not repo_tasks:
|
|
371
|
+
return
|
|
372
|
+
|
|
373
|
+
max_workers = min(8, len(repo_tasks))
|
|
374
|
+
with ThreadPoolExecutor(max_workers=max_workers) as ex:
|
|
375
|
+
rows = list(ex.map(lambda t: gather_repo_row(*t), repo_tasks))
|
|
376
|
+
|
|
377
|
+
# Filter: only repos on non-default branches (toggle not available in CC)
|
|
378
|
+
rows = [r for r in rows if r.get("branch")
|
|
379
|
+
and r["branch"] not in DEFAULT_BRANCHES]
|
|
380
|
+
|
|
381
|
+
if not rows:
|
|
382
|
+
# All repos are on default branches — nothing interesting to show.
|
|
383
|
+
# Output nothing to preserve CC's default footer.
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
# Output ONLY the table. CC's model/cost header is shown above this independently.
|
|
387
|
+
sys.stdout.write("\n".join(render_repo_table(rows)))
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if __name__ == "__main__":
|
|
391
|
+
if len(sys.argv) >= 4 and sys.argv[1] == "--refresh-pr":
|
|
392
|
+
refresh_pr(sys.argv[2], sys.argv[3], sys.argv[4] if len(sys.argv) > 4 else "")
|
|
393
|
+
else:
|
|
394
|
+
main()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HOOK_MARKER = exports.DASHBOARD_DEFAULTS = void 0;
|
|
4
|
+
exports.DASHBOARD_DEFAULTS = {
|
|
5
|
+
sessionName: 'ws-dashboard',
|
|
6
|
+
sidebarWidthPercent: 20,
|
|
7
|
+
pollIntervalMs: 2000,
|
|
8
|
+
staleTtlMs: 300000,
|
|
9
|
+
};
|
|
10
|
+
/** Marker string embedded in hook commands for detection/removal */
|
|
11
|
+
exports.HOOK_MARKER = 'workspace-dashboard-hook';
|