@dazitech/cli 3.0.0 → 3.0.1

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.
Files changed (58) hide show
  1. package/README.md +15 -13
  2. package/dist/clis/dazi-app.js +5 -5
  3. package/dist/clis/dazi-flow.js +600 -170
  4. package/dist/docs/app/app-init.md +15 -15
  5. package/dist/docs/app/build-upload.md +13 -13
  6. package/dist/docs/app/release-guide.md +9 -9
  7. package/dist/docs/app//344/270/273/350/246/201/350/264/242/345/212/241/346/214/207/346/240/207/345/244/215/346/235/202/346/212/245/350/241/250/345/274/200/345/217/221/345/256/236/350/267/265.md +45 -41
  8. package/dist/docs/auth/auth-login.md +4 -4
  9. package/dist/docs/auth/token-management.md +5 -5
  10. package/dist/docs/data/cube-guide.md +2 -2
  11. package/dist/docs/data/data-spaces.md +4 -3
  12. package/dist/docs/data/table-preview.md +6 -6
  13. package/dist/docs/flow/ai-workflow-playbook.md +69 -0
  14. package/dist/docs/flow/flow-project-guide.md +92 -87
  15. package/dist/docs/flow/flows-guide.md +98 -94
  16. package/dist/docs/flow/local-files-spec.md +194 -0
  17. package/dist/docs/flow/node-code-guide.md +57 -55
  18. package/dist/docs/flow/run-guide.md +18 -18
  19. package/dist/docs/flow/variables-guide.md +61 -61
  20. package/dist/docs/flow//346/265/201/347/250/213/345/274/200/345/217/221/346/234/200/344/275/263/345/256/236/350/267/265-VS-flow0/346/241/210/344/276/213.md +31 -31
  21. package/dist/docs/guides/cli-invocation.md +30 -29
  22. package/dist/docs/guides/cli-reference.md +72 -71
  23. package/dist/docs/guides/flow-consistency-checklist.md +42 -0
  24. package/dist/docs/guides/mcp-setup.md +34 -34
  25. package/dist/docs/guides/migrate-v2-v3.md +6 -5
  26. package/dist/docs/guides/quickstart.md +8 -8
  27. package/dist/docs/guides/troubleshooting.md +39 -21
  28. package/dist/docs/guides/workspace-v3.md +17 -17
  29. package/dist/docs/index.json +18 -6
  30. package/dist/docs/onto/action-guide.md +4 -3
  31. package/dist/docs/onto/dazi_script_sdk_reference.md +20 -14
  32. package/dist/docs/onto/dazi_script_seed_data_guide.md +14 -14
  33. package/dist/docs/onto/function-guide.md +5 -5
  34. package/dist/docs/onto/rule-guide.md +7 -6
  35. package/dist/docs/onto/space-management.md +5 -3
  36. package/dist/docs/onto//346/234/254/344/275/223/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +35 -35
  37. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +21 -21
  38. package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/345/210/251/346/266/246/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +11 -11
  39. package/dist/examples/flow/minimal-excel-python/README.md +5 -0
  40. package/dist/examples/flow/minimal-excel-python/flow.json +48 -0
  41. package/dist/examples/flow/minimal-excel-python/flow.meta.json +23 -0
  42. package/dist/examples/flow/minimal-excel-python//350/212/202/347/202/271/Excel/347/244/272/344/276/213/code.py +7 -0
  43. package/dist/examples/flow/minimal-excel-python//350/212/202/347/202/271/Excel/347/244/272/344/276/213/node.info.json +14 -0
  44. package/dist/examples/index.json +6 -0
  45. package/dist/prompts/data/data-analysis.md +2 -2
  46. package/dist/prompts/flow/ai-workflow-playbook.md +69 -0
  47. package/dist/prompts/flow/flow-design.md +33 -19
  48. package/dist/prompts/flow/plan-generate.md +7 -7
  49. package/dist/prompts/flow/run-debug.md +15 -15
  50. package/dist/prompts/flow/run-fix-loop.md +20 -17
  51. package/dist/prompts/general/ask-dazi.md +6 -6
  52. package/dist/prompts/general/troubleshoot.md +4 -3
  53. package/dist/prompts/index.json +1 -0
  54. package/dist/prompts/onto/action-design.md +7 -5
  55. package/dist/prompts/onto/function-design.md +6 -4
  56. package/dist/prompts/onto/rule-seed.md +4 -2
  57. package/dist/prompts/onto/script-publish-run.md +19 -19
  58. package/package.json +1 -1
