@clawpump/claw-agent 0.1.14 → 0.1.16
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/agent/apps/desktop/package.json +1 -1
- package/agent/apps/desktop/src/app/chat/sidebar/index.tsx +3 -2
- package/agent/apps/desktop/src/app/desktop-controller.tsx +9 -0
- package/agent/apps/desktop/src/app/mcp/index.tsx +123 -0
- package/agent/apps/desktop/src/app/routes.ts +5 -1
- package/agent/apps/desktop/src/app/types.ts +1 -0
- package/agent/apps/desktop/src/hermes.ts +19 -0
- package/agent/hermes_cli/distribution.py +9 -1
- package/agent/hermes_cli/main.py +2 -2
- package/agent/hermes_cli/web_server.py +35 -2
- package/agent/scripts/install.cmd +4 -4
- package/agent/scripts/install.ps1 +26 -3
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "hermes",
|
|
3
3
|
"productName": "Claw Agent",
|
|
4
4
|
"private": true,
|
|
5
|
-
"version": "0.15.
|
|
5
|
+
"version": "0.15.7",
|
|
6
6
|
"description": "Claw Agent by ClawPump — native desktop app for Solana agents, built on Hermes Agent by Nous Research.",
|
|
7
7
|
"author": "ClawPump (built on Hermes by Nous Research)",
|
|
8
8
|
"type": "module",
|
|
@@ -95,7 +95,7 @@ import {
|
|
|
95
95
|
sessionPinId
|
|
96
96
|
} from '@/store/session'
|
|
97
97
|
|
|
98
|
-
import { type AppView, ARTIFACTS_ROUTE, MESSAGING_ROUTE, SKILLS_ROUTE, WALLET_ROUTE, X402_ROUTE } from '../../routes'
|
|
98
|
+
import { type AppView, ARTIFACTS_ROUTE, MCP_ROUTE, MESSAGING_ROUTE, SKILLS_ROUTE, WALLET_ROUTE, X402_ROUTE } from '../../routes'
|
|
99
99
|
import { SidebarPanelLabel } from '../../shell/sidebar-label'
|
|
100
100
|
import type { SidebarNavItem } from '../../types'
|
|
101
101
|
|
|
@@ -133,7 +133,8 @@ const SIDEBAR_NAV: SidebarNavItem[] = [
|
|
|
133
133
|
{ id: 'messaging', label: '', icon: props => <Codicon name="comment" {...props} />, route: MESSAGING_ROUTE },
|
|
134
134
|
{ id: 'artifacts', label: '', icon: props => <Codicon name="files" {...props} />, route: ARTIFACTS_ROUTE },
|
|
135
135
|
{ id: 'wallet', label: 'Wallet', icon: props => <Codicon name="credit-card" {...props} />, route: WALLET_ROUTE },
|
|
136
|
-
{ id: 'x402', label: 'x402', icon: props => <Codicon name="zap" {...props} />, route: X402_ROUTE }
|
|
136
|
+
{ id: 'x402', label: 'x402', icon: props => <Codicon name="zap" {...props} />, route: X402_ROUTE },
|
|
137
|
+
{ id: 'mcp', label: 'MCP', icon: props => <Codicon name="plug" {...props} />, route: MCP_ROUTE }
|
|
137
138
|
]
|
|
138
139
|
|
|
139
140
|
const WORKSPACE_PAGE = 5
|
|
@@ -139,6 +139,7 @@ const SettingsView = lazy(async () => ({ default: (await import('./settings')).S
|
|
|
139
139
|
const SkillsView = lazy(async () => ({ default: (await import('./skills')).SkillsView }))
|
|
140
140
|
const WalletView = lazy(async () => ({ default: (await import('./wallet')).WalletView }))
|
|
141
141
|
const X402View = lazy(async () => ({ default: (await import('./x402')).X402View }))
|
|
142
|
+
const McpView = lazy(async () => ({ default: (await import('./mcp')).McpView }))
|
|
142
143
|
|
|
143
144
|
// Latest cron-job sessions surfaced in the collapsed "Cron jobs" section. The
|
|
144
145
|
// Cron sessions are written by a background scheduler tick (the desktop
|
|
@@ -1203,6 +1204,14 @@ export function DesktopController() {
|
|
|
1203
1204
|
}
|
|
1204
1205
|
path="x402"
|
|
1205
1206
|
/>
|
|
1207
|
+
<Route
|
|
1208
|
+
element={
|
|
1209
|
+
<Suspense fallback={null}>
|
|
1210
|
+
<McpView setStatusbarItemGroup={setStatusbarItemGroup} />
|
|
1211
|
+
</Suspense>
|
|
1212
|
+
}
|
|
1213
|
+
path="mcp"
|
|
1214
|
+
/>
|
|
1206
1215
|
<Route element={null} path="cron" />
|
|
1207
1216
|
<Route element={null} path="profiles" />
|
|
1208
1217
|
<Route element={null} path="settings" />
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query'
|
|
2
|
+
|
|
3
|
+
import { Badge } from '@/components/ui/badge'
|
|
4
|
+
import { Button } from '@/components/ui/button'
|
|
5
|
+
import { getMcpServers, type McpServer } from '@/hermes'
|
|
6
|
+
import { Check, ExternalLink, Loader2, Zap } from '@/lib/icons'
|
|
7
|
+
|
|
8
|
+
import type { SetStatusbarItemGroup } from '../shell/statusbar-controls'
|
|
9
|
+
|
|
10
|
+
// Where an unauthenticated user goes to connect the ClawPump MCP — the gateway
|
|
11
|
+
// (browser login / cpk_* key). Shown prominently when not connected.
|
|
12
|
+
const CLAWPUMP_GATEWAY_URL = 'https://agents.clawpump.tech/dashboard/api'
|
|
13
|
+
const CLAWPUMP_NAMES = new Set(['clawpump', 'clawpump-agents', 'clawpump-stdio'])
|
|
14
|
+
|
|
15
|
+
const isClawpump = (s: McpServer) => CLAWPUMP_NAMES.has(s.name)
|
|
16
|
+
|
|
17
|
+
interface McpViewProps extends React.ComponentProps<'section'> {
|
|
18
|
+
setStatusbarItemGroup?: SetStatusbarItemGroup
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function McpView({ setStatusbarItemGroup: _setStatusbarItemGroup, ...props }: McpViewProps) {
|
|
22
|
+
const query = useQuery({ queryKey: ['mcp-servers'], queryFn: getMcpServers, staleTime: 15_000 })
|
|
23
|
+
const servers = query.data?.servers ?? []
|
|
24
|
+
const clawpump = servers.find(isClawpump)
|
|
25
|
+
const others = servers.filter(s => !isClawpump(s))
|
|
26
|
+
|
|
27
|
+
// authenticated === true → OAuth tokens are on disk (the same session chat
|
|
28
|
+
// uses), so the MCP is genuinely connected. === false → needs sign-in.
|
|
29
|
+
const clawpumpConnected = clawpump?.authenticated === true
|
|
30
|
+
const clawpumpNeedsAuth = clawpump != null && clawpump.authenticated === false
|
|
31
|
+
|
|
32
|
+
const openGateway = () => void window.hermesDesktop?.openExternal?.(CLAWPUMP_GATEWAY_URL)
|
|
33
|
+
|
|
34
|
+
return (
|
|
35
|
+
<section {...props} className="flex h-full min-h-0 flex-col">
|
|
36
|
+
<div className="min-h-0 flex-1 overflow-y-auto">
|
|
37
|
+
<div className="mx-auto max-w-3xl space-y-4 px-5 py-4">
|
|
38
|
+
<header className="flex items-center gap-2">
|
|
39
|
+
<Zap className="size-5 text-primary" />
|
|
40
|
+
<h1 className="text-lg font-semibold">MCP Servers</h1>
|
|
41
|
+
</header>
|
|
42
|
+
<p className="text-sm text-muted-foreground">
|
|
43
|
+
Model Context Protocol servers wired into your agent. The ClawPump MCP brings 133 tools —
|
|
44
|
+
wallet, trading, marketplace, perps, token launch.
|
|
45
|
+
</p>
|
|
46
|
+
|
|
47
|
+
{query.isPending && (
|
|
48
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
49
|
+
<Loader2 className="size-4 animate-spin" /> Loading…
|
|
50
|
+
</div>
|
|
51
|
+
)}
|
|
52
|
+
|
|
53
|
+
{clawpump && (
|
|
54
|
+
<div className="rounded-lg border p-4">
|
|
55
|
+
<div className="flex items-center justify-between gap-2">
|
|
56
|
+
<div className="flex items-center gap-2">
|
|
57
|
+
<span className="font-medium">ClawPump MCP</span>
|
|
58
|
+
<span className="text-xs text-muted-foreground">{clawpump.name}</span>
|
|
59
|
+
</div>
|
|
60
|
+
{clawpumpConnected ? (
|
|
61
|
+
<Badge className="gap-1">
|
|
62
|
+
<Check className="size-3" /> Connected
|
|
63
|
+
</Badge>
|
|
64
|
+
) : (
|
|
65
|
+
<Badge variant="outline">Not connected</Badge>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
{clawpumpNeedsAuth && (
|
|
69
|
+
<div className="mt-3 space-y-2">
|
|
70
|
+
<p className="text-sm text-muted-foreground">
|
|
71
|
+
Sign in at the ClawPump gateway to connect — then your 133 ClawPump tools come
|
|
72
|
+
online in chat and across the app.
|
|
73
|
+
</p>
|
|
74
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
75
|
+
<Button onClick={openGateway} size="sm">
|
|
76
|
+
<ExternalLink className="size-4" /> Connect at the gateway
|
|
77
|
+
</Button>
|
|
78
|
+
<code className="rounded bg-muted px-2 py-1 text-xs">claw clawpump login</code>
|
|
79
|
+
</div>
|
|
80
|
+
<p className="break-all text-xs text-muted-foreground">{CLAWPUMP_GATEWAY_URL}</p>
|
|
81
|
+
</div>
|
|
82
|
+
)}
|
|
83
|
+
</div>
|
|
84
|
+
)}
|
|
85
|
+
|
|
86
|
+
{!query.isPending && !clawpump && (
|
|
87
|
+
<div className="space-y-2 rounded-lg border p-4">
|
|
88
|
+
<p className="text-sm text-muted-foreground">
|
|
89
|
+
The ClawPump MCP isn't installed yet. Connect it at the gateway to unlock the 133
|
|
90
|
+
tools.
|
|
91
|
+
</p>
|
|
92
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
93
|
+
<Button onClick={openGateway} size="sm">
|
|
94
|
+
<ExternalLink className="size-4" /> Open the ClawPump gateway
|
|
95
|
+
</Button>
|
|
96
|
+
<code className="rounded bg-muted px-2 py-1 text-xs">claw clawpump setup</code>
|
|
97
|
+
</div>
|
|
98
|
+
<p className="break-all text-xs text-muted-foreground">{CLAWPUMP_GATEWAY_URL}</p>
|
|
99
|
+
</div>
|
|
100
|
+
)}
|
|
101
|
+
|
|
102
|
+
{others.length > 0 && (
|
|
103
|
+
<div className="space-y-2">
|
|
104
|
+
<h2 className="text-sm font-medium text-muted-foreground">Other servers</h2>
|
|
105
|
+
{others.map(s => (
|
|
106
|
+
<div
|
|
107
|
+
className="flex items-center justify-between rounded-md border px-3 py-2"
|
|
108
|
+
key={s.name}
|
|
109
|
+
>
|
|
110
|
+
<div className="flex items-center gap-2">
|
|
111
|
+
<span className="text-sm font-medium">{s.name}</span>
|
|
112
|
+
<span className="text-xs text-muted-foreground">{s.transport}</span>
|
|
113
|
+
</div>
|
|
114
|
+
{s.enabled ? <Badge>Enabled</Badge> : <Badge variant="outline">Disabled</Badge>}
|
|
115
|
+
</div>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
)}
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
</section>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
@@ -10,6 +10,7 @@ export const PROFILES_ROUTE = '/profiles'
|
|
|
10
10
|
export const AGENTS_ROUTE = '/agents'
|
|
11
11
|
export const WALLET_ROUTE = '/wallet'
|
|
12
12
|
export const X402_ROUTE = '/x402'
|
|
13
|
+
export const MCP_ROUTE = '/mcp'
|
|
13
14
|
|
|
14
15
|
export type AppView =
|
|
15
16
|
| 'agents'
|
|
@@ -17,6 +18,7 @@ export type AppView =
|
|
|
17
18
|
| 'chat'
|
|
18
19
|
| 'command-center'
|
|
19
20
|
| 'cron'
|
|
21
|
+
| 'mcp'
|
|
20
22
|
| 'messaging'
|
|
21
23
|
| 'profiles'
|
|
22
24
|
| 'settings'
|
|
@@ -29,6 +31,7 @@ export type AppRouteId =
|
|
|
29
31
|
| 'artifacts'
|
|
30
32
|
| 'command-center'
|
|
31
33
|
| 'cron'
|
|
34
|
+
| 'mcp'
|
|
32
35
|
| 'messaging'
|
|
33
36
|
| 'new'
|
|
34
37
|
| 'profiles'
|
|
@@ -54,7 +57,8 @@ export const APP_ROUTES = [
|
|
|
54
57
|
{ id: 'profiles', path: PROFILES_ROUTE, view: 'profiles' },
|
|
55
58
|
{ id: 'agents', path: AGENTS_ROUTE, view: 'agents' },
|
|
56
59
|
{ id: 'wallet', path: WALLET_ROUTE, view: 'wallet' },
|
|
57
|
-
{ id: 'x402', path: X402_ROUTE, view: 'x402' }
|
|
60
|
+
{ id: 'x402', path: X402_ROUTE, view: 'x402' },
|
|
61
|
+
{ id: 'mcp', path: MCP_ROUTE, view: 'mcp' }
|
|
58
62
|
] as const satisfies readonly AppRoute[]
|
|
59
63
|
|
|
60
64
|
const APP_VIEW_BY_PATH = new Map<string, AppView>(APP_ROUTES.map(route => [route.path, route.view]))
|
|
@@ -771,6 +771,25 @@ export function getPodStatus(): Promise<{ connected: boolean; balance_usdc?: num
|
|
|
771
771
|
})
|
|
772
772
|
}
|
|
773
773
|
|
|
774
|
+
export interface McpServer {
|
|
775
|
+
name: string
|
|
776
|
+
transport: string
|
|
777
|
+
url?: string | null
|
|
778
|
+
command?: string | null
|
|
779
|
+
enabled: boolean
|
|
780
|
+
/** OAuth servers: true/false once tokens are checked; null when not applicable. */
|
|
781
|
+
authenticated?: boolean | null
|
|
782
|
+
tools?: string[] | null
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
/** Configured MCP servers + their connection state (for the sidebar MCP page). */
|
|
786
|
+
export function getMcpServers(): Promise<{ servers: McpServer[] }> {
|
|
787
|
+
return window.hermesDesktop.api<{ servers: McpServer[] }>({
|
|
788
|
+
...profileScoped(),
|
|
789
|
+
path: '/api/mcp/servers'
|
|
790
|
+
})
|
|
791
|
+
}
|
|
792
|
+
|
|
774
793
|
/** ClawPump agent wallets (id + name + USDC balance) for the Pod funding picker. */
|
|
775
794
|
export function getPodWallets(): Promise<{ ok: boolean; wallets: PodWallet[]; error?: string }> {
|
|
776
795
|
return window.hermesDesktop.api<{ ok: boolean; wallets: PodWallet[]; error?: string }>({
|
|
@@ -488,7 +488,15 @@ def _clawpump_mcp_config():
|
|
|
488
488
|
from hermes_cli.mcp_config import _get_mcp_servers, _resolve_mcp_server_config
|
|
489
489
|
|
|
490
490
|
servers = _get_mcp_servers()
|
|
491
|
-
|
|
491
|
+
# Match the dashboard's _clawpump_mcp(): known names first, then any
|
|
492
|
+
# clawpump* entry (e.g. clawpump-agents), so every ClawPump MCP variant
|
|
493
|
+
# the agent can load is also resolvable here.
|
|
494
|
+
name = next(
|
|
495
|
+
(n for n in ("clawpump", "clawpump-stdio", "clawpump-agents") if n in servers),
|
|
496
|
+
None,
|
|
497
|
+
)
|
|
498
|
+
if not name:
|
|
499
|
+
name = next((n for n in servers if n.startswith("clawpump")), None)
|
|
492
500
|
if not name:
|
|
493
501
|
return (None, None)
|
|
494
502
|
return (name, _resolve_mcp_server_config(servers[name]))
|
package/agent/hermes_cli/main.py
CHANGED
|
@@ -5953,7 +5953,7 @@ def _update_via_zip(args):
|
|
|
5953
5953
|
)
|
|
5954
5954
|
sys.exit(1)
|
|
5955
5955
|
zip_url = (
|
|
5956
|
-
f"https://github.com/
|
|
5956
|
+
f"https://github.com/Clawpump/claw-agent/archive/refs/heads/{branch}.zip"
|
|
5957
5957
|
)
|
|
5958
5958
|
|
|
5959
5959
|
print("→ Downloading latest version...")
|
|
@@ -8624,7 +8624,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|
|
8624
8624
|
return
|
|
8625
8625
|
print("✗ Not a git repository. Please reinstall:")
|
|
8626
8626
|
print(
|
|
8627
|
-
"
|
|
8627
|
+
" npx @clawpump/claw-agent"
|
|
8628
8628
|
)
|
|
8629
8629
|
sys.exit(1)
|
|
8630
8630
|
|
|
@@ -7983,6 +7983,24 @@ def _redact_mcp_env(env: Dict[str, Any]) -> Dict[str, str]:
|
|
|
7983
7983
|
return out
|
|
7984
7984
|
|
|
7985
7985
|
|
|
7986
|
+
def _mcp_server_authenticated(name: str, cfg: Dict[str, Any]) -> Optional[bool]:
|
|
7987
|
+
"""True/False if this server uses OAuth and we can tell whether tokens are
|
|
7988
|
+
on disk; None when auth state isn't applicable/known (stdio key servers).
|
|
7989
|
+
|
|
7990
|
+
Lets the GUI render a real "Connected" vs "Connect" state for the ClawPump
|
|
7991
|
+
MCP instead of guessing — the OAuth token is shared on disk, so the sidebar
|
|
7992
|
+
reflects the same authenticated session the chat agent uses.
|
|
7993
|
+
"""
|
|
7994
|
+
is_oauth = cfg.get("auth") == "oauth" or (cfg.get("url") and not cfg.get("command"))
|
|
7995
|
+
if not is_oauth:
|
|
7996
|
+
return None
|
|
7997
|
+
try:
|
|
7998
|
+
from hermes_cli.mcp_config import _oauth_tokens_present
|
|
7999
|
+
return bool(_oauth_tokens_present(name))
|
|
8000
|
+
except Exception:
|
|
8001
|
+
return None
|
|
8002
|
+
|
|
8003
|
+
|
|
7986
8004
|
def _mcp_server_summary(name: str, cfg: Dict[str, Any]) -> Dict[str, Any]:
|
|
7987
8005
|
transport = "http" if cfg.get("url") else ("stdio" if cfg.get("command") else "unknown")
|
|
7988
8006
|
return {
|
|
@@ -7994,6 +8012,7 @@ def _mcp_server_summary(name: str, cfg: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
7994
8012
|
"env": _redact_mcp_env(cfg.get("env") or {}),
|
|
7995
8013
|
"auth": cfg.get("auth"),
|
|
7996
8014
|
"enabled": cfg.get("enabled", True) is not False,
|
|
8015
|
+
"authenticated": _mcp_server_authenticated(name, cfg),
|
|
7997
8016
|
# Tool selection: list of enabled tool names, or None = all.
|
|
7998
8017
|
"tools": cfg.get("tools"),
|
|
7999
8018
|
}
|
|
@@ -12048,11 +12067,25 @@ async def set_dashboard_theme(body: ThemeSetBody):
|
|
|
12048
12067
|
# in the vetted catalog (the font's webfont URL is injected as a <link>,
|
|
12049
12068
|
# so we never accept an arbitrary user-supplied id/URL here).
|
|
12050
12069
|
def _clawpump_mcp():
|
|
12051
|
-
"""Return (server_name, config) for the configured ClawPump MCP, else (None, None).
|
|
12070
|
+
"""Return (server_name, config) for the configured ClawPump MCP, else (None, None).
|
|
12071
|
+
|
|
12072
|
+
The chat agent loads EVERY configured MCP server, so the ClawPump tools work
|
|
12073
|
+
in chat under whatever entry name the user installed — ``clawpump`` (remote
|
|
12074
|
+
OAuth), ``clawpump-stdio``, or ``clawpump-agents`` (``npx @clawpump/agents``).
|
|
12075
|
+
The dashboard must recognise the SAME entry, otherwise chat works while every
|
|
12076
|
+
sidebar MCP page (wallet / x402 / pod / mail) reports "not configured". Try
|
|
12077
|
+
the known names in preference order, then fall back to any ``clawpump*``
|
|
12078
|
+
server so a future/renamed entry still resolves.
|
|
12079
|
+
"""
|
|
12052
12080
|
from hermes_cli.mcp_config import _get_mcp_servers
|
|
12053
12081
|
|
|
12054
12082
|
servers = _get_mcp_servers()
|
|
12055
|
-
name = next(
|
|
12083
|
+
name = next(
|
|
12084
|
+
(n for n in ("clawpump", "clawpump-stdio", "clawpump-agents") if n in servers),
|
|
12085
|
+
None,
|
|
12086
|
+
)
|
|
12087
|
+
if name is None:
|
|
12088
|
+
name = next((n for n in servers if n.startswith("clawpump")), None)
|
|
12056
12089
|
return (name, servers[name]) if name else (None, None)
|
|
12057
12090
|
|
|
12058
12091
|
|
|
@@ -5,10 +5,10 @@ REM ============================================================================
|
|
|
5
5
|
REM This batch file launches the PowerShell installer for users running CMD.
|
|
6
6
|
REM
|
|
7
7
|
REM Usage:
|
|
8
|
-
REM curl -fsSL https://raw.githubusercontent.com/
|
|
8
|
+
REM curl -fsSL https://raw.githubusercontent.com/Clawpump/claw-agent/main/scripts/install.cmd -o install.cmd && install.cmd && del install.cmd
|
|
9
9
|
REM
|
|
10
10
|
REM Or if you're already in PowerShell, use the direct command instead:
|
|
11
|
-
REM iex (irm https://
|
|
11
|
+
REM iex (irm https://raw.githubusercontent.com/Clawpump/claw-agent/main/scripts/install.ps1)
|
|
12
12
|
REM ============================================================================
|
|
13
13
|
|
|
14
14
|
echo.
|
|
@@ -16,12 +16,12 @@ echo Hermes Agent Installer
|
|
|
16
16
|
echo Launching PowerShell installer...
|
|
17
17
|
echo.
|
|
18
18
|
|
|
19
|
-
powershell -ExecutionPolicy ByPass -NoProfile -Command "iex (irm https://
|
|
19
|
+
powershell -ExecutionPolicy ByPass -NoProfile -Command "iex (irm https://raw.githubusercontent.com/Clawpump/claw-agent/main/scripts/install.ps1)"
|
|
20
20
|
|
|
21
21
|
if %ERRORLEVEL% NEQ 0 (
|
|
22
22
|
echo.
|
|
23
23
|
echo Installation failed. Please try running PowerShell directly:
|
|
24
|
-
echo powershell -ExecutionPolicy ByPass -c "iex (irm https://
|
|
24
|
+
echo powershell -ExecutionPolicy ByPass -c "iex (irm https://raw.githubusercontent.com/Clawpump/claw-agent/main/scripts/install.ps1)"
|
|
25
25
|
echo.
|
|
26
26
|
pause
|
|
27
27
|
exit /b 1
|
|
@@ -1208,6 +1208,19 @@ function Install-Repository {
|
|
|
1208
1208
|
# users hit on update. Pin autocrlf=false so the dirt is never
|
|
1209
1209
|
# created in the first place.
|
|
1210
1210
|
git -c windows.appendAtomically=false config core.autocrlf false 2>$null
|
|
1211
|
+
# Re-point a pre-existing checkout at the ClawPump fork. Anyone
|
|
1212
|
+
# who installed upstream Hermes has origin=NousResearch here;
|
|
1213
|
+
# without this the update pulls upstream (none of the ClawPump
|
|
1214
|
+
# features) into the install. Force origin to the fork; the
|
|
1215
|
+
# diverged history means the update below hard-resets onto it.
|
|
1216
|
+
$repoRepointed = $false
|
|
1217
|
+
$currentOrigin = (git -c windows.appendAtomically=false remote get-url origin 2>$null) -join ""
|
|
1218
|
+
if ($currentOrigin -notmatch "(?i)clawpump/claw-agent") {
|
|
1219
|
+
Write-Warn "Re-pointing origin to the ClawPump fork (was: $currentOrigin)."
|
|
1220
|
+
git -c windows.appendAtomically=false remote set-url origin $RepoUrlHttps 2>$null
|
|
1221
|
+
if ($LASTEXITCODE -ne 0) { git -c windows.appendAtomically=false remote add origin $RepoUrlHttps 2>$null }
|
|
1222
|
+
$repoRepointed = $true
|
|
1223
|
+
}
|
|
1211
1224
|
# Preserve any real local changes before the checkout instead of
|
|
1212
1225
|
# discarding them with `reset --hard HEAD`. The old hard reset
|
|
1213
1226
|
# silently destroyed agent-edited source on managed clones (the
|
|
@@ -1254,8 +1267,16 @@ function Install-Repository {
|
|
|
1254
1267
|
} else {
|
|
1255
1268
|
git -c windows.appendAtomically=false checkout $Branch
|
|
1256
1269
|
if ($LASTEXITCODE -ne 0) { throw "git checkout $Branch failed (exit $LASTEXITCODE)" }
|
|
1257
|
-
|
|
1258
|
-
|
|
1270
|
+
if ($repoRepointed) {
|
|
1271
|
+
# Upstream -> fork is a diverged history; fast-forward is
|
|
1272
|
+
# impossible. Hard-reset the branch onto the fork.
|
|
1273
|
+
Write-Info "Resetting $Branch to the ClawPump fork (origin/$Branch)..."
|
|
1274
|
+
git -c windows.appendAtomically=false reset --hard "origin/$Branch"
|
|
1275
|
+
if ($LASTEXITCODE -ne 0) { throw "git reset --hard origin/$Branch failed (exit $LASTEXITCODE)" }
|
|
1276
|
+
} else {
|
|
1277
|
+
git -c windows.appendAtomically=false pull --ff-only origin $Branch
|
|
1278
|
+
if ($LASTEXITCODE -ne 0) { throw "git pull failed (exit $LASTEXITCODE)" }
|
|
1279
|
+
}
|
|
1259
1280
|
}
|
|
1260
1281
|
|
|
1261
1282
|
if ($autostashRef) {
|
|
@@ -1266,7 +1287,9 @@ function Install-Repository {
|
|
|
1266
1287
|
# bootstrap run the installer without a usable console -- in
|
|
1267
1288
|
# those cases Read-Host would hang or return empty, so we
|
|
1268
1289
|
# skip the prompt and just restore (the safe default).
|
|
1269
|
-
|
|
1290
|
+
# Don't replay upstream-Hermes local edits onto the fork —
|
|
1291
|
+
# they target different code and would only conflict.
|
|
1292
|
+
$restoreNow = -not $repoRepointed
|
|
1270
1293
|
$hasConsole = $false
|
|
1271
1294
|
try {
|
|
1272
1295
|
$hasConsole = (
|