@fieldwangai/agentflow 0.1.54 → 0.1.55

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.
@@ -274,7 +274,7 @@ export function listNodesJson(workspaceRoot, flowId, flowSource, opts = {}) {
274
274
  addFromDir(PACKAGE_BUILTIN_NODES_DIR, "project");
275
275
  addFromDir(path.join(root, LEGACY_NODES_DIR), "project");
276
276
  addFromDir(path.join(root, PROJECT_NODES_DIR), "project");
277
- for (const manifest of listMarketplaceNodes(root, marketplaceFlowData)) {
277
+ for (const manifest of listMarketplaceNodes(root, marketplaceFlowData, opts)) {
278
278
  let type = "agent";
279
279
  const runtimeType = String(manifest.baseDefinitionId || manifest.runtime?.type || manifest.type || "").toLowerCase();
280
280
  if (runtimeType.startsWith("control")) type = "control";
@@ -524,7 +524,7 @@ export function readNodeJson(workspaceRoot, nodeId, flowId, flowSource, opts = {
524
524
  } catch (_) {}
525
525
  }
526
526
  }
527
- const resolved = resolveMarketplaceNodePackage(root, flowDir, nodeId, opts.flowData || null);
527
+ const resolved = resolveMarketplaceNodePackage(root, flowDir, nodeId, opts.flowData || null, opts);
528
528
  if (!resolved) return { error: "Node not found: " + nodeId };
529
529
  const readmePath = path.join(resolved.packageDir, "README.md");
530
530
  let type = "agent";
@@ -751,7 +751,7 @@ function resolveNodeFileScope(workspaceRoot, nodeId, flowId, flowSource, opts =
751
751
  } catch (_) {}
752
752
  }
753
753
  }
754
- const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, nodeId, flowData);
754
+ const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, nodeId, flowData, opts);
755
755
  if (!resolved) return null;
756
756
  return { baseDir: resolved.packageDir, allowAllFiles: true, primaryFilePath: path.join(resolved.packageDir, "node.yaml"), manifest: resolved };
757
757
  }
@@ -109,6 +109,17 @@ function normalizeManifest(raw, packageDir, source = "workspace") {
109
109
  };
110
110
  }
111
111
 
112
+ function manifestOwnerUserId(manifest) {
113
+ return String(manifest?.ownerUserId || manifest?.createdBy || "").trim();
114
+ }
115
+
116
+ function canAccessMarketplaceNode(manifest, opts = {}) {
117
+ const requestedUserId = String(opts.userId || "").trim();
118
+ if (!requestedUserId) return true;
119
+ if ((manifest?.source || "marketplace") !== "marketplace") return true;
120
+ return manifestOwnerUserId(manifest) === requestedUserId;
121
+ }
122
+
112
123
  function sortVersionsDesc(versions) {
113
124
  return [...versions].sort((a, b) => b.localeCompare(a, undefined, { numeric: true, sensitivity: "base" }));
114
125
  }
@@ -297,12 +308,13 @@ function collectionDeps(flowData) {
297
308
  return deps && Array.isArray(deps.collections) ? deps.collections : [];
298
309
  }
299
310
 
