@fieldwangai/agentflow 0.1.67 → 0.1.69

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.
@@ -0,0 +1,93 @@
1
+ import fs from "fs";
2
+ import os from "os";
3
+ import path from "path";
4
+
5
+ import {
6
+ AGENTFLOW_HOME_CONFIG_PATH,
7
+ expandAgentflowHomePath,
8
+ getAgentflowDataRoot,
9
+ getAgentflowDataRootOverride,
10
+ writeAgentflowDataRootOverride,
11
+ } from "./paths.mjs";
12
+
13
+ function defaultAgentflowDataRoot() {
14
+ return path.join(os.homedir(), "agentflow");
15
+ }
16
+
17
+ function pathInside(parent, candidate) {
18
+ const base = path.resolve(parent);
19
+ const target = path.resolve(candidate);
20
+ return target === base || target.startsWith(base + path.sep);
21
+ }
22
+
23
+ function normalizeDataRoot(raw) {
24
+ const dataRoot = expandAgentflowHomePath(raw);
25
+ if (dataRoot && !path.isAbsolute(dataRoot)) {
26
+ throw new Error("dataRoot must be an absolute path");
27
+ }
28
+ return dataRoot;
29
+ }
30
+
31
+ function copyEntry(src, dest) {
32
+ const stat = fs.lstatSync(src);
33
+ if (stat.isSymbolicLink()) {
34
+ if (!fs.existsSync(dest)) fs.symlinkSync(fs.readlinkSync(src), dest);
35
+ return;
36
+ }
37
+ if (stat.isDirectory()) {
38
+ fs.mkdirSync(dest, { recursive: true });
39
+ for (const name of fs.readdirSync(src)) {
40
+ copyEntry(path.join(src, name), path.join(dest, name));
41
+ }
42
+ return;
43
+ }
44
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
45
+ fs.copyFileSync(src, dest);
46
+ }
47
+
48
+ function migrateDataRoot(oldRoot, newRoot) {
49
+ const from = path.resolve(oldRoot);
50
+ const to = path.resolve(newRoot);
51
+ if (from === to) return { migrated: false, copied: false };
52
+ if (pathInside(from, to)) {
53
+ throw new Error("dataRoot target cannot be inside the current data root");
54
+ }
55
+ if (pathInside(to, from)) {
56
+ throw new Error("dataRoot target cannot be a parent of the current data root");
57
+ }
58
+ fs.mkdirSync(to, { recursive: true });
59
+ if (!fs.existsSync(from)) return { migrated: true, copied: false };
60
+ for (const name of fs.readdirSync(from)) {
61
+ copyEntry(path.join(from, name), path.join(to, name));
62
+ }
63
+ return { migrated: true, copied: true };
64
+ }
65
+
66
+ export function readAdminStorageConfig() {
67
+ const envDataRoot = normalizeDataRoot(process.env.AGENTFLOW_HOME || "");
68
+ const configuredDataRoot = getAgentflowDataRootOverride();
69
+ return {
70
+ version: 1,
71
+ dataRoot: getAgentflowDataRoot(),
72
+ configuredDataRoot,
73
+ defaultDataRoot: defaultAgentflowDataRoot(),
74
+ envDataRoot,
75
+ envLocked: Boolean(envDataRoot),
76
+ configPath: AGENTFLOW_HOME_CONFIG_PATH,
77
+ };
78
+ }
79
+
80
+ export function writeAdminStorageConfig(config = {}) {
81
+ const current = readAdminStorageConfig();
82
+ if (current.envLocked) {
83
+ throw new Error("AGENTFLOW_HOME is set; update the environment variable instead of Admin Settings");
84
+ }
85
+ const nextRoot = normalizeDataRoot(config.dataRoot ?? "");
86
+ if (!nextRoot) throw new Error("dataRoot is required");
87
+ const migration = migrateDataRoot(current.dataRoot, nextRoot);
88
+ writeAgentflowDataRootOverride(nextRoot);
89
+ return {
90
+ ...readAdminStorageConfig(),
91
+ migration,
92
+ };
93
+ }
@@ -708,6 +708,47 @@ function buildPackagedRuntimeFromScript(command, destDir, opts = {}) {
708
708
  };
709
709
  }
710
710
 
