@josephyan/qingflow-app-builder-mcp 1.1.4 → 1.1.5
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 +6 -5
- package/docs/local-agent-install.md +57 -6
- package/entry_point.py +1 -1
- package/npm/bin/qingflow-app-builder-mcp.mjs +2 -33
- package/npm/bin/qingflow-skills.mjs +5 -0
- package/npm/lib/runtime.mjs +21 -101
- package/npm/scripts/postinstall.mjs +1 -10
- package/package.json +3 -2
- package/pyproject.toml +1 -1
- package/skills/qingflow-app-builder/SKILL.md +51 -34
- package/skills/qingflow-app-builder/references/complete-system-development-guide.md +123 -0
- package/skills/qingflow-app-builder/references/create-app.md +19 -6
- package/skills/qingflow-app-builder/references/environments.md +1 -1
- package/skills/qingflow-app-builder/references/gotchas.md +14 -6
- package/skills/qingflow-app-builder/references/match-rules.md +15 -0
- package/skills/qingflow-app-builder/references/single-app-development-guide.md +58 -0
- package/skills/qingflow-app-builder/references/solution-playbooks.md +10 -0
- package/skills/qingflow-app-builder/references/tool-selection.md +21 -22
- package/skills/qingflow-app-builder/references/update-flow.md +22 -38
- package/skills/qingflow-app-builder/references/update-schema.md +3 -0
- package/skills/qingflow-app-builder/references/update-views.md +34 -14
- package/skills/qingflow-app-builder/scripts/validate_system_build_summary.py +124 -0
- package/skills/qingflow-app-builder-code-integrations/SKILL.md +5 -3
- package/skills/qingflow-app-builder-code-integrations/references/code-block.md +1 -1
- package/skills/qingflow-app-builder-code-integrations/references/q-linker.md +1 -1
- package/src/qingflow_mcp/__init__.py +1 -1
- package/src/qingflow_mcp/__main__.py +6 -2
- package/src/qingflow_mcp/builder_facade/models.py +282 -102
- package/src/qingflow_mcp/builder_facade/service.py +4166 -929
- package/src/qingflow_mcp/cli/commands/builder.py +316 -298
- package/src/qingflow_mcp/cli/commands/chart.py +1 -1
- package/src/qingflow_mcp/cli/commands/common.py +12 -3
- package/src/qingflow_mcp/cli/commands/exports.py +2 -2
- package/src/qingflow_mcp/cli/commands/imports.py +3 -3
- package/src/qingflow_mcp/cli/commands/portal.py +2 -2
- package/src/qingflow_mcp/cli/commands/record.py +101 -27
- package/src/qingflow_mcp/cli/commands/task.py +28 -47
- package/src/qingflow_mcp/cli/commands/view.py +1 -1
- package/src/qingflow_mcp/cli/context.py +0 -3
- package/src/qingflow_mcp/cli/formatters.py +784 -16
- package/src/qingflow_mcp/cli/main.py +117 -33
- package/src/qingflow_mcp/errors.py +43 -2
- package/src/qingflow_mcp/public_surface.py +26 -17
- package/src/qingflow_mcp/response_trim.py +81 -17
- package/src/qingflow_mcp/server.py +14 -12
- package/src/qingflow_mcp/server_app_builder.py +65 -21
- package/src/qingflow_mcp/server_app_user.py +22 -16
- package/src/qingflow_mcp/session_store.py +11 -7
- package/src/qingflow_mcp/solution/compiler/__init__.py +3 -1
- package/src/qingflow_mcp/solution/compiler/workflow_compiler.py +173 -0
- package/src/qingflow_mcp/solution/executor.py +245 -18
- package/src/qingflow_mcp/tools/ai_builder_tools.py +1780 -406
- package/src/qingflow_mcp/tools/app_tools.py +184 -43
- package/src/qingflow_mcp/tools/approval_tools.py +197 -35
- package/src/qingflow_mcp/tools/auth_tools.py +92 -16
- package/src/qingflow_mcp/tools/code_block_tools.py +298 -40
- package/src/qingflow_mcp/tools/custom_button_tools.py +64 -10
- package/src/qingflow_mcp/tools/directory_tools.py +236 -72
- package/src/qingflow_mcp/tools/export_tools.py +244 -34
- package/src/qingflow_mcp/tools/feedback_tools.py +9 -0
- package/src/qingflow_mcp/tools/file_tools.py +9 -3
- package/src/qingflow_mcp/tools/import_tools.py +336 -49
- package/src/qingflow_mcp/tools/navigation_tools.py +91 -12
- package/src/qingflow_mcp/tools/package_tools.py +118 -6
- package/src/qingflow_mcp/tools/portal_tools.py +39 -3
- package/src/qingflow_mcp/tools/qingbi_report_tools.py +116 -7
- package/src/qingflow_mcp/tools/record_tools.py +1141 -356
- package/src/qingflow_mcp/tools/resource_read_tools.py +188 -39
- package/src/qingflow_mcp/tools/role_tools.py +80 -9
- package/src/qingflow_mcp/tools/solution_tools.py +59 -45
- package/src/qingflow_mcp/tools/task_context_tools.py +662 -158
- package/src/qingflow_mcp/tools/task_tools.py +113 -29
- package/src/qingflow_mcp/tools/view_tools.py +106 -3
- package/src/qingflow_mcp/tools/workflow_tools.py +48 -4
- package/src/qingflow_mcp/tools/workspace_tools.py +71 -3
- package/skills/qingflow-app-builder/references/build-complete-system.md +0 -428
- package/skills/qingflow-app-builder/references/build-single-app.md +0 -530
- package/skills/qingflow-mcp-setup/SKILL.md +0 -111
- package/skills/qingflow-mcp-setup/agents/openai.yaml +0 -4
- package/skills/qingflow-mcp-setup/references/claude-desktop.md +0 -34
- package/skills/qingflow-mcp-setup/references/environments.md +0 -61
- package/skills/qingflow-mcp-setup/references/generic-stdio.md +0 -31
- package/skills/qingflow-mcp-setup/scripts/check_local_server.sh +0 -38
- package/skills/qingflow-workflow-builder/SKILL.md +0 -96
- package/skills/qingflow-workflow-builder/manifest.yaml +0 -8
- package/skills/qingflow-workflow-builder/references/01-overview.md +0 -45
- package/skills/qingflow-workflow-builder/references/02-update-mode.md +0 -53
- package/skills/qingflow-workflow-builder/references/03-flow-patterns.md +0 -57
- package/skills/qingflow-workflow-builder/references/04-stage1-business-modeling.md +0 -131
- package/skills/qingflow-workflow-builder/references/05-stage2-members-roles.md +0 -29
- package/skills/qingflow-workflow-builder/references/06-stage3-build-spec.md +0 -165
- package/skills/qingflow-workflow-builder/references/07-stage4-validate-spec.md +0 -33
- package/skills/qingflow-workflow-builder/references/08-stage5-apply-verify.md +0 -51
- package/skills/qingflow-workflow-builder/references/09-stage6-summary.md +0 -88
- package/skills/qingflow-workflow-builder/references/10-node-config-reference.md +0 -93
- package/skills/qingflow-workflow-builder/references/11-troubleshooting.md +0 -15
- package/skills/qingflow-workflow-builder/scripts/diff_flow_spec.py +0 -275
- package/skills/qingflow-workflow-builder/scripts/validate_flow_spec.py +0 -605
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
Install:
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
|
-
npm install @josephyan/qingflow-app-builder-mcp@1.1.
|
|
6
|
+
npm install @josephyan/qingflow-app-builder-mcp@1.1.5
|
|
7
7
|
```
|
|
8
8
|
|
|
9
9
|
Run:
|
|
10
10
|
|
|
11
11
|
```bash
|
|
12
|
-
npx -y -p @josephyan/qingflow-app-builder-mcp@1.1.
|
|
12
|
+
npx -y -p @josephyan/qingflow-app-builder-mcp@1.1.5 qingflow-app-builder-mcp
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Environment:
|
|
@@ -24,11 +24,12 @@ Bundled skills:
|
|
|
24
24
|
|
|
25
25
|
- `skills/qingflow-app-builder`
|
|
26
26
|
- `skills/qingflow-app-builder-code-integrations`
|
|
27
|
-
- `skills/qingflow-workflow-builder`
|
|
28
|
-
- `skills/qingflow-mcp-setup`
|
|
29
27
|
|
|
30
28
|
Note:
|
|
31
29
|
|
|
32
30
|
- The skill files are included in the npm package.
|
|
33
|
-
-
|
|
31
|
+
- Installing the npm package does not overwrite agent skills automatically.
|
|
32
|
+
- To mount bundled skills from an installed package, run `qingflow-app-builder-mcp-skills install --agent codex --scope user`.
|
|
33
|
+
- For one-shot `npx -p` installs, prefer `--copy` because symlinks would point into the npm execution cache.
|
|
34
|
+
- Use `qingflow-app-builder-mcp-skills list` to inspect bundled skills. The installer defaults to symlinks for stable package installs and refuses to overwrite existing skills unless `--force` is provided.
|
|
34
35
|
- If a stdio MCP client reports `Transport closed`, delete `.npm-python`, reinstall the package, and make sure CLI/user/builder packages are on the same version. The stdio entrypoints refuse runtime bootstrap so install logs never corrupt MCP stdout.
|
|
@@ -101,7 +101,51 @@ npm install /absolute/path/to/dist/npm/qingflow-tech-qingflow-app-builder-mcp-<v
|
|
|
101
101
|
1. 创建 `.npm-python/`
|
|
102
102
|
2. 在其中建立 Python 虚拟环境
|
|
103
103
|
3. 执行 `pip install .`
|
|
104
|
-
4.
|
|
104
|
+
4. 在安装位置暴露对应入口:CLI 包暴露 `qingflow` / `qingflow-skills`;app-user 包暴露 `qingflow-app-user-mcp` / `qingflow-app-user-mcp-skills`;app-builder 包暴露 `qingflow-app-builder-mcp` / `qingflow-app-builder-mcp-skills`
|
|
105
|
+
5. 携带 `skills/<skill-name>/SKILL.md`,但不在 `postinstall` 阶段自动覆盖本机 agent skills
|
|
106
|
+
|
|
107
|
+
## Skills 挂载
|
|
108
|
+
|
|
109
|
+
显式查看包内 skills:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
qingflow-skills list
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
独立 MCP split 包使用包专属 skills 命令,避免全局安装多个包时发生 bin 覆盖:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
qingflow-app-user-mcp-skills list
|
|
119
|
+
qingflow-app-builder-mcp-skills list
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
显式挂载到 Codex 用户目录:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
qingflow-skills install --agent codex --scope user
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
如果通过一次性 `npx -p <package>` 执行安装,请加 `--copy`,避免 symlink 指向 npm 临时执行缓存:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
npx -y -p @qingflow-tech/qingflow-cli qingflow-skills install --agent codex --scope user --copy
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
也可以挂载到项目级 agent 目录:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
qingflow-skills install --agent claude-code --scope project
|
|
138
|
+
qingflow-skills install --agent cursor --scope project --copy
|
|
139
|
+
qingflow-skills install --agent all --scope project
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
默认行为:
|
|
143
|
+
|
|
144
|
+
- `--mode symlink`:使用 symlink,让 npm 包版本成为单一来源
|
|
145
|
+
- `--scope user`:安装到用户级 agent skills 目录
|
|
146
|
+
- `--agent codex`:目标 agent 为 Codex
|
|
147
|
+
- 不覆盖已有同名 skill;需要替换时显式加 `--force`
|
|
148
|
+
- 每次安装会在目标 skills 目录下写入 `.qingflow-skill-sources/<skill>.json`,记录 package、version、source、destination、agent、scope、mode
|
|
105
149
|
|
|
106
150
|
## 本地验证
|
|
107
151
|
|
|
@@ -110,24 +154,31 @@ npm install /absolute/path/to/dist/npm/qingflow-tech-qingflow-app-builder-mcp-<v
|
|
|
110
154
|
```bash
|
|
111
155
|
cd qingflow-support/mcp-server
|
|
112
156
|
node ./npm/bin/qingflow.mjs --help
|
|
157
|
+
node ./npm/bin/qingflow-skills.mjs list
|
|
113
158
|
node ./npm/bin/qingflow-app-user-mcp.mjs
|
|
114
159
|
node ./npm/bin/qingflow-app-builder-mcp.mjs
|
|
115
160
|
```
|
|
116
161
|
|
|
117
|
-
|
|
162
|
+
如果你是全局安装对应包:
|
|
118
163
|
|
|
119
164
|
```bash
|
|
120
165
|
qingflow --help
|
|
166
|
+
qingflow-skills list
|
|
121
167
|
qingflow-app-user-mcp
|
|
168
|
+
qingflow-app-user-mcp-skills list
|
|
122
169
|
qingflow-app-builder-mcp
|
|
170
|
+
qingflow-app-builder-mcp-skills list
|
|
123
171
|
```
|
|
124
172
|
|
|
125
|
-
如果你是把包安装到了某个本地 agent workspace
|
|
173
|
+
如果你是把包安装到了某个本地 agent workspace,安装对应包后命令通常位于:
|
|
126
174
|
|
|
127
175
|
```bash
|
|
128
176
|
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow
|
|
177
|
+
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow-skills
|
|
129
178
|
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow-app-user-mcp
|
|
179
|
+
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow-app-user-mcp-skills
|
|
130
180
|
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow-app-builder-mcp
|
|
181
|
+
/absolute/path/to/agent-workspace/node_modules/.bin/qingflow-app-builder-mcp-skills
|
|
131
182
|
```
|
|
132
183
|
|
|
133
184
|
如果你是从 tgz 安装到某个空目录,命令通常位于:
|
|
@@ -217,7 +268,7 @@ qingflow-app-builder-mcp
|
|
|
217
268
|
"command": "npx",
|
|
218
269
|
"args": [
|
|
219
270
|
"-y",
|
|
220
|
-
"@
|
|
271
|
+
"@qingflow-tech/qingflow-app-user-mcp"
|
|
221
272
|
],
|
|
222
273
|
"env": {
|
|
223
274
|
"QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
|
|
@@ -230,7 +281,7 @@ qingflow-app-builder-mcp
|
|
|
230
281
|
"command": "npx",
|
|
231
282
|
"args": [
|
|
232
283
|
"-y",
|
|
233
|
-
"@
|
|
284
|
+
"@qingflow-tech/qingflow-app-builder-mcp"
|
|
234
285
|
],
|
|
235
286
|
"env": {
|
|
236
287
|
"QINGFLOW_MCP_DEFAULT_BASE_URL": "https://qingflow.com/api",
|
|
@@ -272,7 +323,7 @@ npm install
|
|
|
272
323
|
|
|
273
324
|
如果 MCP 客户端一调用工具就报 `Transport closed`,优先检查这几件事:
|
|
274
325
|
|
|
275
|
-
1. 不要混用不同版本的 `@
|
|
326
|
+
1. 不要混用不同版本的 `@qingflow-tech/qingflow-cli`、`@qingflow-tech/qingflow-app-user-mcp`、`@qingflow-tech/qingflow-app-builder-mcp`
|
|
276
327
|
2. 删除安装目录下的 `.npm-python`
|
|
277
328
|
3. 重新执行 `npm install` 或重新安装对应 tgz/npm 包
|
|
278
329
|
4. 再启动 MCP 客户端
|
package/entry_point.py
CHANGED
|
@@ -7,7 +7,7 @@ src_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "src"))
|
|
|
7
7
|
if src_path not in sys.path:
|
|
8
8
|
sys.path.insert(0, src_path)
|
|
9
9
|
|
|
10
|
-
from qingflow_mcp.
|
|
10
|
+
from qingflow_mcp.server_app_user import main
|
|
11
11
|
|
|
12
12
|
if __name__ == "__main__":
|
|
13
13
|
main()
|
|
@@ -1,38 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
2
|
|
|
6
|
-
|
|
7
|
-
qingflow: "qingflow-cli",
|
|
8
|
-
"qingflow-app-user-mcp": "qingflow-app-user-mcp",
|
|
9
|
-
"qingflow-app-builder-mcp": "qingflow-app-builder-mcp",
|
|
10
|
-
};
|
|
3
|
+
import { getPackageRoot, spawnServer } from "../lib/runtime.mjs";
|
|
11
4
|
|
|
12
|
-
function resolvePackageModule(metaUrl, ...segments) {
|
|
13
|
-
const scriptPath = fileURLToPath(metaUrl);
|
|
14
|
-
const scriptDir = path.dirname(scriptPath);
|
|
15
|
-
// bin files live in <pkg>/npm/bin/, runtime.mjs lives in the sibling <pkg>/npm/lib/,
|
|
16
|
-
// so step up one level before joining the requested segments.
|
|
17
|
-
const direct = path.join(scriptDir, "..", ...segments);
|
|
18
|
-
if (fs.existsSync(direct)) {
|
|
19
|
-
return pathToFileURL(direct).href;
|
|
20
|
-
}
|
|
21
|
-
if (path.basename(scriptDir) === ".bin") {
|
|
22
|
-
const binName = path.basename(scriptPath);
|
|
23
|
-
const pkgName = PKG_BY_BIN[binName];
|
|
24
|
-
if (!pkgName) {
|
|
25
|
-
throw new Error(`Unknown qingflow command: ${binName}`);
|
|
26
|
-
}
|
|
27
|
-
const scope = process.env.QINGFLOW_NPM_SCOPE || "@josephyan";
|
|
28
|
-
const fromBin = path.join(scriptDir, "..", scope, pkgName, "npm", ...segments);
|
|
29
|
-
if (fs.existsSync(fromBin)) {
|
|
30
|
-
return pathToFileURL(fromBin).href;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
throw new Error(`Cannot locate ${segments.join("/")} from ${scriptPath}`);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const { getPackageRoot, spawnServer } = await import(resolvePackageModule(import.meta.url, "lib", "runtime.mjs"));
|
|
37
5
|
const packageRoot = getPackageRoot(import.meta.url);
|
|
6
|
+
|
|
38
7
|
spawnServer(packageRoot, process.argv.slice(2), "qingflow-app-builder-mcp", { allowRuntimeBootstrap: false });
|
package/npm/lib/runtime.mjs
CHANGED
|
@@ -5,12 +5,6 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
|
|
6
6
|
const WINDOWS = process.platform === "win32";
|
|
7
7
|
|
|
8
|
-
const PKG_BY_BIN = {
|
|
9
|
-
qingflow: "qingflow-cli",
|
|
10
|
-
"qingflow-app-user-mcp": "qingflow-app-user-mcp",
|
|
11
|
-
"qingflow-app-builder-mcp": "qingflow-app-builder-mcp",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
8
|
function runChecked(command, args, options = {}) {
|
|
15
9
|
const result = spawnSync(command, args, {
|
|
16
10
|
encoding: "utf8",
|
|
@@ -34,18 +28,7 @@ function commandWorks(command, args) {
|
|
|
34
28
|
}
|
|
35
29
|
|
|
36
30
|
export function getPackageRoot(metaUrl) {
|
|
37
|
-
|
|
38
|
-
const scriptDir = path.dirname(scriptPath);
|
|
39
|
-
if (path.basename(scriptDir) === ".bin") {
|
|
40
|
-
const binName = path.basename(scriptPath);
|
|
41
|
-
const pkgName = PKG_BY_BIN[binName];
|
|
42
|
-
if (!pkgName) {
|
|
43
|
-
throw new Error(`Unknown qingflow command: ${binName}`);
|
|
44
|
-
}
|
|
45
|
-
const scope = process.env.QINGFLOW_NPM_SCOPE || "@josephyan";
|
|
46
|
-
return path.join(scriptDir, "..", scope, pkgName);
|
|
47
|
-
}
|
|
48
|
-
return path.resolve(scriptDir, "..", "..");
|
|
31
|
+
return path.resolve(path.dirname(fileURLToPath(metaUrl)), "..", "..");
|
|
49
32
|
}
|
|
50
33
|
|
|
51
34
|
export function getCodexHome() {
|
|
@@ -154,43 +137,6 @@ function writeSkillProvenance(skillsDestRoot, skillName, payload) {
|
|
|
154
137
|
fs.writeFileSync(path.join(provenanceRoot, `${skillName}.json`), `${JSON.stringify(payload, null, 2)}\n`);
|
|
155
138
|
}
|
|
156
139
|
|
|
157
|
-
function sleepMs(ms) {
|
|
158
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function withSkillInstallLock(skillsDestRoot, callback) {
|
|
162
|
-
const lockDir = path.join(skillsDestRoot, ".qingflow-skill-install.lock");
|
|
163
|
-
const startedAt = Date.now();
|
|
164
|
-
while (true) {
|
|
165
|
-
try {
|
|
166
|
-
fs.mkdirSync(lockDir);
|
|
167
|
-
break;
|
|
168
|
-
} catch (error) {
|
|
169
|
-
if (error.code !== "EEXIST") {
|
|
170
|
-
throw error;
|
|
171
|
-
}
|
|
172
|
-
try {
|
|
173
|
-
const stat = fs.statSync(lockDir);
|
|
174
|
-
if (Date.now() - stat.mtimeMs > 300_000) {
|
|
175
|
-
fs.rmSync(lockDir, { recursive: true, force: true });
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
} catch {
|
|
179
|
-
continue;
|
|
180
|
-
}
|
|
181
|
-
if (Date.now() - startedAt > 30_000) {
|
|
182
|
-
throw new Error(`Timed out waiting for skill install lock: ${lockDir}`);
|
|
183
|
-
}
|
|
184
|
-
sleepMs(100);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
try {
|
|
188
|
-
return callback();
|
|
189
|
-
} finally {
|
|
190
|
-
fs.rmSync(lockDir, { recursive: true, force: true });
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
140
|
export function installBundledSkills(
|
|
195
141
|
packageRoot,
|
|
196
142
|
{
|
|
@@ -234,29 +180,27 @@ export function installBundledSkills(
|
|
|
234
180
|
mode,
|
|
235
181
|
};
|
|
236
182
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
});
|
|
255
|
-
}
|
|
183
|
+
for (const skillName of wanted) {
|
|
184
|
+
const src = path.join(skillsSrc, skillName);
|
|
185
|
+
const dest = path.join(skillsDestRoot, skillName);
|
|
186
|
+
const installResult = installOneSkill(src, dest, { force, mode });
|
|
187
|
+
result[installResult.status === "conflict" ? "conflicts" : installResult.status].push(skillName);
|
|
188
|
+
if (installResult.status !== "conflict") {
|
|
189
|
+
writeSkillProvenance(skillsDestRoot, skillName, {
|
|
190
|
+
package: packageJson.name ?? null,
|
|
191
|
+
version: packageJson.version ?? null,
|
|
192
|
+
skill: skillName,
|
|
193
|
+
source: src,
|
|
194
|
+
destination: dest,
|
|
195
|
+
agent,
|
|
196
|
+
scope,
|
|
197
|
+
mode,
|
|
198
|
+
installed_at: new Date().toISOString(),
|
|
199
|
+
});
|
|
256
200
|
}
|
|
201
|
+
}
|
|
257
202
|
|
|
258
|
-
|
|
259
|
-
});
|
|
203
|
+
return result;
|
|
260
204
|
}
|
|
261
205
|
|
|
262
206
|
function parseSkillsCliArgs(args) {
|
|
@@ -536,17 +480,6 @@ function getVenvPip(packageRoot) {
|
|
|
536
480
|
: path.join(getVenvDir(packageRoot), "bin", "pip");
|
|
537
481
|
}
|
|
538
482
|
|
|
539
|
-
function findOfflineProjectWheel(findLinksDir) {
|
|
540
|
-
const wheels = fs
|
|
541
|
-
.readdirSync(findLinksDir)
|
|
542
|
-
.filter((name) => /^qingflow_mcp-.*\.whl$/i.test(name))
|
|
543
|
-
.sort();
|
|
544
|
-
if (wheels.length === 0) {
|
|
545
|
-
throw new Error(`Offline install expected a qingflow_mcp wheel in ${findLinksDir}`);
|
|
546
|
-
}
|
|
547
|
-
return path.join(findLinksDir, wheels[wheels.length - 1]);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
483
|
export function findPython() {
|
|
551
484
|
const preferred = process.env.QINGFLOW_MCP_PYTHON?.trim();
|
|
552
485
|
const candidates = preferred
|
|
@@ -595,20 +528,7 @@ export function ensurePythonEnv(packageRoot, { force = false, commandName = "qin
|
|
|
595
528
|
}
|
|
596
529
|
|
|
597
530
|
const pip = getVenvPip(packageRoot);
|
|
598
|
-
|
|
599
|
-
const offlineFindLinks = process.env.QINGFLOW_MCP_PIP_FIND_LINKS?.trim();
|
|
600
|
-
if (process.env.QINGFLOW_MCP_PIP_NO_INDEX === "1") {
|
|
601
|
-
pipArgs.push("--no-index");
|
|
602
|
-
}
|
|
603
|
-
if (offlineFindLinks) {
|
|
604
|
-
pipArgs.push("--find-links", offlineFindLinks);
|
|
605
|
-
}
|
|
606
|
-
if (process.env.QINGFLOW_MCP_PIP_NO_INDEX === "1" && offlineFindLinks) {
|
|
607
|
-
pipArgs.push(findOfflineProjectWheel(offlineFindLinks));
|
|
608
|
-
} else {
|
|
609
|
-
pipArgs.push(".");
|
|
610
|
-
}
|
|
611
|
-
runChecked(pip, pipArgs, { cwd: packageRoot });
|
|
531
|
+
runChecked(pip, ["install", "--disable-pip-version-check", "."], { cwd: packageRoot });
|
|
612
532
|
|
|
613
533
|
fs.writeFileSync(
|
|
614
534
|
stampPath,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ensurePythonEnv, getPackageRoot
|
|
1
|
+
import { ensurePythonEnv, getPackageRoot } from "../lib/runtime.mjs";
|
|
2
2
|
|
|
3
3
|
const packageRoot = getPackageRoot(import.meta.url);
|
|
4
4
|
|
|
@@ -6,15 +6,6 @@ try {
|
|
|
6
6
|
console.log("[qingflow-mcp] Bootstrapping Python runtime...");
|
|
7
7
|
ensurePythonEnv(packageRoot, { commandName: "qingflow-app-builder-mcp" });
|
|
8
8
|
console.log("[qingflow-mcp] Python runtime is ready.");
|
|
9
|
-
const skills = installBundledSkills(packageRoot, { force: true });
|
|
10
|
-
if (!skills.skipped) {
|
|
11
|
-
const changed = [
|
|
12
|
-
skills.installed.length ? `installed=${skills.installed.join(",")}` : "",
|
|
13
|
-
skills.unchanged.length ? `unchanged=${skills.unchanged.join(",")}` : "",
|
|
14
|
-
skills.conflicts.length ? `conflicts=${skills.conflicts.join(",")}` : "",
|
|
15
|
-
].filter(Boolean).join(" ");
|
|
16
|
-
console.log(`[qingflow-mcp] Installed skills to ${skills.destination}: ${changed || "none"}`);
|
|
17
|
-
}
|
|
18
9
|
} catch (error) {
|
|
19
10
|
console.error(`[qingflow-mcp] postinstall failed: ${error.message}`);
|
|
20
11
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@josephyan/qingflow-app-builder-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.5",
|
|
4
4
|
"description": "Builder MCP for Qingflow app/package/system design and staged solution workflows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"qingflow-app-builder-mcp": "./npm/bin/qingflow-app-builder-mcp.mjs"
|
|
8
|
+
"qingflow-app-builder-mcp": "./npm/bin/qingflow-app-builder-mcp.mjs",
|
|
9
|
+
"qingflow-app-builder-mcp-skills": "./npm/bin/qingflow-skills.mjs"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|
|
11
12
|
"postinstall": "node ./npm/scripts/postinstall.mjs"
|
package/pyproject.toml
CHANGED
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: qingflow-app-builder
|
|
3
|
-
description: Build, configure, and modify Qingflow apps and systems
|
|
3
|
+
description: Build, configure, and modify Qingflow apps and systems using the current Wingent Momo runtime MCP session. Use when the user wants to apply or repair an existing SolutionSpec, modify an existing package with app, view, workflow, portal, navigation, or reporting tools, verify builder-side results, or troubleshoot system-building behavior. Do not use this skill to install the MCP or to author a brand new SolutionSpec from scratch.
|
|
4
4
|
metadata:
|
|
5
5
|
short-description: Build and modify Qingflow apps and systems
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Qingflow App Builder
|
|
9
9
|
|
|
10
|
+
> **Skill 版本**:`qingflow-skills-2026.06.24.2`(入口文档版本;如需确认 CLI 包版本,使用 `qingflow --version` 或 `qingflow --json version`)。
|
|
11
|
+
|
|
10
12
|
## Overview
|
|
11
13
|
|
|
12
14
|
This skill is for the current **public builder surface**, not for legacy low-level builder writes.
|
|
13
|
-
|
|
15
|
+
In Wingent Momo runtime, trust the injected MCP session, credentials, workspace, and route context until a tool explicitly reports otherwise.
|
|
14
16
|
|
|
15
17
|
Before any write or verification flow, identify whether the task targets `test` or `prod` and read [references/environments.md](references/environments.md). If the user did not specify one, default to `prod`.
|
|
16
18
|
|
|
17
19
|
Before choosing a route, skim the shared maintenance baseline: [public-surface-sync.md](references/public-surface-sync.md).
|
|
20
|
+
Then pick the matching development guide: [single-app-development-guide.md](references/single-app-development-guide.md) for one app, or [complete-system-development-guide.md](references/complete-system-development-guide.md) for app packages/systems.
|
|
18
21
|
|
|
19
22
|
## Current Public Mental Model
|
|
20
23
|
|
|
@@ -32,10 +35,29 @@ Default modeling rules:
|
|
|
32
35
|
- Another business object -> a separate app, not a text field
|
|
33
36
|
- Cross-object links -> relation fields, not text fields
|
|
34
37
|
|
|
38
|
+
## Route First
|
|
39
|
+
|
|
40
|
+
Before any builder write, classify the request:
|
|
41
|
+
|
|
42
|
+
- **Complete system / app package**: the user asks for a system, package, workspace module set, or several related forms/apps. Use `package_apply` for the package, then one `app_schema_apply(package_id=..., apps=[...])` for the app shells and fields. This is the main path for complete systems, not a bulk shortcut to abandon after the first slow response. Do not squeeze several business objects into one app.
|
|
43
|
+
- **Single app**: the user names one form/app or gives one `app_key`. Use `app_resolve`/`app_get`, then `app_schema_apply` and the app-scoped apply tools.
|
|
44
|
+
- **Record/user operation**: the user wants to add, edit, delete, approve, or analyze data. Route to the record/task skills instead of builder tools.
|
|
45
|
+
|
|
46
|
+
For complete systems, `apps[]` should use stable `client_key` values. Same-call relation fields should use `target_app_ref` for another `apps[].client_key`; use `target_app_key` only when the target app already exists or has been confirmed by readback. Create the related apps with one multi-app schema apply; do not create each app separately just to collect app keys and then patch relations afterward.
|
|
47
|
+
|
|
48
|
+
If a complete-system `app_schema_apply` times out, returns `partial_success`, returns `write_executed=true`, has `safe_to_retry=false`, or has incomplete readback, treat it as an uncertain write, not as a failed create. The next action is always `readback_before_retry`: read the package/app/fields first, compare intended `client_key`/`app_name`/relations against reality, and only then repair the missing slice. Do not retry the whole multi-app create, create `V2`/`测试`/random-suffix apps, or split the system into single-app rebuilds to bypass a duplicate/conflict.
|
|
49
|
+
|
|
50
|
+
Builder schema inputs should follow agent-intuitive semantics:
|
|
51
|
+
|
|
52
|
+
- primary icon syntax is `icon + color`, for example `icon: "table", color: "blue"`; `icon_name/icon_color`, `icon_config`, and `icon: {name, color}` are compatibility aliases only
|
|
53
|
+
- `single_select` / `multi_select` options may be strings or objects such as `{label, value}`; tools normalize to option labels
|
|
54
|
+
- relation fields need a target plus `display_field` and `visible_fields`
|
|
55
|
+
- do not create built-in system fields as form fields: `数据ID`, `编号`, `申请人`, `申请时间`, `创建人`, `创建时间`, `提交人`, `提交时间`, `更新时间`, `更新人`, `当前流程状态`, `当前处理人`, `当前处理节点`, `流程标题`. They are platform-generated; only reference supported system fields where a tool explicitly says so, such as button `source_field: "数据ID"`
|
|
56
|
+
|
|
35
57
|
## Public Tools You Should Think In
|
|
36
58
|
|
|
37
59
|
- Package: `package_get`, `package_apply`
|
|
38
|
-
- App reads: `app_resolve`, `app_get`, `app_get_fields`, `app_get_layout`, `app_get_views`, `app_get_flow`, `app_get_charts
|
|
60
|
+
- App reads: `app_resolve`, `app_get`, `app_get_fields`, `app_get_layout`, `app_get_views`, `app_get_flow`, `app_get_charts`
|
|
39
61
|
- Builder reads: `portal_list`, `portal_get`, `view_get`, `chart_get`, `builder_tool_contract`
|
|
40
62
|
- Directory: `member_search`, `role_search`, `role_create`
|
|
41
63
|
- Writes: `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, `app_views_apply`, `app_custom_buttons_apply`, `app_associated_resources_apply`, `app_charts_apply`, `portal_apply`, `app_release_edit_lock_if_mine`
|
|
@@ -50,8 +72,10 @@ Treat these as the official surface. Do not default to `package_create`, `packag
|
|
|
50
72
|
- use `package_get(package_id=...)` to read one known package
|
|
51
73
|
- use `package_apply(...)` for package creation, rename, icon, visibility, grouping, ordering, and app/portal layout
|
|
52
74
|
- Multi-app schema work:
|
|
53
|
-
- use one `app_schema_apply(apps=[...])` / CLI `builder schema apply --apps-file` when creating several apps in one package
|
|
54
|
-
-
|
|
75
|
+
- use one `app_schema_apply(package_id=..., apps=[...])` / CLI `builder schema apply --apps-file` when creating several apps in one package
|
|
76
|
+
- every `apps[]` item should carry its own `client_key`, `app_name`, `icon`, `color`, and `add_fields`
|
|
77
|
+
- same-call relation fields should use `target_app_ref` to point at another `apps[].client_key`; use `target_app` only when the app name is unique and stable, and use `target_app_key` only after the target app already exists or readback has confirmed it
|
|
78
|
+
- timeout / `partial_success` / `write_executed=true` / `safe_to_retry=false` means `readback_before_retry`; do not directly downgrade to single-app creation
|
|
55
79
|
- App base permissions:
|
|
56
80
|
- trust `app_get.editability.can_edit_app_base` for app base-info writes like app name, icon, and visibility
|
|
57
81
|
- `can_edit_form` only means schema/form-route capability; it no longer implies app base-info write capability
|
|
@@ -63,12 +87,13 @@ Treat these as the official surface. Do not default to `package_create`, `packag
|
|
|
63
87
|
- `portal_apply` is the public write path
|
|
64
88
|
- in edit mode, omitting `sections` means “preserve existing layout and update base info only”
|
|
65
89
|
- supplying `sections` means full replace semantics for sections
|
|
66
|
-
- portal sections use a 24-column PC grid; all components sharing the same `y` coordinate must have identical `rows` values and their `cols` must sum to exactly 24; mixing `rows` in the same row causes height misalignment, and a `cols` sum under 24 leaves blank space at the row end; the next row's `y` must equal the previous row's `y` + `rows`
|
|
67
90
|
- Chart work:
|
|
68
91
|
- `app_charts_apply` is the public write path for app-source QingBI report bodies/configs; it creates/updates reports with `dataSourceType=qingflow`
|
|
69
92
|
- dataset BI reports are not created or edited by `app_charts_apply` yet; create them in QingBI first, then attach the existing report with `app_associated_resources_apply` and `report_source="dataset"`
|
|
70
93
|
- it does not attach the report to the Qingflow app associated-resource display; use `app_associated_resources_apply` for that
|
|
71
94
|
- supported `chart_type` values include legacy public aliases `target`, `table` and QingBI types such as `summary`, `columnar`, `area`, `stacked_area`, `funnel`, `waterfall`, `gauge`, `heatmap`, `histogram`, `treemap`, `radar`, `stacked_bar`, `stacked_column`, `scatter`, `ring`, `rose`, `dualaxes`, `map`, and `timeline`
|
|
95
|
+
- chart `filters` use the unified fixed-filter DSL: `field_name + operator + value/values`; the tool compiles them to QingBI string judge types
|
|
96
|
+
- for complete systems, submit `upsert_charts` in batches of 4-8. More than 8 upserts is blocked before write with `CHART_UPSERT_BATCH_TOO_LARGE`; execute `details.suggested_batch_payloads[]` one batch at a time.
|
|
72
97
|
- use `patch_charts` for changing a chart name, visibility, filters, or one config fragment on an existing chart
|
|
73
98
|
- `visibility` is a public capability and should be treated as a base-only permission update
|
|
74
99
|
- do not model chart visibility changes as raw config rewrites
|
|
@@ -87,30 +112,34 @@ Treat these as the official surface. Do not default to `package_create`, `packag
|
|
|
87
112
|
- advanced bindings may use `button_limit`, `button_formula`, `button_formula_type`, and `print_tpls` only when visibility or print-template behavior is required
|
|
88
113
|
- Associated resources:
|
|
89
114
|
- `app_associated_resources_apply` is the public write path for the Qingflow app-level associated report/view pool and per-view display config
|
|
90
|
-
- for multi-app systems, use `apps[]` to batch associated-resource writes; each item carries its own `app_key` plus `upsert_resources` / `patch_resources` / `view_configs`
|
|
91
115
|
- it attaches existing BI reports/views for in-app display; it does not create or edit QingBI report bodies/configs, including dataset reports
|
|
92
116
|
- use `patch_resources` for changing match rules or other existing associated-resource parameters; the tool preserves backend-required raw fields internally
|
|
93
117
|
- `associated_item_id` is the backend internal associated-resource id; for `view_configs`, `remove_associated_item_ids`, and `reorder_associated_item_ids`, you may pass `associated_item_id` or an existing resource's `chart_id`/`chart_key`/`view_key`, and the tool resolves it to the internal id
|
|
94
118
|
- before creating a resource, check `app_get.associated_resources` for the same `target_app_key + view_key/chart_key`; if it already exists, use `patch_resources` with that `associated_item_id`
|
|
95
119
|
- `client_key` is only a same-call reference for `view_configs[].associated_item_refs`; it is not saved and cannot deduplicate later calls
|
|
96
120
|
- do not pass backend raw `sourceType`; view resources infer the internal Qingflow view source, report/chart resources default to BI app reports, and existing dataset reports use `report_source="dataset"`
|
|
97
|
-
- use `match_mappings` for associated view/report filters; dynamic
|
|
121
|
+
- use `match_mappings` for associated view/report filters; dynamic context matches use `source_field`, static filters use `value`; do not handwrite raw `matchRules`
|
|
98
122
|
- if field type compatibility is unclear, read [references/match-rules.md](references/match-rules.md)
|
|
99
123
|
- Views and flows:
|
|
100
124
|
- stay on `app_views_apply` / `app_flow_apply`
|
|
125
|
+
- before building approval/fill/copy flows, make sure the app schema has an explicit business status `select` field such as `状态` / `处理状态` / `审批状态`; do not create platform workflow system fields such as `当前流程状态`
|
|
101
126
|
- use `patch_views` for existing-view parameter changes such as `query_conditions`, `filters`, `columns`, or visibility
|
|
102
127
|
- builder view writes use raw `view_key` values from `app_get.views`; `custom:<viewKey>` is a record-data `view_id` form, not a builder `view_key`
|
|
128
|
+
- do not create platform default/system views named `全部数据`, `我的数据`, `我发起的`, `待办`, `已办`, or `抄送`; they are built in. New views must use business-specific names. To change a built-in view, patch by its existing raw `view_key`
|
|
103
129
|
- use `builder_tool_contract` whenever the minimal legal shape is unclear
|
|
104
|
-
- keep view `filters` and `query_conditions` separate: `filters` are fixed saved filters; `query_conditions` configure the frontend query panel fields and only take effect after users enter query values
|
|
105
|
-
-
|
|
130
|
+
- keep view `filters` and `query_conditions` separate: `filters` use `field_name + operator + value/values` and are fixed saved filters; `query_conditions` configure the frontend query panel fields and only take effect after users enter query values
|
|
131
|
+
- keep relation/attachment/subtable/address/Q-Linker/code-block fields out of `query_conditions`; member/department fields may be used as query-panel fields when readback supports them. Use `filters` for fixed filters or associated-resource `match_mappings` for current-record related report/view matching
|
|
106
132
|
- new views default the associated report/view display area to visible with `limit_type="all"`; existing views preserve their current associated-resource display unless `associated_resources` is explicitly patched
|
|
107
133
|
- configure associated reports/views through `app_associated_resources_apply`, not through `app_views_apply`
|
|
108
134
|
|
|
109
135
|
## Standard Operating Order
|
|
110
136
|
|
|
111
|
-
1.
|
|
112
|
-
2.
|
|
113
|
-
3.
|
|
137
|
+
1. Trust the current MCP/session when it is already injected by the runtime; only run auth/workspace recovery after a tool explicitly reports an auth, credential, or workspace error
|
|
138
|
+
2. Confirm whether the task is read-only or write-impacting
|
|
139
|
+
3. Classify the build scope:
|
|
140
|
+
- complete system/package -> `package_apply` or `package_get`, then one `app_schema_apply(package_id=..., apps=[...])`
|
|
141
|
+
- single app -> `app_resolve` / `app_get`, then app-scoped apply tools
|
|
142
|
+
- record/task/data request -> leave builder and use the matching record/task skill
|
|
114
143
|
4. Resolve the smallest stable target:
|
|
115
144
|
- app-scoped work -> `app_resolve`
|
|
116
145
|
- package-scoped work with known id -> `package_get`
|
|
@@ -135,16 +164,20 @@ Treat these as the official surface. Do not default to `package_create`, `packag
|
|
|
135
164
|
- portal -> `portal_apply`
|
|
136
165
|
- package metadata/layout -> `package_apply`
|
|
137
166
|
8. Use `app_publish_verify` only when the user explicitly wants final publish/live verification or you need a dedicated verification pass
|
|
167
|
+
9. For complete-system builds, write `tmp/qingflow_system_build_summary.json` before the final response and make the final report match that file
|
|
138
168
|
|
|
139
169
|
## Safe Usage Rules
|
|
140
170
|
|
|
141
171
|
- Do not guess package identity from a loose name. Public package work assumes a known `package_id`, or an explicit create/update intent through `package_apply`.
|
|
172
|
+
- Do not perform routine auth probes before every builder action in runtime contexts with injected MCP credentials; recover auth only after an actual auth/workspace failure.
|
|
142
173
|
- If `package_id` is unknown, derive it from related app/portal readback when possible; otherwise ask the user instead of falling back to hidden package lookup tools.
|
|
174
|
+
- Do not bypass package/app-name conflicts by inventing `V2`, `测试`, timestamp, or random suffix apps in a real business package. Read back and decide whether to update the existing app, create only a truly missing app, or ask the user.
|
|
175
|
+
- After any uncertain schema write, do `readback_before_retry` with `package_get` / `app_resolve` / `app_get_fields`; retry only the verified missing or failed slice.
|
|
143
176
|
- Do not use `package_create` or `package_attach_app` as a public default path. If they still appear in low-level code, treat them as internal/legacy implementation details.
|
|
144
177
|
- Do not use raw `portal_*` writes or raw `qingbi_report_*` writes as the default builder strategy.
|
|
145
|
-
-
|
|
178
|
+
- `app_schema_apply`, `app_layout_apply`, `app_flow_apply`, and `app_views_apply` publish by default; `app_custom_buttons_apply` and `app_associated_resources_apply` publish after at least one write succeeds and do not accept a draft-only `publish` parameter; `app_charts_apply` is immediate-live without publish.
|
|
146
179
|
- When creating or updating fields, configure the app data title/cover directly in field JSON: `as_data_title: true` is required on exactly one readable top-level title field; `as_data_cover: true` is optional and only valid on one top-level `attachment` field.
|
|
147
|
-
-
|
|
180
|
+
- Do not add platform system fields to `add_fields`; if the user asks for record id, number, applicant, creation/update time, or workflow status, use the built-in data/list/readback fields instead of creating duplicate controls.
|
|
148
181
|
- If the same validation error repeats twice, stop guessing and re-read `builder_tool_contract`.
|
|
149
182
|
- For workflow assignees, prefer `role_search` over explicit members unless the user explicitly wants named members.
|
|
150
183
|
- Public flow building is still intentionally limited to stable linear workflows. If a requirement sounds like branches/conditions, explain the limitation instead of freehanding unsupported graph shapes.
|
|
@@ -158,7 +191,7 @@ Treat these as the official surface. Do not default to `package_create`, `packag
|
|
|
158
191
|
- For UI cards or quick narration, read `resources[]` first. Each resource has `resource_type`, `operation`, `status`, `id`, `key`, `name`, typed `ids`, and `parent`.
|
|
159
192
|
- Use legacy fields such as `field_diff`, `views_diff`, `chart_results`, `created/updated/removed`, and `verification` only for compatibility and troubleshooting.
|
|
160
193
|
- Treat post-write readback as the source of truth, not just write status codes.
|
|
161
|
-
- `success` means write and verification completed; `partial_success` means the write landed but verification is incomplete.
|
|
194
|
+
- `success` means write and verification completed; `partial_success` means the write landed or may have landed but verification is incomplete. If `write_executed=true`, `safe_to_retry=false`, or readback is unavailable, do `readback_before_retry` before any create retry.
|
|
162
195
|
- For portals, distinguish clearly between:
|
|
163
196
|
- base-info-only update with layout preserved
|
|
164
197
|
- full sections replace
|
|
@@ -243,22 +276,6 @@ Use `app_custom_buttons_apply` for the whole custom-button path: button body, ad
|
|
|
243
276
|
|
|
244
277
|
For add-data buttons that create a child record linked back to the current record, map `source_field: "数据ID"` to the target relation field. Do not use raw `que_relation` unless maintaining an existing backend config.
|
|
245
278
|
|
|
246
|
-
## Playbook Selection
|
|
247
|
-
|
|
248
|
-
Before starting any build or create task, route to the right reference first:
|
|
249
|
-
|
|
250
|
-
| User intent | Signal phrases | Playbook |
|
|
251
|
-
|-------------|---------------|---------|
|
|
252
|
-
| Multi-app business system with cross-app relations, shared workflow, and a portal dashboard | "建一套系统"、"包含 N 个模块"、"这几个表单之间建立关联"、"完整的业务系统" | [build-complete-system.md](references/build-complete-system.md) |
|
|
253
|
-
| Single app end-to-end: rich schema, layout, flow, multiple view types, custom buttons, in-app charts, associated resources, and sample data | "建一个应用"、"帮我搭一个XX管理"、"从零开始建一个XX"、"我需要一个管理XX的应用" | [build-single-app.md](references/build-single-app.md) |
|
|
254
|
-
| Add one new app inside an existing package | "在这个包里加一个表单"、"现有系统里新增一个模块" | [create-app.md](references/create-app.md) |
|
|
255
|
-
| Update fields or schema only | "加一个字段"、"改字段名"、"删除字段" | [update-schema.md](references/update-schema.md) |
|
|
256
|
-
| Update layout only | "调整分组"、"改排列顺序" | [update-layout.md](references/update-layout.md) |
|
|
257
|
-
| Update workflow only | "修改审批流"、"加一个审批节点" | [update-flow.md](references/update-flow.md) |
|
|
258
|
-
| Update views only | "加一个看板"、"改筛选条件"、"新增视图" | [update-views.md](references/update-views.md) |
|
|
259
|
-
|
|
260
|
-
Decision rule: if the user mentions **multiple related apps or a portal**, use `build-complete-system.md`. If it is **one app** with a from-scratch setup request, use `build-single-app.md`. If the target app already exists and the user only wants to change one layer, use the matching single-layer playbook.
|
|
261
|
-
|
|
262
279
|
## Resources
|
|
263
280
|
|
|
264
281
|
- Shared public-surface baseline: [public-surface-sync.md](references/public-surface-sync.md)
|
|
@@ -266,6 +283,8 @@ Decision rule: if the user mentions **multiple related apps or a portal**, use `
|
|
|
266
283
|
- Tool choice and sequencing: [references/tool-selection.md](references/tool-selection.md)
|
|
267
284
|
- Field matching rules: [references/match-rules.md](references/match-rules.md)
|
|
268
285
|
- Result semantics and gotchas: [references/gotchas.md](references/gotchas.md)
|
|
286
|
+
- Single app development guide: [references/single-app-development-guide.md](references/single-app-development-guide.md)
|
|
287
|
+
- Complete system development guide: [references/complete-system-development-guide.md](references/complete-system-development-guide.md)
|
|
269
288
|
- Create one app in an existing package: [references/create-app.md](references/create-app.md)
|
|
270
289
|
- Update fields only: [references/update-schema.md](references/update-schema.md)
|
|
271
290
|
- Update layout only: [references/update-layout.md](references/update-layout.md)
|
|
@@ -273,5 +292,3 @@ Decision rule: if the user mentions **multiple related apps or a portal**, use `
|
|
|
273
292
|
- Workflow assignees and node permissions: [references/flow-actors-and-permissions.md](references/flow-actors-and-permissions.md)
|
|
274
293
|
- Update views only: [references/update-views.md](references/update-views.md)
|
|
275
294
|
- Standard end-to-end builder sequences: [references/solution-playbooks.md](references/solution-playbooks.md)
|
|
276
|
-
- Build a complete multi-app system from scratch: [references/build-complete-system.md](references/build-complete-system.md)
|
|
277
|
-
- Build a single app end-to-end (schema + layout + flow + views + buttons + charts + associated resources + data): [references/build-single-app.md](references/build-single-app.md)
|