@@ -959,8 +959,8 @@ var require_command = __commonJS({
959
959
  "node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports2) {
960
960
  var EventEmitter = require("node:events").EventEmitter;
961
961
  var childProcess = require("node:child_process");
962
- var path20 = require("node:path");
963
- var fs16 = require("node:fs");
962
+ var path21 = require("node:path");
963
+ var fs17 = require("node:fs");
964
964
  var process2 = require("node:process");
965
965
  var { Argument: Argument2, humanReadableArgName } = require_argument();
966
966
  var { CommanderError: CommanderError2 } = require_error();
@@ -1892,11 +1892,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
1892
1892
  let launchWithNode = false;
1893
1893
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1894
1894
  function findFile(baseDir, baseName) {
1895
- const localBin = path20.resolve(baseDir, baseName);
1896
- if (fs16.existsSync(localBin)) return localBin;
1897
- if (sourceExt.includes(path20.extname(baseName))) return void 0;
1895
+ const localBin = path21.resolve(baseDir, baseName);
1896
+ if (fs17.existsSync(localBin)) return localBin;
1897
+ if (sourceExt.includes(path21.extname(baseName))) return void 0;
1898
1898
  const foundExt = sourceExt.find(
1899
- (ext) => fs16.existsSync(`${localBin}${ext}`)
1899
+ (ext) => fs17.existsSync(`${localBin}${ext}`)
1900
1900
  );
1901
1901
  if (foundExt) return `${localBin}${foundExt}`;
1902
1902
  return void 0;
@@ -1908,21 +1908,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
1908
1908
  if (this._scriptPath) {
1909
1909
  let resolvedScriptPath;
1910
1910
  try {
1911
- resolvedScriptPath = fs16.realpathSync(this._scriptPath);
1911
+ resolvedScriptPath = fs17.realpathSync(this._scriptPath);
1912
1912
  } catch (err) {
1913
1913
  resolvedScriptPath = this._scriptPath;
1914
1914
  }
1915
- executableDir = path20.resolve(
1916
- path20.dirname(resolvedScriptPath),
1915
+ executableDir = path21.resolve(
1916
+ path21.dirname(resolvedScriptPath),
1917
1917
  executableDir
1918
1918
  );
1919
1919
  }
1920
1920
  if (executableDir) {
1921
1921
  let localFile = findFile(executableDir, executableFile);
1922
1922
  if (!localFile && !subcommand._executableFile && this._scriptPath) {
1923
- const legacyName = path20.basename(
1923
+ const legacyName = path21.basename(
1924
1924
  this._scriptPath,
1925
- path20.extname(this._scriptPath)
1925
+ path21.extname(this._scriptPath)
1926
1926
  );
1927
1927
  if (legacyName !== this._name) {
1928
1928
  localFile = findFile(
@@ -1933,7 +1933,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1933
1933
  }
1934
1934
  executableFile = localFile || executableFile;
1935
1935
  }
1936
- launchWithNode = sourceExt.includes(path20.extname(executableFile));
1936
+ launchWithNode = sourceExt.includes(path21.extname(executableFile));
1937
1937
  let proc;
1938
1938
  if (process2.platform !== "win32") {
1939
1939
  if (launchWithNode) {
@@ -2773,7 +2773,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
2773
2773
  * @return {Command}
2774
2774
  */
2775
2775
  nameFromFilename(filename) {
2776
- this._name = path20.basename(filename, path20.extname(filename));
2776
+ this._name = path21.basename(filename, path21.extname(filename));
2777
2777
  return this;
2778
2778
  }
2779
2779
  /**
@@ -2787,9 +2787,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
2787
2787
  * @param {string} [path]
2788
2788
  * @return {(string|null|Command)}
2789
2789
  */
2790
- executableDir(path21) {
2791
- if (path21 === void 0) return this._executableDir;
2792
- this._executableDir = path21;
2790
+ executableDir(path22) {
2791
+ if (path22 === void 0) return this._executableDir;
2792
+ this._executableDir = path22;
2793
2793
  return this;
2794
2794
  }
2795
2795
  /**
@@ -3084,9 +3084,9 @@ function loadAuth() {
3084
3084
  }
3085
3085
 
3086
3086
  // cli/shared/src/httpClient.js
3087
- async function apiRequest(path20, opts = {}) {
3087
+ async function apiRequest(path21, opts = {}) {
3088
3088
  const auth = opts.token || opts.serverUrl ? { token: opts.token ?? "", serverUrl: opts.serverUrl ?? "" } : loadAuth();
3089
- const url = `${auth.serverUrl.replace(/\/$/, "")}${path20}`;
3089
+ const url = `${auth.serverUrl.replace(/\/$/, "")}${path21}`;
3090
3090
  const headers = {
3091
3091
  "Content-Type": "application/json",
3092
3092
  Authorization: `Bearer ${auth.token}`,
@@ -3583,11 +3583,11 @@ function makeSnapshotCommand() {
3583
3583
  }
3584
3584
 
3585
3585
  // cli/dazi-flow/src/commands/project.ts
3586
- var import_path9 = __toESM(require("path"), 1);
3587
- var import_fs7 = __toESM(require("fs"), 1);
3586
+ var import_path10 = __toESM(require("path"), 1);
3587
+ var import_fs8 = __toESM(require("fs"), 1);
3588
3588
 
3589
3589
  // src/shared/flowScaffoldDocs.ts
3590
- var import_path7 = __toESM(require("path"));
3590
+ var import_path8 = __toESM(require("path"));
3591
3591
 
3592
3592
  // src/shared/flowNodeCatalog.ts
3593
3593
  var FLOW_NODE_CATALOG = [
@@ -3773,9 +3773,339 @@ function shortVar(s) {
3773
3773
  }
3774
3774
 
3775
3775
  // src/shared/flowCliText.ts
3776
- var DAZI_PS1 = ".\\\\scripts\\\\dazi.ps1";
3776
+ var DAZI_CLI = "dazi";
3777
+ function psFlowLine(subcommand) {
3778
+ return `${DAZI_CLI} flow ${subcommand}`;
3779
+ }
3780
+ function psDaziLine(args) {
3781
+ return `${DAZI_CLI} ${args}`;
3782
+ }
3777
3783
  function mdFlowCmd(subcommand) {
3778
- return `\`${DAZI_PS1} flow ${subcommand}\``;
3784
+ return `\`${DAZI_CLI} flow ${subcommand}\``;
3785
+ }
3786
+
3787
+ // src/shared/flowWorkspaceAudit.ts
3788
+ var import_crypto2 = __toESM(require("crypto"));
3789
+ var import_fs6 = __toESM(require("fs"));
3790
+ var import_path7 = __toESM(require("path"));
3791
+ var NODES_DIR2 = "\u8282\u70B9";
3792
+ var FLOW_JSON2 = "flow.json";
3793
+ var FLOW_META_JSON2 = "flow.meta.json";
3794
+ var NODE_INFO_JSON2 = "node.info.json";
3795
+ var NODE_TYPE_CODE_DATA_KEY2 = {
3796
+ "database-source": "sql",
3797
+ "dataspace-source": "sql",
3798
+ "python-script": "pythonCode",
3799
+ "excel-python": "pythonCode",
3800
+ "sql-query": "sql",
3801
+ condition: "pythonCode",
3802
+ "data-quality-check": "dqPythonCode"
3803
+ };
3804
+ function sha12(text) {
3805
+ return import_crypto2.default.createHash("sha1").update(text, "utf8").digest("hex");
3806
+ }
3807
+ function resolveNodeType2(node) {
3808
+ if (node.type === "custom") {
3809
+ return String(node.data?.type ?? "custom");
3810
+ }
3811
+ return String(node.type ?? "custom");
3812
+ }
3813
+ function codeLanguageForNodeType2(nodeType) {
3814
+ if (["python-script", "excel-python", "condition", "data-quality-check"].includes(nodeType)) {
3815
+ return "python";
3816
+ }
3817
+ if (["database-source", "dataspace-source", "sql-query"].includes(nodeType)) {
3818
+ return "sql";
3819
+ }
3820
+ return void 0;
3821
+ }
3822
+ function codeFileExt2(language) {
3823
+ if (language === "python") return "py";
3824
+ if (language === "sql") return "sql";
3825
+ return "txt";
3826
+ }
3827
+ function sanitizeName2(name) {
3828
+ const cleaned = (name || "").replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").trim().replace(/\s+/g, "_");
3829
+ return cleaned || "node";
3830
+ }
3831
+ function readFlowJson2(flowDir) {
3832
+ const raw = JSON.parse(import_fs6.default.readFileSync(import_path7.default.join(flowDir, FLOW_JSON2), "utf8"));
3833
+ return {
3834
+ nodes: Array.isArray(raw.nodes) ? raw.nodes : [],
3835
+ edges: Array.isArray(raw.edges) ? raw.edges : []
3836
+ };
3837
+ }
3838
+ function readMeta2(flowDir) {
3839
+ const p = import_path7.default.join(flowDir, FLOW_META_JSON2);
3840
+ if (!import_fs6.default.existsSync(p)) return void 0;
3841
+ try {
3842
+ return JSON.parse(import_fs6.default.readFileSync(p, "utf8"));
3843
+ } catch {
3844
+ return void 0;
3845
+ }
3846
+ }
3847
+ function isCodeNodeType(nodeType) {
3848
+ return Boolean(NODE_TYPE_CODE_DATA_KEY2[nodeType]);
3849
+ }
3850
+ function listNodeDirs(flowDir) {
3851
+ const nodesRoot = import_path7.default.join(flowDir, NODES_DIR2);
3852
+ if (!import_fs6.default.existsSync(nodesRoot)) return [];
3853
+ return import_fs6.default.readdirSync(nodesRoot).filter((n) => {
3854
+ try {
3855
+ return import_fs6.default.statSync(import_path7.default.join(nodesRoot, n)).isDirectory();
3856
+ } catch {
3857
+ return false;
3858
+ }
3859
+ });
3860
+ }
3861
+ function findCodeFileInDir(dirAbs) {
3862
+ if (!import_fs6.default.existsSync(dirAbs)) return void 0;
3863
+ for (const f of import_fs6.default.readdirSync(dirAbs)) {
3864
+ if (/^code\.(py|sql|txt)$/i.test(f)) return f;
3865
+ }
3866
+ return void 0;
3867
+ }
3868
+ function findDirForUuid(flowDir, uuid) {
3869
+ const nodesRoot = import_path7.default.join(flowDir, NODES_DIR2);
3870
+ for (const dirName of listNodeDirs(flowDir)) {
3871
+ const infoPath = import_path7.default.join(nodesRoot, dirName, NODE_INFO_JSON2);
3872
+ if (import_fs6.default.existsSync(infoPath)) {
3873
+ try {
3874
+ const info = JSON.parse(import_fs6.default.readFileSync(infoPath, "utf8"));
3875
+ if (String(info.node_uuid ?? "") === uuid) return import_path7.default.posix.join(NODES_DIR2, dirName);
3876
+ } catch {
3877
+ }
3878
+ }
3879
+ }
3880
+ return void 0;
3881
+ }
3882
+ function auditFlowWorkspace(flowDir) {
3883
+ const warnings = [];
3884
+ const doc = readFlowJson2(flowDir);
3885
+ const meta = readMeta2(flowDir) ?? { nodes: {} };
3886
+ const canvasNodeCount = doc.nodes.length;
3887
+ let canvasCodeNodeCount = 0;
3888
+ const missingInMeta = [];
3889
+ const missingCodeFiles = [];
3890
+ const flowUuids = /* @__PURE__ */ new Set();
3891
+ for (const node of doc.nodes) {
3892
+ const uuid = String(node.node_uuid ?? "").trim();
3893
+ if (!uuid) continue;
3894
+ flowUuids.add(uuid);
3895
+ const nodeType = resolveNodeType2(node);
3896
+ if (!isCodeNodeType(nodeType)) continue;
3897
+ canvasCodeNodeCount++;
3898
+ const label = String(node.data?.label ?? node.id ?? "");
3899
+ const m = meta.nodes[uuid];
3900
+ if (!m?.dir || !m.codeFile) {
3901
+ missingInMeta.push({ uuid, nodeId: String(node.id ?? ""), nodeType, label });
3902
+ continue;
3903
+ }
3904
+ const codePath = import_path7.default.join(flowDir, m.dir, m.codeFile);
3905
+ if (!import_fs6.default.existsSync(codePath)) {
3906
+ missingCodeFiles.push({ uuid, dir: m.dir, codeFile: m.codeFile });
3907
+ }
3908
+ }
3909
+ const orphanInMeta = Object.keys(meta.nodes).filter((u) => !flowUuids.has(u));
3910
+ let metaCodeIndexedCount = 0;
3911
+ for (const m of Object.values(meta.nodes)) {
3912
+ if (m.dir && m.codeFile) metaCodeIndexedCount++;
3913
+ }
3914
+ const unindexedDirs = [];
3915
+ for (const dirName of listNodeDirs(flowDir)) {
3916
+ const dirAbs = import_path7.default.join(flowDir, NODES_DIR2, dirName);
3917
+ if (!findCodeFileInDir(dirAbs)) continue;
3918
+ const rel = import_path7.default.posix.join(NODES_DIR2, dirName);
3919
+ const indexed = Object.values(meta.nodes).some((m) => m.dir?.replace(/\\/g, "/") === rel);
3920
+ if (!indexed) unindexedDirs.push(rel);
3921
+ }
3922
+ if (canvasCodeNodeCount !== metaCodeIndexedCount) {
3923
+ warnings.push(
3924
+ `\u753B\u5E03\u4EE3\u7801\u8282\u70B9 ${canvasCodeNodeCount} \u4E2A\uFF0Cmeta \u5DF2\u7D22\u5F15 ${metaCodeIndexedCount} \u4E2A\uFF08\u4E0D\u4E00\u81F4\u4F1A\u5BFC\u81F4 node push / \u8BBE\u8BA1\u5668\u6253\u5F00\u4EE3\u7801\u5931\u8D25\uFF09`
3925
+ );
3926
+ }
3927
+ if (missingInMeta.length) {
3928
+ warnings.push("\u90E8\u5206 flow.json \u4EE3\u7801\u8282\u70B9\u672A\u5199\u5165 flow.meta.json\uFF0C\u8BF7\u6267\u884C project repair-meta");
3929
+ }
3930
+ if (unindexedDirs.length) {
3931
+ warnings.push(`\u5B58\u5728\u672A\u7D22\u5F15\u7684\u8282\u70B9\u76EE\u5F55\uFF1A${unindexedDirs.join(", ")}`);
3932
+ }
3933
+ const ok3 = missingInMeta.length === 0 && orphanInMeta.length === 0 && missingCodeFiles.length === 0 && unindexedDirs.length === 0 && canvasCodeNodeCount === metaCodeIndexedCount;
3934
+ return {
3935
+ ok: ok3,
3936
+ canvasNodeCount,
3937
+ canvasCodeNodeCount,
3938
+ metaIndexedCount: Object.keys(meta.nodes).length,
3939
+ metaCodeIndexedCount,
3940
+ missingInMeta,
3941
+ orphanInMeta,
3942
+ missingCodeFiles,
3943
+ unindexedDirs,
3944
+ warnings
3945
+ };
3946
+ }
3947
+ function writeNodeInfo(flowDir, node, uuid, nodeType, relDir, codeFile, language, strippedData) {
3948
+ const abs = import_path7.default.join(flowDir, relDir);
3949
+ import_fs6.default.writeFileSync(
3950
+ import_path7.default.join(abs, NODE_INFO_JSON2),
3951
+ JSON.stringify(
3952
+ {
3953
+ _readonly: `\u6B64\u6587\u4EF6\u7531 dazi-flow \u751F\u6210\uFF0C\u4EC5\u4F9B\u67E5\u770B\uFF1B\u7F16\u8F91\u4EE3\u7801\u8BF7\u6539 ${codeFile}\uFF0C\u914D\u7F6E\u6539 flow.json`,
3954
+ node_uuid: uuid,
3955
+ nodeId: String(node.id ?? ""),
3956
+ nodeType,
3957
+ label: String(node.data?.label ?? ""),
3958
+ codeFile,
3959
+ codeLanguage: language,
3960
+ position: node.position,
3961
+ data: strippedData
3962
+ },
3963
+ null,
3964
+ 2
3965
+ ),
3966
+ "utf8"
3967
+ );
3968
+ }
3969
+ function repairFlowMeta(flowDir) {
3970
+ const warnings = [];
3971
+ const repairedUuids = [];
3972
+ const wroteNodeInfo = [];
3973
+ const doc = readFlowJson2(flowDir);
3974
+ const meta = readMeta2(flowDir) ?? { flowId: null, flowName: import_path7.default.basename(flowDir), nodes: {} };
3975
+ if (!meta.nodes) meta.nodes = {};
3976
+ const usedDirNames = new Set(
3977
+ Object.values(meta.nodes).map((m) => m.dir?.split("/").pop()).filter(Boolean)
3978
+ );
3979
+ for (const node of doc.nodes) {
3980
+ const uuid = String(node.node_uuid ?? "").trim();
3981
+ if (!uuid) continue;
3982
+ const nodeType = resolveNodeType2(node);
3983
+ const codeKey = NODE_TYPE_CODE_DATA_KEY2[nodeType];
3984
+ const semanticId = String(node.id ?? "");
3985
+ const label = String(node.data?.label ?? semanticId ?? nodeType);
3986
+ let entry = meta.nodes[uuid];
3987
+ if (!entry) {
3988
+ entry = { nodeId: semanticId, nodeType };
3989
+ meta.nodes[uuid] = entry;
3990
+ repairedUuids.push(uuid);
3991
+ } else {
3992
+ entry.nodeId = semanticId || entry.nodeId;
3993
+ entry.nodeType = nodeType;
3994
+ }
3995
+ if (!codeKey) continue;
3996
+ let relDir = entry.dir?.replace(/\\/g, "/");
3997
+ if (relDir && findCodeFileInDir(import_path7.default.join(flowDir, relDir))) {
3998
+ } else {
3999
+ relDir = findDirForUuid(flowDir, uuid);
4000
+ }
4001
+ if (!relDir) {
4002
+ const byLabel = import_path7.default.posix.join(NODES_DIR2, sanitizeName2(label));
4003
+ if (import_fs6.default.existsSync(import_path7.default.join(flowDir, byLabel)) && findCodeFileInDir(import_path7.default.join(flowDir, byLabel))) {
4004
+ relDir = byLabel;
4005
+ }
4006
+ }
4007
+ if (!relDir) {
4008
+ let dirName = sanitizeName2(label);
4009
+ if (usedDirNames.has(dirName)) dirName = `${dirName}_${uuid.slice(0, 6)}`;
4010
+ usedDirNames.add(dirName);
4011
+ relDir = import_path7.default.posix.join(NODES_DIR2, dirName);
4012
+ import_fs6.default.mkdirSync(import_path7.default.join(flowDir, relDir), { recursive: true });
4013
+ const lang = codeLanguageForNodeType2(nodeType);
4014
+ const codeFile2 = `code.${codeFileExt2(lang)}`;
4015
+ const template = nodeType === "excel-python" ? "# -*- coding: utf-8 -*-\n# Excel \u8282\u70B9\uFF1A\u753B\u5E03\u914D\u7F6E managed_file_id\uFF1B\u4EE3\u7801\u4F7F\u7528 excel_source_path\n" : lang === "sql" ? "-- \u8282\u70B9 SQL\nSELECT 1;\n" : "# -*- coding: utf-8 -*-\n";
4016
+ if (!findCodeFileInDir(import_path7.default.join(flowDir, relDir))) {
4017
+ import_fs6.default.writeFileSync(import_path7.default.join(flowDir, relDir, codeFile2), template, "utf8");
4018
+ warnings.push(`\u5DF2\u4E3A ${uuid} \u521B\u5EFA\u7A7A\u4EE3\u7801\u6A21\u677F ${relDir}/${codeFile2}`);
4019
+ }
4020
+ }
4021
+ const dirAbs = import_path7.default.join(flowDir, relDir);
4022
+ const codeFile = findCodeFileInDir(dirAbs);
4023
+ if (!codeFile) {
4024
+ warnings.push(`\u8282\u70B9 ${uuid} \u76EE\u5F55 ${relDir} \u65E0 code.*\uFF0C\u8DF3\u8FC7\u4EE3\u7801\u7D22\u5F15`);
4025
+ continue;
4026
+ }
4027
+ const language = codeLanguageForNodeType2(nodeType);
4028
+ const code = import_fs6.default.readFileSync(import_path7.default.join(dirAbs, codeFile), "utf8");
4029
+ entry.dir = relDir;
4030
+ entry.codeFile = codeFile;
4031
+ entry.codeLanguage = language;
4032
+ entry.codeHash = sha12(code);
4033
+ const strippedData = { ...node.data ?? {} };
4034
+ delete strippedData[codeKey];
4035
+ const infoPath = import_path7.default.join(dirAbs, NODE_INFO_JSON2);
4036
+ if (!import_fs6.default.existsSync(infoPath)) {
4037
+ writeNodeInfo(flowDir, node, uuid, nodeType, relDir, codeFile, language, strippedData);
4038
+ wroteNodeInfo.push(relDir);
4039
+ }
4040
+ if (!repairedUuids.includes(uuid)) repairedUuids.push(uuid);
4041
+ }
4042
+ meta.graphFingerprint = "sha1:" + sha12(JSON.stringify({ nodes: doc.nodes, edges: doc.edges }));
4043
+ import_fs6.default.writeFileSync(import_path7.default.join(flowDir, FLOW_META_JSON2), JSON.stringify(meta, null, 2), "utf8");
4044
+ const okAfter = auditFlowWorkspace(flowDir).ok;
4045
+ return {
4046
+ ok: okAfter,
4047
+ repairedUuids: [...new Set(repairedUuids)],
4048
+ wroteNodeInfo,
4049
+ warnings
4050
+ };
4051
+ }
4052
+ function buildFlowConsistencyMarkdown(audit, localFilesSpecLink = "../../\u8D44\u6E90/docs/flow/local-files-spec.md") {
4053
+ const lines = [
4054
+ "## \u672C\u5730\u6587\u4EF6\u4E00\u81F4\u6027",
4055
+ "",
4056
+ "| \u6307\u6807 | \u6570\u91CF |",
4057
+ "|------|------|",
4058
+ `| \u753B\u5E03\u8282\u70B9\uFF08flow.json\uFF09 | ${audit.canvasNodeCount} |`,
4059
+ `| \u753B\u5E03\u4EE3\u7801\u8282\u70B9\uFF08flow.json\uFF09 | ${audit.canvasCodeNodeCount} |`,
4060
+ `| meta \u5DF2\u767B\u8BB0\u8282\u70B9 | ${audit.metaIndexedCount} |`,
4061
+ `| meta \u5DF2\u7D22\u5F15\u4EE3\u7801\uFF08dir+codeFile\uFF09 | ${audit.metaCodeIndexedCount} |`,
4062
+ ""
4063
+ ];
4064
+ if (audit.ok) {
4065
+ lines.push("\u2705 **flow.json / flow.meta.json / \u8282\u70B9/ \u4E00\u81F4**\u3002\u8BBE\u8BA1\u5668\u53EF\u6B63\u5E38\u300C\u6253\u5F00\u4EE3\u7801\u300D\uFF0C`node push` \u53EF\u8BC6\u522B\u810F\u8282\u70B9\u3002", "");
4066
+ } else {
4067
+ lines.push("\u26A0\uFE0F **\u76EE\u5F55\u4E0D\u4E00\u81F4**\uFF08\u4F1A\u5BFC\u81F4\u8BBE\u8BA1\u5668\u627E\u4E0D\u5230\u4EE3\u7801\u3001\u6216 `node push` \u8DF3\u8FC7\uFF09\uFF1A", "");
4068
+ if (audit.missingInMeta.length) {
4069
+ lines.push("| uuid | \u8282\u70B9 | \u7C7B\u578B |");
4070
+ lines.push("|------|------|------|");
4071
+ for (const m of audit.missingInMeta) {
4072
+ lines.push(`| \`${m.uuid.slice(0, 8)}\u2026\` | ${m.label || m.nodeId} | ${m.nodeType} |`);
4073
+ }
4074
+ lines.push("");
4075
+ }
4076
+ if (audit.unindexedDirs.length) {
4077
+ lines.push(`- \u672A\u7D22\u5F15\u76EE\u5F55\uFF1A${audit.unindexedDirs.map((d) => `\`${d}\``).join(" ")}`);
4078
+ }
4079
+ if (audit.orphanInMeta.length) {
4080
+ lines.push(`- meta \u591A\u4F59 uuid\uFF1A${audit.orphanInMeta.length} \u4E2A\uFF08flow.json \u4E2D\u5DF2\u4E0D\u5B58\u5728\uFF09`);
4081
+ }
4082
+ for (const w of audit.warnings) lines.push(`- ${w}`);
4083
+ lines.push(
4084
+ "",
4085
+ "\u4FEE\u590D\uFF08\u5728\u6D41\u7A0B\u76EE\u5F55\uFF09\uFF1A",
4086
+ "",
4087
+ "```powershell",
4088
+ "dazi flow project repair-meta --dir .",
4089
+ "dazi flow project doctor --dir .",
4090
+ "```",
4091
+ "",
4092
+ `\u8BE6\u89C1 [\u6D41\u7A0B\u672C\u5730\u6587\u4EF6\u89C4\u8303](${localFilesSpecLink})\u3002`,
4093
+ ""
4094
+ );
4095
+ }
4096
+ lines.push(
4097
+ "## \u53D8\u66F4\u63D0\u4EA4\u547D\u4EE4\u77E9\u9635",
4098
+ "",
4099
+ "| \u6539\u4E86\u4EC0\u4E48 | \u547D\u4EE4 |",
4100
+ "|----------|------|",
4101
+ "| `managed_file_id`\u3001`output_variable_name`\u3001\u8FDE\u7EBF\u3001\u589E\u5220\u8282\u70B9 | `dazi flow project push --dir . --canvas` |",
4102
+ "| `\u8282\u70B9/<\u540D>/code.py` \u6216 `code.sql` | `dazi flow node push --node <uuid> --dir .` |",
4103
+ '| **\u65B0\u589E\u4EE3\u7801\u8282\u70B9** | `dazi flow node new --type <type> --dir . --label "<\u540D>"` \u2192 \u6539\u914D\u7F6E \u2192 `push --canvas` \u2192 \u5199 code \u2192 `node push` |',
4104
+ "",
4105
+ "> \u7981\u6B62\u53EA\u6539 `flow.json` \u800C\u4E0D\u66F4\u65B0 `flow.meta.json`\uFF08\u987B `node new` / `pull` / `repair-meta`\uFF09\u3002",
4106
+ ""
4107
+ );
4108
+ return lines;
3779
4109
  }
3780
4110
 
3781
4111
  // src/shared/flowScaffoldDocs.ts
@@ -3812,7 +4142,9 @@ function buildDocsTable(anchor) {
3812
4142
  ["\u8282\u70B9\u4EE3\u7801\u7F16\u5199\u6307\u5357\uFF08\u542B SQL/Python \u793A\u4F8B\uFF09", "flow/node-code-guide.md"],
3813
4143
  ["Flow \u8FD0\u884C\u4E0E\u6D4B\u8BD5", "flow/run-guide.md"],
3814
4144
  ["\u6570\u636E\u6E90\u4E0E connectionId", "flow/source-guide.md"],
3815
- ["CLI \u8C03\u7528\u7EA6\u5B9A\uFF08`dazi.ps1`\uFF09", "guides/cli-invocation.md"]
4145
+ ["**\u6D41\u7A0B\u672C\u5730\u6587\u4EF6\u89C4\u8303\uFF08AI \u5FC5\u8BFB\uFF09**", "flow/local-files-spec.md"],
4146
+ ["\u6D41\u7A0B AI \u5DE5\u4F5C\u624B\u518C", "flow/ai-workflow-playbook.md"],
4147
+ ["CLI \u8C03\u7528\u7EA6\u5B9A\uFF08`dazi` / `dazi.ps1`\uFF09", "guides/cli-invocation.md"]
3816
4148
  ];
3817
4149
  return [
3818
4150
  "## \u5E2E\u52A9\u6587\u6863",
@@ -3823,13 +4155,13 @@ function buildDocsTable(anchor) {
3823
4155
  "|------|------|",
3824
4156
  ...rows.map(([title, p]) => `| ${title} | [${p.split("/").pop()}](${flowDocsRel(anchor, p)}) |`),
3825
4157
  "",
3826
- "\u7EC8\u7AEF\u6253\u5F00\u6587\u6863\uFF08\u5728 **dazi-work \u6839**\uFF09\uFF1A",
4158
+ "\u7EC8\u7AEF\u6253\u5F00\u6587\u6863\uFF08**dazi-work \u6839**\u6216\u5DF2 `cd` \u5230\u6D41\u7A0B\u76EE\u5F55\uFF09\uFF1A",
3827
4159
  "",
3828
4160
  "```powershell",
3829
- ".\\scripts\\dazi.ps1 docs open flow/flow-project-guide",
3830
- ".\\scripts\\dazi.ps1 docs open flow/variables-guide",
3831
- ".\\scripts\\dazi.ps1 docs open flow/node-code-guide",
3832
- ".\\scripts\\dazi.ps1 docs open flow/flows-guide",
4161
+ psDaziLine("docs open flow/flow-project-guide"),
4162
+ psDaziLine("docs open flow/variables-guide"),
4163
+ psDaziLine("docs open flow/node-code-guide"),
4164
+ psDaziLine("docs open flow/flows-guide"),
3833
4165
  "```",
3834
4166
  "",
3835
4167
  "**\u4EE3\u7801\u793A\u4F8B**\uFF1A\u53D8\u91CF\u8BFB\u5199\u3001`python-script` / `sql-query` \u6A21\u677F\u89C1 [\u8282\u70B9\u4EE3\u7801\u7F16\u5199\u6307\u5357](" + flowDocsRel(anchor, "flow/node-code-guide.md") + ") \u4E0E [\u6D41\u7A0B\u53D8\u91CF\u7CFB\u7EDF\u6307\u5357](" + flowDocsRel(anchor, "flow/variables-guide.md") + ")\u3002",
@@ -3837,7 +4169,7 @@ function buildDocsTable(anchor) {
3837
4169
  ];
3838
4170
  }
3839
4171
  function cliPrefix() {
3840
- return `\`${DAZI_PS1} flow\`\uFF08\u5728 **dazi-work \u6839**\uFF1B\u8FDB\u5165\u6D41\u7A0B\u76EE\u5F55\u540E\u53EF\u7528 \`flow\` \u5B50\u547D\u4EE4\u7701\u7565 \`--dir\`\uFF09`;
4172
+ return `\`${DAZI_CLI} flow\`\uFF08\u5168\u5C40 CLI\uFF1B\u5728 **dazi-work \u6839** \u6216\u6D41\u7A0B\u76EE\u5F55\u52A0 \`--dir .\`\uFF1B\u672A\u88C5\u5168\u5C40\u65F6\u53EF\u7528 \`.scriptsdazi.ps1 flow\`\uFF09`;
3841
4173
  }
3842
4174
  function buildFlowQuickStartMarkdown(opts) {
3843
4175
  const folder = opts.projectFolder;
@@ -3875,7 +4207,7 @@ function buildFlowQuickStartMarkdown(opts) {
3875
4207
  "\u547D\u4EE4\u884C\uFF08`dazi-work` \u6839\uFF09\uFF1A",
3876
4208
  "",
3877
4209
  "```powershell",
3878
- `.\\scripts\\dazi.ps1 flow project pull --flow <flowId> --dir "\u9879\u76EE\\${folder}\\\u6D41\u7A0B\\<\u6D41\u7A0B\u540D>"`,
4210
+ psFlowLine(`project pull --flow <flowId> --dir "\u9879\u76EE\\${folder}\\\u6D41\u7A0B\\<\u6D41\u7A0B\u540D>"`),
3879
4211
  "```",
3880
4212
  "",
3881
4213
  "\u62C9\u53D6\u540E\u6BCF\u4E2A\u6D41\u7A0B\u76EE\u5F55\u4F1A\u751F\u6210 **`\u5FEB\u901F\u542F\u52A8_<\u6D41\u7A0B\u540D>.md`**\uFF08\u542B flowId \u4E0E\u672C\u6D41\u7A0B\u5E38\u7528\u547D\u4EE4\uFF0C\u4FBF\u4E8E @ \u9644\u52A0\u7ED9 AI\uFF09\u3002",
@@ -3924,7 +4256,7 @@ function buildFlowsDirReadmeMarkdown(opts) {
3924
4256
  "",
3925
4257
  "```powershell",
3926
4258
  "# \u547D\u4EE4\u884C\u62C9\u53D6\uFF08dazi-work \u6839\uFF09",
3927
- `.\\scripts\\dazi.ps1 flow project pull --flow <id> --dir "\u9879\u76EE\\${opts.projectFolder}\\\u6D41\u7A0B\\<\u6D41\u7A0B\u540D>"`,
4259
+ psFlowLine(`project pull --flow <id> --dir "\u9879\u76EE\\${opts.projectFolder}\\\u6D41\u7A0B\\<\u6D41\u7A0B\u540D>"`),
3928
4260
  "```",
3929
4261
  "",
3930
4262
  "\u62C9\u53D6\u5B8C\u6210\u540E\u8BF7\u9605\u8BFB\u5404\u6D41\u7A0B\u5B50\u76EE\u5F55\u4E0B\u7684 **`\u5FEB\u901F\u542F\u52A8_<\u6D41\u7A0B\u540D>.md`**\u3002",
@@ -3934,10 +4266,34 @@ function buildFlowsDirReadmeMarkdown(opts) {
3934
4266
  }
3935
4267
  function buildFlowDirQuickStartMarkdown(opts) {
3936
4268
  const name = opts.flowName;
3937
- const stats = opts.nodeCount != null ? `
3938
- | \u8282\u70B9\u6570 | ${opts.nodeCount}${opts.codeNodeCount != null ? `\uFF08\u4EE3\u7801\u8282\u70B9 ${opts.codeNodeCount}\uFF09` : ""} |` : "";
4269
+ let audit;
4270
+ if (opts.flowDir) {
4271
+ try {
4272
+ audit = auditFlowWorkspace(opts.flowDir);
4273
+ } catch {
4274
+ }
4275
+ }
4276
+ const canvasN = audit?.canvasNodeCount ?? opts.nodeCount;
4277
+ const codeN = audit?.canvasCodeNodeCount ?? opts.codeNodeCount;
4278
+ const metaCodeN = audit?.metaCodeIndexedCount;
4279
+ const statsParts = [];
4280
+ if (canvasN != null) {
4281
+ let line = `
4282
+ | \u753B\u5E03\u8282\u70B9\uFF08flow.json\uFF09 | ${canvasN}`;
4283
+ if (codeN != null) line += `\uFF0C\u5176\u4E2D\u4EE3\u7801\u8282\u70B9 ${codeN}`;
4284
+ line += " |";
4285
+ statsParts.push(line);
4286
+ }
4287
+ if (metaCodeN != null && codeN != null && metaCodeN !== codeN) {
4288
+ statsParts.push(`
4289
+ | meta \u5DF2\u7D22\u5F15\u4EE3\u7801 | ${metaCodeN} \u26A0\uFE0F \u4E0E\u753B\u5E03\u4E0D\u4E00\u81F4 |`);
4290
+ } else if (metaCodeN != null) {
4291
+ statsParts.push(`
4292
+ | meta \u5DF2\u7D22\u5F15\u4EE3\u7801 | ${metaCodeN} |`);
4293
+ }
3939
4294
  const pulled = opts.pulledAt ? `
3940
4295
  | \u4E0A\u6B21\u62C9\u53D6 | ${opts.pulledAt} |` : "";
4296
+ const consistencySection = audit ? buildFlowConsistencyMarkdown(audit, flowDocsRel("flow-dir", "flow/local-files-spec.md")) : [];
3941
4297
  return [
3942
4298
  SCAFFOLD_MARKER,
3943
4299
  "# \u5FEB\u901F\u542F\u52A8",
@@ -3949,27 +4305,28 @@ function buildFlowDirQuickStartMarkdown(opts) {
3949
4305
  "| \u5B57\u6BB5 | \u503C |",
3950
4306
  "|------|-----|",
3951
4307
  `| flowId | \`${opts.flowId}\` |`,
3952
- `| \u672C\u5730\u76EE\u5F55 | \`\u6D41\u7A0B/${name}/\` |${stats}${pulled}`,
4308
+ `| \u672C\u5730\u76EE\u5F55 | \`\u6D41\u7A0B/${name}/\` |${statsParts.join("")}${pulled}`,
3953
4309
  "",
4310
+ ...consistencySection,
3954
4311
  "## \u5E38\u7528\u547D\u4EE4",
3955
4312
  "",
3956
- "\u5728 **dazi-work \u6839**\uFF08\u6216\u5C06 `--dir` \u6307\u5411\u672C\u76EE\u5F55\uFF09\uFF1A",
4313
+ "\u5728 **dazi-work \u6839**\uFF08\u6216\u5C06 `--dir` \u6307\u5411\u672C\u76EE\u5F55\uFF09\uFF1B\u9700\u5DF2\u5B89\u88C5\u5168\u5C40 CLI\uFF08`pnpm add -g @dazitech/cli`\uFF09\uFF1A",
3957
4314
  "",
3958
4315
  "```powershell",
3959
4316
  `cd "\u9879\u76EE\\${opts.projectFolder ?? "flow_<\u9879\u76EE\u540D>"}\\\u6D41\u7A0B\\${name}"`,
3960
4317
  "",
3961
4318
  "# \u72B6\u6001 / \u62C9\u53D6 / \u63D0\u4EA4",
3962
- `${DAZI_PS1} flow project status --dir .`,
3963
- `${DAZI_PS1} flow project pull --flow ${opts.flowId} --dir .`,
3964
- `${DAZI_PS1} flow project push --dir . --canvas`,
4319
+ psFlowLine("project status --dir ."),
4320
+ psFlowLine(`project pull --flow ${opts.flowId} --dir .`),
4321
+ psFlowLine("project push --dir . --canvas"),
3965
4322
  "",
3966
4323
  "# \u5355\u8282\u70B9\u6D4B\u8BD5\uFF08uuid \u89C1 flow.meta.json \u6216 node.info.json\uFF09",
3967
- `${DAZI_PS1} flow run node-exec --node <node_uuid> --dir .`,
4324
+ psFlowLine("run node-exec --node <node_uuid> --dir ."),
3968
4325
  "",
3969
4326
  "# \u6574\u6D41\u7A0B\u8C03\u8BD5 + \u53D8\u91CF",
3970
- `${DAZI_PS1} flow run flow-exec --dir . --type debug`,
3971
- `${DAZI_PS1} flow variable sync --dir .`,
3972
- `${DAZI_PS1} flow variable pull --name <output_variable_name> --dir .`,
4327
+ psFlowLine("run flow-exec --dir . --type debug"),
4328
+ psFlowLine("variable sync --dir ."),
4329
+ psFlowLine("variable pull --name <output_variable_name> --dir ."),
3973
4330
  "```",
3974
4331
  "",
3975
4332
  ...buildFlowNodeCatalogQuickStartSection(flowDocsRel("flow-dir", "flow/flows-guide.md")),
@@ -3979,10 +4336,10 @@ function buildFlowDirQuickStartMarkdown(opts) {
3979
4336
  "",
3980
4337
  "### \u573A\u666F A\uFF1A\u65B0\u589E\u8282\u70B9\uFF08\u5DF2\u6709\u6D41\u7A0B\u7EE7\u7EED\u6539\uFF09",
3981
4338
  "",
3982
- "1. \u5148\u8BFB `flow.json` \u4E0E `flow.meta.json`\uFF0C\u786E\u8BA4\u5F53\u524D\u8282\u70B9\u4E0E\u8FDE\u7EBF",
3983
- `2. \u65B0\u5EFA\u8282\u70B9\uFF08\u907F\u514D\u4F2A\u9020 uuid\uFF09\uFF1A${mdFlowCmd('node new --type <node_type> --dir . --label "<\u8282\u70B9\u540D>"')}`,
4339
+ "1. \u5148\u8BFB `flow.json` \u4E0E `flow.meta.json`\uFF0C\u6267\u884C `dazi flow project doctor --dir .`",
4340
+ `2. **\u5FC5\u987B**\u7528 CLI \u65B0\u5EFA\u8282\u70B9\uFF08\u7981\u6B62\u624B\u6413 uuid\uFF09\uFF1A${mdFlowCmd('node new --type <node_type> --dir . --label "<\u8282\u70B9\u540D>"')}`,
3984
4341
  "3. \u5728 `flow.json` \u91CC\u8865 `nodes/edges`\uFF08\u9075\u5B88\u951A\u70B9\uFF1A`sourceHandle` \u4EC5 `r/b/true/false`\uFF0C`targetHandle` \u4EC5 `l/t`\uFF09",
3985
- "4. \u82E5\u662F\u4EE3\u7801\u8282\u70B9\uFF0C\u8865 `\u8282\u70B9/<\u540D>/code.sql|py`\uFF08type \u89C1\u4E0A\u6587 **\u53EF\u7528\u6D41\u7A0B\u8282\u70B9**\uFF09",
4342
+ "4. \u7F16\u8F91 `\u8282\u70B9/<\u540D>/code.sql|py`\uFF08`node new` \u4F1A\u521B\u5EFA\u76EE\u5F55\u4E0E meta \u7D22\u5F15\uFF09",
3986
4343
  `5. \u5355\u8282\u70B9\u6D4B\u8BD5\uFF1A${mdFlowCmd("run node-exec --node <node_uuid> --dir .")}`,
3987
4344
  `6. \u63D0\u4EA4\u753B\u5E03\uFF08\u542B\u8FDE\u7EBF/\u914D\u7F6E\uFF09\uFF1A${mdFlowCmd("project push --dir . --canvas")}`,
3988
4345
  "",
@@ -4011,7 +4368,7 @@ function buildFlowDirQuickStartMarkdown(opts) {
4011
4368
  "",
4012
4369
  "| \u73B0\u8C61 | \u5E38\u89C1\u539F\u56E0 | \u4FEE\u590D |",
4013
4370
  "|------|----------|------|",
4014
- `| \u547D\u4EE4\u627E\u4E0D\u5230 | \u5728 dazi-work \u5916\u6267\u884C\uFF0C\u6216\u7528\u4E86\u65E7\u524D\u7F00 | \u5207\u5230 dazi-work \u6839\uFF0C\u4F7F\u7528 ${mdFlowCmd("...")} |`,
4371
+ `| \u547D\u4EE4\u627E\u4E0D\u5230 | \u672A\u88C5\u5168\u5C40 CLI \u6216\u4E0D\u5728 dazi-work | \`pnpm add -g @dazitech/cli\` \u6216 ${mdFlowCmd("...")} / \`.scriptsdazi.ps1 flow ...\` |`,
4015
4372
  "| \u8282\u70B9\u6D4B\u8BD5\u62A5\u4E0A\u6E38\u53D8\u91CF\u4E0D\u5B58\u5728 | \u672A\u5148\u8FD0\u884C\u4E0A\u6E38\u8282\u70B9\u4EA7\u51FA\u53D8\u91CF | \u5148\u8DD1\u4E0A\u6E38\uFF0C\u6216\u6574\u6D41\u7A0B `flow run flow-exec --type debug` \u540E\u518D\u6D4B |",
4016
4373
  "| excel-python \u627E\u4E0D\u5230\u6587\u4EF6 | code.py \u5199\u4E86\u6587\u4EF6\u540D/\u672C\u5730\u8DEF\u5F84 | \u753B\u5E03\u914D `managed_file_id`\uFF08UUID\uFF09\uFF1B\u4EE3\u7801\u7528 `excel_source_path` |",
4017
4374
  "| Excel \u7528\u4E86 file-source | file-source \u4E0D\u89E3\u6790 xlsx | \u6539\u4E3A **`excel-python`** + `managed_file_id` |",
@@ -4078,7 +4435,7 @@ function buildFlowDirQuickStartMarkdown(opts) {
4078
4435
  ].join("\n");
4079
4436
  }
4080
4437
  function removeLegacyFlowDirQuickStartFiles(flowDir, currentFilename, fsImpl) {
4081
- const legacy = import_path7.default.join(flowDir, LEGACY_FLOW_DIR_QUICKSTART_FILENAME);
4438
+ const legacy = import_path8.default.join(flowDir, LEGACY_FLOW_DIR_QUICKSTART_FILENAME);
4082
4439
  if (fsImpl.existsSync(legacy)) {
4083
4440
  try {
4084
4441
  if (isFlowScaffoldFile(fsImpl.readFileSync(legacy, "utf8"))) {
@@ -4090,7 +4447,7 @@ function removeLegacyFlowDirQuickStartFiles(flowDir, currentFilename, fsImpl) {
4090
4447
  for (const entry of fsImpl.readdirSync(flowDir)) {
4091
4448
  if (entry === currentFilename) continue;
4092
4449
  if (!/^快速启动_.+\.md$/.test(entry)) continue;
4093
- const full = import_path7.default.join(flowDir, entry);
4450
+ const full = import_path8.default.join(flowDir, entry);
4094
4451
  try {
4095
4452
  if (isFlowScaffoldFile(fsImpl.readFileSync(full, "utf8"))) {
4096
4453
  fsImpl.unlinkSync(full);
@@ -4101,12 +4458,12 @@ function removeLegacyFlowDirQuickStartFiles(flowDir, currentFilename, fsImpl) {
4101
4458
  }
4102
4459
  function writeFlowDirQuickStartScaffold(flowDir, flowName, content, fsImpl) {
4103
4460
  const filename = flowDirQuickStartFilename(flowName);
4104
- writeScaffoldIfAllowed(import_path7.default.join(flowDir, filename), content, fsImpl);
4461
+ writeScaffoldIfAllowed(import_path8.default.join(flowDir, filename), content, fsImpl);
4105
4462
  removeLegacyFlowDirQuickStartFiles(flowDir, filename, fsImpl);
4106
4463
  return filename;
4107
4464
  }
4108
4465
  function removeLegacyFlowDirScaffoldReadme(flowDir, fsImpl) {
4109
- const legacy = import_path7.default.join(flowDir, "README.md");
4466
+ const legacy = import_path8.default.join(flowDir, "README.md");
4110
4467
  if (!fsImpl.existsSync(legacy)) return;
4111
4468
  try {
4112
4469
  if (isFlowScaffoldFile(fsImpl.readFileSync(legacy, "utf8"))) {
@@ -4127,17 +4484,17 @@ function writeScaffoldIfAllowed(filePath, content, fsImpl, opts) {
4127
4484
  }
4128
4485
 
4129
4486
  // cli/dazi-flow/src/lib/flowVariables.ts
4130
- var import_fs6 = __toESM(require("fs"), 1);
4131
- var import_path8 = __toESM(require("path"), 1);
4487
+ var import_fs7 = __toESM(require("fs"), 1);
4488
+ var import_path9 = __toESM(require("path"), 1);
4132
4489
  async function ensureFlowDebugRun(flowId) {
4133
4490
  return apiRequest(`${FLOW_API}/${flowId}/debug-run`);
4134
4491
  }
4135
4492
  function variablesDir(flowDir) {
4136
- return import_path8.default.join(flowDir, VARIABLES_DIR);
4493
+ return import_path9.default.join(flowDir, VARIABLES_DIR);
4137
4494
  }
4138
4495
  function variableFilePath(flowDir, varName) {
4139
4496
  const safe = sanitizeName(varName) || "variable";
4140
- return import_path8.default.join(variablesDir(flowDir), `${safe}.json`);
4497
+ return import_path9.default.join(variablesDir(flowDir), `${safe}.json`);
4141
4498
  }
4142
4499
  function collectDesignTimeVariableNames(flowDir) {
4143
4500
  const doc = readFlowJson(flowDir);
@@ -4151,9 +4508,9 @@ function collectDesignTimeVariableNames(flowDir) {
4151
4508
  }
4152
4509
  function writeVariableFile(flowDir, payload) {
4153
4510
  const dir = variablesDir(flowDir);
4154
- import_fs6.default.mkdirSync(dir, { recursive: true });
4511
+ import_fs7.default.mkdirSync(dir, { recursive: true });
4155
4512
  const file = variableFilePath(flowDir, payload.name);
4156
- import_fs6.default.writeFileSync(file, JSON.stringify(payload, null, 2), "utf8");
4513
+ import_fs7.default.writeFileSync(file, JSON.stringify(payload, null, 2), "utf8");
4157
4514
  return file;
4158
4515
  }
4159
4516
  async function fetchVariableDetail(variableId, previewLimit) {
@@ -4277,7 +4634,17 @@ async function syncAllVariables(flowId, flowDir, previewLimit = 10) {
4277
4634
 
4278
4635
  // cli/dazi-flow/src/commands/project.ts
4279
4636
  function resolveFlowDir(dir) {
4280
- return import_path9.default.resolve(dir ?? process.cwd());
4637
+ return import_path10.default.resolve(dir ?? process.cwd());
4638
+ }
4639
+ function readLocalCanvasNodeCount(flowDir) {
4640
+ const p = import_path10.default.join(flowDir, "flow.json");
4641
+ if (!import_fs8.default.existsSync(p)) return 0;
4642
+ try {
4643
+ const doc = JSON.parse(import_fs8.default.readFileSync(p, "utf8"));
4644
+ return Array.isArray(doc.nodes) ? doc.nodes.length : 0;
4645
+ } catch {
4646
+ return 0;
4647
+ }
4281
4648
  }
4282
4649
  function inferProjectFolder(flowDir) {
4283
4650
  const norm = flowDir.replace(/\\/g, "/");
@@ -4286,41 +4653,42 @@ function inferProjectFolder(flowDir) {
4286
4653
  }
4287
4654
  function writeFlowPullScaffold(flowDir, meta) {
4288
4655
  const projectFolder = inferProjectFolder(flowDir) ?? "flow_<\u9879\u76EE\u540D>";
4289
- const flowName = meta.flowName || import_path9.default.basename(flowDir);
4656
+ const flowName = meta.flowName || import_path10.default.basename(flowDir);
4290
4657
  const quickStart = buildFlowDirQuickStartMarkdown({
4291
4658
  flowName,
4292
4659
  flowId: meta.flowId,
4293
4660
  projectFolder,
4294
4661
  nodeCount: meta.nodeCount,
4295
4662
  codeNodeCount: meta.codeNodeCount,
4296
- pulledAt: (/* @__PURE__ */ new Date()).toISOString()
4663
+ pulledAt: (/* @__PURE__ */ new Date()).toISOString(),
4664
+ flowDir
4297
4665
  });
4298
- writeFlowDirQuickStartScaffold(flowDir, flowName, quickStart, import_fs7.default);
4299
- removeLegacyFlowDirScaffoldReadme(flowDir, import_fs7.default);
4300
- const flowsDir = import_path9.default.dirname(flowDir);
4301
- if (import_path9.default.basename(flowsDir) === "\u6D41\u7A0B") {
4666
+ writeFlowDirQuickStartScaffold(flowDir, flowName, quickStart, import_fs8.default);
4667
+ removeLegacyFlowDirScaffoldReadme(flowDir, import_fs8.default);
4668
+ const flowsDir = import_path10.default.dirname(flowDir);
4669
+ if (import_path10.default.basename(flowsDir) === "\u6D41\u7A0B") {
4302
4670
  const flowsReadme = buildFlowsDirReadmeMarkdown({ projectFolder });
4303
- writeScaffoldIfAllowed(import_path9.default.join(flowsDir, "README.md"), flowsReadme, import_fs7.default, { upgradeLegacy: true });
4304
- const projectRoot = import_path9.default.dirname(flowsDir);
4671
+ writeScaffoldIfAllowed(import_path10.default.join(flowsDir, "README.md"), flowsReadme, import_fs8.default, { upgradeLegacy: true });
4672
+ const projectRoot = import_path10.default.dirname(flowsDir);
4305
4673
  const quickStart2 = buildFlowQuickStartMarkdown({ projectFolder });
4306
- writeScaffoldIfAllowed(import_path9.default.join(projectRoot, "\u5FEB\u901F\u542F\u52A8.md"), quickStart2, import_fs7.default, { upgradeLegacy: true });
4674
+ writeScaffoldIfAllowed(import_path10.default.join(projectRoot, "\u5FEB\u901F\u542F\u52A8.md"), quickStart2, import_fs8.default, { upgradeLegacy: true });
4307
4675
  }
4308
4676
  }
4309
4677
  function makeProjectCommand() {
4310
4678
  const cmd = new Command("project").description("\u6D41\u7A0B\u9879\u76EE\u672C\u5730\u6587\u4EF6\u5316\uFF08\u62C9\u53D6/\u63D0\u4EA4/\u72B6\u6001\uFF09");
4311
4679
  cmd.command("init <name>").description("\u5728 \u9879\u76EE/flow_<name>/ \u521D\u59CB\u5316\u6D41\u7A0B\u9879\u76EE\u9AA8\u67B6").option("--root <dir>", "\u5DE5\u4F5C\u533A\u6839\uFF08\u9ED8\u8BA4 cwd\uFF09").option("--json", "\u8F93\u51FA JSON").action((name, opts) => {
4312
4680
  try {
4313
- const root = import_path9.default.resolve(opts.root ?? process.cwd());
4681
+ const root = import_path10.default.resolve(opts.root ?? process.cwd());
4314
4682
  const folder = name.startsWith("flow_") ? name : `flow_${name}`;
4315
- const projectRoot = import_path9.default.join(root, "\u9879\u76EE", folder);
4316
- if (import_fs7.default.existsSync(projectRoot)) {
4683
+ const projectRoot = import_path10.default.join(root, "\u9879\u76EE", folder);
4684
+ if (import_fs8.default.existsSync(projectRoot)) {
4317
4685
  console.error(`\u9519\u8BEF: \u9879\u76EE\u76EE\u5F55\u5DF2\u5B58\u5728: ${projectRoot}`);
4318
4686
  process.exit(1);
4319
4687
  }
4320
- import_fs7.default.mkdirSync(import_path9.default.join(projectRoot, "\u6D41\u7A0B"), { recursive: true });
4321
- import_fs7.default.mkdirSync(import_path9.default.join(projectRoot, "\u89C4\u5212"), { recursive: true });
4322
- import_fs7.default.writeFileSync(
4323
- import_path9.default.join(projectRoot, "README.md"),
4688
+ import_fs8.default.mkdirSync(import_path10.default.join(projectRoot, "\u6D41\u7A0B"), { recursive: true });
4689
+ import_fs8.default.mkdirSync(import_path10.default.join(projectRoot, "\u89C4\u5212"), { recursive: true });
4690
+ import_fs8.default.writeFileSync(
4691
+ import_path10.default.join(projectRoot, "README.md"),
4324
4692
  `# ${name}
4325
4693
 
4326
4694
  \u6570\u636E\u6D41\u7A0B\u9879\u76EE\uFF08\u4E0D\u7ED1\u5B9A\u6570\u636E\u7A7A\u95F4/\u8FDE\u63A5\uFF09\u3002\u6D41\u7A0B\u4F4D\u4E8E \`\u6D41\u7A0B/\` \u76EE\u5F55\u3002
@@ -4330,14 +4698,14 @@ function makeProjectCommand() {
4330
4698
  "utf8"
4331
4699
  );
4332
4700
  writeScaffoldIfAllowed(
4333
- import_path9.default.join(projectRoot, "\u5FEB\u901F\u542F\u52A8.md"),
4701
+ import_path10.default.join(projectRoot, "\u5FEB\u901F\u542F\u52A8.md"),
4334
4702
  buildFlowQuickStartMarkdown({ projectFolder: folder }),
4335
- import_fs7.default
4703
+ import_fs8.default
4336
4704
  );
4337
4705
  writeScaffoldIfAllowed(
4338
- import_path9.default.join(projectRoot, "\u6D41\u7A0B", "README.md"),
4706
+ import_path10.default.join(projectRoot, "\u6D41\u7A0B", "README.md"),
4339
4707
  buildFlowsDirReadmeMarkdown({ projectFolder: folder }),
4340
- import_fs7.default
4708
+ import_fs8.default
4341
4709
  );
4342
4710
  console.log(`\u2705 \u6D41\u7A0B\u9879\u76EE\u5DF2\u521D\u59CB\u5316: ${projectRoot}`);
4343
4711
  ok({ projectRoot, folder });
@@ -4348,11 +4716,21 @@ function makeProjectCommand() {
4348
4716
  cmd.command("pull").description("\u4ECE\u5E73\u53F0\u62C9\u53D6\u6D41\u7A0B\u5FEB\u7167\u5E76\u62C6\u5206\u4E3A\u672C\u5730\u6587\u4EF6\uFF08flow.json + \u8282\u70B9/<\u540D>/code.*\uFF09").requiredOption("--flow <flowId>", "Flow ID").option("--dir <dir>", "\u6D41\u7A0B\u76EE\u5F55\uFF08\u9ED8\u8BA4 cwd\uFF09").option("--json", "\u8F93\u51FA JSON").action(async (opts) => {
4349
4717
  try {
4350
4718
  const flowDir = resolveFlowDir(opts.dir);
4351
- import_fs7.default.mkdirSync(flowDir, { recursive: true });
4719
+ import_fs8.default.mkdirSync(flowDir, { recursive: true });
4720
+ const localCount = readLocalCanvasNodeCount(flowDir);
4721
+ const preAudit = localCount > 0 ? auditFlowWorkspace(flowDir) : null;
4722
+ if (preAudit && !preAudit.ok) {
4723
+ console.warn("\u26A0\uFE0F flow.json \u4E0E flow.meta.json \u4E0D\u4E00\u81F4\uFF1Bpull \u5C06\u7528\u5E73\u53F0\u5FEB\u7167\u8986\u76D6 flow.json\u3002\u624B\u6539\u753B\u5E03\u672A push \u65F6\u53EF\u80FD\u4E22\u5931\uFF0C\u53EF\u5148 repair-meta \u6216 push --canvas\u3002");
4724
+ }
4352
4725
  console.log(`\u6B63\u5728\u62C9\u53D6\u6D41\u7A0B\u5FEB\u7167: ${opts.flow} ...`);
4353
4726
  const snapshot = await apiRequest(`${FLOW_API}/${opts.flow}/snapshot`);
4354
4727
  const doc = extractDocument(snapshot);
4355
4728
  const { strippedDoc, nodeMetas } = splitDocumentToFiles(flowDir, doc);
4729
+ if (localCount > strippedDoc.nodes.length) {
4730
+ console.warn(
4731
+ `\u26A0\uFE0F \u672C\u5730\u753B\u5E03 ${localCount} \u4E2A\u8282\u70B9\uFF0C\u5E73\u53F0\u5FEB\u7167 ${strippedDoc.nodes.length} \u4E2A\uFF1Bpull \u5DF2\u8986\u76D6\u672C\u5730 flow.json\u3002\u82E5\u672C\u5730\u66F4\u65B0\u5C1A\u672A\u63D0\u4EA4\uFF0C\u8BF7\u52FF\u518D pull\uFF0C\u5E94\u5148 project push --canvas\u3002`
4732
+ );
4733
+ }
4356
4734
  const flowMeta = snapshot.flow_meta ?? {};
4357
4735
  const meta = {
4358
4736
  flowId: opts.flow,
@@ -4365,7 +4743,7 @@ function makeProjectCommand() {
4365
4743
  const codeNodes = Object.values(nodeMetas).filter((m) => m.codeFile).length;
4366
4744
  writeFlowPullScaffold(flowDir, {
4367
4745
  flowId: opts.flow,
4368
- flowName: String(flowMeta.name ?? import_path9.default.basename(flowDir)),
4746
+ flowName: String(flowMeta.name ?? import_path10.default.basename(flowDir)),
4369
4747
  nodeCount: strippedDoc.nodes.length,
4370
4748
  codeNodeCount: codeNodes
4371
4749
  });
@@ -4461,12 +4839,64 @@ function makeProjectCommand() {
4461
4839
  handleError(err);
4462
4840
  }
4463
4841
  });
4842
+ cmd.command("doctor").description("\u68C0\u67E5 flow.json / flow.meta.json / \u8282\u70B9/ \u4E00\u81F4\u6027").option("--dir <dir>", "\u6D41\u7A0B\u76EE\u5F55\uFF08\u9ED8\u8BA4 cwd\uFF09").option("--json", "\u8F93\u51FA JSON").action((opts) => {
4843
+ try {
4844
+ const flowDir = resolveFlowDir(opts.dir);
4845
+ const audit = auditFlowWorkspace(flowDir);
4846
+ if (!opts.json) {
4847
+ console.log(`\u6D41\u7A0B\u76EE\u5F55: ${flowDir}`);
4848
+ console.log(audit.ok ? "\u2705 \u672C\u5730\u6587\u4EF6\u4E00\u81F4" : "\u26A0\uFE0F \u5B58\u5728\u4E0D\u4E00\u81F4\u9879");
4849
+ for (const w of audit.warnings) console.log(` - ${w}`);
4850
+ if (!audit.ok) {
4851
+ console.log("\n\u4FEE\u590D: dazi flow project repair-meta --dir .");
4852
+ console.log("\u8BF4\u660E: \u8D44\u6E90/docs/flow/local-files-spec.md");
4853
+ }
4854
+ }
4855
+ ok(audit);
4856
+ } catch (err) {
4857
+ handleError(err);
4858
+ }
4859
+ });
4860
+ cmd.command("repair-meta").description("\u6839\u636E flow.json \u4E0E \u8282\u70B9/ \u76EE\u5F55\u4FEE\u590D flow.meta.json\uFF08\u53CA node.info.json\uFF09").option("--dir <dir>", "\u6D41\u7A0B\u76EE\u5F55\uFF08\u9ED8\u8BA4 cwd\uFF09").option("--json", "\u8F93\u51FA JSON").action((opts) => {
4861
+ try {
4862
+ const flowDir = resolveFlowDir(opts.dir);
4863
+ const result = repairFlowMeta(flowDir);
4864
+ const meta = readMeta(flowDir);
4865
+ if (meta?.flowId) {
4866
+ const audit = auditFlowWorkspace(flowDir);
4867
+ writeFlowPullScaffold(flowDir, {
4868
+ flowId: String(meta.flowId),
4869
+ flowName: meta.flowName || import_path10.default.basename(flowDir),
4870
+ nodeCount: audit.canvasNodeCount,
4871
+ codeNodeCount: audit.canvasCodeNodeCount,
4872
+ pulledAt: meta.lastPulledAt,
4873
+ flowDir
4874
+ });
4875
+ if (!opts.json) console.log(" \u5DF2\u66F4\u65B0 \u5FEB\u901F\u542F\u52A8_*.md\uFF08\u542B\u4E00\u81F4\u6027\u7EDF\u8BA1\uFF09");
4876
+ }
4877
+ if (!opts.json) {
4878
+ console.log(`\u6D41\u7A0B\u76EE\u5F55: ${flowDir}`);
4879
+ if (result.repairedUuids.length) {
4880
+ console.log(`\u2705 \u5DF2\u4FEE\u590D meta \u7D22\u5F15: ${result.repairedUuids.join(", ")}`);
4881
+ } else {
4882
+ console.log("\uFF08meta \u65E0\u9700\u53D8\u66F4\uFF09");
4883
+ }
4884
+ for (const p of result.wroteNodeInfo) console.log(` + node.info.json \u2192 ${p}`);
4885
+ for (const w of result.warnings) console.log(` \u26A0 ${w}`);
4886
+ const audit = auditFlowWorkspace(flowDir);
4887
+ console.log(audit.ok ? "\u2705 doctor \u68C0\u67E5\u901A\u8FC7" : "\u26A0\uFE0F \u4ECD\u6709\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u67E5\u770B doctor \u8F93\u51FA");
4888
+ }
4889
+ ok(result);
4890
+ } catch (err) {
4891
+ handleError(err);
4892
+ }
4893
+ });
4464
4894
  return cmd;
4465
4895
  }
4466
4896
 
4467
4897
  // cli/dazi-flow/src/commands/node.ts
4468
- var import_path10 = __toESM(require("path"), 1);
4469
- var import_fs8 = __toESM(require("fs"), 1);
4898
+ var import_path11 = __toESM(require("path"), 1);
4899
+ var import_fs9 = __toESM(require("fs"), 1);
4470
4900
  var NODE_TYPE_REQUIRED = {
4471
4901
  "database-source": ["connectionId", "sql"],
4472
4902
  "database-sink": ["connectionId", "tableName"],
@@ -4498,7 +4928,7 @@ var NODE_TYPE_LABELS = {
4498
4928
  "folder-resource-register": "\u8D44\u6E90\u6CE8\u518C"
4499
4929
  };
4500
4930
  function resolveFlowDir2(dir) {
4501
- return import_path10.default.resolve(dir ?? process.cwd());
4931
+ return import_path11.default.resolve(dir ?? process.cwd());
4502
4932
  }
4503
4933
  function requireMeta(flowDir) {
4504
4934
  const meta = readMeta(flowDir);
@@ -4584,19 +5014,19 @@ function makeNodeCommand() {
4584
5014
  data: created.data ?? {}
4585
5015
  };
4586
5016
  doc.nodes.push(stripped);
4587
- import_fs8.default.writeFileSync(import_path10.default.join(flowDir, FLOW_JSON), JSON.stringify(doc, null, 2), "utf8");
5017
+ import_fs9.default.writeFileSync(import_path11.default.join(flowDir, FLOW_JSON), JSON.stringify(doc, null, 2), "utf8");
4588
5018
  const nodeMeta = { nodeId: String(created.id ?? ""), nodeType: opts.type };
4589
5019
  const codeKey = NODE_TYPE_CODE_DATA_KEY[opts.type];
4590
5020
  if (codeKey) {
4591
5021
  const language = codeLanguageForNodeType(opts.type);
4592
5022
  const ext = codeFileExt(language);
4593
5023
  const dirName = sanitizeName(opts.label || String(created.id ?? "") || opts.type);
4594
- const nodeDirAbs = import_path10.default.join(flowDir, NODES_DIR, dirName);
4595
- import_fs8.default.mkdirSync(nodeDirAbs, { recursive: true });
5024
+ const nodeDirAbs = import_path11.default.join(flowDir, NODES_DIR, dirName);
5025
+ import_fs9.default.mkdirSync(nodeDirAbs, { recursive: true });
4596
5026
  const codeFile = `code.${ext}`;
4597
5027
  const template = CODE_TEMPLATES[language ?? ""] ?? "";
4598
- import_fs8.default.writeFileSync(import_path10.default.join(nodeDirAbs, codeFile), template, "utf8");
4599
- nodeMeta.dir = import_path10.default.posix.join(NODES_DIR, dirName);
5028
+ import_fs9.default.writeFileSync(import_path11.default.join(nodeDirAbs, codeFile), template, "utf8");
5029
+ nodeMeta.dir = import_path11.default.posix.join(NODES_DIR, dirName);
4600
5030
  nodeMeta.codeFile = codeFile;
4601
5031
  nodeMeta.codeLanguage = language;
4602
5032
  nodeMeta.codeHash = sha1(template);
@@ -4616,11 +5046,11 @@ function makeNodeCommand() {
4616
5046
  }
4617
5047
 
4618
5048
  // cli/dazi-flow/src/commands/run.ts
4619
- var import_path12 = __toESM(require("path"), 1);
5049
+ var import_path13 = __toESM(require("path"), 1);
4620
5050
 
4621
5051
  // cli/dazi-flow/src/lib/flowRun.ts
4622
- var import_fs9 = __toESM(require("fs"), 1);
4623
- var import_path11 = __toESM(require("path"), 1);
5052
+ var import_fs10 = __toESM(require("fs"), 1);
5053
+ var import_path12 = __toESM(require("path"), 1);
4624
5054
  function classifyError(text) {
4625
5055
  const t = (text || "").toLowerCase();
4626
5056
  if (/(变量|variable).*(不存在|未找到|missing|not found|undefined)|缺少.*输入|no.*input|上游/.test(t)) {
@@ -4650,16 +5080,16 @@ function classifyError(text) {
4650
5080
  return { category: "\u672A\u77E5", hint: "\u8BF7\u67E5\u770B\u5B8C\u6574 traceback \u4E0E\u65E5\u5FD7\u3002" };
4651
5081
  }
4652
5082
  function runDir(flowDir) {
4653
- const d = import_path11.default.join(flowDir, RUN_DIR);
4654
- import_fs9.default.mkdirSync(d, { recursive: true });
5083
+ const d = import_path12.default.join(flowDir, RUN_DIR);
5084
+ import_fs10.default.mkdirSync(d, { recursive: true });
4655
5085
  return d;
4656
5086
  }
4657
5087
  function safeBase(name) {
4658
5088
  return (name || "run").replace(/[<>:"/\\|?*\x00-\x1f]/g, "_").trim() || "run";
4659
5089
  }
4660
5090
  function writeLastRun(flowDir, base, payload) {
4661
- const p = import_path11.default.join(runDir(flowDir), `${safeBase(base)}.last-run.json`);
4662
- import_fs9.default.writeFileSync(p, JSON.stringify(payload, null, 2), "utf8");
5091
+ const p = import_path12.default.join(runDir(flowDir), `${safeBase(base)}.last-run.json`);
5092
+ import_fs10.default.writeFileSync(p, JSON.stringify(payload, null, 2), "utf8");
4663
5093
  return p;
4664
5094
  }
4665
5095
  function writeErrorMarkdown(flowDir, base, input) {
@@ -4696,8 +5126,8 @@ function writeErrorMarkdown(flowDir, base, input) {
4696
5126
  if (input.failureBundle != null) {
4697
5127
  lines.push("## FailureBundle", "", "```json", JSON.stringify(input.failureBundle, null, 2), "```", "");
4698
5128
  }
4699
- const p = import_path11.default.join(runDir(flowDir), `${safeBase(base)}.last-error.md`);
4700
- import_fs9.default.writeFileSync(p, lines.join("\n"), "utf8");
5129
+ const p = import_path12.default.join(runDir(flowDir), `${safeBase(base)}.last-error.md`);
5130
+ import_fs10.default.writeFileSync(p, lines.join("\n"), "utf8");
4701
5131
  return p;
4702
5132
  }
4703
5133
  var RUNNING_STATES = /* @__PURE__ */ new Set(["running", "pending", "queued", "debugging", "created", "init"]);
@@ -4830,15 +5260,15 @@ function writeRunProgressMarkdown(flowDir, base, snap, runId) {
4830
5260
  }
4831
5261
  }
4832
5262
  }
4833
- const p = import_path11.default.join(runDir(flowDir), `${safeBase(base)}.last-run.md`);
4834
- import_fs9.default.writeFileSync(p, lines.join("\n"), "utf8");
5263
+ const p = import_path12.default.join(runDir(flowDir), `${safeBase(base)}.last-run.md`);
5264
+ import_fs10.default.writeFileSync(p, lines.join("\n"), "utf8");
4835
5265
  return p;
4836
5266
  }
4837
5267
 
4838
5268
  // cli/dazi-flow/src/commands/run.ts
4839
5269
  var FLOW_API2 = "/api/data-pipelines/v1/flows";
4840
5270
  function resolveFlowDir3(dir) {
4841
- return import_path12.default.resolve(dir ?? process.cwd());
5271
+ return import_path13.default.resolve(dir ?? process.cwd());
4842
5272
  }
4843
5273
  function sleep(ms) {
4844
5274
  return new Promise((r) => setTimeout(r, ms));
@@ -5013,7 +5443,7 @@ function makeRunCommand() {
5013
5443
  console.error(`\u9519\u8BEF: \u672A\u627E\u5230\u8282\u70B9 ${opts.node} \u7684\u8BED\u4E49 id\uFF08meta.nodeId\uFF09`);
5014
5444
  process.exit(1);
5015
5445
  }
5016
- const base = nodeMeta?.dir ? import_path12.default.basename(nodeMeta.dir) : nodeId;
5446
+ const base = nodeMeta?.dir ? import_path13.default.basename(nodeMeta.dir) : nodeId;
5017
5447
  await apiRequest(`${FLOW_API2}/${flowId}/debug-run`);
5018
5448
  const result = await apiRequest(
5019
5449
  `${FLOW_API2}/${flowId}/nodes/${encodeURIComponent(nodeId)}/run`,
@@ -5178,8 +5608,8 @@ function makeRunCommand() {
5178
5608
  }
5179
5609
 
5180
5610
  // cli/dazi-flow/src/commands/source.ts
5181
- var import_path13 = __toESM(require("path"), 1);
5182
- var import_fs10 = __toESM(require("fs"), 1);
5611
+ var import_path14 = __toESM(require("path"), 1);
5612
+ var import_fs11 = __toESM(require("fs"), 1);
5183
5613
  function makeSourceCommand() {
5184
5614
  const cmd = new Command("source").description("\u6570\u636E\u6E90\u7BA1\u7406");
5185
5615
  cmd.command("list").description("\u5217\u51FA\u6570\u636E\u6E90").option("--space <spaceId>", "\u7A7A\u95F4 ID").option("--json", "\u8F93\u51FA JSON").action(async (opts) => {
@@ -5253,10 +5683,10 @@ function makeSourceCommand() {
5253
5683
  `/api/connections/${sourceId}/tables${qs}`
5254
5684
  );
5255
5685
  const ws = resolveWorkspace();
5256
- const dataDir = import_path13.default.join(ws.flows, opts.flow, "data");
5257
- if (!import_fs10.default.existsSync(dataDir)) import_fs10.default.mkdirSync(dataDir, { recursive: true });
5258
- const outFile = import_path13.default.join(dataDir, `${tableName}.schema.json`);
5259
- import_fs10.default.writeFileSync(outFile, JSON.stringify({
5686
+ const dataDir = import_path14.default.join(ws.flows, opts.flow, "data");
5687
+ if (!import_fs11.default.existsSync(dataDir)) import_fs11.default.mkdirSync(dataDir, { recursive: true });
5688
+ const outFile = import_path14.default.join(dataDir, `${tableName}.schema.json`);
5689
+ import_fs11.default.writeFileSync(outFile, JSON.stringify({
5260
5690
  sourceId,
5261
5691
  tableName,
5262
5692
  schema: opts.schema,
@@ -5330,8 +5760,8 @@ function makeDataspaceCommand() {
5330
5760
  }
5331
5761
 
5332
5762
  // cli/dazi-flow/src/commands/plan.ts
5333
- var import_path14 = __toESM(require("path"), 1);
5334
- var import_fs11 = __toESM(require("fs"), 1);
5763
+ var import_path15 = __toESM(require("path"), 1);
5764
+ var import_fs12 = __toESM(require("fs"), 1);
5335
5765
  function makePlanCommand() {
5336
5766
  const cmd = new Command("plan").description("Flow \u6267\u884C\u8BA1\u5212");
5337
5767
  cmd.command("compile <flowId>").alias("generate").description("\u7F16\u8BD1/\u751F\u6210 Flow \u6267\u884C\u8BA1\u5212").option("--out <file>", "\u8F93\u51FA\u6587\u4EF6\uFF08\u9ED8\u8BA4 flows/<flowId>/plans/plan.json\uFF09").option("--input <json>", "\u8F93\u5165\u53C2\u6570 JSON", "{}").option("--json", "\u8F93\u51FA JSON").action(async (flowId, opts) => {
@@ -5342,10 +5772,10 @@ function makePlanCommand() {
5342
5772
  { method: "POST", body: { input } }
5343
5773
  );
5344
5774
  const ws = resolveWorkspace();
5345
- const outFile = opts.out ?? import_path14.default.join(ws.flows, flowId, "plans", "plan.json");
5346
- const outDir = import_path14.default.dirname(outFile);
5347
- if (!import_fs11.default.existsSync(outDir)) import_fs11.default.mkdirSync(outDir, { recursive: true });
5348
- import_fs11.default.writeFileSync(outFile, JSON.stringify(plan, null, 2), "utf-8");
5775
+ const outFile = opts.out ?? import_path15.default.join(ws.flows, flowId, "plans", "plan.json");
5776
+ const outDir = import_path15.default.dirname(outFile);
5777
+ if (!import_fs12.default.existsSync(outDir)) import_fs12.default.mkdirSync(outDir, { recursive: true });
5778
+ import_fs12.default.writeFileSync(outFile, JSON.stringify(plan, null, 2), "utf-8");
5349
5779
  if (opts.json) {
5350
5780
  console.log(JSON.stringify(plan, null, 2));
5351
5781
  } else {
@@ -5359,12 +5789,12 @@ function makePlanCommand() {
5359
5789
  cmd.command("apply <flowId>").description("\u5C06\u672C\u5730\u8BA1\u5212\u6587\u4EF6\u63A8\u9001\u5230\u5E73\u53F0\u5E76\u5E94\u7528").option("--file <path>", "\u8BA1\u5212\u6587\u4EF6\uFF08\u9ED8\u8BA4 flows/<flowId>/plans/plan.json\uFF09").option("--dry-run", "\u4EC5\u9A8C\u8BC1\uFF0C\u4E0D\u5B9E\u9645\u5E94\u7528").action(async (flowId, opts) => {
5360
5790
  try {
5361
5791
  const ws = resolveWorkspace();
5362
- const planFile = opts.file ?? import_path14.default.join(ws.flows, flowId, "plans", "plan.json");
5363
- if (!import_fs11.default.existsSync(planFile)) {
5792
+ const planFile = opts.file ?? import_path15.default.join(ws.flows, flowId, "plans", "plan.json");
5793
+ if (!import_fs12.default.existsSync(planFile)) {
5364
5794
  console.error(`\u8BA1\u5212\u6587\u4EF6\u4E0D\u5B58\u5728: ${planFile}\uFF0C\u8BF7\u5148\u6267\u884C plan compile`);
5365
5795
  process.exit(1);
5366
5796
  }
5367
- const plan = JSON.parse(import_fs11.default.readFileSync(planFile, "utf-8"));
5797
+ const plan = JSON.parse(import_fs12.default.readFileSync(planFile, "utf-8"));
5368
5798
  const endpoint = opts.dryRun ? `/api/data-pipelines/v1/flows/${flowId}/validate` : `/api/data-pipelines/v1/apply-plan`;
5369
5799
  const result = await apiRequest(endpoint, { method: "POST", body: plan });
5370
5800
  console.log(`\u2705 ${opts.dryRun ? "\u8BA1\u5212\u9A8C\u8BC1\u901A\u8FC7" : "\u8BA1\u5212\u5DF2\u5E94\u7528"}`);
@@ -5379,10 +5809,10 @@ function makePlanCommand() {
5379
5809
  `/api/data-pipelines/v1/flows/${flowId}/snapshot`
5380
5810
  );
5381
5811
  const ws = resolveWorkspace();
5382
- const outFile = opts.out ?? import_path14.default.join(ws.flows, flowId, "plans", `plan-${opts.type}.md`);
5383
- const outDir = import_path14.default.dirname(outFile);
5384
- if (!import_fs11.default.existsSync(outDir)) import_fs11.default.mkdirSync(outDir, { recursive: true });
5385
- import_fs11.default.writeFileSync(outFile, doc.content, "utf-8");
5812
+ const outFile = opts.out ?? import_path15.default.join(ws.flows, flowId, "plans", `plan-${opts.type}.md`);
5813
+ const outDir = import_path15.default.dirname(outFile);
5814
+ if (!import_fs12.default.existsSync(outDir)) import_fs12.default.mkdirSync(outDir, { recursive: true });
5815
+ import_fs12.default.writeFileSync(outFile, doc.content, "utf-8");
5386
5816
  console.log(`\u2705 Markdown \u6587\u6863\u5DF2\u4FDD\u5B58: ${outFile}`);
5387
5817
  ok({ flowId, file: outFile });
5388
5818
  } catch (err) {
@@ -5395,10 +5825,10 @@ function makePlanCommand() {
5395
5825
  `/api/data-pipelines/v1/dq-ai-code-prompt`
5396
5826
  );
5397
5827
  const ws = resolveWorkspace();
5398
- const outFile = opts.out ?? import_path14.default.join(ws.flows, flowId, "plans", "llm-guide.md");
5399
- const outDir = import_path14.default.dirname(outFile);
5400
- if (!import_fs11.default.existsSync(outDir)) import_fs11.default.mkdirSync(outDir, { recursive: true });
5401
- import_fs11.default.writeFileSync(outFile, guide.content, "utf-8");
5828
+ const outFile = opts.out ?? import_path15.default.join(ws.flows, flowId, "plans", "llm-guide.md");
5829
+ const outDir = import_path15.default.dirname(outFile);
5830
+ if (!import_fs12.default.existsSync(outDir)) import_fs12.default.mkdirSync(outDir, { recursive: true });
5831
+ import_fs12.default.writeFileSync(outFile, guide.content, "utf-8");
5402
5832
  console.log(`\u2705 LLM \u5F15\u5BFC\u6587\u6863\u5DF2\u4FDD\u5B58: ${outFile}`);
5403
5833
  ok({ flowId, file: outFile });
5404
5834
  } catch (err) {
@@ -5411,11 +5841,11 @@ function makePlanCommand() {
5411
5841
  `/api/data-pipelines/v1/compile-plan`
5412
5842
  );
5413
5843
  const ws = resolveWorkspace();
5414
- const outDir = opts.out ?? import_path14.default.join(ws.flows, flowId, "plans", "db");
5415
- if (!import_fs11.default.existsSync(outDir)) import_fs11.default.mkdirSync(outDir, { recursive: true });
5844
+ const outDir = opts.out ?? import_path15.default.join(ws.flows, flowId, "plans", "db");
5845
+ if (!import_fs12.default.existsSync(outDir)) import_fs12.default.mkdirSync(outDir, { recursive: true });
5416
5846
  for (const f of scaffold.files ?? []) {
5417
- const outFile = import_path14.default.join(outDir, f.name);
5418
- import_fs11.default.writeFileSync(outFile, f.content, "utf-8");
5847
+ const outFile = import_path15.default.join(outDir, f.name);
5848
+ import_fs12.default.writeFileSync(outFile, f.content, "utf-8");
5419
5849
  console.log(` \u2192 ${outFile}`);
5420
5850
  }
5421
5851
  console.log(`\u2705 \u6570\u636E\u5E93\u811A\u624B\u67B6\u5DF2\u751F\u6210\uFF08${scaffold.files?.length ?? 0} \u4E2A\u6587\u4EF6\uFF09`);
@@ -5428,8 +5858,8 @@ function makePlanCommand() {
5428
5858
  }
5429
5859
 
5430
5860
  // cli/dazi-flow/src/commands/file.ts
5431
- var import_path15 = __toESM(require("path"), 1);
5432
- var import_fs12 = __toESM(require("fs"), 1);
5861
+ var import_path16 = __toESM(require("path"), 1);
5862
+ var import_fs13 = __toESM(require("fs"), 1);
5433
5863
  function makeFileCommand() {
5434
5864
  const cmd = new Command("file").description("\u5E73\u53F0\u6258\u7BA1\u6587\u4EF6\u7BA1\u7406");
5435
5865
  cmd.command("list").description("\u5217\u51FA\u5E73\u53F0\u6587\u4EF6").option("--space <spaceId>", "\u7A7A\u95F4 ID").option("--dir <dir>", "\u76EE\u5F55\u8DEF\u5F84\u524D\u7F00").option("--json", "\u8F93\u51FA JSON").action(async (opts) => {
@@ -5474,13 +5904,13 @@ function makeFileCommand() {
5474
5904
  });
5475
5905
  cmd.command("upload <localFile>").description("\u4E0A\u4F20\u672C\u5730\u6587\u4EF6\u5230\u5E73\u53F0").option("--space <spaceId>", "\u7A7A\u95F4 ID").option("--remote-path <path>", "\u8FDC\u7AEF\u8DEF\u5F84\uFF08\u9ED8\u8BA4\u4E0E\u6587\u4EF6\u540D\u76F8\u540C\uFF09").option("--overwrite", "\u8986\u76D6\u5DF2\u5B58\u5728\u6587\u4EF6").action(async (localFile, opts) => {
5476
5906
  try {
5477
- const filePath = import_path15.default.resolve(localFile);
5478
- if (!import_fs12.default.existsSync(filePath)) {
5907
+ const filePath = import_path16.default.resolve(localFile);
5908
+ if (!import_fs13.default.existsSync(filePath)) {
5479
5909
  console.error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
5480
5910
  process.exit(1);
5481
5911
  }
5482
- const content = import_fs12.default.readFileSync(filePath);
5483
- const remotePath = opts.remotePath ?? import_path15.default.basename(filePath);
5912
+ const content = import_fs13.default.readFileSync(filePath);
5913
+ const remotePath = opts.remotePath ?? import_path16.default.basename(filePath);
5484
5914
  const endpoint = opts.space ? `/api/v1/spaces/${opts.space}/files/upload` : "/api/v1/files/upload";
5485
5915
  const result = await apiRequest(endpoint, {
5486
5916
  method: "POST",
@@ -5506,16 +5936,16 @@ function makeFileCommand() {
5506
5936
  const content = data.encoding === "base64" ? Buffer.from(data.content, "base64") : Buffer.from(data.content, "utf-8");
5507
5937
  let outFile;
5508
5938
  if (opts.out) {
5509
- outFile = import_path15.default.resolve(opts.out);
5939
+ outFile = import_path16.default.resolve(opts.out);
5510
5940
  } else if (opts.flow) {
5511
5941
  const ws = resolveWorkspace();
5512
- const dataDir = import_path15.default.join(ws.flows, opts.flow, "data");
5513
- if (!import_fs12.default.existsSync(dataDir)) import_fs12.default.mkdirSync(dataDir, { recursive: true });
5514
- outFile = import_path15.default.join(dataDir, import_path15.default.basename(remotePath));
5942
+ const dataDir = import_path16.default.join(ws.flows, opts.flow, "data");
5943
+ if (!import_fs13.default.existsSync(dataDir)) import_fs13.default.mkdirSync(dataDir, { recursive: true });
5944
+ outFile = import_path16.default.join(dataDir, import_path16.default.basename(remotePath));
5515
5945
  } else {
5516
- outFile = import_path15.default.join(process.cwd(), import_path15.default.basename(remotePath));
5946
+ outFile = import_path16.default.join(process.cwd(), import_path16.default.basename(remotePath));
5517
5947
  }
5518
- import_fs12.default.writeFileSync(outFile, content);
5948
+ import_fs13.default.writeFileSync(outFile, content);
5519
5949
  console.log(`\u2705 \u5DF2\u4E0B\u8F7D: ${outFile}`);
5520
5950
  ok({ remotePath, localFile: outFile });
5521
5951
  } catch (err) {
@@ -5526,28 +5956,28 @@ function makeFileCommand() {
5526
5956
  }
5527
5957
 
5528
5958
  // cli/dazi-flow/src/commands/data.ts
5529
- var import_path16 = __toESM(require("path"), 1);
5530
- var import_fs13 = __toESM(require("fs"), 1);
5959
+ var import_path17 = __toESM(require("path"), 1);
5960
+ var import_fs14 = __toESM(require("fs"), 1);
5531
5961
  function makeDataCommand() {
5532
5962
  const cmd = new Command("data").description("Flow \u6570\u636E\u4E0A\u4F20");
5533
5963
  cmd.command("upload <localFile>").description("\u5C06\u672C\u5730\u6570\u636E\u6587\u4EF6\u4E0A\u4F20\u5230\u5E73\u53F0\uFF08CSV / JSON / Parquet\uFF09").option("--space <spaceId>", "\u76EE\u6807\u7A7A\u95F4 ID").option("--flow <flowId>", "\u5173\u8054 Flow ID\uFF08\u5199\u5165 flows/<flowId> \u5143\u6570\u636E\uFF09").option("--table <name>", "\u76EE\u6807\u8868\u540D\uFF08\u82E5\u5E73\u53F0\u652F\u6301\u76F4\u63A5\u5199\u8868\uFF09").option("--overwrite", "\u8986\u76D6\u5DF2\u6709\u6570\u636E").option("--json", "\u8F93\u51FA JSON").action(async (localFile, opts) => {
5534
5964
  try {
5535
- const filePath = import_path16.default.resolve(localFile);
5536
- if (!import_fs13.default.existsSync(filePath)) {
5965
+ const filePath = import_path17.default.resolve(localFile);
5966
+ if (!import_fs14.default.existsSync(filePath)) {
5537
5967
  console.error(`\u6587\u4EF6\u4E0D\u5B58\u5728: ${filePath}`);
5538
5968
  process.exit(1);
5539
5969
  }
5540
- const ext = import_path16.default.extname(filePath).toLowerCase();
5970
+ const ext = import_path17.default.extname(filePath).toLowerCase();
5541
5971
  const supportedExts = [".csv", ".json", ".jsonl", ".parquet", ".tsv"];
5542
5972
  if (!supportedExts.includes(ext)) {
5543
5973
  console.error(`\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u683C\u5F0F: ${ext}\uFF08\u652F\u6301: ${supportedExts.join(", ")}\uFF09`);
5544
5974
  process.exit(1);
5545
5975
  }
5546
- const content = import_fs13.default.readFileSync(filePath);
5976
+ const content = import_fs14.default.readFileSync(filePath);
5547
5977
  const body = {
5548
5978
  content: content.toString("base64"),
5549
5979
  encoding: "base64",
5550
- fileName: import_path16.default.basename(filePath),
5980
+ fileName: import_path17.default.basename(filePath),
5551
5981
  format: ext.slice(1),
5552
5982
  overwrite: opts.overwrite ?? false
5553
5983
  };
@@ -5575,9 +6005,9 @@ function makeDataCommand() {
5575
6005
  }
5576
6006
 
5577
6007
  // cli/dazi-flow/src/commands/variable.ts
5578
- var import_path17 = __toESM(require("path"), 1);
6008
+ var import_path18 = __toESM(require("path"), 1);
5579
6009
  function resolveFlowDir4(dir) {
5580
- return import_path17.default.resolve(dir ?? process.cwd());
6010
+ return import_path18.default.resolve(dir ?? process.cwd());
5581
6011
  }
5582
6012
  function requireFlowId(flowDir) {
5583
6013
  const meta = readMeta(flowDir);
@@ -5596,7 +6026,7 @@ function makeVariableCommand() {
5596
6026
  const previewLimit = Math.max(1, Math.min(100, parseInt(opts.limit, 10) || 10));
5597
6027
  if (!opts.json) console.log(`\u6B63\u5728\u540C\u6B65\u53D8\u91CF\uFF08flowId=${flowId}\uFF09\u2026`);
5598
6028
  const result = await syncAllVariables(flowId, flowDir, previewLimit);
5599
- if (!opts.json) console.log(`\u2705 \u5DF2\u540C\u6B65 ${result.count} \u4E2A\u53D8\u91CF \u2192 ${import_path17.default.join(flowDir, "\u53D8\u91CF")}`);
6029
+ if (!opts.json) console.log(`\u2705 \u5DF2\u540C\u6B65 ${result.count} \u4E2A\u53D8\u91CF \u2192 ${import_path18.default.join(flowDir, "\u53D8\u91CF")}`);
5600
6030
  ok({ flowId, flowDir, ...result });
5601
6031
  } catch (err) {
5602
6032
  handleError(err);
@@ -5811,12 +6241,12 @@ function makeMcpCommand() {
5811
6241
  }
5812
6242
 
5813
6243
  // cli/dazi-flow/src/commands/managedFiles.ts
5814
- var import_path19 = __toESM(require("path"), 1);
5815
- var import_fs15 = __toESM(require("fs"), 1);
6244
+ var import_path20 = __toESM(require("path"), 1);
6245
+ var import_fs16 = __toESM(require("fs"), 1);
5816
6246
 
5817
6247
  // src/shared/managedFilesBundle.ts
5818
- var import_fs14 = __toESM(require("fs"));
5819
- var import_path18 = __toESM(require("path"));
6248
+ var import_fs15 = __toESM(require("fs"));
6249
+ var import_path19 = __toESM(require("path"));
5820
6250
 
5821
6251
  // src/shared/managedFilesTypes.ts
5822
6252
  var MANAGED_FILES_API = "/api/data-pipelines/v1/managed-files";
@@ -5842,10 +6272,10 @@ function managedFileLocalFolderName(meta) {
5842
6272
  return `${base}_${shortId}`;
5843
6273
  }
5844
6274
  function managedFileLocalDir(filesRoot, meta) {
5845
- return import_path18.default.join(filesRoot, managedFileLocalFolderName(meta));
6275
+ return import_path19.default.join(filesRoot, managedFileLocalFolderName(meta));
5846
6276
  }
5847
6277
  function isExcelManagedFile(meta) {
5848
- const ext = (meta.file_ext ?? import_path18.default.extname(meta.display_name ?? "")).toLowerCase();
6278
+ const ext = (meta.file_ext ?? import_path19.default.extname(meta.display_name ?? "")).toLowerCase();
5849
6279
  if (ext === ".xlsx" || ext === ".xls") return true;
5850
6280
  const mime = (meta.mime_type ?? "").toLowerCase();
5851
6281
  return mime.includes("spreadsheet") || mime.endsWith(".sheet");
@@ -5874,8 +6304,8 @@ async function downloadBinary(auth, urlPath, destPath) {
5874
6304
  throw new Error(`\u4E0B\u8F7D\u5931\u8D25 HTTP ${res.status}: ${text || res.statusText}`);
5875
6305
  }
5876
6306
  const buf = Buffer.from(await res.arrayBuffer());
5877
- import_fs14.default.mkdirSync(import_path18.default.dirname(destPath), { recursive: true });
5878
- import_fs14.default.writeFileSync(destPath, buf);
6307
+ import_fs15.default.mkdirSync(import_path19.default.dirname(destPath), { recursive: true });
6308
+ import_fs15.default.writeFileSync(destPath, buf);
5879
6309
  }
5880
6310
  async function resolveNativeDigest(auth, fileId, parseIfMissing) {
5881
6311
  if (!parseIfMissing) {
@@ -5931,13 +6361,13 @@ async function pullManagedFileBundle(opts) {
5931
6361
  const fileId = meta.file_id?.trim();
5932
6362
  if (!fileId) throw new Error("\u7F3A\u5C11 file_id\uFF0C\u4EC5\u652F\u6301\u5DF2\u767B\u8BB0\u6587\u4EF6");
5933
6363
  const dir = managedFileLocalDir(opts.filesRootDir, meta);
5934
- import_fs14.default.mkdirSync(dir, { recursive: true });
6364
+ import_fs15.default.mkdirSync(dir, { recursive: true });
5935
6365
  const written = [];
5936
6366
  const notes = [];
5937
6367
  const pulledAt = (/* @__PURE__ */ new Date()).toISOString();
5938
- const ext = (meta.file_ext && meta.file_ext.startsWith(".") ? meta.file_ext : meta.file_ext ? `.${meta.file_ext}` : "") || import_path18.default.extname(meta.display_name ?? meta.stored_filename ?? "") || "";
6368
+ const ext = (meta.file_ext && meta.file_ext.startsWith(".") ? meta.file_ext : meta.file_ext ? `.${meta.file_ext}` : "") || import_path19.default.extname(meta.display_name ?? meta.stored_filename ?? "") || "";
5939
6369
  const originalName = `${MANAGED_BUNDLE_FILES.originalPrefix}${ext || ""}`;
5940
- const originalPath = import_path18.default.join(dir, originalName);
6370
+ const originalPath = import_path19.default.join(dir, originalName);
5941
6371
  await downloadBinary(
5942
6372
  auth,
5943
6373
  `${MANAGED_FILES_API}/${encodeURIComponent(fileId)}/content`,
@@ -5947,15 +6377,15 @@ async function pullManagedFileBundle(opts) {
5947
6377
  if (isExcelManagedFile(meta)) {
5948
6378
  const digest = await resolveNativeDigest(auth, fileId, opts.parseNativeIfMissing !== false);
5949
6379
  if (digest?.markdown) {
5950
- import_fs14.default.writeFileSync(import_path18.default.join(dir, MANAGED_BUNDLE_FILES.nativeDigest), digest.markdown, "utf8");
6380
+ import_fs15.default.writeFileSync(import_path19.default.join(dir, MANAGED_BUNDLE_FILES.nativeDigest), digest.markdown, "utf8");
5951
6381
  written.push(MANAGED_BUNDLE_FILES.nativeDigest);
5952
6382
  } else {
5953
6383
  notes.push("\u539F\u751F\u89E3\u6790\u672A\u751F\u6210\uFF1A\u8BF7\u5728\u5E73\u53F0\u300C\u6587\u4EF6\u4E0A\u4F20\u7BA1\u7406\u300D\u4E2D\u5BF9 Excel \u6267\u884C\u300C\u539F\u751F\u89E3\u6790\u300D\u540E\u91CD\u8BD5\u62C9\u53D6");
5954
6384
  }
5955
6385
  const structureResp = await resolveAiStructure(auth, fileId);
5956
6386
  if (structureResp?.structure) {
5957
- import_fs14.default.writeFileSync(
5958
- import_path18.default.join(dir, MANAGED_BUNDLE_FILES.aiStructure),
6387
+ import_fs15.default.writeFileSync(
6388
+ import_path19.default.join(dir, MANAGED_BUNDLE_FILES.aiStructure),
5959
6389
  JSON.stringify(structureResp.structure, null, 2),
5960
6390
  "utf8"
5961
6391
  );
@@ -5965,8 +6395,8 @@ async function pullManagedFileBundle(opts) {
5965
6395
  }
5966
6396
  const layoutResp = await resolveReportLayout(auth, fileId);
5967
6397
  if (layoutResp?.layout) {
5968
- import_fs14.default.writeFileSync(
5969
- import_path18.default.join(dir, MANAGED_BUNDLE_FILES.reportLayout),
6398
+ import_fs15.default.writeFileSync(
6399
+ import_path19.default.join(dir, MANAGED_BUNDLE_FILES.reportLayout),
5970
6400
  JSON.stringify(layoutResp.layout, null, 2),
5971
6401
  "utf8"
5972
6402
  );
@@ -5987,8 +6417,8 @@ async function pullManagedFileBundle(opts) {
5987
6417
  notes: notes.length ? notes : void 0
5988
6418
  };
5989
6419
  manifest.files = [...written, MANAGED_BUNDLE_FILES.manifest];
5990
- import_fs14.default.writeFileSync(
5991
- import_path18.default.join(dir, MANAGED_BUNDLE_FILES.manifest),
6420
+ import_fs15.default.writeFileSync(
6421
+ import_path19.default.join(dir, MANAGED_BUNDLE_FILES.manifest),
5992
6422
  JSON.stringify({ ...meta, ...manifest }, null, 2),
5993
6423
  "utf8"
5994
6424
  );
@@ -6048,8 +6478,8 @@ function makeManagedFilesCommand() {
6048
6478
  process.exit(1);
6049
6479
  }
6050
6480
  const ws = resolveWorkspace();
6051
- const filesRoot = import_path19.default.resolve(opts.filesRoot ?? ws.files);
6052
- import_fs15.default.mkdirSync(filesRoot, { recursive: true });
6481
+ const filesRoot = import_path20.default.resolve(opts.filesRoot ?? ws.files);
6482
+ import_fs16.default.mkdirSync(filesRoot, { recursive: true });
6053
6483
  const result = await pullManagedFileBundle({
6054
6484
  auth: { serverUrl: auth.serverUrl, token: auth.token },
6055
6485
  meta,