711
+ function safePackageRefPath(raw) {
712
+ const text = String(raw || "").trim().replace(/^["']|["']$/g, "").replace(/\\/g, "/");
713
+ if (!text || path.isAbsolute(text) || text.includes("\n") || text.includes("\r")) return "";
714
+ const normalized = path.posix.normalize(text).replace(/^\/+/, "");
715
+ if (!normalized || normalized === "." || normalized.startsWith("../") || normalized.includes("/../")) return "";
716
+ return normalized;
717
+ }
718
+
719
+ function packageNodeReferenceFiles(destDir, opts = {}) {
720
+ const flowDir = opts.flowDir ? path.resolve(opts.flowDir) : "";
721
+ const packagedFiles = [];
722
+ const result = {};
723
+ const copyRef = (rawRef, targetRel, key) => {
724
+ const clean = safePackageRefPath(rawRef);
725
+ if (!clean || !flowDir) return "";
726
+ const source = path.resolve(flowDir, ...clean.split("/"));
727
+ if (!isInsideDir(source, flowDir) || !fs.existsSync(source) || !fs.statSync(source).isFile()) return "";
728
+ const rel = targetRel.replace(/\\/g, "/");
729
+ const abs = path.join(destDir, rel);
730
+ fs.mkdirSync(path.dirname(abs), { recursive: true });
731
+ fs.copyFileSync(source, abs);
732
+ packagedFiles.push({ from: source, to: rel, role: key });
733
+ result[key] = rel;
734
+ return rel;
735
+ };
736
+ const scriptRef = copyRef(opts.scriptRef, `scripts/${path.basename(safePackageRefPath(opts.scriptRef) || "script.mjs")}`, "scriptRef");
737
+ const implementationRef = copyRef(opts.implementationRef, "implementation.md", "implementationRef");
738
+ let scriptRuntime = null;
739
+ if (scriptRef) {
740
+ const abs = path.join(destDir, scriptRef);
741
+ scriptRuntime = {
742
+ type: "tool_nodejs",
743
+ language: scriptLanguageFor("", scriptRef),
744
+ entry: scriptRef,
745
+ args: [],
746
+ };
747
+ if (!fs.existsSync(abs)) scriptRuntime = null;
748
+ }
749
+ return { ...result, packagedFiles, scriptRuntime };
750
+ }
751
+
711
752
  export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {}) {
712
753
  const label = String(payload.label || payload.instanceId || "node").trim();
713
754
  const id = safePackageId(payload.id || payload.packageId || label);
@@ -732,6 +773,9 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
732
773
  ...(slot.showOnNode != null ? { showOnNode: Boolean(slot.showOnNode) } : {}),
733
774
  }));
734
775
  const script = String(payload.script || "").trim();
776
+ const scriptRef = String(payload.scriptRef || "").trim();
777
+ const implementationRef = String(payload.implementationRef || "").trim();
778
+ const implementationMode = String(payload.implementationMode || "").trim();
735
779
  const body = String(payload.body || "").trim();
736
780
  const description = String(payload.description || body || `Published from node ${label}`).trim();
737
781
  const dest = path.join(workspacePackageRoot(workspaceRoot), "nodes", id, version);
@@ -744,13 +788,18 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
744
788
  fs.mkdirSync(path.dirname(dest), { recursive: true });
745
789
  fs.rmSync(dest, { recursive: true, force: true });
746
790
  fs.mkdirSync(dest, { recursive: true });
791
+ const packagedRefs = packageNodeReferenceFiles(dest, {
792
+ flowDir: options.flowDir || payload.flowDir,
793
+ scriptRef,
794
+ implementationRef,
795
+ });
747
796
  const packagedScript = script
748
797
  ? buildPackagedRuntimeFromScript(script, dest, {
749
798
  flowDir: options.flowDir || payload.flowDir,
750
799
  workspaceRoot,
751
800
  })
752
801
  : null;
