@g1cloud/bpmn-modeler-next 5.0.0-alpha.1
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/README.md +140 -0
- package/dist/adapter/extensions.d.ts +8 -0
- package/dist/adapter/i18n.d.ts +9 -0
- package/dist/adapter/xml.d.ts +13 -0
- package/dist/agent/agentBatch.d.ts +57 -0
- package/dist/agent/describeProcess.d.ts +40 -0
- package/dist/agent/resolver/documentIndex.d.ts +15 -0
- package/dist/agent/resolver/index.d.ts +14 -0
- package/dist/agent/resolver/issues.d.ts +108 -0
- package/dist/agent/resolver/lower.d.ts +22 -0
- package/dist/agent/resolver/validate.d.ts +4 -0
- package/dist/agent/schema.d.ts +11 -0
- package/dist/agent/strictSubset.d.ts +32 -0
- package/dist/agent/symbolicOp.d.ts +103 -0
- package/dist/bpmn-modeler-next.css +1 -0
- package/dist/bpmn-modeler.js +1645 -0
- package/dist/bpmn-modeler.umd.cjs +1 -0
- package/dist/command/commandSeam.d.ts +13 -0
- package/dist/command/undoEpisode.d.ts +10 -0
- package/dist/core/hints.d.ts +82 -0
- package/dist/core/ir.d.ts +98 -0
- package/dist/core/modelerLike.d.ts +20 -0
- package/dist/editor/controller.d.ts +42 -0
- package/dist/headless/dom.d.ts +68 -0
- package/dist/headless/index.d.ts +2 -0
- package/dist/headless/modeler.d.ts +25 -0
- package/dist/index.d.ts +16 -0
- package/dist/view/BpmnModelerView.vue.d.ts +22 -0
- package/package.json +59 -0
package/README.md
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# @g1cloud/bpmn-modeler-next
|
|
2
|
+
|
|
3
|
+
> **BPMN 프로세스 문서 저작 에디터** Vue 3 라이브러리. 표준 BPMN 2.0 다이어그램을 시각적으로 저작하고, **AI 에이전트로 프로세스 문서를 생성·편집**하는 것을 목표로 한다.
|
|
4
|
+
|
|
5
|
+
- **패키지**: `@g1cloud/bpmn-modeler-next`
|
|
6
|
+
- **스택**: TypeScript · Vue 3 · Vite(library mode) · Vitest 4(browser mode) · 캔버스 = **bpmn-js 18 래핑**
|
|
7
|
+
- **상태**: `5.0.0-alpha.1` (활발한 개발 중)
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 개요
|
|
12
|
+
|
|
13
|
+
레거시 bluework 의 BPMN 저작 기능을 시블링(`entity-modeler-next` / `ui-modeler-next`)과 동일 위상 — **라이브러리 패키지 + `bluework4-tool` 호스트 임베드 + 에이전트 저작** — 으로 재구현한다.
|
|
14
|
+
|
|
15
|
+
두 종류의 소비자를 지원한다.
|
|
16
|
+
|
|
17
|
+
- **에디터 통합자** — Vue 앱(호스트)에 캔버스를 임베드. `createBpmnEditorController` + `BpmnModelerView` + op 전송층.
|
|
18
|
+
- **에이전트/서버** — 에디터 없이 문서를 읽고(`describeProcess`) 쓰는(`applyBpmnOpBatch`) 표면. read 는 순수 함수, write 는 헤드리스 modeler(`createHeadlessBpmnModeler`)로 서버에서 집행한다.
|
|
19
|
+
|
|
20
|
+
## 핵심 설계
|
|
21
|
+
|
|
22
|
+
- **진실은 표준 BPMN 2.0 XML 단일.** 영속 형태는 표준 XML 하나뿐이고, 에이전트 대면 IR 은 거기서 파생 생성되는 **뷰**다(IR·JSON 병행 저장 없음). 레거시가 이미 표준 XML 을 저장하므로 마이그레이션 비용이 0이다.
|
|
23
|
+
- **2단계 컴파일러.** 라이브러리에 LLM SDK 는 없다. 외부 LLM 이 심볼릭 op 를 생성하고, 결정론적 `resolver` 가 이를 bpmn-js `modeling` API 로 하강(lowering)한다.
|
|
24
|
+
- **AI 는 좌표를 직접 생성하지 않는다.** 신규 초안은 하이브리드 배치(프로세스 내부 자동 레이아웃 + 풀 골격·메시지플로우·주석 op), 부분 편집은 기존 배치를 보존한다.
|
|
25
|
+
- **힌트 = 선택적 장식.** 배치 힌트(주석 방위·그룹 멤버·풀 순서·밴드)는 표준 내 `extensionElements`(`bwl` 네임스페이스)에 싣는다. 소실되어도 휴리스틱으로 재생성 가능한 파생 정보이며, 어휘 진화는 additive-only 다.
|
|
26
|
+
- **문서 단위 낙관적 버전.** 동시성 단위는 문서 하나(`baseVersion` 스칼라). BPMN 은 단일 저작자·소규모 문서가 일반적이라 element 단위 CAS 는 두지 않는다 — 시블링의 파트 단위 CAS 와 의도적으로 다른 선택이다.
|
|
27
|
+
|
|
28
|
+
### 하강 경로 2종 (같은 의미론)
|
|
29
|
+
|
|
30
|
+
| 경로 | 주체 | 용도 |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| 캔버스 | `controller.applyAgentBatch` — 열린 에디터가 적용 | GUI 채팅. 배치 = **단일 undo 에피소드**(op 수십 개가 사용자 undo 1회로 되감김) + 턴 중 사용자 편집 잠금 |
|
|
33
|
+
| 헤드리스 | `createHeadlessBpmnModeler` + `applyBpmnOpBatch` — 호스트 서버가 집행 | CLI·배치 저작. Node + jsdom 에서 동작 |
|
|
34
|
+
|
|
35
|
+
두 경로는 같은 resolver·같은 배치 wire 를 타며, 구조 타입 `BpmnModelerLike` 가 그 공유를 타입으로 강제한다. 헤드리스 산출 DI 는 캔버스와 도형 바운즈 0 오차·외부 라벨 ±2px 로 등가가 고정되어 있다(회귀 게이트 2종).
|
|
36
|
+
|
|
37
|
+
## 설치
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pnpm add @g1cloud/bpmn-modeler-next
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
peer dependency:
|
|
44
|
+
|
|
45
|
+
```jsonc
|
|
46
|
+
{
|
|
47
|
+
"vue": "^3.5.0"
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
bpmn-js·diagram-js·bpmn-moddle 계열은 이 패키지의 dependencies 로 함께 설치된다.
|
|
52
|
+
|
|
53
|
+
스타일시트를 함께 임포트한다(bpmn-js 캔버스 자산이 흡수되어 있어 **없으면 다이어그램이 렌더되지 않는다**).
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import '@g1cloud/bpmn-modeler-next/style.css'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## 빠른 시작 — 에디터 임베드
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<template>
|
|
63
|
+
<BpmnModelerView ref="view" :xml="initialXml" @ready="onReady" />
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<script setup lang="ts">
|
|
67
|
+
import { provide, ref } from 'vue'
|
|
68
|
+
import { BpmnModelerView, createBpmnEditorController, EDITOR } from '@g1cloud/bpmn-modeler-next'
|
|
69
|
+
|
|
70
|
+
const view = ref<InstanceType<typeof BpmnModelerView>>()
|
|
71
|
+
const controller = createBpmnEditorController()
|
|
72
|
+
|
|
73
|
+
// 뷰 컴포넌트·패널이 inject 로 소비
|
|
74
|
+
provide(EDITOR, controller)
|
|
75
|
+
|
|
76
|
+
// 캔버스가 마운트되면 modeler 를 컨트롤러에 붙인다(컨트롤러는 bpmn-js 생성을 소유하지 않는다)
|
|
77
|
+
function onReady() {
|
|
78
|
+
controller.attach(view.value!.getModeler()!)
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
컨트롤러는 `importXml`/`saveXml`/`dirty` 와 에이전트 턴 통합(`applyAgentBatch`·`setEditable`·`agentBusy`)을 제공한다. 뷰는 `imported`(경고 목록)·`import-error` 도 emit 한다.
|
|
84
|
+
|
|
85
|
+
## 에이전트 / 서버 표면
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
import {
|
|
89
|
+
describeProcess, // moddle definitions → IrDefinition + hints + omitted (파생 뷰)
|
|
90
|
+
describeProcessXml, // XML 입력 래퍼 — 순수, 서버 실행 가능
|
|
91
|
+
buildBpmnOpBatch, // SymbolicOp[] → BpmnOpBatch (baseVersion·origin·멱등 키)
|
|
92
|
+
applyBpmnOps, // op 배치 하강 (사전 전수 검증 + 실패 시 단일 undo 되감기)
|
|
93
|
+
applyBpmnOpBatch, // CAS 포함 배치 적용 → ApplyBatchOutcome
|
|
94
|
+
createHeadlessBpmnModeler, // 에디터 없는 하강용 modeler (Node + jsdom)
|
|
95
|
+
APPLY_BPMN_OPS_SCHEMA, // applyOps 도구 input_schema (op 어휘의 JSON Schema 단일 출처)
|
|
96
|
+
SYMBOLIC_OP_KINDS, // op 종류 17
|
|
97
|
+
MVP_FLOW_NODE_TYPES, // MVP 노드 타입 9
|
|
98
|
+
BWL_SIDES, // 주석 방위 8
|
|
99
|
+
} from '@g1cloud/bpmn-modeler-next'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
- **실패는 throw 하지 않는다.** `ApplyBatchOutcome` 은 `applied` / `conflict` / `rejected` 세 상태이고, 거부는 `issues` 로 교정 지점을 지시한다(LLM 교정 루프 전제).
|
|
103
|
+
- **원자성**: 한 배치 = 한 원자 단위. `rejected` 면 문서는 무변경이다.
|
|
104
|
+
- **카탈로그는 별도 함수가 아니라 정적 스키마 + 어휘 상수다** — BPMN 어휘가 닫힌 집합이라 시블링의 런타임 catalog 필터가 불필요하다. 공개 표면은 `src/index.test.ts` 가 계약으로 고정한다.
|
|
105
|
+
|
|
106
|
+
헤드리스 하강은 jsdom 전역을 세운 뒤 호출한다. 라벨 정밀도가 더 필요하면 `canvas` 패키지를 설치하고 `dom: { textMeasurement: 'native' }` 로 전환한다.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
const modeler = createHeadlessBpmnModeler()
|
|
110
|
+
await modeler.importXML(xml)
|
|
111
|
+
const outcome = await applyBpmnOpBatch(modeler, batch, { currentVersion })
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 공개 API 표면
|
|
115
|
+
|
|
116
|
+
| 영역 | 주요 export |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `core` | `IrDefinition`·`IrNode`·`IrSequenceFlow` 등 IR 어휘 · `BWL_NS`/`BWL_PREFIX`/`BWL_MODDLE_SCHEMA` 힌트 네임스페이스 · `BpmnModelerLike` |
|
|
119
|
+
| `command` | `commandSeam`(do/undo 계약) · `executeAsUndoEpisode`(배치를 undo 1회 단위로 묶는 합성 커맨드) |
|
|
120
|
+
| `agent` | `SymbolicOp` 어휘 · `applyBpmnOps`·`validateOps`·`lowerOps` · `describeProcess` · `APPLY_BPMN_OPS_SCHEMA` · `buildBpmnOpBatch`/`applyBpmnOpBatch` |
|
|
121
|
+
| `editor` | `createBpmnEditorController` · `EDITOR` inject key |
|
|
122
|
+
| `view` | `BpmnModelerView` |
|
|
123
|
+
| `headless` | `createHeadlessBpmnModeler` · `installHeadlessBpmnDom` · `HEADLESS_BPMN_MODULES` · `HEADLESS_TEXT_METRICS` |
|
|
124
|
+
| `adapter` | `loadBpmnXml`/`saveBpmnXml` · `createBpmnModdle` · `BPMN_MODDLE_EXTENSIONS`(i18n·bwl 스키마 등록) |
|
|
125
|
+
|
|
126
|
+
## 개발
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm dev # 데모 하네스 (src/dev)
|
|
130
|
+
pnpm test # Vitest — unit(jsdom) + browser(chromium) 2계층
|
|
131
|
+
pnpm typecheck # vue-tsc --noEmit
|
|
132
|
+
pnpm build # 라이브러리 빌드 → dist/
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
- Node `>= 24.10.0`
|
|
136
|
+
- 테스트는 2계층이다. 순수 로직은 jsdom, **bpmn-js 하강 검증(`*.browser.test.ts`)은 실브라우저(chromium)** 에서 돈다 — 하강이 실 DOM 의미에 의존하므로 시블링의 Vitest 2.x 단일 환경과 의도적으로 diverge 했다.
|
|
137
|
+
|
|
138
|
+
## 라이선스
|
|
139
|
+
|
|
140
|
+
`LicenseRef-LICENSE` — 사내 라이선스(패키지 `license` 필드 기준).
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* moddle 확장 등록 맵 (M1-1) — 헤드리스 경로(adapter/xml)와 캔버스 경로(view 의
|
|
3
|
+
* bpmn-js `moddleExtensions` 옵션)가 반드시 같은 맵을 공유한다. 두 경로의 파싱 의미가
|
|
4
|
+
* 갈라지면 왕복 보존 테스트가 실운영 경로를 대변하지 못하게 된다.
|
|
5
|
+
*
|
|
6
|
+
* bwl 힌트 스키마(C-1, 세션 ②-b 등록) — 어휘 진화는 additive-only(불변식 5).
|
|
7
|
+
*/
|
|
8
|
+
export declare const BPMN_MODDLE_EXTENSIONS: Record<string, object>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 레거시 bpmn-i18n-moddle 호환 (백로그 B-4).
|
|
3
|
+
*
|
|
4
|
+
* 스키마 자체는 유지한다 — 기존 운영 문서(실측 112곳 확장)와의 호환 필수.
|
|
5
|
+
* 재설계 대상은 스키마가 아니라 적용 방식: 레거시 bpmnTranslationService 의
|
|
6
|
+
* commandStack 우회 변조를 표시용/저장용 라벨 분리로 대체한다.
|
|
7
|
+
*/
|
|
8
|
+
export declare const I18N_NS = "http://www.omg.org/spec/BPMN/non-normative/extensions/i18n/1.0";
|
|
9
|
+
export declare const I18N_PREFIX = "i18n";
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { BpmnModdle, ModdleElement, ParseWarning } from 'bpmn-moddle';
|
|
2
|
+
export type { ModdleElement, ParseWarning };
|
|
3
|
+
export declare function createBpmnModdle(): BpmnModdle;
|
|
4
|
+
export interface LoadBpmnXmlResult {
|
|
5
|
+
/** bpmn:Definitions 루트. */
|
|
6
|
+
definitions: ModdleElement;
|
|
7
|
+
/** 파싱 경고 — 수용 기준상 실운영 문서는 빈 배열이어야 한다. */
|
|
8
|
+
warnings: ParseWarning[];
|
|
9
|
+
}
|
|
10
|
+
export declare function loadBpmnXml(xml: string): Promise<LoadBpmnXmlResult>;
|
|
11
|
+
export declare function saveBpmnXml(definitions: ModdleElement): Promise<string>;
|
|
12
|
+
/** moddle/bpmn-js 파싱 경고를 표시용 메시지로 정규화 — 두 경로의 경고 형태가 동일(`{ message }`). */
|
|
13
|
+
export declare function warningMessages(warnings: ReadonlyArray<unknown>): string[];
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { BpmnDocumentModelerLike } from '../core/modelerLike';
|
|
2
|
+
import { SymbolicOp } from './symbolicOp';
|
|
3
|
+
import { ResolveIssue } from './resolver';
|
|
4
|
+
/** op 출처 — 감사·정책 분기용. `gui` = 호스트 채팅 패널, `rest` = 외부 브리지. */
|
|
5
|
+
export type BpmnOpOrigin = 'agent' | 'gui' | 'rest';
|
|
6
|
+
export interface BpmnOpBatch {
|
|
7
|
+
/** 호스트 문서 식별자(BPMN 문서 id 가 아니라 영속 레코드 id). */
|
|
8
|
+
documentId: string;
|
|
9
|
+
/** 이 배치가 전제한 문서 버전 — 적용 시점 버전과 다르면 충돌(C-3). */
|
|
10
|
+
baseVersion: number;
|
|
11
|
+
/** 한 원자 단위. 순서가 의미를 가진다(resolver 가 정규 순서로 재배열해 하강). */
|
|
12
|
+
ops: SymbolicOp[];
|
|
13
|
+
origin: BpmnOpOrigin;
|
|
14
|
+
/** 멱등 키 — 재시도 시 중복 적용 차단. 중복 판정(적용 이력 보관)은 영속 소유자 = 호스트 몫. */
|
|
15
|
+
clientOpId: string;
|
|
16
|
+
}
|
|
17
|
+
export interface BuildBpmnOpBatchOptions {
|
|
18
|
+
/** 기본 `agent`. */
|
|
19
|
+
origin?: BpmnOpOrigin;
|
|
20
|
+
/** 멱등 키 발급기 — 주입 시 테스트 결정성. 기본 `crypto.randomUUID()`. */
|
|
21
|
+
mkClientOpId?: () => string;
|
|
22
|
+
}
|
|
23
|
+
/** 배치 조립 — 순수 함수(검증은 resolver 몫이라 여기서 op 를 판정하지 않는다). */
|
|
24
|
+
export declare function buildBpmnOpBatch(documentId: string, baseVersion: number, ops: readonly SymbolicOp[], options?: BuildBpmnOpBatchOptions): BpmnOpBatch;
|
|
25
|
+
/**
|
|
26
|
+
* 배치 적용 결과. 실패를 throw 하지 않는 이유는 resolver `issues` 와 같다 — 에이전트 교정
|
|
27
|
+
* 루프가 구조화된 실패를 읽어야 한다. 세 상태는 각각 다른 후속 행동을 지시한다:
|
|
28
|
+
* - `applied` → 호스트가 `xml` 을 `version` 으로 영속
|
|
29
|
+
* - `conflict` → 에이전트가 read 부터 다시(재-ground 후 재생성). op 재전송은 무의미
|
|
30
|
+
* - `rejected` → 어휘·참조 문제라 op 를 고쳐 재전송
|
|
31
|
+
*/
|
|
32
|
+
export type ApplyBatchOutcome = {
|
|
33
|
+
status: 'applied';
|
|
34
|
+
version: number;
|
|
35
|
+
xml: string;
|
|
36
|
+
} | {
|
|
37
|
+
status: 'conflict';
|
|
38
|
+
baseVersion: number;
|
|
39
|
+
currentVersion: number;
|
|
40
|
+
} | {
|
|
41
|
+
status: 'rejected';
|
|
42
|
+
issues: ResolveIssue[];
|
|
43
|
+
};
|
|
44
|
+
export interface ApplyBpmnOpBatchOptions {
|
|
45
|
+
/** 적용 시점의 권위 버전 — 호스트(영속 소유자)가 공급한다. */
|
|
46
|
+
currentVersion: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 배치를 캔버스에 적용하고 영속 페이로드를 낸다.
|
|
50
|
+
*
|
|
51
|
+
* CAS 비교를 라이브러리에 둔 이유: 클라이언트 권위 배치에서도 같은 비교가 필요하므로 구현이
|
|
52
|
+
* 둘로 갈라지면 안 된다. 권위 버전 자체는 항상 호스트가 주입한다(라이브러리는 버전을 모른다).
|
|
53
|
+
*
|
|
54
|
+
* 적용은 단일 undo 에피소드다(`applyBpmnOps` → `command/undoEpisode`) — 배치 수십 op 가
|
|
55
|
+
* 사용자 undo 1회로 되감긴다.
|
|
56
|
+
*/
|
|
57
|
+
export declare function applyBpmnOpBatch(modeler: BpmnDocumentModelerLike, batch: BpmnOpBatch, { currentVersion }: ApplyBpmnOpBatchOptions): Promise<ApplyBatchOutcome>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { ModdleElement, ParseWarning } from '../adapter/xml';
|
|
2
|
+
import { BwlBand, BwlPlacement, BwlPoolOrder } from '../core/hints';
|
|
3
|
+
import { IrDefinition } from '../core/ir';
|
|
4
|
+
/** 파생 뷰가 표현하지 못한 요소 — 침묵 폐기 금지(에이전트가 미표현 존재를 알아야 안전). */
|
|
5
|
+
export interface IrOmission {
|
|
6
|
+
id: string;
|
|
7
|
+
/** bpmn $type 원형 (예: `bpmn:BoundaryEvent`) */
|
|
8
|
+
type: string;
|
|
9
|
+
reason:
|
|
10
|
+
/** MVP 타입 집합 밖 (boundaryEvent·subProcess·dataObject 등 — 승격 시 자동 해소) */
|
|
11
|
+
'type-outside-mvp'
|
|
12
|
+
/** 끝점이 미표현 요소라 연결 자체를 표현할 수 없음 */
|
|
13
|
+
| 'endpoint-outside-mvp'
|
|
14
|
+
/** 협업 문서인데 어느 participant 도 참조하지 않는 프로세스 (풀 귀속 불명) */
|
|
15
|
+
| 'unreachable-process';
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* bwl 힌트 판독 결과 — IR 밖 채널(위 헤더 "힌트 반환 채널"). 키 = 소유 요소 id.
|
|
19
|
+
* 그룹 멤버(`bwl:members`)는 IR `IrGroup.members` 로 간다.
|
|
20
|
+
*/
|
|
21
|
+
export interface BwlHintView {
|
|
22
|
+
/** participant id → 풀 세로 순서 */
|
|
23
|
+
poolOrders: Record<string, BwlPoolOrder>;
|
|
24
|
+
/** 플로우 노드 id → 프로세스 내부 가로 밴드 */
|
|
25
|
+
bands: Record<string, BwlBand>;
|
|
26
|
+
/** 주석 id → 앵커 기준 방위 (앵커 부재분은 필터됨) */
|
|
27
|
+
placements: Record<string, BwlPlacement>;
|
|
28
|
+
}
|
|
29
|
+
export interface DescribeProcessResult {
|
|
30
|
+
definition: IrDefinition;
|
|
31
|
+
hints: BwlHintView;
|
|
32
|
+
omitted: IrOmission[];
|
|
33
|
+
}
|
|
34
|
+
export interface DescribeProcessXmlResult extends DescribeProcessResult {
|
|
35
|
+
/** 입력 XML 파싱 경고 — 실운영 문서는 빈 배열이어야 한다(M1 수용 기준 1). */
|
|
36
|
+
warnings: ParseWarning[];
|
|
37
|
+
}
|
|
38
|
+
export declare function describeProcess(definitions: ModdleElement): DescribeProcessResult;
|
|
39
|
+
/** XML 문자열 입력 래퍼 — 헤드리스 read 경로(호스트 `describeProcess` API·테스트). */
|
|
40
|
+
export declare function describeProcessXml(xml: string): Promise<DescribeProcessXmlResult>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { default as ElementRegistry } from 'diagram-js/lib/core/ElementRegistry';
|
|
2
|
+
/** 검증이 구분하는 요소 카테고리 — bpmn $type 을 참조 적합성 판단 단위로 접는다. */
|
|
3
|
+
export type ElementCategory = 'participant' | 'lane' | 'flowNode' | 'sequenceFlow' | 'messageFlow' | 'dataStore' | 'dataAssociation' | 'annotation' | 'association' | 'group' | 'other';
|
|
4
|
+
export interface DocumentIndex {
|
|
5
|
+
/** 협업 문서(참여자 존재) 여부 — node.add 의 participant 필수 판단 */
|
|
6
|
+
isCollaboration(): boolean;
|
|
7
|
+
/** id 의 카테고리. undefined = 문서에 없음 */
|
|
8
|
+
categoryOf(id: string): ElementCategory | undefined;
|
|
9
|
+
/** 참여자에 속한 레인 id 목록 — **y순(위→아래)** 계약. lanes 재선언 diff 의 순서 비교 기준 */
|
|
10
|
+
lanesOf(participantId: string): readonly string[];
|
|
11
|
+
/** 플로우 노드가 속한 참여자 id (풀 없는 단일 프로세스 문서면 undefined) */
|
|
12
|
+
participantOf(nodeId: string): string | undefined;
|
|
13
|
+
}
|
|
14
|
+
/** elementRegistry 어댑터 — 하강 직전 실문서 상태를 대변한다. */
|
|
15
|
+
export declare function buildRegistryIndex(registry: ElementRegistry): DocumentIndex;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BpmnModelerLike } from '../../core/modelerLike';
|
|
2
|
+
import { SymbolicOp } from '../symbolicOp';
|
|
3
|
+
import { ResolveIssue } from './issues';
|
|
4
|
+
import { lowerOps } from './lower';
|
|
5
|
+
export type { ResolveIssue } from './issues';
|
|
6
|
+
export type { DocumentIndex, ElementCategory } from './documentIndex';
|
|
7
|
+
export { buildRegistryIndex } from './documentIndex';
|
|
8
|
+
export { validateOps } from './validate';
|
|
9
|
+
export { lowerOps, resolverServicesOf, type ResolverServices } from './lower';
|
|
10
|
+
export interface ApplyBpmnOpsResult {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
issues: ResolveIssue[];
|
|
13
|
+
}
|
|
14
|
+
export declare function applyBpmnOps(modeler: BpmnModelerLike, ops: readonly SymbolicOp[], lower?: typeof lowerOps): ApplyBpmnOpsResult;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* resolver 이슈 리포팅 (M2-2) — 실패는 throw 가 아니라 issue 목록으로 모아 반환한다.
|
|
3
|
+
* 시블링 ui-modeler resolver 의 `ResolveIssue`(kind 슬러그 union) 선례 동형 — LLM 이
|
|
4
|
+
* issue 를 읽고 op 를 교정해 재시도하는 루프를 전제한다.
|
|
5
|
+
*
|
|
6
|
+
* `opIndex` 는 배치 내 위치(0-기준) — 어느 op 가 문제인지 LLM 에게 되짚어 준다.
|
|
7
|
+
*/
|
|
8
|
+
export type ResolveIssue =
|
|
9
|
+
/** 신규 id 가 XML NCName 규칙 위반 (선두 숫자·콜론·공백 등) */
|
|
10
|
+
{
|
|
11
|
+
kind: 'id-invalid';
|
|
12
|
+
opIndex: number;
|
|
13
|
+
id: string;
|
|
14
|
+
}
|
|
15
|
+
/** 신규 id 가 문서 또는 배치 내 기존 id 와 충돌 */
|
|
16
|
+
| {
|
|
17
|
+
kind: 'id-duplicate';
|
|
18
|
+
opIndex: number;
|
|
19
|
+
id: string;
|
|
20
|
+
}
|
|
21
|
+
/** 참조 대상이 문서에도 배치에도 없음. `role` = 참조 위치(source/target/anchor/member/…) */
|
|
22
|
+
| {
|
|
23
|
+
kind: 'ref-missing';
|
|
24
|
+
opIndex: number;
|
|
25
|
+
ref: string;
|
|
26
|
+
role: string;
|
|
27
|
+
}
|
|
28
|
+
/** 참조 대상은 있으나 카테고리가 부적합 (예: sequenceFlow 끝점이 참여자) */
|
|
29
|
+
| {
|
|
30
|
+
kind: 'ref-category';
|
|
31
|
+
opIndex: number;
|
|
32
|
+
ref: string;
|
|
33
|
+
role: string;
|
|
34
|
+
expected: string;
|
|
35
|
+
actual: string;
|
|
36
|
+
}
|
|
37
|
+
/** node 의 lane 이 해당 참여자의 레인 목록에 없음 */
|
|
38
|
+
| {
|
|
39
|
+
kind: 'lane-unknown';
|
|
40
|
+
opIndex: number;
|
|
41
|
+
lane: string;
|
|
42
|
+
participant: string;
|
|
43
|
+
}
|
|
44
|
+
/** 협업 문서에서 node.add 가 participant 를 생략함 */
|
|
45
|
+
| {
|
|
46
|
+
kind: 'participant-required';
|
|
47
|
+
opIndex: number;
|
|
48
|
+
id: string;
|
|
49
|
+
}
|
|
50
|
+
/** sequenceFlow 끝점이 서로 다른 풀 (풀 간 연결은 messageFlow) */
|
|
51
|
+
| {
|
|
52
|
+
kind: 'flow-cross-pool';
|
|
53
|
+
opIndex: number;
|
|
54
|
+
id: string;
|
|
55
|
+
}
|
|
56
|
+
/** messageFlow 끝점이 같은 풀 (풀 내 연결은 sequenceFlow) */
|
|
57
|
+
| {
|
|
58
|
+
kind: 'message-flow-same-pool';
|
|
59
|
+
opIndex: number;
|
|
60
|
+
id: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* sequenceFlow 에 name 과 condition.label 동시 지정 — 실운영 문서에서 조건 라벨의
|
|
64
|
+
* 유일 채널이 name 이라(conditionExpression 0건 실측) 둘을 함께 주면 모호하다.
|
|
65
|
+
*/
|
|
66
|
+
| {
|
|
67
|
+
kind: 'condition-name-conflict';
|
|
68
|
+
opIndex: number;
|
|
69
|
+
id: string;
|
|
70
|
+
}
|
|
71
|
+
/** dataAssociation 양끝이 (노드, 데이터 스토어) 짝이 아님 */
|
|
72
|
+
| {
|
|
73
|
+
kind: 'data-association-ends';
|
|
74
|
+
opIndex: number;
|
|
75
|
+
source: string;
|
|
76
|
+
target: string;
|
|
77
|
+
}
|
|
78
|
+
/** association 의 어느 끝도 해당 주석이 아님 */
|
|
79
|
+
| {
|
|
80
|
+
kind: 'association-detached';
|
|
81
|
+
opIndex: number;
|
|
82
|
+
annotation: string;
|
|
83
|
+
}
|
|
84
|
+
/** update/remove 의 대상이 같은 배치의 add — 배치는 원자 단위라 자기 산출물 수정은 무의미(add 페이로드로 표현하라) */
|
|
85
|
+
| {
|
|
86
|
+
kind: 'target-added-in-batch';
|
|
87
|
+
opIndex: number;
|
|
88
|
+
id: string;
|
|
89
|
+
}
|
|
90
|
+
/** lanes 재선언이 기존 레인을 누락 — 레인 축소는 미실증 축(B-0)이라 거부 (세션 ②-b 판단) */
|
|
91
|
+
| {
|
|
92
|
+
kind: 'lane-shrink-unsupported';
|
|
93
|
+
opIndex: number;
|
|
94
|
+
participant: string;
|
|
95
|
+
lane: string;
|
|
96
|
+
}
|
|
97
|
+
/** lanes 재선언이 기존 레인의 상대 순서를 바꿈 — 순서 변경 하강 미실증, 거부 */
|
|
98
|
+
| {
|
|
99
|
+
kind: 'lane-reorder-unsupported';
|
|
100
|
+
opIndex: number;
|
|
101
|
+
participant: string;
|
|
102
|
+
}
|
|
103
|
+
/** 하강 실행 중 실패 — 실행분은 롤백됨(원자성 2차 방어) */
|
|
104
|
+
| {
|
|
105
|
+
kind: 'lower-failed';
|
|
106
|
+
opIndex?: number;
|
|
107
|
+
message: string;
|
|
108
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { BpmnModelerLike } from '../../core/modelerLike';
|
|
2
|
+
import { default as Modeling } from 'bpmn-js/lib/features/modeling/Modeling';
|
|
3
|
+
import { default as BpmnFactory } from 'bpmn-js/lib/features/modeling/BpmnFactory';
|
|
4
|
+
import { default as ElementFactory } from 'bpmn-js/lib/features/modeling/ElementFactory';
|
|
5
|
+
import { default as ElementRegistry } from 'diagram-js/lib/core/ElementRegistry';
|
|
6
|
+
import { default as Canvas } from 'diagram-js/lib/core/Canvas';
|
|
7
|
+
import { default as AutoPlace } from 'diagram-js/lib/features/auto-place/AutoPlace';
|
|
8
|
+
import { default as BpmnReplace } from 'bpmn-js/lib/features/replace/BpmnReplace';
|
|
9
|
+
import { SymbolicOp } from '../symbolicOp';
|
|
10
|
+
/** resolver 가 대면하는 bpmn-js 서비스 표면 — 하강은 이 묶음만 사용한다. */
|
|
11
|
+
export interface ResolverServices {
|
|
12
|
+
modeling: Modeling;
|
|
13
|
+
bpmnFactory: BpmnFactory;
|
|
14
|
+
elementFactory: ElementFactory;
|
|
15
|
+
elementRegistry: ElementRegistry;
|
|
16
|
+
canvas: Canvas;
|
|
17
|
+
autoPlace: AutoPlace;
|
|
18
|
+
bpmnReplace: BpmnReplace;
|
|
19
|
+
}
|
|
20
|
+
export declare function resolverServicesOf(modeler: BpmnModelerLike): ResolverServices;
|
|
21
|
+
/** 검증 통과가 전제 — 참조 해소 실패는 여기서 프로그래밍 오류로 throw 되고 applyBpmnOps 가 롤백한다. */
|
|
22
|
+
export declare function lowerOps(ops: readonly SymbolicOp[], services: ResolverServices): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type JsonSchema = Record<string, unknown>;
|
|
2
|
+
/** 단일 SymbolicOp 의 JSON Schema(kind 로 판별되는 anyOf). $defs 는 최상위에서 정의. */
|
|
3
|
+
export declare const SYMBOLIC_OP_SCHEMA: JsonSchema;
|
|
4
|
+
/**
|
|
5
|
+
* 호스트 `applyOps` 도구의 input_schema. 한 배치 = 한 원자 단위(resolver 가 전부 해소 or
|
|
6
|
+
* 전부 실패). description 은 "언제 호출하는지"를 명시 — 최신 모델은 도구를 보수적으로
|
|
7
|
+
* 집으므로 트리거 조건이 호출률을 좌우한다(시블링 선례). 모든 $defs 는 최상위에 모은다
|
|
8
|
+
* (엄격 서브셋: nested $defs 금지).
|
|
9
|
+
*/
|
|
10
|
+
export declare const APPLY_BPMN_OPS_SCHEMA: JsonSchema;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ── Anthropic structured-outputs 엄격 서브셋 적합성 검증기 ──
|
|
3
|
+
*
|
|
4
|
+
* `agent/schema.ts` 가 방출하는 JSON Schema 가 Anthropic structured-outputs / strict tool use 의
|
|
5
|
+
* **엄격 서브셋**을 지키는지 기계적으로 검사하는 스키마 drift 게이트 — 미지원 키워드·
|
|
6
|
+
* additionalProperties 누락·재귀($ref 사이클)를 CI 에서 잡는다. 라이브러리엔 LLM 이 없으므로
|
|
7
|
+
* (불변식 6) 라이브 API 프로브 대신 문서-권위 제약을 검증기로 코드화한다.
|
|
8
|
+
*
|
|
9
|
+
* 시블링 `../ui-modeler-next/src/agent/strictSubset.ts` 의 **복제**(C-2 구조 복제 — 검증 로직
|
|
10
|
+
* 본문 무수정, 헤더만 본 패키지 맥락으로 교체). BPMN op 스키마는 ui-modeler 의 inline-fold
|
|
11
|
+
* children 같은 재귀 유혹이 없어 flat 하지만, 게이트는 동일하게 둔다(어휘 확장 시 안전망).
|
|
12
|
+
*
|
|
13
|
+
* 엄격 서브셋 규칙(claude-api: Structured Outputs → JSON Schema Limitations):
|
|
14
|
+
* - 지원: object/array/string/integer/number/boolean/null, enum, const, anyOf, allOf, $ref/$defs,
|
|
15
|
+
* string formats, 모든 object에 `additionalProperties: false`.
|
|
16
|
+
* - 미지원: **재귀 스키마**, 수치 제약(minimum/maximum/multipleOf), 문자열 제약(minLength/maxLength/pattern),
|
|
17
|
+
* 복합 배열 제약(minItems/maxItems/uniqueItems), `additionalProperties`가 false 아닌 값.
|
|
18
|
+
*/
|
|
19
|
+
export interface StrictSubsetViolation {
|
|
20
|
+
/** 위반 규칙 슬러그. */
|
|
21
|
+
rule: 'missing-additional-properties-false' | 'unsupported-keyword' | 'nested-$defs' | 'recursion' | 'dangling-$ref';
|
|
22
|
+
/** 스키마 내 위치(디버그용 경로). */
|
|
23
|
+
path: string;
|
|
24
|
+
detail: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 스키마가 Anthropic 엄격 서브셋을 지키는지 검사. 위반 배열 반환(빈 배열 = 적합).
|
|
28
|
+
* @param root 루트 스키마(도구 input_schema — `$defs`는 여기 최상위).
|
|
29
|
+
*/
|
|
30
|
+
export declare function checkStrictSubset(root: unknown): StrictSubsetViolation[];
|
|
31
|
+
/** 적합 여부 단축 판정. */
|
|
32
|
+
export declare function isStrictSubset(root: unknown): boolean;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { BwlBand, BwlPlacement, BwlPoolOrder } from '../core/hints';
|
|
2
|
+
import { IrAssociation, IrDataAssociation, IrDataStore, IrFlowCondition, IrFlowNodeType, IrGroup, IrLane, IrMessageFlow, IrNode, IrParticipant, IrSequenceFlow, IrTextAnnotation } from '../core/ir';
|
|
3
|
+
/** LLM 이 산출하는 단일 심볼릭 op. `kind` 로 판별한다. */
|
|
4
|
+
export type SymbolicOp =
|
|
5
|
+
/** 풀 추가. `order` = 풀 세로 순서 힌트(생략 시 op 순서가 곧 배치 순서). */
|
|
6
|
+
{
|
|
7
|
+
kind: 'participant.add';
|
|
8
|
+
participant: IrParticipant;
|
|
9
|
+
order?: BwlPoolOrder;
|
|
10
|
+
}
|
|
11
|
+
/** 플로우 노드 추가. `node.lane` 은 좌표 결정에만 쓰인다(A-3 — flowNodeRef 는 bpmn-js 지오메트리 자동 유지). `band` = 프로세스 내부 가로 밴드 힌트. */
|
|
12
|
+
| {
|
|
13
|
+
kind: 'node.add';
|
|
14
|
+
node: IrNode;
|
|
15
|
+
band?: BwlBand;
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'sequenceFlow.add';
|
|
18
|
+
flow: IrSequenceFlow;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'messageFlow.add';
|
|
21
|
+
flow: IrMessageFlow;
|
|
22
|
+
}
|
|
23
|
+
/** 데이터 스토어 추가(+ 입출력 연관 동반 가능 — 방향은 IrDataAssociation source→target). */
|
|
24
|
+
| {
|
|
25
|
+
kind: 'dataStore.add';
|
|
26
|
+
dataStore: IrDataStore;
|
|
27
|
+
associations?: IrDataAssociation[];
|
|
28
|
+
}
|
|
29
|
+
/** 기존 노드 ↔ 기존 데이터 스토어의 입출력 연관 추가. */
|
|
30
|
+
| {
|
|
31
|
+
kind: 'dataAssociation.add';
|
|
32
|
+
association: IrDataAssociation;
|
|
33
|
+
}
|
|
34
|
+
/** 주석 ↔ 요소 연관 추가(한쪽 끝은 주석). 주석 신설 동반은 annotation.add 의 association 이 우선 — 이 op 는 추가 연관(한 주석에 2개 이상)용. */
|
|
35
|
+
| {
|
|
36
|
+
kind: 'association.add';
|
|
37
|
+
association: IrAssociation;
|
|
38
|
+
}
|
|
39
|
+
/** 텍스트 주석 추가. `placement` = 앵커 기준 방위 힌트(있으면 결정적 배치 + bwl:placement 기록, 없으면 휴리스틱 — B-2). */
|
|
40
|
+
| {
|
|
41
|
+
kind: 'annotation.add';
|
|
42
|
+
annotation: IrTextAnnotation;
|
|
43
|
+
association?: IrAssociation;
|
|
44
|
+
placement?: BwlPlacement;
|
|
45
|
+
}
|
|
46
|
+
/** 그룹 추가. `group.members` 가 bwl:members 힌트로 기록되고 resolver 가 멤버 bbox + 패딩으로 바운즈를 산출한다(A-4). */
|
|
47
|
+
| {
|
|
48
|
+
kind: 'group.add';
|
|
49
|
+
group: IrGroup;
|
|
50
|
+
}
|
|
51
|
+
/** `lanes` 는 전체 재선언(생략 = 보존) — resolver 가 기존과 diff 해 하강한다. 레인 축소(제거)는 B-0 미실증 축이라 resolver 가 거부할 수 있다(세션 ② 판단). */
|
|
52
|
+
| {
|
|
53
|
+
kind: 'participant.update';
|
|
54
|
+
id: string;
|
|
55
|
+
name?: string | null;
|
|
56
|
+
lanes?: IrLane[];
|
|
57
|
+
}
|
|
58
|
+
/** `lane` = 레인 재배정(이동). `type` = 태스크/이벤트 타입 전환(bpmn-js replace 하강 — 외래 확장 속성 유실 가능성은 불변식 2 가 완충). */
|
|
59
|
+
| {
|
|
60
|
+
kind: 'node.update';
|
|
61
|
+
id: string;
|
|
62
|
+
name?: string | null;
|
|
63
|
+
lane?: string;
|
|
64
|
+
type?: IrFlowNodeType;
|
|
65
|
+
} | {
|
|
66
|
+
kind: 'sequenceFlow.update';
|
|
67
|
+
id: string;
|
|
68
|
+
name?: string | null;
|
|
69
|
+
condition?: IrFlowCondition | null;
|
|
70
|
+
} | {
|
|
71
|
+
kind: 'messageFlow.update';
|
|
72
|
+
id: string;
|
|
73
|
+
name?: string | null;
|
|
74
|
+
} | {
|
|
75
|
+
kind: 'dataStore.update';
|
|
76
|
+
id: string;
|
|
77
|
+
name?: string | null;
|
|
78
|
+
}
|
|
79
|
+
/** `text` 는 주석의 본질이라 제거 불가(주석 삭제 = element.remove). `placement: null` = 힌트 제거(휴리스틱 복귀). */
|
|
80
|
+
| {
|
|
81
|
+
kind: 'annotation.update';
|
|
82
|
+
id: string;
|
|
83
|
+
text?: string;
|
|
84
|
+
placement?: BwlPlacement | null;
|
|
85
|
+
}
|
|
86
|
+
/** `members` 는 전체 재선언(생략 = 보존) — resolver 가 바운즈를 재산출한다. */
|
|
87
|
+
| {
|
|
88
|
+
kind: 'group.update';
|
|
89
|
+
id: string;
|
|
90
|
+
name?: string | null;
|
|
91
|
+
members?: string[];
|
|
92
|
+
}
|
|
93
|
+
/** 요소 제거(카테고리 무관 — 도형·연결 균일, 부착 연결은 연쇄 제거). */
|
|
94
|
+
| {
|
|
95
|
+
kind: 'element.remove';
|
|
96
|
+
id: string;
|
|
97
|
+
};
|
|
98
|
+
/**
|
|
99
|
+
* 심볼릭 op 종류의 닫힌 집합(단일 출처). resolver·JSON Schema(`schema.ts`)가 공유한다.
|
|
100
|
+
* 아래 컴파일타임 단언이 이 튜플과 `SymbolicOp['kind']` 의 일치를 강제 — 한쪽만 늘리면 타입 에러.
|
|
101
|
+
*/
|
|
102
|
+
export declare const SYMBOLIC_OP_KINDS: readonly ["participant.add", "participant.update", "node.add", "node.update", "sequenceFlow.add", "sequenceFlow.update", "messageFlow.add", "messageFlow.update", "dataStore.add", "dataStore.update", "dataAssociation.add", "association.add", "annotation.add", "annotation.update", "group.add", "group.update", "element.remove"];
|
|
103
|
+
export type SymbolicOpKind = (typeof SYMBOLIC_OP_KINDS)[number];
|