claudeup 6.2.0 → 6.3.0
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/README.md +22 -0
- package/bin/claudeup.js +6 -1
- package/package.json +6 -6
- package/src/__tests__/alias-adopt.test.ts +331 -329
- package/src/__tests__/alias-parser.test.ts +384 -376
- package/src/__tests__/alias-shell-writer.test.ts +638 -625
- package/src/__tests__/alias-store.test.ts +143 -143
- package/src/__tests__/catalog-cache-store.test.ts +265 -265
- package/src/__tests__/catalog-notice.test.ts +123 -123
- package/src/__tests__/cli-apply-seams.test.ts +12 -8
- package/src/__tests__/cli-router.test.ts +132 -3
- package/src/__tests__/cli-update-view.test.ts +27 -8
- package/src/__tests__/community-staleness.test.ts +0 -2
- package/src/__tests__/component-badge.test.ts +4 -4
- package/src/__tests__/content-drift.test.ts +5 -1
- package/src/__tests__/conventions-integration.test.ts +774 -689
- package/src/__tests__/conventions-manager.test.ts +1216 -1152
- package/src/__tests__/doctor-bins.test.ts +14 -6
- package/src/__tests__/doctor.test.ts +438 -425
- package/src/__tests__/dual-write-prevention.test.ts +277 -282
- package/src/__tests__/enabled-not-installed.test.ts +71 -63
- package/src/__tests__/file-locking.test.ts +196 -196
- package/src/__tests__/gap-fill-versions.test.ts +318 -311
- package/src/__tests__/github-budget.test.ts +170 -164
- package/src/__tests__/gitignore-detector.test.ts +160 -152
- package/src/__tests__/gitignore-fixer.test.ts +285 -247
- package/src/__tests__/gitignore-prerun.test.ts +57 -57
- package/src/__tests__/gitignore-resolver.test.ts +173 -146
- package/src/__tests__/gitignore-service.test.ts +121 -119
- package/src/__tests__/go-module.test.ts +43 -0
- package/src/__tests__/install-command.test.ts +3 -3
- package/src/__tests__/install-plan.test.ts +13 -7
- package/src/__tests__/manifest.test.ts +16 -5
- package/src/__tests__/markdown-renderer.test.ts +0 -1
- package/src/__tests__/marketplace-badge.test.ts +111 -90
- package/src/__tests__/marketplace-version.test.ts +64 -61
- package/src/__tests__/plugin-manager-fallback.test.ts +249 -239
- package/src/__tests__/plugin-requires.test.ts +55 -1
- package/src/__tests__/plugin-setup.test.ts +111 -9
- package/src/__tests__/profile-command.test.ts +1 -7
- package/src/__tests__/profile-materializer.test.ts +31 -8
- package/src/__tests__/profile-sync.test.ts +23 -5
- package/src/__tests__/registry-version-resolution.test.ts +61 -47
- package/src/__tests__/resolve-executable.test.ts +1 -1
- package/src/__tests__/resolver.test.ts +38 -13
- package/src/__tests__/scope-action.test.ts +52 -50
- package/src/__tests__/scope-squares.test.tsx +4 -5
- package/src/__tests__/skill-install-files.test.ts +111 -103
- package/src/__tests__/symlink-manager.test.ts +27 -10
- package/src/__tests__/theme-env.test.ts +281 -0
- package/src/__tests__/theme-resolve.test.ts +380 -0
- package/src/__tests__/update-apply.test.ts +1 -3
- package/src/__tests__/useGitignoreModal.test.ts +69 -61
- package/src/__tests__/version-snapshot.test.ts +183 -165
- package/src/cli/ansi.ts +23 -15
- package/src/cli/doctor.ts +10 -9
- package/src/cli/install.ts +3 -3
- package/src/cli/profile.ts +5 -4
- package/src/cli/prompt.ts +0 -1
- package/src/cli/router.ts +69 -2
- package/src/cli/update-view.ts +11 -6
- package/src/cli/update.ts +9 -4
- package/src/cli/upgrade.ts +6 -4
- package/src/data/alias-flags.ts +260 -260
- package/src/data/gitignore-defaults.ts +20 -20
- package/src/data/gitignore-reasons.ts +86 -92
- package/src/data/gitignore-templates.ts +14 -14
- package/src/data/predefined-profiles.ts +1 -2
- package/src/data/skill-repos.ts +43 -35
- package/src/main.tsx +29 -6
- package/src/opentui.d.ts +1 -3
- package/src/prerunner/index.ts +7 -8
- package/src/services/alias-settings.ts +20 -23
- package/src/services/alias-shell-writer.ts +800 -803
- package/src/services/alias-store.ts +77 -77
- package/src/services/claude-settings.ts +27 -18
- package/src/services/content-drift.ts +14 -4
- package/src/services/conventions-manager.ts +692 -617
- package/src/services/doctor.ts +464 -403
- package/src/services/gitignore-detector.ts +113 -103
- package/src/services/gitignore-fixer.ts +204 -189
- package/src/services/gitignore-prerun.ts +26 -26
- package/src/services/gitignore-resolver.ts +162 -144
- package/src/services/gitignore-service.ts +120 -117
- package/src/services/install-plan.ts +4 -4
- package/src/services/local-marketplace.ts +7 -5
- package/src/services/manifest.ts +1 -1
- package/src/services/marketplace-catalog-git.ts +5 -2
- package/src/services/marketplace-fetcher.ts +241 -235
- package/src/services/plugin-manager.ts +17 -20
- package/src/services/plugin-mcp-config.ts +2 -2
- package/src/services/plugin-requires.ts +16 -8
- package/src/services/plugin-setup.ts +32 -15
- package/src/services/plugin-version-check.ts +4 -4
- package/src/services/profile-materializer.ts +9 -5
- package/src/services/profile-sync.ts +12 -4
- package/src/services/profiles.ts +3 -3
- package/src/services/resolver.ts +10 -6
- package/src/services/settings-manager.ts +82 -46
- package/src/services/skills-manager.ts +11 -9
- package/src/services/symlink-manager.ts +2 -5
- package/src/services/toolchain.ts +3 -3
- package/src/services/update-cache.ts +1 -1
- package/src/services/update-engine.ts +4 -4
- package/src/services/update-plan.ts +9 -11
- package/src/services/version-snapshot.ts +88 -88
- package/src/types/gitignore.ts +28 -28
- package/src/ui/App.tsx +36 -36
- package/src/ui/adapters/settingsAdapter.ts +2 -2
- package/src/ui/components/CategoryHeader.tsx +1 -1
- package/src/ui/components/FlagDetailEditor.tsx +0 -0
- package/src/ui/components/ScopeIndicator.tsx +3 -1
- package/src/ui/components/ScrollableList.tsx +2 -1
- package/src/ui/components/StyledText.tsx +1 -1
- package/src/ui/components/layout/FooterHints.tsx +5 -3
- package/src/ui/components/layout/Panel.tsx +2 -2
- package/src/ui/components/layout/ScreenLayout.tsx +5 -4
- package/src/ui/components/modals/InputModal.tsx +7 -1
- package/src/ui/components/modals/ModalContainer.tsx +3 -3
- package/src/ui/components/modals/SelectModal.tsx +1 -1
- package/src/ui/components/primitives/DetailSection.tsx +1 -1
- package/src/ui/components/primitives/KeyValueLine.tsx +1 -1
- package/src/ui/components/primitives/ScopeSquares.tsx +2 -2
- package/src/ui/hooks/index.ts +0 -1
- package/src/ui/hooks/useGitignoreModal.ts +1 -5
- package/src/ui/hooks/useMismatchModal.ts +4 -10
- package/src/ui/renderers/cliToolRenderers.tsx +2 -2
- package/src/ui/renderers/gitignoreRenderers.tsx +2 -2
- package/src/ui/renderers/mcpRenderers.tsx +1 -1
- package/src/ui/renderers/pluginRenderers.tsx +3 -9
- package/src/ui/renderers/profileRenderers.tsx +9 -8
- package/src/ui/renderers/settingsRenderers.tsx +4 -4
- package/src/ui/renderers/skillRenderers.tsx +14 -14
- package/src/ui/screens/AliasScreen.tsx +31 -34
- package/src/ui/screens/CliToolsScreen.tsx +14 -13
- package/src/ui/screens/EnvVarsScreen.tsx +8 -8
- package/src/ui/screens/GitignoreScreen.tsx +15 -14
- package/src/ui/screens/McpRegistryScreen.tsx +10 -7
- package/src/ui/screens/McpScreen.tsx +10 -10
- package/src/ui/screens/PluginsScreen.tsx +17 -21
- package/src/ui/screens/ProfilesScreen.tsx +25 -24
- package/src/ui/screens/SkillsScreen.tsx +16 -14
- package/src/ui/state/AppContext.tsx +4 -8
- package/src/ui/state/DimensionsContext.tsx +3 -2
- package/src/ui/theme-mode.ts +20 -38
- package/src/ui/theme-resolve.ts +148 -0
- package/src/utils/clipboard.ts +5 -5
- package/src/utils/command-utils.ts +2 -2
- package/src/utils/config-dir.ts +1 -3
- package/src/utils/file-locking.ts +88 -86
- package/src/utils/go-module.ts +36 -0
- package/src/ui/hooks/useAsyncData.ts +0 -127
- package/src/ui/state/AnimationContext.tsx +0 -76
|
@@ -1,103 +1,97 @@
|
|
|
1
1
|
import type { RuleAction } from "../types/gitignore.js";
|
|
2
2
|
|
|
3
3
|
const RULE_REASONS = new Map<string, string>([
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
"Team MCP configuration should be committed so shared tools are discoverable.",
|
|
83
|
-
],
|
|
84
|
-
[
|
|
85
|
-
key("track", "plugin.json"),
|
|
86
|
-
"The plugin manifest is source metadata required by the plugin system.",
|
|
87
|
-
],
|
|
4
|
+
[
|
|
5
|
+
key("ignore", ".claude/settings.local.json"),
|
|
6
|
+
"Personal Claude settings belong to each developer and should not be shared.",
|
|
7
|
+
],
|
|
8
|
+
[
|
|
9
|
+
key("ignore", ".claude/scheduled_tasks.lock"),
|
|
10
|
+
"Runtime lock files are local process state and should be regenerated locally.",
|
|
11
|
+
],
|
|
12
|
+
[
|
|
13
|
+
key("ignore", ".claude/cache/"),
|
|
14
|
+
"Claude cache contents are local generated data and can grow quickly.",
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
key("ignore", ".claude/.statusline-worktree-*"),
|
|
18
|
+
"Statusline worktree markers are local runtime state.",
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
key("ignore", "ai-docs/sessions/"),
|
|
22
|
+
"Session transcripts and scratch notes are local working artifacts.",
|
|
23
|
+
],
|
|
24
|
+
[
|
|
25
|
+
key("ignore", ".mnemex/"),
|
|
26
|
+
"Local memory/index data is machine-specific and regenerated by tooling.",
|
|
27
|
+
],
|
|
28
|
+
[
|
|
29
|
+
key("ignore", ".claudemem/"),
|
|
30
|
+
"Local claudemem indexes are generated from the repo and should not be committed.",
|
|
31
|
+
],
|
|
32
|
+
[
|
|
33
|
+
key("ignore", "gtd/sessions/"),
|
|
34
|
+
"Local GTD session artifacts are personal workflow state.",
|
|
35
|
+
],
|
|
36
|
+
[
|
|
37
|
+
key("ignore", ".agents/"),
|
|
38
|
+
"Local agent workspaces and runtime artifacts should stay out of team history.",
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
key("ignore", "node_modules/"),
|
|
42
|
+
"Installed dependencies are restored from the package manager lockfile.",
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
key("ignore", ".env"),
|
|
46
|
+
"Environment files commonly contain local secrets and machine-specific values.",
|
|
47
|
+
],
|
|
48
|
+
[
|
|
49
|
+
key("ignore", ".env.local"),
|
|
50
|
+
"Local environment overrides commonly contain secrets or developer-specific values.",
|
|
51
|
+
],
|
|
52
|
+
[
|
|
53
|
+
key("ignore", ".DS_Store"),
|
|
54
|
+
"macOS Finder metadata is machine-generated noise.",
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
key("ignore", "dist/"),
|
|
58
|
+
"Distribution output is generated from source during builds.",
|
|
59
|
+
],
|
|
60
|
+
[
|
|
61
|
+
key("ignore", "build/"),
|
|
62
|
+
"Build output is generated from source during builds.",
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
key("ignore", "*.log"),
|
|
66
|
+
"Log files are runtime output and usually contain noisy local details.",
|
|
67
|
+
],
|
|
68
|
+
[key("ignore", "coverage/"), "Coverage reports are generated by test runs."],
|
|
69
|
+
[key("ignore", ".cache/"), "Tool cache contents are local generated data."],
|
|
70
|
+
[
|
|
71
|
+
key("track", ".claude/settings.json"),
|
|
72
|
+
"Team Claude settings should be committed so everyone gets the same project behavior.",
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
key("track", ".mcp.json"),
|
|
76
|
+
"Team MCP configuration should be committed so shared tools are discoverable.",
|
|
77
|
+
],
|
|
78
|
+
[
|
|
79
|
+
key("track", "plugin.json"),
|
|
80
|
+
"The plugin manifest is source metadata required by the plugin system.",
|
|
81
|
+
],
|
|
88
82
|
]);
|
|
89
83
|
|
|
90
84
|
export function getGitignoreRuleReason(
|
|
91
|
-
|
|
92
|
-
|
|
85
|
+
action: RuleAction,
|
|
86
|
+
pattern: string,
|
|
93
87
|
): string {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
const reason = RULE_REASONS.get(key(action, pattern));
|
|
89
|
+
if (reason) return reason;
|
|
90
|
+
return action === "ignore"
|
|
91
|
+
? "A managed rule says this path should stay out of git."
|
|
92
|
+
: "A managed rule says this path should stay tracked in git.";
|
|
99
93
|
}
|
|
100
94
|
|
|
101
95
|
function key(action: RuleAction, pattern: string): string {
|
|
102
|
-
|
|
96
|
+
return `${action}:${pattern}`;
|
|
103
97
|
}
|
|
@@ -6,20 +6,20 @@ import type { GitignoreManifest } from "../types/gitignore.js";
|
|
|
6
6
|
* apply when explicitly requested.
|
|
7
7
|
*/
|
|
8
8
|
export const BUILTIN_TEMPLATES: Record<string, GitignoreManifest> = {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
"common-dev": {
|
|
10
|
+
ignore: [
|
|
11
|
+
"node_modules/",
|
|
12
|
+
".env",
|
|
13
|
+
".env.local",
|
|
14
|
+
".DS_Store",
|
|
15
|
+
"dist/",
|
|
16
|
+
"build/",
|
|
17
|
+
"*.log",
|
|
18
|
+
"coverage/",
|
|
19
|
+
".cache/",
|
|
20
|
+
],
|
|
21
|
+
track: [],
|
|
22
|
+
},
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
export type BuiltinTemplateName = keyof typeof BUILTIN_TEMPLATES;
|
|
@@ -78,8 +78,7 @@ export const PREDEFINED_PROFILES: PredefinedProfile[] = [
|
|
|
78
78
|
{
|
|
79
79
|
id: "frontend-pro",
|
|
80
80
|
name: "Frontend Pro",
|
|
81
|
-
description:
|
|
82
|
-
"UI implementation, design fidelity, browser-driven workflows",
|
|
81
|
+
description: "UI implementation, design fidelity, browser-driven workflows",
|
|
83
82
|
icon: "★",
|
|
84
83
|
magusPlugins: [
|
|
85
84
|
"dev",
|
package/src/data/skill-repos.ts
CHANGED
|
@@ -12,11 +12,11 @@ export interface RecommendedSkill {
|
|
|
12
12
|
// ─── Skill Sets (grouped skills from a single repo) ──────────────────────────
|
|
13
13
|
|
|
14
14
|
export interface RecommendedSkillSet {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
name: string;
|
|
16
|
+
repo: string;
|
|
17
|
+
description: string;
|
|
18
|
+
icon: string;
|
|
19
|
+
stars?: number;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// ─── Star reliability classification ────────────────────────────────────────
|
|
@@ -24,11 +24,11 @@ export interface RecommendedSkillSet {
|
|
|
24
24
|
|
|
25
25
|
/** Mega-repos: huge projects that happen to include skills. Stars are about the project. */
|
|
26
26
|
const MEGA_REPOS = new Set([
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
"microsoft/vscode",
|
|
28
|
+
"Significant-Gravitas/AutoGPT",
|
|
29
|
+
"n8n-io/n8n",
|
|
30
|
+
"anomalyco/opencode",
|
|
31
|
+
"shadcn-ui/ui",
|
|
32
32
|
]);
|
|
33
33
|
|
|
34
34
|
/** Skill-dump repos: large collections where stars reflect quantity, not quality. */
|
|
@@ -37,12 +37,12 @@ const MEGA_REPOS = new Set([
|
|
|
37
37
|
// list still carry the old one; dropping either silently reclassifies the repo
|
|
38
38
|
// as "dedicated" and its stars start reading as a quality signal again.
|
|
39
39
|
const SKILL_DUMP_REPOS = new Set([
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
"affaan-m/everything-claude-code",
|
|
41
|
+
"openclaw/openclaw",
|
|
42
|
+
"jh941213/my-claude-code-asset",
|
|
43
|
+
"jh941213/my-cc-harness", // renamed from my-claude-code-asset
|
|
44
|
+
"inferen-sh/skills",
|
|
45
|
+
"inference-sh/skills", // renamed from inferen-sh
|
|
46
46
|
]);
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -51,27 +51,35 @@ const SKILL_DUMP_REPOS = new Set([
|
|
|
51
51
|
* - "mega-repo": Stars are about a larger project, not the skills (e.g. microsoft/vscode)
|
|
52
52
|
* - "skill-dump": Large skill collection — stars reflect popularity/quantity, not individual quality
|
|
53
53
|
*/
|
|
54
|
-
export function classifyStarReliability(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
export function classifyStarReliability(
|
|
55
|
+
repo: string,
|
|
56
|
+
stars?: number,
|
|
57
|
+
): StarReliability {
|
|
58
|
+
if (MEGA_REPOS.has(repo)) return "mega-repo";
|
|
59
|
+
if (SKILL_DUMP_REPOS.has(repo)) return "skill-dump";
|
|
60
|
+
// Heuristic: unknown repos with >50K stars are likely mega-repos
|
|
61
|
+
if (stars && stars > 50000) return "mega-repo";
|
|
62
|
+
return "dedicated";
|
|
60
63
|
}
|
|
61
64
|
|
|
62
|
-
export const STAR_RELIABILITY_INFO: Record<
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
65
|
+
export const STAR_RELIABILITY_INFO: Record<
|
|
66
|
+
StarReliability,
|
|
67
|
+
{ label: string; description: string }
|
|
68
|
+
> = {
|
|
69
|
+
dedicated: {
|
|
70
|
+
label: "Skill repo",
|
|
71
|
+
description: "Stars reflect this skill repository's quality",
|
|
72
|
+
},
|
|
73
|
+
"mega-repo": {
|
|
74
|
+
label: "Project repo",
|
|
75
|
+
description:
|
|
76
|
+
"Stars are for the parent project, not the skills. Skill quality may vary.",
|
|
77
|
+
},
|
|
78
|
+
"skill-dump": {
|
|
79
|
+
label: "Skill collection",
|
|
80
|
+
description:
|
|
81
|
+
"Large skill collection — stars reflect repo popularity, not individual skill quality.",
|
|
82
|
+
},
|
|
75
83
|
};
|
|
76
84
|
|
|
77
85
|
export const DEFAULT_SKILL_REPOS: SkillSource[] = [
|
package/src/main.tsx
CHANGED
|
@@ -9,6 +9,7 @@ import { route } from "./cli/router.js";
|
|
|
9
9
|
import { loadProjectDotenv } from "./services/dotenv.js";
|
|
10
10
|
import { App } from "./ui/App.js";
|
|
11
11
|
import { setThemeMode } from "./ui/theme-mode.js";
|
|
12
|
+
import { resolveTheme, snapshotThemeEnv } from "./ui/theme-resolve.js";
|
|
12
13
|
|
|
13
14
|
export const VERSION = (pkg as { version: string }).version;
|
|
14
15
|
|
|
@@ -16,6 +17,11 @@ export const VERSION = (pkg as { version: string }).version;
|
|
|
16
17
|
// No need for manual ANSI escape codes
|
|
17
18
|
|
|
18
19
|
async function main(): Promise<void> {
|
|
20
|
+
// FIRST, before anything can touch process.env: the theme is read from the
|
|
21
|
+
// environment claudeup was started with, never from a project's .env. The
|
|
22
|
+
// dotenv load below merges into process.env, so the only thing separating
|
|
23
|
+
// the two is that this line runs before it (pinned by theme-env.test.ts).
|
|
24
|
+
const themeEnv = snapshotThemeEnv();
|
|
19
25
|
const args = process.argv.slice(2);
|
|
20
26
|
|
|
21
27
|
// Load the project's .env ourselves. Bun's standalone autoload is compiled OFF
|
|
@@ -43,6 +49,11 @@ async function main(): Promise<void> {
|
|
|
43
49
|
process.exit(outcome.exitCode ?? 0);
|
|
44
50
|
}
|
|
45
51
|
|
|
52
|
+
// Both streams must be TTYs for the OSC probe: `claudeup < file` has a tty
|
|
53
|
+
// stdout but the reply arrives on stdin, so the probe would wait for nothing.
|
|
54
|
+
const isInteractive =
|
|
55
|
+
process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
56
|
+
|
|
46
57
|
// Create OpenTUI renderer (handles alternate screen buffer automatically).
|
|
47
58
|
//
|
|
48
59
|
// The background is the terminal's own, not a colour of ours: painting an
|
|
@@ -80,12 +91,24 @@ async function main(): Promise<void> {
|
|
|
80
91
|
if (text.length > 0) renderer.copyToClipboardOSC52(text);
|
|
81
92
|
});
|
|
82
93
|
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
|
|
94
|
+
// Resolve light vs dark once: --theme, CLAUDEUP_THEME, TERM_THEME, the OSC
|
|
95
|
+
// probe, COLORFGBG, dark — see src/ui/theme-resolve.ts. Only the disabled-row
|
|
96
|
+
// tint and the chips need this (src/ui/theme-mode.ts explains why that one
|
|
97
|
+
// case cannot be solved the way the rest of the palette is).
|
|
98
|
+
//
|
|
99
|
+
// The renderer sends OSC 10/11 at creation regardless: @opentui/core 0.1.107
|
|
100
|
+
// has no option to suppress it. So the rule "TERM_THEME skips the probe" is
|
|
101
|
+
// satisfied by NOT AWAITING — when steps 1-3 answer, `probe` is never called,
|
|
102
|
+
// `waitForThemeMode(250)` never runs, first paint is not delayed, and
|
|
103
|
+
// `renderer.themeMode` is never read anywhere in claudeup. Any late reply the
|
|
104
|
+
// terminal sends is consumed by OpenTUI's own handleSequence and ignored here.
|
|
105
|
+
const { mode } = await resolveTheme({
|
|
106
|
+
flag: outcome.theme,
|
|
107
|
+
env: themeEnv,
|
|
108
|
+
isInteractive,
|
|
109
|
+
probe: () => renderer.waitForThemeMode(250).catch(() => null),
|
|
110
|
+
});
|
|
111
|
+
setThemeMode(mode);
|
|
89
112
|
|
|
90
113
|
const root = createRoot(renderer);
|
|
91
114
|
|
package/src/opentui.d.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* ReactElement | null.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { ReactNode } from "react";
|
|
11
10
|
import type { RGBA } from "@opentui/core";
|
|
11
|
+
import type { ReactNode } from "react";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* What OpenTUI actually accepts for a colour: a CSS string OR an RGBA, which is
|
|
@@ -201,5 +201,3 @@ interface MouseEvent {
|
|
|
201
201
|
y: number;
|
|
202
202
|
button: number;
|
|
203
203
|
}
|
|
204
|
-
|
|
205
|
-
export {};
|
package/src/prerunner/index.ts
CHANGED
|
@@ -2,8 +2,8 @@ import os from "node:os";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import fs from "fs-extra";
|
|
4
4
|
import {
|
|
5
|
-
isClaudeAvailable,
|
|
6
5
|
type PluginScope,
|
|
6
|
+
isClaudeAvailable,
|
|
7
7
|
repairPlugin,
|
|
8
8
|
updatePlugin,
|
|
9
9
|
} from "../services/claude-cli.js";
|
|
@@ -18,13 +18,13 @@ import {
|
|
|
18
18
|
saveLocalInstalledPluginVersion,
|
|
19
19
|
writeGlobalSettings,
|
|
20
20
|
} from "../services/claude-settings.js";
|
|
21
|
+
import { clearContentDriftCache } from "../services/content-drift.js";
|
|
21
22
|
import {
|
|
22
23
|
checkGitignore,
|
|
23
24
|
formatPrerunWarning as formatGitignoreWarning,
|
|
24
25
|
} from "../services/gitignore-prerun.js";
|
|
25
26
|
import { refreshRegisteredMarketplaces } from "../services/marketplace-refresh.js";
|
|
26
27
|
import { autoAddMissingMarketplaces } from "../services/marketplace-sync.js";
|
|
27
|
-
import { clearContentDriftCache } from "../services/content-drift.js";
|
|
28
28
|
import {
|
|
29
29
|
clearMarketplaceCache,
|
|
30
30
|
compareVersions,
|
|
@@ -77,8 +77,8 @@ async function ensureTmuxContinuityHooks(): Promise<string | null> {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
// Append hooks, preserving any existing entries in SessionStart and Stop
|
|
80
|
-
const sessionStartGroups = existingHooks
|
|
81
|
-
const stopGroups = existingHooks
|
|
80
|
+
const sessionStartGroups = existingHooks.SessionStart ?? [];
|
|
81
|
+
const stopGroups = existingHooks.Stop ?? [];
|
|
82
82
|
|
|
83
83
|
sessionStartGroups.push({
|
|
84
84
|
hooks: [
|
|
@@ -168,7 +168,7 @@ export async function prerunClaude(
|
|
|
168
168
|
const addedHooks = await ensureTmuxContinuityHooks();
|
|
169
169
|
if (addedHooks) {
|
|
170
170
|
console.log(
|
|
171
|
-
|
|
171
|
+
"✓ Added tmux-claude-continuity hooks to ~/.claude/settings.json",
|
|
172
172
|
);
|
|
173
173
|
}
|
|
174
174
|
|
|
@@ -270,9 +270,8 @@ export async function prerunClaude(
|
|
|
270
270
|
if (await fs.pathExists(path.join(marketplacesDir, mpName))) {
|
|
271
271
|
continue;
|
|
272
272
|
}
|
|
273
|
-
const repo = defaultMarketplaces.find(
|
|
274
|
-
|
|
275
|
-
)?.source.repo;
|
|
273
|
+
const repo = defaultMarketplaces.find((m) => m.name === mpName)
|
|
274
|
+
?.source.repo;
|
|
276
275
|
if (!repo) continue;
|
|
277
276
|
try {
|
|
278
277
|
await addMarketplace(repo);
|
|
@@ -16,19 +16,16 @@
|
|
|
16
16
|
* block and are read on screen mount via `parseAliasFromRc`.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import {
|
|
20
|
-
readGlobalSettings,
|
|
21
|
-
writeGlobalSettings,
|
|
22
|
-
} from "./claude-settings.js";
|
|
23
19
|
import { DEFAULT_ALIAS_NAME, validateAliasName } from "./alias-store.js";
|
|
20
|
+
import { readGlobalSettings, writeGlobalSettings } from "./claude-settings.js";
|
|
24
21
|
|
|
25
22
|
interface ClaudeupSettings {
|
|
26
|
-
|
|
23
|
+
aliasName?: string;
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
interface SettingsWithClaudeup {
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
claudeup?: ClaudeupSettings;
|
|
28
|
+
[key: string]: unknown;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
/**
|
|
@@ -36,11 +33,11 @@ interface SettingsWithClaudeup {
|
|
|
36
33
|
* Returns the default `"c"` when the key is absent or invalid.
|
|
37
34
|
*/
|
|
38
35
|
export async function loadAliasName(): Promise<string> {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
const settings = (await readGlobalSettings()) as SettingsWithClaudeup;
|
|
37
|
+
const stored = settings.claudeup?.aliasName;
|
|
38
|
+
if (typeof stored !== "string") return DEFAULT_ALIAS_NAME;
|
|
39
|
+
if (validateAliasName(stored) !== null) return DEFAULT_ALIAS_NAME;
|
|
40
|
+
return stored;
|
|
44
41
|
}
|
|
45
42
|
|
|
46
43
|
/**
|
|
@@ -49,15 +46,15 @@ export async function loadAliasName(): Promise<string> {
|
|
|
49
46
|
* if the name fails validation — caller should validate first.
|
|
50
47
|
*/
|
|
51
48
|
export async function saveAliasName(name: string): Promise<void> {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
49
|
+
if (validateAliasName(name) !== null) return;
|
|
50
|
+
const settings = (await readGlobalSettings()) as SettingsWithClaudeup;
|
|
51
|
+
const next: SettingsWithClaudeup = {
|
|
52
|
+
...settings,
|
|
53
|
+
claudeup: {
|
|
54
|
+
...(settings.claudeup ?? {}),
|
|
55
|
+
aliasName: name,
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
// claude-settings.writeGlobalSettings accepts the same shape we received.
|
|
59
|
+
await writeGlobalSettings(next as Parameters<typeof writeGlobalSettings>[0]);
|
|
63
60
|
}
|