rainskills 0.1.25 → 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 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.25`,不会执行浮动的 `@latest` 业务代码。新版本原子刷新已经安装的 Rainskills Skills;当前业务继续使用启动时已经加载的版本,最迟从下一条新任务开始使用新版。npm 超时、版本检查失败、安装位置不安全或文件迁移失败时会保留旧版本,且不会阻塞或改变当前操作。
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.25`):
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>`。
@@ -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
- && !/[\u0000-\u001f\u007f-\u009f]/u.test(value)
1023
+ && !CONTROL_CHARACTER_PATTERN.test(value)
1021
1024
  ? value
1022
1025
  : null;
1023
1026
  }
1024
1027
 
1025
- async function resolveStatelessContext(input, config) {
1026
- const required = input?.required;
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 (options.length === 1) {
1075
- const option = options[0];
1076
- return {
1077
- state: "resolved",
1078
- context: {
1079
- enterprise_id: enterpriseId,
1080
- team_id: option.team_id,
1081
- team_name: option.team_name,
1082
- region_name: option.region_name,
1083
- },
1084
- };
1085
- }
1086
- return { state: "needs-selection", dimension: "workspace-region", options };
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) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rainskills",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "Install the complete Rainskills AI deployment skill suite as one product.",
5
5
  "author": {
6
6
  "name": "Goodrain",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rainskills",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "Install the complete Rainskills AI deployment skill suite as one product.",
5
5
  "author": {
6
6
  "name": "Goodrain",
@@ -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.25 <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.
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.25`):
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": "rainskills",
3
- "version": "0.1.25",
3
+ "version": "0.1.26",
4
4
  "description": "Interactive Rainbond skill installer for Codex, Claude Code, and Pi Agent",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/goodrain/rainskills#readme",
