@ixo/editor 5.19.1 → 5.20.0-experimental.2

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.
@@ -571,15 +571,68 @@ registerAction({
571
571
  });
572
572
 
573
573
  // src/core/lib/actionRegistry/actions/pod/listDomainFlows.ts
574
+ function normalizeSelectedTemplates(value) {
575
+ if (!Array.isArray(value)) return [];
576
+ return value.map((item) => {
577
+ if (!item || typeof item !== "object") return null;
578
+ const raw = item;
579
+ const protocolDid = String(raw.protocolDid || "").trim();
580
+ const sourceRoomId = String(raw.sourceRoomId || "").trim();
581
+ if (!protocolDid || !sourceRoomId) return null;
582
+ const sourceLabel = String(raw.sourceLabel || raw.label || sourceRoomId).trim();
583
+ return {
584
+ protocolDid,
585
+ protocolName: String(raw.protocolName || protocolDid).trim(),
586
+ sourceRoomId,
587
+ sourceLabel,
588
+ ...raw.path ? { path: String(raw.path) } : {}
589
+ };
590
+ }).filter((item) => item !== null);
591
+ }
574
592
  registerAction({
575
593
  type: "qi/pod.list-domain-flows",
576
594
  can: "pod/list-domain-flows",
577
595
  sideEffect: false,
578
596
  defaultRequiresConfirmation: false,
579
- outputSchema: [{ path: "selectedFlowDids", displayName: "Selected Flow DIDs", type: "array", description: "Array of selected flow template DIDs" }],
597
+ outputSchema: [
598
+ {
599
+ path: "selectedProtocolTemplates",
600
+ displayName: "Selected Protocol Templates",
601
+ type: "array",
602
+ description: "Selected protocol templates with protocol DID and source room ID"
603
+ },
604
+ { path: "selectedFlowDids", displayName: "Selected Flow Room IDs", type: "array", description: "Source Matrix room IDs for selected templates" },
605
+ { path: "flowTemplateConfig", displayName: "Flow Template Config", type: "object", description: "Event payload consumed by POD signing/import steps" }
606
+ ],
607
+ events: [
608
+ {
609
+ name: "configured",
610
+ displayName: "Flow Templates Configured",
611
+ description: "Fires when protocol flow templates are selected for the POD.",
612
+ payloadSchema: [
613
+ {
614
+ path: "flowTemplateConfig",
615
+ displayName: "Flow Template Config",
616
+ type: "object",
617
+ description: "Selected templates grouped by their protocol DID for later import"
618
+ }
619
+ ],
620
+ pendingDisplayFields: ["flowTemplateConfig.templateCount", "flowTemplateConfig.protocolCount"]
621
+ }
622
+ ],
580
623
  run: async (inputs) => {
581
- const selectedFlowDids = Array.isArray(inputs.selectedFlowDids) ? inputs.selectedFlowDids : [];
582
- return { output: { selectedFlowDids } };
624
+ const selectedProtocolTemplates = normalizeSelectedTemplates(inputs.selectedProtocolTemplates);
625
+ const selectedFlowDids = selectedProtocolTemplates.length > 0 ? selectedProtocolTemplates.map((template) => template.sourceRoomId) : Array.isArray(inputs.selectedFlowDids) ? inputs.selectedFlowDids : [];
626
+ const protocolCount = new Set(selectedProtocolTemplates.map((template) => template.protocolDid)).size;
627
+ const flowTemplateConfig = {
628
+ selectedTemplates: selectedProtocolTemplates,
629
+ templateCount: selectedProtocolTemplates.length,
630
+ protocolCount
631
+ };
632
+ return {
633
+ output: { selectedProtocolTemplates, selectedFlowDids, flowTemplateConfig },
634
+ events: [{ name: "configured", payload: { flowTemplateConfig } }]
635
+ };
583
636
  }
584
637
  });
585
638
 
@@ -2669,6 +2722,89 @@ function parseContextInput(value) {
2669
2722
  return key && val ? { key, val } : null;
2670
2723
  }).filter((entry) => entry !== null);
2671
2724
  }
2725
+ function getSelectedProtocolTemplates(flowTemplateConfig) {
2726
+ const raw = flowTemplateConfig?.selectedTemplates;
2727
+ if (!Array.isArray(raw)) return [];
2728
+ return raw.map((item) => {
2729
+ if (!item || typeof item !== "object") return null;
2730
+ const record = item;
2731
+ const protocolDid = String(record.protocolDid || "").trim();
2732
+ const sourceRoomId = String(record.sourceRoomId || "").trim();
2733
+ if (!protocolDid || !sourceRoomId) return null;
2734
+ const sourceLabel = String(record.sourceLabel || record.label || "").trim();
2735
+ return {
2736
+ protocolDid,
2737
+ sourceRoomId,
2738
+ ...sourceLabel ? { sourceLabel } : {}
2739
+ };
2740
+ }).filter((item) => item !== null);
2741
+ }
2742
+ function groupTemplatesByProtocol(templates) {
2743
+ const grouped = /* @__PURE__ */ new Map();
2744
+ for (const template of templates) {
2745
+ const existing = grouped.get(template.protocolDid) || [];
2746
+ existing.push({
2747
+ sourceRoomId: template.sourceRoomId,
2748
+ ...template.sourceLabel ? { sourceLabel: template.sourceLabel } : {}
2749
+ });
2750
+ grouped.set(template.protocolDid, existing);
2751
+ }
2752
+ return grouped;
2753
+ }
2754
+ var DOMAIN_SIGN_CACHE_KEY = "domainSign";
2755
+ function getDomainSignCheckpointKey(inputs, ctx) {
2756
+ return String(ctx.pendingInvocation?.id || inputs.pendingInvocationId || inputs.invocationId || "manual");
2757
+ }
2758
+ function readDomainSignCheckpoint(ctx, key) {
2759
+ const cache = ctx.runtime?.get?.(ctx.nodeId)?.cache;
2760
+ const bucket = cache?.[DOMAIN_SIGN_CACHE_KEY];
2761
+ if (!bucket || typeof bucket !== "object") return void 0;
2762
+ const checkpoint = bucket[key];
2763
+ return checkpoint && typeof checkpoint === "object" ? checkpoint : void 0;
2764
+ }
2765
+ function writeDomainSignCheckpoint(ctx, key, checkpoint) {
2766
+ if (!ctx.runtime?.get || !ctx.runtime?.update || !ctx.nodeId) return;
2767
+ const current = ctx.runtime.get(ctx.nodeId) || {};
2768
+ const cache = current.cache && typeof current.cache === "object" ? current.cache : {};
2769
+ const bucket = cache[DOMAIN_SIGN_CACHE_KEY] && typeof cache[DOMAIN_SIGN_CACHE_KEY] === "object" ? cache[DOMAIN_SIGN_CACHE_KEY] : {};
2770
+ ctx.runtime.update(ctx.nodeId, {
2771
+ cache: {
2772
+ ...cache,
2773
+ [DOMAIN_SIGN_CACHE_KEY]: {
2774
+ ...bucket,
2775
+ [key]: checkpoint
2776
+ }
2777
+ }
2778
+ });
2779
+ }
2780
+ function buildCompletedDomainSignResult(output) {
2781
+ const payload = {
2782
+ entityDid: output.entityDid,
2783
+ governanceGroupCoreAddress: output.governanceGroupCoreAddress || "",
2784
+ transactionHash: output.transactionHash || "",
2785
+ linkedResourceTransactionHash: output.linkedResourceTransactionHash || "",
2786
+ ...output.parentLinkedEntityTransactionHash ? { parentLinkedEntityTransactionHash: output.parentLinkedEntityTransactionHash } : {}
2787
+ };
2788
+ return {
2789
+ output,
2790
+ events: [
2791
+ {
2792
+ name: "created",
2793
+ payload
2794
+ }
2795
+ ]
2796
+ };
2797
+ }
2798
+ function readDidInput(value) {
2799
+ if (typeof value !== "string") return "";
2800
+ const did = value.trim();
2801
+ if (!did || did === "null" || did === "undefined") return "";
2802
+ return did.startsWith("did:") ? did : "";
2803
+ }
2804
+ function getSelectedParentEntityDid(inputs) {
2805
+ if (inputs.skipped === true || inputs.parentSkipped === true) return "";
2806
+ return readDidInput(inputs.selectedEntityDid) || readDidInput(inputs.parentDid) || readDidInput(inputs.parentDID);
2807
+ }
2672
2808
  function parseDuration(raw) {
2673
2809
  const seconds = parseInt(raw, 10) || 0;
2674
2810
  if (seconds % (7 * 86400) === 0) return { amount: seconds / (7 * 86400), unit: "weeks" };
@@ -2755,6 +2891,36 @@ registerAction({
2755
2891
  displayName: "Linked Resource Transaction Hash",
2756
2892
  type: "string",
2757
2893
  description: "The on-chain transaction hash for adding the domain card linked resource"
2894
+ },
2895
+ {
2896
+ path: "parentEntityDid",
2897
+ displayName: "Parent Entity DID",
2898
+ type: "string",
2899
+ description: "The selected parent entity DID that was updated with the new POD linked entity"
2900
+ },
2901
+ {
2902
+ path: "parentLinkedEntityTransactionHash",
2903
+ displayName: "Parent Linked Entity Transaction Hash",
2904
+ type: "string",
2905
+ description: "The on-chain transaction hash for linking the new POD to the selected parent entity"
2906
+ },
2907
+ {
2908
+ path: "flowTemplateConfig",
2909
+ displayName: "Flow Template Config",
2910
+ type: "object",
2911
+ description: "Selected protocol templates captured before POD creation"
2912
+ },
2913
+ {
2914
+ path: "domainSpaces",
2915
+ displayName: "Domain Spaces",
2916
+ type: "object",
2917
+ description: "Matrix space structure sourced for the new domain"
2918
+ },
2919
+ {
2920
+ path: "protocolTemplateImports",
2921
+ displayName: "Protocol Template Imports",
2922
+ type: "array",
2923
+ description: "Import results for selected protocol templates"
2758
2924
  }
2759
2925
  ],
2760
2926
  events: [
@@ -2776,22 +2942,19 @@ registerAction({
2776
2942
  displayName: "Linked Resource Transaction Hash",
2777
2943
  type: "string",
2778
2944
  description: "On-chain transaction hash for adding the domain card linked resource"
2945
+ },
2946
+ {
2947
+ path: "parentLinkedEntityTransactionHash",
2948
+ displayName: "Parent Linked Entity Transaction Hash",
2949
+ type: "string",
2950
+ description: "On-chain transaction hash for linking the new POD to the selected parent entity"
2779
2951
  }
2780
2952
  ],
2781
2953
  pendingDisplayFields: ["entityDid", "governanceGroupCoreAddress"]
2782
2954
  }
2783
2955
  ],