300
- export function resolveMarketplaceNodePackage(workspaceRoot, flowDir, definitionId, flowData = null) {
311
+ export function resolveMarketplaceNodePackage(workspaceRoot, flowDir, definitionId, flowData = null, opts = {}) {
301
312
  const parsed = parseMarketplaceDefinitionId(definitionId);
302
313
  if (!parsed) return null;
303
314
  const id = parsed.id;
304
315
  const requestedVersion = parsed.version || dependencyVersion(flowData, id) || lockVersion(flowDir, id);
305
316
  let packageDir = findNodePackageDir(workspaceRoot, id, requestedVersion);
317
+ let packageSource = "marketplace";
306
318
 
307
319
  if (!packageDir) {
308
320
  for (const dir of iterCollectionNodeDirs(workspaceRoot, collectionDeps(flowData))) {
@@ -311,13 +323,15 @@ export function resolveMarketplaceNodePackage(workspaceRoot, flowDir, definition
311
323
  if (!manifest || manifest.id !== id) continue;
312
324
  if (requestedVersion && manifest.version !== requestedVersion) continue;
313
325
  packageDir = dir;
326
+ packageSource = "collection";
314
327
  break;
315
328
  }
316
329
  }
317
330
 
318
331
  if (!packageDir) return null;
319
- const manifest = normalizeManifest(readYamlObject(path.join(packageDir, NODE_MANIFEST)), packageDir);
332
+ const manifest = normalizeManifest(readYamlObject(path.join(packageDir, NODE_MANIFEST)), packageDir, packageSource);
320
333
  if (!manifest) return null;
334
+ if (!canAccessMarketplaceNode(manifest, opts)) return null;
321
335
  return {
322
336
  ...manifest,
323
337
  requestedDefinitionId: definitionId,
@@ -325,13 +339,14 @@ export function resolveMarketplaceNodePackage(workspaceRoot, flowDir, definition
325
339
  };
326
340
  }
327
341
 
328
- export function listMarketplaceNodes(workspaceRoot, flowData = null) {
342
+ export function listMarketplaceNodes(workspaceRoot, flowData = null, opts = {}) {
329
343
  const root = workspacePackageRoot(workspaceRoot);
330
344
  const out = [];
331
345
  const seen = new Set();
332
346
  const addManifest = (dir, source = "marketplace") => {
333
347
  const manifest = normalizeManifest(readYamlObject(path.join(dir, NODE_MANIFEST)), dir, source);
334
348
  if (!manifest) return;
349
+ if (!canAccessMarketplaceNode(manifest, opts)) return;
335
350
  const key = `${manifest.id}@${manifest.version}`;
336
351
  if (seen.has(key)) return;
337
352
  seen.add(key);
@@ -357,7 +372,7 @@ export function listMarketplaceNodes(workspaceRoot, flowData = null) {
357
372
 
358
373
  export function listMarketplacePackages(workspaceRoot, opts = {}) {
359
374
  const root = workspacePackageRoot(workspaceRoot);
360
- const nodes = listMarketplaceNodes(workspaceRoot).map((n) => ({
375
+ const nodes = listMarketplaceNodes(workspaceRoot, null, opts).map((n) => ({
361
376
  id: n.id,
362
377
  version: n.version,
363
378
  definitionId: n.definitionId,
@@ -434,9 +449,15 @@ export function listMarketplaceFlowSnippets(workspaceRoot, opts = {}) {
434
449
  export function deleteMarketplaceNodePackage(workspaceRoot, id, version, opts = {}) {
435
450
  const packageDir = resolveWorkspaceNodePackageDir(workspaceRoot, id, version);
436
451
  if (!packageDir) return { ok: false, error: "Invalid marketplace node id or version" };
437
- if (!fs.existsSync(path.join(packageDir, NODE_MANIFEST))) {
452
+ const manifestPath = path.join(packageDir, NODE_MANIFEST);
453
+ if (!fs.existsSync(manifestPath)) {
438
454
  return { ok: false, error: `Marketplace node package not found: ${id}@${version}` };
439
455
  }
456
+ const manifest = normalizeManifest(readYamlObject(manifestPath), packageDir, "marketplace");
457
+ const requestedUserId = String(opts.userId || "").trim();
458
+ if (!requestedUserId || !manifest || manifestOwnerUserId(manifest) !== requestedUserId) {
459
+ return { ok: false, error: "Marketplace node permission denied" };
460
+ }
440
461
  const usage = listMarketplaceNodeUsages(workspaceRoot, id, version, opts);
441
462
  if (usage.length > 0) {
442
463
  return { ok: false, error: "Marketplace node is still used by flows", usage };
@@ -478,12 +499,12 @@ export function deleteMarketplaceFlowSnippetPackage(workspaceRoot, id, version,
478
499
  return { ok: true, id, version, packageDir };
479
500
  }
480
501
 
481
- export function writeFlowMarketplaceLock(workspaceRoot, flowDir, flowData) {
502
+ export function writeFlowMarketplaceLock(workspaceRoot, flowDir, flowData, opts = {}) {
482
503
  if (!flowData || !flowData.instances || typeof flowData.instances !== "object") return null;
483
504
  const nodes = {};
484
505
  for (const inst of Object.values(flowData.instances)) {
485
506
  const defId = inst && (inst.marketplaceRef || inst.definitionId);
486
- const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, defId, flowData);
507
+ const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, defId, flowData, opts);
487
508
  if (!resolved) continue;
488
509
  nodes[resolved.id] = {
489
510
  version: resolved.version,
@@ -674,6 +695,8 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
674
695
  const version = normalizeVersion(payload.version || "1.0.0");
675
696
  const sourceDefinitionId = String(payload.definitionId || "").trim();
676
697
  if (!id) return { ok: false, error: "Invalid package id" };
698
+ const ownerUserId = String(options.userId || "").trim();
699
+ if (!ownerUserId) return { ok: false, error: "Authentication required" };
677
700
 
678
701
  const inputs = normalizeSlotList(payload.inputs || payload.input).map((slot) => ({
679
702
  type: slot.type,
@@ -693,6 +716,12 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
693
716
  const body = String(payload.body || "").trim();
694
717
  const description = String(payload.description || body || `Published from node ${label}`).trim();
695
718
  const dest = path.join(workspacePackageRoot(workspaceRoot), "nodes", id, version);
719
+ const existingManifest = readYamlObject(path.join(dest, NODE_MANIFEST));
720
+ if (existingManifest) {
721
+ const existingOwner = manifestOwnerUserId(existingManifest);
722
+ if (existingOwner !== ownerUserId) return { ok: false, error: "Marketplace node permission denied" };
723
+ }
724
+ const now = new Date().toISOString();
696
725
  fs.mkdirSync(path.dirname(dest), { recursive: true });
697
726
  fs.rmSync(dest, { recursive: true, force: true });
698
727
  fs.mkdirSync(dest, { recursive: true });
@@ -722,6 +751,10 @@ export function publishNodeFromInstance(workspaceRoot, payload = {}, options = {
722
751
  runtime,
723
752
  inputs,
724
753
  outputs,
754
+ ownerUserId,
755
+ createdBy: ownerUserId,
756
+ createdAt: existingManifest?.createdAt || now,
757
+ updatedAt: now,
725
758
  };
726
759
  if (packagedScript?.packagedFiles?.length) manifest.packagedFiles = packagedScript.packagedFiles;
727
760
  fs.writeFileSync(path.join(dest, NODE_MANIFEST), yaml.dump(manifest, { lineWidth: -1 }), "utf-8");
@@ -803,10 +836,10 @@ export function publishFlowSnippet(workspaceRoot, payload = {}, opts = {}) {
803
836
  return { ok: true, id, version, packageDir: dest, snippet: manifest.snippet };
804
837
  }
805
838
 
806
- export function installFlowDependency(workspaceRoot, flowDir, spec) {
839
+ export function installFlowDependency(workspaceRoot, flowDir, spec, opts = {}) {
807
840
  const parsed = parseMarketplaceDefinitionId(spec.startsWith("marketplace:") ? spec : `marketplace:${spec}`);
808
841
  if (!parsed) return { ok: false, error: `Invalid marketplace node spec: ${spec}` };
809
- const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, `marketplace:${parsed.id}${parsed.version ? `@${parsed.version}` : ""}`, { dependencies: {} });
842
+ const resolved = resolveMarketplaceNodePackage(workspaceRoot, flowDir, `marketplace:${parsed.id}${parsed.version ? `@${parsed.version}` : ""}`, { dependencies: {} }, opts);
810
843
  if (!resolved) return { ok: false, error: `Marketplace node not found: ${spec}` };
811
844
 
812
845
  const flowYamlPath = path.join(flowDir, "flow.yaml");
@@ -818,6 +851,6 @@ export function installFlowDependency(workspaceRoot, flowDir, spec) {
818
851
  if (!exists) nodes.push({ id: resolved.id, version: resolved.version });
819
852
  data.dependencies = { ...deps, nodes };
820
853
  fs.writeFileSync(flowYamlPath, yaml.dump(data, { lineWidth: -1 }), "utf-8");
821
- writeFlowMarketplaceLock(workspaceRoot, flowDir, data);
854
+ writeFlowMarketplaceLock(workspaceRoot, flowDir, data, opts);
822
855
  return { ok: true, id: resolved.id, version: resolved.version, definitionId: `marketplace:${resolved.id}@${resolved.version}` };
823
856
  }
@@ -4911,7 +4911,7 @@ export function startUiServer({
4911
4911
  json(res, 400, { error: resolved.error || "Could not resolve flow directory" });
4912
4912
  return;
4913
4913
  }
4914
- const result = installFlowDependency(root, resolved.flowDir, nodeSpec);
4914
+ const result = installFlowDependency(root, resolved.flowDir, nodeSpec, userCtx);
4915
4915
  json(res, result.ok ? 200 : 400, result);
4916
4916
  } catch (e) {
4917
4917
  json(res, 500, { ok: false, error: (e && e.message) || String(e) });
@@ -4935,7 +4935,7 @@ export function startUiServer({
4935
4935
  const resolved = resolveFlowDirForWrite(root, flowId, flowSource, userCtx);
4936
4936
  if (!resolved.error && resolved.flowDir) flowDir = resolved.flowDir;
4937
4937
  }
4938
- const result = publishNodeFromInstance(root, payload || {}, { flowDir });
4938
+ const result = publishNodeFromInstance(root, payload || {}, { flowDir, ...userCtx });
4939
4939
  json(res, result.ok ? 200 : 400, result);
4940
4940
  } catch (e) {
4941
4941
  json(res, 500, { ok: false, error: (e && e.message) || String(e) });