@synergenius/flow-weaver 0.17.10 → 0.17.12

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.
@@ -786,7 +786,7 @@ export type TNodeTagAST = {
786
786
  };
787
787
  /** Visual customization for node types */
788
788
  export type TNodeVisualsAST = {
789
- /** Theme color: blue, purple, teal, orange, pink, green */
789
+ /** Theme color: blue, purple, cyan, orange, pink, green, red, yellow (teal is an alias for cyan) */
790
790
  color?: string;
791
791
  /** Icon preset name */
792
792
  icon?: string;
@@ -9671,7 +9671,7 @@ var VERSION;
9671
9671
  var init_generated_version = __esm({
9672
9672
  "src/generated-version.ts"() {
9673
9673
  "use strict";
9674
- VERSION = "0.17.10";
9674
+ VERSION = "0.17.12";
9675
9675
  }
9676
9676
  });
9677
9677
 
@@ -37889,7 +37889,7 @@ function darkenHex(hex, amount) {
37889
37889
  const nb = Math.round(b * (1 - amount));
37890
37890
  return `#${nr.toString(16).padStart(2, "0")}${ng.toString(16).padStart(2, "0")}${nb.toString(16).padStart(2, "0")}`;
37891
37891
  }
37892
- var DARK_PORT_COLORS, LIGHT_PORT_COLORS, DARK_FAILURE_COLOR, LIGHT_FAILURE_COLOR, NODE_VARIANT_COLORS, DARK_PALETTE, LIGHT_PALETTE, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, VALID_NODE_ICONS;
37892
+ var DARK_PORT_COLORS, LIGHT_PORT_COLORS, DARK_FAILURE_COLOR, LIGHT_FAILURE_COLOR, NODE_DEFAULT_COLOR, NODE_VARIANT_COLORS, DARK_PALETTE, LIGHT_PALETTE, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, VALID_NODE_ICONS;
37893
37893
  var init_theme = __esm({
37894
37894
  "src/diagram/theme.ts"() {
37895
37895
  "use strict";
@@ -37931,6 +37931,7 @@ var init_theme = __esm({
37931
37931
  };
37932
37932
  DARK_FAILURE_COLOR = "#ff4f4f";
37933
37933
  LIGHT_FAILURE_COLOR = "#e34646";
37934
+ NODE_DEFAULT_COLOR = "#334155";
37934
37935
  NODE_VARIANT_COLORS = {
37935
37936
  blue: { border: "#548ce3", darkBorder: "#5e9eff" },
37936
37937
  // blue-shade-2 / blue-dark-shade-1
@@ -37938,6 +37939,8 @@ var init_theme = __esm({
37938
37939
  // purple-shade-2 / purple-dark-shade-1
37939
37940
  cyan: { border: "#63ccc4", darkBorder: "#6fe5dc" },
37940
37941
  // cyan-shade-2 / cyan-dark-shade-1
37942
+ teal: { border: "#63ccc4", darkBorder: "#6fe5dc" },
37943
+ // alias for cyan
37941
37944
  orange: { border: "#e3732d", darkBorder: "#ff8133" },
37942
37945
  // orange-shade-2 / orange-dark-shade-1
37943
37946
  pink: { border: "#e349c2", darkBorder: "#ff52da" },
@@ -37946,10 +37949,8 @@ var init_theme = __esm({
37946
37949
  // green-shade-2 / green-dark-shade-1
37947
37950
  red: { border: "#e34646", darkBorder: "#ff4f4f" },
37948
37951
  // red-shade-2 / red-dark-shade-1
37949
- yellow: { border: "#e3a82b", darkBorder: "#ffbd30" },
37952
+ yellow: { border: "#e3a82b", darkBorder: "#ffbd30" }
37950
37953
  // yellow-shade-2 / yellow-dark-shade-1
37951
- teal: { border: "#3db0a8", darkBorder: "#4dc7be" }
37952
- // teal-shade-2 / teal-dark-shade-1
37953
37954
  };
37954
37955
  DARK_PALETTE = {
37955
37956
  background: "#202139",
@@ -50852,7 +50853,7 @@ function buildDiagramGraph(ast, options = {}) {
50852
50853
  diagramNodes.set("Start", {
50853
50854
  id: "Start",
50854
50855
  label: "Start",
50855
- color: "#334155",
50856
+ color: NODE_DEFAULT_COLOR,
50856
50857
  icon: "startNode",
50857
50858
  isVirtual: true,
50858
50859
  inputs: [],
@@ -50875,7 +50876,7 @@ function buildDiagramGraph(ast, options = {}) {
50875
50876
  diagramNodes.set("Exit", {
50876
50877
  id: "Exit",
50877
50878
  label: "Exit",
50878
- color: "#334155",
50879
+ color: NODE_DEFAULT_COLOR,
50879
50880
  icon: "exitNode",
50880
50881
  isVirtual: true,
50881
50882
  inputs: exitInputs,
@@ -51181,7 +51182,7 @@ function filterNonScopedPorts(ports) {
51181
51182
  return result;
51182
51183
  }
51183
51184
  function resolveNodeColor(color, theme = "dark") {
51184
- if (!color) return "#334155";
51185
+ if (!color) return NODE_DEFAULT_COLOR;
51185
51186
  const variant = NODE_VARIANT_COLORS[color];
51186
51187
  if (variant) return theme === "dark" ? variant.darkBorder : variant.border;
51187
51188
  return color;
@@ -51890,12 +51891,12 @@ function renderScopeConnection(parts2, conn, allConnections, parentNodeId) {
51890
51891
  );
51891
51892
  }
51892
51893
  function renderNodeBody(parts2, node, theme, indent) {
51893
- const strokeColor = node.color !== "#334155" ? node.color : theme.nodeIconColor;
51894
+ const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
51894
51895
  parts2.push(
51895
51896
  `${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`
51896
51897
  );
51897
51898
  const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
51898
- const iconColor = node.color !== "#334155" ? node.color : theme.nodeIconColor;
51899
+ const iconColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
51899
51900
  const iconSize = 40;
51900
51901
  const iconX = node.x + (node.width - iconSize) / 2;
51901
51902
  const iconY = node.y + (node.height - iconSize) / 2;
@@ -51907,7 +51908,7 @@ function renderNode(node, theme, themeName, allConnections) {
51907
51908
  const parts2 = [];
51908
51909
  parts2.push(` <g data-node-id="${escapeXml(node.id)}">`);
51909
51910
  if (node.scopeChildren && node.scopeChildren.length > 0) {
51910
- const strokeColor = node.color !== "#334155" ? node.color : theme.nodeIconColor;
51911
+ const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
51911
51912
  parts2.push(
51912
51913
  ` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`
51913
51914
  );
@@ -51954,7 +51955,7 @@ function renderNodeLabel(parts2, node, theme) {
51954
51955
  const labelAnchor = isScoped ? "start" : "middle";
51955
51956
  parts2.push(` <g data-label-for="${escapeXml(node.id)}">`);
51956
51957
  parts2.push(` <rect x="${labelBgX}" y="${labelBgY}" width="${labelBgWidth}" height="${labelBgHeight}" rx="6" fill="${theme.labelBadgeFill}" opacity="0.8"/>`);
51957
- parts2.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== "#334155" ? node.color : theme.labelColor}">${labelText}</text>`);
51958
+ parts2.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor}">${labelText}</text>`);
51958
51959
  parts2.push(` </g>`);
51959
51960
  }
51960
51961
  function renderPortLabelsForNode(parts2, node, theme, themeName, showPortLabels) {
@@ -101300,8 +101301,17 @@ async function generateManifest(options) {
101300
101301
  errors2.push(`Failed to parse ${file}: ${err instanceof Error ? err.message : String(err)}`);
101301
101302
  }
101302
101303
  }
101304
+ const existing = readManifest(directory);
101305
+ const v2Fields = {};
101306
+ if (existing) {
101307
+ if (existing.tagHandlers) v2Fields.tagHandlers = existing.tagHandlers;
101308
+ if (existing.validationRuleSets) v2Fields.validationRuleSets = existing.validationRuleSets;
101309
+ if (existing.exportTargets) v2Fields.exportTargets = existing.exportTargets;
101310
+ if (existing.docs) v2Fields.docs = existing.docs;
101311
+ if (existing.initContributions) v2Fields.initContributions = existing.initContributions;
101312
+ }
101303
101313
  const manifest = {
101304
- manifestVersion: 1,
101314
+ manifestVersion: 2,
101305
101315
  name: pkg.name ?? "unknown",
101306
101316
  version: pkg.version ?? "0.0.0",
101307
101317
  ...pkg.description && { description: pkg.description },
@@ -101310,6 +101320,7 @@ async function generateManifest(options) {
101310
101320
  nodeTypes: allNodeTypes,
101311
101321
  workflows: allWorkflows,
101312
101322
  patterns: allPatterns,
101323
+ ...v2Fields,
101313
101324
  ...Object.keys(pkg.dependencies ?? {}).length > 0 && {
101314
101325
  dependencies: {
101315
101326
  npm: pkg.dependencies
@@ -101330,7 +101341,7 @@ function readManifest(directory) {
101330
101341
  }
101331
101342
  function emptyManifest(name, version3) {
101332
101343
  return {
101333
- manifestVersion: 1,
101344
+ manifestVersion: 2,
101334
101345
  name,
101335
101346
  version: version3,
101336
101347
  nodeTypes: [],
@@ -104449,6 +104460,8 @@ async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isD
104449
104460
  throw new Error(`Input file not found: ${inputPath}`);
104450
104461
  }
104451
104462
  const parser3 = new AnnotationParser();
104463
+ const projectDir = path46.dirname(inputPath);
104464
+ await parser3.loadPackHandlers(projectDir);
104452
104465
  const parseResult = parser3.parse(inputPath);
104453
104466
  if (parseResult.workflows.length === 0) {
104454
104467
  throw new Error(`No workflows found in ${inputPath}`);
@@ -104524,6 +104537,8 @@ async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDr
104524
104537
  throw new Error(`Input file not found: ${inputPath}`);
104525
104538
  }
104526
104539
  const parser3 = new AnnotationParser();
104540
+ const projectDir = path46.dirname(inputPath);
104541
+ await parser3.loadPackHandlers(projectDir);
104527
104542
  const parseResult = parser3.parse(inputPath);
104528
104543
  if (parseResult.workflows.length === 0) {
104529
104544
  throw new Error(`No workflows found in ${inputPath}`);
@@ -105876,7 +105891,7 @@ function displayInstalledPackage(pkg) {
105876
105891
  // src/cli/index.ts
105877
105892
  init_logger();
105878
105893
  init_error_utils();
105879
- var version2 = true ? "0.17.10" : "0.0.0-dev";
105894
+ var version2 = true ? "0.17.12" : "0.0.0-dev";
105880
105895
  var program2 = new Command();
105881
105896
  program2.name("flow-weaver").description("Flow Weaver Annotations - Compile and validate workflow files").option("-v, --version", "Output the current version").option("--no-color", "Disable colors").option("--color", "Force colors").on("option:version", () => {
105882
105897
  logger.banner(version2);
@@ -1,6 +1,6 @@
1
1
  import { isExecutePort, isSuccessPort, isFailurePort, SCOPED_PORT_NAMES, isScopedStartPort, isScopedSuccessPort, isScopedFailurePort } from '../constants.js';
2
2
  import { assignImplicitPortOrders } from '../utils/port-ordering.js';
3
- import { getPortColor, NODE_VARIANT_COLORS, TYPE_ABBREVIATIONS } from './theme.js';
3
+ import { getPortColor, NODE_VARIANT_COLORS, NODE_DEFAULT_COLOR, TYPE_ABBREVIATIONS } from './theme.js';
4
4
  import { layoutWorkflow } from './layout.js';
5
5
  import { calculateOrthogonalPathSafe, TrackAllocator } from './orthogonal-router.js';
6
6
  // ---- Constants (matching React component-node) ----
@@ -707,7 +707,7 @@ export function buildDiagramGraph(ast, options = {}) {
707
707
  diagramNodes.set('Start', {
708
708
  id: 'Start',
709
709
  label: 'Start',
710
- color: '#334155',
710
+ color: NODE_DEFAULT_COLOR,
711
711
  icon: 'startNode',
712
712
  isVirtual: true,
713
713
  inputs: [],
@@ -731,7 +731,7 @@ export function buildDiagramGraph(ast, options = {}) {
731
731
  diagramNodes.set('Exit', {
732
732
  id: 'Exit',
733
733
  label: 'Exit',
734
- color: '#334155',
734
+ color: NODE_DEFAULT_COLOR,
735
735
  icon: 'exitNode',
736
736
  isVirtual: true,
737
737
  inputs: exitInputs,
@@ -1098,7 +1098,7 @@ function filterNonScopedPorts(ports) {
1098
1098
  }
1099
1099
  function resolveNodeColor(color, theme = 'dark') {
1100
1100
  if (!color)
1101
- return '#334155';
1101
+ return NODE_DEFAULT_COLOR;
1102
1102
  const variant = NODE_VARIANT_COLORS[color];
1103
1103
  if (variant)
1104
1104
  return theme === 'dark' ? variant.darkBorder : variant.border;
@@ -1,4 +1,4 @@
1
- import { getTheme, getPortColor, getPortRingColor, TYPE_ABBREVIATIONS, NODE_ICON_PATHS } from './theme.js';
1
+ import { getTheme, getPortColor, getPortRingColor, TYPE_ABBREVIATIONS, NODE_ICON_PATHS, NODE_DEFAULT_COLOR } from './theme.js';
2
2
  import { PORT_RADIUS, BORDER_RADIUS, LABEL_HEIGHT, LABEL_GAP, SCOPE_PORT_COLUMN, measureText } from './geometry.js';
3
3
  function escapeXml(str) {
4
4
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
@@ -113,10 +113,10 @@ function renderScopeConnection(parts, conn, allConnections, parentNodeId) {
113
113
  // ---- Node rendering ----
114
114
  /** Render node body rect + icon */
115
115
  function renderNodeBody(parts, node, theme, indent) {
116
- const strokeColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
116
+ const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
117
117
  parts.push(`${indent}<rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
118
118
  const iconPath = NODE_ICON_PATHS[node.icon] ?? NODE_ICON_PATHS.code;
119
- const iconColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
119
+ const iconColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
120
120
  const iconSize = 40;
121
121
  const iconX = node.x + (node.width - iconSize) / 2;
122
122
  const iconY = node.y + (node.height - iconSize) / 2;
@@ -126,8 +126,8 @@ function renderNode(node, theme, themeName, allConnections) {
126
126
  const parts = [];
127
127
  parts.push(` <g data-node-id="${escapeXml(node.id)}">`);
128
128
  if (node.scopeChildren && node.scopeChildren.length > 0) {
129
- // Scoped node: body rect only (no icon), then scope internals
130
- const strokeColor = node.color !== '#334155' ? node.color : theme.nodeIconColor;
129
+ // Scoped node: body rect only (icon omitted children occupy the inner area)
130
+ const strokeColor = node.color !== NODE_DEFAULT_COLOR ? node.color : theme.nodeIconColor;
131
131
  parts.push(` <rect x="${node.x}" y="${node.y}" width="${node.width}" height="${node.height}" rx="${BORDER_RADIUS}" fill="${theme.nodeFill}" stroke="${strokeColor}" stroke-width="2" filter="url(#node-shadow)"/>`);
132
132
  renderScopedContent(parts, node, theme, themeName, allConnections);
133
133
  }
@@ -178,7 +178,7 @@ function renderNodeLabel(parts, node, theme) {
178
178
  const labelAnchor = isScoped ? 'start' : 'middle';
179
179
  parts.push(` <g data-label-for="${escapeXml(node.id)}">`);
180
180
  parts.push(` <rect x="${labelBgX}" y="${labelBgY}" width="${labelBgWidth}" height="${labelBgHeight}" rx="6" fill="${theme.labelBadgeFill}" opacity="0.8"/>`);
181
- parts.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== '#334155' ? node.color : theme.labelColor}">${labelText}</text>`);
181
+ parts.push(` <text class="node-label" x="${labelTextX}" y="${labelBgY + labelBgHeight / 2 + 6}" text-anchor="${labelAnchor}" fill="${node.color !== NODE_DEFAULT_COLOR ? node.color : theme.labelColor}">${labelText}</text>`);
182
182
  parts.push(` </g>`);
183
183
  }
184
184
  /** Render port labels for a node if showPortLabels is enabled */
@@ -1,5 +1,6 @@
1
1
  import type { TDataType } from '../ast/types.js';
2
2
  import type { ThemePalette } from './types.js';
3
+ export declare const NODE_DEFAULT_COLOR = "#334155";
3
4
  export declare const NODE_VARIANT_COLORS: Record<string, {
4
5
  border: string;
5
6
  darkBorder: string;
@@ -26,16 +26,17 @@ const LIGHT_FAILURE_COLOR = '#e34646'; // red-shade-2
26
26
  // ---- Node theme variant colors ----
27
27
  // Dark: border = X-dark-shade-1 (base), icon = X-dark-shade-3
28
28
  // Light: border = X-shade-2
29
+ export const NODE_DEFAULT_COLOR = '#334155';
29
30
  export const NODE_VARIANT_COLORS = {
30
31
  blue: { border: '#548ce3', darkBorder: '#5e9eff' }, // blue-shade-2 / blue-dark-shade-1
31
32
  purple: { border: '#9f5fe3', darkBorder: '#b36bff' }, // purple-shade-2 / purple-dark-shade-1
32
33
  cyan: { border: '#63ccc4', darkBorder: '#6fe5dc' }, // cyan-shade-2 / cyan-dark-shade-1
34
+ teal: { border: '#63ccc4', darkBorder: '#6fe5dc' }, // alias for cyan
33
35
  orange: { border: '#e3732d', darkBorder: '#ff8133' }, // orange-shade-2 / orange-dark-shade-1
34
36
  pink: { border: '#e349c2', darkBorder: '#ff52da' }, // pink-shade-2 / pink-dark-shade-1
35
37
  green: { border: '#0ec850', darkBorder: '#10e15a' }, // green-shade-2 / green-dark-shade-1
36
38
  red: { border: '#e34646', darkBorder: '#ff4f4f' }, // red-shade-2 / red-dark-shade-1
37
39
  yellow: { border: '#e3a82b', darkBorder: '#ffbd30' }, // yellow-shade-2 / yellow-dark-shade-1
38
- teal: { border: '#3db0a8', darkBorder: '#4dc7be' }, // teal-shade-2 / teal-dark-shade-1
39
40
  };
40
41
  // ---- Theme palettes (exact values from token system) ----
41
42
  const DARK_PALETTE = {
@@ -100,7 +100,7 @@ const ANNOTATION_VALUES = {
100
100
  },
101
101
  {
102
102
  label: 'teal',
103
- detail: 'Teal node color',
103
+ detail: 'Teal node color (alias for cyan)',
104
104
  insertText: 'teal',
105
105
  insertTextFormat: 'plain',
106
106
  kind: 'value',
@@ -42,8 +42,10 @@ async function exportSingleWorkflowViaRegistry(target, inputPath, outputDir, isD
42
42
  if (!fs.existsSync(inputPath)) {
43
43
  throw new Error(`Input file not found: ${inputPath}`);
44
44
  }
45
- // Parse to find workflows
45
+ // Parse to find workflows (load pack tag handlers so CI/CD annotations resolve)
46
46
  const parser = new AnnotationParser();
47
+ const projectDir = path.dirname(inputPath);
48
+ await parser.loadPackHandlers(projectDir);
47
49
  const parseResult = parser.parse(inputPath);
48
50
  if (parseResult.workflows.length === 0) {
49
51
  throw new Error(`No workflows found in ${inputPath}`);
@@ -123,8 +125,10 @@ async function exportMultiWorkflowViaRegistry(target, inputPath, outputDir, isDr
123
125
  if (!fs.existsSync(inputPath)) {
124
126
  throw new Error(`Input file not found: ${inputPath}`);
125
127
  }
126
- // Parse to find workflows
128
+ // Parse to find workflows (load pack tag handlers so CI/CD annotations resolve)
127
129
  const parser = new AnnotationParser();
130
+ const projectDir = path.dirname(inputPath);
131
+ await parser.loadPackHandlers(projectDir);
128
132
  const parseResult = parser.parse(inputPath);
129
133
  if (parseResult.workflows.length === 0) {
130
134
  throw new Error(`No workflows found in ${inputPath}`);
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.17.10";
1
+ export declare const VERSION = "0.17.12";
2
2
  //# sourceMappingURL=generated-version.d.ts.map
@@ -1,3 +1,3 @@
1
1
  // Auto-generated by scripts/generate-version.ts — do not edit manually
2
- export const VERSION = '0.17.10';
2
+ export const VERSION = '0.17.12';
3
3
  //# sourceMappingURL=generated-version.js.map
@@ -132,8 +132,25 @@ export async function generateManifest(options) {
132
132
  errors.push(`Failed to parse ${file}: ${err instanceof Error ? err.message : String(err)}`);
133
133
  }
134
134
  }
135
+ // Preserve v2 extension fields from the existing manifest so that
136
+ // re-running pack:manifest doesn't wipe manually declared tagHandlers,
137
+ // validationRuleSets, docs, exportTargets, initContributions, etc.
138
+ const existing = readManifest(directory);
139
+ const v2Fields = {};
140
+ if (existing) {
141
+ if (existing.tagHandlers)
142
+ v2Fields.tagHandlers = existing.tagHandlers;
143
+ if (existing.validationRuleSets)
144
+ v2Fields.validationRuleSets = existing.validationRuleSets;
145
+ if (existing.exportTargets)
146
+ v2Fields.exportTargets = existing.exportTargets;
147
+ if (existing.docs)
148
+ v2Fields.docs = existing.docs;
149
+ if (existing.initContributions)
150
+ v2Fields.initContributions = existing.initContributions;
151
+ }
135
152
  const manifest = {
136
- manifestVersion: 1,
153
+ manifestVersion: 2,
137
154
  name: pkg.name ?? 'unknown',
138
155
  version: pkg.version ?? '0.0.0',
139
156
  ...(pkg.description && { description: pkg.description }),
@@ -142,6 +159,7 @@ export async function generateManifest(options) {
142
159
  nodeTypes: allNodeTypes,
143
160
  workflows: allWorkflows,
144
161
  patterns: allPatterns,
162
+ ...v2Fields,
145
163
  ...(Object.keys(pkg.dependencies ?? {}).length > 0 && {
146
164
  dependencies: {
147
165
  npm: pkg.dependencies,
@@ -165,7 +183,7 @@ export function readManifest(directory) {
165
183
  }
166
184
  function emptyManifest(name, version) {
167
185
  return {
168
- manifestVersion: 1,
186
+ manifestVersion: 2,
169
187
  name,
170
188
  version,
171
189
  nodeTypes: [],
@@ -9,7 +9,7 @@ import type { TDataType } from '../ast/types.js';
9
9
  /** Auto-generated manifest describing a marketplace package's contents. */
10
10
  export type TMarketplaceManifest = {
11
11
  /** Manifest schema version */
12
- manifestVersion: 1 | 2;
12
+ manifestVersion: 2;
13
13
  /** npm package name */
14
14
  name: string;
15
15
  /** Semver version */
@@ -481,7 +481,7 @@ These annotations go on `@flowWeaver nodeType` blocks:
481
481
  | `@name` | Override display name | `@name MyCustomName` |
482
482
  | `@label` | Human-readable label | `@label Fetch with Timeout` |
483
483
  | `@description` | Node description | `@description Validates expense data` |
484
- | `@color` | Custom color | `@color "#ff6b35"` |
484
+ | `@color` | Custom color | `@color purple` or `@color "#ff6b35"` |
485
485
  | `@icon` | Custom icon | `@icon "database"` |
486
486
  | `@tag` | Visual tag/badge | `@tag async` or `@tag beta "Experimental"` |
487
487
  | `@scope` | Provides a named scope | `@scope processItem` |
@@ -491,6 +491,42 @@ These annotations go on `@flowWeaver nodeType` blocks:
491
491
 
492
492
  ---
493
493
 
494
+ ## Available Colors
495
+
496
+ Named colors adapt to the diagram theme (dark/light). You can also pass any hex color directly (e.g. `@color "#ff6b35"`).
497
+
498
+ `blue` · `purple` · `cyan` · `orange` · `pink` · `green` · `red` · `yellow` · `teal` (alias for cyan)
499
+
500
+ ## Available Icons
501
+
502
+ Icons render inside the node body in SVG diagrams. Names correspond to Material Symbols (outlined, weight 500).
503
+
504
+ **AI & ML:** `psychology` · `smartToy` · `autoAwesome` · `modelTraining` · `science` · `biotech`
505
+
506
+ **Data & storage:** `database` · `dataObject` · `tableChart` · `token` · `storage` · `memory`
507
+
508
+ **Cloud & network:** `api` · `webhook` · `cloudSync` · `cloudUpload` · `cloudDownload` · `dns` · `router` · `http` · `link`
509
+
510
+ **Security & auth:** `key` · `shield` · `vpnKey` · `verified` · `security` · `policy` · `adminPanelSettings`
511
+
512
+ **Logic & flow:** `altRoute` · `callSplit` · `callMerge` · `rule` · `filterAlt` · `repeat` · `sort`
513
+
514
+ **Actions & status:** `bolt` · `build` · `rocketLaunch` · `send` · `sync` · `refresh`
515
+
516
+ **Communication:** `notifications` · `email` · `campaign`
517
+
518
+ **Scheduling:** `event` · `schedule` · `timer`
519
+
520
+ **General tools:** `terminal` · `settings` · `tune` · `search` · `save` · `upload` · `download` · `edit` · `delete`
521
+
522
+ **Status:** `checkCircle` · `error` · `warning` · `info` · `help` · `visibility`
523
+
524
+ **Files:** `folder` · `description` · `attachFile`
525
+
526
+ **Structural:** `code` (default) · `flow` (workflow nodes) · `startNode` · `exitNode`
527
+
528
+ ---
529
+
494
530
  ## Related Topics
495
531
 
496
532
  - [Concepts](concepts) — Core workflow fundamentals
@@ -137,6 +137,7 @@ Expression nodes are pure functions where:
137
137
  - Primitive/array return -> single output port
138
138
  - Object return `{ a, b }` -> one port per property
139
139
  - Best for: transformers, math, utilities, data mapping, async fetchers, API calls
140
+ - Optional `@color` and `@icon` annotations customize the node's appearance in SVG diagrams (see `advanced-annotations` for available values)
140
141
 
141
142
  > **Start with expression mode.** Only switch to normal mode when you need to return data alongside a failure (error-with-data patterns) or for void side-effect functions. Expression nodes handle success/failure branching automatically — throw to trigger the `onFailure` path.
142
143
 
@@ -244,7 +244,7 @@ Multiple attribute brackets are allowed (zero or more). Attributes can be split
244
244
  @node myAdd Add [minimized, label: "Compact"]
245
245
  @node myAdd Add [pullExecution: trigger]
246
246
  @node myAdd Add [size: 200 150]
247
- @node myAdd Add [color: "#ff0000", icon: "math-plus"]
247
+ @node myAdd Add [color: "red", icon: "database"]
248
248
  @node myAdd Add [tags: "math" "Math operation", "transform"]
249
249
  @node myAdd Add [position: 180 0]
250
250
  @node myAdd Add [label: "hi"] [color: "#f00"] [position: 360 0]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synergenius/flow-weaver",
3
- "version": "0.17.10",
3
+ "version": "0.17.12",
4
4
  "description": "Deterministic workflow compiler for AI agents. Compiles to standalone TypeScript, no runtime dependencies.",
5
5
  "private": false,
6
6
  "type": "module",