2784
2956
  run: async (inputs, ctx) => {
2785
- const handlers = ctx.handlers;
2786
- if (!handlers) {
2787
- throw new Error("Handlers not available");
2788
- }
2789
- if (!handlers.requestPin) throw new Error("requestPin handler not available");
2790
- if (!handlers.signCredential) throw new Error("signCredential handler not implemented");
2791
- if (!handlers.publicFileUpload) throw new Error("publicFileUpload handler not available");
2792
- if (!handlers.createDomain) throw new Error("createDomain handler not implemented");
2793
- if (!handlers.createAddLinkedResourceMessage) throw new Error("createAddLinkedResourceMessage handler not implemented");
2794
- if (!handlers.executeTransaction) throw new Error("executeTransaction handler not implemented");
2957
+ const handlers = ctx.handlers || {};
2795
2958
  let domainCardData;
2796
2959
  if (typeof inputs.domainCardData === "string") {
2797
2960
  try {
@@ -2814,99 +2977,276 @@ registerAction({
2814
2977
  d.setFullYear(d.getFullYear() + 100);
2815
2978
  return d.toISOString();
2816
2979
  })();
2817
- let governanceGroupLinkedEntities = [];
2818
- let governanceGroupCoreAddress = "";
2819
2980
  const govConfig = parseJsonInput(inputs.governanceConfig);
2820
2981
  const memberConfig = parseJsonInput(inputs.memberConfig);
2982
+ const flowTemplateConfig = parseJsonInput(inputs.flowTemplateConfig);
2821
2983
  const context = parseContextInput(inputs.context);
2822
- if (govConfig && handlers.createGovernanceGroup) {
2823
- const groupType = govConfig.groupType;
2824
- const governance = govConfig.governance || {};
2825
- const config = buildGroupConfig(groupType, governance, memberConfig);
2826
- const groupResult = await handlers.createGovernanceGroup({
2827
- groupType,
2828
- name: govConfig.groupName || domainCardData.credentialSubject?.name || "Governance Group",
2829
- config
2830
- });
2831
- governanceGroupCoreAddress = groupResult.coreAddress;
2832
- governanceGroupLinkedEntities = [
2833
- {
2834
- id: `{id}#${governanceGroupCoreAddress}`,
2835
- type: "group",
2836
- relationship: "governs",
2837
- service: ""
2984
+ const selectedParentEntityDid = getSelectedParentEntityDid(inputs);
2985
+ const selectedProtocolTemplates = getSelectedProtocolTemplates(flowTemplateConfig);
2986
+ const checkpointKey = getDomainSignCheckpointKey(inputs, ctx);
2987
+ let checkpoint = readDomainSignCheckpoint(ctx, checkpointKey) || {
2988
+ invocationId: checkpointKey,
2989
+ status: "running",
2990
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2991
+ completedSteps: {}
2992
+ };
2993
+ if (checkpoint.status === "completed" && checkpoint.output) {
2994
+ return buildCompletedDomainSignResult(checkpoint.output);
2995
+ }
2996
+ if (!ctx.handlers) {
2997
+ throw new Error("Handlers not available");
2998
+ }
2999
+ if (typeof handlers.requestPin !== "function") throw new Error("requestPin handler not available");
3000
+ if (typeof handlers.signCredential !== "function") throw new Error("signCredential handler not implemented");
3001
+ if (typeof handlers.publicFileUpload !== "function") throw new Error("publicFileUpload handler not available");
3002
+ if (typeof handlers.createDomain !== "function") throw new Error("createDomain handler not implemented");
3003
+ if (typeof handlers.createAddLinkedResourceMessage !== "function") throw new Error("createAddLinkedResourceMessage handler not implemented");
3004
+ if (typeof handlers.executeTransaction !== "function") throw new Error("executeTransaction handler not implemented");
3005
+ const saveCheckpoint = (updates) => {
3006
+ checkpoint = {
3007
+ ...checkpoint,
3008
+ ...updates,
3009
+ invocationId: checkpointKey,
3010
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
3011
+ completedSteps: {
3012
+ ...checkpoint.completedSteps || {},
3013
+ ...updates.completedSteps || {}
2838
3014
  }
2839
- ];
2840
- }
2841
- const endDate = domainCardData.endDate || validUntil;
2842
- const { entityDid: newEntityDid, transactionHash } = await handlers.createDomain({
2843
- entityType,
2844
- context: context.length > 0 ? context : void 0,
2845
- linkedResource: [],
2846
- linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
2847
- startDate: validFrom,
2848
- endDate
2849
- });
2850
- const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
2851
- if (!issuerDid) throw new Error("Unable to determine issuer DID");
2852
- const credentialSubject = {
2853
- ...domainCardData.credentialSubject,
2854
- id: newEntityDid
3015
+ };
3016
+ writeDomainSignCheckpoint(ctx, checkpointKey, checkpoint);
3017
+ return checkpoint;
2855
3018
  };
2856
- const unsignedCredential = buildVerifiableCredential({
2857
- entityDid: newEntityDid,
2858
- issuerDid,
2859
- credentialSubject,
2860
- validFrom,
2861
- validUntil
2862
- });
2863
- const pin = await handlers.requestPin({
2864
- title: "Sign Domain Card",
2865
- description: "Enter your PIN to sign the Domain Card credential",
2866
- submitText: "Sign"
2867
- });
2868
- const { signedCredential } = await handlers.signCredential({
2869
- issuerDid,
2870
- issuerType: "user",
2871
- credential: unsignedCredential,
2872
- pin
2873
- });
2874
- const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
2875
- type: "application/json"
2876
- });
2877
- const credentialFile = new File([credentialBlob], "domainCard.json", {
2878
- type: "application/json"
2879
- });
2880
- const uploadResult = await handlers.publicFileUpload(credentialFile);
2881
- const domainCardLinkedResource = buildDomainCardLinkedResource({
2882
- entityDid: newEntityDid,
2883
- cid: uploadResult.cid,
2884
- serviceEndpoint: uploadResult.url,
2885
- description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
2886
- });
2887
- const addLinkedResourceMessage = await handlers.createAddLinkedResourceMessage({
2888
- entityDid: newEntityDid,
2889
- linkedResource: domainCardLinkedResource
2890
- });
2891
- const addLinkedResourceResult = await handlers.executeTransaction({
2892
- messages: [addLinkedResourceMessage],
2893
- memo: ""
3019
+ saveCheckpoint({
3020
+ status: "running",
3021
+ error: void 0,
3022
+ flowTemplateConfig
2894
3023
  });
2895
- const linkedResourceTransactionHash = String(addLinkedResourceResult?.transactionHash || "");
2896
- if (!linkedResourceTransactionHash) {
2897
- throw new Error("Linked resource transaction completed but no transaction hash received");
2898
- }
2899
- return {
2900
- output: {
3024
+ try {
3025
+ let governanceGroupLinkedEntities = checkpoint.governanceGroupLinkedEntities || [];
3026
+ let governanceGroupCoreAddress = checkpoint.governanceGroupCoreAddress || "";
3027
+ if (govConfig && handlers.createGovernanceGroup && !checkpoint.completedSteps?.createGovernanceGroup) {
3028
+ const groupType = govConfig.groupType;
3029
+ const governance = govConfig.governance || {};
3030
+ const config = buildGroupConfig(groupType, governance, memberConfig);
3031
+ const groupResult = await handlers.createGovernanceGroup({
3032
+ groupType,
3033
+ name: govConfig.groupName || domainCardData.credentialSubject?.name || "Governance Group",
3034
+ config
3035
+ });
3036
+ governanceGroupCoreAddress = groupResult.coreAddress;
3037
+ governanceGroupLinkedEntities = [
3038
+ {
3039
+ id: `{id}#${governanceGroupCoreAddress}`,
3040
+ type: "group",
3041
+ relationship: "governs",
3042
+ service: ""
3043
+ }
3044
+ ];
3045
+ saveCheckpoint({
3046
+ governanceGroupCoreAddress,
3047
+ governanceGroupLinkedEntities,
3048
+ completedSteps: { createGovernanceGroup: true }
3049
+ });
3050
+ } else if (!govConfig) {
3051
+ saveCheckpoint({ completedSteps: { createGovernanceGroup: true } });
3052
+ }
3053
+ const issuerDid = handlers.getEntityDid?.() || handlers.getCurrentUser?.()?.address;
3054
+ if (!issuerDid) throw new Error("Unable to determine issuer DID");
3055
+ const signAndUploadDomainCard = async (entityDid) => {
3056
+ const credentialSubject = {
3057
+ ...domainCardData.credentialSubject,
3058
+ id: entityDid
3059
+ };
3060
+ const unsignedCredential = buildVerifiableCredential({
3061
+ entityDid,
3062
+ issuerDid,
3063
+ credentialSubject,
3064
+ validFrom,
3065
+ validUntil
3066
+ });
3067
+ const pin = await handlers.requestPin({
3068
+ title: "Sign Domain Card",
3069
+ description: "Enter your PIN to sign the Domain Card credential",
3070
+ submitText: "Sign"
3071
+ });
3072
+ const { signedCredential } = await handlers.signCredential({
3073
+ issuerDid,
3074
+ issuerType: "user",
3075
+ credential: unsignedCredential,
3076
+ pin
3077
+ });
3078
+ const credentialBlob = new Blob([JSON.stringify(signedCredential, null, 2)], {
3079
+ type: "application/json"
3080
+ });
3081
+ const credentialFile = new File([credentialBlob], "domainCard.json", {
3082
+ type: "application/json"
3083
+ });
3084
+ const uploadResult = await handlers.publicFileUpload(credentialFile);
3085
+ return {
3086
+ ...buildDomainCardLinkedResource({
3087
+ entityDid,
3088
+ cid: uploadResult.cid,
3089
+ serviceEndpoint: uploadResult.url,
3090
+ description: `Domain Card for ${domainCardData.credentialSubject?.name || "Domain"}`
3091
+ }),
3092
+ id: "{id}#dmn"
3093
+ };
3094
+ };
3095
+ const endDate = domainCardData.endDate || validUntil;
3096
+ let newEntityDid = checkpoint.entityDid || "";
3097
+ let transactionHash = checkpoint.transactionHash || "";
3098
+ let linkedResourceTransactionHash = checkpoint.linkedResourceTransactionHash || "";
3099
+ const parentEntityDid = checkpoint.parentEntityDid || selectedParentEntityDid;
3100
+ let parentLinkedEntity = checkpoint.parentLinkedEntity;
3101
+ let parentLinkedEntityTransactionHash = checkpoint.parentLinkedEntityTransactionHash || "";
3102
+ let domainCardLinkedResource = checkpoint.domainCardLinkedResource;
3103
+ if (!checkpoint.completedSteps?.createDomain || !newEntityDid || !transactionHash) {
3104
+ const createResult = await handlers.createDomain({
3105
+ entityType,
3106
+ context: context.length > 0 ? context : void 0,
3107
+ linkedResource: [],
3108
+ linkedEntity: governanceGroupLinkedEntities.length > 0 ? governanceGroupLinkedEntities : void 0,
3109
+ startDate: validFrom,
3110
+ endDate
3111
+ });
3112
+ newEntityDid = createResult.entityDid;
3113
+ transactionHash = createResult.transactionHash;
3114
+ saveCheckpoint({
3115
+ entityDid: newEntityDid,
3116
+ transactionHash,
3117
+ completedSteps: { createDomain: true }
3118
+ });
3119
+ }
3120
+ if (!checkpoint.completedSteps?.signAndUploadDomainCard || !domainCardLinkedResource) {
3121
+ domainCardLinkedResource = await signAndUploadDomainCard(newEntityDid);
3122
+ saveCheckpoint({
3123
+ domainCardLinkedResource,
3124
+ completedSteps: { signAndUploadDomainCard: true }
3125
+ });
3126
+ }
3127
+ if (!checkpoint.completedSteps?.addLinkedResource || !linkedResourceTransactionHash) {
3128
+ const addLinkedResourceMessage = await handlers.createAddLinkedResourceMessage({
3129
+ entityDid: newEntityDid,
3130
+ linkedResource: domainCardLinkedResource
3131
+ });
3132
+ const addLinkedResourceResult = await handlers.executeTransaction({
3133
+ messages: [addLinkedResourceMessage],
3134
+ memo: ""
3135
+ });
3136
+ linkedResourceTransactionHash = String(addLinkedResourceResult?.transactionHash || "");
3137
+ if (!linkedResourceTransactionHash) {
3138
+ throw new Error("Linked resource transaction completed but no transaction hash received");
3139
+ }
3140
+ saveCheckpoint({
3141
+ linkedResourceTransactionHash,
3142
+ completedSteps: { addLinkedResource: true }
3143
+ });
3144
+ }
3145
+ if (parentEntityDid && (!checkpoint.completedSteps?.addParentLinkedEntity || !parentLinkedEntityTransactionHash)) {
3146
+ if (typeof handlers.createAddLinkedEntityMessage !== "function") {
3147
+ throw new Error("createAddLinkedEntityMessage handler not implemented");
3148
+ }
3149
+ parentLinkedEntity = parentLinkedEntity || {
3150
+ id: newEntityDid,
3151
+ type: entityType,
3152
+ relationship: "manages",
3153
+ service: ""
3154
+ };
3155
+ const addParentLinkedEntityMessage = await handlers.createAddLinkedEntityMessage({
3156
+ entityDid: parentEntityDid,
3157
+ linkedEntity: parentLinkedEntity
3158
+ });
3159
+ const addParentLinkedEntityResult = await handlers.executeTransaction({
3160
+ messages: [addParentLinkedEntityMessage],
3161
+ memo: ""
3162
+ });
3163
+ parentLinkedEntityTransactionHash = String(addParentLinkedEntityResult?.transactionHash || "");
3164
+ if (!parentLinkedEntityTransactionHash) {
3165
+ throw new Error("Parent linked entity transaction completed but no transaction hash received");
3166
+ }
3167
+ saveCheckpoint({
3168
+ parentEntityDid,
3169
+ parentLinkedEntity,
3170
+ parentLinkedEntityTransactionHash,
3171
+ completedSteps: { addParentLinkedEntity: true }
3172
+ });
3173
+ } else if (!parentEntityDid) {
3174
+ saveCheckpoint({ completedSteps: { addParentLinkedEntity: true } });
3175
+ }
3176
+ let domainSpaces = checkpoint.domainSpaces;
3177
+ let protocolTemplateImports = checkpoint.protocolTemplateImports || [];
3178
+ if (handlers.sourceDomainSpaces && (!checkpoint.completedSteps?.sourceDomainSpaces || !domainSpaces)) {
3179
+ domainSpaces = await handlers.sourceDomainSpaces({ entityDid: newEntityDid });
3180
+ if (!domainSpaces?.success) {
3181
+ throw new Error("Domain spaces could not be sourced for the newly created domain");
3182
+ }
3183
+ saveCheckpoint({
3184
+ domainSpaces,
3185
+ completedSteps: { sourceDomainSpaces: true }
3186
+ });
3187
+ } else if (!handlers.sourceDomainSpaces) {
3188
+ saveCheckpoint({ completedSteps: { sourceDomainSpaces: true } });
3189
+ }
3190
+ if (selectedProtocolTemplates.length > 0 && !checkpoint.completedSteps?.importTemplates) {
3191
+ if (!handlers.sourceDomainSpaces) {
3192
+ throw new Error("sourceDomainSpaces handler is required to import selected protocol templates");
3193
+ }
3194
+ if (!handlers.importProtocolTemplatesToSpace) {
3195
+ throw new Error("importProtocolTemplatesToSpace handler is required to import selected protocol templates");
3196
+ }
3197
+ const targetFlowsSubspaceId = domainSpaces?.subspaces?.["domain flows"]?.space_id;
3198
+ if (!targetFlowsSubspaceId) {
3199
+ throw new Error("Domain flows subspace was not returned by sourceDomainSpaces");
3200
+ }
3201
+ const groupedTemplates = groupTemplatesByProtocol(selectedProtocolTemplates);
3202
+ protocolTemplateImports = await Promise.all(
3203
+ Array.from(groupedTemplates.entries()).map(async ([protocolDid, templates]) => {
3204
+ const result = await handlers.importProtocolTemplatesToSpace({
3205
+ protocolDid,
3206
+ entityDid: newEntityDid,
3207
+ targetFlowsSubspaceId,
3208
+ templates
3209
+ });
3210
+ return { protocolDid, imported: result.imported };
3211
+ })
3212
+ );
3213
+ saveCheckpoint({
3214
+ protocolTemplateImports,
3215
+ completedSteps: { importTemplates: true }
3216
+ });
3217
+ } else if (selectedProtocolTemplates.length === 0) {
3218
+ saveCheckpoint({
3219
+ protocolTemplateImports,
3220
+ completedSteps: { importTemplates: true }
3221
+ });
3222
+ }
3223
+ const output = {
2901
3224
  entityDid: newEntityDid,
2902
3225
  governanceGroupCoreAddress,
2903
3226
  linkedEntities: governanceGroupLinkedEntities,
2904
3227
  linkedResources: [domainCardLinkedResource],
3228
+ parentEntityDid,
3229
+ parentLinkedEntity,
3230
+ flowTemplateConfig,
3231
+ domainSpaces,
3232
+ protocolTemplateImports,
2905
3233
  transactionHash,
2906
- linkedResourceTransactionHash
2907
- },
2908
- events: [{ name: "created", payload: { entityDid: newEntityDid, governanceGroupCoreAddress, transactionHash, linkedResourceTransactionHash } }]
2909
- };
3234
+ linkedResourceTransactionHash,
3235
+ parentLinkedEntityTransactionHash
3236
+ };
3237
+ saveCheckpoint({
3238
+ status: "completed",
3239
+ output
3240
+ });
3241
+ return buildCompletedDomainSignResult(output);
3242
+ } catch (error) {
3243
+ const message = error instanceof Error ? error.message : "Domain sign failed";
3244
+ saveCheckpoint({
3245
+ status: "failed",
3246
+ error: message
3247
+ });
3248
+ throw error;
3249
+ }
2910
3250
  }
2911
3251
  });
2912
3252
 
@@ -3078,9 +3418,7 @@ registerAction({
3078
3418
  }
3079
3419
  const verb = String(inputs.verb || "").trim().toLowerCase();
3080
3420
  if (verb !== "propose" && verb !== "execute" && verb !== "check") {
3081
- throw new Error(
3082
- 'verb is required and must be one of: "propose", "execute", "check"'
3083
- );
3421
+ throw new Error('verb is required and must be one of: "propose", "execute", "check"');
3084
3422
  }
3085
3423
  const paymentBlockId = String(inputs.paymentBlockId || "").trim();
3086
3424
  if (!paymentBlockId) {
@@ -3108,6 +3446,15 @@ registerAction({
3108
3446
  verb,
3109
3447
  rowCount: rowIds.length,
3110
3448
  paymentBlockId
3449
+ },
3450
+ completion: {
3451
+ state: "awaiting_readback",
3452
+ readBack: {
3453
+ kind: "paymentRows",
3454
+ paymentBlockId,
3455
+ rowIds,
3456
+ verb
3457
+ }
3111
3458
  }
3112
3459
  };
3113
3460
  }
@@ -5275,6 +5622,7 @@ function toSupportedDID(did) {
5275
5622
  }
5276
5623
  function normalizeDid(did) {
5277
5624
  if (did.startsWith("did:")) return did;
5625
+ if (did.startsWith("ixo1")) return `did:ixo:${did}`;
5278
5626
  if (!did.startsWith("@did-")) return did;
5279
5627
  const [localpart] = did.split(":");
5280
5628
  const parts = localpart.split("-");
@@ -5363,7 +5711,7 @@ var createUcanService = (config) => {
5363
5711
  const capabilities = [{ can: "flow/*", with: uri }];
5364
5712
  if (handlers.createSignerSession && handlers.createDelegationWithSession) {
5365
5713
  const session = await handlers.createSignerSession({
5366
- did: ownerDid,
5714
+ did: normalizedOwnerDid,
5367
5715
  didType: issuerType,
5368
5716
  entityRoomId,
5369
5717
  pin,
@@ -5371,15 +5719,15 @@ var createUcanService = (config) => {
5371
5719
  });
5372
5720
  const result = await handlers.createDelegationWithSession({
5373
5721
  sessionId: session.sessionId,
5374
- audience: ownerDid,
5722
+ audience: normalizedOwnerDid,
5375
5723
  capabilities,
5376
5724
  proofs: []
5377
5725
  });
5378
5726
  const storedDelegation2 = {
5379
5727
  cid: result.cid,
5380
5728
  delegation: result.delegation,
5381
- issuerDid: ownerDid,
5382
- audienceDid: ownerDid,
5729
+ issuerDid: normalizedOwnerDid,
5730
+ audienceDid: normalizedOwnerDid,
5383
5731
  capabilities,
5384
5732
  createdAt: Date.now(),
5385
5733
  format: "car",
@@ -5420,7 +5768,7 @@ var createUcanService = (config) => {
5420
5768
  const proofCids = proofs;
5421
5769
  if (handlers.createSignerSession && handlers.createDelegationWithSession) {
5422
5770
  const session = await handlers.createSignerSession({
5423
- did: issuerDid,
5771
+ did: normalizedIssuerDid,
5424
5772
  didType: issuerType,
5425
5773
  entityRoomId,
5426
5774
  pin,
@@ -5429,7 +5777,7 @@ var createUcanService = (config) => {
5429
5777
  const proofCars = await getProofCars(proofCids);
5430
5778
  const result = await handlers.createDelegationWithSession({
5431
5779
  sessionId: session.sessionId,
5432
- audience,
5780
+ audience: normalizedAudienceDid,
5433
5781
  capabilities,
5434
5782
  proofs: proofCars,
5435
5783
  expiration: expiration ? Math.floor(expiration / 1e3) : void 0
@@ -5437,8 +5785,8 @@ var createUcanService = (config) => {
5437
5785
  const storedDelegation2 = {
5438
5786
  cid: result.cid,
5439
5787
  delegation: result.delegation,
5440
- issuerDid,
5441
- audienceDid: audience,
5788
+ issuerDid: normalizedIssuerDid,
5789
+ audienceDid: normalizedAudienceDid,
5442
5790
  capabilities,
5443
5791
  expiration,
5444
5792
  createdAt: Date.now(),
@@ -5491,7 +5839,7 @@ var createUcanService = (config) => {
5491
5839
  const delegations = delegationStore.getByAudience(audienceDid);
5492
5840
  if (delegations.length === 0) {
5493
5841
  const root = delegationStore.getRoot();
5494
- if (root && root.audienceDid === audienceDid) {
5842
+ if (root && normalizeDid(root.audienceDid) === normalizeDid(audienceDid)) {
5495
5843
  return { found: true, proofCids: [root.cid] };
5496
5844
  }
5497
5845
  return { found: false, error: "No delegations found for actor" };
@@ -5547,7 +5895,7 @@ var createUcanService = (config) => {
5547
5895
  const isFlowScoped = capability.can === "flow/*" || capability.can.startsWith("flow/");
5548
5896
  if (isFlowScoped) {
5549
5897
  const root = proofChain[proofChain.length - 1];
5550
- if (root.issuerDid !== flowOwnerDid) {
5898
+ if (normalizeDid(root.issuerDid) !== normalizeDid(flowOwnerDid)) {
5551
5899
  return { valid: false, error: `Root issuer ${root.issuerDid} is not flow owner ${flowOwnerDid}` };
5552
5900
  }
5553
5901
  }
@@ -5555,7 +5903,8 @@ var createUcanService = (config) => {
5555
5903
  };
5556
5904
  const createAndValidateInvocation = async (params, _flowId, _blockId) => {
5557
5905
  const { invokerDid, invokerType, entityRoomId, capability, proofs, pin } = params;
5558
- const validation = await validateDelegationChain(invokerDid, capability);
5906
+ const normalizedInvokerDid = normalizeDid(invokerDid);
5907
+ const validation = await validateDelegationChain(normalizedInvokerDid, capability);
5559
5908
  if (!validation.valid) {
5560
5909
  return {
5561
5910
  cid: "",
@@ -5564,11 +5913,11 @@ var createUcanService = (config) => {
5564
5913
  error: validation.error
5565
5914
  };
5566
5915
  }
5567
- const audience = params.audience ?? flowOwnerDid;
5916
+ const audience = normalizeDid(params.audience ?? flowOwnerDid);
5568
5917
  if (handlers.createSignerSession && handlers.createInvocationWithSession) {
5569
5918
  try {
5570
5919
  const session = await handlers.createSignerSession({
5571
- did: invokerDid,
5920
+ did: normalizedInvokerDid,
5572
5921
  didType: invokerType,
5573
5922
  entityRoomId,
5574
5923
  pin,
@@ -6083,6 +6432,9 @@ var createRuntimeStateManager = (editor) => {
6083
6432
  }
6084
6433
  return createMemoryManager();
6085
6434
  };
6435
+ var createYDocRuntimeManager = (yDoc) => {
6436
+ return createYMapManager(yDoc.getMap("runtime"));
6437
+ };
6086
6438
  function clearRuntimeForTemplateClone(yDoc) {
6087
6439
  const runtime = yDoc.getMap("runtime");
6088
6440
  const invocations = yDoc.getMap("invocations");
@@ -6100,6 +6452,66 @@ function clearRuntimeForTemplateClone(yDoc) {
6100
6452
  });
6101
6453
  }
6102
6454
 
6455
+ // src/core/types/baseUcan.ts
6456
+ function isRuntimeRef(value) {
6457
+ return typeof value === "object" && value !== null && "$ref" in value && typeof value.$ref === "string";
6458
+ }
6459
+
6460
+ // src/core/lib/flowCompiler/resolveRefs.ts
6461
+ function resolveRuntimeRefs(nb, getNodeOutput2, triggerContext) {
6462
+ return resolveValue(nb, getNodeOutput2, triggerContext);
6463
+ }
6464
+ function resolveValue(value, getNodeOutput2, triggerContext) {
6465
+ if (isRuntimeRef(value)) {
6466
+ return resolveRef(value.$ref, getNodeOutput2, triggerContext);
6467
+ }
6468
+ if (Array.isArray(value)) {
6469
+ return value.map((item) => resolveValue(item, getNodeOutput2, triggerContext));
6470
+ }
6471
+ if (typeof value === "object" && value !== null) {
6472
+ const result = {};
6473
+ for (const [key, val] of Object.entries(value)) {
6474
+ result[key] = resolveValue(val, getNodeOutput2, triggerContext);
6475
+ }
6476
+ return result;
6477
+ }
6478
+ return value;
6479
+ }
6480
+ function resolveRef(ref, getNodeOutput2, triggerContext) {
6481
+ if (ref.startsWith("trigger.payload.")) {
6482
+ if (!triggerContext) {
6483
+ throw new Error(`Trigger ref "${ref}" used outside of a listener invocation context. trigger.payload.* refs are only valid on block.event-triggered blocks.`);
6484
+ }
6485
+ const fieldPath2 = ref.slice("trigger.payload.".length);
6486
+ return getNestedValue(triggerContext.payload, fieldPath2);
6487
+ }
6488
+ if (triggerContext && Object.prototype.hasOwnProperty.call(triggerContext.refSnapshots, ref)) {
6489
+ return triggerContext.refSnapshots[ref];
6490
+ }
6491
+ const outputIndex = ref.indexOf(".output.");
6492
+ if (outputIndex === -1) {
6493
+ throw new Error(`Invalid runtime reference "${ref}". Expected format: "nodeId.output.fieldPath" or "trigger.payload.fieldPath"`);
6494
+ }
6495
+ const nodeId = ref.slice(0, outputIndex);
6496
+ const fieldPath = ref.slice(outputIndex + ".output.".length);
6497
+ const output = getNodeOutput2(nodeId);
6498
+ if (!output) {
6499
+ return void 0;
6500
+ }
6501
+ return getNestedValue(output, fieldPath);
6502
+ }
6503
+ function getNestedValue(obj, path) {
6504
+ const parts = path.split(".");
6505
+ let current = obj;
6506
+ for (const part of parts) {
6507
+ if (current == null || typeof current !== "object") {
6508
+ return void 0;
6509
+ }
6510
+ current = current[part];
6511
+ }
6512
+ return current;
6513
+ }
6514
+
6103
6515
  // src/core/lib/flowEngine/versionManifest.ts
6104
6516
  var VERSION_MANIFEST = {
6105
6517
  "0.3": {
@@ -6310,11 +6722,6 @@ var executeNode = async ({ node, actorDid, actorType, entityRoomId, context, act
6310
6722
  }
6311
6723
  };
6312
6724
 
6313
- // src/core/types/baseUcan.ts
6314
- function isRuntimeRef(value) {
6315
- return typeof value === "object" && value !== null && "$ref" in value && typeof value.$ref === "string";
6316
- }
6317
-
6318
6725
  // src/core/lib/flowEngine/triggers.ts
6319
6726
  import * as Y from "yjs";
6320
6727
  var RUN_RECORD_AUDIT_TYPE = "block.run";
@@ -6323,15 +6730,15 @@ function computePendingInvocationId(args) {
6323
6730
  const input = `${sourceBlockId}:${sourceRunId}:${listenerBlockId}:${eventName}:${eventIndex}`;
6324
6731
  return `pi-${fnv1a32(input)}`;
6325
6732
  }
6326
- function snapshotInputRefs(inputs, getNodeOutput) {
6733
+ function snapshotInputRefs(inputs, getNodeOutput2) {
6327
6734
  const snapshots = {};
6328
6735
  walkRefs(inputs, (ref) => {
6329
6736
  if (ref.$ref.startsWith("trigger.")) return;
6330
6737
  const parsed = parseOutputRef(ref.$ref);
6331
6738
  if (!parsed) return;
6332
- const output = getNodeOutput(parsed.nodeId);
6739
+ const output = getNodeOutput2(parsed.nodeId);
6333
6740
  if (!output) return;
6334
- snapshots[ref.$ref] = getNestedValue(output, parsed.fieldPath);
6741
+ snapshots[ref.$ref] = getNestedValue2(output, parsed.fieldPath);
6335
6742
  });
6336
6743
  return snapshots;
6337
6744
  }
@@ -6356,7 +6763,7 @@ function parseOutputRef(ref) {
6356
6763
  fieldPath: ref.slice(outputIndex + ".output.".length)
6357
6764
  };
6358
6765
  }
6359
- function getNestedValue(obj, path) {
6766
+ function getNestedValue2(obj, path) {
6360
6767
  const parts = path.split(".");
6361
6768
  let current = obj;
6362
6769
  for (const part of parts) {
@@ -6584,7 +6991,7 @@ function _reconcilePendingInvocationsInner(editor) {
6584
6991
  }
6585
6992
  if (listenersBySource.size === 0 && barrierListenersBySource.size === 0) return;
6586
6993
  const runtimeMap = editor._yRuntime;
6587
- const getNodeOutput = (nodeId) => {
6994
+ const getNodeOutput2 = (nodeId) => {
6588
6995
  if (!runtimeMap) return void 0;
6589
6996
  const state = runtimeMap.get(nodeId);
6590
6997
  if (!state || typeof state !== "object") return void 0;
@@ -6610,12 +7017,12 @@ function _reconcilePendingInvocationsInner(editor) {
6610
7017
  if (!hasAnyListener) continue;
6611
7018
  const records = readRunRecords(yDoc, sourceBlockId);
6612
7019
  for (const record of records) {
6613
- processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNodeOutput, runtimeMap);
6614
- processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBySource, getNodeOutput, runtimeMap);
7020
+ processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNodeOutput2, runtimeMap);
7021
+ processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBySource, getNodeOutput2, runtimeMap);
6615
7022
  }
6616
7023
  }
6617
7024
  }
6618
- function processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNodeOutput, runtimeMap) {
7025
+ function processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNodeOutput2, runtimeMap) {
6619
7026
  if (!Array.isArray(record.events)) return;
6620
7027
  record.events.forEach((event, eventIndex) => {
6621
7028
  if (!event?.name) return;
@@ -6634,7 +7041,7 @@ function processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNod
6634
7041
  });
6635
7042
  const assigneeDid = resolveAssignee(listenerBlock) || "unassigned";
6636
7043
  const inputs = parseInputs(listenerBlock);
6637
- const refSnapshots = snapshotInputRefs(inputs, getNodeOutput);
7044
+ const refSnapshots = snapshotInputRefs(inputs, getNodeOutput2);
6638
7045
  const expiresAt = computeExpiry(listenerBlock, record.completedAt);
6639
7046
  const invocation = {
6640
7047
  id,
@@ -6659,7 +7066,7 @@ function processRunRecord(yDoc, sourceBlockId, record, listenersBySource, getNod
6659
7066
  }
6660
7067
  });
6661
7068
  }
6662
- function processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBySource, getNodeOutput, runtimeMap) {
7069
+ function processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBySource, getNodeOutput2, runtimeMap) {
6663
7070
  if (!Array.isArray(record.events)) return;
6664
7071
  for (const event of record.events) {
6665
7072
  if (!event?.name) continue;
@@ -6694,7 +7101,7 @@ function processBarrierRunRecord(yDoc, sourceBlockId, record, barrierListenersBy
6694
7101
  const id = computeBarrierInvocationId(currentState, listenerBlockId);
6695
7102
  const mergedPayload = mergeBarrierPayloads(currentState);
6696
7103
  const inputs = parseInputs(listenerBlock);
6697
- const refSnapshots = snapshotInputRefs(inputs, getNodeOutput);
7104
+ const refSnapshots = snapshotInputRefs(inputs, getNodeOutput2);
6698
7105
  const expiresAt = computeExpiry(listenerBlock, record.completedAt);
6699
7106
  const invocation = {
6700
7107
  id,
@@ -6804,6 +7211,553 @@ function writeRunRecordAndReconcile(editor, blockId, output, events, actorDid, d
6804
7211
  reconcilePendingInvocations(editor);
6805
7212
  }
6806
7213
 
7214
+ // src/core/lib/flowEngine/actionExecutor.ts
7215
+ import * as Y3 from "yjs";
7216
+
7217
+ // src/core/lib/flowEngine/readBackReconciler.ts
7218
+ import * as Y2 from "yjs";
7219
+ function isYDoc(value) {
7220
+ return value instanceof Y2.Doc;
7221
+ }
7222
+ function getYDoc(editorOrYDoc) {
7223
+ if (!editorOrYDoc) return void 0;
7224
+ if (isYDoc(editorOrYDoc)) return editorOrYDoc;
7225
+ return editorOrYDoc._yDoc;
7226
+ }
7227
+ function getEditor(editorOrYDoc) {
7228
+ return editorOrYDoc && !isYDoc(editorOrYDoc) ? editorOrYDoc : void 0;
7229
+ }
7230
+ function getRuntime(editorOrYDoc, runtime) {
7231
+ if (runtime) return runtime;
7232
+ const yDoc = getYDoc(editorOrYDoc);
7233
+ if (yDoc) return createYDocRuntimeManager(yDoc);
7234
+ return createRuntimeStateManager(!isYDoc(editorOrYDoc) ? editorOrYDoc : void 0);
7235
+ }
7236
+ function getReconcileEditor(params, yDoc, editor) {
7237
+ if (editor) return editor;
7238
+ if (!yDoc || !params.document) return void 0;
7239
+ return {
7240
+ _yDoc: yDoc,
7241
+ _yRuntime: yDoc.getMap("runtime"),
7242
+ document: params.document
7243
+ };
7244
+ }
7245
+ function makeRunId(now) {
7246
+ return `readback-${now()}-${Math.random().toString(36).slice(2, 8)}`;
7247
+ }
7248
+ function asOutput(value) {
7249
+ return value && typeof value === "object" && !Array.isArray(value) ? { ...value } : {};
7250
+ }
7251
+ function errorRecord(error) {
7252
+ if (!error) return void 0;
7253
+ return typeof error === "string" ? { message: error } : { message: error.message, code: error.code };
7254
+ }
7255
+ function normalizeActionReadBackMetadata(params) {
7256
+ const base = params.readBack && typeof params.readBack === "object" && !Array.isArray(params.readBack) ? { ...params.readBack } : {};
7257
+ const kind = typeof base.kind === "string" && base.kind.trim() ? base.kind.trim() : params.actionType;
7258
+ const normalized = {
7259
+ ...base,
7260
+ kind,
7261
+ status: "pending",
7262
+ requestedAt: typeof base.requestedAt === "string" ? base.requestedAt : new Date(params.requestedAt).toISOString(),
7263
+ blockId: params.blockId,
7264
+ actionType: params.actionType,
7265
+ actorDid: params.actorDid,
7266
+ invocationCid: params.invocationCid,
7267
+ capabilityId: params.capabilityId
7268
+ };
7269
+ if (params.pendingInvocation) {
7270
+ normalized.pendingInvocation = {
7271
+ id: params.pendingInvocation.id,
7272
+ triggeringBlockId: params.pendingInvocation.triggeringBlockId,
7273
+ eventName: params.pendingInvocation.eventName,
7274
+ sourceRunId: params.pendingInvocation.sourceRunId
7275
+ };
7276
+ }
7277
+ return normalized;
7278
+ }
7279
+ function writeReconciliationRunRecord(params) {
7280
+ if (!params.yDoc) return void 0;
7281
+ const completedAt = params.now();
7282
+ const runId = makeRunId(params.now);
7283
+ const pendingInvocation = params.readBack.pendingInvocation;
7284
+ const details = {
7285
+ runId,
7286
+ output: params.output,
7287
+ events: params.events,
7288
+ startedAt: params.readBack.requestedAt || new Date(completedAt).toISOString(),
7289
+ completedAt: new Date(completedAt).toISOString(),
7290
+ actorDid: params.actorDid,
7291
+ invocationCid: params.readBack.invocationCid,
7292
+ capabilityId: params.readBack.capabilityId,
7293
+ error: params.error,
7294
+ readBack: params.readBack,
7295
+ reconciled: true
7296
+ };
7297
+ if (pendingInvocation) {
7298
+ details.fromPendingInvocationId = pendingInvocation.id;
7299
+ details.triggeredBy = {
7300
+ sourceBlockId: pendingInvocation.triggeringBlockId,
7301
+ eventName: pendingInvocation.eventName
7302
+ };
7303
+ details.sourceRunId = pendingInvocation.sourceRunId;
7304
+ }
7305
+ appendRunRecord(params.yDoc, params.blockId, details, params.actorDid);
7306
+ if (params.editor && params.events.length > 0) {
7307
+ reconcilePendingInvocations(params.editor);
7308
+ }
7309
+ return runId;
7310
+ }
7311
+ async function reconcileActionReadBack(params) {
7312
+ const now = params.now || Date.now;
7313
+ const yDoc = getYDoc(params.editorOrYDoc);
7314
+ const editor = getEditor(params.editorOrYDoc);
7315
+ const runtime = getRuntime(params.editorOrYDoc, params.runtime);
7316
+ const current = runtime.get(params.blockId);
7317
+ const output = asOutput(current.output);
7318
+ const readBack = current.readBack;
7319
+ if (current.state !== "awaiting_readback" || !readBack?.kind) {
7320
+ return {
7321
+ success: false,
7322
+ blockId: params.blockId,
7323
+ state: current.state === "failed" ? "failed" : "pending",
7324
+ output,
7325
+ events: [],
7326
+ error: `Block "${params.blockId}" is not awaiting read-back`,
7327
+ pendingInvocationRemoved: false,
7328
+ readBack
7329
+ };
7330
+ }
7331
+ const resolver = params.resolver || params.resolvers?.[readBack.kind];
7332
+ if (!resolver) {
7333
+ return {
7334
+ success: false,
7335
+ blockId: params.blockId,
7336
+ state: "pending",
7337
+ output,
7338
+ events: [],
7339
+ error: `No read-back resolver registered for "${readBack.kind}"`,
7340
+ pendingInvocationRemoved: false,
7341
+ readBack
7342
+ };
7343
+ }
7344
+ const resolution = await resolver({
7345
+ blockId: params.blockId,
7346
+ runtime: current,
7347
+ output,
7348
+ readBack
7349
+ });
7350
+ const checkedAt = now();
7351
+ const checkedIso = new Date(checkedAt).toISOString();
7352
+ const nextReadBack = {
7353
+ ...readBack,
7354
+ ...resolution.readBack || {},
7355
+ status: resolution.state,
7356
+ lastCheckedAt: checkedIso
7357
+ };
7358
+ if (resolution.state === "pending") {
7359
+ runtime.update(params.blockId, {
7360
+ readBack: nextReadBack
7361
+ });
7362
+ return {
7363
+ success: true,
7364
+ blockId: params.blockId,
7365
+ state: "pending",
7366
+ output,
7367
+ events: resolution.events || [],
7368
+ pendingInvocationRemoved: false,
7369
+ readBack: nextReadBack
7370
+ };
7371
+ }
7372
+ const events = resolution.events || [];
7373
+ const finalOutput = {
7374
+ ...output,
7375
+ ...resolution.output || {}
7376
+ };
7377
+ const actorDid = params.actorDid || readBack.actorDid || current.executedByDid || "system:readback";
7378
+ if (resolution.state === "failed") {
7379
+ const error = errorRecord(resolution.error) || { message: "External read-back failed" };
7380
+ const failedReadBack = {
7381
+ ...nextReadBack,
7382
+ terminalAt: checkedIso
7383
+ };
7384
+ runtime.update(params.blockId, {
7385
+ state: "failed",
7386
+ output: finalOutput,
7387
+ error: { ...error, at: checkedAt },
7388
+ readBack: failedReadBack
7389
+ });
7390
+ const runId2 = writeReconciliationRunRecord({
7391
+ yDoc,
7392
+ editor: getReconcileEditor(params, yDoc, editor),
7393
+ blockId: params.blockId,
7394
+ actorDid,
7395
+ output: finalOutput,
7396
+ events,
7397
+ readBack: failedReadBack,
7398
+ error,
7399
+ now
7400
+ });
7401
+ return {
7402
+ success: false,
7403
+ blockId: params.blockId,
7404
+ state: "failed",
7405
+ output: finalOutput,
7406
+ events,
7407
+ error: error.message,
7408
+ runId: runId2,
7409
+ pendingInvocationRemoved: false,
7410
+ readBack: failedReadBack
7411
+ };
7412
+ }
7413
+ const completedReadBack = {
7414
+ ...nextReadBack,
7415
+ terminalAt: checkedIso
7416
+ };
7417
+ runtime.update(params.blockId, {
7418
+ state: "completed",
7419
+ output: finalOutput,
7420
+ executedAt: checkedAt,
7421
+ error: void 0,
7422
+ readBack: completedReadBack
7423
+ });
7424
+ const runId = writeReconciliationRunRecord({
7425
+ yDoc,
7426
+ editor: getReconcileEditor(params, yDoc, editor),
7427
+ blockId: params.blockId,
7428
+ actorDid,
7429
+ output: finalOutput,
7430
+ events,
7431
+ readBack: completedReadBack,
7432
+ now
7433
+ });
7434
+ const pendingInvocationRemoved = Boolean(yDoc && completedReadBack.pendingInvocation?.id) && removePendingInvocation(yDoc, params.blockId, completedReadBack.pendingInvocation.id);
7435
+ return {
7436
+ success: true,
7437
+ blockId: params.blockId,
7438
+ state: "completed",
7439
+ output: finalOutput,
7440
+ events,
7441
+ runId,
7442
+ pendingInvocationRemoved,
7443
+ readBack: completedReadBack
7444
+ };
7445
+ }
7446
+
7447
+ // src/core/lib/flowEngine/actionExecutor.ts
7448
+ function isYDoc2(value) {
7449
+ return value instanceof Y3.Doc;
7450
+ }
7451
+ function getYDoc2(editorOrYDoc) {
7452
+ if (!editorOrYDoc) return void 0;
7453
+ if (isYDoc2(editorOrYDoc)) return editorOrYDoc;
7454
+ return editorOrYDoc._yDoc;
7455
+ }
7456
+ function parseInputs2(value) {
7457
+ if (value == null || value === "") return {};
7458
+ if (typeof value === "object" && !Array.isArray(value)) return { ...value };
7459
+ if (typeof value !== "string") return {};
7460
+ try {
7461
+ const parsed = JSON.parse(value);
7462
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7463
+ } catch {
7464
+ return {};
7465
+ }
7466
+ }
7467
+ function getRuntime2(editorOrYDoc, runtime) {
7468
+ if (runtime) return runtime;
7469
+ const yDoc = getYDoc2(editorOrYDoc);
7470
+ if (yDoc) return createYDocRuntimeManager(yDoc);
7471
+ return createRuntimeStateManager(!isYDoc2(editorOrYDoc) ? editorOrYDoc : void 0);
7472
+ }
7473
+ function getEditor2(editorOrYDoc) {
7474
+ return editorOrYDoc && !isYDoc2(editorOrYDoc) ? editorOrYDoc : void 0;
7475
+ }
7476
+ function findBlock(params) {
7477
+ if (params.block) return params.block;
7478
+ const blockId = params.blockId;
7479
+ if (!blockId) return void 0;
7480
+ const editor = getEditor2(params.editorOrYDoc);
7481
+ return (params.document || editor?.document || []).find((block) => block?.id === blockId);
7482
+ }
7483
+ function getFlowMetadata(editor) {
7484
+ const metadata = editor?.getFlowMetadata?.();
7485
+ const flowId = metadata?.doc_id || "";
7486
+ return {
7487
+ flowId,
7488
+ flowUri: flowId ? `ixo:flow:${flowId}` : "",
7489
+ flowOwnerDid: editor?.getFlowOwnerDid?.() || metadata?.flowOwnerDid || "",
7490
+ schemaVersion: metadata?.schema_version || "0.3"
7491
+ };
7492
+ }
7493
+ function getPendingInvocation(yDoc, blockId, pendingInvocationId) {
7494
+ if (!pendingInvocationId) return void 0;
7495
+ if (!yDoc) {
7496
+ throw new Error(`Cannot load pending invocation "${pendingInvocationId}" without a Y.Doc`);
7497
+ }
7498
+ if (!blockId) {
7499
+ throw new Error(`Cannot load pending invocation "${pendingInvocationId}" without a block id`);
7500
+ }
7501
+ const pending = readPendingInvocations(yDoc, blockId).find((invocation) => invocation.id === pendingInvocationId);
7502
+ if (!pending) {
7503
+ throw new Error(`Pending invocation "${pendingInvocationId}" was not found for block "${blockId}"`);
7504
+ }
7505
+ return pending;
7506
+ }
7507
+ function getNodeOutput(runtime, nodeId) {
7508
+ const state = runtime.get(nodeId);
7509
+ const output = state.output;
7510
+ return output && typeof output === "object" && !Array.isArray(output) ? output : void 0;
7511
+ }
7512
+ function buildActionRunInputs(params) {
7513
+ const blockId = params.blockId || params.block?.id;
7514
+ const yDoc = getYDoc2(params.editorOrYDoc);
7515
+ const runtime = getRuntime2(params.editorOrYDoc, params.runtime);
7516
+ const savedInputs = parseInputs2(params.savedInputs ?? params.block?.props?.inputs);
7517
+ const pendingInvocation = getPendingInvocation(yDoc, blockId, params.pendingInvocationId);
7518
+ const triggerContext = pendingInvocation ? {
7519
+ payload: pendingInvocation.payload || {},
7520
+ refSnapshots: pendingInvocation.refSnapshots || {}
7521
+ } : void 0;
7522
+ const mergedInputs = {
7523
+ ...savedInputs,
7524
+ ...pendingInvocation?.payload || {},
7525
+ ...pendingInvocation?.refSnapshots || {},
7526
+ ...params.runtimeInputs || {}
7527
+ };
7528
+ return {
7529
+ inputs: resolveRuntimeRefs(mergedInputs, (nodeId) => getNodeOutput(runtime, nodeId), triggerContext),
7530
+ savedInputs,
7531
+ mergedInputs,
7532
+ pendingInvocation,
7533
+ triggerContext
7534
+ };
7535
+ }
7536
+ function buildFailureResult(params) {
7537
+ return {
7538
+ success: false,
7539
+ stage: params.stage,
7540
+ blockId: params.blockId,
7541
+ actionType: params.actionType,
7542
+ events: [],
7543
+ error: params.error,
7544
+ completionState: "failed",
7545
+ pendingInvocation: params.pendingInvocation
7546
+ };
7547
+ }
7548
+ function updateRuntimeFailure(runtime, blockId, message, now) {
7549
+ runtime.update(blockId, {
7550
+ state: "failed",
7551
+ error: { message, at: now() }
7552
+ });
7553
+ }
7554
+ function makeRunId2(now) {
7555
+ return `run-${now()}-${Math.random().toString(36).slice(2, 8)}`;
7556
+ }
7557
+ function getReconcileEditor2(params, yDoc, editor) {
7558
+ if (editor) return editor;
7559
+ if (!yDoc || !params.document) return void 0;
7560
+ return {
7561
+ _yDoc: yDoc,
7562
+ _yRuntime: yDoc.getMap("runtime"),
7563
+ document: params.document
7564
+ };
7565
+ }
7566
+ function persistEvents(params) {
7567
+ if (!params.yDoc || params.events.length === 0) return void 0;
7568
+ const runId = makeRunId2(params.now);
7569
+ const details = {
7570
+ runId,
7571
+ output: params.output,
7572
+ events: params.events,
7573
+ startedAt: new Date(params.startedAt).toISOString(),
7574
+ completedAt: new Date(params.completedAt).toISOString(),
7575
+ actorDid: params.actorDid,
7576
+ invocationCid: params.invocationCid,
7577
+ capabilityId: params.capabilityId
7578
+ };
7579
+ if (params.pendingInvocation) {
7580
+ details.fromPendingInvocationId = params.pendingInvocation.id;
7581
+ details.triggeredBy = {
7582
+ sourceBlockId: params.pendingInvocation.triggeringBlockId,
7583
+ eventName: params.pendingInvocation.eventName
7584
+ };
7585
+ details.sourceRunId = params.pendingInvocation.sourceRunId;
7586
+ }
7587
+ appendRunRecord(params.yDoc, params.blockId, details, params.actorDid);
7588
+ if (params.editor) {
7589
+ reconcilePendingInvocations(params.editor);
7590
+ }
7591
+ return runId;
7592
+ }
7593
+ function cleanupCompletedPendingInvocation(yDoc, blockId, pendingInvocation) {
7594
+ if (!yDoc || !pendingInvocation) return false;
7595
+ return removePendingInvocation(yDoc, blockId, pendingInvocation.id);
7596
+ }
7597
+ async function executeActionBlock(params) {
7598
+ const block = findBlock(params);
7599
+ const blockId = params.blockId || block?.id;
7600
+ const editor = getEditor2(params.editorOrYDoc);
7601
+ const yDoc = getYDoc2(params.editorOrYDoc);
7602
+ const runtime = getRuntime2(params.editorOrYDoc, params.runtime);
7603
+ const now = params.now || Date.now;
7604
+ if (!block || !blockId) {
7605
+ return buildFailureResult({
7606
+ blockId: blockId || "",
7607
+ stage: "input",
7608
+ error: blockId ? `Block "${blockId}" was not found` : "executeActionBlock requires a blockId or block"
7609
+ });
7610
+ }
7611
+ const actionType = typeof block.props?.actionType === "string" ? block.props.actionType : void 0;
7612
+ if (!actionType) {
7613
+ updateRuntimeFailure(runtime, blockId, "Action block is missing props.actionType", now);
7614
+ return buildFailureResult({
7615
+ blockId,
7616
+ stage: "input",
7617
+ error: "Action block is missing props.actionType"
7618
+ });
7619
+ }
7620
+ const action = getAction(actionType);
7621
+ if (!action) {
7622
+ const message = `No registered action found for ${actionType}`;
7623
+ updateRuntimeFailure(runtime, blockId, message, now);
7624
+ return buildFailureResult({ blockId, actionType, stage: "action_lookup", error: message });
7625
+ }
7626
+ let inputBuild;
7627
+ try {
7628
+ inputBuild = buildActionRunInputs({ ...params, block, blockId, runtime });
7629
+ } catch (error) {
7630
+ const message = error instanceof Error ? error.message : "Failed to build action inputs";
7631
+ updateRuntimeFailure(runtime, blockId, message, now);
7632
+ return buildFailureResult({ blockId, actionType, stage: "input", error: message });
7633
+ }
7634
+ const flowNode = buildFlowNodeFromBlock(block);
7635
+ const metadata = getFlowMetadata(editor);
7636
+ const flowId = params.flowId || metadata.flowId || blockId;
7637
+ const flowUri = params.flowUri || metadata.flowUri || `ixo:flow:${flowId}`;
7638
+ const flowOwnerDid = params.flowOwnerDid || metadata.flowOwnerDid;
7639
+ const schemaVersion = params.schemaVersion || metadata.schemaVersion;
7640
+ const events = [];
7641
+ let completionState = "completed";
7642
+ let readBack;
7643
+ let rawReadBack;
7644
+ let requestedAwaitingReadBack = false;
7645
+ const startedAt = now();
7646
+ runtime.update(blockId, {
7647
+ state: "running",
7648
+ output: void 0,
7649
+ error: void 0,
7650
+ executedByDid: params.actorDid
7651
+ });
7652
+ const outcome = await executeNode({
7653
+ node: flowNode,
7654
+ actorDid: params.actorDid,
7655
+ actorType: params.actorType,
7656
+ entityRoomId: params.entityRoomId,
7657
+ context: {
7658
+ runtime,
7659
+ ucanService: params.ucanService || editor?.getUcanService?.() || void 0,
7660
+ invocationStore: params.invocationStore || editor?._invocationStore,
7661
+ flowUri,
7662
+ flowId,
7663
+ flowOwnerDid,
7664
+ schemaVersion,
7665
+ now
7666
+ },
7667
+ action: async () => {
7668
+ const result = await action.run(inputBuild.inputs, {
7669
+ actorDid: params.actorDid,
7670
+ flowId,
7671
+ flowUri,
7672
+ nodeId: blockId,
7673
+ flowNode,
7674
+ runtime,
7675
+ services: params.services || {},
7676
+ handlers: params.handlers,
7677
+ editor,
7678
+ pendingInvocation: inputBuild.pendingInvocation
7679
+ });
7680
+ if (result.events?.length) events.push(...result.events);
7681
+ if (result.completion?.state === "awaiting_readback") {
7682
+ requestedAwaitingReadBack = true;
7683
+ rawReadBack = result.completion.readBack;
7684
+ }
7685
+ return {
7686
+ payload: result.output,
7687
+ submittedByDid: params.actorDid || void 0
7688
+ };
7689
+ },
7690
+ pin: params.pin || ""
7691
+ });
7692
+ if (!outcome.success) {
7693
+ const message = outcome.error || "Action execution failed";
7694
+ updateRuntimeFailure(runtime, blockId, message, now);
7695
+ return {
7696
+ ...buildFailureResult({
7697
+ blockId,
7698
+ actionType,
7699
+ stage: outcome.stage,
7700
+ error: message,
7701
+ pendingInvocation: inputBuild.pendingInvocation
7702
+ }),
7703
+ invocationCid: outcome.invocationCid,
7704
+ capabilityId: outcome.capabilityId
7705
+ };
7706
+ }
7707
+ const output = outcome.result?.payload || {};
7708
+ const completedAt = now();
7709
+ if (requestedAwaitingReadBack) {
7710
+ completionState = "awaiting_readback";
7711
+ readBack = normalizeActionReadBackMetadata({
7712
+ readBack: rawReadBack,
7713
+ blockId,
7714
+ actionType,
7715
+ actorDid: params.actorDid,
7716
+ invocationCid: outcome.invocationCid,
7717
+ capabilityId: outcome.capabilityId,
7718
+ requestedAt: startedAt,
7719
+ pendingInvocation: inputBuild.pendingInvocation
7720
+ });
7721
+ }
7722
+ runtime.update(blockId, {
7723
+ state: completionState,
7724
+ output,
7725
+ executedByDid: params.actorDid,
7726
+ executedAt: completedAt,
7727
+ lastInvocationCid: outcome.invocationCid || outcome.capabilityId,
7728
+ readBack
7729
+ });
7730
+ const runId = persistEvents({
7731
+ yDoc,
7732
+ editor: getReconcileEditor2(params, yDoc, editor),
7733
+ blockId,
7734
+ actorDid: params.actorDid,
7735
+ output,
7736
+ events,
7737
+ invocationCid: outcome.invocationCid,
7738
+ capabilityId: outcome.capabilityId,
7739
+ pendingInvocation: inputBuild.pendingInvocation,
7740
+ startedAt,
7741
+ completedAt,
7742
+ now
7743
+ });
7744
+ const pendingInvocationRemoved = completionState === "completed" ? cleanupCompletedPendingInvocation(yDoc, blockId, inputBuild.pendingInvocation) : false;
7745
+ return {
7746
+ success: true,
7747
+ stage: outcome.stage,
7748
+ blockId,
7749
+ actionType,
7750
+ output,
7751
+ events,
7752
+ invocationCid: outcome.invocationCid,
7753
+ capabilityId: outcome.capabilityId,
7754
+ runId,
7755
+ pendingInvocationRemoved,
7756
+ completionState,
7757
+ pendingInvocation: inputBuild.pendingInvocation
7758
+ };
7759
+ }
7760
+
6807
7761
  // src/core/lib/flowEngine/migration.ts
6808
7762
  var MIGRATION_REGISTRY = {};
6809
7763
  function registerMigration(definition) {
@@ -7251,13 +8205,13 @@ function detectTriggerCycles(triggerEdges) {
7251
8205
  }
7252
8206
 
7253
8207
  // src/core/lib/flowCompiler/readFlow.ts
7254
- import * as Y2 from "yjs";
8208
+ import * as Y4 from "yjs";
7255
8209
  function readCompiledFlowFromYDoc(yDoc) {
7256
8210
  const flowMeta = yDoc.getMap("qi.flow.meta");
7257
8211
  const flowNodes = yDoc.getMap("qi.flow.nodes");
7258
8212
  const nodes = {};
7259
8213
  flowNodes.forEach((value, nodeId) => {
7260
- if (value instanceof Y2.Map) {
8214
+ if (value instanceof Y4.Map) {
7261
8215
  nodes[nodeId] = yMapToFlowNode(value);
7262
8216
  }
7263
8217
  });
@@ -7277,7 +8231,7 @@ function readCompiledFlowFromYDoc(yDoc) {
7277
8231
  const flowEdges = yDoc.getMap("qi.flow.edges");
7278
8232
  const edges = [];
7279
8233
  flowEdges.forEach((value) => {
7280
- if (value instanceof Y2.Map) {
8234
+ if (value instanceof Y4.Map) {
7281
8235
  edges.push(yMapToEdge(value));
7282
8236
  }
7283
8237
  });
@@ -7458,11 +8412,11 @@ function nodeToCapability(node) {
7458
8412
  }
7459
8413
 
7460
8414
  // src/core/lib/flowCompiler/setup.ts
7461
- import * as Y5 from "yjs";
8415
+ import * as Y7 from "yjs";
7462
8416
  import { MatrixProvider } from "@ixo/matrix-crdt";
7463
8417
 
7464
8418
  // src/core/lib/flowCompiler/hydrate.ts
7465
- import * as Y3 from "yjs";
8419
+ import * as Y5 from "yjs";
7466
8420
  function hydrateYDocFromCompiledFlow(yDoc, compiled) {
7467
8421
  yDoc.transact(() => {
7468
8422
  const flowMeta = yDoc.getMap("qi.flow.meta");
@@ -7477,7 +8431,7 @@ function hydrateYDocFromCompiledFlow(yDoc, compiled) {
7477
8431
  }
7478
8432
  const flowEdges = yDoc.getMap("qi.flow.edges");
7479
8433
  for (const edge of compiled.edges) {
7480
- const yEdge = new Y3.Map();
8434
+ const yEdge = new Y5.Map();
7481
8435
  yEdge.set("id", edge.id);
7482
8436
  yEdge.set("source", edge.source);
7483
8437
  yEdge.set("target", edge.target);
@@ -7531,7 +8485,7 @@ function hydrateYDocFromMergeResult(yDoc, mergeResult) {
7531
8485
  const flowEdges = yDoc.getMap("qi.flow.edges");
7532
8486
  flowEdges.forEach((_, key) => flowEdges.delete(key));
7533
8487
  for (const edge of merged.edges) {
7534
- const yEdge = new Y3.Map();
8488
+ const yEdge = new Y5.Map();
7535
8489
  yEdge.set("id", edge.id);
7536
8490
  yEdge.set("source", edge.source);
7537
8491
  yEdge.set("target", edge.target);
@@ -7566,7 +8520,7 @@ function initializeRuntimeForNodes(runtimeMap, compiled, nodeIds) {
7566
8520
  }
7567
8521
  }
7568
8522
  function createYMapFromNode(node) {
7569
- const yNode = new Y3.Map();
8523
+ const yNode = new Y5.Map();
7570
8524
  yNode.set("id", node.id);
7571
8525
  yNode.set("blockId", node.blockId);
7572
8526
  yNode.set("can", node.can);
@@ -7581,7 +8535,7 @@ function createYMapFromNode(node) {
7581
8535
  }
7582
8536
 
7583
8537
  // src/core/lib/flowCompiler/documentFragment.ts
7584
- import * as Y4 from "yjs";
8538
+ import * as Y6 from "yjs";
7585
8539
  function writeCompiledBlocksToFragment(fragment, blocks) {
7586
8540
  const documentBlockGroup = getOrCreateDocumentBlockGroup(fragment);
7587
8541
  for (const block of blocks) {
@@ -7600,7 +8554,7 @@ function replaceBlockInFragment(fragment, block) {
7600
8554
  if (!blockGroup) return false;
7601
8555
  for (let i = 0; i < blockGroup.length; i++) {
7602
8556
  const container = blockGroup.get(i);
7603
- if (container instanceof Y4.XmlElement && container.getAttribute("id") === block.id) {
8557
+ if (container instanceof Y6.XmlElement && container.getAttribute("id") === block.id) {
7604
8558
  blockGroup.delete(i, 1);
7605
8559
  const newContainer = createBlockContainer(block);
7606
8560
  blockGroup.insert(i, [newContainer]);
@@ -7634,12 +8588,12 @@ function applyMergeResultToFragment(fragment, mergeResult) {
7634
8588
  }
7635
8589
  }
7636
8590
  function createBlockContainer(block) {
7637
- const blockContainer = new Y4.XmlElement("blockContainer");
8591
+ const blockContainer = new Y6.XmlElement("blockContainer");
7638
8592
  const { backgroundColor: rawBackgroundColor, textColor: rawTextColor, ...contentProps } = block.props;
7639
8593
  blockContainer.setAttribute("id", block.id);
7640
8594
  blockContainer.setAttribute("textColor", rawTextColor || "default");
7641
8595
  blockContainer.setAttribute("backgroundColor", rawBackgroundColor || "default");
7642
- const blockContent = new Y4.XmlElement(block.type);
8596
+ const blockContent = new Y6.XmlElement(block.type);
7643
8597
  for (const [key, value] of Object.entries(contentProps)) {
7644
8598
  if (value !== "") {
7645
8599
  blockContent.setAttribute(key, value);
@@ -7654,13 +8608,13 @@ function appendBlockToGroup(blockGroup, block) {
7654
8608
  }
7655
8609
  function getOrCreateDocumentBlockGroup(fragment) {
7656
8610
  if (fragment.length === 0) {
7657
- const blockGroup = new Y4.XmlElement("blockGroup");
8611
+ const blockGroup = new Y6.XmlElement("blockGroup");
7658
8612
  fragment.insert(0, [blockGroup]);
7659
8613
  return blockGroup;
7660
8614
  }
7661
8615
  if (fragment.length === 1) {
7662
8616
  const rootNode = fragment.get(0);
7663
- if (rootNode instanceof Y4.XmlElement && rootNode.nodeName === "blockGroup") {
8617
+ if (rootNode instanceof Y6.XmlElement && rootNode.nodeName === "blockGroup") {
7664
8618
  return rootNode;
7665
8619
  }
7666
8620
  }
@@ -7670,7 +8624,7 @@ function getExistingBlockGroup(fragment) {
7670
8624
  if (fragment.length === 0) return null;
7671
8625
  if (fragment.length === 1) {
7672
8626
  const rootNode = fragment.get(0);
7673
- if (rootNode instanceof Y4.XmlElement && rootNode.nodeName === "blockGroup") {
8627
+ if (rootNode instanceof Y6.XmlElement && rootNode.nodeName === "blockGroup") {
7674
8628
  return rootNode;
7675
8629
  }
7676
8630
  }
@@ -7773,7 +8727,7 @@ async function setupFlowFromBaseUcan(options) {
7773
8727
  };
7774
8728
  }
7775
8729
  async function connectToRoom(roomId, matrixClient) {
7776
- const yDoc = new Y5.Doc();
8730
+ const yDoc = new Y7.Doc();
7777
8731
  const client = matrixClient;
7778
8732
  client.canSupportVoip = false;
7779
8733
  client.clientOpts = { lazyLoadMembers: true };
@@ -7828,7 +8782,7 @@ function setRootMetadata(yDoc, root, plan, creatorDid, docId) {
7828
8782
  }
7829
8783
 
7830
8784
  // src/core/lib/flowAgent/store.ts
7831
- import * as Y6 from "yjs";
8785
+ import * as Y8 from "yjs";
7832
8786
 
7833
8787
  // src/core/lib/flowAgent/utils.ts
7834
8788
  function stableStringify(value) {
@@ -8009,7 +8963,7 @@ function appendAgentLedgerEvent(yDoc, event) {
8009
8963
  const auditMap = yDoc.getMap("auditTrail");
8010
8964
  let arr = auditMap.get(FLOW_AGENT_AUDIT_SCOPE);
8011
8965
  if (!arr) {
8012
- arr = new Y6.Array();
8966
+ arr = new Y8.Array();
8013
8967
  auditMap.set(FLOW_AGENT_AUDIT_SCOPE, arr);
8014
8968
  }
8015
8969
  const fullEvent = {
@@ -8273,12 +9227,88 @@ function snapshotNode(block, runtime, now, pendingInvocationCount = 0) {
8273
9227
  return snapshot;
8274
9228
  }
8275
9229
 
9230
+ // src/core/lib/flowAgent/actionExecutionPolicy.ts
9231
+ var RUNTIME_INPUT_REQUIRED_ACTIONS = /* @__PURE__ */ new Set(["qi/form.submit", "qi/human.form.submit", "qi/human.checkbox.set", "qi/protocol.select"]);
9232
+ function isRecord(value) {
9233
+ return value != null && typeof value === "object" && !Array.isArray(value);
9234
+ }
9235
+ function parseStringList(value) {
9236
+ const parsed = parseJsonProp(value, []);
9237
+ if (!Array.isArray(parsed)) return [];
9238
+ return parsed.filter((item) => typeof item === "string" && item.length > 0);
9239
+ }
9240
+ function normalizeMode(value) {
9241
+ if (value === "saved-input" || value === "saved_input" || value === "savedInput") return "saved-input";
9242
+ if (value === "runtime-input-required" || value === "runtime_input_required" || value === "runtimeInputRequired") return "runtime-input-required";
9243
+ if (value === "human-only" || value === "human_only" || value === "humanOnly") return "human-only";
9244
+ return void 0;
9245
+ }
9246
+ function parseExecutionConfig(value) {
9247
+ if (value == null || value === "") return {};
9248
+ if (typeof value === "string") {
9249
+ const directMode = normalizeMode(value);
9250
+ if (directMode) return { mode: directMode };
9251
+ }
9252
+ const parsed = parseJsonProp(value, {});
9253
+ if (!isRecord(parsed)) return {};
9254
+ return {
9255
+ mode: normalizeMode(parsed.mode),
9256
+ requiredRuntimeInputs: parseStringList(parsed.requiredRuntimeInputs)
9257
+ };
9258
+ }
9259
+ function inferDefaultMode(actionType, requiredRuntimeInputs) {
9260
+ if (requiredRuntimeInputs.length > 0) return "runtime-input-required";
9261
+ if (actionType && RUNTIME_INPUT_REQUIRED_ACTIONS.has(actionType)) return "runtime-input-required";
9262
+ return "saved-input";
9263
+ }
9264
+ function getFlowAgentActionExecutionPolicy(block) {
9265
+ const props = getBlockProps(block);
9266
+ const actionType = getBlockActionType(block);
9267
+ const config = parseExecutionConfig(props.flowAgentExecution || props.flowAgentExecutionMode || props.agentExecutionMode);
9268
+ const requiredRuntimeInputs = [
9269
+ ...config.requiredRuntimeInputs || [],
9270
+ ...parseStringList(props.requiredRuntimeInputs || props.runtimeRequiredInputs || props.flowAgentRequiredRuntimeInputs)
9271
+ ];
9272
+ return {
9273
+ mode: config.mode || inferDefaultMode(actionType, requiredRuntimeInputs),
9274
+ requiredRuntimeInputs: Array.from(new Set(requiredRuntimeInputs))
9275
+ };
9276
+ }
9277
+ function getCommandRuntimeInputs(payload) {
9278
+ return isRecord(payload.runtimeInputs) ? payload.runtimeInputs : void 0;
9279
+ }
9280
+ function validateFlowAgentExecuteActionPayload(block, payload) {
9281
+ const policy = getFlowAgentActionExecutionPolicy(block);
9282
+ if (policy.mode === "human-only") {
9283
+ return {
9284
+ valid: false,
9285
+ mode: policy.mode,
9286
+ missingRuntimeInputs: [],
9287
+ reason: "Action requires human execution and cannot be run by the Flow Agent"
9288
+ };
9289
+ }
9290
+ if (policy.mode !== "runtime-input-required") {
9291
+ return { valid: true, mode: policy.mode, missingRuntimeInputs: [] };
9292
+ }
9293
+ const runtimeInputs = getCommandRuntimeInputs(payload);
9294
+ const missingRuntimeInputs = policy.requiredRuntimeInputs.length > 0 ? policy.requiredRuntimeInputs.filter((key) => runtimeInputs?.[key] == null || runtimeInputs[key] === "") : runtimeInputs ? [] : ["runtimeInputs"];
9295
+ if (missingRuntimeInputs.length > 0) {
9296
+ return {
9297
+ valid: false,
9298
+ mode: policy.mode,
9299
+ missingRuntimeInputs,
9300
+ reason: policy.requiredRuntimeInputs.length > 0 ? `Missing required runtimeInputs: ${missingRuntimeInputs.join(", ")}` : "Action requires runtimeInputs before the Flow Agent can execute it"
9301
+ };
9302
+ }
9303
+ return { valid: true, mode: policy.mode, missingRuntimeInputs: [] };
9304
+ }
9305
+
8276
9306
  // src/core/lib/flowAgent/orchestrator.ts
8277
9307
  var BLOCKER_DIAGNOSIS_VERSION = 2;
8278
9308
  function getBlocks(context) {
8279
9309
  return context.blocks || context.editor?.document || [];
8280
9310
  }
8281
- function getRuntime(yDoc, nodeId) {
9311
+ function getRuntime3(yDoc, nodeId) {
8282
9312
  const runtime = yDoc.getMap("runtime");
8283
9313
  const value = runtime.get(nodeId);
8284
9314
  return value && typeof value === "object" ? value : {};
@@ -8373,6 +9403,11 @@ function queueIfAuthorized(context, options, type, nodeId, reason, payload) {
8373
9403
  }
8374
9404
  return queueAgentCommand(context.yDoc, command).created ? command : null;
8375
9405
  }
9406
+ function statusForResult(result) {
9407
+ if (result.status) return result.status;
9408
+ if (!result.success) return "failed";
9409
+ return result.confirmed === false ? "awaiting_readback" : "confirmed";
9410
+ }
8376
9411
  function planForSnapshot(context, options, block, snapshot) {
8377
9412
  const queued = [];
8378
9413
  const actionType = getBlockActionType(block);
@@ -8432,8 +9467,25 @@ function planForSnapshot(context, options, block, snapshot) {
8432
9467
  return queued;
8433
9468
  }
8434
9469
  if (actionType && canQueueCommand("execute_action", snapshot.nodeId, context, options)) {
9470
+ const pendingInvocation = readPendingInvocations(context.yDoc, snapshot.nodeId)[0];
9471
+ const payload = {
9472
+ actionType,
9473
+ ...pendingInvocation ? { pendingInvocationId: pendingInvocation.id } : {}
9474
+ };
9475
+ const actionValidation = validateFlowAgentExecuteActionPayload(block, payload);
9476
+ if (!actionValidation.valid) {
9477
+ const commandType = actionValidation.mode === "human-only" ? "notify_actor" : "diagnose_blocker";
9478
+ const command2 = queueIfAuthorized(context, options, commandType, snapshot.nodeId, actionValidation.reason || "Action node cannot be executed by Flow Agent yet", {
9479
+ cause: actionValidation.mode === "runtime-input-required" ? "missing_input" : "unknown",
9480
+ requiredActionType: actionType,
9481
+ requiredRuntimeInputs: actionValidation.missingRuntimeInputs,
9482
+ severity: actionValidation.mode === "human-only" ? "attention" : void 0
9483
+ });
9484
+ if (command2) queued.push(command2);
9485
+ return queued;
9486
+ }
8435
9487
  const command = queueIfAuthorized(context, options, "execute_action", snapshot.nodeId, "Action node is pending and executable", {
8436
- actionType
9488
+ ...payload
8437
9489
  });
8438
9490
  if (command) queued.push(command);
8439
9491
  return queued;
@@ -8455,7 +9507,7 @@ function planRalphLoopCommands(context, options = {}) {
8455
9507
  const nodeId = getBlockId(block);
8456
9508
  if (!nodeId) continue;
8457
9509
  const pendingInvocationCount = readPendingInvocations(context.yDoc, nodeId).length;
8458
- const snapshot = snapshotNode(block, getRuntime(context.yDoc, nodeId), now, pendingInvocationCount);
9510
+ const snapshot = snapshotNode(block, getRuntime3(context.yDoc, nodeId), now, pendingInvocationCount);
8459
9511
  snapshots.push(snapshot);
8460
9512
  queuedCommands.push(...planForSnapshot(context, options, block, snapshot));
8461
9513
  }
@@ -8538,7 +9590,7 @@ async function executeQueuedAgentCommands(context, options = {}) {
8538
9590
  continue;
8539
9591
  }
8540
9592
  updateAgentCommand(context.yDoc, command.id, {
8541
- status: result.success ? "confirmed" : "failed",
9593
+ status: statusForResult(result),
8542
9594
  error: result.error,
8543
9595
  updatedAt: context.now?.() || Date.now()
8544
9596
  });
@@ -8587,7 +9639,7 @@ function safeAppendAgentLedgerEvent2(yDoc, event) {
8587
9639
  throw error;
8588
9640
  }
8589
9641
  }
8590
- function createYDocRuntimeManager(yDoc) {
9642
+ function createYDocRuntimeManager2(yDoc) {
8591
9643
  const runtime = yDoc.getMap("runtime");
8592
9644
  return {
8593
9645
  get: (nodeId) => {
@@ -8618,19 +9670,16 @@ function clearRuntimeBlocker(yDoc, nodeId, updates) {
8618
9670
  });
8619
9671
  }
8620
9672
  function findContextBlock(context, nodeId) {
8621
- const block = (context.blocks || []).find((entry) => getBlockId(entry) === nodeId);
9673
+ const block = (context.blocks || context.editor?.document || []).find((entry) => getBlockId(entry) === nodeId);
8622
9674
  return block && typeof block === "object" ? block : null;
8623
9675
  }
8624
- function parseInputs2(value) {
8625
- return parseJsonProp(value, {});
8626
- }
8627
9676
  function getXmlAttribute(element, key) {
8628
9677
  return element.getAttribute(key);
8629
9678
  }
8630
9679
  function setXmlAttribute(element, key, value) {
8631
9680
  element.setAttribute(key, value);
8632
9681
  }
8633
- function isRecord(value) {
9682
+ function isRecord2(value) {
8634
9683
  return value != null && typeof value === "object" && !Array.isArray(value);
8635
9684
  }
8636
9685
  function isYXmlContainerLike(value) {
@@ -8643,13 +9692,13 @@ function getElementBlockId(element) {
8643
9692
  const directId = getXmlAttribute(element, "id");
8644
9693
  if (typeof directId === "string" && directId.length > 0) return directId;
8645
9694
  const attrs = getXmlAttribute(element, "attrs");
8646
- const attrsId = isRecord(attrs) ? attrs.id : void 0;
9695
+ const attrsId = isRecord2(attrs) ? attrs.id : void 0;
8647
9696
  return typeof attrsId === "string" && attrsId.length > 0 ? attrsId : void 0;
8648
9697
  }
8649
9698
  function updateXmlElementProps(element, blockId, propsPatch) {
8650
9699
  const attrs = getXmlAttribute(element, "attrs");
8651
- if (isRecord(attrs)) {
8652
- const existingProps = isRecord(attrs.props) ? attrs.props : {};
9700
+ if (isRecord2(attrs)) {
9701
+ const existingProps = isRecord2(attrs.props) ? attrs.props : {};
8653
9702
  setXmlAttribute(element, "attrs", {
8654
9703
  ...attrs,
8655
9704
  id: typeof attrs.id === "string" ? attrs.id : blockId,
@@ -8706,7 +9755,7 @@ function assignActorInYDoc(yDoc, command, context) {
8706
9755
  if (!updatedDocument) {
8707
9756
  throw new Error(`Block ${command.nodeId} was not found for assignment`);
8708
9757
  }
8709
- const runtime = createYDocRuntimeManager(yDoc);
9758
+ const runtime = createYDocRuntimeManager2(yDoc);
8710
9759
  runtime.update(command.nodeId, {
8711
9760
  assignedActorDid: targetActorDid,
8712
9761
  assignedByDid: context.actor.did,
@@ -8751,76 +9800,69 @@ async function executeActionCommand(command, context, options) {
8751
9800
  if (!actionType) {
8752
9801
  return { commandId: command.id, success: false, error: "execute_action command is missing payload.actionType" };
8753
9802
  }
8754
- const action = getAction(actionType);
8755
- if (!action) {
8756
- return { commandId: command.id, success: false, error: `No registered action found for ${actionType}` };
8757
- }
8758
9803
  const block = findContextBlock(context, command.nodeId);
8759
9804
  if (!block) {
8760
9805
  return { commandId: command.id, success: false, error: `Block ${command.nodeId} was not found in runtime context` };
8761
9806
  }
8762
9807
  const props = getBlockProps(block);
8763
- const inputs = parseInputs2(props.inputs);
8764
- const runtime = createYDocRuntimeManager(context.yDoc);
8765
- const flowNode = buildFlowNodeFromBlock(block);
8766
- const outcome = await executeNode({
8767
- node: flowNode,
9808
+ if (typeof props.actionType === "string" && props.actionType !== actionType) {
9809
+ return {
9810
+ commandId: command.id,
9811
+ success: false,
9812
+ error: `execute_action payload.actionType ${actionType} does not match block actionType ${props.actionType}`
9813
+ };
9814
+ }
9815
+ const runtimeInputs = command.payload.runtimeInputs;
9816
+ if (runtimeInputs != null && !isRecord2(runtimeInputs)) {
9817
+ return { commandId: command.id, success: false, error: "execute_action payload.runtimeInputs must be an object when provided" };
9818
+ }
9819
+ const inputValidation = validateFlowAgentExecuteActionPayload(block, command.payload);
9820
+ if (!inputValidation.valid) {
9821
+ return {
9822
+ commandId: command.id,
9823
+ success: false,
9824
+ confirmed: false,
9825
+ status: inputValidation.mode === "human-only" ? "skipped" : "failed",
9826
+ error: inputValidation.reason
9827
+ };
9828
+ }
9829
+ const pendingInvocationId = typeof command.payload.pendingInvocationId === "string" ? command.payload.pendingInvocationId : void 0;
9830
+ const outcome = await executeActionBlock({
9831
+ editorOrYDoc: context.editor || context.yDoc,
9832
+ block,
9833
+ blockId: command.nodeId,
9834
+ document: context.blocks || context.editor?.document || [],
8768
9835
  actorDid: context.actor.did,
8769
9836
  actorType: options.actorType,
8770
9837
  entityRoomId: options.entityRoomId,
8771
- context: {
8772
- runtime,
8773
- ucanService: options.ucanService,
8774
- invocationStore: options.invocationStore,
8775
- flowUri: context.flowUri,
8776
- flowId: context.flowId,
8777
- flowOwnerDid: "",
8778
- schemaVersion: options.schemaVersion || DEFAULT_SCHEMA_VERSION,
8779
- now: options.now || context.now
8780
- },
8781
- action: async () => {
8782
- const result = await action.run(inputs, {
8783
- actorDid: context.actor.did,
8784
- flowId: context.flowId,
8785
- flowUri: context.flowUri,
8786
- nodeId: command.nodeId,
8787
- flowNode,
8788
- runtime,
8789
- services: options.actionServices || {}
8790
- });
8791
- return { payload: result.output };
8792
- },
8793
- pin: options.pin
9838
+ ucanService: options.ucanService,
9839
+ invocationStore: options.invocationStore,
9840
+ services: options.actionServices || {},
9841
+ handlers: options.actionHandlers,
9842
+ runtimeInputs: getCommandRuntimeInputs(command.payload),
9843
+ pendingInvocationId,
9844
+ pin: options.pin,
9845
+ flowUri: context.flowUri,
9846
+ flowId: context.flowId,
9847
+ flowOwnerDid: options.flowOwnerDid || "",
9848
+ schemaVersion: options.schemaVersion || DEFAULT_SCHEMA_VERSION,
9849
+ now: options.now || context.now
8794
9850
  });
8795
- if (outcome.success && outcome.result) {
8796
- runtime.update(command.nodeId, {
8797
- state: "completed",
8798
- output: outcome.result.payload || {},
8799
- executedByDid: context.actor.did,
8800
- executedAt: options.now?.() || context.now?.() || Date.now(),
8801
- lastInvocationCid: outcome.invocationCid || outcome.capabilityId,
8802
- lastCommandId: command.id
8803
- });
8804
- } else if (!outcome.success) {
8805
- runtime.update(command.nodeId, {
8806
- state: "failed",
8807
- error: {
8808
- message: outcome.error || "Unknown execution error",
8809
- at: options.now?.() || context.now?.() || Date.now(),
8810
- commandId: command.id
8811
- },
8812
- lastCommandId: command.id
8813
- });
8814
- }
8815
9851
  return {
8816
9852
  commandId: command.id,
8817
9853
  success: outcome.success,
8818
- confirmed: outcome.success,
9854
+ confirmed: outcome.success && outcome.completionState === "completed",
8819
9855
  output: {
8820
- ...outcome.result?.payload && typeof outcome.result.payload === "object" ? outcome.result.payload : {},
8821
- ...outcome.invocationCid ? { invocationCid: outcome.invocationCid } : {}
9856
+ ...outcome.output && typeof outcome.output === "object" ? outcome.output : {},
9857
+ ...outcome.invocationCid ? { invocationCid: outcome.invocationCid } : {},
9858
+ ...outcome.capabilityId ? { capabilityId: outcome.capabilityId } : {},
9859
+ ...outcome.runId ? { runId: outcome.runId } : {},
9860
+ ...outcome.events.length > 0 ? { events: outcome.events } : {},
9861
+ ...pendingInvocationId ? { pendingInvocationId, pendingInvocationRemoved: outcome.pendingInvocationRemoved } : {},
9862
+ completionState: outcome.completionState
8822
9863
  },
8823
- error: outcome.error
9864
+ error: outcome.error,
9865
+ completionState: outcome.completionState
8824
9866
  };
8825
9867
  }
8826
9868
  function getRecoverableBlockerReason(runtime) {
@@ -8915,6 +9957,11 @@ async function callConfiguredExecutor(command, context, options) {
8915
9957
  return void 0;
8916
9958
  }
8917
9959
  }
9960
+ function statusForResult2(result) {
9961
+ if (result.status) return result.status;
9962
+ if (!result.success) return "failed";
9963
+ return result.confirmed === false ? "awaiting_readback" : "confirmed";
9964
+ }
8918
9965
  async function executeQueuedFlowAgentCoreCommands(context, options) {
8919
9966
  const now = options.now?.() || context.now?.() || Date.now();
8920
9967
  const { leases } = getFlowAgentMaps(context.yDoc);
@@ -8968,7 +10015,7 @@ async function executeQueuedFlowAgentCoreCommands(context, options) {
8968
10015
  continue;
8969
10016
  }
8970
10017
  updateAgentCommand(context.yDoc, command.id, {
8971
- status: normalized.success ? "confirmed" : "failed",
10018
+ status: statusForResult2(normalized),
8972
10019
  error: normalized.error,
8973
10020
  updatedAt: options.now?.() || context.now?.() || Date.now()
8974
10021
  });
@@ -9085,9 +10132,10 @@ export {
9085
10132
  buildFlowNodeFromBlock,
9086
10133
  createRuntimeStateManager,
9087
10134
  clearRuntimeForTemplateClone,
10135
+ isRuntimeRef,
10136
+ resolveRuntimeRefs,
9088
10137
  isAuthorized,
9089
10138
  executeNode,
9090
- isRuntimeRef,
9091
10139
  RUN_RECORD_AUDIT_TYPE,
9092
10140
  computePendingInvocationId,
9093
10141
  snapshotInputRefs,
@@ -9102,6 +10150,9 @@ export {
9102
10150
  replayFailedListenerRun,
9103
10151
  reconcilePendingInvocations,
9104
10152
  getActionForBlock,
10153
+ reconcileActionReadBack,
10154
+ buildActionRunInputs,
10155
+ executeActionBlock,
9105
10156
  writeRunRecordAndReconcile,
9106
10157
  compileBaseUcanFlow,
9107
10158
  readCompiledFlowFromYDoc,
@@ -9143,4 +10194,4 @@ export {
9143
10194
  executeQueuedFlowAgentCoreCommands,
9144
10195
  FlowAgentService
9145
10196
  };
9146
- //# sourceMappingURL=chunk-67477PYU.mjs.map
10197
+ //# sourceMappingURL=chunk-OK3ILV2C.mjs.map