@shundoo-ai/dsh-cosmic 1.0.7 → 1.0.9
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
|
@@ -90,6 +90,8 @@ description: >
|
|
|
90
90
|
> **build + 热部署**:R0 → R1 → R2 → R3 → R4 → R5。
|
|
91
91
|
> 每一步都给「期望」与「失败处置」;**不做即兴发挥**,缺规则就回写手册(见文末自检)。
|
|
92
92
|
|
|
93
|
+
> 🔁 **执行方式**:可以逐步执行,也可以把本手册**物化**成工作区内的临时脚本一次跑完(实测:Windows 会话把它写成 `<cwd>/.dsh/cosmic/scripts/hotdeploy.ps1`,此后"构建+热部署"每次只花 1 次调用)。**若物化,遵守四条**:① 放在 `.dsh/` 下(git 忽略、不入库);② **本手册是唯一权威**——手册更新后重新生成,不得反向以脚本为准;③ 脚本只做编排(发现 → 构建 → 注入),**不得引入手册之外的行为**;④ **不得写死本机路径**(工作区 / Gradle 根 / profile 名 / JDK 安装路径),工作区与 Gradle 根按 R1.1 推导、profile 用 `$DSH_PROFILE_DIR`、JDK 按 R2.1 顺位选择 —— 实测有脚本写死 `$cwd` 与 `profiles\web`,换机器即失效。**生成后自查**:在脚本里 grep 一遍本机绝对路径与写死的 profile 名,应当**只出现推导逻辑、不出现具体值**。
|
|
94
|
+
|
|
93
95
|
> **平台约定:本手册三平台通用**(Windows / macOS / Linux 各步骤都可用)。平台差异见下表;
|
|
94
96
|
> 失败分支表里**未标注平台的条目三平台通用**,标 `[Win]` 的只会发生在 Windows。
|
|
95
97
|
>
|
|
@@ -102,7 +104,7 @@ description: >
|
|
|
102
104
|
> |---|---|---|
|
|
103
105
|
> | PID 定位 | `Get-NetTCPConnection` → `Get-CimInstance`(**`jps` 看不到 SYSTEM 账户的 cosmic**) | `lsof -tiTCP:<port> -sTCP:LISTEN` 或 `jps -l \| grep JettyServer` |
|
|
104
106
|
> | classpath 分隔符 | `;` | `:` |
|
|
105
|
-
> | 沙箱 |
|
|
107
|
+
> | 沙箱 | 受限沙箱**砍令牌特权**(实测只剩 `SeChangeNotifyPrivilege`)→ 端口查询被拒、attach 缺 `SeDebugPrivilege`(见 F4);构建的 `CreatePipe error=5` 是另一条(见 F3) | 无此限制 |
|
|
106
108
|
> | shell / 变量 | PowerShell(DSH 兜底到 5.1,注意默认 ANSI 解码);`$env:VAR=` | bash/sh;`export VAR=` |
|
|
107
109
|
> | 构建可执行 | `gradle.bat`(按 wrapper 定版) | `gradle`(按 wrapper 定版) |
|
|
108
110
|
> | 缓存预热命令 | `robocopy`(见 R3.2) | `cp -R`(见 R3.2) |
|
|
@@ -155,7 +157,7 @@ $proc.CommandLine # 必须含 kd.bos.service.webserver.JettyServer
|
|
|
155
157
|
|
|
156
158
|
- ⚠️ **Windows 上 `jps` 看不到 cosmic**(实测):cosmic 常由 **SYSTEM** 账户启动,而 `jps` 只列举**当前用户**的 JVM → 输出为空,**极易误判「cosmic 没启动」**。用端口反查。
|
|
157
159
|
- 定位后必查命令行是否含 `-XX:+DisableAttachMechanism` —— 带此参数的 JVM **无法 attach**,直接停。
|
|
158
|
-
-
|
|
160
|
+
- attach 到 cosmic(**SYSTEM 属主**,与调用方**异属主/异 IL**)需要**打开目标进程句柄**的特权,判据就是调用方令牌带不带 **`SeDebugPrivilege`**(**`whoami /priv` 一眼可判**)。DSH 受限沙箱(`workspace-write`)/ 未提升 / UAC 过滤令牌,**都只是"缺这个特权"的不同成因** → `openProcess` 报 `拒绝访问`。⚠️ **别写"无需提权"**(早期结论已被证伪;本机 `EnableLUA=0` 恒带该特权,才看起来"不需要")。
|
|
159
161
|
- 同机多个 cosmic 进程,认命令行区分(例:`mservice-cosmic\lib` + `-agentlib:jdwp=…address=5005` = 热部署目标;`mservice\lib` + `-Dmonitor.dev.model=debug` = 另一套)。**勿杀错进程。**
|
|
160
162
|
|
|
161
163
|
#### R1.3 定位模块目录与产物
|
|
@@ -179,6 +181,7 @@ $proc.CommandLine # 必须含 kd.bos.service.webserver.JettyServer
|
|
|
179
181
|
|
|
180
182
|
> ⚠️ 跨大版本 attach(JDK17 attach JDK8)会报 `AgentLoadException`。
|
|
181
183
|
> ⚠️ Windows 注册表 `HKLM\SOFTWARE\JavaSoft\Java Development Kit\JavaHome` 可能被 JRE 安装包改写 → Gradle 报 `Could not find tools.jar`;**必须显式设 `JAVA_HOME`**。
|
|
184
|
+
> ✅ **别把"两套安装"当成配置错误**:编译类路径来自 `gradle.properties` 的 `systemProp.cosmic_home`(**编译期 SDK**),而 Attacher JDK 取**目标进程自身** —— 实测两者可以是完全不同的安装(如编译期 `F:/xhhome8`、运行实例 `F:\cosmic\xinghan8`),这是**正常布局**,与"能否构建 / 热部署成功"无关,**不要建议用户去改成一致**。唯一固有代价:用到的 API 必须**编译期在 SDK 里、运行期在实例里都存在**(缺前者编译失败,缺后者运行时 `NoSuchMethodError`)。
|
|
182
185
|
|
|
183
186
|
#### R2.2 Gradle(按 wrapper 锁定,不取"最新 dist")
|
|
184
187
|
|
|
@@ -195,6 +198,7 @@ $GRADLE = Get-ChildItem "$env:USERPROFILE\.gradle\wrapper\dists\gradle-$VER-bin"
|
|
|
195
198
|
```
|
|
196
199
|
|
|
197
200
|
> ⚠️ 机器上可能并存要求 Java 22 的新版 Gradle —— 取"最新"会把构建带偏。
|
|
201
|
+
> ⚠️ **dist 可能只在两处之一**:系统 `~/.gradle/wrapper/dists/`(`$env:USERPROFILE\.gradle\wrapper\dists\`)**或**工作区 `<Gradle根>/.gradle/user-home/wrapper/dists/`(AGENTS.md 约定的 `GRADLE_USER_HOME`)。上面两段示例都只搜了系统那处 —— **两处都搜,命中即用**。
|
|
198
202
|
|
|
199
203
|
#### R2.3 agent jar(用机器级缓存副本,**不要**直接用 preset 原件)
|
|
200
204
|
|
|
@@ -253,14 +257,53 @@ try { & $GRADLE ":<模块>:build" -x test --console=plain } finally { Pop-Locati
|
|
|
253
257
|
| 有 javac 的 `deprecation` / `unchecked` 提示 | 真编译 | 正常 |
|
|
254
258
|
| `BUILD SUCCESSFUL` 但 `build/classes` 为空 | 伪成功 | 同上,重跑 |
|
|
255
259
|
|
|
256
|
-
>
|
|
260
|
+
> 真编译判据:**① 与 ③ 是硬判据** —— ① `compileJava` 后**没有** `UP-TO-DATE`/`FROM-CACHE`;③ `build/classes` 下 class 的 mtime 是**刚刚**。
|
|
261
|
+
> **② 只是旁证**:出现 javac 的 `deprecation`/`unchecked` 提示可佐证真编译,但**该文件没触发这类警告时就不会出现 —— 不代表没编译**(实测:1 个 class 真编译,①③ 成立而 ② 为空)。**别把 ② 当必要条件**,否则会误判"没编译"。
|
|
257
262
|
> ⚠️ 本模板 `gradle.properties` 带 `org.gradle.caching=true`,`clean` 后仍可能 `FROM-CACHE`(macOS 实测 **879ms**、Windows 约 **2 秒** 跑完)。**要真编译必须加 `--no-build-cache`**(必要时再加 `--rerun-tasks` 强制重跑整任务图 —— 注意它在大模块上会连 jar transform 一起重跑,见 R3.2)。
|
|
263
|
+
> 🔬 **一个可复用的诊断手法**:想逼出"真实 javac"又不想全量重编,可**删掉某一个产出的 `.class`** 再构建 —— 如果它 **1~2 秒就从 `FROM-CACHE` 还原**,说明构建缓存(`org.gradle.caching=true`)在起作用、**javac 依然没跑**;此时要真编译必须 `--no-build-cache`。(实测:Windows 1.5s `FROM-CACHE`。)
|
|
264
|
+
|
|
265
|
+
#### R3.2 构建耗时:先看"该花多少"的基准,再判异常
|
|
266
|
+
|
|
267
|
+
**实测基准**(Windows;模块 ~100 class;编译类路径 **4497 jar** —— 该数是 **ymprj 工作区 `mservice-cosmic/lib` 目录的 jar 总数**,与 slow-windows 文档 §4.4 的"4008 个文件(khxty 工作区、模块 `compileClasspath` 文件数)"**口径与工程都不同**,别混;**同机,跨若干 daemon** —— 正是因为"daemon 新旧"被证明不是因子,才把两次全新 daemon 的对照都列进来):
|
|
268
|
+
|
|
269
|
+
| 场景 | Wall | javac 真跑了吗 |
|
|
270
|
+
|------|------|----------------|
|
|
271
|
+
| no-op(只做配置 + UP-TO-DATE 检查) | **1.4s** | 否 |
|
|
272
|
+
| 删产物 class → 构建缓存还原 | **1.5s** | 否(`FROM-CACHE`) |
|
|
273
|
+
| 真 javac(1 个文件,**距上次真编译 1–8 分钟**) | **3~4.7s** | 是 |
|
|
274
|
+
| **全新 daemon**、缓存热(距上次真编译 **8 分钟**) | **8.75s** | 是 |
|
|
275
|
+
| **全新 daemon**、缓存热(距上次真编译 **46 分钟**) | **8.65s** | 是 |
|
|
276
|
+
| 真 javac,**距上次真编译 13.5 小时**(daemon 新旧**无关**) | **~139s** | 是 |
|
|
277
|
+
|
|
278
|
+
> 🔥 **热窗口(实测边界)**:间隔 **≤1 小时**仍为 ~9s 量级(8min→8.75s、**46min→8.65s**,几乎无变化);**13.5h → ~139s**。⇒ 冷热分界落在 **46 分钟 ~ 13.5 小时**之间(未进一步二分);**"全新 daemon"不是变慢的原因**(上表两行全新 daemon 都很便宜)。
|
|
279
|
+
|
|
280
|
+
**两种"冷"必须分开,判据不同:**
|
|
281
|
+
|
|
282
|
+
| 触发 | 判据 | 量级 | 处置 |
|
|
283
|
+
|---|---|---|---|
|
|
284
|
+
| ① 快照**从零建**(新工作区 / 新类路径) | `javaCompile/classAnalysis.bin` **持续增长** | 20 分钟级(4000+ jar / 1.9 GB) | 搬运现成快照(见下),或预热一次后等 |
|
|
285
|
+
| ② 冷缓存的一次性开销(**触发是「距上次真编译的间隔」,与 daemon 是否新建无关**) | `classAnalysis.bin` 已存在(实测 ~370MB)**且不再增长**,而 **wall ≫ 进程 CPU**(139s wall / 累计 ~30s CPU → **≥3/4 时间不烧 CPU,阻塞型**;对照热态那次是 **CPU-bound**:36s 生命期烧 35.3s CPU) | **~140s(间隔小时级)**;**间隔 ≤1 小时**则 ~9s 量级(实测 8min→8.75s、46min→8.65s) | 等它跑完(**不要 kill**) |
|
|
286
|
+
|
|
287
|
+
> ⚠️ **归因修正(2026-09-24 实测,推翻早前写法)**:曾据两个数据点写成「每个 daemon 生命周期只付一次」,被**后续数据点证伪** —— 已有**两个**"全新 daemon 却很便宜"的独立反例(12:59 启动的 8.75s、13:44 启动的 8.65s,后者距上次真编译 **46 分钟**),而另一 daemon 在**隔 13.5 小时**后花了 139s。
|
|
288
|
+
> 四点数据:间隔 **13.5h → 139s**(阻塞型)|**46min → 8.65s**|**8min → 8.75s**|**1–8min → 3–4s**。→ **相关因子是"距上次真编译的间隔",不是 daemon 寿命**。
|
|
289
|
+
> 🔁 **跨日复现(唯一的非当日样本)**:`daemon-28568`(**9/23** 22:49)**首次构建 157s → 同一 daemon 第 2 次 8.7s**,与今日同一形态 ⇒ 该现象**不是当日偶发**。⚠️ 该次只留存 wall(构建期 daemon 日志 0 行、客户端输出未留存),**无法确认当次 javac 是否真跑**,故记"首次构建"而非"首次真编译"。
|
|
290
|
+
> 成因**未定**:OS page cache 冷读(371 MB 快照被换出)与 Gradle 缓存状态需重新校验,**两者都能解释现有数据,没有可区分二者的证据** —— 不要写成已证结论。
|
|
291
|
+
> 内存已排除:实测该机 **65 GB 总量 / 40.6 GB 可用**(也印证删掉 `-Xmx` 那条建议是对的)。
|
|
292
|
+
> 源文件可追溯:`<Gradle根>/.gradle/user-home/daemon/<ver>/daemon-<pid>.out.log`(如 `daemon-33008`(46min→8.65s)/ `daemon-1944`(8min→8.75s)/ `daemon-7524`(13.5h→139s)/ `daemon-28568`(9/23 跨日复现:首次构建 157s → 第 2 次 8.7s))。
|
|
293
|
+
|
|
294
|
+
规则:
|
|
258
295
|
|
|
259
|
-
|
|
296
|
+
- **不要 `--no-daemon`**:每次构建都要付 JVM 冷启动 + 配置开销,量级**因项目而异**:本工作区实测全新 daemon 冷启动 **3–5s**(13.9s 总 wall − daemon 内构建 8.75s,含客户端握手与本手册 R0–R2 发现 ~1.9s);另一工作区数据是 `--no-daemon` 42s vs 常驻 32s(**Δ≈10s**,见 `cosmic-dev-best-practices/references/cosmic-hotdeploy-build-slow-windows.md` §4.7/§5.1)。⚠️ 别引用 "+30s"(该文档早前版本有此处,与它自己的数据表不符,已修正)。方向不变:**保留常驻 daemon**;另⚠️ 本条与 ② 无关 —— 早前写的"否则 140s 每次都要重付"基于已被证伪的 daemon 寿命归因。
|
|
297
|
+
- **隔了几小时没编译后的第一次构建会慢(~140s),属正常**,别误判成卡死、也别急着重启 daemon。想把它与正式构建分开观察时,可以先跑一次 `:<模块>:compileJava` 把冷开销付掉再跑构建。
|
|
298
|
+
- 🔬 **量构建 wall 的两个仪表,含义不同,别混用**:① Gradle 自报 `BUILD SUCCESSFUL in Ns` = 客户端观测的整次构建;② `daemon-<pid>.out.log` 里成对的 `has started executing the build` / `has finished executing the build` = **daemon 侧真正执行构建的时段**。实测同一次构建两者可差几秒(**8.75s vs 12s**,差在客户端握手/启动)。做分档归因(如 ② 的冷开销)用 ②,报告用户感知耗时用总 wall。注意:该文件**只有生命周期标记、没有构建期内容日志**(见下条)。
|
|
299
|
+
- 判"卡住"必须**两个信号同时看**:进程 CPU 增量 ≈ 0 **且** `classAnalysis.bin` 不再增长。只看"没有输出"会把冷开销误判成死锁(这条是实测踩出来的)。
|
|
300
|
+
- **"低 CPU 不是活干在别的进程"的佐证**:Gradle 7.6 默认在 daemon 进程内执行 javac(未显式配 `options.fork`),且实测构建后 `Get-Process java` 只有 Gradle daemon + cosmic + MC 三个 JVM、**无额外 worker**(Gradle worker daemon 默认 idle 3 小时不会自动退,若 fork 过必然还在)。
|
|
301
|
+
- ⚠️ **别用 `.out.log` 里 `Starting process / fork` 计数去证明"是否 fork"**:客户端连着构建时,daemon 把**内容日志全部转发给客户端**,`.out.log` 在构建期间**一行内容都不落** —— 那些计数为 0 是**结构性为零**,不是"观测到没 fork"(实测两份 daemon 日志在构建时段各 0 行;唯一像"编译"的行出现在 daemon **关闭**时释放缓存锁,属假阳性)。该文件里**只有生命周期标记**(上面那条仪表)是可用的。
|
|
302
|
+
- ⚠️ **`--rerun-tasks` 非必要不加**:它会强制重跑**整个任务图**(含 `jar transform`),在大模块上更慢,且实测在 `org.gradle.parallel=true` 下撞过 `AsyncCacheAccessDecoratedCache` 的跨进程缓存锁等待(54 线程 parked、守护进程 CPU≈0,12 分钟无进展)。怀疑缓存欺骗时,先试 `clean` + `--no-build-cache`(R3.1),仍不够再考虑它。
|
|
303
|
+
- 🔍 **别把这条与 ② 的 ~140s 合并成一条结论**:本条由 `--rerun-tasks` 触发,且跨**进程**锁需要 ≥2 个 Gradle 进程 —— 实测 ② 发生时机器上只有 **1 个** Gradle 进程(另有 cosmic、MC),条件不满足,两者是不同现象。
|
|
304
|
+
- 可选缓解(**未直证,仅现象吻合**):把安装根(含 `mservice-cosmic/lib`)与 `<Gradle根>/.gradle` 加入 **Defender 实时扫描排除**(需管理员)—— 411 MB 分析文件首次读入被 AV 拦一遍,与百秒级等待吻合,但没有做过 A/B。
|
|
260
305
|
|
|
261
|
-
|
|
262
|
-
- **判据**:`<Gradle根>/.gradle/user-home/caches/<ver>/javaCompile/classAnalysis.bin` **持续增长 = 正在建快照(正常)**;12 秒内该文件不涨**且**守护进程 CPU 增量 ≈ 0 = 可能真卡住。
|
|
263
|
-
- **加速**:从系统 Gradle 主目录搬现成快照(按内容哈希寻址,同机同 jar 可复用):
|
|
306
|
+
**加速(① 的解法)**:从系统 Gradle 主目录搬现成快照(按内容哈希寻址,同机同 jar 可复用):
|
|
264
307
|
|
|
265
308
|
```powershell
|
|
266
309
|
# Windows
|
|
@@ -315,7 +358,8 @@ try { & $GRADLE ":<模块>:build" -x test --console=plain } finally { Pop-Locati
|
|
|
315
358
|
[ ] PID 的命令行含 kd.bos.service.webserver.JettyServer(没杀错进程)
|
|
316
359
|
[ ] jar 是绝对路径、且是本次构建产物(时间戳/大小对得上)
|
|
317
360
|
[ ] account_id / tenant_id 非空
|
|
318
|
-
[ ]
|
|
361
|
+
[ ] 调用方令牌带 `SeDebugPrivilege`(`whoami /priv` 一眼可判)—— **attach 到 SYSTEM 属主的 cosmic 时,缺它必报 `拒绝访问`**;**同用户同 IL 的目标(如自己起的 dev JVM)则不需要**(见 F4 与 slow-windows §7.10)
|
|
362
|
+
—— 受限沙箱 / 未提升 / UAC 过滤令牌都会造成缺它;⚠️ `EnableLUA=0` 时"提升"是空操作
|
|
319
363
|
```
|
|
320
364
|
|
|
321
365
|
### R5 验证
|
|
@@ -335,9 +379,9 @@ try { & $GRADLE ":<模块>:build" -x test --console=plain } finally { Pop-Locati
|
|
|
335
379
|
|---|-------------|------|------|
|
|
336
380
|
| F1 | `Unexpected UTF-8 BOM` | 凭证文件带 BOM,某处用裸 `utf-8` 读 | 去 BOM;**别再手编辑该 JSON,改走 `erp-config.py write`** |
|
|
337
381
|
| F2 | `does not contain a Gradle build` | 执行构建的 cwd 不是 Gradle 根 | 按 R1.1 切到含 `settings.gradle` 的目录 |
|
|
338
|
-
| F3 | `[Win]` `拒绝访问` / `CreatePipe error=5
|
|
339
|
-
| F4 | `[Win]` attach 报 `拒绝访问`(`WindowsVirtualMachine.openProcess
|
|
340
|
-
| F5 | `jps` 查不到 /
|
|
382
|
+
| F3 | `[Win]` **端口查询 / 起子进程**阶段的 `拒绝访问` / `CreatePipe error=5`(**不含 attach** —— attach 一律走 F4) | 沙箱未放开 | 把「体检 + 构建 + 注入」合成**尽量少的命令**并带 `danger-full-access` 重发;**不要先单独跑体检**(白花一次授权)。⚠️ **若会话审批提示已被禁用**(approval=never)而策略仍为 `workspace-write`,则**无法自行放开** → 构建/注入 fail-closed,**须先请用户恢复策略或授权**再继续 |
|
|
383
|
+
| F4 | `[Win]` attach 报 `拒绝访问`(`WindowsVirtualMachine.openProcess`)——**与 F3 同因(受限令牌)、不同失败点**:本条的 Attacher **已起来**,卡在打开句柄 | **调用方令牌缺"打开目标进程"的权限**:判据 = `whoami /priv` 里有没有 **`SeDebugPrivilege`**(沙箱受限令牌 / 未提升 / UAC 过滤令牌都只是缺它的成因;cosmic 常为 SYSTEM 属主,故必须有)。**已证**:沙箱外用 `runas /trustlevel:0x20000` 摘掉特权、**IL 未变**亦复现同一签名 ⇒ 与"跨完整性级别"无关(实验全文 + 复现命令见 slow-windows §7.14) | ① 在**同一 shell** 跑 `whoami /priv`:**无**该特权 → 放开沙箱(`danger-full-access`)或提升后原样重跑;**有**仍失败 → 查集合外原因(attach socket 残留 / 目标 JVM 未就绪 / `DisableAttachMechanism`);② ⚠️ `EnableLUA=0` 时 `RunAs` 是空操作 —— 此时**最常见**的缺特权来源是沙箱,但**不止它**(显式降权启动如 `runas /trustlevel:0x20000` 同样会造成) |
|
|
384
|
+
| F5 | `jps` 查不到 / 端口反查为空或报 `CimException: 拒绝访问` | ① Windows 上 cosmic 由 SYSTEM 启动 ② 端口错 ③ **沙箱拒绝**(受限沙箱下 `Get-NetTCPConnection` 会被拒) | 先用 R0.3 的 HTTP 探测区分"活着"与"查不到";活着 → 用 R1.2 端口反查;若反查被**沙箱**拒(`CimException: 拒绝访问`)→ **放开 `danger-full-access` 重跑**(注意:受限沙箱下运行手册会**止步于 R0.4**,要单测 Attacher 见 slow-windows §7.14 的复现命令) |
|
|
341
385
|
| F6 | `Could not find tools.jar` | `JAVA_HOME` 指向 JRE(或被注册表带偏) | 显式设 `JAVA_HOME` 到含 `lib/tools.jar` 的 JDK |
|
|
342
386
|
| F7 | `AgentLoadException` | Attacher 与目标 JVM 大版本不一致 | 用目标进程自己的 JDK(R2.1 第 1 顺位) |
|
|
343
387
|
| F8 | 构建长时间无输出 | 多半是冷缓存建快照,不一定是死锁 | 用 R3.2 判据;确卡住再清 Gradle 守护进程重试(**不要动 cosmic 进程**) |
|
|
@@ -16,11 +16,13 @@ Caused by: java.io.IOException: Cannot run program "…\jdk1.8.0_281\bin\java.ex
|
|
|
16
16
|
CreatePipe error=5, 拒绝访问
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
- 根因:DSH Windows
|
|
20
|
-
|
|
19
|
+
- 根因:DSH Windows 沙箱(受限令牌)下 **Gradle fork daemon 会撞 `CreatePipe error=5`**(`--no-daemon` 也无效:仍 fork single-use daemon)。
|
|
20
|
+
⚠️ 但**"起子进程 / 跨进程管道被一刀切禁止"不成立**(2026-09-24 实测):`cmd /c "echo PIPE_OK"` 在 `workspace-write` 下**成功**;早期见到的 `Program 'NETSTAT.EXE' failed to run: 拒绝访问` 触发条件**未钉死** —— **别把这条写成普遍规则**,逐例判断。
|
|
21
|
+
- ⚠️ **与热部署 Attacher 的失败不是同一个失败点**(2026-09-24 实测修正):Attacher 进程**能正常起来**(会打印 `attaching to pid=…`),是在 `openProcess`(打开目标进程句柄)时才被拒 —— 轴是**令牌特权**(见 §7.14),与 `CreatePipe` 这条无关,**别合并叙述**。
|
|
21
22
|
- 解决:构建/热部署命令须**单命令级放开权限**(`danger-full-access`,仅该命令生效)或会话级放宽;
|
|
22
23
|
放开后本文的增量排查才可进行
|
|
23
|
-
- 区分:`CreatePipe error=5` = 权限问题(跑不起来);本文第 3/4 节 =
|
|
24
|
+
- 区分:`CreatePipe error=5` = 权限问题(跑不起来);本文第 3/4 节 = 增量失效(跑得慢)——先排除前者。
|
|
25
|
+
注:**attach 的 `拒绝访问` 是另一条**(`openProcess` 阶段、轴是令牌特权),见 §7.14,别与本条的 `CreatePipe` 混。
|
|
24
26
|
|
|
25
27
|
---
|
|
26
28
|
|
|
@@ -106,9 +108,16 @@ Gradle 增量编译被禁用时,任何一次源码改动都会触发全量重
|
|
|
106
108
|
### 4.1 修改根 `cosmic/build.gradle`
|
|
107
109
|
|
|
108
110
|
```groovy
|
|
109
|
-
// subprojects 块内,trd 依赖排除嫌疑 jar
|
|
111
|
+
// subprojects 块内,trd 依赖排除嫌疑 jar。
|
|
112
|
+
// ⚠️ 清单**必须按 §4.8 的全量扫描重算**(版本敏感,勿照抄早期清单):
|
|
113
|
+
// 早期清单里的 bcprov-jdk18on-1.78.1.jar 在当前 trd 中已**不存在**(现为 1.82)——
|
|
114
|
+
// 这种 exclude 属于**静默空排除**:不报错、也不生效,最难排查。
|
|
115
|
+
// 下列为 2026-09 实测集合,仅作对照(log4j-core 是注解处理器那条,其余是含 Java17+ 类的):
|
|
116
|
+
// log4j-core-*.jar | bcprov-jdk18on-*.jar | hive-service-*.jar
|
|
117
|
+
// | ImpalaJDBC42-*.jar | jackson-core-*.jar | jsch-*.jar
|
|
110
118
|
api fileTree(dir: trd, include: '*.jar',
|
|
111
|
-
exclude: ['
|
|
119
|
+
exclude: ['log4j-core-2.20.0.jar', 'bcprov-jdk18on-1.82.jar', 'hive-service-4.2.0.jar',
|
|
120
|
+
'ImpalaJDBC42-2.6.38.jar', 'jackson-core-2.16.2.jar', 'jsch-0.2.26.jar'])
|
|
112
121
|
|
|
113
122
|
// allprojects 块内,JavaCompile 关闭注解处理(可选项,非增量必需——
|
|
114
123
|
// 实测去掉后增量编译仍生效,仅在全量编译时省 ~10s javac 处理器扫描时间;本项目最终去掉,保留最小改动)
|
|
@@ -123,7 +132,8 @@ tasks.withType(JavaCompile) {
|
|
|
123
132
|
```groovy
|
|
124
133
|
api fileTree(trd) {
|
|
125
134
|
include '*.jar'
|
|
126
|
-
|
|
135
|
+
// ⚠️ 按 §4.8 的全量扫描结果重算后再填(下面是 2026-09 实测集合,版本变了就作废)
|
|
136
|
+
exclude 'qing-arthas-*.jar', 'log4j-core-2.20.0.jar', 'bcprov-jdk18on-1.82.jar', 'hive-service-4.2.0.jar', 'ImpalaJDBC42-2.6.38.jar', 'jackson-core-2.16.2.jar', 'jsch-0.2.26.jar'
|
|
127
137
|
}
|
|
128
138
|
```
|
|
129
139
|
|
|
@@ -185,7 +195,8 @@ allprojects {
|
|
|
185
195
|
$gradle ":<模块>:showCompileCp" -I "<path>\showcp.gradle" --console=plain
|
|
186
196
|
```
|
|
187
197
|
|
|
188
|
-
>
|
|
198
|
+
> 实测(**khxty 工程,2026-08**):排除前 4008 个文件且 3 个嫌疑 jar 都在;排除后 4005 个文件 `(none - exclusion OK)`。
|
|
199
|
+
> 注:这个 **4008** 是该模块 `compileClasspath` 的**文件数**,与"`mservice-cosmic/lib` 目录下 jar 总数"(另一工作区 ymprj 实测 **4497**,见 SKILL.md R3.2)**口径不同、环境也不同**,两个数字不矛盾,比较时别混。
|
|
189
200
|
|
|
190
201
|
### 4.5 扫描注解处理器(PowerShell)
|
|
191
202
|
|
|
@@ -226,12 +237,18 @@ $gradle = "C:\Users\<user>\.gradle\wrapper\dists\gradle-7.6.3-bin\<hash>\gradle-
|
|
|
226
237
|
> `~/.gradle/wrapper/dists` 下最新」。本机同时存在 `gradle-8.8-bin`,它要求 Java 22
|
|
227
238
|
> 运行时,与本项目 JDK 8 + tools.jar 链路不兼容,会直接把构建带偏。
|
|
228
239
|
>
|
|
240
|
+
> ⚠️ **gradle.bat 可能只在两处之一**:系统 `$env:USERPROFILE\.gradle\wrapper\dists\` **或**
|
|
241
|
+
> 工作区 `<Gradle根>\.gradle\user-home\wrapper\dists\`(AGENTS.md 约定的 `GRADLE_USER_HOME`)。
|
|
242
|
+
> 上面示例只写了前者 —— **找不到就改搜后者**(两个都搜更稳,见 `cosmic-vibe-coding/SKILL.md` R2.2)。
|
|
243
|
+
>
|
|
229
244
|
> 🧩 完整流程(端口反查 PID / JDK 选择 / Gradle 定版 / 构建 / 注入)见
|
|
230
245
|
> `cosmic-vibe-coding/SKILL.md` 的**运行手册(R0–R5)**,其中已内置上述 JDK、Gradle 版本、
|
|
231
246
|
> PID 发现、account/tenant 读取逻辑,以及失败分支表(F1–F10)。
|
|
232
247
|
|
|
233
|
-
> ❌ 不要加 `--no-daemon`:每次 fork 单次 Daemon(JVM 冷启动 +
|
|
248
|
+
> ❌ 不要加 `--no-daemon`:每次 fork 单次 Daemon(JVM 冷启动 + 重新加载配置都要重付)
|
|
234
249
|
> ✅ 复用常驻 Daemon(`org.gradle.daemon=true` 默认开启),改几行代码约 5-10 秒
|
|
250
|
+
>
|
|
251
|
+
> ℹ️ **量级以本项目实测为准,别引用 "+30s"**:本项目数据表(§5.1)是 `--no-daemon` **42s** vs 常驻 **32s** → **Δ≈10s**;本文「误区层」的结论也是「Daemon 只占几秒,大头是全量编译本身」。另一工作区(ymprj)实测全新 daemon 冷启动仅 **3–5s**。早前此处写的 "+30s" 与本文自身数据不符,已修正。
|
|
235
252
|
|
|
236
253
|
### 4.8 全量扫描定位「Java 17+ 类」jar(推荐,避免打地鼠)
|
|
237
254
|
|
|
@@ -363,9 +380,10 @@ $jar = "<模块>\build\libs\<模块>-1.0.0.jar"
|
|
|
363
380
|
- Windows classpath 分隔符用 **`;`**(不是 `:`)
|
|
364
381
|
- 成功标志:退出码 0 + `SUCCESS: N jar(s) deployed & reloaded`
|
|
365
382
|
|
|
366
|
-
> ⚠️
|
|
367
|
-
>
|
|
368
|
-
>
|
|
383
|
+
> ⚠️ **权限:attach 需要"能打开目标进程句柄"的特权** —— 一眼判据是调用方令牌带不带 **`SeDebugPrivilege`**(`whoami /priv`)。
|
|
384
|
+
> 沙箱受限令牌 / 未提升 / UAC 过滤令牌,**都只是"缺这个特权"的不同成因**;缺了就在 `openProcess` 报 `拒绝访问`(见 §7.14)。
|
|
385
|
+
> 处置:**先放开沙箱(`danger-full-access`)原样重跑**;仍不行再提升 Attacher(⚠️ `EnableLUA=0` 时提升是空操作)。
|
|
386
|
+
> 注:目标进程与调用方**同用户同 IL**(自己起的 dev JVM)时不带该特权也能 attach —— cosmic 这种 **SYSTEM 属主**则必须有。
|
|
369
387
|
- 原理:`ExtJarApi.save(字节)` 写 `t_meta_ext_jar` 表 → `ExtJarApi.reset(accountId)` 重载 ExtClassLoader
|
|
370
388
|
- 不重启 cosmic、不碰 mc;jar 无需拷到 `lib/cus`
|
|
371
389
|
|
|
@@ -378,7 +396,7 @@ $jar = "<模块>\build\libs\<模块>-1.0.0.jar"
|
|
|
378
396
|
改完依赖务必用自定义任务打印真实 compileClasspath 验证
|
|
379
397
|
4. **改 build.gradle 后首次构建必全量**,属正常;之后才增量
|
|
380
398
|
5. **`Get-NetTCPConnection` 在非管理员权限下会误报"无监听"**,用 `Invoke-WebRequest` 探测兜底
|
|
381
|
-
6. **build 前确认 Daemon 活着**:`gradle --status` 应见 `IDLE` 条目;`--no-daemon`
|
|
399
|
+
6. **build 前确认 Daemon 活着**:`gradle --status` 应见 `IDLE` 条目;`--no-daemon` 会为每次构建重付 JVM 冷启动 + 配置(本项目实测 Δ≈10s;另一工作区全新 daemon 冷启动 3–5s —— **别引用"+30s"**,见 §4.7 注)
|
|
382
400
|
7. **识别全量重编**:改一行后 class 文件时间戳全变 = 全量;只有个别变 = 增量正常;
|
|
383
401
|
多次构建间隔短时用「最新时间戳 ±30s」窗口精确切分,避免混入前一次全量产物
|
|
384
402
|
8. **`dependencies --configuration compileClasspath` 对 fileTree 是惰性展开**,不一定显示 jar 明细,
|
|
@@ -387,28 +405,43 @@ $jar = "<模块>\build\libs\<模块>-1.0.0.jar"
|
|
|
387
405
|
(`F:\cosmic\xinghan8\jdk\bin\java ... -DappName=cosmic ... kd.bos.service.webserver.JettyServer`),
|
|
388
406
|
而 `jps` 只列举当前用户的 JVM → 输出里完全没有它,容易误判「cosmic 没启动」。
|
|
389
407
|
用 §6.1 方式零(按端口反查 OwningProcess)替代。
|
|
390
|
-
10.
|
|
391
|
-
|
|
392
|
-
|
|
408
|
+
10. **attach 到 cosmic(SYSTEM 属主)是*需要特权*的 —— 早期"跨用户 attach 无需提权"的结论已被证伪**(2026-09-24 判决性测试):
|
|
409
|
+
- **实际判据**:调用方令牌是否带 **`SeDebugPrivilege`**(它绕过目标进程 DACL)—— `whoami /priv` 一眼可判。
|
|
410
|
+
- **为什么以前看起来"无需提权"**:本机 `EnableLUA = 0`(UAC 关闭)→ Administrator 进程**恒为 High IL 且默认带该特权**,所以每次 attach 都成功 —— **并非因为"不需要特权"**。
|
|
411
|
+
- **在 UAC 启用的机器、或 DSH 受限沙箱(`workspace-write`)下,该特权缺失 → `openProcess` 报 `拒绝访问`**。
|
|
412
|
+
- 精确表述:**需要能打开目标进程句柄**(目标与调用方**异属主/异 IL** ⇒ 需 `SeDebugPrivilege`;同用户同 IL 则不需要)。
|
|
413
|
+
**判决实验**:`runas /trustlevel:0x20000` 摘掉特权后,**完整性级别未变(仍 High)却复现同一签名** ⇒ 与"跨 IL"无关,轴是特权。
|
|
393
414
|
11. **`-XX:+DisableAttachMechanism` 是硬阻断**:本机 IDEA 侧另一个 JVM(`CosmicStudio-runnable.jar`)
|
|
394
415
|
带此参数,对它 attach 必然失败;发现 PID 后先扫命令行里有没有这个 flag。
|
|
395
|
-
|
|
416
|
+
12. **`java_home` 以 IDEA 项目 SDK 为准**(Windows 常见 `C:\Program Files\java\jdk`),
|
|
396
417
|
不要误填 cosmic 自带 JDK 目录;Attacher 只需与 cosmic 同 JDK 大版本(同为 JDK8 即兼容)
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
- 现象:`[reloadjar] FAILED: java.io.IOException:
|
|
400
|
-
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
-
|
|
405
|
-
|
|
418
|
+
13. **gradle 构建命令不要加 `--no-daemon`**;多 IDLE Daemon 并存无害,`--stop` 可一次性清理
|
|
419
|
+
14. **attach 报 `拒绝访问`(`WindowsVirtualMachine.openProcess`)—— 判据是 `SeDebugPrivilege`,不是"先试着提权"**:
|
|
420
|
+
- 现象:`[reloadjar] FAILED: java.io.IOException: 拒绝访问`(Attacher 进程**已正常起来**,卡在打开目标进程句柄)
|
|
421
|
+
- **原因(单一机制)**:attach 到 cosmic(常为 **SYSTEM** 属主,与调用方**异属主**)需要**打开目标进程句柄**的特权,实际判据就是调用方令牌带不带 **`SeDebugPrivilege`**(它绕过目标 DACL)。
|
|
422
|
+
**沙箱受限令牌 / 未提升 / UAC 过滤令牌,都只是"缺这个特权"的不同成因** —— 不要再按"沙箱 vs elevated"拆成两个候选,它们不是并列原因。
|
|
423
|
+
> **🎯 判决性证据(2026-09-24 三点实验)**:① `danger-full-access`:令牌含 `SeDebugPrivilege` → **SUCCESS**;② **沙箱外**用 `runas /trustlevel:0x20000`(同用户、摘掉管理员):令牌只剩 `SeChangeNotifyPrivilege`、**完整性级别仍是 High(未变)** → **同一签名 `拒绝访问`**;③ DSH `workspace-write`:令牌同样只剩 `SeChangeNotifyPrivilege` → **同一签名**。
|
|
424
|
+
> ⇒ **轴是「令牌特权」,不是「完整性级别」**(②里 IL 未变仍被拒),**也不是沙箱独有**(②在沙箱外复现)。
|
|
425
|
+
- 🔍 **一眼可判的观测**:失败时在**同一个 shell** 跑 **`whoami /priv`** ——
|
|
426
|
+
**在** `SeDebugPrivilege` → 不是特权问题,往集合外查(attach socket 残留 / 目标 JVM 未就绪 / `DisableAttachMechanism`);
|
|
427
|
+
**不在** → 就是它:**放开沙箱(`danger-full-access`)或提升后原样重跑**。
|
|
428
|
+
- ⚠️ **`EnableLUA = 0` 的机器上"提升"是空操作**(Administrator 恒为 High IL、恒带该特权):既解释了历史上"不用提权也成功",也意味着此时**最常见的**缺特权来源是沙箱(`workspace-write`)——**但不止它**:显式降权启动(`runas /trustlevel:0x20000`,即判决实验②,**沙箱外**)同样会造成。
|
|
429
|
+
- ⚠️ **与 §0 的 `CreatePipe error=5` 不是同一个失败点**:那个发生在**起子进程**阶段(Gradle fork),本条发生在**打开句柄**阶段;同因(受限令牌)不同环节,签名与处置都不同。
|
|
430
|
+
- 提升处置(仅当 `whoami /priv` 无该特权且本机 UAC 启用):`Start-Process -Verb RunAs`,详见 `cosmic-jdwp-debug-config.md` §9.3。
|
|
431
|
+
- 🧪 **复现命令**(会话策略切到 `workspace-write` 后)。⚠️ 此时**运行手册会在 R0.4(端口反查)就失败**(`Get-NetTCPConnection` → `CimException: 拒绝访问`),走不到 R4,所以要**直接调 Attacher**:
|
|
432
|
+
```powershell
|
|
433
|
+
whoami /priv # 期望:只剩 SeChangeNotifyPrivilege(无 SeDebugPrivilege)
|
|
434
|
+
$jdk='<安装根>\jdk'; $agent=Join-Path $HOME '.dsh\cache\cosmic\agent\kd-reloadjar-agent-d8ca9d80.jar'
|
|
435
|
+
& "$jdk\bin\java.exe" -cp "$jdk\lib\tools.jar;$agent" kd.reloadjar.Attacher <PID> "$agent" "<jar>" <account_id> <tenant_id>
|
|
436
|
+
```
|
|
437
|
+
15. **重启 cosmic 的连带影响**:PID 变化 + `t_meta_ext_jar` 清空(热部署状态失效),
|
|
406
438
|
重启后需重新 build + 热部署;新 PID 用 wmic 查 `-DappName=cosmic` 的 JettyServer 进程确认
|
|
407
|
-
|
|
439
|
+
16. **新版 trd jar 会带 Java 21+ 类,排除清单按实际扫描定**:bcprov 1.82 / jackson-core 2.16.2 /
|
|
408
440
|
jsch 0.2.26 / ImpalaJDBC42 2.6.38 / hive-service 4.2.0 共 5 个 jar 含 major≥65 的类(见 4.8),
|
|
409
441
|
旧文档只排除 3 个 jar 的方案在新版本下不够——必须用 4.8 的全量扫描一次性定位
|
|
410
|
-
|
|
442
|
+
17. **排除 jar 后仍报旧类无法分析 = 增量快照缓存坑**:`build/tmp/compileJava/previous-compilation-data.bin`
|
|
411
443
|
复用旧 classpath 分析结果,`clean`(或重启 daemon)后重建基线即恢复增量(见 4.9)
|
|
412
|
-
|
|
413
|
-
`CreatePipe error=5
|
|
414
|
-
`danger-full-access`(`--no-daemon` 无效),**不是**本文的增量失效问题;放开后仍慢再按第 3/4
|
|
444
|
+
18. **先分清"跑不起来"还是"跑得慢"**:DSH 受限沙箱(workspace-write)下**构建**直接报
|
|
445
|
+
`CreatePipe error=5 拒绝访问`(**Gradle fork daemon** 被拦)是**权限问题**,须单命令级放开
|
|
446
|
+
`danger-full-access`(`--no-daemon` 无效),**不是**本文的增量失效问题;放开后仍慢再按第 3/4 节排查。
|
|
447
|
+
⚠️ **热部署 attach 不走这条**:它报的是 `openProcess` + Java 栈的 `拒绝访问`(见 §7.14),别混。
|