@@ -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, or a named application that is not identified as a third-party open-source suite. 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."
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) 做静态归属判断。只加载最终所属 Skill 的 Runtime Gate,不得读取相邻 Skill 的 Gate。
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
- | operation/context 已建立,需要编排或执行 | [workflow rules](references/workflow-rules.md);仅在核对路线或复盘时读取 [operational reference](references/operational-reference.md) | 输出与对象细节 |
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
- 这里的 operation/context 是当前任务内的业务操作与 team/region/app 上下文;不得生成或传递 CLI 业务 operation ID、运行环境 ID 或 intent JSON。
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 或授权边界,也不得读取相邻 Skill Gate
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
- 详细主线、operation/context 复用、代理规则、构建/运行时证据链、依赖、确认边界与尝试预算只在需要执行时读取 [workflow rules](references/workflow-rules.md)。
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.25",
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
- "enterprise",
76
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
131
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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 MCP 工具边界都要把十进制字符串 `app_id` 规范化为正整数;非数字 ID 必须拒绝。
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. 当前 MCP 不支持显式 `dockerfile_path` 时,不要在顶层编排里承诺该能力。
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` — 不要回答"MCP 没有依赖接口";调用失败时按 MCP/控制面真实错误报告,不要描述为工具不存在
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 是允许的,但**禁止**回显原始文件内容或密钥明文,只报结构化不一致。文件内容无法用当前 MCP 能力读取时,显式标注覆盖风险并停下来让用户确认,不要默默改 env 就当成功
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
- - 不能通过 MCP 对它们执行重启、部署、修改等写操作;当前 MCP 工具集不支持此类操作
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 MCP 写工具调用之前**,必须先按下面的映射调用对应的 `select_skill_<id>` 工具,把该阶段的执行手册加载进会话上下文;没先调 `select_skill_<id>` 就直接动手等于**无授权操作**,是 Iron Law 违反。
461
- 触发动作(凡是这类,第一次调之前都必须先 `select_skill_<id>`):
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) → 在第一个 MCP 写调用之前调 `select_skill_rainbond-fullstack-bootstrap`
468
- - 当前 run 是**排查运行态/构建失败**(CrashLoopBackOff / ImagePullBackOff / 构建报错 / 端口/依赖不通) → 在第一个 MCP 写调用之前调 `select_skill_rainbond-fullstack-troubleshooter`
469
- - 当前 run 是**交付验收**(验证 URL 可达、reverse-proxy 路径连通) → `select_skill_rainbond-delivery-verifier`
470
- - 当前 run 是**开发到测试 promotion**(创建快照 + 测试 app) → `select_skill_rainbond-app-version-assistant`
471
- - 当前 run 是**模板安装**(本地/云端 Rainbond 应用模板) → `select_skill_rainbond-template-installer`
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
- - `select_skill_<id>` 本身不需用户审批、不消耗 MCP,但它的调用是**前置门控**,没调不允许走下去
474
- - 一个 skill 在同一次 run 内只需调一次(重复调用工具会返回 "already active" ack)
475
- - **判断依据**:用户消息中只要含"部署 / 跑起来 / 上线 / 创建组件 / 发布"等部署意图,且当前 app 还没有对应组件,就必然要先 `select_skill_rainbond-fullstack-bootstrap`,不论用户是不是显式说"先 deep dive"
476
- - 如果一次 run 内场景跨阶段(先创建后排障),按需追加 `select_skill_<id>`,旧的不会被卸载
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 不触发检测**,调完之后下一个 MCP 写调用**必须**是 `rainbond_check_component(service_id=..., is_again=true)`,不允许中间夹任何其他工具,也不允许跳过它直接读 check_result 或调 build。
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:任何 MCP 写工具传入的 `service_id` 必须有明确出处**,不允许凭模型记忆或上下文里飘着的 UUID 猜。
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 管"写工具前必须 select skill",34 管"写工具的 service_id 必须有明确出处"。两条共同把"模型自由发挥参数"这条路堵死。
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
- - **`select_skill_*` 工具调用本身**:这是 server 内部 hookup,把指定 skill 的执行手册拼到 system prompt 用的。调用前**不要**说"我先加载 bootstrap 手册"、"现在调用 select_skill_...";调用后**不要**说"Bootstrap 手册已加载""skill ready" 这类回声。server 返回的 `loaded_skill` / `already active` ack 是给你看的内部信号,**直接进入下一个真实工具调用**,保持沉默。
532
- - **`rainbond_get_current_user`**:不得由 Agent 单独调用。企业、工作空间和集群上下文统一由受保护的 `context resolve` 命令解析并绑定到本次 operation;只有 CLI 明确返回需要选择时才询问用户。
533
- - **`rainbond_query_components` 同入参重复轮询**:服务端 30s 内的同 args 调用会走缓存;你**不要**在每个新 user turn 开头都"先查一下组件列表",priorTurnMessages 里上一次的 query 结果在 contextSignature 不变时仍然有效。
534
- - **规则推理过程 / MCP 工具内部限制 / 分类决策叙述**:你内部基于哪条 Iron Law / hard rule / 推断信号做的决策、具体 MCP 工具签名 / 字段限制、对组件 / 服务的分类判断("ClickHouse 是公认的列式分析数据库"这类),都属于内部状态,对用户**无信息量**。
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
- **同一个 `<skill_id>` 在 session 内最多 select 一次(跨 user turn 也算)**,但**不同 skill 之间切换永远允许**(典型流程:bootstrap 部署 → troubleshooter 排障 → delivery-verifier 验收 → version-assistant promote,每切一个阶段调一次新的 select_skill_<id>)。判断方式:如果当前会话的 priorTurnMessages 里已经出现过该 `skill_id` `loaded_skill` `already active` tool_result,**不要再调** `select_skill_<that-same-id>`;但如果你要切到另一个 skill_id(如从 bootstrap 切到 troubleshooter),就**必须**调 `select_skill_<new-id>` 一次。
557
+ **同一个专项 Skill 在 session 内最多读取一次(跨 user turn 也算)**,但**切换到不同阶段时必须读取新阶段的专项 Skill**。判断方式:如果当前会话已经完整读取过该专项 `SKILL.md` 及本次需要的 supporting resources,就直接复用;若阶段从 bootstrap 变为 troubleshooter,则读取 troubleshooter 的手册后继续。
558
558
 
559
- 反例(**禁止**):上一轮已经 `select_skill_rainbond-fullstack-bootstrap` 过了,本轮 user 简短回复 "java/jar",你又调一次 `select_skill_rainbond-fullstack-bootstrap` 并叙述"先加载 bootstrap"。正确做法:priorTurnMessages 已有 ack → 直接 `rainbond_update_component_build_source(...)` 继续。
560
- 正例:上一轮 `select_skill_rainbond-fullstack-bootstrap`,本轮用户说"组件起不来帮我排查下" → 现在阶段从部署切到排障调一次 `select_skill_rainbond-fullstack-troubleshooter`(新 skill,允许)→ 沉默地进入诊断流程,不复述"troubleshooter 已加载"。
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` 当默认值(应该让后端/MCP 默认值生效,传 `master` 的前提是用户说过 master 或者你是 carrying over 从已有组件 build_source 拿到的字面值)
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`**:同一 operation 复用 `context resolve` 已保存的企业、工作空间和集群上下文;只有上下文失效或用户明确切换目标时才重新解析。
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
- 在主线流程进入每个专项阶段的**第一个动作之前**,调用对应的 `select_skill_<id>` 工具一次(同一个 skill 在同一次 run 内只需调一次,后续都已生效)。具体映射:
655
+ 在主线流程进入每个专项阶段的**第一个动作之前**,从主机的可用 Skills 清单定位并完整读取对应专项 Skill 的 `SKILL.md`,再按其渐进加载规则读取本次需要的 supporting resources。同一个专项 Skill 在同一会话内只读一次。具体映射:
656
656
 
657
- | 主线阶段 | 触发条件 | 必须先调的工具 |
657
+ | 主线阶段 | 触发条件 | 必须读取的专项 Skill |
658
658
  |---------|---------|---------------|
659
- | 步骤 3:topology 创建 | linked 但拓扑/组件不存在;或要从源码/镜像/包创建/补齐组件 | `select_skill_rainbond-fullstack-bootstrap` |
660
- | 步骤 4:运行态排障 | 组件已存在但运行不健康;构建失败、CrashLoopBackOff、ImagePullBackOff 等 | `select_skill_rainbond-fullstack-troubleshooter` |
661
- | 步骤 5:交付验收 | 运行态健康,剩下的问题是用户能否访问、URL 是否可达、文件是否落盘等 | `select_skill_rainbond-delivery-verifier` |
662
- | 步骤 6:dev-to-test promotion | 已 `delivered`,用户要求创建快照 + 测试 app | `select_skill_rainbond-app-version-assistant` |
663
- | 模板安装路径 | 用户要求安装本地/云端 Rainbond 应用模板到目标 app | `select_skill_rainbond-template-installer` |
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
- - `select_skill_<id>` 是当前会话的载入指令,不消耗 MCP 工具,无副作用,无需用户审批
668
- - 调用后该 skill 的完整执行手册立即进入系统提示,后续动作必须严格按该 skill 的判断顺序、术语、输出契约执行
669
- - 多个专项 skill 可以叠加加载(例如 bootstrap → 发现需要排障 → 再 `select_skill_rainbond-fullstack-troubleshooter`),新加载的 skill 在主题冲突时优先级更高
670
- - 不能用调用 `select_skill_<id>` 来"探索这个 skill 是什么意思"——只在确认要进入对应阶段时调用
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 等有本地项目目录的客户端有意义;在 Web rainagent 中**不存在** `select_skill_rainbond-project-init`,主线遇到 unlinked 时直接停下来让用户在 UI 中绑定项目
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
- - MCP / 控制面后端异常
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
- "| operation/context 已建立,需要建模、部署、排障或交付 | 读取 "
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, "operation context")
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
- APP_OPERATION_STAGE = (
19
- "| operation/context 已建立,需要编排或执行 | "
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(APP_OPERATION_STAGE in root, "App operation/context stage mapping is invalid", failures)
72
- if APP_INITIAL_STAGE in root and APP_OPERATION_STAGE in root:
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(APP_OPERATION_STAGE),
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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25",
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
- "enterprise",
111
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
166
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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 - --operation-id <uuid> --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 environment already bound to the protected operation; never ask the user for `RAINBOND_URL` and never take it from the current shell
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.25",
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
- "enterprise",
111
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
166
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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
- | operation/context 已建立,需要建模、部署、排障或交付 | 读取 [deployment workflow](references/deployment-workflow.md) |
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;operation/context 是当前任务内的 team/region/app 上下文,不得生成 CLI 业务 operation ID、运行环境 ID 或 intent JSON。
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
- 建立 operation/context 后,按 [deployment workflow](references/deployment-workflow.md) 执行 **per-component image modeling**:Compose、Helm 和 installer-generated topology 都是证据来源,不是必须走的平台黑盒导入路径。配置组件、显式依赖、配置文件与存储后再部署,等待终态,有限修复,并通过真实入口和 UI/core smoke。
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.25",
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
- "enterprise",
76
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
131
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25` 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.
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,5 +1,5 @@
1
1
  "use strict";
2
2
 
3
3
  module.exports = Object.freeze({
4
- version: "0.1.25",
4
+ version: "0.1.26",
5
5
  });
@@ -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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍按其契约刷新环境列表;平台只读查询未指定环境时由 CLI 使用全局默认环境,不枚举环境。带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 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.25",
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
- "enterprise",
79
- "workspace"
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(首次使用本地 CLI 前);仅在 Node.jsRainskills 安装、升级,或 PATH 变更后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。每个新的业务操作仍需要刷新一次环境列表;带已有 `operation_id` 或 `onboarding-id` 的续接复用已绑定的环境 ID,不重复枚举环境。
134
+ 执行优化:同一会话内只检查一次 Node.js 和运行环境状态;仅在 Node.jsRainskillsPATH 或唯一运行环境发生变化后失效。固定 launcher 和 argv 已在本 Skill 中,禁止读取、搜索或探测 `rainskills.js`,也禁止执行 `npm root -g`。
134
135
 
135
136
  <!-- rainskills-runtime-routing:start -->
136
137
  ## 缺少运行环境时