rainskills 0.1.24 → 0.1.26
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 +1 -1
- package/SKILL.md +1 -1
- package/bin/rainskills-tools.js +101 -16
- package/marketplace/rainskills/.claude-plugin/plugin.json +1 -1
- package/marketplace/rainskills/.codex-plugin/plugin.json +1 -1
- package/marketplace/rainskills/skills/rainskills/SKILL.md +2 -2
- package/package.json +1 -1
- package/rainbond-app-assistant/SKILL.md +6 -6
- package/rainbond-app-assistant/references/runtime-gate.md +7 -6
- package/rainbond-app-assistant/references/workflow-rules.md +42 -42
- package/rainbond-app-assistant/scripts/validate_cross_skill_routing.py +2 -2
- package/rainbond-app-assistant/scripts/validate_progressive_loading.py +5 -5
- package/rainbond-app-version-assistant/SKILL.md +7 -6
- package/rainbond-delivery-verifier/SKILL.md +7 -6
- package/rainbond-env-sync/SKILL.md +7 -6
- package/rainbond-fullstack-bootstrap/SKILL.md +7 -6
- package/rainbond-fullstack-bootstrap/modules/40-source-and-package-rules.md +2 -2
- package/rainbond-fullstack-troubleshooter/SKILL.md +7 -6
- package/rainbond-opensource-app-deploy/SKILL.md +3 -3
- package/rainbond-opensource-app-deploy/references/runtime-gate.md +7 -6
- package/rainbond-platform-installer/SKILL.md +1 -1
- package/rainbond-platform-installer/references/installation-policy.json +1 -6
- package/rainbond-platform-installer/references/installation-policy.md +2 -2
- package/rainbond-platform-installer/references/troubleshooting.md +1 -1
- package/rainbond-platform-installer/scripts/installed-version.js +1 -1
- package/rainbond-platform-installer/scripts/platform-installer.js +1 -10
- package/rainbond-platform-installer/scripts/platform-routing.js +3 -2
- package/rainbond-platform-installer/scripts/windows-platform.js +0 -9
- package/rainbond-platform-query/SKILL.md +7 -6
- package/rainbond-project-init/SKILL.md +7 -6
- package/rainbond-template-installer/SKILL.md +7 -6
package/README.md
CHANGED
|
@@ -223,7 +223,7 @@ node ~/.rainbond/lib/rainskills/bin/rainskills.js platform install --onboarding-
|
|
|
223
223
|
|
|
224
224
|
Rainskills 会在用户下一次发起业务动作时,由本地运行时立即返回环境查询结果,并另行启动后台任务静默检查更新。更新只跟随 npm `latest` 指向的正式版。当前版本是 RC 或其他预发布版本时不会查询、不会自动升级;npm 上的新 RC 版本也不参与正式版自动升级。
|
|
225
225
|
|
|
226
|
-
发现更高的正式版后,后台任务只委托到经过校验的精确版本,例如 `rainskills@0.1.
|
|
226
|
+
发现更高的正式版后,后台任务只委托到经过校验的精确版本,例如 `rainskills@0.1.26`,不会执行浮动的 `@latest` 业务代码。新版本原子刷新已经安装的 Rainskills Skills;当前业务继续使用启动时已经加载的版本,最迟从下一条新任务开始使用新版。npm 超时、版本检查失败、安装位置不安全或文件迁移失败时会保留旧版本,且不会阻塞或改变当前操作。
|
|
227
227
|
|
|
228
228
|
升级只更新 Rainskills 自身,不触发 Rainbond 安装、运行环境选择、登录授权或重新对接,也不会新增 Agent MCP 配置。更新内容仅包括 Skills 和本地 CLI。原始业务操作会继续执行;只有该业务操作本身需要运行环境时,才按既有门禁检查当前连接。可用连接直接复用,401 只重新授权一次,403 立即停止,从未连接过运行环境时才进入环境选择。
|
|
229
229
|
|
package/SKILL.md
CHANGED
|
@@ -44,7 +44,7 @@ Rainskills 安装完成,下一条消息即可直接使用。
|
|
|
44
44
|
|
|
45
45
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
46
46
|
|
|
47
|
-
Rainskills 只保存一个全局运行环境,不维护环境列表、名称、默认值或环境 ID。使用固定 launcher `node <home>/.rainbond/lib/rainskills/bin/rainskills.js`(运行包版本 `rainskills@0.1.
|
|
47
|
+
Rainskills 只保存一个全局运行环境,不维护环境列表、名称、默认值或环境 ID。使用固定 launcher `node <home>/.rainbond/lib/rainskills/bin/rainskills.js`(运行包版本 `rainskills@0.1.26`):
|
|
48
48
|
|
|
49
49
|
- 状态:执行 `runtime status --json`。
|
|
50
50
|
- 首次连接:执行 `runtime connect <target> --saas` 或 `runtime connect <target> --rainbond-url <Console origin>`。
|
package/bin/rainskills-tools.js
CHANGED
|
@@ -23,6 +23,9 @@ const SKILL_MANIFEST_FILENAME = "rainskills-skill-manifest.json";
|
|
|
23
23
|
const OPERATION_ID_PATTERN = /^[a-f0-9]{8}-[a-f0-9-]{27,}$/;
|
|
24
24
|
const SKILL_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
|
|
25
25
|
const SHA256_PATTERN = /^[a-f0-9]{64}$/;
|
|
26
|
+
const CONTROL_CHARACTER_PATTERN = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
27
|
+
const CONTEXT_RESOLVE_FIELDS = new Set(["required", "hints", "selection"]);
|
|
28
|
+
const CONTEXT_HINT_FIELDS = new Set(["team_id", "team_name", "region_name"]);
|
|
26
29
|
const SKILL_CONTENT_MAX_BYTES = 128 * 1024;
|
|
27
30
|
const SKILL_MANIFEST_MAX_BYTES = 4 * 1024 * 1024;
|
|
28
31
|
const SENSITIVE_RESPONSE_KEY_PATTERN = /(?:authorization|jwt|token|password|secret|credential|private[_-]?key|key[_-]?file|certificate|cert[_-]?file|ssl[_-]?ca[_-]?cert)/i;
|
|
@@ -1017,17 +1020,96 @@ function boundedContextString(value) {
|
|
|
1017
1020
|
return typeof value === "string"
|
|
1018
1021
|
&& value.length > 0
|
|
1019
1022
|
&& value.length <= 128
|
|
1020
|
-
&&
|
|
1023
|
+
&& !CONTROL_CHARACTER_PATTERN.test(value)
|
|
1021
1024
|
? value
|
|
1022
1025
|
: null;
|
|
1023
1026
|
}
|
|
1024
1027
|
|
|
1025
|
-
|
|
1026
|
-
|
|
1028
|
+
function contextInputUsageError() {
|
|
1029
|
+
return new BridgeError("context input fields are invalid", EXIT.USAGE, {
|
|
1030
|
+
error: "context input fields are invalid",
|
|
1031
|
+
expected: {
|
|
1032
|
+
required: ["enterprise", "workspace"],
|
|
1033
|
+
hints: { team_name: "<team-name>" },
|
|
1034
|
+
},
|
|
1035
|
+
note: "enterprise is resolved from the current authenticated identity",
|
|
1036
|
+
});
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
function validateContextHints(value) {
|
|
1040
|
+
if (value === undefined) return null;
|
|
1041
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1042
|
+
throw new BridgeError("context workspace hints are invalid", EXIT.USAGE);
|
|
1043
|
+
}
|
|
1044
|
+
const entries = Object.entries(value);
|
|
1045
|
+
if (entries.length === 0
|
|
1046
|
+
|| entries.some(([field, item]) => !CONTEXT_HINT_FIELDS.has(field) || !boundedContextString(item))) {
|
|
1047
|
+
throw new BridgeError("context workspace hints are invalid", EXIT.USAGE);
|
|
1048
|
+
}
|
|
1049
|
+
return Object.fromEntries(entries);
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
function validateContextSelection(value) {
|
|
1053
|
+
if (value === undefined) return null;
|
|
1054
|
+
if (!value || typeof value !== "object" || Array.isArray(value)
|
|
1055
|
+
|| Object.keys(value).length !== 1
|
|
1056
|
+
|| typeof value.option_id !== "string"
|
|
1057
|
+
|| value.option_id.length === 0
|
|
1058
|
+
|| value.option_id.length > 300
|
|
1059
|
+
|| CONTROL_CHARACTER_PATTERN.test(value.option_id)) {
|
|
1060
|
+
throw new BridgeError("context workspace selection is invalid", EXIT.USAGE);
|
|
1061
|
+
}
|
|
1062
|
+
return { option_id: value.option_id };
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
function validateContextResolveInput(input) {
|
|
1066
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
1067
|
+
throw contextInputUsageError();
|
|
1068
|
+
}
|
|
1069
|
+
if (Object.keys(input).some((field) => !CONTEXT_RESOLVE_FIELDS.has(field))) {
|
|
1070
|
+
throw contextInputUsageError();
|
|
1071
|
+
}
|
|
1072
|
+
const required = input.required;
|
|
1027
1073
|
if (!Array.isArray(required)
|
|
1028
1074
|
|| required.some((item) => !["enterprise", "workspace"].includes(item))) {
|
|
1029
1075
|
throw new BridgeError("context required dimensions are invalid", EXIT.USAGE);
|
|
1030
1076
|
}
|
|
1077
|
+
|
|
1078
|
+
const hints = validateContextHints(input.hints);
|
|
1079
|
+
const selection = validateContextSelection(input.selection);
|
|
1080
|
+
|
|
1081
|
+
if ((hints || selection) && !required.includes("workspace")) {
|
|
1082
|
+
throw new BridgeError("context workspace input requires the workspace dimension", EXIT.USAGE);
|
|
1083
|
+
}
|
|
1084
|
+
if (hints && selection) {
|
|
1085
|
+
throw new BridgeError("context hints and selection are mutually exclusive", EXIT.USAGE);
|
|
1086
|
+
}
|
|
1087
|
+
return { required, hints, selection };
|
|
1088
|
+
}
|
|
1089
|
+
|
|
1090
|
+
function resolvedWorkspaceContext(enterpriseId, option) {
|
|
1091
|
+
return {
|
|
1092
|
+
state: "resolved",
|
|
1093
|
+
context: {
|
|
1094
|
+
enterprise_id: enterpriseId,
|
|
1095
|
+
team_id: option.team_id,
|
|
1096
|
+
team_name: option.team_name,
|
|
1097
|
+
region_name: option.region_name,
|
|
1098
|
+
},
|
|
1099
|
+
};
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
function workspaceSelectionResult(enterpriseId, options) {
|
|
1103
|
+
return {
|
|
1104
|
+
state: "needs-selection",
|
|
1105
|
+
enterprise_id: enterpriseId,
|
|
1106
|
+
dimension: "workspace-region",
|
|
1107
|
+
options,
|
|
1108
|
+
};
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
async function resolveStatelessContext(input, config) {
|
|
1112
|
+
const { required, hints, selection } = validateContextResolveInput(input);
|
|
1031
1113
|
const identity = await execute({
|
|
1032
1114
|
command: "read",
|
|
1033
1115
|
toolName: "rainbond_get_current_user",
|
|
@@ -1071,19 +1153,22 @@ async function resolveStatelessContext(input, config) {
|
|
|
1071
1153
|
}
|
|
1072
1154
|
}
|
|
1073
1155
|
if (options.length === 0) return { state: "blocked", reason: "no-accessible-workspace" };
|
|
1074
|
-
if (
|
|
1075
|
-
const
|
|
1076
|
-
return
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
};
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1156
|
+
if (selection) {
|
|
1157
|
+
const selected = options.find((option) => option.id === selection.option_id);
|
|
1158
|
+
return selected
|
|
1159
|
+
? resolvedWorkspaceContext(enterpriseId, selected)
|
|
1160
|
+
: { state: "blocked", reason: "workspace-selection-invalid" };
|
|
1161
|
+
}
|
|
1162
|
+
const matchingOptions = hints
|
|
1163
|
+
? options.filter((option) => Object.entries(hints).every(([field, value]) => option[field] === value))
|
|
1164
|
+
: options;
|
|
1165
|
+
if (matchingOptions.length === 0) {
|
|
1166
|
+
return { state: "blocked", reason: "workspace-hint-not-found" };
|
|
1167
|
+
}
|
|
1168
|
+
if (matchingOptions.length === 1) {
|
|
1169
|
+
return resolvedWorkspaceContext(enterpriseId, matchingOptions[0]);
|
|
1170
|
+
}
|
|
1171
|
+
return workspaceSelectionResult(enterpriseId, matchingOptions);
|
|
1087
1172
|
}
|
|
1088
1173
|
|
|
1089
1174
|
async function execute(command, config) {
|
|
@@ -14,7 +14,7 @@ This is the single marketplace entry for the complete Rainskills product. The in
|
|
|
14
14
|
3. Keep stdin, stdout, and stderr attached. When `RAINSKILLS_USER_INPUT_REQUIRED` appears, pause for that installer choice. If the installer emits `rainskills.next-action.v1`, execute only its fixed `argv` through the same launcher; never evaluate output as a shell command. If the adjacent `bin/rainskills.js` exists, use it for fixed next actions; otherwise use the same versioned npm package fallback described below.
|
|
15
15
|
4. Stay attached until every independent Skill is installed. Do not select, connect, or configure an application runtime during installation. In the user-facing response, output only the fixed completion message below.
|
|
16
16
|
|
|
17
|
-
If the adjacent installer is missing, check the local Node.js version before choosing the fallback. With `npx` and Node.js 18 or newer, use `npx --yes rainskills@0.1.
|
|
17
|
+
If the adjacent installer is missing, check the local Node.js version before choosing the fallback. With `npx` and Node.js 18 or newer, use `npx --yes rainskills@0.1.26 <target>`. With no Node.js or a version below 18, use `bash <(curl -fsSL https://get.rainbond.com/rainskills/install.sh) <target>` instead. Omit `<target>` only when the host cannot be determined reliably. Keep either command attached to the interactive terminal. For an update or repair, refresh this marketplace Skill first, then run the installer again; it compares and updates every independent internal Skill.
|
|
18
18
|
|
|
19
19
|
Skills-only 安装不需要 Node.js;CDN fallback 只负责安装 Skill 文件,不代表运行环境连接、应用部署或平台安装已经可执行。用户首次提出需要运行环境的动作时,对应业务 Skill 才检查 Node.js;固定 Rainskills launcher 需要 Node.js 18 或更高版本。缺失或版本过低时保留原始 intent 并停止,等待用户或 agent 明确同意安装或升级 Node.js,安装完成消息不得提前提示 Node.js。
|
|
20
20
|
|
|
@@ -44,7 +44,7 @@ Rainskills 安装完成,下一条消息即可直接使用。
|
|
|
44
44
|
|
|
45
45
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
46
46
|
|
|
47
|
-
Rainskills 只保存一个全局运行环境,不维护环境列表、名称、默认值或环境 ID。使用固定 launcher `node <home>/.rainbond/lib/rainskills/bin/rainskills.js`(运行包版本 `rainskills@0.1.
|
|
47
|
+
Rainskills 只保存一个全局运行环境,不维护环境列表、名称、默认值或环境 ID。使用固定 launcher `node <home>/.rainbond/lib/rainskills/bin/rainskills.js`(运行包版本 `rainskills@0.1.26`):
|
|
48
48
|
|
|
49
49
|
- 状态:执行 `runtime status --json`。
|
|
50
50
|
- 首次连接:执行 `runtime connect <target> --saas` 或 `runtime connect <target> --rainbond-url <Console origin>`。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rainbond-app-assistant
|
|
3
|
-
description: "Use whenever a user asks to deploy, run, deliver, publish, inspect, repair, or troubleshoot source code, the current project or local project, a source directory/package, an ordinary bare Git repository URL, a private-image project,
|
|
3
|
+
description: "Use whenever a user asks to deploy, run, deliver, publish, inspect, repair, or troubleshoot source code, the current project or local project, a source directory/package, an ordinary bare Git repository URL, a private-image project, a named application that is not identified as a third-party open-source suite, or a new app/component built from one container image. Trigger phrases: 帮我部署当前项目 / 帮我把这个项目跑起来 / 帮我看看当前项目卡在哪 / 如果还没初始化就先初始化,然后自动继续到应该停止的位置 / 帮我处理一下这个应用 / 在团队下新建应用并使用镜像创建组件. Not for supplied third-party Compose, Helm, image-set descriptors, or an explicit named third-party open-source suite; use rainbond-opensource-app-deploy. Confirmed market templates use rainbond-template-installer."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Rainbond App Assistant
|
|
@@ -14,7 +14,7 @@ description: "Use whenever a user asks to deploy, run, deliver, publish, inspect
|
|
|
14
14
|
- 用户实际提供第三方 Docker Compose、Helm、镜像集合描述符,或明确要求部署 Harbor、Dify、n8n 等第三方开源套件:转到 rainbond-opensource-app-deploy。
|
|
15
15
|
- 已确认是 Rainbond 本地/云端市场模板:转到 rainbond-template-installer。
|
|
16
16
|
|
|
17
|
-
开始前读取 [routing](references/routing.md)
|
|
17
|
+
开始前读取 [routing](references/routing.md) 做静态归属判断。初始路由阶段只加载最终所属入口 Skill 的 Runtime Gate,不得提前读取专项 Skill 的 Gate。
|
|
18
18
|
|
|
19
19
|
## 渐进加载
|
|
20
20
|
|
|
@@ -23,11 +23,11 @@ description: "Use whenever a user asks to deploy, run, deliver, publish, inspect
|
|
|
23
23
|
| 阶段 | 必须读取 | 禁止提前读取 |
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| 初始部署或首次 Rainbond 操作 | 本根入口、[own runtime gate](references/runtime-gate.md)、[routing](references/routing.md) | 其余全部 |
|
|
26
|
-
|
|
|
26
|
+
| workspace context 已解析,需要编排或执行 app/component | [workflow rules](references/workflow-rules.md);仅在核对路线或复盘时读取 [operational reference](references/operational-reference.md) | 输出与对象细节 |
|
|
27
27
|
| 需要对象边界或跨阶段状态语义 | [product object model](references/product-object-model.md) | 不相关工作流 |
|
|
28
28
|
| 需要生成最终结果或自动化契约 | [output contract](references/output-contract.md) | 不需要结果协议时不得读取 |
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
workspace context 包含 `enterprise_id`、`team_id`、`team_name` 和 `region_name`;app/component 标识只来自用户明确输入或本次实时查询/创建结果。它们都由当前任务携带,不写入 Runtime,也不得生成或传递 CLI 业务 operation ID、运行环境 ID 或 intent JSON。
|
|
31
31
|
|
|
32
32
|
## Runtime Gate
|
|
33
33
|
|
|
@@ -35,7 +35,7 @@ description: "Use whenever a user asks to deploy, run, deliver, publish, inspect
|
|
|
35
35
|
|
|
36
36
|
不可弱化的不变量:
|
|
37
37
|
|
|
38
|
-
- 不得绕过 Gate 选择的 transport、context
|
|
38
|
+
- 不得绕过 Gate 选择的 transport、context 或授权边界。进入专项阶段后,按 workflow rules 完整读取对应专项 Skill;其中重复的 Gate 只用于一致性核对,不得触发第二次连接、状态检查或 context 解析,除非 Gate 声明的失效条件已经发生。
|
|
39
39
|
- 401:只读调用仅可按 Gate 允许的恢复流程重试一次;写调用不得自动重放,必须先查询真实状态。403:立即停止,不做未授权重试。
|
|
40
40
|
- 可变调用必须先取得确认 ID,再用完全相同输入附加确认执行;不得绕过确认。
|
|
41
41
|
- JWT、凭据与密钥不得回显、复制到报告或通过替代 transport 绕过保护。
|
|
@@ -49,7 +49,7 @@ description: "Use whenever a user asks to deploy, run, deliver, publish, inspect
|
|
|
49
49
|
- 到达 code_or_build_handoff_needed 后硬停止,不自动改代码、运行本地测试、提交、推送或重试。
|
|
50
50
|
- 密钥只来自当前 profile 允许的输入源,永不回显或写入报告。
|
|
51
51
|
|
|
52
|
-
详细主线、
|
|
52
|
+
详细主线、context 复用、专项手册加载、构建/运行时证据链、依赖、确认边界与尝试预算只在需要执行时读取 [workflow rules](references/workflow-rules.md)。
|
|
53
53
|
|
|
54
54
|
## 简洁结果协议
|
|
55
55
|
|
|
@@ -11,10 +11,12 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
11
11
|
|
|
12
12
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
13
13
|
|
|
14
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
15
|
+
|
|
14
16
|
```json
|
|
15
17
|
{
|
|
16
18
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
17
|
-
"package_version": "rainskills@0.1.
|
|
19
|
+
"package_version": "rainskills@0.1.26",
|
|
18
20
|
"runtime_status": [
|
|
19
21
|
"node",
|
|
20
22
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -71,10 +73,9 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
71
73
|
"rainbond-app-assistant"
|
|
72
74
|
],
|
|
73
75
|
"stdin": {
|
|
74
|
-
"required": [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
]
|
|
76
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
77
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
78
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
78
79
|
}
|
|
79
80
|
},
|
|
80
81
|
"read": {
|
|
@@ -127,7 +128,7 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
127
128
|
|
|
128
129
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
129
130
|
|
|
130
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
131
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
131
132
|
|
|
132
133
|
<!-- rainskills-runtime-routing:start -->
|
|
133
134
|
## 缺少运行环境时
|
|
@@ -354,7 +354,7 @@
|
|
|
354
354
|
- 多个 team 且无 manifest 提示 → 停下来询问用户,**禁止**静默选 `default` / 第一个 / 任意已有 team。
|
|
355
355
|
- app 选择同上逻辑:manifest 指定且可解析 → 直接用;无提示且多候选 → 询问。
|
|
356
356
|
- 任何自动选择的结果都必须在最终报告里以"已选 X(理由:来自 manifest / 单一可选)"形式告知,邀请用户覆盖。
|
|
357
|
-
- 每个 Rainbond
|
|
357
|
+
- 每个 Rainbond Tool 边界都要把十进制字符串 `app_id` 规范化为正整数;非数字 ID 必须拒绝。
|
|
358
358
|
3. 单入口主线一旦触发:
|
|
359
359
|
`project-init -> bootstrap -> troubleshooter -> delivery-verifier -> version-assistant -> testing-app delivery-verifier`
|
|
360
360
|
应按 gate 自动继续,不要在中途停成“下一步建议”。
|
|
@@ -404,12 +404,12 @@
|
|
|
404
404
|
不要把语言构建参数塞进 `build_info`。
|
|
405
405
|
17. 如果源码检测同时命中 Dockerfile 和语言构建,按 `rainbond-fullstack-bootstrap` 的 Build Mode Selection 优先级链解决:manifest `source.build.strategy` 优先 → 启发式按 Dockerfile 分类 + 意图信号判断("语言 buildpack 能否产生等价运行时行为",原则驱动而非固定清单)→ 真正模糊时才问一次并建议用户写回 manifest。决策必须双轨可审计:prose 输出"Build mode for `<name>`: `<picked>` (`<source>` — `<reason>`; to override: `<hint>`)"逐组件展示,且 bootstrap 的结构化输出 `deployment_plan.workflow.build_strategy_decisions[<name>]` 同步记录(仅给有 dual detection 的组件填)。`dockerfile` 决策映射到 `rainbond_create_component_from_source` 的 `prefer_dockerfile_when_detected = true`。详见 `rainbond-fullstack-bootstrap/references/source-build-parameter-guide.md § Build Mode Selection`。
|
|
406
406
|
- **恢复例外按状态决定**:`checking` / `checked` / 未完成组件可以通过 `rainbond_get_component_check_result(prefer_dockerfile_when_detected=true)` 在原拓扑中取得 Dockerfile 证据,禁止删除。只有 `create_status=complete` 的 CNB 组件不存在通用原地切换能力时,才允许在已保存 topology and configuration snapshot、已向用户展示该完成状态并获得 explicit user confirmation 后删除并重建;任一证据缺失时只读停止。
|
|
407
|
-
18. 当前
|
|
407
|
+
18. 当前 Rainbond Tool catalog 不支持显式 `dockerfile_path` 时,不要在顶层编排里承诺该能力。
|
|
408
408
|
19. 对 reverse-proxy full-stack 项目,不要只因为根路径 URL 存在就把它当作最终交付成功或 Fast Path 的可信 URL;同 host 的 backend 路径(通常是 `/api`)必须也一致可用,或明确停在 blocker。
|
|
409
409
|
20. **组件依赖与连接变量管理**(合并自原 20-23 四条):多组件拓扑里,provider/consumer 关系必须用显式依赖 + provider 侧连接变量管理,不要让 consumer 端硬编码或重复声明。
|
|
410
410
|
|
|
411
411
|
**可执行工具(fact)**:
|
|
412
|
-
- 显式依赖:`rainbond_manage_component_dependency` — 不要回答"
|
|
412
|
+
- 显式依赖:`rainbond_manage_component_dependency` — 不要回答"没有依赖接口";调用失败时按 Rainbond Tool / 控制面真实错误报告,不要描述为工具不存在
|
|
413
413
|
- Provider 连接变量:`rainbond_manage_component_connection_envs(scope=outer)` — 这是 provider 暴露给 consumer 的接口面
|
|
414
414
|
- Consumer 自身的本地 env:`rainbond_manage_component_envs` — 仅放该 consumer 真正本地的值
|
|
415
415
|
|
|
@@ -418,7 +418,7 @@
|
|
|
418
418
|
- 共享连接信息(数据库连接串、缓存地址、消息队列 broker 等任何"provider 拥有的连接 fact")→ 配在 provider 的 connection envs 上,**不要**在每个 consumer 上重复写
|
|
419
419
|
- 运行时报 `connection refused` / `ENOTFOUND <provider-name>` / 错 host / 错 port / 缺密码等连接类错误 → 先看 provider connection env / dependency alias / compatibility env,**不要**把 baseline 里的硬编码主机名当成事实
|
|
420
420
|
- 多组件拓扑进入交付验收前 → 必须跑一遍依赖完整性 gate(列已接受边 → 查现有依赖 → 补齐缺失 → 再次验证依赖摘要)。手工创建镜像组件、Compose fallback 路径、组件能独立启动都**不能**跳过 gate
|
|
421
|
-
- **配置覆盖 gate(backend 组件,设完 env 后、宣布健康/可交付前必跑)**:从 `rainbond_get_component_summary` 枚举该组件挂载的 config-file 卷。若有卷挂到已知配置路径(`config.yml` / `application.yml` / `application.properties` / `.env` / `nginx.conf` / `*.conf`),运行态有效配置由该文件决定而非 env(mounted config-file > env > 镜像默认值)。这时必须警告"env 可能被挂载的配置文件覆盖",并先确认该文件反映了预期值,再宣布交付健康。比较配置值用于该 gate 是允许的,但**禁止**回显原始文件内容或密钥明文,只报结构化不一致。文件内容无法用当前
|
|
421
|
+
- **配置覆盖 gate(backend 组件,设完 env 后、宣布健康/可交付前必跑)**:从 `rainbond_get_component_summary` 枚举该组件挂载的 config-file 卷。若有卷挂到已知配置路径(`config.yml` / `application.yml` / `application.properties` / `.env` / `nginx.conf` / `*.conf`),运行态有效配置由该文件决定而非 env(mounted config-file > env > 镜像默认值)。这时必须警告"env 可能被挂载的配置文件覆盖",并先确认该文件反映了预期值,再宣布交付健康。比较配置值用于该 gate 是允许的,但**禁止**回显原始文件内容或密钥明文,只报结构化不一致。文件内容无法用当前 Rainbond Tool catalog 读取时,显式标注覆盖风险并停下来让用户确认,不要默默改 env 就当成功
|
|
422
422
|
|
|
423
423
|
具体的 provider 命名约定、connection env 变量名(`DB_*` / `REDIS_*` / `KAFKA_*` 等是示例,按 provider 文档实际名字为准)、以及依赖 alias 细节,详见 bootstrap modules/30-creation-rules.md 的相关章节。
|
|
424
424
|
24. 不要自动拉起本地 Docker Desktop/OrbStack、执行本地 Docker build/push、或推送临时镜像作为兜底;这属于 delivery-mode 策略切换,必须先得到用户明确确认。
|
|
@@ -429,7 +429,7 @@
|
|
|
429
429
|
代理事实属于执行记录,不是强制暴露 YAML 的理由。
|
|
430
430
|
28. `rbd-*` 组件(rbd-gateway、rbd-api、rbd-worker、rbd-chaos、rbd-db、rbd-mq、rbd-monitor、rbd-node 等)是 Rainbond 平台自身的基础设施组件,不是用户应用组件。
|
|
431
431
|
- 可以用 `rainbond_query_region_rbd_components` 查询并展示它们的状态
|
|
432
|
-
- 不能通过
|
|
432
|
+
- 不能通过 Rainbond Tool 对它们执行重启、部署、修改等写操作;当前 Tool catalog 不支持此类操作
|
|
433
433
|
- 如果用户要求操作这些组件,明确告知:需要通过 Kubernetes 命令(如 `kubectl rollout restart deployment/<name> -n rbd-system`)或 Rainbond 集群管理控制台进行,超出本技能的操作范围,不要假装可以执行
|
|
434
434
|
28a. 已知 `service_id` 的组件在构建、部署或运行操作后失败或立即异常时,调用 `rainbond_get_operation_failure_context({team_name, region_name, app_id, service_id, event_id?})`,按其 `classified_reason` 决定停下、只读核实或低风险修复;`unknown` 回退既有证据链,禁止盲目重放写操作。CLI 在确认令牌生成前报告的 missing/invalid field 属于参数校验失败,尚未进入组件操作:按 Console Tool schema 修正参数一次,不调用 failure context,也不查询组件残留。
|
|
435
435
|
`event_log_tail` 只作为敏感诊断证据使用,绝不能复制、引用或向用户展示其原文;输出只能使用 `classified_reason`、非敏感摘要和已脱敏字段。
|
|
@@ -457,23 +457,23 @@
|
|
|
457
457
|
- **不允许**根据"模型对该仓库的先验知识"猜常见名字(Java-maven-demo、java_maven_demo、demo/java-maven 等)
|
|
458
458
|
- 这与 Iron Law 29 入口"必须问用户"配套:29 管入口、30 管中途用户输入验证失败的二次询问。
|
|
459
459
|
猜测换参数 + 删-再-create 循环是典型 anti-pattern,server 端可能直接 reject 重复 create 调用。
|
|
460
|
-
31. **任何 Rainbond
|
|
461
|
-
|
|
460
|
+
31. **任何 Rainbond 写工具调用之前**,必须先完整读取当前阶段对应专项 Skill 的 `SKILL.md`,再按其渐进加载规则读取本次动作需要的 modules / references;没有执行手册就直接动手等于**无授权操作**,是 Iron Law 违反。
|
|
461
|
+
触发动作(凡是这类,第一次调用之前都必须先加载对应专项手册):
|
|
462
462
|
- 创建/更新/部署组件:`rainbond_create_component_from_source`、`rainbond_create_component_from_image`、`rainbond_create_component_from_package`、`rainbond_create_component`、`rainbond_build_component`、`rainbond_update_component_build_source`、`rainbond_change_component_image`
|
|
463
463
|
- 包上传事务:`rainbond_init_package_upload`、`rainbond_delete_package_upload`;包内容必须由 bootstrap 的客户端 helper 上传,完成后再用上面的 event-based package create
|
|
464
464
|
- 组件配置:`rainbond_manage_component_envs`、`rainbond_manage_component_ports`、`rainbond_manage_component_connection_envs`、`rainbond_manage_component_dependency`、`rainbond_manage_component_storage`、`rainbond_manage_component_probe`、`rainbond_manage_component_autoscaler`
|
|
465
465
|
- 应用操作:`rainbond_operate_app`、`rainbond_horizontal_scale_component`、`rainbond_vertical_scale_component`、`rainbond_delete_component`
|
|
466
466
|
映射表:
|
|
467
|
-
- 当前 run 是**首次部署/创建组件/补齐拓扑**(含从源码/镜像创建,以及客户端 package upload + event-based package create) →
|
|
468
|
-
- 当前 run 是**排查运行态/构建失败**(CrashLoopBackOff / ImagePullBackOff / 构建报错 / 端口/依赖不通) →
|
|
469
|
-
- 当前 run 是**交付验收**(验证 URL 可达、reverse-proxy 路径连通) →
|
|
470
|
-
- 当前 run 是**开发到测试 promotion**(创建快照 + 测试 app) →
|
|
471
|
-
- 当前 run 是**模板安装**(本地/云端 Rainbond 应用模板) →
|
|
467
|
+
- 当前 run 是**首次部署/创建组件/补齐拓扑**(含从源码/镜像创建,以及客户端 package upload + event-based package create) → `rainbond-fullstack-bootstrap`
|
|
468
|
+
- 当前 run 是**排查运行态/构建失败**(CrashLoopBackOff / ImagePullBackOff / 构建报错 / 端口/依赖不通) → `rainbond-fullstack-troubleshooter`
|
|
469
|
+
- 当前 run 是**交付验收**(验证 URL 可达、reverse-proxy 路径连通) → `rainbond-delivery-verifier`
|
|
470
|
+
- 当前 run 是**开发到测试 promotion**(创建快照 + 测试 app) → `rainbond-app-version-assistant`
|
|
471
|
+
- 当前 run 是**模板安装**(本地/云端 Rainbond 应用模板) → `rainbond-template-installer`
|
|
472
472
|
规则细节:
|
|
473
|
-
-
|
|
474
|
-
-
|
|
475
|
-
- **判断依据**:用户消息中只要含"部署 / 跑起来 / 上线 / 创建组件 / 发布"等部署意图,且当前 app
|
|
476
|
-
-
|
|
473
|
+
- 从当前主机提供的可用 Skills 清单定位专项 Skill;不得把 Skill 名当作 Rainbond Tool 名称或通过业务工具目录调用
|
|
474
|
+
- 一个专项 Skill 在同一会话内只需读取一次;跨阶段时再读取新阶段的专项 Skill
|
|
475
|
+
- **判断依据**:用户消息中只要含"部署 / 跑起来 / 上线 / 创建组件 / 发布"等部署意图,且当前 app 还没有对应组件,就必然要先加载 `rainbond-fullstack-bootstrap`,不论用户是不是显式说"先 deep dive"
|
|
476
|
+
- App Assistant 已完成的唯一运行环境检查和无状态 context 解析可在专项阶段复用;除非 Node.js、Rainskills、PATH、唯一运行环境或用户目标发生变化,不得重新检查或重新解析
|
|
477
477
|
正确路径:用户说"试试 maven-demo" → 你直接调 `rainbond_update_component_build_source(service_id=已知的, subdirectories='maven-demo')` → `rainbond_check_component(service_id=已知的, is_again=true)` → 轮询 `rainbond_get_component_check_result` 直到拿到新一轮 `check_event_id`/`check_uuid` 的结果。
|
|
478
478
|
32. **简短回复继承上一轮被中断的操作**:当上一轮你向用户提了问、或在 prose 里邀请用户回复("回复继续 / check / OK / 完成 / 重试" 等),用户给了简短或单值回复("继续"、"OK"、"试试 X"、"对的就是 Y"、"换 master"),你的**下一个动作必须基于 priorTurnMessages 的最新状态继续上一个被中断的操作**,**禁止**把它当成一次"全新的开始"。
|
|
479
479
|
- 看 priorTurnMessages 里上一条 assistant 消息:以问号结尾 / 含"回复 X / 你看 / 是否 / 请确认 / 请选" → 视为对你提问的回答
|
|
@@ -482,7 +482,7 @@
|
|
|
482
482
|
- **禁止**:本轮重新走"加载 skill / 询问意图 / 查 app 详情 / 列能力清单"的初始化流程
|
|
483
483
|
- **例外**:用户消息明显是新任务("换个项目"、"算了别部署了"、"先停下"),按新任务处理
|
|
484
484
|
- 信号词识别:"继续 / check / OK / 完成了吗 / 现在怎样 / 进度 / 试 X" 这类短词 → 多半属于回答;超过一句完整描述新任务的才算 fresh intent
|
|
485
|
-
33. **`rainbond_update_component_build_source` 只改 DB 不触发检测**,调完之后下一个
|
|
485
|
+
33. **`rainbond_update_component_build_source` 只改 DB 不触发检测**,调完之后下一个 Rainbond 写调用**必须**是 `rainbond_check_component(service_id=..., is_again=true)`,不允许中间夹任何其他工具,也不允许跳过它直接读 check_result 或调 build。
|
|
486
486
|
背景(必读):后端 `update_component_build_source` 视图仅把 `git_url`/`subdirectories`/`code_version`/凭证字段写进 DB(`service.save()` 结束),**没有调用 `app_check_service.check_service`**。因此:
|
|
487
487
|
- 改完 build_source 后调 `rainbond_get_component_check_result` → 返回的依然是**上一轮**(最初 create 时)的 `check_uuid` 和 "源码目录不存在" 旧结果,给人"我的修改没生效"的假象,实际是检测根本没重跑
|
|
488
488
|
- 改完 build_source 后调 `rainbond_build_component` → 组件还停留在 `service_source=source_code` + 上轮检测未通过的状态,build 任务会被卡在 `checking`,无法真正启动
|
|
@@ -502,7 +502,7 @@
|
|
|
502
502
|
- `update_component_build_source` → `build_component`(中间没 `check_component`,组件仍 `checking`,build 必失败)
|
|
503
503
|
- 多次 `update_component_build_source` 之间不夹 `check_component`(等价于在改了 DB 但没触发检测的情况下又改一遍,每次轮询的还是同一个旧 `check_uuid`)
|
|
504
504
|
与 Iron Law 30 配套:30 管"换参数重试"的预算(同 `service_cname` 最多 2 次 create / 同 service_id 同字段最多 N 次 update),33 管"改完后必须走完一个完整 check 闭环"。两者一起堵住"猜参数 → 改了又不重检测 → 又看到旧错误 → 再猜"的死循环。
|
|
505
|
-
34. **service_id provenance:任何
|
|
505
|
+
34. **service_id provenance:任何 Rainbond 写工具传入的 `service_id` 必须有明确出处**,不允许凭模型记忆或上下文里飘着的 UUID 猜。
|
|
506
506
|
合法的 `service_id` 来源(按优先级):
|
|
507
507
|
- 本会话内 `rainbond_query_components` 的返回结果(最新一次)
|
|
508
508
|
- 本会话内 `rainbond_create_component_*` 工具的返回值
|
|
@@ -513,7 +513,7 @@
|
|
|
513
513
|
- 用户消息里粘的、但本会话没验证过的 ID
|
|
514
514
|
强制流程:动手前如果不能 100% 确定 `service_id` 出处,**第一动作**必须是 `rainbond_query_components({enterprise_id, app_id})`,必要时携带 `query=<service_cname 或 service_id>`,按 `service_cname` 或 `k8s_component_name` 匹配出真实 `service_id`,再调写工具。
|
|
515
515
|
反例(**禁止**):日志里出现"修改组件 `7059eb62cccc3a16f22c9415c905bbcc` 的构建源" — 这个 ID 在本会话所有 query 结果里都没出现过,是模型从某处幻觉出来的。正确做法:调 update 之前先 `rainbond_query_components` 拿到真实 `service_id`,再 update。
|
|
516
|
-
与 Iron Law 31 配套:31 管"
|
|
516
|
+
与 Iron Law 31 配套:31 管"写工具前必须加载对应专项手册",34 管"写工具的 service_id 必须有明确出处"。两条共同把"模型自由发挥参数"这条路堵死。
|
|
517
517
|
|
|
518
518
|
**同样的 provenance 规则对 `event_id` 生效**:调 `rainbond_get_component_build_logs` / `rainbond_get_app_upgrade_record` 等需要 `event_id` 的工具时,`event_id` 必须是**真实 UUID**(如 `805f6397871d467b968d14c3575082a6`),合法来源仅限:
|
|
519
519
|
- 本会话内 `rainbond_get_component_events` 返回的 `events[*].event_id`
|
|
@@ -528,10 +528,10 @@
|
|
|
528
528
|
|
|
529
529
|
反例(来自真实回归 case `cs_1779149681822_3u`,2026-05-19):模型从 `rainbond_get_component_summary` 响应的 `recent_events` 段看到形如 `{"ID": 17740, "event_id": "...", "opt_type": "build-service"}`,直接把 `17740` 当成 `event_id` 传给 `rainbond_get_component_build_logs`,工具返回 `items: []`(找不到该 UUID 的日志)。正确做法:从同一 `recent_events[i].event_id` 字段取出 UUID 字符串,或调 `rainbond_get_component_events` 重查。
|
|
530
530
|
35. **会话内部叙述纪律 + 内部 preflight 工具不要主动调**。下列四类是"内部会话状态",对用户**无信息量**,禁止外漏到 assistant 可见消息:
|
|
531
|
-
-
|
|
532
|
-
- **`rainbond_get_current_user`**:不得由 Agent
|
|
533
|
-
- **`rainbond_query_components` 同入参重复轮询**:服务端 30s 内的同 args 调用会走缓存;你**不要**在每个新 user turn 开头都"先查一下组件列表"
|
|
534
|
-
- **规则推理过程 /
|
|
531
|
+
- **专项 Skill 手册加载过程**:这是当前任务的内部准备。不要说"我先加载 bootstrap 手册"、"手册已加载"或"skill ready";读完直接进入下一个真实工具调用。
|
|
532
|
+
- **`rainbond_get_current_user`**:不得由 Agent 单独调用。`enterprise_id`、`team_id`、`team_name` 和 `region_name` 统一由受保护的 `context resolve` 命令无状态解析并由当前任务携带;只有 CLI 明确返回需要选择时才询问用户。
|
|
533
|
+
- **`rainbond_query_components` 同入参重复轮询**:服务端 30s 内的同 args 调用会走缓存;你**不要**在每个新 user turn 开头都"先查一下组件列表"。只有本次调用使用的 `enterprise_id`、`app_id` 和查询条件均未变化,且没有新的平台动作时,才可复用 priorTurnMessages 里的最近结果。
|
|
534
|
+
- **规则推理过程 / Rainbond Tool 内部限制 / 分类决策叙述**:你内部基于哪条 Iron Law / hard rule / 推断信号做的决策、具体 Tool 签名 / 字段限制、对组件 / 服务的分类判断("ClickHouse 是公认的列式分析数据库"这类),都属于内部状态,对用户**无信息量**。
|
|
535
535
|
|
|
536
536
|
**禁止**这类叙述(来自真实回归 case 的典型模式):
|
|
537
537
|
- "ClickHouse 是公认的列式分析数据库,属于基础设施软件,按 image 模式创建"
|
|
@@ -554,10 +554,10 @@
|
|
|
554
554
|
|
|
555
555
|
> rainagent 运行时通过 server-side "最终覆盖规则" 段也强制了同一条规则;本条主要服务 CLI / Codex 端使用者(他们没有 runtime tail 注入)。
|
|
556
556
|
|
|
557
|
-
|
|
557
|
+
**同一个专项 Skill 在 session 内最多读取一次(跨 user turn 也算)**,但**切换到不同阶段时必须读取新阶段的专项 Skill**。判断方式:如果当前会话已经完整读取过该专项 `SKILL.md` 及本次需要的 supporting resources,就直接复用;若阶段从 bootstrap 变为 troubleshooter,则读取 troubleshooter 的手册后继续。
|
|
558
558
|
|
|
559
|
-
|
|
560
|
-
|
|
559
|
+
反例(**禁止**):上一轮已经完整读取 `rainbond-fullstack-bootstrap`,本轮 user 简短回复 "java/jar",又重新读取同一手册并叙述"先加载 bootstrap"。正确做法:直接 `rainbond_update_component_build_source(...)` 继续。
|
|
560
|
+
正例:上一轮处于 bootstrap,本轮用户说"组件起不来帮我排查下" → 阶段变为 troubleshooter → 完整读取 `rainbond-fullstack-troubleshooter` 后进入诊断,不复述内部加载过程。
|
|
561
561
|
36. **用户给出的字面值(URL / 镜像地址 / 分支名 / 凭证)必须 verbatim 传给工具,禁止 LLM 凭训练知识"补全"、"修正"、"猜测"**。
|
|
562
562
|
适用字段:`git_url` / `image`(用户所说的镜像地址映射到 Console Tool 的 `image` 字段)/ `code_version`(分支/tag/commit)/ `username` / `password` / `token` / `subdirectories` 等任何用户在消息里给出的字面值。
|
|
563
563
|
**禁止行为**:
|
|
@@ -565,7 +565,7 @@
|
|
|
565
565
|
- 用户给的 URL 没 `.git` 后缀就自动加上
|
|
566
566
|
- 用户给的 URL 是 `gitee.com/xxx/yyy`,你"知道这个仓库其实在 GitHub" 就改成 `github.com/...`
|
|
567
567
|
- 用户给了主仓库 URL(`https://gitee.com/rainbond/sourcecode-examples`),你把它换成你以为的子项目独立仓库(`https://gitee.com/some-org/java-maven-demo.git`)—— 同一个仓库下的不同子项目应该用**同一个 URL + subdirectories 参数**区分,而不是换 URL
|
|
568
|
-
- 用户没说分支,你自己写 `code_version=main` 或 `master` 当默认值(应该让后端/
|
|
568
|
+
- 用户没说分支,你自己写 `code_version=main` 或 `master` 当默认值(应该让后端/Tool 默认值生效,传 `master` 的前提是用户说过 master 或者你是 carrying over 从已有组件 build_source 拿到的字面值)
|
|
569
569
|
|
|
570
570
|
**正确做法**:
|
|
571
571
|
- 用户消息里出现的 URL/分支/凭证,**逐字符 copy** 传给工具
|
|
@@ -624,7 +624,7 @@
|
|
|
624
624
|
- 与 Iron Law 14(delivery mode 切换必须用户确认)配套:14 管 source↔package↔image↔template 的策略切换需用户确认,38 管"用户已经显式给了源码意图时,模板不是默认路径、且切换必须清理残留"。
|
|
625
625
|
39. **轮次纪律:复用已知值,不重复无变化的调用**(与 Iron Law 35 的"内部 preflight 工具不要主动调"配套,35 管哪些工具不该调,39 管已拿到的值要复用):
|
|
626
626
|
- **复用创建返回的 `service_id` / `service_alias`**:`rainbond_create_component_*` 成功后会返回 `service_id` 和 `service_alias`(k8s component name),**记住并在本轮后续 mutating 操作里直接复用**。**禁止**在每次 `rainbond_manage_component_*` / `rainbond_operate_app` 之前都先 `rainbond_query_components` 重查一遍 alias —— 创建时已经返回过,重查只是浪费轮次(仅当 `service_id` 出处不明、按 Iron Law 34 必须重新建立 provenance 时才查)。
|
|
627
|
-
- **不重复调 `rainbond_get_current_user
|
|
627
|
+
- **不重复调 `rainbond_get_current_user`**:复用当前任务直接携带的 enterprise/team/region 参数;只有唯一运行环境变化、上下文失效或用户明确切换目标时才重新执行无状态 `context resolve`。
|
|
628
628
|
- **同一 mutating 调用成功后禁止原样重复**:一个写工具用相同入参成功返回后,不要在同一轮再发一次相同调用"确认一下"——成功就是成功,要确认状态用读工具(`rainbond_get_component_summary` 等),不要重发写调用。
|
|
629
629
|
40. **对外访问地址必须引用工具返回的真实值,禁止按格式拼装。** 组件的对外访问地址是**事实信息**,权威来源是 `rainbond_get_component_detail` 或 `rainbond_get_component_summary` 返回的 `access_infos` 字段(都来自网关真实绑定)。只需状态和访问地址时优先调用轻量的 detail;只有异常组件确实需要端口、env、存储或事件证据时才调用 summary。
|
|
630
630
|
- 本轮已通过上述任一工具拿到真实地址 → 报告里引用 `access_infos` 的真实值。
|
|
@@ -652,28 +652,28 @@
|
|
|
652
652
|
|
|
653
653
|
### 触发时机
|
|
654
654
|
|
|
655
|
-
|
|
655
|
+
在主线流程进入每个专项阶段的**第一个动作之前**,从主机的可用 Skills 清单定位并完整读取对应专项 Skill 的 `SKILL.md`,再按其渐进加载规则读取本次需要的 supporting resources。同一个专项 Skill 在同一会话内只读一次。具体映射:
|
|
656
656
|
|
|
657
|
-
| 主线阶段 | 触发条件 |
|
|
657
|
+
| 主线阶段 | 触发条件 | 必须读取的专项 Skill |
|
|
658
658
|
|---------|---------|---------------|
|
|
659
|
-
| 步骤 3:topology 创建 | linked 但拓扑/组件不存在;或要从源码/镜像/包创建/补齐组件 | `
|
|
660
|
-
| 步骤 4:运行态排障 | 组件已存在但运行不健康;构建失败、CrashLoopBackOff、ImagePullBackOff 等 | `
|
|
661
|
-
| 步骤 5:交付验收 | 运行态健康,剩下的问题是用户能否访问、URL 是否可达、文件是否落盘等 | `
|
|
662
|
-
| 步骤 6:dev-to-test promotion | 已 `delivered`,用户要求创建快照 + 测试 app | `
|
|
663
|
-
| 模板安装路径 | 用户要求安装本地/云端 Rainbond 应用模板到目标 app | `
|
|
659
|
+
| 步骤 3:topology 创建 | linked 但拓扑/组件不存在;或要从源码/镜像/包创建/补齐组件 | `rainbond-fullstack-bootstrap` |
|
|
660
|
+
| 步骤 4:运行态排障 | 组件已存在但运行不健康;构建失败、CrashLoopBackOff、ImagePullBackOff 等 | `rainbond-fullstack-troubleshooter` |
|
|
661
|
+
| 步骤 5:交付验收 | 运行态健康,剩下的问题是用户能否访问、URL 是否可达、文件是否落盘等 | `rainbond-delivery-verifier` |
|
|
662
|
+
| 步骤 6:dev-to-test promotion | 已 `delivered`,用户要求创建快照 + 测试 app | `rainbond-app-version-assistant` |
|
|
663
|
+
| 模板安装路径 | 用户要求安装本地/云端 Rainbond 应用模板到目标 app | `rainbond-template-installer` |
|
|
664
664
|
|
|
665
|
-
###
|
|
665
|
+
### 加载语义
|
|
666
666
|
|
|
667
|
-
-
|
|
668
|
-
-
|
|
669
|
-
-
|
|
670
|
-
-
|
|
667
|
+
- 手册读取是本地只读动作,无需用户审批;它不是 Rainbond Tool 调用
|
|
668
|
+
- 读取后必须严格按专项 Skill 的判断顺序、术语、输出契约执行,并只加载其明确路由到的 supporting resources
|
|
669
|
+
- 阶段可以顺序叠加(例如 bootstrap → troubleshooter),新阶段手册在阶段性细节冲突时优先
|
|
670
|
+
- 只在确认进入对应阶段后读取专项手册,不要把加载动作当作能力探索
|
|
671
671
|
|
|
672
672
|
### 边界
|
|
673
673
|
|
|
674
674
|
- 顶层路由判断("用户的意图是不是部署/排障/交付")仍然由本 skill 负责,不要在专项 skill 加载之后回头改路由
|
|
675
675
|
- 工具行为约束(如本 skill 硬规则第 30 条"源码失败后必须先 query 不能直接重 create")即使在专项 skill 加载之后仍然有效,专项 skill 只是补充更细的操作规则
|
|
676
|
-
- `rainbond-project-init` 是 workspace 型 skill,只在 Claude/Codex CLI
|
|
676
|
+
- `rainbond-project-init` 是 workspace 型 skill,只在 Claude/Codex CLI 等有本地项目目录的客户端有意义;Web 端没有本地项目目录时,主线遇到 unlinked 直接停下来让用户在 UI 中绑定项目
|
|
677
677
|
|
|
678
678
|
## 停止条件
|
|
679
679
|
|
|
@@ -683,6 +683,6 @@
|
|
|
683
683
|
- team / app 选择仍然有歧义
|
|
684
684
|
- source ref 无效
|
|
685
685
|
- 多组件源码检测需要显式策略选择
|
|
686
|
-
-
|
|
686
|
+
- Rainbond Tool / 控制面后端异常
|
|
687
687
|
- `delivery-verifier` 结果只是 `delivered-but-needs-manual-validation`
|
|
688
688
|
- 进入 `code_or_build_handoff_needed`
|
|
@@ -19,7 +19,7 @@ OPEN_STAGE_ROWS = (
|
|
|
19
19
|
"[source acquisition](references/source-acquisition.md) |",
|
|
20
20
|
"| 官方部署清单已验证,首次需要连接或调用 Rainbond | 只读取自己的 "
|
|
21
21
|
"[runtime gate](references/runtime-gate.md) |",
|
|
22
|
-
"|
|
|
22
|
+
"| workspace context 已解析,需要建模、部署、排障或交付 app/component | 读取 "
|
|
23
23
|
"[deployment workflow](references/deployment-workflow.md) |",
|
|
24
24
|
"| 新鲜证据命中已知部署故障模式 | 再读取 "
|
|
25
25
|
"[failure-mode playbook](references/failure-mode-playbook.md) |",
|
|
@@ -520,7 +520,7 @@ def validate_routing_conflicts(
|
|
|
520
520
|
|
|
521
521
|
stage_conflict = any(pre_inventory_rainbond_action(statement) for statement in statements(staged_loading)) or any(
|
|
522
522
|
contains(statement, "deployment workflow")
|
|
523
|
-
and contains(statement, "
|
|
523
|
+
and contains(statement, "workspace context")
|
|
524
524
|
and ("前" in statement or "before" in statement)
|
|
525
525
|
and not has_negation(statement)
|
|
526
526
|
for statement in statements(staged_loading)
|
|
@@ -15,8 +15,8 @@ APP_INITIAL_STAGE = (
|
|
|
15
15
|
"[own runtime gate](references/runtime-gate.md)、"
|
|
16
16
|
"[routing](references/routing.md) | 其余全部 |"
|
|
17
17
|
)
|
|
18
|
-
|
|
19
|
-
"|
|
|
18
|
+
APP_CONTEXT_STAGE = (
|
|
19
|
+
"| workspace context 已解析,需要编排或执行 app/component | "
|
|
20
20
|
"[workflow rules](references/workflow-rules.md);仅在核对路线或复盘时读取 "
|
|
21
21
|
"[operational reference](references/operational-reference.md) | 输出与对象细节 |"
|
|
22
22
|
)
|
|
@@ -68,10 +68,10 @@ def validate_progressive_loading(skill_dir: Path) -> list[str]:
|
|
|
68
68
|
require((skill_dir / relative_path).is_file(), f"missing {relative_path}", failures)
|
|
69
69
|
|
|
70
70
|
require(APP_INITIAL_STAGE in root, "App initial stage mapping is invalid", failures)
|
|
71
|
-
require(
|
|
72
|
-
if APP_INITIAL_STAGE in root and
|
|
71
|
+
require(APP_CONTEXT_STAGE in root, "App stateless context stage mapping is invalid", failures)
|
|
72
|
+
if APP_INITIAL_STAGE in root and APP_CONTEXT_STAGE in root:
|
|
73
73
|
require(
|
|
74
|
-
root.index(APP_INITIAL_STAGE) < root.index(
|
|
74
|
+
root.index(APP_INITIAL_STAGE) < root.index(APP_CONTEXT_STAGE),
|
|
75
75
|
"App stage mapping must load the runtime gate before workflow rules",
|
|
76
76
|
failures,
|
|
77
77
|
)
|
|
@@ -14,10 +14,12 @@ description: "Use when a user explicitly asks for an existing Rainbond app versi
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: "Use when a user explicitly asks for an existing Rainbond app versi
|
|
|
74
76
|
"rainbond-app-version-assistant"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: "Use when a user explicitly asks for an existing Rainbond app versi
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|
|
@@ -46,10 +46,12 @@ description: "Use only when the user explicitly asks for final delivery or acces
|
|
|
46
46
|
|
|
47
47
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
48
48
|
|
|
49
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
50
|
+
|
|
49
51
|
```json
|
|
50
52
|
{
|
|
51
53
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
52
|
-
"package_version": "rainskills@0.1.
|
|
54
|
+
"package_version": "rainskills@0.1.26",
|
|
53
55
|
"runtime_status": [
|
|
54
56
|
"node",
|
|
55
57
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -106,10 +108,9 @@ description: "Use only when the user explicitly asks for final delivery or acces
|
|
|
106
108
|
"rainbond-delivery-verifier"
|
|
107
109
|
],
|
|
108
110
|
"stdin": {
|
|
109
|
-
"required": [
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
]
|
|
111
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
112
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
113
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
113
114
|
}
|
|
114
115
|
},
|
|
115
116
|
"read": {
|
|
@@ -162,7 +163,7 @@ description: "Use only when the user explicitly asks for final delivery or acces
|
|
|
162
163
|
|
|
163
164
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
164
165
|
|
|
165
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
166
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
166
167
|
|
|
167
168
|
<!-- rainskills-runtime-routing:start -->
|
|
168
169
|
## 缺少运行环境时
|
|
@@ -14,10 +14,12 @@ description: "Use when a user explicitly asks to sync non-sensitive preview or p
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: "Use when a user explicitly asks to sync non-sensitive preview or p
|
|
|
74
76
|
"rainbond-env-sync"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: "Use when a user explicitly asks to sync non-sensitive preview or p
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|
|
@@ -14,10 +14,12 @@ description: "Use only when the user explicitly asks to create the Rainbond app
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: "Use only when the user explicitly asks to create the Rainbond app
|
|
|
74
76
|
"rainbond-fullstack-bootstrap"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: "Use only when the user explicitly asks to create the Rainbond app
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|
|
@@ -240,8 +240,8 @@ Follow this transaction in the exact order below:
|
|
|
240
240
|
- capture the helper's `archive_path`, `file_name`, `generated`, and `staging_root` result fields
|
|
241
241
|
- a supported package file is reused directly; a directory is converted to a zip archive by the helper
|
|
242
242
|
2. Call `rainbond_init_package_upload` with Rainbond context only. It must return a non-empty `event_id` and an `upload_request`. Do not continue when either is absent or malformed.
|
|
243
|
-
3. Run the protected local CLI command `package-upload --archive <archive_path> --input - --
|
|
244
|
-
- the CLI resolves the Console origin from the
|
|
243
|
+
3. Run the protected local CLI command `package-upload --archive <archive_path> --input - --skill-id rainbond-fullstack-bootstrap` using the fixed CLI launcher defined by the active Skill, passing the complete `upload_request` object through stdin as JSON:
|
|
244
|
+
- the CLI resolves the Console origin from the protected single-runtime store; never ask the user for `RAINBOND_URL` and never take it from the current shell
|
|
245
245
|
- do not add `RAINBOND_URL`, JWT, upload credentials, or a Console address to argv or stdin
|
|
246
246
|
- do not invent or rewrite the URL, authorization mode, form field, HTTP method, content type, or timeout; the CLI validates the same-Console-origin upload contract before invoking the local helper
|
|
247
247
|
4. Run `upload_local_package.py cleanup` immediately after the HTTP attempt returns, whether upload succeeded, failed, or timed out. Pass the captured `archive_path`, `staging_root`, and `generated` flag. This cleanup must finish or be reported before any upload-status or component-create call.
|
|
@@ -46,10 +46,12 @@ description: "Use only when the user explicitly asks for a bounded build, runtim
|
|
|
46
46
|
|
|
47
47
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
48
48
|
|
|
49
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
50
|
+
|
|
49
51
|
```json
|
|
50
52
|
{
|
|
51
53
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
52
|
-
"package_version": "rainskills@0.1.
|
|
54
|
+
"package_version": "rainskills@0.1.26",
|
|
53
55
|
"runtime_status": [
|
|
54
56
|
"node",
|
|
55
57
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -106,10 +108,9 @@ description: "Use only when the user explicitly asks for a bounded build, runtim
|
|
|
106
108
|
"rainbond-fullstack-troubleshooter"
|
|
107
109
|
],
|
|
108
110
|
"stdin": {
|
|
109
|
-
"required": [
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
]
|
|
111
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
112
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
113
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
113
114
|
}
|
|
114
115
|
},
|
|
115
116
|
"read": {
|
|
@@ -162,7 +163,7 @@ description: "Use only when the user explicitly asks for a bounded build, runtim
|
|
|
162
163
|
|
|
163
164
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
164
165
|
|
|
165
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
166
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
166
167
|
|
|
167
168
|
<!-- rainskills-runtime-routing:start -->
|
|
168
169
|
## 缺少运行环境时
|
|
@@ -27,10 +27,10 @@ description: "Use when the user supplies a third-party Docker Compose file/conte
|
|
|
27
27
|
|---|---|
|
|
28
28
|
| Phase 0:归属已确认、部署清单尚未验证 | 只读取 [source acquisition](references/source-acquisition.md) |
|
|
29
29
|
| 官方部署清单已验证,首次需要连接或调用 Rainbond | 只读取自己的 [runtime gate](references/runtime-gate.md) |
|
|
30
|
-
|
|
|
30
|
+
| workspace context 已解析,需要建模、部署、排障或交付 app/component | 读取 [deployment workflow](references/deployment-workflow.md) |
|
|
31
31
|
| 新鲜证据命中已知部署故障模式 | 再读取 [failure-mode playbook](references/failure-mode-playbook.md) |
|
|
32
32
|
|
|
33
|
-
正确顺序是:先验证官方部署清单,再加载 Runtime Gate。这里只允许加载本 Skill 的 Gate
|
|
33
|
+
正确顺序是:先验证官方部署清单,再加载 Runtime Gate。这里只允许加载本 Skill 的 Gate。workspace context 包含 `enterprise_id`、`team_id`、`team_name` 和 `region_name`;app/component 标识只来自用户明确输入或本次实时查询/创建结果。它们都由当前任务携带,不得生成 CLI 业务 operation ID、运行环境 ID 或 intent JSON。
|
|
34
34
|
|
|
35
35
|
## Runtime 与安全边界
|
|
36
36
|
|
|
@@ -43,7 +43,7 @@ description: "Use when the user supplies a third-party Docker Compose file/conte
|
|
|
43
43
|
|
|
44
44
|
## 执行边界
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
解析 workspace context 后,按 [deployment workflow](references/deployment-workflow.md) 执行 **per-component image modeling**:Compose、Helm 和 installer-generated topology 都是证据来源,不是必须走的平台黑盒导入路径。配置组件、显式依赖、配置文件与存储后再部署,等待终态,有限修复,并通过真实入口和 UI/core smoke。只有证据匹配已知故障时才读取 [failure-mode playbook](references/failure-mode-playbook.md)。
|
|
47
47
|
|
|
48
48
|
Helm is evidence, not a deployment path。不得因 Rainbond Helm 解析失败就停止,也不得在没有确认上传全链路时承诺“改用 Compose”;先判断能否根据官方证据逐组件建模。配置、初始化任务、特权能力或存储语义无法完整映射时,在创建裸组件之前停止。
|
|
49
49
|
|
|
@@ -11,10 +11,12 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
11
11
|
|
|
12
12
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
13
13
|
|
|
14
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
15
|
+
|
|
14
16
|
```json
|
|
15
17
|
{
|
|
16
18
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
17
|
-
"package_version": "rainskills@0.1.
|
|
19
|
+
"package_version": "rainskills@0.1.26",
|
|
18
20
|
"runtime_status": [
|
|
19
21
|
"node",
|
|
20
22
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -71,10 +73,9 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
71
73
|
"rainbond-opensource-app-deploy"
|
|
72
74
|
],
|
|
73
75
|
"stdin": {
|
|
74
|
-
"required": [
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
]
|
|
76
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
77
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
78
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
78
79
|
}
|
|
79
80
|
},
|
|
80
81
|
"read": {
|
|
@@ -127,7 +128,7 @@ Canonical progressive-loading contract: `rainskills.skill-runtime-contract.v1`.
|
|
|
127
128
|
|
|
128
129
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
129
130
|
|
|
130
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
131
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
131
132
|
|
|
132
133
|
<!-- rainskills-runtime-routing:start -->
|
|
133
134
|
## 缺少运行环境时
|
|
@@ -32,7 +32,7 @@ Do not use it to deploy an application to an existing Rainbond. Route those requ
|
|
|
32
32
|
## Workflow
|
|
33
33
|
|
|
34
34
|
1. Read [installation-policy.md](references/installation-policy.md).
|
|
35
|
-
2. Use the installed local launcher `["node", "<home>/.rainbond/lib/rainskills/bin/rainskills.js"]`; its protected runtime package marker is `rainskills@0.1.
|
|
35
|
+
2. Use the installed local launcher `["node", "<home>/.rainbond/lib/rainskills/bin/rainskills.js"]`; its protected runtime package marker is `rainskills@0.1.26` and must equal this package's `package.json`. For a Rainskills marker, first validate schema `rainskills.next-action.v1`, action, onboarding id, and the bounded `argv` array, then append that array to the launcher. Never use `latest` or evaluate a shell string from output.
|
|
36
36
|
3. 业务 Skill 的四项运行环境菜单会把本机或独立服务器选择写入 `rainskills.next-action.v1` 的显式 `--location`;收到这类 next-action 后直接执行固定 argv,不得再次调用 `private-deployment-location`。只有用户直接要求安装 Rainbond 平台且尚未选择部署位置时,才执行 launcher + `["runtime", "message", "--id", "private-deployment-location"]` 并原样输出固定的三项部署位置消息:选择 1 后执行带 `["--location", "local", "--mode", "single-node"]` 的 `platform install`;选择 2 后执行带 `["--location", "server"]` 的 `platform install`,由 helper 继续显示固定的服务器类型消息;选择 3 后执行 launcher + `["runtime", "message", "--id", "private-console-origin"]` 并进入已有环境连接,不得执行 `platform install`。平台安装 onboarding 只保存安装断点,不保存或恢复业务 intent。
|
|
37
37
|
4. Let the helper perform one read-only preflight against the already selected local or remote target, then show resources, blockers, and applicable host changes. Never invoke `platform install` without an explicit `--location`; the helper must not ask for the deployment location again.
|
|
38
38
|
5. 主机集群开始前必须获得 explicit confirmation,并使用受限 AI 交接:首次调用在固定安装 argv 后追加 `--agent-handoff`,记录该子进程会话;用户确认后,使用相同固定 argv 追加 `--agent-handoff --yes` 一次。不得向等待进程写入 `y`、不得启动第二个竞争安装、不得 `kill` 安装进程,也不得让用户复制完整安装或恢复命令。用户取消时,仅使用同一 argv 追加 `--agent-handoff --cancel`;它只能清除匹配的待确认状态,不能建立 SSH 连接或修改服务器。
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "rainskills.platform-installation-policy.v2",
|
|
3
|
-
"recommended": {
|
|
4
|
-
"cpu_cores": 4,
|
|
5
|
-
"memory_bytes": 8589934592,
|
|
6
|
-
"disk_bytes": 53687091200
|
|
7
|
-
},
|
|
8
3
|
"minimums": {
|
|
9
4
|
"cpu_cores": 2,
|
|
10
5
|
"memory_bytes": 4294967296,
|
|
11
|
-
"disk_bytes":
|
|
6
|
+
"disk_bytes": 10737418240
|
|
12
7
|
},
|
|
13
8
|
"required_ports": [80, 443, 7070],
|
|
14
9
|
"supported_control_platforms": ["linux", "darwin", "win32"],
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
- 控制端支持 Linux、macOS 和 Windows;Rainbond 目标支持 Linux、macOS,以及 Windows 本地预览路径中的专用 WSL2 环境。
|
|
8
8
|
- Linux `x64` / `arm64`:选择“部署到本机”时安装到当前设备;选择“部署到独立服务器”时通过 SSH 安装到其他 Linux 服务器。不提供回车默认项。
|
|
9
|
-
- macOS `x64` / `arm64
|
|
9
|
+
- macOS `x64` / `arm64`:可安装到当前 Mac,也可选择独立 Linux 服务器。
|
|
10
10
|
- Windows:与其他控制端使用同一份“部署到本机 / 部署到独立服务器 / 部署到已有 Rainbond”选择;本机路径目前为 preview,只支持 Windows 10 build 19041+ / Windows 11 x64 工作站。
|
|
11
|
-
-
|
|
11
|
+
- 预检最低门槛为 2 核 CPU、4 GB 内存、10 GB 可用磁盘。达到最低门槛时继续安装,最终以 Rainbond 实际部署验证为准。
|
|
12
12
|
- 安装前端口 `80`、`443`、`7070` 必须空闲。
|
|
13
13
|
|
|
14
14
|
远程单机只接受 `user@host` 或 `~/.ssh/config` 主机别名;ROI 主机集群逐节点使用配置中的 root 地址和端口。两种方式都先用 `BatchMode=yes` 检查现有免密连接。远程单机检查失败时固定输出一条版本锁定的 `ssh prepare`;主机集群先检查全部节点,再一次列出所有未就绪节点并输出一条版本锁定的 `ssh prepare-cluster --cluster-config`。用户只在自己电脑的系统终端执行,OpenSSH 读取每台服务器的指纹确认和一次密码;命令只准备公钥连接,不安装 Rainbond。全部完成后只统一回复一次“已完成”。恢复后所有 `ssh` / `scp` 均为免密非交互调用。Rainskills 不接收聊天中的 SSH 密码或私钥,也不支持离线安装或自动清理冲突环境。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 安装问题处理
|
|
2
2
|
|
|
3
|
-
-
|
|
3
|
+
- **资源不足**:低于预检最低门槛(2 核 / 4 GB / 10 GB)时停止安装,否则继续。最终以 Rainbond 实际部署验证结果为准。
|
|
4
4
|
- **端口占用**:停止安装,提示用户处理占用 `80`、`443`、`7070` 的服务,不主动停止服务。
|
|
5
5
|
- **已有 Rainbond**:停止新安装,建议返回 Rainskills 选择“已经有,填写平台地址”。
|
|
6
6
|
- **权限不足**:Linux 需要 root 或已经可用的 `sudo -n`,不得在聊天中索取密码。
|
|
@@ -1094,10 +1094,8 @@ function gibibytes(bytes) {
|
|
|
1094
1094
|
|
|
1095
1095
|
function evaluatePreflight(facts) {
|
|
1096
1096
|
const blockers = [];
|
|
1097
|
-
const warnings = [];
|
|
1098
1097
|
const effects = [];
|
|
1099
1098
|
const minimums = POLICY.minimums;
|
|
1100
|
-
const recommended = POLICY.recommended;
|
|
1101
1099
|
if (!POLICY.supported_platforms.includes(facts.platform)) {
|
|
1102
1100
|
blockers.push(`不支持当前系统 ${facts.platform},首版仅支持 Linux 和 macOS`);
|
|
1103
1101
|
}
|
|
@@ -1106,18 +1104,12 @@ function evaluatePreflight(facts) {
|
|
|
1106
1104
|
}
|
|
1107
1105
|
if (facts.cpuCores < minimums.cpu_cores) {
|
|
1108
1106
|
blockers.push(`CPU 最低需要 ${minimums.cpu_cores} 核,当前 ${facts.cpuCores} 核`);
|
|
1109
|
-
} else if (facts.cpuCores < recommended.cpu_cores) {
|
|
1110
|
-
warnings.push(`CPU ${facts.cpuCores} 核低于推荐配置 ${recommended.cpu_cores} 核`);
|
|
1111
1107
|
}
|
|
1112
1108
|
if (facts.memoryBytes < minimums.memory_bytes) {
|
|
1113
1109
|
blockers.push(`内存最低需要 ${gibibytes(minimums.memory_bytes).toFixed(0)} GB,当前 ${gibibytes(facts.memoryBytes).toFixed(1)} GB`);
|
|
1114
|
-
} else if (facts.memoryBytes < recommended.memory_bytes) {
|
|
1115
|
-
warnings.push(`内存 ${gibibytes(facts.memoryBytes).toFixed(1)} GB 低于推荐配置 ${gibibytes(recommended.memory_bytes).toFixed(0)} GB`);
|
|
1116
1110
|
}
|
|
1117
1111
|
if (facts.diskBytes < minimums.disk_bytes) {
|
|
1118
1112
|
blockers.push(`可用磁盘最低需要 ${gibibytes(minimums.disk_bytes).toFixed(0)} GB,当前 ${gibibytes(facts.diskBytes).toFixed(1)} GB`);
|
|
1119
|
-
} else if (facts.diskBytes < recommended.disk_bytes) {
|
|
1120
|
-
warnings.push(`可用磁盘 ${gibibytes(facts.diskBytes).toFixed(1)} GB 低于推荐配置 ${gibibytes(recommended.disk_bytes).toFixed(0)} GB`);
|
|
1121
1113
|
}
|
|
1122
1114
|
if (facts.occupiedPorts.length > 0) blockers.push(`端口 ${facts.occupiedPorts.join("、")} 已被占用`);
|
|
1123
1115
|
if (facts.platform === "linux" && !facts.hasPrivilege) blockers.push("Linux 安装需要 root 或已配置可用的 sudo -n 权限");
|
|
@@ -1135,7 +1127,7 @@ function evaluatePreflight(facts) {
|
|
|
1135
1127
|
}
|
|
1136
1128
|
effects.push("启动 privileged rainbond 容器并写入持久化数据");
|
|
1137
1129
|
|
|
1138
|
-
return { ok: blockers.length === 0, blockers,
|
|
1130
|
+
return { ok: blockers.length === 0, blockers, effects };
|
|
1139
1131
|
}
|
|
1140
1132
|
|
|
1141
1133
|
function extractConsoleUrl(output) {
|
|
@@ -1720,7 +1712,6 @@ function preflightMessage(facts, assessment, target) {
|
|
|
1720
1712
|
"",
|
|
1721
1713
|
`${facts.cpuCores} 核 CPU / ${gibibytes(facts.memoryBytes).toFixed(1)} GB 内存 / ${gibibytes(facts.diskBytes).toFixed(1)} GB 可用磁盘`,
|
|
1722
1714
|
];
|
|
1723
|
-
if (facts.platform === "darwin") lines.push("macOS 安装依赖 OrbStack,首次准备时间通常比 Linux 更长。");
|
|
1724
1715
|
if (!assessment.ok) {
|
|
1725
1716
|
lines.push("", "需要先处理:", ...assessment.blockers.map((blocker) => `- ${blocker}`));
|
|
1726
1717
|
return lines.join("\n");
|
|
@@ -9,6 +9,7 @@ const LOCATIONS = new Set(["local", "server"]);
|
|
|
9
9
|
const SERVER_MODES = new Set(["single-node", "host-cluster", "existing-kubernetes"]);
|
|
10
10
|
const LEGACY_TARGETS = new Set(["local-linux", "local-macos", "local-windows", "remote-linux"]);
|
|
11
11
|
const LOCAL_TARGETS = new Set(["local-linux", "local-macos", "local-windows"]);
|
|
12
|
+
const SSH_TARGET_PROMPT = "Linux SSH 地址(例如 root@192.168.1.20 或主机别名)";
|
|
12
13
|
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f-\u009f]/u;
|
|
13
14
|
const CREDENTIAL_LIKE_VALUE = /^(?:gh[pousr]_|github_pat_|xox[baprs]-|sk-[A-Za-z0-9_-]{16,}|AKIA[A-Z0-9]{12,}|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+$)/i;
|
|
14
15
|
|
|
@@ -181,7 +182,7 @@ function writeMissingSsh(write) {
|
|
|
181
182
|
writeUserMessage(
|
|
182
183
|
write,
|
|
183
184
|
"platform.server-ssh",
|
|
184
|
-
|
|
185
|
+
SSH_TARGET_PROMPT,
|
|
185
186
|
);
|
|
186
187
|
}
|
|
187
188
|
|
|
@@ -291,7 +292,7 @@ async function selectPlatformRoute({
|
|
|
291
292
|
});
|
|
292
293
|
}
|
|
293
294
|
while (!remoteHost) {
|
|
294
|
-
remoteHost = (await ask(
|
|
295
|
+
remoteHost = (await ask(`${SSH_TARGET_PROMPT}: `)).trim();
|
|
295
296
|
if (!remoteHost) write("SSH 地址不能为空。\n");
|
|
296
297
|
}
|
|
297
298
|
}
|
|
@@ -789,9 +789,7 @@ function evaluateWindowsPreflight(facts, policy, expectedUserSid) {
|
|
|
789
789
|
if (!windowsPolicy) throw new Error("缺少 Windows 安装策略");
|
|
790
790
|
|
|
791
791
|
const blockers = [];
|
|
792
|
-
const warnings = [];
|
|
793
792
|
const minimums = policy.minimums;
|
|
794
|
-
const recommended = policy.recommended;
|
|
795
793
|
if (!windowsPolicy.supported_product_types.includes(facts.productType)) {
|
|
796
794
|
blockers.push("仅支持 Windows 工作站版本,当前系统不是受支持的 Windows 工作站");
|
|
797
795
|
}
|
|
@@ -808,18 +806,12 @@ function evaluateWindowsPreflight(facts, policy, expectedUserSid) {
|
|
|
808
806
|
if (!facts.uacEnabled) blockers.push("必须启用 Windows UAC,才能安全执行需要管理员权限的固定操作");
|
|
809
807
|
if (Number(facts.cpuCores) < minimums.cpu_cores) {
|
|
810
808
|
blockers.push(`CPU 最低需要 ${minimums.cpu_cores} 核,当前 ${Number(facts.cpuCores) || 0} 核`);
|
|
811
|
-
} else if (Number(facts.cpuCores) < recommended.cpu_cores) {
|
|
812
|
-
warnings.push(`CPU ${Number(facts.cpuCores) || 0} 核低于推荐配置 ${recommended.cpu_cores} 核`);
|
|
813
809
|
}
|
|
814
810
|
if (Number(facts.memoryBytes) < minimums.memory_bytes) {
|
|
815
811
|
blockers.push(`内存最低需要 ${gibibytes(minimums.memory_bytes).toFixed(0)} GB,当前 ${gibibytes(facts.memoryBytes).toFixed(1)} GB`);
|
|
816
|
-
} else if (Number(facts.memoryBytes) < recommended.memory_bytes) {
|
|
817
|
-
warnings.push(`内存 ${gibibytes(facts.memoryBytes).toFixed(1)} GB 低于推荐配置 ${gibibytes(recommended.memory_bytes).toFixed(0)} GB`);
|
|
818
812
|
}
|
|
819
813
|
if (Number(facts.diskBytes) < minimums.disk_bytes) {
|
|
820
814
|
blockers.push(`可用磁盘最低需要 ${gibibytes(minimums.disk_bytes).toFixed(0)} GB,当前 ${gibibytes(facts.diskBytes).toFixed(1)} GB`);
|
|
821
|
-
} else if (Number(facts.diskBytes) < recommended.disk_bytes) {
|
|
822
|
-
warnings.push(`可用磁盘 ${gibibytes(facts.diskBytes).toFixed(1)} GB 低于推荐配置 ${gibibytes(recommended.disk_bytes).toFixed(0)} GB`);
|
|
823
815
|
}
|
|
824
816
|
if (!facts.virtualizationEnabled) blockers.push("未检测到可用的固件虚拟化,请先在 BIOS/UEFI 中启用虚拟化");
|
|
825
817
|
if (facts.wslInstalled && !windowsPolicy.networking_modes.includes(String(facts.wslNetworkingMode || "").toLowerCase())) {
|
|
@@ -856,7 +848,6 @@ function evaluateWindowsPreflight(facts, policy, expectedUserSid) {
|
|
|
856
848
|
return {
|
|
857
849
|
ok: blockers.length === 0,
|
|
858
850
|
blockers,
|
|
859
|
-
warnings,
|
|
860
851
|
effects: [
|
|
861
852
|
"启用 WSL 2 和虚拟机平台组件(可能需要重启 Windows)",
|
|
862
853
|
"安装或更新经过验证的 WSL 运行时",
|
|
@@ -14,10 +14,12 @@ description: Use for a user-requested, read-only Rainbond platform query about t
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: Use for a user-requested, read-only Rainbond platform query about t
|
|
|
74
76
|
"rainbond-platform-query"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: Use for a user-requested, read-only Rainbond platform query about t
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|
|
@@ -14,10 +14,12 @@ description: "Use only when the user explicitly asks to initialize or link a loc
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: "Use only when the user explicitly asks to initialize or link a loc
|
|
|
74
76
|
"rainbond-project-init"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: "Use only when the user explicitly asks to initialize or link a loc
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|
|
@@ -14,10 +14,12 @@ description: "Use when the user explicitly asks to install a local or cloud Rain
|
|
|
14
14
|
|
|
15
15
|
`context resolve` 是无状态调用:单一工作空间直接返回上下文,多个候选返回组合选项;用户选择后由当前任务直接携带 team/region 参数,不执行 `context select`,不写本地 operation。所有可变 `call` 仍需先取得 confirmation ID,再以完全相同的输入追加 `--confirm` 执行一次。
|
|
16
16
|
|
|
17
|
+
`required` 只声明要解析的维度,企业 ID 始终来自当前登录身份。用户明确给出的 team/region 必须放进 `hints` 做精确匹配;不得把企业名、team 名或选择对象作为顶层 `enterprise` / `workspace` 字段传入。多候选时只展示 CLI 返回的 label;用户选择后再次执行同一个无状态 `context resolve`,通过 `selection.option_id` 让 CLI 重新查询并验证当前候选,不写本地 context 状态。
|
|
18
|
+
|
|
17
19
|
```json
|
|
18
20
|
{
|
|
19
21
|
"schema": "rainskills.single-runtime-contract.v1",
|
|
20
|
-
"package_version": "rainskills@0.1.
|
|
22
|
+
"package_version": "rainskills@0.1.26",
|
|
21
23
|
"runtime_status": [
|
|
22
24
|
"node",
|
|
23
25
|
"<home>/.rainbond/lib/rainskills/bin/rainskills.js",
|
|
@@ -74,10 +76,9 @@ description: "Use when the user explicitly asks to install a local or cloud Rain
|
|
|
74
76
|
"rainbond-template-installer"
|
|
75
77
|
],
|
|
76
78
|
"stdin": {
|
|
77
|
-
"required": [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
]
|
|
79
|
+
"default": {"required": ["enterprise", "workspace"]},
|
|
80
|
+
"with_hints": {"required": ["enterprise", "workspace"], "hints": {"team_name": "<team-name>"}},
|
|
81
|
+
"with_selection": {"required": ["enterprise", "workspace"], "selection": {"option_id": "<option-id>"}}
|
|
81
82
|
}
|
|
82
83
|
},
|
|
83
84
|
"read": {
|
|
@@ -130,7 +131,7 @@ description: "Use when the user explicitly asks to install a local or cloud Rain
|
|
|
130
131
|
|
|
131
132
|
`runtime connect` 的 Device Flow 不依赖 stdin TTY;Agent 必须执行固定 argv 并保持进程附着直到授权完成。能打开本机浏览器时由连接器自动跳转,SSH、容器等无浏览器场景原样展示授权地址并继续轮询。只有 Rainbond 不支持 Device Flow 且进入旧版 loopback 手动粘贴时才需要交互终端;不得要求用户在聊天中粘贴 JWT。
|
|
132
133
|
|
|
133
|
-
执行优化:同一会话内只检查一次 Node.js
|
|
134
|
+
执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.js、Rainskills、PATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
|
|
134
135
|
|
|
135
136
|
<!-- rainskills-runtime-routing:start -->
|
|
136
137
|
## 缺少运行环境时
|