@dotbep/core 0.2.7 → 0.2.9
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/dist/index.d.ts +7 -40
- package/dist/index.js +1142 -1179
- package/package.json +4 -1
- package/examples/01-participants.ts +0 -127
- package/examples/02-files.ts +0 -100
- package/examples/03-workflows.ts +0 -149
- package/examples/04-bim-uses.ts +0 -70
- package/examples/05-standards.ts +0 -60
- package/examples/06-schedule.ts +0 -124
- package/examples/07-loin.ts +0 -133
- package/examples/08-deliverables.ts +0 -126
- package/examples/09-notes.ts +0 -73
- package/examples/10-llm.ts +0 -109
- package/examples/11-resolved.ts +0 -133
- package/examples/12-history.ts +0 -166
- package/examples/13-engine.ts +0 -152
- package/examples/bep.d.ts +0 -38
- package/examples/example.bep +0 -0
- package/examples/run-all.ts +0 -38
- package/src/base/entity.ts +0 -148
- package/src/base/history.ts +0 -497
- package/src/base/index.ts +0 -5
- package/src/base/singleton.ts +0 -26
- package/src/entities/actions.ts +0 -25
- package/src/entities/adapters.ts +0 -16
- package/src/entities/annexes.ts +0 -17
- package/src/entities/assetTypes.ts +0 -30
- package/src/entities/automations.ts +0 -24
- package/src/entities/bimUses.ts +0 -50
- package/src/entities/deliverables.ts +0 -66
- package/src/entities/disciplines.ts +0 -21
- package/src/entities/effects.ts +0 -28
- package/src/entities/env.ts +0 -17
- package/src/entities/events.ts +0 -24
- package/src/entities/extensions.ts +0 -16
- package/src/entities/flags.ts +0 -17
- package/src/entities/guides.ts +0 -26
- package/src/entities/index.ts +0 -32
- package/src/entities/lbsNodes.ts +0 -193
- package/src/entities/lods.ts +0 -22
- package/src/entities/loin.ts +0 -127
- package/src/entities/lois.ts +0 -22
- package/src/entities/members.ts +0 -137
- package/src/entities/milestones.ts +0 -32
- package/src/entities/notes.ts +0 -27
- package/src/entities/objectives.ts +0 -17
- package/src/entities/phases.ts +0 -17
- package/src/entities/remoteData.ts +0 -17
- package/src/entities/resolvers.ts +0 -20
- package/src/entities/roles.ts +0 -29
- package/src/entities/softwares.ts +0 -26
- package/src/entities/standards.ts +0 -68
- package/src/entities/teams.ts +0 -42
- package/src/entities/workflows.ts +0 -256
- package/src/index.ts +0 -464
- package/src/runtime/Engine.ts +0 -352
- package/src/runtime/MemoryStorage.ts +0 -31
- package/src/runtime/Runtime.ts +0 -106
- package/src/runtime/index.ts +0 -4
- package/src/runtime/transitions.ts +0 -456
- package/src/runtime/types.ts +0 -279
- package/src/types/history.ts +0 -37
- package/src/types/index.ts +0 -24
- package/src/types/resolved.ts +0 -137
- package/src/types/schema.ts +0 -757
- package/src/utils/diff.ts +0 -109
- package/src/utils/index.ts +0 -9
- package/src/utils/integrity.ts +0 -108
- package/src/utils/lbs.ts +0 -116
- package/src/utils/mermaid.ts +0 -110
- package/src/utils/naming.ts +0 -62
- package/src/utils/nomenclature.ts +0 -107
- package/src/utils/normalize.ts +0 -35
- package/src/utils/raci.ts +0 -25
- package/src/utils/textFile.ts +0 -24
- package/tsconfig.json +0 -12
- package/vite.config.ts +0 -24
package/examples/07-loin.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --07 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: lods, lois, loin.
|
|
4
|
-
//
|
|
5
|
-
// The LOIN section defines the Level of Information Need — what must be known
|
|
6
|
-
// about each model element at each milestone. It is the core of an ISO 19650
|
|
7
|
-
// information requirements framework.
|
|
8
|
-
//
|
|
9
|
-
// LOD (Level of Development) — geometric completeness of a model element.
|
|
10
|
-
// LOI (Level of Information) — richness of the non-geometric data attached to it.
|
|
11
|
-
// LOIN — the per-element table that maps (element × milestone) → (LOD, LOI).
|
|
12
|
-
//
|
|
13
|
-
// LOD and LOI ids are numeric strings ('100', '200', …). They are readable
|
|
14
|
-
// codes, not UUIDs — the user chooses them to match the project's convention.
|
|
15
|
-
|
|
16
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
17
|
-
import { Bep } from '../dist/index.js'
|
|
18
|
-
|
|
19
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
20
|
-
|
|
21
|
-
const m1Id = bep.milestones.list().find(m => m.name === 'Design Delivery')!.id
|
|
22
|
-
const m2Id = bep.milestones.list().find(m => m.name === 'Construction Delivery')!.id
|
|
23
|
-
|
|
24
|
-
// ─── LODs ─────────────────────────────────────────────────────────────────────
|
|
25
|
-
|
|
26
|
-
// LOD levels are defined once and reused across all LOIN entries. Each level
|
|
27
|
-
// can carry a checklist that the frontend renders as acceptance criteria.
|
|
28
|
-
// The id is a string (not a number) so that it participates in the same
|
|
29
|
-
// get/update/remove API as all other entities.
|
|
30
|
-
|
|
31
|
-
console.log('=== lods ===')
|
|
32
|
-
|
|
33
|
-
const lodsAdded = bep.lods.add([
|
|
34
|
-
{ id: '100', name: 'LOD 100', checklist: ['Conceptual massing present' ] },
|
|
35
|
-
{ id: '200', name: 'LOD 200' },
|
|
36
|
-
{ id: '300', name: 'LOD 300', checklist: ['All geometry defined', 'Dimensions accurate' ] },
|
|
37
|
-
{ id: '350', name: 'LOD 350', checklist: ['Connections and interfaces defined' ] },
|
|
38
|
-
{ id: '100', name: 'Duplicate' }, // fails
|
|
39
|
-
])
|
|
40
|
-
console.log('add succeeded:', lodsAdded.succeeded.map(l => l.id))
|
|
41
|
-
console.log('add failed: ', lodsAdded.failed)
|
|
42
|
-
|
|
43
|
-
const gotLod = bep.lods.get(['100', '999'])
|
|
44
|
-
console.log('\nget 100:', gotLod.succeeded[0].name)
|
|
45
|
-
console.log('get 999 (failed):', gotLod.failed)
|
|
46
|
-
|
|
47
|
-
bep.lods.update([
|
|
48
|
-
{ id: '100', name: 'LOD 100 — Conceptual' },
|
|
49
|
-
{ id: '999', name: 'Ghost' }, // fails
|
|
50
|
-
])
|
|
51
|
-
|
|
52
|
-
// ─── LOIs ─────────────────────────────────────────────────────────────────────
|
|
53
|
-
|
|
54
|
-
// LOI levels follow the same pattern as LODs — numeric string ids, optional
|
|
55
|
-
// checklists. LOI 1 might require only a classification code; LOI 3 might
|
|
56
|
-
// require a full property set with IFC links. The checklists make those
|
|
57
|
-
// expectations explicit and auditable.
|
|
58
|
-
|
|
59
|
-
console.log('\n=== lois ===')
|
|
60
|
-
|
|
61
|
-
const loisAdded = bep.lois.add([
|
|
62
|
-
{ id: '1', name: 'LOI 1' },
|
|
63
|
-
{ id: '2', name: 'LOI 2', checklist: ['Classification assigned', 'Material specified' ] },
|
|
64
|
-
{ id: '3', name: 'LOI 3', checklist: ['Full property set defined', 'IFC classification linked' ] },
|
|
65
|
-
{ id: '1', name: 'Duplicate' }, // fails
|
|
66
|
-
])
|
|
67
|
-
console.log('add succeeded:', loisAdded.succeeded.map(l => l.id))
|
|
68
|
-
console.log('add failed: ', loisAdded.failed)
|
|
69
|
-
|
|
70
|
-
// ─── LOIN ─────────────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
// A LOIN entry describes one model element type (e.g. "Walls") and its
|
|
73
|
-
// information requirements across milestones. Each entry maps a discipline to
|
|
74
|
-
// a list of (milestone → LOD + LOI) pairs.
|
|
75
|
-
//
|
|
76
|
-
// Every reference — discipline, milestone, LOD, LOI — is validated on add.
|
|
77
|
-
// A single bad reference fails the entire LOIN entry, not just that milestone.
|
|
78
|
-
|
|
79
|
-
console.log('\n=== loin ===')
|
|
80
|
-
|
|
81
|
-
const loinAdded = bep.loin.add([
|
|
82
|
-
{
|
|
83
|
-
element: 'Walls',
|
|
84
|
-
disciplineId: 'ARQ',
|
|
85
|
-
milestones: [
|
|
86
|
-
{ milestoneId: m1Id, lodId: '300', loiId: '2' },
|
|
87
|
-
{ milestoneId: m2Id, lodId: '350', loiId: '3' },
|
|
88
|
-
],
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
element: 'Slabs',
|
|
92
|
-
disciplineId: 'EST',
|
|
93
|
-
milestones: [
|
|
94
|
-
{ milestoneId: m1Id, lodId: '200', loiId: '1' },
|
|
95
|
-
{ milestoneId: m2Id, lodId: '300', loiId: '2' },
|
|
96
|
-
],
|
|
97
|
-
},
|
|
98
|
-
// integrity failures —
|
|
99
|
-
{ element: 'Bad discipline', disciplineId: 'ghost-disc' }, // fails
|
|
100
|
-
{ element: 'Bad milestone', disciplineId: 'ARQ', milestones: [{ milestoneId: 'ghost', lodId: '100', loiId: '1' }] }, // fails
|
|
101
|
-
{ element: 'Bad LOD', disciplineId: 'ARQ', milestones: [{ milestoneId: m1Id, lodId: '999', loiId: '1' }] }, // fails
|
|
102
|
-
{ element: 'Bad LOI', disciplineId: 'ARQ', milestones: [{ milestoneId: m1Id, lodId: '100', loiId: '99' }] }, // fails
|
|
103
|
-
])
|
|
104
|
-
const loinWallsId = loinAdded.succeeded[0].id
|
|
105
|
-
const loinSlabsId = loinAdded.succeeded[1].id
|
|
106
|
-
console.log('add succeeded:', loinAdded.succeeded.map(l => l.element))
|
|
107
|
-
console.log('add failed: ', loinAdded.failed)
|
|
108
|
-
|
|
109
|
-
console.log('\n--- integrity: entities referenced by LOIN cannot be removed ---')
|
|
110
|
-
console.log('remove ARQ (discipline):', bep.disciplines.remove(['ARQ']).failed)
|
|
111
|
-
console.log('remove m1 (milestone): ', bep.milestones.remove([m1Id]).failed)
|
|
112
|
-
console.log('remove 300 (lod): ', bep.lods.remove(['300']).failed)
|
|
113
|
-
console.log('remove LOI 2: ', bep.lois.remove(['2']).failed)
|
|
114
|
-
|
|
115
|
-
// remove works when the LOIN entry itself is deleted first
|
|
116
|
-
const loinRemoved = bep.loin.remove([loinSlabsId, 'ghost-loin'])
|
|
117
|
-
console.log('\nremove Slabs LOIN succeeded:', loinRemoved.succeeded)
|
|
118
|
-
console.log('remove ghost failed: ', loinRemoved.failed)
|
|
119
|
-
|
|
120
|
-
// re-add Slabs so the complete BEP carries it forward
|
|
121
|
-
bep.loin.add([{
|
|
122
|
-
element: 'Slabs',
|
|
123
|
-
disciplineId: 'EST',
|
|
124
|
-
milestones: [
|
|
125
|
-
{ milestoneId: m1Id, lodId: '200', loiId: '1' },
|
|
126
|
-
{ milestoneId: m2Id, lodId: '300', loiId: '2' },
|
|
127
|
-
],
|
|
128
|
-
}])
|
|
129
|
-
|
|
130
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
133
|
-
console.log('\nSaved → examples/example.bep')
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --08 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: deliverables, nomenclature.
|
|
4
|
-
//
|
|
5
|
-
// Deliverables are the actual files that teams must produce and exchange.
|
|
6
|
-
// They are the most cross-referenced entity in the BEP — each one ties together
|
|
7
|
-
// a discipline, a document type, a set of extensions, a responsible team, a
|
|
8
|
-
// milestone, and optionally an LBS location and a predecessor deliverable.
|
|
9
|
-
//
|
|
10
|
-
// Nomenclature derives a human-readable naming code from those references:
|
|
11
|
-
// {project.code}-{team.id}-{zoneCode}-{locationCode}-{assetType.id}-{disc.id}-{NNN}
|
|
12
|
-
// NNN is a global sequence counter across all deliverables, zero-padded to three digits.
|
|
13
|
-
|
|
14
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
15
|
-
import { Bep, buildCodeMap } from '../dist/index.js'
|
|
16
|
-
|
|
17
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
18
|
-
|
|
19
|
-
const m1Id = bep.milestones.list().find(m => m.name === 'Design Delivery')!.id
|
|
20
|
-
const m2Id = bep.milestones.list().find(m => m.name === 'Construction Delivery')!.id
|
|
21
|
-
|
|
22
|
-
// ─── Deliverables ─────────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
// Every reference field is validated on add. A deliverable with a ghost
|
|
25
|
-
// disciplineId, assetTypeId, extensionId, responsibleId, milestoneId, or
|
|
26
|
-
// lbsNodeId fails individually — other deliverables in the same batch proceed.
|
|
27
|
-
// predecessorId is set via update() after both IDs are known.
|
|
28
|
-
|
|
29
|
-
console.log('=== deliverables ===')
|
|
30
|
-
|
|
31
|
-
const delAdded = bep.deliverables.add([
|
|
32
|
-
{
|
|
33
|
-
description: 'Architectural Model — Floor 1',
|
|
34
|
-
disciplineId: 'ARQ',
|
|
35
|
-
assetTypeId: 'M3D',
|
|
36
|
-
extensionIds: ['ifc', 'rvt'],
|
|
37
|
-
responsibleId: 'ARC',
|
|
38
|
-
milestoneId: m1Id,
|
|
39
|
-
lbsNodeId: 'P01',
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
description: 'Architectural Model — Floor 2',
|
|
43
|
-
disciplineId: 'ARQ',
|
|
44
|
-
assetTypeId: 'M3D',
|
|
45
|
-
extensionIds: ['ifc', 'rvt'],
|
|
46
|
-
responsibleId: 'ARC',
|
|
47
|
-
milestoneId: m1Id,
|
|
48
|
-
lbsNodeId: 'P02',
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
description: 'Structural Model — Floor 1',
|
|
52
|
-
disciplineId: 'EST',
|
|
53
|
-
assetTypeId: 'M3D',
|
|
54
|
-
responsibleId: 'ARC',
|
|
55
|
-
milestoneId: m2Id,
|
|
56
|
-
lbsNodeId: 'P01',
|
|
57
|
-
// predecessorId set after d1 is known
|
|
58
|
-
},
|
|
59
|
-
// integrity failures —
|
|
60
|
-
{ description: 'Bad discipline', disciplineId: 'ghost-disc', assetTypeId: 'M3D', responsibleId: 'ARC', milestoneId: m1Id },
|
|
61
|
-
{ description: 'Bad assetType', disciplineId: 'ARQ', assetTypeId: 'ghost-dt', responsibleId: 'ARC', milestoneId: m1Id },
|
|
62
|
-
{ description: 'Bad extension', disciplineId: 'ARQ', assetTypeId: 'M3D', extensionIds: ['ghost-ext'], responsibleId: 'ARC', milestoneId: m1Id },
|
|
63
|
-
{ description: 'Bad team', disciplineId: 'ARQ', assetTypeId: 'M3D', responsibleId: 'ghost-team', milestoneId: m1Id },
|
|
64
|
-
{ description: 'Bad milestone', disciplineId: 'ARQ', assetTypeId: 'M3D', responsibleId: 'ARC', milestoneId: 'ghost-ms' },
|
|
65
|
-
{ description: 'Bad lbsNode', disciplineId: 'ARQ', assetTypeId: 'M3D', responsibleId: 'ARC', milestoneId: m1Id, lbsNodeId: 'ghost-node' },
|
|
66
|
-
])
|
|
67
|
-
const d1 = delAdded.succeeded[0].id
|
|
68
|
-
const d2 = delAdded.succeeded[1].id
|
|
69
|
-
const d3 = delAdded.succeeded[2].id
|
|
70
|
-
console.log('add succeeded:', delAdded.succeeded.map(d => d.description))
|
|
71
|
-
console.log('add failed: ', delAdded.failed)
|
|
72
|
-
|
|
73
|
-
// set predecessor now that both IDs are known
|
|
74
|
-
bep.deliverables.update([{ id: d3, predecessorId: d1 }])
|
|
75
|
-
|
|
76
|
-
console.log('\n--- integrity: predecessor blocks removal of the referenced deliverable ---')
|
|
77
|
-
const d1Blocked = bep.deliverables.remove([d1])
|
|
78
|
-
console.log('remove d1 (blocked by d3.predecessorId):', d1Blocked.failed)
|
|
79
|
-
|
|
80
|
-
console.log('\n--- integrity: entities referenced by deliverables cannot be removed ---')
|
|
81
|
-
console.log('remove ARQ (discipline):', bep.disciplines.remove(['ARQ']).failed)
|
|
82
|
-
console.log('remove M3D (assetType): ', bep.assetTypes.remove(['M3D']).failed)
|
|
83
|
-
console.log('remove m1 (milestone): ', bep.milestones.remove([m1Id]).failed)
|
|
84
|
-
console.log('remove ARC (team): ', bep.teams.remove(['ARC']).failed)
|
|
85
|
-
console.log('remove P01 (lbsNode): ', bep.lbsNodes.remove(['P01']).failed)
|
|
86
|
-
|
|
87
|
-
// ─── Nomenclature ─────────────────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
// buildCodeMap() computes naming codes for all deliverables in one pass.
|
|
90
|
-
// LBS resolution: P01 is a child of BLK → zoneCode=BLK, locationCode=P01.
|
|
91
|
-
// P02 is also a child of BLK → same zone, different location.
|
|
92
|
-
// NNN is a global zero-padded sequence, so d1→001, d2→002, d3→003.
|
|
93
|
-
//
|
|
94
|
-
// getCode() is a single-deliverable shortcut that internally calls buildCodeMap.
|
|
95
|
-
// buildConsecutivoMap() returns the raw integer sequence numbers before zero-padding.
|
|
96
|
-
// The standalone buildCodeMap import is useful when BEP data comes from outside
|
|
97
|
-
// the Bep class (e.g. from a raw JSON snapshot).
|
|
98
|
-
const codeMap = bep.nomenclature.buildCodeMap()
|
|
99
|
-
console.log('code map:')
|
|
100
|
-
for (const [id, code] of codeMap) {
|
|
101
|
-
console.log(' ', id.slice(0, 8), '→', code)
|
|
102
|
-
}
|
|
103
|
-
// d1 → EXP-ARC-BLK-P01-M3D-ARQ-001
|
|
104
|
-
// d2 → EXP-ARC-BLK-P02-M3D-ARQ-001 (different location → new NNN sequence)
|
|
105
|
-
// d3 → EXP-ARC-BLK-P01-M3D-EST-001
|
|
106
|
-
|
|
107
|
-
// getCode: single deliverable by id
|
|
108
|
-
console.log('\nd1 code:', bep.nomenclature.getCode(d1))
|
|
109
|
-
console.log('d2 code:', bep.nomenclature.getCode(d2))
|
|
110
|
-
console.log('d3 code:', bep.nomenclature.getCode(d3))
|
|
111
|
-
console.log('ghost: ', bep.nomenclature.getCode('ghost-id')) // null
|
|
112
|
-
|
|
113
|
-
// buildConsecutivoMap: raw sequence numbers per deliverable (before zero-padding)
|
|
114
|
-
const seqMap = bep.nomenclature.buildConsecutivoMap()
|
|
115
|
-
console.log('seq d1:', seqMap.get(d1)) // 1
|
|
116
|
-
console.log('seq d2:', seqMap.get(d2)) // 1 (different location → independent sequence)
|
|
117
|
-
console.log('seq d3:', seqMap.get(d3)) // 1
|
|
118
|
-
|
|
119
|
-
// standalone buildCodeMap — useful when BEP data comes from an external source
|
|
120
|
-
const externalMap = buildCodeMap(bep.data.deliverables, bep.data.project.code, bep.data.lbs)
|
|
121
|
-
console.log('\nexternal buildCodeMap matches:', [...externalMap.values()].join(', '))
|
|
122
|
-
|
|
123
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
124
|
-
|
|
125
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
126
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/09-notes.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --09 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: notes.
|
|
4
|
-
//
|
|
5
|
-
// Notes are the human layer of the BEP — annotations written by team members
|
|
6
|
-
// to record decisions, concerns, or confirmations that do not fit into the
|
|
7
|
-
// structured data. They are identified by the author's email, which must
|
|
8
|
-
// reference an existing member of the BEP.
|
|
9
|
-
//
|
|
10
|
-
// Because notes are authored by members, removing a member who has authored
|
|
11
|
-
// notes is blocked by referential integrity. The constraint is released only
|
|
12
|
-
// when the note itself is deleted first.
|
|
13
|
-
|
|
14
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
15
|
-
import { Bep } from '../dist/index.js'
|
|
16
|
-
|
|
17
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
18
|
-
|
|
19
|
-
// ─── Notes ────────────────────────────────────────────────────────────────────
|
|
20
|
-
|
|
21
|
-
// Notes are authored by members (identified by email) and carry a free-text
|
|
22
|
-
// message and a creation timestamp. The memberEmail must reference a member
|
|
23
|
-
// already registered in the BEP — unknown authors are rejected individually.
|
|
24
|
-
|
|
25
|
-
console.log('=== notes ===')
|
|
26
|
-
|
|
27
|
-
// notes are human annotations authored by BEP members (identified by email)
|
|
28
|
-
const notesAdded = bep.notes.add([
|
|
29
|
-
{
|
|
30
|
-
message: 'LOD 300 definition confirmed with client in meeting of 2026-03-15.',
|
|
31
|
-
memberEmail: 'alice@arc.com',
|
|
32
|
-
createdAt: '2026-03-15T10:00:00Z',
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
message: 'Structure team has not confirmed milestone M2 date yet.',
|
|
36
|
-
memberEmail: 'bob@arc.com',
|
|
37
|
-
createdAt: '2026-03-16T09:00:00Z',
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
message: 'Bad author.',
|
|
41
|
-
memberEmail: 'ghost@x.com', // fails — not a registered member
|
|
42
|
-
createdAt: '2026-03-16T09:00:00Z',
|
|
43
|
-
},
|
|
44
|
-
])
|
|
45
|
-
const n1Id = notesAdded.succeeded[0].id
|
|
46
|
-
const n2Id = notesAdded.succeeded[1].id
|
|
47
|
-
console.log('add succeeded:', notesAdded.succeeded.map(n => n.message.slice(0, 50)))
|
|
48
|
-
console.log('add failed: ', notesAdded.failed)
|
|
49
|
-
|
|
50
|
-
// sparse update — only message or other fields can be patched
|
|
51
|
-
const notesUpdated = bep.notes.update([
|
|
52
|
-
{ id: n2Id, message: 'Structure team confirmed: M2 date is 2027-03-31.' },
|
|
53
|
-
{ id: 'ghost-id', message: 'Ghost' }, // fails — id not found
|
|
54
|
-
])
|
|
55
|
-
console.log('\nupdate succeeded:', notesUpdated.succeeded.map(n => n.message.slice(0, 50)))
|
|
56
|
-
console.log('update failed: ', notesUpdated.failed)
|
|
57
|
-
|
|
58
|
-
console.log('\n--- integrity: member with authored notes cannot be removed ---')
|
|
59
|
-
const aliceBlocked = bep.members.remove(['alice@arc.com'])
|
|
60
|
-
console.log('remove alice (blocked by note.memberEmail):', aliceBlocked.failed)
|
|
61
|
-
|
|
62
|
-
// removing the note frees the member constraint for that note
|
|
63
|
-
const noteRemoved = bep.notes.remove([n1Id, 'ghost-note'])
|
|
64
|
-
console.log('\nremove n1 succeeded:', noteRemoved.succeeded)
|
|
65
|
-
console.log('remove ghost failed: ', noteRemoved.failed)
|
|
66
|
-
|
|
67
|
-
// alice can now be removed (her only note was n1Id, which was just deleted)
|
|
68
|
-
// — not doing it here to keep alice in the BEP for subsequent examples
|
|
69
|
-
|
|
70
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
71
|
-
|
|
72
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
73
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/10-llm.ts
DELETED
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --10 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: flags, memory, skill.
|
|
4
|
-
//
|
|
5
|
-
// These three entities are the LLM's layer of the BEP — they are written by
|
|
6
|
-
// the agent, not by the BIM Manager directly.
|
|
7
|
-
//
|
|
8
|
-
// Flags — observations generated after analyze_bep. Each flag points to an
|
|
9
|
-
// entity (or to the whole BEP) and carries a severity level. Flags
|
|
10
|
-
// are transient: they are cleared and regenerated on each analysis.
|
|
11
|
-
//
|
|
12
|
-
// Memory — a single markdown string the LLM writes to persist context across
|
|
13
|
-
// sessions: confirmed decisions, acknowledged flags, client constraints.
|
|
14
|
-
// The caller owns the full string — there is no append API.
|
|
15
|
-
//
|
|
16
|
-
// Skill — instructions authored by the BIM Manager that tell the LLM how to
|
|
17
|
-
// behave in this specific BEP (terminology, tone, LOD conventions).
|
|
18
|
-
// Skill can be copied from a template BEP to seed a new project.
|
|
19
|
-
|
|
20
|
-
import { readFileSync, writeFileSync } from 'node:fs'
|
|
21
|
-
import { Bep } from '../dist/index.js'
|
|
22
|
-
|
|
23
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
24
|
-
|
|
25
|
-
const d1 = bep.deliverables.list().find(d => d.description === 'Architectural Model — Floor 1')!.id
|
|
26
|
-
|
|
27
|
-
// ─── Flags ────────────────────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
// Flags point to specific entities (or to the whole BEP when entityId is null)
|
|
30
|
-
// and communicate issues the LLM detected during analysis. Once a flag is
|
|
31
|
-
// knowingly accepted, it should be removed and the decision documented in memory
|
|
32
|
-
// so it is not re-reported in a future session.
|
|
33
|
-
|
|
34
|
-
console.log('=== flags ===')
|
|
35
|
-
|
|
36
|
-
// Flags are generated by the LLM after analyze_bep — not authored by users.
|
|
37
|
-
// entity / entityId point to what the flag refers to; null means the whole BEP.
|
|
38
|
-
const flagsAdded = bep.flags.add([
|
|
39
|
-
{
|
|
40
|
-
entity: 'deliverables',
|
|
41
|
-
entityId: d1,
|
|
42
|
-
severity: 'warning',
|
|
43
|
-
message: 'Deliverable has no dueDate and the milestone date is in the past.',
|
|
44
|
-
generatedAt: '2026-03-24T08:00:00Z',
|
|
45
|
-
},
|
|
46
|
-
{
|
|
47
|
-
entity: null,
|
|
48
|
-
entityId: null,
|
|
49
|
-
severity: 'info',
|
|
50
|
-
message: 'BEP has no KPIs defined in the indicators section.',
|
|
51
|
-
generatedAt: '2026-03-24T08:00:00Z',
|
|
52
|
-
},
|
|
53
|
-
])
|
|
54
|
-
const f1Id = flagsAdded.succeeded[0].id
|
|
55
|
-
const f2Id = flagsAdded.succeeded[1].id
|
|
56
|
-
console.log('flags added:', flagsAdded.succeeded.map(f => `[${f.severity}] ${f.message.slice(0, 40)}`))
|
|
57
|
-
|
|
58
|
-
// remove a flag once it has been resolved or knowingly accepted
|
|
59
|
-
const flagRemoved = bep.flags.remove([f2Id, 'ghost-flag'])
|
|
60
|
-
console.log('remove info flag:', flagRemoved.succeeded)
|
|
61
|
-
console.log('remove ghost (failed):', flagRemoved.failed)
|
|
62
|
-
console.log('flags remaining:', bep.flags.list().length)
|
|
63
|
-
|
|
64
|
-
// ─── Memory ───────────────────────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
console.log('\n=== memory ===')
|
|
67
|
-
|
|
68
|
-
// memory is project-specific context the LLM writes for itself to recall across sessions
|
|
69
|
-
console.log('memory (empty):', JSON.stringify(await bep.memory.get()))
|
|
70
|
-
|
|
71
|
-
bep.memory.set([
|
|
72
|
-
'# Project Memory',
|
|
73
|
-
'',
|
|
74
|
-
'- LOD 300 confirmed with client on 2026-03-15.',
|
|
75
|
-
'- Structure team is responsible for all EST deliverables.',
|
|
76
|
-
'- "No KPIs" flag acknowledged — no KPI framework planned for this phase.',
|
|
77
|
-
].join('\n'))
|
|
78
|
-
|
|
79
|
-
console.log('memory set (first 60 chars):', (await bep.memory.get()).slice(0, 60))
|
|
80
|
-
|
|
81
|
-
// overwrite — no append, the caller owns the full string
|
|
82
|
-
const current = await bep.memory.get()
|
|
83
|
-
bep.memory.set(current + '\n- Coordination meetings every Monday at 09:00.')
|
|
84
|
-
console.log('memory length after update:', (await bep.memory.get()).length)
|
|
85
|
-
|
|
86
|
-
// ─── Skill ────────────────────────────────────────────────────────────────────
|
|
87
|
-
|
|
88
|
-
console.log('\n=== skill ===')
|
|
89
|
-
|
|
90
|
-
// skill is the BIM Manager's instructions for how the LLM should behave in this BEP
|
|
91
|
-
console.log('skill (empty):', JSON.stringify(await bep.skill.get()))
|
|
92
|
-
|
|
93
|
-
bep.skill.set([
|
|
94
|
-
'Always use ISO 19650 terminology.',
|
|
95
|
-
'Prefer concise descriptions — one sentence per deliverable.',
|
|
96
|
-
'When suggesting LOD levels, reference the project phases in bep.phases.',
|
|
97
|
-
].join('\n'))
|
|
98
|
-
|
|
99
|
-
console.log('skill set (first 60 chars):', (await bep.skill.get()).slice(0, 60))
|
|
100
|
-
|
|
101
|
-
// key use case: copy skill from a template BEP to a new project
|
|
102
|
-
const templateBep = Bep.create({ name: 'New Project', code: 'NEW' })
|
|
103
|
-
templateBep.skill.set(await bep.skill.get())
|
|
104
|
-
console.log('\nskill copied to new BEP (first 50):', (await templateBep.skill.get()).slice(0, 50))
|
|
105
|
-
|
|
106
|
-
// ─── Save ─────────────────────────────────────────────────────────────────────
|
|
107
|
-
|
|
108
|
-
writeFileSync('examples/example.bep', await bep.save())
|
|
109
|
-
console.log('\nSaved → examples/example.bep')
|
package/examples/11-resolved.ts
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
// part of: node --experimental-strip-types examples/run-all.ts (use --11 to stop here)
|
|
2
|
-
//
|
|
3
|
-
// Covers: listResolved() across all entity types. Read-only — no save.
|
|
4
|
-
//
|
|
5
|
-
// Every list() call returns raw entities with ID references (e.g. roleId: 'uuid').
|
|
6
|
-
// listResolved() replaces every ID with the full referenced object, so callers
|
|
7
|
-
// get a ready-to-render shape without performing any lookups themselves.
|
|
8
|
-
//
|
|
9
|
-
// This is particularly useful for the MCP — list_* tools always call
|
|
10
|
-
// listResolved() internally and return the enriched objects, so the LLM never
|
|
11
|
-
// needs to issue a follow-up call just to resolve a name.
|
|
12
|
-
//
|
|
13
|
-
// If a reference is broken (the referenced entity was deleted), listResolved()
|
|
14
|
-
// returns { id, name: null } instead of throwing, so the rest of the record
|
|
15
|
-
// remains usable.
|
|
16
|
-
|
|
17
|
-
import { readFileSync } from 'node:fs'
|
|
18
|
-
import { Bep } from '../dist/index.js'
|
|
19
|
-
|
|
20
|
-
const bep = await Bep.open(readFileSync('examples/example.bep'))
|
|
21
|
-
|
|
22
|
-
// ─── members ──────────────────────────────────────────────────────────────────
|
|
23
|
-
|
|
24
|
-
console.log('=== members.listResolved() ===')
|
|
25
|
-
|
|
26
|
-
const resolvedMembers = bep.members.listResolved()
|
|
27
|
-
const alice = resolvedMembers.find(m => m.email === 'alice@arc.com')!
|
|
28
|
-
console.log('alice role: ', alice.role) // { id, name, color }
|
|
29
|
-
console.log('alice team: ', alice.team) // { id: 'ARC', name: '...' }
|
|
30
|
-
console.log('alice isRepresentative:', alice.isRepresentative) // true
|
|
31
|
-
|
|
32
|
-
// ─── teams ────────────────────────────────────────────────────────────────────
|
|
33
|
-
|
|
34
|
-
console.log('\n=== teams.listResolved() ===')
|
|
35
|
-
|
|
36
|
-
const resolvedTeams = bep.teams.listResolved()
|
|
37
|
-
const arc = resolvedTeams.find(t => t.id === 'ARC')!
|
|
38
|
-
console.log('ARC representative:', arc.representative?.name)
|
|
39
|
-
console.log('ARC members: ', arc.members.map(m => m.name))
|
|
40
|
-
console.log('ARC disciplines: ', arc.disciplines.map(d => d.id))
|
|
41
|
-
|
|
42
|
-
// ─── milestones ───────────────────────────────────────────────────────────────
|
|
43
|
-
|
|
44
|
-
console.log('\n=== milestones.listResolved() ===')
|
|
45
|
-
|
|
46
|
-
const resolvedMilestones = bep.milestones.listResolved()
|
|
47
|
-
for (const m of resolvedMilestones) {
|
|
48
|
-
console.log(` ${m.name} (${m.date}) → phase: ${m.phase?.name}`)
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ─── lbsNodes ─────────────────────────────────────────────────────────────────
|
|
52
|
-
|
|
53
|
-
console.log('\n=== lbsNodes.listResolved() ===')
|
|
54
|
-
|
|
55
|
-
const resolvedLbs = bep.lbsNodes.listResolved()
|
|
56
|
-
const site = resolvedLbs.find(n => n.id === 'SIT')!
|
|
57
|
-
const blkA = resolvedLbs.find(n => n.id === 'BLK')!
|
|
58
|
-
const p01 = resolvedLbs.find(n => n.id === 'P01')!
|
|
59
|
-
|
|
60
|
-
console.log('SIT isRoot:', site.isRoot, '| parent:', site.parent, '| children:', site.children.map(c => c.id))
|
|
61
|
-
console.log('BLK isRoot:', blkA.isRoot, '| parent:', blkA.parent?.id, '| children:', blkA.children.map(c => c.id))
|
|
62
|
-
console.log('P01 isRoot:', p01.isRoot, '| parent:', p01.parent?.id)
|
|
63
|
-
|
|
64
|
-
// ─── guides ───────────────────────────────────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
console.log('\n=== guides.listResolved() ===')
|
|
67
|
-
|
|
68
|
-
const resolvedGuides = bep.guides.listResolved()
|
|
69
|
-
for (const g of resolvedGuides) {
|
|
70
|
-
console.log(` ${g.name}: annexes=[${g.annexes.map(a => a.name).join(', ')}]`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// ─── workflows ────────────────────────────────────────────────────────────────
|
|
74
|
-
|
|
75
|
-
console.log('\n=== workflows.listResolved() ===')
|
|
76
|
-
|
|
77
|
-
const resolvedWorkflows = bep.workflows.listResolved()
|
|
78
|
-
const wf = resolvedWorkflows[0]
|
|
79
|
-
console.log('workflow:', wf.name)
|
|
80
|
-
|
|
81
|
-
const updateNode = wf.diagram.nodes['update']
|
|
82
|
-
if (updateNode) {
|
|
83
|
-
console.log('update node action: ', updateNode.action?.name)
|
|
84
|
-
console.log('update node responsible:', updateNode.responsible.roles.map(r => r.name))
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ─── bimUses ──────────────────────────────────────────────────────────────────
|
|
88
|
-
|
|
89
|
-
console.log('\n=== bimUses.listResolved() ===')
|
|
90
|
-
|
|
91
|
-
const resolvedBimUses = bep.bimUses.listResolved()
|
|
92
|
-
for (const bu of resolvedBimUses) {
|
|
93
|
-
console.log(` ${bu.name}:`)
|
|
94
|
-
console.log(` objectives: [${bu.objectives.map(o => o.description.slice(0, 35)).join(' | ')}]`)
|
|
95
|
-
console.log(` workflows: [${bu.workflows.map(w => w.name).join(', ')}]`)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ─── loin ─────────────────────────────────────────────────────────────────────
|
|
99
|
-
|
|
100
|
-
console.log('\n=== loin.listResolved() ===')
|
|
101
|
-
|
|
102
|
-
const resolvedLoin = bep.loin.listResolved()
|
|
103
|
-
for (const l of resolvedLoin) {
|
|
104
|
-
console.log(` ${l.element} (${l.discipline?.name}):`)
|
|
105
|
-
for (const lm of l.milestones) {
|
|
106
|
-
console.log(` milestone=${lm.milestone?.name} lod=${lm.lod?.name} loi=${lm.loi?.name}`)
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// ─── deliverables ─────────────────────────────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
console.log('\n=== deliverables.listResolved() ===')
|
|
113
|
-
|
|
114
|
-
const resolvedDelivs = bep.deliverables.listResolved()
|
|
115
|
-
for (const d of resolvedDelivs) {
|
|
116
|
-
console.log(` ${d.nomenclatureCode ?? d.id}`)
|
|
117
|
-
console.log(` discipline: ${d.discipline?.name}`)
|
|
118
|
-
console.log(` assetType: ${d.assetType?.name}`)
|
|
119
|
-
console.log(` responsible: ${d.responsible?.name}`)
|
|
120
|
-
console.log(` milestone: ${d.milestone?.name}`)
|
|
121
|
-
if (d.predecessor) console.log(` predecessor: ${d.predecessor.id}`)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// ─── notes ────────────────────────────────────────────────────────────────────
|
|
125
|
-
|
|
126
|
-
console.log('\n=== notes.listResolved() ===')
|
|
127
|
-
|
|
128
|
-
const resolvedNotes = bep.notes.listResolved()
|
|
129
|
-
for (const n of resolvedNotes) {
|
|
130
|
-
console.log(` [${n.member?.name ?? '(unknown)'}] ${n.message.slice(0, 60)}`)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
console.log('\nDone — no save (read-only example).')
|