753
- const runtime = packagedScript?.runtime || (
802
+ const runtime = packagedScript?.runtime || packagedRefs.scriptRuntime || (
754
803
  script
755
804
  ? {
756
805
  type: "tool_nodejs",
@@ -775,7 +824,10 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
775
824
  createdAt: existingManifest?.createdAt || now,
776
825
  updatedAt: now,
777
826
  };
778
- if (packagedScript?.packagedFiles?.length) manifest.packagedFiles = packagedScript.packagedFiles;
827
+ if (packagedRefs.implementationRef) manifest.implementationRef = packagedRefs.implementationRef;
828
+ if (implementationMode) manifest.implementationMode = implementationMode;
829
+ const packagedFiles = [...(packagedScript?.packagedFiles || []), ...(packagedRefs.packagedFiles || [])];
830
+ if (packagedFiles.length) manifest.packagedFiles = packagedFiles;
779
831
  fs.writeFileSync(path.join(dest, NODE_MANIFEST), yaml.dump(manifest, { lineWidth: -1 }), "utf-8");
780
832
  fs.writeFileSync(
781
833
  path.join(dest, "README.md"),
@@ -791,7 +843,7 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
791
843
  definitionId: `marketplace:${id}@${version}`,
792
844
  baseDefinitionId: manifest.baseDefinitionId,
793
845
  marketplaceDefinitionId: `marketplace:${id}@${version}`,
794
- packagedFiles: packagedScript?.packagedFiles || [],
846
+ packagedFiles,
795
847
  };
796
848
  }
797
849
 
package/bin/lib/paths.mjs CHANGED
@@ -20,17 +20,55 @@ export const PACKAGE_AGENTS_DIR = path.join(PACKAGE_ROOT, "agents");
20
20
  export const PACKAGE_AGENTS_JSON = path.join(PACKAGE_AGENTS_DIR, "agents.json");
21
21
 
22
22
  /**
23
- * 用户级 AgentFlow 数据根目录:`AGENTFLOW_HOME` 或 `~/agentflow`。
23
+ * 用户级 AgentFlow 数据根目录:`AGENTFLOW_HOME`、`~/.agentflow/config.json:dataRoot` 或 `~/agentflow`。
24
24
  * 与项目根 workspaceRoot 分离;run、pipelines、agents 等均落盘于此。
25
25
  */
26
+ export const AGENTFLOW_CONFIG_DIR = path.join(os.homedir(), ".agentflow");
27
+ export const AGENTFLOW_HOME_CONFIG_PATH = path.join(AGENTFLOW_CONFIG_DIR, "config.json");
28
+
29
+ export function expandAgentflowHomePath(rawPath) {
30
+ let raw = String(rawPath || "").trim();
31
+ if (!raw) return "";
32
+ if (raw === "~") raw = os.homedir();
33
+ else if (raw.startsWith("~/")) raw = path.join(os.homedir(), raw.slice(2));
34
+ return path.resolve(raw);
35
+ }
36
+
37
+ function readAgentflowHomeConfig() {
38
+ try {
39
+ if (!fs.existsSync(AGENTFLOW_HOME_CONFIG_PATH)) return {};
40
+ const parsed = JSON.parse(fs.readFileSync(AGENTFLOW_HOME_CONFIG_PATH, "utf-8"));
41
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
42
+ } catch {
43
+ return {};
44
+ }
45
+ }
46
+
47
+ export function getAgentflowDataRootOverride() {
48
+ const config = readAgentflowHomeConfig();
49
+ return expandAgentflowHomePath(config.dataRoot || "");
50
+ }
51
+
52
+ export function writeAgentflowDataRootOverride(dataRoot) {
53
+ const nextRoot = expandAgentflowHomePath(dataRoot);
54
+ if (nextRoot && !path.isAbsolute(nextRoot)) {
55
+ throw new Error("dataRoot must be an absolute path");
56
+ }
57
+ const current = readAgentflowHomeConfig();
58
+ const next = { ...current, dataRoot: nextRoot };
59
+ if (!nextRoot) delete next.dataRoot;
60
+ fs.mkdirSync(path.dirname(AGENTFLOW_HOME_CONFIG_PATH), { recursive: true });
61
+ fs.writeFileSync(AGENTFLOW_HOME_CONFIG_PATH, JSON.stringify(next, null, 2) + "\n", "utf-8");
62
+ return nextRoot;
63
+ }
64
+
26
65
  export function getAgentflowDataRoot() {
27
66
  const env = process.env.AGENTFLOW_HOME;
28
67
  if (env != null && String(env).trim() !== "") {
29
- let raw = String(env).trim();
30
- if (raw === "~") raw = os.homedir();
31
- else if (raw.startsWith("~/")) raw = path.join(os.homedir(), raw.slice(2));
32
- return path.resolve(raw);
68
+ return expandAgentflowHomePath(env);
33
69
  }
70
+ const configured = getAgentflowDataRootOverride();
71
+ if (configured) return configured;
34
72
  return path.join(os.homedir(), "agentflow");
35
73
  }
36
74