opencode-idea 0.0.17 → 0.0.19
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 +408 -183
- package/package.json +5 -1
- package/skills/idea-run-config-manager/SKILL.md +62 -0
- package/skills/idea-run-config-manager/assets/AGENTS.template.md +46 -0
- package/skills/idea-run-config-manager/assets/types/go-build.md +44 -0
- package/skills/idea-run-config-manager/assets/types/gradle.md +57 -0
- package/skills/idea-run-config-manager/assets/types/maven.md +61 -0
- package/skills/idea-run-config-manager/assets/types/node.md +30 -0
- package/skills/idea-run-config-manager/assets/types/npm.md +58 -0
- package/skills/idea-run-config-manager/assets/types/python.md +59 -0
- package/skills/idea-run-config-manager/assets/types/shell.md +77 -0
- package/skills/idea-standalone/SKILL.md +5 -3
- package/skills/idea-standalone/assets/AGENTS.template.md +18 -13
- package/src/ide-guidance.js +183 -38
- package/src/ide-guidance.template.md +131 -37
- package/src/ide-launcher.js +87 -27
- package/src/ide-projects.js +262 -0
- package/src/mcp/enhance.js +111 -29
- package/src/mcp/idea-tool-defaults.js +27 -12
- package/src/mcp/idea.js +9 -75
- package/src/plugin.js +726 -365
- package/src/skill/loader.js +43 -3
|
@@ -16,14 +16,14 @@
|
|
|
16
16
|
- **入口唯一(唯一绝对的约束)**:每个应用的启动入口就是 IDEA 的 run configuration,**不是手搓命令行**。
|
|
17
17
|
- **形态不限**:配置可以起本机进程,也可以是容器(Compose / K8s)、或部署到远端 —— 怎么起是配置的事,**不要假设它一定在本机直跑**。相应地,哪些应用**不在本机跑、或本机起不来**要单独写明(需要 GPU 的服务、本机直连的远端数据库、只能部署后验证的服务),别当成"本机直跑"来验证。
|
|
18
18
|
- **只启动其中一部分是常态** —— 不要求所有应用都起来,用户可能只开一两个。
|
|
19
|
-
- **跑应用只用
|
|
19
|
+
- **跑应用只用 `<前缀>_rerun_run_configuration`**:在跑就重启、没在跑就启动 —— 不必分辨"这是启动还是重启",直接 rerun 就完事。
|
|
20
20
|
常驻进程化 / 服务化的 run configuration 一律走这一条。
|
|
21
|
-
- **不要用 `
|
|
21
|
+
- **不要用 `<前缀>_execute_run_configuration` 跑这些应用**:它是给**命令 / Job 类型**的配置跑的,standalone 的配置是**常驻型**(起来就不退),
|
|
22
22
|
用它只会起出重复实例。
|
|
23
23
|
- **也不要绕过 IDEA**:不用 `go run` / `pnpm dev` / `uvicorn` / `python -m ...` 这类裸命令起进程,更不要 `kill` / `pkill` 业务进程 ——
|
|
24
24
|
外部杀掉的进程 IDE 并不知道(Run 窗口仍显示运行中,下次启动就撞端口)。
|
|
25
|
-
- **重启不必先问**:改完代码要重启哪个应用,直接 `
|
|
26
|
-
- 工具列表里没有 `
|
|
25
|
+
- **重启不必先问**:改完代码要重启哪个应用,直接 `<前缀>_rerun_run_configuration` —— 这条链是无人化的,先征求同意只会把重启卡住。
|
|
26
|
+
- 工具列表里没有 `<前缀>_rerun_run_configuration` 时(没装配套插件):交回用户,请他在 IDEA 里手动跑,AI 不动手。
|
|
27
27
|
- **与部署链纪律互不构成许可**:本段管的是 **standalone 跑应用的方式**,不适用于部署流程;反过来,部署链里的步骤也不构成"可以绕开本段、用裸命令在本机起应用"的许可 —— 两阶段纪律互相独立。
|
|
28
28
|
|
|
29
29
|
## 二、standalone 下启动哪些应用(必须经 IDEA run configuration)
|
|
@@ -33,24 +33,29 @@
|
|
|
33
33
|
一行一个应用,**按操作系统分成两张表**:macOS / Linux 一张,Windows 一张。同一份项目在不同平台上的启动方式往往不一样(解释器路径、脚本、
|
|
34
34
|
甚至该用哪个配置都不同 —— 比如某个配置的 `INTERPRETER_PATH` 指向 Windows PowerShell,在 macOS 上根本起不来),
|
|
35
35
|
所以**每张表里的 `run configuration` 必须是该平台上真正存在、真正能跑的那个名字**,不要把 Windows 上能用的配置写进 macOS 那张表。
|
|
36
|
-
某个应用在某平台上起不来,就在该表里注明(或干脆不列),别让 AI
|
|
37
|
-
|
|
38
|
-
`run configuration` 列**必须是 `
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
某个应用在某平台上起不来,就在该表里注明(或干脆不列),别让 AI 在一个平台上去跑另一个平台的配置。哪个平台用哪张表,不要自己猜。
|
|
37
|
+
|
|
38
|
+
`run configuration` 列**必须是 `<前缀>_get_run_configurations` 里真实存在的名字**,不凭印象写;缺配置就**交给用户**:
|
|
39
|
+
让他调 `idea-run-config-manager` skill 去建(那个 skill 管这个项目 run configuration 的增 / 删 / 改),不要手搓启动命令,也不要自己写 `.run/*.run.xml`。
|
|
40
|
+
**怎么跑**写走哪条工具:常驻 / 服务化的配置一律 `rerun`(在跑就重启、没在跑就启动),**不要**用 `execute` —— 它是 Run 路径,对常驻进程会起出重复实例;细节见「跑应用只用 rerun」那条。
|
|
41
|
+
**端口**写清"固定 / 默认 / 被占用即启动失败";读不到就**问用户**,不要编。**服务化的应用一定有端口**,这一格是它区别于固定流程的地方。
|
|
42
|
+
**何时跑**列写**什么时候起它**(日常开发 / 只在某个流程之前 / 联调时才起 …);多数应用留这一格就够,起不来就写清触发场景。
|
|
43
|
+
**跑前做**列写**跑之前要先做的事**:**多数应用留空**。只有确实"得先做点什么才能起"时才写,而且**按顺序写清第 1 步、第 2 步、第 3 步**(例如 `1. 装依赖 2. 构建 3. 起前置服务`);
|
|
41
44
|
这些事**用文字写出来**(AI 照这段文本自己按序去做)。这类前置事项往往没被写成 run configuration,所以必须在这里说明,否则 AI 直接 rerun 会拿到一个起不来的进程。
|
|
42
45
|
**哪个应用必须先起来**也要写明(例如前端 dev server 的 proxy 指向本机后端)。与本项目无关的应用不写。
|
|
46
|
+
**说明**写剩下的坑与依赖关系(依赖谁、跟别的应用什么先后)。**目录**这类配置里本来就有的字段不要单开一格 —— 会跟配置变旧而对不上。
|
|
47
|
+
**列宽按同一约定**(中文两字 = 四个 dash,英文按字符数),**两个块各自的 macOS / Linux 表、Windows 表,公共列一一对位、宽度一致**(谁 / `run configuration` / `怎么跑` / `何时跑` / `跑前做` / `说明`);**各自特有的列插在自己的语义位置上** —— 应用表多一格 `端口`,因为服务化应用一定有端口,`idea-run-config-manager` 的流程表没有这一格。两个块住在同一份 `AGENTS.md` 里,公共列对上了才看得出哪几行是服务、哪几行是固定流程。**某格不适用就留空,不要写 `-`;填行时别去改表头的空格。**
|
|
43
48
|
<!-- 生成提示:end -->
|
|
44
49
|
|
|
45
50
|
### macOS / Linux
|
|
46
51
|
|
|
47
|
-
| 应用 | run configuration |
|
|
48
|
-
| ---- | ----------------- |
|
|
52
|
+
| 应用 | run configuration | 怎么跑 | 端口 | 何时跑 | 跑前做 | 说明 |
|
|
53
|
+
| ---- | ----------------- | ------ | ---- | ------ | ------ | ---- |
|
|
49
54
|
|
|
50
55
|
### Windows
|
|
51
56
|
|
|
52
|
-
| 应用 | run configuration |
|
|
53
|
-
| ---- | ----------------- |
|
|
57
|
+
| 应用 | run configuration | 怎么跑 | 端口 | 何时跑 | 跑前做 | 说明 |
|
|
58
|
+
| ---- | ----------------- | ------ | ---- | ------ | ------ | ---- |
|
|
54
59
|
|
|
55
60
|
## 三、热重载矩阵:改代码后要不要提醒重启
|
|
56
61
|
|
package/src/ide-guidance.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// IDE MCP routing guidance injected into the model's system prompt.
|
|
2
2
|
//
|
|
3
3
|
// The TEXT lives in `ide-guidance.template.md`, not here. It is a prompt document
|
|
4
4
|
// a human has to review as a document — with the conditionals visible as
|
|
@@ -14,23 +14,52 @@
|
|
|
14
14
|
// 2. Only IDE-only capability is routed here; reading, writing and searching
|
|
15
15
|
// stay on the native tools.
|
|
16
16
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
17
|
+
// 校验 (lint / build) is one place that also carries a *when*, because the tools
|
|
18
|
+
// are not there to be offered — they are there to be used unprompted, and the
|
|
19
|
+
// model simply skips them (observed: it went and compiled by hand in `shell`
|
|
20
|
+
// instead, then reported success). The rule is a decision, not a mandate: batch
|
|
21
|
+
// edits → one `build_project` at the end, single-file fiddling → `lint_files`
|
|
22
|
+
// once when the round is over, never one check per keystroke and never zero
|
|
23
|
+
// checks. Spelling out both failure modes is the point — "always check" is as
|
|
24
|
+
// wrong as "never check", and only the model knows which round it is in.
|
|
25
|
+
//
|
|
26
|
+
// 符号 carries the same kind of *when*, for the same reason. In the observed
|
|
27
|
+
// session (a JetBrains plugin job on the IntelliJ Platform API) the model ran 398
|
|
28
|
+
// shells and mentioned `javap` 175 times in its own reasoning while mentioning
|
|
29
|
+
// `search_symbol` three times, two of which were after the user insisted. So the
|
|
30
|
+
// text now names the *situation* first ("you want to know how this class or
|
|
31
|
+
// method is implemented"), then bans the route it actually takes (`javap`,
|
|
32
|
+
// `unzip` on a hand-assembled jar path) with the reason that wins that argument:
|
|
33
|
+
// the IDE index holds the copy the project compiles against, and it hands back
|
|
34
|
+
// decompiled source instead of a bytecode listing.
|
|
35
|
+
//
|
|
36
|
+
// ## 一个会话,多个项目,多套前缀
|
|
37
|
+
//
|
|
38
|
+
// 每个接入的项目都用**自己的** MCP server 注册(root = `ide`,子项目 = 目录名),
|
|
39
|
+
// 所以同一个 IDE 工具会以 `ide_search_symbol` / `modelserver_search_symbol` 这样多份
|
|
40
|
+
// 出现。但**功能是同一套,只有前缀不同** —— 所以模板只写一遍功能说明,每条功能后面用
|
|
41
|
+
// `{{cmd_xxx}}` 列出它在各项目下的命令名(由 `commandVariables` 扫模板自动生成)。
|
|
42
|
+
//
|
|
43
|
+
// 这样模型同时拿到"这条功能是什么"和"这个项目里它叫什么",不需要自己拼前缀 —— 少一层
|
|
44
|
+
// 推理,就少一类"拿错项目工具"的失败;而且文本不会随项目数成倍增长。
|
|
21
45
|
//
|
|
22
46
|
// The `{{#if can…}}` blocks gate the companion plugin's tools (`mcp/enhance.js`),
|
|
23
47
|
// which only exist when the user installed it. Nothing in the document says so:
|
|
24
48
|
// which plugin a tool came from is this plugin's plumbing, not the model's
|
|
25
|
-
// business — it either sees the tool or it does not.
|
|
49
|
+
// business — it either sees the tool or it does not. The deployment section is
|
|
50
|
+
// gated on ONE of those flags (`canListDeploymentServers`) rather than on a flag of
|
|
51
|
+
// its own: the four tools are registered together, so one of them answers for the
|
|
52
|
+
// section — heading included, which is why the gate wraps the `###` line too.
|
|
26
53
|
|
|
27
54
|
import { readFileSync } from 'node:fs';
|
|
28
55
|
|
|
56
|
+
import { IDE_LABELS } from './ide-projects.js';
|
|
29
57
|
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
58
|
+
DEPLOYMENT_SUFFIXES,
|
|
59
|
+
RUN_LIFECYCLE_SUFFIXES,
|
|
60
|
+
deploymentCapabilities,
|
|
61
|
+
runLifecycleCapabilities,
|
|
62
|
+
servesTool,
|
|
34
63
|
} from './mcp/enhance.js';
|
|
35
64
|
import { renderTemplate } from './template.js';
|
|
36
65
|
|
|
@@ -41,28 +70,144 @@ const TEMPLATE_PATH = new URL('ide-guidance.template.md', import.meta.url);
|
|
|
41
70
|
const TEMPLATE = readFileSync(TEMPLATE_PATH, 'utf8');
|
|
42
71
|
|
|
43
72
|
/**
|
|
44
|
-
*
|
|
73
|
+
* 配套插件那两组工具的后缀全集 —— 判据只有一条:**这张表里的工具按项目分别存在**。
|
|
74
|
+
*
|
|
75
|
+
* 表外(内置 MCP Server 自带的那批)是每个项目都有的,列命令名时不需要看快照;表内的必须
|
|
76
|
+
* 逐项目核对(见 {@link commandVariables})。两组都收进来而不是只收部署那组:它们的
|
|
77
|
+
* 存在性本来就按项目、按 IDE 不同 —— 启停工具取决于装没装配套插件,部署工具还多一道
|
|
78
|
+
* "是不是 Ultimate"。把 run-lifecycle 留在表外,等于默认"一个项目装了、别的项目也装了",
|
|
79
|
+
* 而那只是个默认,不是事实。
|
|
80
|
+
*/
|
|
81
|
+
const ENHANCE_SUFFIXES = new Set([...RUN_LIFECYCLE_SUFFIXES, ...DEPLOYMENT_SUFFIXES]);
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 「本会话有哪些项目、各自用哪个 MCP 工具前缀」的清单。
|
|
85
|
+
*
|
|
86
|
+
* 放在公共段最前面,是因为模型**先要知道"该用哪个前缀"**,再去看具体工具。没有这张清单,它得从
|
|
87
|
+
* 每一节的标题里自己重建映射 —— 那是多一次推理,而推理错了的代价是"拿 root 的工具去操作
|
|
88
|
+
* 子项目",恰恰是这套多前缀设计要防的事。
|
|
89
|
+
*
|
|
90
|
+
* 明确写出"根项目 / 子项目"这个层级词:前缀本身(root `ide` vs 子项目目录名)不足以让模型一眼
|
|
91
|
+
* 看出谁是谁,而它的判断依据是"这个文件在哪个目录下"。
|
|
92
|
+
*
|
|
93
|
+
* @param {ReadonlyArray<{ label: string, path: string, app: string, server: string, isRoot: boolean }>} projects
|
|
94
|
+
*/
|
|
95
|
+
function routeTableFor(projects) {
|
|
96
|
+
const hasChildren = projects.some((project) => !project.isRoot);
|
|
97
|
+
return projects
|
|
98
|
+
.map((project) => {
|
|
99
|
+
const kind = project.isRoot ? '根项目' : '子项目';
|
|
100
|
+
const ide = IDE_LABELS[project.app] ?? project.app;
|
|
101
|
+
// 根项目的那一行必须写明"不含下列子项目" —— 子项目就在它的目录树里,不写清楚,
|
|
102
|
+
// "modelserver 的文件算根项目还是子项目"就成了模型要自己猜的问题。
|
|
103
|
+
const scope = project.isRoot && hasChildren ? ',**不含下列子项目**' : '';
|
|
104
|
+
return `- **${kind}** \`${project.label}\`(${ide} 打开)→ MCP 工具前缀 \`${project.server}_*\`,项目路径 \`${project.path}\`${scope}`;
|
|
105
|
+
})
|
|
106
|
+
.join('\n');
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 每条功能在各项目下的命令名,预渲染成一行。
|
|
111
|
+
*
|
|
112
|
+
* 变量名**直接扫模板得到**:模板里写 `{{cmd_search_symbol}}`,这里就填
|
|
113
|
+
* `` `根项目 ide_search_symbol` | `modelserver modelserver_search_symbol` ``。
|
|
114
|
+
* 所以模板增删一条工具不需要动这里的代码,也不会出现"模板里写了、代码忘了给值"的空行。
|
|
115
|
+
*
|
|
116
|
+
* **配套插件那条线要逐项目过滤**(见 {@link ENHANCE_SUFFIXES}):内置工具每个项目都有,列全即可;
|
|
117
|
+
* 而 `idea-mcp-enhance` 的工具是**按项目分别存在**的(装了插件的那个 IDE 有,另一个可能没有;
|
|
118
|
+
* 部署那组还要求 Ultimate)。它常常同进同出,但"通常"不是"总是" —— 一旦不一致,列全就会在
|
|
119
|
+
* 缺工具的那个项目下点名一个模型调不到的命令,而那正是这整个模块要防的失败。
|
|
120
|
+
* 过滤不会产生空行:每条 bullet 的 `{{#if}}` 用的是**并集**判断(任一项目有即渲染),
|
|
121
|
+
* 并集为真 ⇒ 至少一个项目通过过滤。
|
|
122
|
+
*
|
|
123
|
+
* @param {ReadonlyArray<{ label: string, server: string, isRoot: boolean }>} projects
|
|
124
|
+
* @param {Record<string, unknown> | undefined} tools 本次请求的工具快照
|
|
125
|
+
*/
|
|
126
|
+
function commandVariables(projects, tools) {
|
|
127
|
+
/** @type {Record<string, string>} */
|
|
128
|
+
const variables = {};
|
|
129
|
+
for (const match of TEMPLATE.matchAll(/\{\{\s*(cmd_[A-Za-z0-9_]+)\s*\}\}/g)) {
|
|
130
|
+
const name = match[1];
|
|
131
|
+
const suffix = name.slice('cmd_'.length);
|
|
132
|
+
variables[name] = projects
|
|
133
|
+
.filter((project) => !ENHANCE_SUFFIXES.has(suffix) || servesTool(tools, `${project.server}_`, suffix))
|
|
134
|
+
// 每条都写清"哪个项目 → 哪个命令":根项目直接用它的角色名,子项目用目录名。
|
|
135
|
+
// 不写 `.`/目录名这种需要回看清单才能解读的代号 —— 模型读每条功能时不必回头查表。
|
|
136
|
+
.map((project) => `${project.isRoot ? '根项目' : project.label} \`${project.server}_${suffix}\``)
|
|
137
|
+
.join(' | ');
|
|
138
|
+
}
|
|
139
|
+
return variables;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 本会话里这些 run-lifecycle 能力可不可用。
|
|
144
|
+
*
|
|
145
|
+
* 提示词只有一份,所以这里要回答的是"这套能力在本次会话里存不存在" —— 任一项目提供即算存在。
|
|
146
|
+
* 同一个人的几个 IDE 装不装配套插件通常是一致的;万一不一致,模板里那句"没装就交给用户"兜住。
|
|
147
|
+
*
|
|
148
|
+
* @param {ReadonlyArray<{ server: string }>} projects
|
|
149
|
+
* @param {Record<string, unknown> | undefined} tools
|
|
150
|
+
*/
|
|
151
|
+
function mergeRunLifecycle(projects, tools) {
|
|
152
|
+
const all = projects.map((project) => runLifecycleCapabilities(tools, `${project.server}_`));
|
|
153
|
+
return {
|
|
154
|
+
canCreateRunConfiguration: all.some((c) => c.canCreateRunConfiguration),
|
|
155
|
+
canListRunningConfigurations: all.some((c) => c.canListRunningConfigurations),
|
|
156
|
+
canStopRunConfiguration: all.some((c) => c.canStopRunConfiguration),
|
|
157
|
+
canRerunRunConfiguration: all.some((c) => c.canRerunRunConfiguration),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 部署工具同理(见 `mergeRunLifecycle`):逐项目判断,任一项目提供即算存在。
|
|
163
|
+
*
|
|
164
|
+
* **整节的锚点就是 `canListDeploymentServers`**(模板里 `{{#if canListDeploymentServers}}` 直接包住标题):
|
|
165
|
+
* 配套插件只要装了,IDE 的 MCP 工具表里就多出这一组(它们由同一道前提注册,同进同出),
|
|
166
|
+
* 所以拿其中一个当判据就够了 —— 不需要再造一个"四个里任一个"的聚合标志。
|
|
167
|
+
*
|
|
168
|
+
* 不锚在那些"必须有工具才算"的地方也不成问题:一个都没有时 `canListDeploymentServers` 为 false,
|
|
169
|
+
* 标题与正文一起消失;而这一节和前一组不同 —— run-lifecycle 那节是内置工具
|
|
170
|
+
* (`get_run_configurations` / `execute_run_configuration`)撑起来的**自己的**标题,缺配套插件时标题仍在。
|
|
171
|
+
* 顺带一提,这一组还额外要求 `com.jetbrains.plugins.webDeployment`(**仅 Ultimate 有**),所以
|
|
172
|
+
* "整节不出现"是常态而非边角。
|
|
173
|
+
*
|
|
174
|
+
* @param {ReadonlyArray<{ server: string }>} projects
|
|
175
|
+
* @param {Record<string, unknown> | undefined} tools
|
|
176
|
+
*/
|
|
177
|
+
function mergeDeployment(projects, tools) {
|
|
178
|
+
const all = projects.map((project) => deploymentCapabilities(tools, `${project.server}_`));
|
|
179
|
+
return {
|
|
180
|
+
canListDeploymentServers: all.some((c) => c.canListDeploymentServers),
|
|
181
|
+
canUploadToDeployment: all.some((c) => c.canUploadToDeployment),
|
|
182
|
+
canDownloadFromDeployment: all.some((c) => c.canDownloadFromDeployment),
|
|
183
|
+
canGetDeploymentTaskStatus: all.some((c) => c.canGetDeploymentTaskStatus),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* 把本会话接入的全部项目渲染成**一份**引导文本。
|
|
189
|
+
*
|
|
190
|
+
* 只渲染一次,不按项目重复:功能说明与项目无关,只有命令名带项目前缀 —— 所以每条功能后面直接
|
|
191
|
+
* 列出各项目的命令名(`cmd_*` 变量),而不是把整份工具清单按前缀抄 N 遍。
|
|
45
192
|
*
|
|
46
|
-
* @param {string}
|
|
47
|
-
* @param {{
|
|
48
|
-
*
|
|
49
|
-
* omit for a stock IDE.
|
|
193
|
+
* @param {ReadonlyArray<{ path: string, server: string, app: string, label: string, isRoot: boolean }>} projects
|
|
194
|
+
* @param {{ tools?: Record<string, unknown> }} [options] `tools` 是本次请求的工具快照
|
|
195
|
+
* (`event.tools`),用来判断配套插件(run-lifecycle / deployment)的工具在不在。
|
|
50
196
|
* @returns {string}
|
|
51
197
|
*/
|
|
52
|
-
export function
|
|
53
|
-
const present = options.runLifecycleTools ?? [];
|
|
198
|
+
export function buildIdeGuidanceText(projects, options = {}) {
|
|
54
199
|
return renderTemplate(TEMPLATE, {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
200
|
+
projectCount: projects.length,
|
|
201
|
+
routeTable: routeTableFor(projects),
|
|
202
|
+
...mergeRunLifecycle(projects, options.tools),
|
|
203
|
+
...mergeDeployment(projects, options.tools),
|
|
204
|
+
...commandVariables(projects, options.tools),
|
|
60
205
|
});
|
|
61
206
|
}
|
|
62
207
|
|
|
63
208
|
export const MCP_RECOVERY_GUIDANCE = [
|
|
64
|
-
'###
|
|
65
|
-
'If an
|
|
209
|
+
'### IDE MCP failure recovery',
|
|
210
|
+
'If an IDE MCP tool (the `<prefix>_*` ones) is missing, MCP is disconnected, the connection is refused, or a tool times out: stop retrying immediately; do not run extra probes or wait in tool calls. Tell the user that IDE MCP is unavailable and ask them to run /open-in-ide to reconnect.',
|
|
66
211
|
].join('\n');
|
|
67
212
|
|
|
68
213
|
/**
|
|
@@ -71,12 +216,12 @@ export const MCP_RECOVERY_GUIDANCE = [
|
|
|
71
216
|
* single connection error is all it saw — the reconnect is already happening.
|
|
72
217
|
*/
|
|
73
218
|
export const MCP_RECOVERY_GUIDANCE_MARKED = [
|
|
74
|
-
'###
|
|
75
|
-
'This project is
|
|
219
|
+
'### IDE MCP failure recovery',
|
|
220
|
+
'This project is IDE-connected and the plugin reconnects the IDE MCP automatically. When an IDE MCP call fails with a connection error (for example `MCP server "ide" is not available`), do not run extra probes or wait in tool calls: the reconnect is already under way, so retry the operation once. Only if it still fails, tell the user that IDE MCP is unavailable and to run /open-in-ide.',
|
|
76
221
|
].join('\n');
|
|
77
222
|
|
|
78
223
|
/**
|
|
79
|
-
* Recovery instruction for a marked project whose
|
|
224
|
+
* Recovery instruction for a marked project whose IDE tools are NOT in this
|
|
80
225
|
* request's tool list. The connection dropped and the plugin is already
|
|
81
226
|
* reconnecting, but the reconnect only lands on a LATER request — so within this
|
|
82
227
|
* one a call can only fail with `No tool named "..." is currently available`.
|
|
@@ -84,26 +229,26 @@ export const MCP_RECOVERY_GUIDANCE_MARKED = [
|
|
|
84
229
|
* exactly that doomed call.
|
|
85
230
|
*/
|
|
86
231
|
export const MCP_RECOVERY_GUIDANCE_RECONNECTING = [
|
|
87
|
-
'###
|
|
88
|
-
'No
|
|
232
|
+
'### IDE MCP failure recovery',
|
|
233
|
+
'No IDE MCP tool (the `<prefix>_*` ones) is in this request: the IDE connection dropped and the plugin is reconnecting in the background. Do NOT call any of them now — it will fail with `No tool named "..." is currently available` — and do not go looking for them through Code Mode either: they are only ever listed as native tools, so a search finds nothing. Do not fall back to shell/read/write for in-project work. Continue with what you can, or tell the user the IDE is reconnecting; if the tools are still missing on a later message, ask the user to run /open-in-ide.',
|
|
89
234
|
].join('\n');
|
|
90
235
|
|
|
91
236
|
/**
|
|
92
237
|
* Push the guidance onto a session `system` array. Called for every primary
|
|
93
238
|
* model request, so it stays idempotent per request.
|
|
94
239
|
*
|
|
95
|
-
* The text depends on which
|
|
96
|
-
* idempotence check compares the built text rather
|
|
240
|
+
* The text depends on which projects are connected and which run-lifecycle tools
|
|
241
|
+
* this request carries, so the idempotence check compares the built text rather
|
|
242
|
+
* than assuming one variant.
|
|
97
243
|
*
|
|
98
244
|
* @param {unknown} system
|
|
99
|
-
* @param {string}
|
|
100
|
-
* @param {{
|
|
101
|
-
* tools present in this request's tool snapshot.
|
|
245
|
+
* @param {ReadonlyArray<{ path: string, server: string, app: string, label: string, isRoot: boolean }>} projects
|
|
246
|
+
* @param {{ tools?: Record<string, unknown> }} [options]
|
|
102
247
|
*/
|
|
103
|
-
export function appendIdeGuidance(system,
|
|
248
|
+
export function appendIdeGuidance(system, projects, options = {}) {
|
|
104
249
|
if (!Array.isArray(system)) return;
|
|
105
|
-
if (!
|
|
106
|
-
const text =
|
|
250
|
+
if (!Array.isArray(projects) || projects.length === 0) return;
|
|
251
|
+
const text = buildIdeGuidanceText(projects, options);
|
|
107
252
|
if (system.some((part) => part?.text === text)) return;
|
|
108
253
|
system.push({ type: 'text', text });
|
|
109
254
|
}
|
|
@@ -112,7 +257,7 @@ export function appendIdeGuidance(system, projectPath, options = {}) {
|
|
|
112
257
|
* @param {unknown} system
|
|
113
258
|
* @param {{ marked?: boolean, serving?: boolean }} [options] `marked` picks the
|
|
114
259
|
* auto-reconnect variant; `serving: false` additionally picks the variant for
|
|
115
|
-
* a request that has no
|
|
260
|
+
* a request that has no IDE tools at all, where a call can only fail.
|
|
116
261
|
*/
|
|
117
262
|
export function appendIdeRecoveryGuidance(system, { marked = false, serving = true } = {}) {
|
|
118
263
|
if (!Array.isArray(system)) return;
|
|
@@ -1,71 +1,165 @@
|
|
|
1
|
-
#
|
|
1
|
+
# IDE MCP:只有非 IDE 不可的能力才走 IDE
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本会话接入了 {{projectCount}} 个 JetBrains 项目。**每个功能在所有项目下都各有一份工具**,命令名就是
|
|
4
|
+
`<项目前缀>_<工具名>`;下面每条功能后面直接列出它在各项目里的命令名。
|
|
4
5
|
|
|
5
|
-
##
|
|
6
|
+
## 本会话接入的项目与各自的 MCP 工具
|
|
7
|
+
|
|
8
|
+
{{routeTable}}
|
|
9
|
+
|
|
10
|
+
**子项目就是根目录下的目录**,只是被另一个 IDE 单独打开、配了另一套工具。所以这里说的"根项目",指的是
|
|
11
|
+
**根目录中扣掉这些子项目之后的部分** —— 操作某个子项目里的文件,就用那个子项目的命令,不要因为它"在根目录下"
|
|
12
|
+
就用根项目的工具。
|
|
13
|
+
|
|
14
|
+
**规则:操作哪个目录下的文件/代码,就用那个目录对应的命令。** IDE 是按项目解析的 —— 跨项目调用要么直接报错,
|
|
15
|
+
要么被解析到另一个项目上、作用在错误的代码上。
|
|
16
|
+
|
|
17
|
+
按需读文件:要了解某个子项目自己的约定,读它的 `<子项目目录>/AGENTS.md`(它不会自动进入本会话的上下文,
|
|
18
|
+
本会话是 root 打开的那一个)。
|
|
19
|
+
|
|
20
|
+
## 总则(所有项目通用)
|
|
6
21
|
|
|
7
22
|
- 原生工具(当前工具列表里直接列出的那些)**直接调用**;不需要、也不应该用 Code Mode 的 `search` 去找。
|
|
8
|
-
-
|
|
9
|
-
- **只有 IDE
|
|
10
|
-
- **读写与搜索用原生工具**(`read` / `write` / `edit` / `grep` / `glob`):不要为读一个文件、写一个文件、搜一段文本去绕
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
23
|
+
- 下面这些 IDE 工具也是原生工具:直接调用(参数按各工具 schema 传),不要包进 `execute`;它们不在 Code Mode 的工具目录里,`search` 搜不到。
|
|
24
|
+
- **只有 IDE 才有的能力才用它们**:符号级检索、项目模型、检查与构建、重构与格式化、run configuration。
|
|
25
|
+
- **读写与搜索用原生工具**(`read` / `write` / `edit` / `grep` / `glob`):不要为读一个文件、写一个文件、搜一段文本去绕 IDE 工具。
|
|
26
|
+
- **改完代码自己先查一遍**(`lint_files` / `build_project`,怎么挑见下面「校验」):什么时候查、查几次由你判断,但**别把校验整段省掉** —— 自己查一次,远比让用户替你发现或留到构建 / 测试炸了才暴露要便宜。
|
|
27
|
+
- **要看某个类 / 方法 / 字段在哪定义、内部怎么实现的**(见下面「符号」):`<P>_search_symbol`(`include_external: true`)找到位置 → `<P>_read_file` 原样读它给的路径。
|
|
28
|
+
- 某条功能下面没有你正要操作的那个项目的命令,就是那个项目没接上:提示用户执行 `/open-in-ide`,不要重试,也不要去别处找。
|
|
14
29
|
|
|
15
|
-
##
|
|
30
|
+
## 工具(每条第一行是各项目的命令,接着是它的用法)
|
|
16
31
|
|
|
17
32
|
### 符号(只有 IDE 的语义索引能给)
|
|
18
33
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
34
|
+
**要读任何类 / 方法 / 字段的源码,就两步**:`<P>_search_symbol`(`q` 传名字,**带 `include_external: true`**)找到位置 → `<P>_read_file` 原样读它给的路径。**依赖库 / 三方包 / 平台 jar 里的实现,正是它最该用的场合**,也是 `javap` / `unzip` / 解包 jar / 按 jar 路径 `grep` 唯一的正解:**IDE 索引里那份就是项目编译时真正用的依赖**(自己拼的 jar 路径常常是另一份副本,版本对不上),读出来还是反编译源码 —— 字节码清单要来回十几次才能拼出逻辑,这边一次到位。
|
|
35
|
+
|
|
36
|
+
- {{cmd_search_symbol}}
|
|
37
|
+
**`q` 传查询文本,固定带上 `include_external: true`。** 本插件最不可替代的能力 —— 它搜的是**符号**(类 / 接口 / 方法 / 函数 / 字段 / 类型 / 常量这类**有名字的定义**)的**声明位置**,不是"哪段文本提到过它"(那是 `grep` 的事);带上 `include_external` 才会连**依赖库和标准库**一起搜,于是你能直接定位第三方库里的实现 —— 这是原生 `grep` / `glob` 够不着的地方(IDE 自己的 `search_text` / `search_file` 也只搜项目内)。
|
|
38
|
+
- **典型用法 ①:代码里引用了某个库的 API(最常见)** —— 读代码时看到 `from fastapi import FastAPI`、`import org.apache.poi...FormulaParser`、`gorm.DeletedAt`、`from 'vue'` 这类引用时,**包名就在代码里**,直接**用「包名+符号名」当 `q` 搜**,一次定位到它的实现:
|
|
39
|
+
- **Java**:全限定名 —— `com.nimbusds.jose.util.Base64`(实测 1 条命中 `~/.m2/.../poi-5.3.0-sources.jar!/...`)
|
|
40
|
+
- **Go**:包名.符号 —— `gorm.DeletedAt`(实测 2 条,全在 `go/pkg/mod/gorm.io/gorm@...`)
|
|
41
|
+
- **Python**:模块路径给得越全越准 —— `torch.nn.modules.module.Module`(目标全在最前);`torch.nn.Module` 也能把目标排进前 2
|
|
42
|
+
- **Node/TS**:用 **import 的那层包名**(不是子模块路径)—— `vue.Teleport` 有效,`@vue/runtime-core.TeleportProps` 搜不到
|
|
43
|
+
- **典型用法 ②:调研一个库有哪些 API** —— 包名从依赖清单里拿(pom.xml / package.json / go.mod / requirements.txt),**直接拿包名当 `q` 搜**,结果基本就落在这个库里,再读入口:
|
|
44
|
+
- **Python**:`fastapi` → `fastapi/applications.py`、`fastapi/__init__.py`(**入口就是导出清单**:直接看到 `FastAPI`、`HTTPException` 这些公开名字)
|
|
45
|
+
- **Java**:`poi` → `~/.m2/.../poi-5.3.0-sources.jar!/org/apache/poi/...`;读该库的入口类
|
|
46
|
+
- **Go**:`gorm` → `go/pkg/mod/gorm.io/gorm@v1.31.0/...`
|
|
47
|
+
- **Node/TS 例外**:包名当 `q` 搜不到(实测 `element-plus` → 0 条)。要用**代码里 import 的符号名**;包名是简单标识符时可以「包名.符号」(`vue.Teleport` 有效),但**带 `-` 或 `@scope/` 的这么拼是 0 条**(`element-plus.ElMessage`、`@vue/runtime-core.TeleportProps` 都搜不到)。而裸符号名会跨多个子项目(`ElMessage` 命中 user / admin / vcop 三处),这时用 `paths` 圈到那个 `node_modules` —— `paths: ['frontend/user/**']` 就收敛到一处。
|
|
48
|
+
- **它只覆盖「项目已经引入」的依赖**:搜不到某个库,基本就是这个库还没进依赖 —— 别反复试:要么先把它加进依赖(pom / requirements / package.json),要么改用 web 搜索 / GitHub 看它的源码。
|
|
49
|
+
- **同名符号往往有多处定义**(标准库一份、几个依赖各一份,还有测试和示例),所以**按代码上下文选**:看调用处 import 的是哪个包、传参是什么类型、返回路径属于哪个库 —— 别把第一行当答案。
|
|
50
|
+
- **它返回的路径,原样交给同一个项目的 `<P>_read_file` 就是源码**:两者同属一个项目、相对路径的基准一致,所以不用拼绝对路径、不用管是什么语言 —— 压缩包里的条目它也照样读(`.class` 还会反编译)。
|
|
51
|
+
例:`<P>_search_symbol({ q: "UvicornWorker", include_external: true })` 给出 `../../../Library/.../uvicorn/workers.py` → `<P>_read_file({ file_path: "那个字符串" })`。
|
|
52
|
+
- **依赖索引是按项目的**:任何依赖都用**它所在项目**的那个 MCP 工具去搜 —— 根项目的依赖用根项目的命令,子项目的依赖用子项目的命令。拿一个项目的工具去搜另一个项目的依赖,只会在那个项目自己的文件里找,**拿不到库**。
|
|
53
|
+
- **别把这条路径交给原生 `read`**:原生 read 的基准是本会话的工作目录(根项目),拿子项目的相对路径去读会落到错误的位置。
|
|
54
|
+
- {{cmd_get_symbol_info}}
|
|
55
|
+
**一个符号的签名 / 文档 / 声明位置**:`filePath` + `line` + `column`。
|
|
56
|
+
- {{cmd_analyze_calls}}
|
|
57
|
+
**调用关系**:`symbolFqn` 传符号名,`analysisKind` 取 `INCOMING_CALLS` / `OUTGOING_CALLS`;`depth` 控层数,`childOffset` 翻页。
|
|
22
58
|
|
|
23
59
|
### 项目与编辑器
|
|
24
60
|
|
|
25
|
-
-
|
|
26
|
-
|
|
27
|
-
-
|
|
28
|
-
|
|
29
|
-
-
|
|
61
|
+
- {{cmd_list_directory_tree}}
|
|
62
|
+
**项目视角的目录树**(尊重内容根与排除项):`maxDepth` 控深度。
|
|
63
|
+
- {{cmd_get_project_modules}}
|
|
64
|
+
**项目模块及类型**。
|
|
65
|
+
- {{cmd_get_project_dependencies}}
|
|
66
|
+
**项目直接声明的依赖**。
|
|
67
|
+
- {{cmd_get_all_open_file_paths}}
|
|
68
|
+
**用户在 IDE 里打开了哪些文件**(含当前激活的那个)。
|
|
69
|
+
- {{cmd_open_file_in_editor}}
|
|
70
|
+
**把文件在 IDE 里打开并激活**,给用户看。
|
|
30
71
|
|
|
31
72
|
### 重构与格式化
|
|
32
73
|
|
|
33
|
-
-
|
|
34
|
-
|
|
74
|
+
- {{cmd_rename_refactoring}}
|
|
75
|
+
**按符号改名**,项目内的引用一并更新。
|
|
76
|
+
- {{cmd_reformat_file}}
|
|
77
|
+
**按 IDE 的代码风格重排**。
|
|
35
78
|
|
|
36
79
|
### 校验
|
|
37
80
|
|
|
38
|
-
-
|
|
39
|
-
|
|
40
|
-
-
|
|
81
|
+
- {{cmd_lint_files}}
|
|
82
|
+
**批量检查**:`files` 传数组;只列有问题的文件。
|
|
83
|
+
- {{cmd_get_file_problems}}
|
|
84
|
+
**单文件检查**:`filePath`;结果在 `errors`。
|
|
85
|
+
- {{cmd_build_project}}
|
|
86
|
+
**构建校验**:`filesToRebuild` 可只构建指定文件;有问题返回在 `problems`,没返回即没问题。
|
|
87
|
+
|
|
88
|
+
**改完代码,自己先查一遍再收尾。** 这不是流程要求,是你自己的判断 —— 查一次很便宜,而问题一旦漏到用户
|
|
89
|
+
看见、或留到构建 / 测试炸了才暴露,回头纠正的代价就高一个量级了。
|
|
90
|
+
|
|
91
|
+
- **这次要改一大片**(多文件、跨模块、"顺手把这几处一起对齐")→ 全部改完再 `build_project` 一次。中途不查:
|
|
92
|
+
半成品状态下的检查结果只会误导你。
|
|
93
|
+
- **这次只改一处,或在同一个文件上反复微调** → 告一段落时,把这轮改过的文件一次 `lint_files` 掉;要看单个
|
|
94
|
+
文件的细节再上 `get_file_problems`。
|
|
95
|
+
- **改了签名 / 接口 / import / 依赖**这类"别处会跟着坏"的地方 → 走 `build_project`;只动了文件内部的实现 →
|
|
96
|
+
lint 就够。
|
|
97
|
+
- 查出来的问题**改掉,或说清为什么不改**,别把没处理的问题原样交给用户。
|
|
98
|
+
- 校验走上面这些工具,**不要改用 `shell` 里临时自己编一遍代替**。
|
|
99
|
+
- 也别先猜"索引还没同步 / 那个环境是另一个进程"就绕开 —— 先调一次,它真看不到会明说。
|
|
100
|
+
|
|
101
|
+
### 读压缩包内的东西
|
|
102
|
+
|
|
103
|
+
- {{cmd_read_file}}
|
|
104
|
+
**压缩包内的条目**(路径形如 `libs/foo.jar!/com/x/Bar.class` 或 `jar://` URL)只有它能读 —— 原生 `read` 打不开压缩包,而它还能把 `.class` **反编译成源码**;「符号」那条搜出来的路径也用它(原样传即可)。
|
|
41
105
|
|
|
42
106
|
### 运行配置
|
|
43
107
|
|
|
44
|
-
-
|
|
45
|
-
|
|
108
|
+
- {{cmd_get_run_configurations}}
|
|
109
|
+
**项目里有哪些运行配置**:传 `filePath` 可列该文件的运行入口。**不要翻 `.run/` 目录** —— 存在 `.idea/` 里的那些看不到。
|
|
110
|
+
- {{cmd_execute_run_configuration}}
|
|
111
|
+
**跑已有配置**:Shell Script 要 `EXECUTE_IN_TERMINAL: false`;覆盖参数(`programArguments` / `workingDirectory` / `envs`)需配置支持 `supportsDynamicLaunchOverrides`。
|
|
46
112
|
{{#if canCreateRunConfiguration}}
|
|
47
|
-
-
|
|
113
|
+
- {{cmd_create_shell_run_configuration}}
|
|
114
|
+
**新建项目级 Shell 配置**(`configurationName` + `scriptPath` / `scriptText` / `cloneFrom` 三选一;写 `.run/<name>.run.xml`):只支持 Shell 类型。它是**项目资产**,不是"跑命令"的手段 —— 只是要跑一条命令就用原生 `shell`。判据只有一条:**这件事以后会不会以同样的形态再发生?**
|
|
115
|
+
- **这里只是"建"的一个入口,不是全部**:非 Shell 类型,以及**删 / 改**,都走 `idea-run-config-manager` skill —— 让用户调它(它有逐类型模板;没有模板的类型,它会让用户在 IDE 里配)。
|
|
116
|
+
- **会 → 该建,而且你要主动提**。典型信号:用户让你做的是**重复性动作**,还会对别的环境 / 别的分支 / 下一次改表再做一遍 —— 例如改完表结构要**同步某个环境的 DDL**、跑数据库迁移或回滚、生成代码、打包、起 dev server、往某个环境部署、按固定步骤清洗数据。这时**别默默每次手搓命令**(下次还得从头猜一遍),也**别自己动手建**:**先问用户**"这个流程以后要反复跑,要不要固化成一个 Shell run configuration?",并把方案摊开:配置名、实际执行的命令(`scriptText`,或它指向的 `scriptPath`)、工作目录、为什么值得留。**同意才建**;用户说这次先这样,就照办,别再追着问。
|
|
117
|
+
- **不会 → 用原生 `shell` 直接跑,别建**。这就是两者的分界线:原生 `shell` 是**就地执行、用完不留痕**(命令只存在于会话里);`create_shell_run_configuration` 是**把命令落盘成 `.run/<name>.run.xml`、往后反复用**(它产出的是项目文件,IDE 的 Run 窗口里也会多一项)。所以一次性的、探索性的、调试性的、参数每次都不一样的操作(查条数据、看个日志、试一条命令、临时换个路径跑一下)一律走 `shell` 跑完算 —— 这类东西建配置只是给项目留垃圾。确需项目环境的解释器时,在 `shell` 命令里显式指定、或在已有配置上单次覆盖参数,也别为这一次性的事新建配置。
|
|
118
|
+
- **建之前先查,防泛滥**:先 `get_run_configurations` 看有没有已在做同一件事的配置 —— 有就**复用**(必要时让用户改它),别新建一个几乎一样的;同一件事**不要按参数 / 按文件 / 按环境拆成一堆配置**,变化的入参用 `programArguments` / `envs` 单次覆盖。一个项目通常就那么**几个**(构建、装依赖、起服务、迁移这类固定流程);配置数量明显长起来就是滥用信号 —— 动手前先问自己:这是项目固定流程,还是我只是想省一条 shell 命令?
|
|
48
119
|
{{/if}}
|
|
49
120
|
{{#if canListRunningConfigurations}}
|
|
50
|
-
-
|
|
121
|
+
- {{cmd_list_running_configurations}}
|
|
122
|
+
**当前真正在跑的配置**(几个实例 / 各自 pid / 退出码):停 / 重启前后都先用它看状态。
|
|
51
123
|
{{/if}}
|
|
52
124
|
{{#if canStopRunConfiguration}}
|
|
53
|
-
-
|
|
125
|
+
- {{cmd_stop_run_configuration}}
|
|
126
|
+
**停掉该配置的全部实例并等它们退出**:没在跑也返回成功。
|
|
54
127
|
{{/if}}
|
|
55
128
|
{{#if canRerunRunConfiguration}}
|
|
56
|
-
-
|
|
129
|
+
- {{cmd_rerun_run_configuration}}
|
|
130
|
+
**改完代码重启无热重载的进程**:在跑就重启、没在跑就启动;读 `started` 判断新进程是否真的起来了。不要用 `pkill` / `kill` / `shell` 代替。
|
|
131
|
+
{{/if}}
|
|
132
|
+
{{#if canListDeploymentServers}}
|
|
133
|
+
|
|
134
|
+
### 服务器文件同步
|
|
135
|
+
|
|
136
|
+
往服务器传文件 / 从服务器取文件,走这一组 —— **别用 `ssh` / `rsync` / `scp` 自己拼一份**:IDE 的连接、路径映射、排除规则都在它们后面,自己拼的不是 IDE 在管的那一份。
|
|
137
|
+
|
|
138
|
+
- {{cmd_list_deployment_servers}}
|
|
139
|
+
**本项目能用的部署服务器**:名称(后面几条用它当 `serverName`)、项目级还是应用级、协议、host / port、在本项目里的路径映射,以及**项目级**的部署选项与危险组合告警。**只读 IDE 配置、不联网**;动手前先看 `warnings[]`。
|
|
140
|
+
{{#if canUploadToDeployment}}
|
|
141
|
+
- {{cmd_upload_to_deployment}}
|
|
142
|
+
**把映射到的本地目录传到服务器**(等同 IDE 的 Upload to …)。`mode` 默认 `mirror` —— **会删掉服务器上多出来的文件**,使两边一致;要留住它们就传 `upload`。**破坏性操作**。
|
|
143
|
+
{{/if}}
|
|
144
|
+
{{#if canDownloadFromDeployment}}
|
|
145
|
+
- {{cmd_download_from_deployment}}
|
|
146
|
+
**把服务器上映射目录的内容拉回本地**(等同 IDE 的 Download from …),**以服务器为准**:两边都有的文件会被远端覆盖(内容相同则不写)。**没有"保留我的版本"这个选项**。
|
|
147
|
+
{{/if}}
|
|
148
|
+
{{#if canGetDeploymentTaskStatus}}
|
|
149
|
+
- {{cmd_get_deployment_task_status}}
|
|
150
|
+
**查一次传输的状态**:`handle` 用上传 / 下载返回的那个 —— **它自己不启动任何传输**。
|
|
151
|
+
{{/if}}
|
|
152
|
+
|
|
153
|
+
上传 / 下载都在 IDE 后台跑,单次调用只等到 `waitMs`(默认 10 秒)为止;返回 `in_progress` 是**正常**的,不是失败 —— 拿 `handle` 去查进度,**别用重复调上传 / 下载代替**(那样拿不到进度)。
|
|
57
154
|
{{/if}}
|
|
58
155
|
|
|
59
|
-
|
|
156
|
+
## 命令执行(所有项目通用)
|
|
60
157
|
|
|
61
|
-
- 需要项目环境的命令(依赖 IDE 里配好的 JDK / Node / Python 版本等)
|
|
62
|
-
- run
|
|
63
|
-
- 要新建:先确认它**反复要用、且属于项目固定流程**;确认后**先告诉用户要建什么、为什么,取得同意再动手**,别自己决定。
|
|
64
|
-
- **配置一律不由你写**:不要手写 `.run/*.run.xml`,也不要手搓启动命令。
|
|
65
|
-
- **要查有哪些配置,用 `idea_get_run_configurations`,不要翻 `.run/` 目录**:工具给的是 IDE 当前认的配置;翻目录只能看到项目级文件,存在 `.idea/` 里的那些看不到。
|
|
158
|
+
- 需要项目环境的命令(依赖 IDE 里配好的 JDK / Node / Python 版本等):用该项目前缀的 run configuration 工具,不要用原生 `shell`。
|
|
159
|
+
- 写 `.run/*.run.xml` **只走 `idea-run-config-manager` skill**:它有逐类型模板(`assets/types/`),写完还要复查。**平时不要自己手写配置,也不要用一条裸命令代替配置。**
|
|
66
160
|
{{#if canCreateRunConfiguration}}
|
|
67
|
-
-
|
|
161
|
+
- 要固化的固定流程(判据见上:会不会以同样形态重复发生):Shell 类型用上面那个「新建项目级 Shell 配置」建;非 Shell 类型与删 / 改,交给用户调 `idea-run-config-manager` skill。
|
|
68
162
|
{{else}}
|
|
69
|
-
-
|
|
163
|
+
- 要固化的固定流程:把配置名、实际执行的命令、工作目录、为什么值得留讲清楚,**请用户在 IDE 里自己建** —— 当前没有能建它的工具(`idea-run-config-manager` skill 的门就是这个工具,所以它这次也不会出现),不要手写文件凑。
|
|
70
164
|
{{/if}}
|
|
71
165
|
- 不需要项目环境的命令:用原生 `shell`。
|