@shundoo-ai/dsh-cosmic 1.0.2 → 1.0.3-alpha.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/package.json
CHANGED
|
@@ -42,6 +42,32 @@ description: >
|
|
|
42
42
|
|
|
43
43
|
---
|
|
44
44
|
|
|
45
|
+
## Windows:一条命令走完全程(推荐)
|
|
46
|
+
|
|
47
|
+
> 下面各职责给的是 **macOS/Linux** 命令。Windows 上**手拼这套流程代价极高** —— 实测一个 Windows 会话为跑通「构建 + 热部署」发了 **63 条 pwsh**、**6 次提权**(探测 PID → 找 JDK → 找 tools.jar → attach,每步都要单独授权)。
|
|
48
|
+
|
|
49
|
+
本 skill 随包提供封装脚本,**把全程收敛成一次调用 ⇒ 只需一次提权**:
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
# 体检(不部署)
|
|
53
|
+
pwsh -File {SKILL_DIR}\scripts\cosmic-hotdeploy.ps1
|
|
54
|
+
# 构建 + 热部署
|
|
55
|
+
pwsh -File {SKILL_DIR}\scripts\cosmic-hotdeploy.ps1 -Module <模块名>
|
|
56
|
+
# 干净重建 + 热部署
|
|
57
|
+
pwsh -File {SKILL_DIR}\scripts\cosmic-hotdeploy.ps1 -Module <模块名> -Clean
|
|
58
|
+
# 只热部署已有 jar
|
|
59
|
+
pwsh -File {SKILL_DIR}\scripts\cosmic-hotdeploy.ps1 -Jar <jar路径>
|
|
60
|
+
# 只构建、不部署
|
|
61
|
+
pwsh -File {SKILL_DIR}\scripts\cosmic-hotdeploy.ps1 -Module <模块名> -WhatIf
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
内部依次完成:定位工作区 → 解析 preset bundle → 读 `dev.json` → **按端口反查 cosmic PID**(不是 `jps`,见职责②)→ 挑含 `tools.jar` 的 JDK → 构建 → Attacher 热加载。
|
|
65
|
+
|
|
66
|
+
参数:`-Module`|`-Jar`|`-Clean`|`-WhatIf`|`-LogFile`|`-Workspace`|`-PresetDir`|`-Port`。
|
|
67
|
+
工作区默认从「脚本位置的上两级」或当前目录推断;布局不同就传 `-Workspace <项目根>`。
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
45
71
|
## 职责①:开启热部署(每个环境一次性)
|
|
46
72
|
|
|
47
73
|
1. **IDEA 启动 MCP(可选)**:JetBrains MCP,固定 URL `http://127.0.0.1:64342/stream`,用于**代码智能**(符号查找、调用分析、重构、即时查错)。⚠️ **非构建必需**——产 jar 走 gradle 命令行(见职责③),MCP 未配/未连不影响「build + 热部署」主线。
|
|
@@ -89,6 +115,16 @@ description: >
|
|
|
89
115
|
|
|
90
116
|
- 通用:`jps -l | grep kd.bos.service.webserver.JettyServer`(取 `appName=cosmic` 的那个)
|
|
91
117
|
- macOS 备选:`lsof -tiTCP:<port> -sTCP:LISTEN`
|
|
118
|
+
- **Windows 推荐(实测最可靠)**:按端口反查 + 命令行校验
|
|
119
|
+
|
|
120
|
+
```powershell
|
|
121
|
+
$conn = Get-NetTCPConnection -LocalPort <port> -State Listen | Select-Object -First 1
|
|
122
|
+
(Get-CimInstance Win32_Process -Filter "ProcessId=$($conn.OwningProcess)").CommandLine # 应含 kd.bos.service.webserver.JettyServer
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
> ⚠️ **Windows 上 `jps` 看不到 cosmic**(实测):cosmic 常由 **SYSTEM** 账户启动,而 `jps` 只列举**当前用户**的 JVM → 输出里完全没有它,**极易误判「cosmic 没启动」**。用上面的方式零替代。
|
|
126
|
+
> 另:发现 PID 后先扫命令行里有没有 `-XX:+DisableAttachMechanism` —— 带此参数的 JVM **无法 attach**(硬阻断)。
|
|
127
|
+
> 跨用户 attach 本身**可用、无需提权**(Windows JVM attach 命名管道对 Administrators 组放行)。
|
|
92
128
|
|
|
93
129
|
### 3. 热部署
|
|
94
130
|
|
|
@@ -131,6 +167,13 @@ GRADLE_USER_HOME=<cwd>/.gradle/user-home "$GRADLE" :<模块>:build -x test
|
|
|
131
167
|
- 产物在 `<模块>/build/libs/*.jar`(本环境 `code/yun/sd-khxty-yun/build/libs/sd-khxty-yun-1.0.0.jar`)。
|
|
132
168
|
- ⚠️ 产 jar **只认 gradle 命令行**:IDEA MCP `build_project` 默认增量、源码未变会跳过(`isSuccess:true` 但 jar 不更新);勿用 `buildJar`/`deployJar`(那是冷启动拷贝到 lib/cus,热部署不需要)。
|
|
133
169
|
|
|
170
|
+
> **Windows 必读(实测踩坑,失败一次排查很久)**
|
|
171
|
+
> - **必须显式设 `JAVA_HOME` 指向 JDK(不是 JRE)**:Windows 注册表 `HKLM\SOFTWARE\JavaSoft\Java Development Kit` 的 `JavaHome` 会被 JRE 安装包改写成 `...\jre1.8.0_481`,Gradle 采信它 → `java.home` 指向 JRE → 报 `Could not find tools.jar`。显式 `$env:JAVA_HOME="C:\Program Files\Java\jdk1.8.0_XXX"`
|
|
172
|
+
> - **Gradle 版本必须按 `gradle/wrapper/gradle-wrapper.properties` 锁定**,不要「取 `~/.gradle/wrapper/dists` 下最新」—— 机器上可能同时装了要求 Java 22 的新版 Gradle,会直接把构建带偏。
|
|
173
|
+
> - ⚠️ **「伪成功构建」陷阱**:`compileJava` 处于 `UP-TO-DATE` 时 Gradle **根本不加载编译器**,缺 tools.jar 也不报错 → 看到 `BUILD SUCCESSFUL` + jar 正常产出,**但里面是旧字节码**。首次接入务必 `clean build` 验证一次真编译。
|
|
174
|
+
>
|
|
175
|
+
> 完整分析见 `cosmic-dev-best-practices/references/cosmic-hotdeploy-build-slow-windows.md` §4.3 / §4.7。Windows 上直接用上面「Windows:一条命令走完全程」的封装脚本即可,它已内置这些约束。
|
|
176
|
+
|
|
134
177
|
### 2. 定位错误 / 理解代码(IDEA MCP 代码智能,可选加分项)
|
|
135
178
|
|
|
136
179
|
> 此节可选:MCP 未配/未连不影响「build + 热部署」主线(gradle stderr 本身也会报编译错误,含文件名+行号)。
|
|
@@ -181,4 +224,5 @@ agent(`kd.reloadjar.ReloadAgent`)在 cosmic 进程内自动执行这两步
|
|
|
181
224
|
|------|------|------|
|
|
182
225
|
| `assets/dev.json` | ① 开启热部署 | 空配置模板(`dev.py` 读它作字段基础,生成工作区 `.dsh/cosmic/config/dev.json`) |
|
|
183
226
|
| `scripts/dev.py` | ① 开启热部署 | 环境配置脚本(`init`=读 `.kd/config.json` 覆盖 dev.json;`read`=只读;`__file__` 反推 skill 根) |
|
|
227
|
+
| `scripts/cosmic-hotdeploy.ps1` | ②③ 热加载 / 构建+热部署 | **Windows 一键封装**(可移植:工作区自动推断、无硬编码路径):体检 / `-Module` 构建+热部署 / `-Clean` / `-Jar` 直传 / `-WhatIf`。见「Windows:一条命令走完全程」 |
|
|
184
228
|
| `assets/kd-reloadjar-agent.jar` | ② 热加载 | 热重载 agent(含 `kd.reloadjar.ReloadAgent` + `Attacher`) |
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# cosmic-hotdeploy.ps1 -- Kingdee Cosmic build + hot-deploy (Windows, portable)
|
|
2
|
+
#
|
|
3
|
+
# PURPOSE
|
|
4
|
+
# Windows port of the cosmic-vibe-coding skill workflow (the skill docs give
|
|
5
|
+
# macOS/Linux commands). Discovers the running cosmic JVM, builds the module
|
|
6
|
+
# with the wrapper-pinned Gradle + a real JDK8, then hot-loads the jar via the
|
|
7
|
+
# Attacher agent -- no cosmic restart, no touching mc.
|
|
8
|
+
#
|
|
9
|
+
# USAGE
|
|
10
|
+
# pwsh -File cosmic-hotdeploy.ps1 # health check only
|
|
11
|
+
# pwsh -File cosmic-hotdeploy.ps1 -Module <name> # build + hot-deploy
|
|
12
|
+
# pwsh -File cosmic-hotdeploy.ps1 -Module <name> -Clean # clean build + hot-deploy
|
|
13
|
+
# pwsh -File cosmic-hotdeploy.ps1 -Jar a.jar,b.jar # hot-deploy existing jars
|
|
14
|
+
# pwsh -File cosmic-hotdeploy.ps1 -Module <name> -WhatIf # dry run (build only)
|
|
15
|
+
#
|
|
16
|
+
# PORTABILITY
|
|
17
|
+
# The workspace is inferred from this script's location (expects to live in
|
|
18
|
+
# <workspace>/runtime/); override with -Workspace. The skill bundle is located
|
|
19
|
+
# via $DSH_PROFILE_DIR or $DSH_HOME; override with -PresetDir. No other
|
|
20
|
+
# machine-specific paths are hard-coded -- the JDK is discovered from the
|
|
21
|
+
# running cosmic process, then from JAVA_HOME, then from common install roots.
|
|
22
|
+
#
|
|
23
|
+
# NOTE
|
|
24
|
+
# Windows classpath separator is ';' (not ':'). The Attacher must run on a JDK
|
|
25
|
+
# whose major version matches the target JVM (JDK8 + lib\tools.jar for cosmic).
|
|
26
|
+
|
|
27
|
+
[CmdletBinding()]
|
|
28
|
+
param(
|
|
29
|
+
[string[]]$Jar,
|
|
30
|
+
[string]$Module,
|
|
31
|
+
[switch]$Clean,
|
|
32
|
+
[switch]$WhatIf,
|
|
33
|
+
[string]$LogFile,
|
|
34
|
+
[string]$Workspace,
|
|
35
|
+
[string]$PresetDir,
|
|
36
|
+
[int]$Port
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
$ErrorActionPreference = 'Stop'
|
|
40
|
+
|
|
41
|
+
# ---- 0. Resolve workspace (no hard-coded user paths) ----
|
|
42
|
+
if (-not $Workspace) {
|
|
43
|
+
# Expect this script at <workspace>\runtime\cosmic-hotdeploy.ps1
|
|
44
|
+
if ($PSScriptRoot) {
|
|
45
|
+
$Workspace = Split-Path $PSScriptRoot -Parent
|
|
46
|
+
} else {
|
|
47
|
+
$Workspace = (Get-Location).Path
|
|
48
|
+
}
|
|
49
|
+
# If it was moved elsewhere, fall back to the cwd when that looks like a workspace.
|
|
50
|
+
if (-not (Test-Path (Join-Path $Workspace 'settings.gradle'))) {
|
|
51
|
+
if (Test-Path (Join-Path (Get-Location).Path 'settings.gradle')) {
|
|
52
|
+
$Workspace = (Get-Location).Path
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (-not (Test-Path (Join-Path $Workspace 'settings.gradle'))) {
|
|
57
|
+
throw "Workspace '$Workspace' has no settings.gradle. Pass -Workspace <project root>."
|
|
58
|
+
}
|
|
59
|
+
$cwd = (Resolve-Path $Workspace).Path
|
|
60
|
+
|
|
61
|
+
# ---- 0.1 Resolve the cosmic skill bundle ----
|
|
62
|
+
if (-not $PresetDir) {
|
|
63
|
+
$roots = @()
|
|
64
|
+
if ($env:DSH_PROFILE_DIR) { $roots += (Join-Path $env:DSH_PROFILE_DIR 'node_modules\@shundoo-ai\dsh-cosmic') }
|
|
65
|
+
if ($env:DSH_HOME) { $roots += (Join-Path $env:DSH_HOME '.agent-presets\cosmic') }
|
|
66
|
+
$PresetDir = $roots | Where-Object { $_ -and (Test-Path $_) } | Select-Object -First 1
|
|
67
|
+
}
|
|
68
|
+
if (-not $PresetDir) {
|
|
69
|
+
throw "Cannot locate the cosmic skill bundle. Set DSH_PROFILE_DIR/DSH_HOME, or pass -PresetDir <path containing skills\cosmic-build>."
|
|
70
|
+
}
|
|
71
|
+
$agent = Join-Path $PresetDir 'skills\cosmic-build\skills\cosmic-vibe-coding\assets\kd-reloadjar-agent.jar'
|
|
72
|
+
if (-not (Test-Path $agent)) { throw "Missing reload agent: $agent" }
|
|
73
|
+
$devScript = Join-Path $PresetDir 'skills\cosmic-build\skills\cosmic-vibe-coding\scripts\dev.py'
|
|
74
|
+
|
|
75
|
+
# ---- 1. Read dev.json (env config produced by dev.py init) ----
|
|
76
|
+
$devJson = Join-Path $cwd '.dsh\cosmic\config\dev.json'
|
|
77
|
+
if (-not (Test-Path $devJson)) {
|
|
78
|
+
throw "Missing $devJson -- run 'dev.py init' first (enable hot-deploy / set ERP login)."
|
|
79
|
+
}
|
|
80
|
+
$dev = Get-Content $devJson -Raw | ConvertFrom-Json
|
|
81
|
+
|
|
82
|
+
# Port: explicit -Port wins, then dev.json, then the port embedded in erp_url.
|
|
83
|
+
$effPort = if ($Port) { $Port }
|
|
84
|
+
elseif ($dev.port) { [int]$dev.port }
|
|
85
|
+
elseif ($dev.erp_url -match '^https?://[^:/]+:(\d+)') { [int]$Matches[1] }
|
|
86
|
+
else { 80 }
|
|
87
|
+
$accountId = $dev.account_id
|
|
88
|
+
$tenantId = $dev.tenant_id
|
|
89
|
+
if (-not $accountId) { throw "dev.json has no account_id -- re-run 'dev.py init'." }
|
|
90
|
+
|
|
91
|
+
# ---- 2. Discover the cosmic PID by port ownership, then validate the JVM ----
|
|
92
|
+
$conn = Get-NetTCPConnection -LocalPort $effPort -State Listen -ErrorAction SilentlyContinue |
|
|
93
|
+
Select-Object -First 1
|
|
94
|
+
if (-not $conn) { throw "Nothing is listening on port $effPort -- is cosmic running?" }
|
|
95
|
+
$targetPid = $conn.OwningProcess
|
|
96
|
+
$proc = Get-CimInstance Win32_Process -Filter "ProcessId=$targetPid"
|
|
97
|
+
if ($proc.CommandLine -notmatch 'kd\.bos\.service\.webserver\.JettyServer') {
|
|
98
|
+
throw "Process $targetPid on port $effPort is not the cosmic JettyServer: $($proc.CommandLine)"
|
|
99
|
+
}
|
|
100
|
+
if ($proc.CommandLine -match 'DisableAttachMechanism') {
|
|
101
|
+
throw "Process $targetPid has -XX:+DisableAttachMechanism -- hot-deploy cannot attach to it."
|
|
102
|
+
}
|
|
103
|
+
$owner = ($proc | Invoke-CimMethod -MethodName GetOwner).User
|
|
104
|
+
|
|
105
|
+
# ---- 3. Pick the JDK: prefer the one the cosmic process itself runs on ----
|
|
106
|
+
# Derive JAVA_HOME from the process executable (reliable, unlike parsing the
|
|
107
|
+
# command line, which may quote "C:\path with spaces"\bin\java differently).
|
|
108
|
+
$candidates = @()
|
|
109
|
+
if ($proc.ExecutablePath) {
|
|
110
|
+
$javaBin = Split-Path $proc.ExecutablePath -Parent # ...\jdk\bin
|
|
111
|
+
if ((Split-Path $javaBin -Leaf) -ieq 'bin') { $candidates += (Split-Path $javaBin -Parent) }
|
|
112
|
+
}
|
|
113
|
+
if ($env:JAVA_HOME) { $candidates += $env:JAVA_HOME }
|
|
114
|
+
# Common JDK install roots across drives (best effort, machine independent).
|
|
115
|
+
foreach ($root in @("$env:ProgramFiles\Java", "${env:ProgramFiles(x86)}\Java", 'C:\Java',
|
|
116
|
+
'D:\Java', 'D:\Program Files\Java', "$env:USERPROFILE\.jdks")) {
|
|
117
|
+
if ($root -and (Test-Path $root)) {
|
|
118
|
+
$candidates += (Get-ChildItem $root -Directory -ErrorAction SilentlyContinue |
|
|
119
|
+
Where-Object { $_.Name -match '^jdk' } | ForEach-Object { $_.FullName })
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
$candidates = $candidates | Where-Object { $_ } | Select-Object -Unique
|
|
123
|
+
|
|
124
|
+
# A usable JDK for the Attacher has lib\tools.jar (JDK8) and bin\java.exe.
|
|
125
|
+
$attacherJdk = $candidates |
|
|
126
|
+
Where-Object { (Test-Path (Join-Path $_ 'lib\tools.jar')) -and (Test-Path (Join-Path $_ 'bin\java.exe')) } |
|
|
127
|
+
Select-Object -First 1
|
|
128
|
+
if (-not $attacherJdk) {
|
|
129
|
+
throw @"
|
|
130
|
+
No usable JDK for the Attacher (needs lib\tools.jar + bin\java.exe).
|
|
131
|
+
Candidates tried: $($candidates -join ' | ')
|
|
132
|
+
The target cosmic JVM needs a matching JDK whose major version matches it.
|
|
133
|
+
If cosmic runs on JDK8, install a JDK8 (not a JRE!) and pass -Workspace/-PresetDir as needed,
|
|
134
|
+
or set `$env:JAVA_HOME to a real JDK.
|
|
135
|
+
"@
|
|
136
|
+
}
|
|
137
|
+
$java = Join-Path $attacherJdk 'bin\java.exe'
|
|
138
|
+
$toolsJar = Join-Path $attacherJdk 'lib\tools.jar'
|
|
139
|
+
|
|
140
|
+
Write-Host "[env] workspace = $cwd"
|
|
141
|
+
Write-Host "[env] erp_url = $($dev.erp_url) (port $effPort)"
|
|
142
|
+
Write-Host "[env] cosmic PID = $targetPid (owner=$owner)"
|
|
143
|
+
Write-Host "[env] attacher JDK = $attacherJdk"
|
|
144
|
+
Write-Host "[env] accountId = $accountId / tenantId = $tenantId"
|
|
145
|
+
|
|
146
|
+
# ---- 4. Optional: build first ----
|
|
147
|
+
if ($Module) {
|
|
148
|
+
$gradleHome = Join-Path $cwd '.gradle\user-home'
|
|
149
|
+
|
|
150
|
+
# 4.1 Gradle version must follow the wrapper, never "newest dist" -- a newer
|
|
151
|
+
# dist (e.g. 8.x) may demand a newer Java runtime and derail this JDK8 chain.
|
|
152
|
+
$wrapperProps = Join-Path $cwd 'gradle\wrapper\gradle-wrapper.properties'
|
|
153
|
+
if (-not (Test-Path $wrapperProps)) { throw "Missing $wrapperProps." }
|
|
154
|
+
$m = [regex]::Match((Get-Content $wrapperProps -Raw), 'gradle-([0-9.]+)-bin')
|
|
155
|
+
if (-not $m.Success) { throw "Cannot parse the Gradle version from $wrapperProps." }
|
|
156
|
+
$distVer = $m.Groups[1].Value
|
|
157
|
+
$distRoot = Join-Path $env:USERPROFILE ".gradle\wrapper\dists\gradle-$distVer-bin"
|
|
158
|
+
$gradleBat = Get-ChildItem $distRoot -Recurse -Filter 'gradle.bat' -ErrorAction SilentlyContinue |
|
|
159
|
+
Select-Object -First 1
|
|
160
|
+
if (-not $gradleBat) {
|
|
161
|
+
throw "Gradle $distVer not found under $distRoot. Let the wrapper download it first (run .\gradlew.bat)."
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
# 4.2 Build JDK: same preference order as above, but must carry tools.jar.
|
|
165
|
+
$buildJdk = $attacherJdk
|
|
166
|
+
if ($WhatIf) { Write-Host '[whatif] dry run: skipping the actual build.' }
|
|
167
|
+
|
|
168
|
+
$gradleArgs = @()
|
|
169
|
+
if ($Clean) { $gradleArgs += (':' + $Module + ':clean') }
|
|
170
|
+
$gradleArgs += (':' + $Module + ':build')
|
|
171
|
+
$gradleArgs += @('-x', 'test', '--console=plain')
|
|
172
|
+
Write-Host "[build] gradle $distVer | $($gradleArgs -join ' ')"
|
|
173
|
+
Write-Host "[build] JAVA_HOME=$buildJdk (GRADLE_USER_HOME=$gradleHome)"
|
|
174
|
+
$env:GRADLE_USER_HOME = $gradleHome
|
|
175
|
+
$env:JAVA_HOME = $buildJdk
|
|
176
|
+
& $gradleBat.FullName @gradleArgs
|
|
177
|
+
if ($LASTEXITCODE -ne 0) { throw "Gradle build failed (exit $LASTEXITCODE) -- see the compile errors above." }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
# ---- 5. Resolve jars (auto-locate the build output when -Module was given) ----
|
|
181
|
+
if ((-not $Jar -or $Jar.Count -eq 0) -and $Module) {
|
|
182
|
+
$settings = Get-Content (Join-Path $cwd 'settings.gradle') -Raw
|
|
183
|
+
$mm = [regex]::Match($settings,
|
|
184
|
+
"project\(':$([regex]::Escape($Module))'\)\.projectDir\s*=\s*new File\('([^']+)'\)")
|
|
185
|
+
$moduleDir = if ($mm.Success) { Join-Path $cwd ($mm.Groups[1].Value -replace '/', '\') }
|
|
186
|
+
else { Join-Path $cwd "code\$Module" }
|
|
187
|
+
$libsDir = Join-Path $moduleDir 'build\libs'
|
|
188
|
+
$Jar = @(Get-ChildItem $libsDir -Filter '*.jar' -ErrorAction SilentlyContinue |
|
|
189
|
+
Where-Object { $_.Name -notlike '*sources*' -and $_.Name -notlike '*javadoc*' } |
|
|
190
|
+
Sort-Object LastWriteTime -Descending | Select-Object -First 1 |
|
|
191
|
+
ForEach-Object { $_.FullName })
|
|
192
|
+
if (-not $Jar) { throw "No build output jar in $libsDir." }
|
|
193
|
+
}
|
|
194
|
+
if (-not $Jar -or $Jar.Count -eq 0) {
|
|
195
|
+
Write-Host '[done] Health check only -- no hot-deploy (pass -Jar or -Module).'
|
|
196
|
+
exit 0
|
|
197
|
+
}
|
|
198
|
+
$jars = $Jar | ForEach-Object { (Resolve-Path $_).Path }
|
|
199
|
+
foreach ($j in $jars) {
|
|
200
|
+
Write-Host "[jar] $j ($([math]::Round((Get-Item $j).Length / 1KB)) KB)"
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
# ---- 6. Attach: save the jar bytes, then reload the ExtClassLoader ----
|
|
204
|
+
$attArgs = @(
|
|
205
|
+
'-cp', "$toolsJar;$agent",
|
|
206
|
+
'kd.reloadjar.Attacher',
|
|
207
|
+
$targetPid, $agent,
|
|
208
|
+
($jars -join ','),
|
|
209
|
+
$accountId, $tenantId
|
|
210
|
+
)
|
|
211
|
+
if ($LogFile) {
|
|
212
|
+
$dir = Split-Path $LogFile -Parent
|
|
213
|
+
if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Force -Path $dir | Out-Null }
|
|
214
|
+
$attArgs += (Join-Path (Resolve-Path $dir).Path (Split-Path $LogFile -Leaf))
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
& $java @attArgs
|
|
218
|
+
if ($LASTEXITCODE -ne 0) { throw "Hot-deploy failed (exit $LASTEXITCODE)." }
|
|
219
|
+
Write-Host '[done] Hot-deploy complete (SUCCESS = save + reset both applied).'
|
|
@@ -139,13 +139,25 @@ api fileTree(trd) {
|
|
|
139
139
|
`<cwd>/.dsh/cosmic/config/dev.json`:
|
|
140
140
|
|
|
141
141
|
```json
|
|
142
|
-
{ "java_home": "C:\\Program Files\\
|
|
142
|
+
{ "java_home": "C:\\Program Files\\Java\\jdk1.8.0_281" }
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
- 以 IDEA 项目 SDK
|
|
146
|
-
- Attacher 需与 cosmic 进程同 JDK **大版本**(JDK 8
|
|
145
|
+
- 以 IDEA 项目 SDK 为准(实测本机 = `C:\Program Files\Java\jdk1.8.0_281`,JDK 8,含 tools.jar)
|
|
146
|
+
- Attacher 需与 cosmic 进程同 JDK **大版本**(JDK 8,具体小版本无关;cosmic 自带
|
|
147
|
+
`F:\cosmic\xinghan8\jdk` = 1.8.0_212,与本机 1.8.0_281 混用无碍)
|
|
147
148
|
- `dev.py init` 自动发现不到时手动补;改后 `dev.py read` 验证
|
|
148
149
|
|
|
150
|
+
> ⚠️ **必设 `JAVA_HOME`,否则 `compileJava` 必失败**(实测踩坑):本机 Windows 注册表
|
|
151
|
+
> `HKLM\SOFTWARE\JavaSoft\Java Development Kit` 的 `JavaHome` 被 8u481 安装包改写成
|
|
152
|
+
> **JRE** 路径 `C:\Program Files\Java\jre1.8.0_481`。Gradle 在该值存在时优先采信它,
|
|
153
|
+
> 于是 `java.home` 指向 JRE → 没有 `tools.jar` → 报
|
|
154
|
+
> `Could not find tools.jar. Please check that ...\jre1.8.0_481 contains a valid JDK installation`。
|
|
155
|
+
> 显式 `$env:JAVA_HOME="C:\Program Files\Java\jdk1.8.0_281"` 即解(实测全量编译 10s 通过)。
|
|
156
|
+
>
|
|
157
|
+
> 🔎 **同源陷阱:「伪成功构建」**。若 `compileJava` 处于 `UP-TO-DATE`,Gradle 根本不加载
|
|
158
|
+
> 编译器,缺 tools.jar 也不报错 —— 你会看到 `BUILD SUCCESSFUL` + `jar` 正常产出,
|
|
159
|
+
> **但 jar 里是旧字节码**。首次接入务必用 `clean build` 验证一次真编译(本次就是这么暴露的)。
|
|
160
|
+
|
|
149
161
|
### 4.4 验证 classpath 是否真的干净(临时 init script)
|
|
150
162
|
|
|
151
163
|
`showcp.gradle`(用完可删):
|
|
@@ -205,11 +217,19 @@ Get-ChildItem "<lib>" -Recurse -Filter *.jar | ForEach-Object {
|
|
|
205
217
|
> 见 §0),须先单命令级放开 `danger-full-access`;`--no-daemon` 也救不了。
|
|
206
218
|
|
|
207
219
|
```powershell
|
|
208
|
-
$env:JAVA_HOME = "C:\Program Files\
|
|
220
|
+
$env:JAVA_HOME = "C:\Program Files\Java\jdk1.8.0_281" # 必须:注册表 java.home 指向 JRE(见 §4.3)
|
|
209
221
|
$gradle = "C:\Users\<user>\.gradle\wrapper\dists\gradle-7.6.3-bin\<hash>\gradle-7.6.3\bin\gradle.bat"
|
|
210
222
|
& $gradle ":<模块>:build" -x test --console=plain
|
|
211
223
|
```
|
|
212
224
|
|
|
225
|
+
> ⚠️ **Gradle 版本必须按 `gradle/wrapper/gradle-wrapper.properties` 锁定**,不要「取
|
|
226
|
+
> `~/.gradle/wrapper/dists` 下最新」。本机同时存在 `gradle-8.8-bin`,它要求 Java 22
|
|
227
|
+
> 运行时,与本项目 JDK 8 + tools.jar 链路不兼容,会直接把构建带偏。
|
|
228
|
+
>
|
|
229
|
+
> 🧩 本工作区已把整套流程封装为脚本:`runtime/cosmic-hotdeploy.ps1`
|
|
230
|
+
> (体检 / `-Jar` 热加载 / `-Module` 构建+热加载 / `-Clean`),内置上述 JDK、Gradle
|
|
231
|
+
> 版本、PID 发现、account/tenant 读取逻辑,可直接用。
|
|
232
|
+
|
|
213
233
|
> ❌ 不要加 `--no-daemon`:每次 fork 单次 Daemon(JVM 冷启动 + 重新加载配置 ≈ +30s)
|
|
214
234
|
> ✅ 复用常驻 Daemon(`org.gradle.daemon=true` 默认开启),改几行代码约 5-10 秒
|
|
215
235
|
|
|
@@ -314,6 +334,11 @@ for incremental compilation. See the debug log for more details.
|
|
|
314
334
|
### 6.1 发现 cosmic PID
|
|
315
335
|
|
|
316
336
|
```powershell
|
|
337
|
+
# ⭐ 方式零(推荐):按端口归属进程反查 + 命令行校验(实测最可靠)
|
|
338
|
+
$conn = Get-NetTCPConnection -LocalPort <cosmic_port> -State Listen | Select-Object -First 1
|
|
339
|
+
$cosmicPID = $conn.OwningProcess
|
|
340
|
+
(Get-CimInstance Win32_Process -Filter "ProcessId=$cosmicPID").CommandLine # 应含 kd.bos.service.webserver.JettyServer
|
|
341
|
+
|
|
317
342
|
# 方式一:HTTP 探测端口(最可靠,权限问题兜底)
|
|
318
343
|
Invoke-WebRequest http://127.0.0.1:<cosmic_port>/ierp # HTTP 200 = cosmic 活着
|
|
319
344
|
|
|
@@ -355,6 +380,15 @@ $jar = "<模块>\build\libs\<模块>-1.0.0.jar"
|
|
|
355
380
|
多次构建间隔短时用「最新时间戳 ±30s」窗口精确切分,避免混入前一次全量产物
|
|
356
381
|
8. **`dependencies --configuration compileClasspath` 对 fileTree 是惰性展开**,不一定显示 jar 明细,
|
|
357
382
|
要确认真实 classpath 必须用自定义任务打印 `sourceSets.main.compileClasspath.files`
|
|
383
|
+
9. **`jps` 看不到 cosmic 进程**(实测):本机 cosmic 由 **SYSTEM** 账户启动
|
|
384
|
+
(`F:\cosmic\xinghan8\jdk\bin\java ... -DappName=cosmic ... kd.bos.service.webserver.JettyServer`),
|
|
385
|
+
而 `jps` 只列举当前用户的 JVM → 输出里完全没有它,容易误判「cosmic 没启动」。
|
|
386
|
+
用 §6.1 方式零(按端口反查 OwningProcess)替代。
|
|
387
|
+
10. **跨用户 attach 是可用的,无需提权**:cosmic 跑在 SYSTEM 下、Attacher 由
|
|
388
|
+
`lihaisheng\administrator` 启动,实测 attach 成功(Windows JVM attach 命名管道对
|
|
389
|
+
Administrators 组放行),不必 `Start-Process -Verb RunAs`。
|
|
390
|
+
11. **`-XX:+DisableAttachMechanism` 是硬阻断**:本机 IDEA 侧另一个 JVM(`CosmicStudio-runnable.jar`)
|
|
391
|
+
带此参数,对它 attach 必然失败;发现 PID 后先扫命令行里有没有这个 flag。
|
|
358
392
|
9. **`java_home` 以 IDEA 项目 SDK 为准**(Windows 常见 `C:\Program Files\java\jdk`),
|
|
359
393
|
不要误填 cosmic 自带 JDK 目录;Attacher 只需与 cosmic 同 JDK 大版本(同为 JDK8 即兼容)
|
|
360
394
|
10. **gradle 构建命令不要加 `--no-daemon`**;多 IDLE Daemon 并存无害,`--stop` 可一次性清理
|