work-ctrl-flow-logic 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +5 -5
  2. package/src/instance.ts +53 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "work-ctrl-flow-logic",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "description": "WorkCtrlFlow 引擎:可中断可恢复的动态工作流(快照重放 + WaitHandle/ResumeSignal)",
6
6
  "type": "module",
@@ -12,10 +12,10 @@
12
12
  },
13
13
  "dependencies": {
14
14
  "depa-behavior-tree": "0.1.0",
15
- "flow-step-space-logic": "0.1.0",
16
- "instant-ctrl-flow-contract": "0.1.1",
17
- "instant-ctrl-flow-logic": "0.1.3",
18
- "work-ctrl-flow-contract": "0.1.2"
15
+ "flow-step-space-logic": "0.1.1",
16
+ "instant-ctrl-flow-contract": "0.1.2",
17
+ "instant-ctrl-flow-logic": "0.1.4",
18
+ "work-ctrl-flow-contract": "0.1.3"
19
19
  },
20
20
  "files": [
21
21
  "src"
package/src/instance.ts CHANGED
@@ -8,7 +8,12 @@ import fs from 'node:fs';
8
8
  import path from 'node:path';
9
9
  import { createHash, randomUUID } from 'node:crypto';
10
10
  import { loadFlowBundle } from 'instant-ctrl-flow-logic/filesystem';
11
- import { assembleDefinitionStepProfileDirectory } from 'flow-step-space-logic/filesystem';
11
+ import { loadCtrlFlowProfileFromSources } from 'instant-ctrl-flow-logic';
12
+ import type { FlowNodeSpec } from 'instant-ctrl-flow-contract';
13
+ import {
14
+ assembleDefinitionStepProfileDirectory,
15
+ createFilesystemDefinitionStepProfileRuntime,
16
+ } from 'flow-step-space-logic/filesystem';
12
17
  import {
13
18
  FLOW_INSTANCE_SCHEMA_VERSION,
14
19
  type FlowDefinitionProvenance,
@@ -51,6 +56,48 @@ export interface MaterializedFlowInstance {
51
56
  readonly created: boolean;
52
57
  }
53
58
 
59
+ /** Definition-admission projection used by the checkpoint owner for Ctrl membership. */
60
+ export function loadFrozenCtrlDefinitionStepIds(
61
+ definitionDir: string,
62
+ profileKind: 'WorkCtrlFlow' | 'AICtrlWorkflow',
63
+ ): readonly string[] {
64
+ const runtime = createFilesystemDefinitionStepProfileRuntime({ rootDir: definitionDir });
65
+ const assembled = assembleDefinitionStepProfileDirectory(runtime, {}, { profileRoot: profileKind });
66
+ if (assembled.diagnostics.length > 0) {
67
+ throw new FlowInstanceMaterializationError(
68
+ 'instance-definition-invalid',
69
+ `frozen ${profileKind} StepSpace is invalid: ${assembled.diagnostics.map((item) => item.code).join(', ')}`,
70
+ );
71
+ }
72
+ const profileSpec = profileKind === 'AICtrlWorkflow'
73
+ ? loadCtrlFlowProfileFromSources(
74
+ Object.fromEntries((assembled.sources as readonly ({ readonly ref: string; readonly content: string } | { readonly name: string; readonly content: string })[])
75
+ .map((source) => ['name' in source ? source.name : source.ref, source.content])),
76
+ { profileRoot: 'AICtrlWorkflow', substrateForm: 'WorkCtrlFlow' },
77
+ ).spec
78
+ : undefined;
79
+ // The AICtrl runtime can also be bound to an already-canonical WorkCtrl
80
+ // definition. That frozen substrate binding remains the membership authority.
81
+ const spec = profileSpec ?? loadFlowBundle(definitionDir).spec;
82
+ if (!spec) {
83
+ throw new FlowInstanceMaterializationError('instance-definition-invalid', `frozen ${profileKind} binding is invalid`);
84
+ }
85
+ const ids: string[] = [];
86
+ const visit = (node: FlowNodeSpec): void => {
87
+ if (node.id) ids.push(node.id);
88
+ node.children.forEach(visit);
89
+ Object.values(node.sections).forEach(visit);
90
+ };
91
+ spec.statements.forEach(visit);
92
+ if (ids.length === 0 || new Set(ids).size !== ids.length) {
93
+ throw new FlowInstanceMaterializationError(
94
+ 'instance-definition-step-identities-invalid',
95
+ 'frozen Ctrl binding must expose unique executable step identities',
96
+ );
97
+ }
98
+ return Object.freeze(ids);
99
+ }
100
+
54
101
  export class FlowInstanceMaterializationError extends Error {
55
102
  constructor(public readonly code: string, message: string) {
56
103
  super(message);
@@ -688,7 +735,11 @@ export function annotateFlowFile(instanceDir: string, view: TreeViewAnnotation):
688
735
  fs.writeFileSync(tmp, text);
689
736
  fs.renameSync(tmp, file);
690
737
 
691
- const assembled = assembleDefinitionStepProfileDirectory(instanceDir, 'WorkCtrlFlow');
738
+ const assembled = assembleDefinitionStepProfileDirectory(
739
+ createFilesystemDefinitionStepProfileRuntime({ rootDir: instanceDir }),
740
+ {},
741
+ { profileRoot: 'WorkCtrlFlow' },
742
+ );
692
743
  if (!assembled.forest || assembled.diagnostics.length > 0) return;
693
744
  for (const stepId of assembled.forest.stepOrder) {
694
745
  const stepFile = path.join(instanceDir, ...assembled.forest.steps[stepId].sourceRef.split('/'));