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.
- package/package.json +5 -5
- 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.
|
|
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.
|
|
16
|
-
"instant-ctrl-flow-contract": "0.1.
|
|
17
|
-
"instant-ctrl-flow-logic": "0.1.
|
|
18
|
-
"work-ctrl-flow-contract": "0.1.
|
|
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 {
|
|
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(
|
|
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('/'));
|