@dotbep/core 0.2.7 → 0.2.8

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 (77) hide show
  1. package/dist/index.d.ts +7 -5
  2. package/dist/index.js +604 -596
  3. package/package.json +4 -1
  4. package/examples/01-participants.ts +0 -127
  5. package/examples/02-files.ts +0 -100
  6. package/examples/03-workflows.ts +0 -149
  7. package/examples/04-bim-uses.ts +0 -70
  8. package/examples/05-standards.ts +0 -60
  9. package/examples/06-schedule.ts +0 -124
  10. package/examples/07-loin.ts +0 -133
  11. package/examples/08-deliverables.ts +0 -126
  12. package/examples/09-notes.ts +0 -73
  13. package/examples/10-llm.ts +0 -109
  14. package/examples/11-resolved.ts +0 -133
  15. package/examples/12-history.ts +0 -166
  16. package/examples/13-engine.ts +0 -152
  17. package/examples/bep.d.ts +0 -38
  18. package/examples/example.bep +0 -0
  19. package/examples/run-all.ts +0 -38
  20. package/src/base/entity.ts +0 -148
  21. package/src/base/history.ts +0 -497
  22. package/src/base/index.ts +0 -5
  23. package/src/base/singleton.ts +0 -26
  24. package/src/entities/actions.ts +0 -25
  25. package/src/entities/adapters.ts +0 -16
  26. package/src/entities/annexes.ts +0 -17
  27. package/src/entities/assetTypes.ts +0 -30
  28. package/src/entities/automations.ts +0 -24
  29. package/src/entities/bimUses.ts +0 -50
  30. package/src/entities/deliverables.ts +0 -66
  31. package/src/entities/disciplines.ts +0 -21
  32. package/src/entities/effects.ts +0 -28
  33. package/src/entities/env.ts +0 -17
  34. package/src/entities/events.ts +0 -24
  35. package/src/entities/extensions.ts +0 -16
  36. package/src/entities/flags.ts +0 -17
  37. package/src/entities/guides.ts +0 -26
  38. package/src/entities/index.ts +0 -32
  39. package/src/entities/lbsNodes.ts +0 -193
  40. package/src/entities/lods.ts +0 -22
  41. package/src/entities/loin.ts +0 -127
  42. package/src/entities/lois.ts +0 -22
  43. package/src/entities/members.ts +0 -137
  44. package/src/entities/milestones.ts +0 -32
  45. package/src/entities/notes.ts +0 -27
  46. package/src/entities/objectives.ts +0 -17
  47. package/src/entities/phases.ts +0 -17
  48. package/src/entities/remoteData.ts +0 -17
  49. package/src/entities/resolvers.ts +0 -20
  50. package/src/entities/roles.ts +0 -29
  51. package/src/entities/softwares.ts +0 -26
  52. package/src/entities/standards.ts +0 -68
  53. package/src/entities/teams.ts +0 -42
  54. package/src/entities/workflows.ts +0 -256
  55. package/src/index.ts +0 -464
  56. package/src/runtime/Engine.ts +0 -352
  57. package/src/runtime/MemoryStorage.ts +0 -31
  58. package/src/runtime/Runtime.ts +0 -106
  59. package/src/runtime/index.ts +0 -4
  60. package/src/runtime/transitions.ts +0 -456
  61. package/src/runtime/types.ts +0 -279
  62. package/src/types/history.ts +0 -37
  63. package/src/types/index.ts +0 -24
  64. package/src/types/resolved.ts +0 -137
  65. package/src/types/schema.ts +0 -757
  66. package/src/utils/diff.ts +0 -109
  67. package/src/utils/index.ts +0 -9
  68. package/src/utils/integrity.ts +0 -108
  69. package/src/utils/lbs.ts +0 -116
  70. package/src/utils/mermaid.ts +0 -110
  71. package/src/utils/naming.ts +0 -62
  72. package/src/utils/nomenclature.ts +0 -107
  73. package/src/utils/normalize.ts +0 -35
  74. package/src/utils/raci.ts +0 -25
  75. package/src/utils/textFile.ts +0 -24
  76. package/tsconfig.json +0 -12
  77. package/vite.config.ts +0 -24
package/src/index.ts DELETED
@@ -1,464 +0,0 @@
1
- import JSZip from 'jszip'
2
- import type { BEP, NamingConvention, Project } from './types/schema.js'
3
- import { NamingConventionSchema, ProjectSchema } from './types/schema.js'
4
- import { normalizeBep } from './utils/normalize.js'
5
- import { validateTokenValue, validateAllTokens } from './utils/naming.js'
6
- import { Singleton } from './base/singleton.js'
7
- import { Actions } from './entities/actions.js'
8
- import { Adapters } from './entities/adapters.js'
9
- import { Annexes } from './entities/annexes.js'
10
- import { Effects } from './entities/effects.js'
11
- import { Automations } from './entities/automations.js'
12
- import { Env } from './entities/env.js'
13
- import { Events } from './entities/events.js'
14
- import { Deliverables } from './entities/deliverables.js'
15
- import { Flags } from './entities/flags.js'
16
- import { Notes } from './entities/notes.js'
17
- import { BIMUses } from './entities/bimUses.js'
18
- import { Disciplines } from './entities/disciplines.js'
19
- import { Guides } from './entities/guides.js'
20
- import { LODs } from './entities/lods.js'
21
- import { LOIs } from './entities/lois.js'
22
- import { LOINEntity } from './entities/loin.js'
23
- import { AssetTypes } from './entities/assetTypes.js'
24
- import { Extensions } from './entities/extensions.js'
25
- import { Roles } from './entities/roles.js'
26
- import { LBSNodes } from './entities/lbsNodes.js'
27
- import { Members } from './entities/members.js'
28
- import { Milestones } from './entities/milestones.js'
29
- import { Objectives } from './entities/objectives.js'
30
- import { Phases } from './entities/phases.js'
31
- import { RemoteDataEntity } from './entities/remoteData.js'
32
- import { Resolvers } from './entities/resolvers.js'
33
- import { Softwares } from './entities/softwares.js'
34
- import { Standards } from './entities/standards.js'
35
- import { Teams } from './entities/teams.js'
36
- import { Workflows } from './entities/workflows.js'
37
- import { History } from './base/history.js'
38
- import { Nomenclature } from './utils/nomenclature.js'
39
- import { TextFile } from './utils/textFile.js'
40
- import { Engine } from './runtime/Engine.js'
41
-
42
- export class Bep {
43
- // ─── Singleton fields ─────────────────────────────────────────────────────
44
-
45
- readonly project: Singleton<Project>
46
-
47
- // ─── Entities ─────────────────────────────────────────────────────────────
48
-
49
- readonly actions: Actions
50
- readonly adapters: Adapters
51
- readonly annexes: Annexes
52
- readonly deliverables: Deliverables
53
- readonly effects: Effects
54
- readonly automations: Automations
55
- readonly env: Env
56
- readonly events: Events
57
- readonly notes: Notes
58
- readonly flags: Flags
59
- readonly bimUses: BIMUses
60
- readonly disciplines: Disciplines
61
- readonly guides: Guides
62
- readonly lods: LODs
63
- readonly lois: LOIs
64
- readonly loin: LOINEntity
65
- readonly lbsNodes: LBSNodes
66
- readonly assetTypes: AssetTypes
67
- readonly extensions: Extensions
68
- readonly roles: Roles
69
- readonly members: Members
70
- readonly milestones: Milestones
71
- readonly objectives: Objectives
72
- readonly phases: Phases
73
- readonly remoteData: RemoteDataEntity
74
- readonly resolvers: Resolvers
75
- readonly softwares: Softwares
76
- readonly standards: Standards
77
- readonly teams: Teams
78
- readonly workflows: Workflows
79
-
80
- // ─── Engine ───────────────────────────────────────────────────────────────
81
-
82
- readonly engine: Engine
83
-
84
- // ─── History ──────────────────────────────────────────────────────────────
85
-
86
- readonly history: History
87
-
88
- // ─── Nomenclature ─────────────────────────────────────────────────────────
89
-
90
- readonly nomenclature: Nomenclature
91
-
92
- // ─── Project files ────────────────────────────────────────────────────────
93
-
94
- readonly memory: TextFile
95
- readonly skill: TextFile
96
- readonly icon: TextFile
97
-
98
- private constructor(
99
- private _data: BEP,
100
- private _zip: JSZip,
101
- ) {
102
- const bep = () => this._data
103
- this.project = new Singleton(
104
- () => this._data.project,
105
- (p) => { this._data.project = p },
106
- ProjectSchema,
107
- (p, bep) => {
108
- const errors: string[] = []
109
- const tokenErr = validateTokenValue('project', p.code, bep.deliverableNamingConvention)
110
- if (tokenErr) errors.push(tokenErr)
111
- if (p.clientId && !bep.teams.some(t => t.id === p.clientId))
112
- errors.push(`teams["${p.clientId}"] not found`)
113
- return errors
114
- },
115
- bep,
116
- )
117
- this.actions = new Actions(bep)
118
- this.adapters = new Adapters(bep)
119
- this.annexes = new Annexes(bep)
120
- this.env = new Env(bep)
121
- this.events = new Events(bep)
122
- this.effects = new Effects(bep)
123
- this.automations = new Automations(bep)
124
- this.bimUses = new BIMUses(bep, () => this.workflows)
125
- this.disciplines = new Disciplines(bep)
126
- this.guides = new Guides(bep)
127
- this.lods = new LODs(bep)
128
- this.lois = new LOIs(bep)
129
- this.loin = new LOINEntity(bep)
130
- this.lbsNodes = new LBSNodes(bep)
131
- this.assetTypes = new AssetTypes(bep)
132
- this.extensions = new Extensions(bep)
133
- this.roles = new Roles(bep)
134
- this.members = new Members(bep)
135
- this.milestones = new Milestones(bep)
136
- this.objectives = new Objectives(bep)
137
- this.phases = new Phases(bep)
138
- this.remoteData = new RemoteDataEntity(bep)
139
- this.resolvers = new Resolvers(bep)
140
- this.softwares = new Softwares(bep, () => this.assetTypes)
141
- this.standards = new Standards(bep, () => this._zip)
142
- this.teams = new Teams(bep, () => this.members)
143
- this.workflows = new Workflows(bep, () => this.members, () => this.teams)
144
- this.deliverables = new Deliverables(bep, () => this.teams, () => this.assetTypes, () => this.lbsNodes, () => this.milestones)
145
- this.notes = new Notes(bep, () => this.members)
146
- this.flags = new Flags(bep)
147
- this.engine = new Engine(
148
- () => this._data,
149
- (version) => this.history.get(version),
150
- )
151
- this.history = new History(
152
- bep,
153
- (newBep) => { this._data = newBep },
154
- () => this._zip,
155
- )
156
- this.nomenclature = new Nomenclature(bep)
157
- this.memory = new TextFile('memory.md', () => this._zip)
158
- this.skill = new TextFile('skills/bep-authoring/SKILL.md', () => this._zip)
159
- this.icon = new TextFile('icon.svg', () => this._zip)
160
- }
161
-
162
- // ─── Factory ──────────────────────────────────────────────────────────────
163
-
164
- /**
165
- * Opens a .bep archive from a buffer.
166
- * The caller is responsible for obtaining the buffer (fs.readFile in Node,
167
- * fetch + arrayBuffer() in the browser, etc.).
168
- *
169
- * Automatically initializes any missing files (memory.md, skills/bep-authoring/SKILL.md,
170
- * standards content, baseline and v0.0 terminus) so the instance is always
171
- * fully operational after open(). Idempotent — existing files are untouched.
172
- */
173
- static async open(buffer: Uint8Array | ArrayBuffer | Buffer): Promise<Bep> {
174
- const zip = await JSZip.loadAsync(buffer)
175
- const bepJsonFile = zip.file('bep.json')
176
- if (!bepJsonFile) throw new Error('Invalid .bep file: missing bep.json')
177
- const raw = await bepJsonFile.async('string')
178
- const data = normalizeBep(JSON.parse(raw) as BEP)
179
- await Bep._initialize(data, zip)
180
- return new Bep(data, zip)
181
- }
182
-
183
- /**
184
- * Ensures all expected files exist in the zip.
185
- * Called by open() after loading bep.json. Safe to call multiple times.
186
- *
187
- * Does NOT create changelog.json — that is created on the first commit().
188
- * The v0.0 terminus snapshot (changelog/v0.0.json) is the hidden root of
189
- * the diff chain; it is never exposed as a user-facing version. The first
190
- * commit() bumps to v0.1 (patch) or v1.0 (version) and writes the inverse
191
- * diff against this terminus. The baseline is written so history.status()
192
- * and history.discard() work before the first commit.
193
- */
194
- private static async _initialize(data: BEP, zip: JSZip): Promise<void> {
195
- // Text files
196
- if (!zip.file('memory.md')) zip.file('memory.md', '')
197
- if (!zip.file('skills/bep-authoring/SKILL.md')) zip.file('skills/bep-authoring/SKILL.md', '')
198
-
199
- // Standards content files — ensure each .md referenced in bep.json exists
200
- for (const standard of data.standards) {
201
- if (!zip.file(standard.contentPath)) zip.file(standard.contentPath, '')
202
- }
203
-
204
- // Versioning bootstrap — only if no baseline exists yet
205
- // baseline/bep.json is used as the sentinel: if it's present, the zip
206
- // was already initialized (either by a previous open() or by commit()).
207
- if (!zip.file('baseline/bep.json')) {
208
- const snapshot = JSON.stringify(data, null, 2)
209
- zip.file('baseline/bep.json', snapshot)
210
- zip.file('changelog/v0.0.json', snapshot)
211
- for (const standard of data.standards) {
212
- const content = await zip.file(standard.contentPath)!.async('string')
213
- zip.file(`baseline/standards/${standard.id}.md`, content)
214
- zip.file(`changelog/standards/${standard.id}/v0.0.md`, content)
215
- }
216
- }
217
- }
218
-
219
- static create(project: Project): Bep {
220
- const data = normalizeBep({
221
- project: { name: project.name, code: project.code, clientId: project.clientId, description: project.description },
222
- roles: [],
223
- members: [],
224
- teams: [],
225
- phases: [],
226
- milestones: [],
227
- lbs: [],
228
- disciplines: [],
229
- extensions: [],
230
- assetTypes: [],
231
- softwares: [],
232
- objectives: [],
233
- bimUses: [],
234
- actions: [],
235
- events: [],
236
- effects: [],
237
- workflows: [],
238
- guides: [],
239
- annexes: [],
240
- standards: [],
241
- lods: [],
242
- lois: [],
243
- loin: [],
244
- deliverables: [],
245
- notes: [],
246
- flags: [],
247
- env: [],
248
- automations: [],
249
- } as unknown as BEP)
250
- const zip = new JSZip()
251
- // Initialize required files so the zip is fully functional from the start.
252
- // changelog.json is omitted — commit() creates it. The v0.0 terminus is the
253
- // hidden root; the first commit() bumps to v0.1 (patch) or v1.0 (version).
254
- const snapshot = JSON.stringify(data, null, 2)
255
- zip.file('memory.md', '')
256
- zip.file('skills/bep-authoring/SKILL.md', '')
257
- zip.file('baseline/bep.json', snapshot)
258
- zip.file('changelog/v0.0.json', snapshot)
259
- return new Bep(data, zip)
260
- }
261
-
262
-
263
- // ─── Accessors ────────────────────────────────────────────────────────────
264
-
265
- get data(): BEP {
266
- return this._data
267
- }
268
-
269
- // ─── Deliverable naming convention ────────────────────────────────────────
270
-
271
- getNamingConvention(): NamingConvention | undefined {
272
- return this._data.deliverableNamingConvention
273
- }
274
-
275
- /** Pass null to remove the convention and fall back to the default format. */
276
- setNamingConvention(convention: NamingConvention | null): void {
277
- if (convention === null) {
278
- delete this._data.deliverableNamingConvention
279
- return
280
- }
281
- const parsed = NamingConventionSchema.parse(convention)
282
- const errors = validateAllTokens(this._data, parsed)
283
- if (errors.length) throw new Error(`Naming convention incompatible with existing data:\n${errors.join('\n')}`)
284
- this._data.deliverableNamingConvention = parsed
285
- }
286
-
287
- // ─── File access ──────────────────────────────────────────────────────────
288
-
289
- /** Reads any text file stored inside the .bep archive by its zip path. */
290
- async readFile(path: string): Promise<string | null> {
291
- const file = this._zip.file(path)
292
- return file ? file.async('string') : null
293
- }
294
-
295
- // ─── Skills ───────────────────────────────────────────────────────────────
296
-
297
- /** Returns the names of all skills present in the archive. */
298
- listSkills(): string[] {
299
- const names = new Set<string>()
300
- this._zip.forEach((path) => {
301
- const match = path.match(/^skills\/([^/]+)\/SKILL\.md$/)
302
- if (match) names.add(match[1]!)
303
- })
304
- return [...names]
305
- }
306
-
307
- /** Returns the SKILL.md content for the given skill, or null if it does not exist. */
308
- async getSkill(name: string): Promise<string | null> {
309
- const file = this._zip.file(`skills/${name}/SKILL.md`)
310
- return file ? file.async('string') : null
311
- }
312
-
313
- /** Writes the SKILL.md content for the given skill, creating it if needed. */
314
- async setSkill(name: string, content: string): Promise<void> {
315
- this._zip.file(`skills/${name}/SKILL.md`, content)
316
- }
317
-
318
- /** Returns the names of all resource files for the given skill. */
319
- listSkillResources(name: string): string[] {
320
- const prefix = `skills/${name}/resources/`
321
- const files: string[] = []
322
- this._zip.forEach((path) => {
323
- if (path.startsWith(prefix) && path !== prefix) {
324
- files.push(path.slice(prefix.length))
325
- }
326
- })
327
- return files
328
- }
329
-
330
- /** Returns the content of a resource file for the given skill, or null if it does not exist. */
331
- async getSkillResource(name: string, filename: string): Promise<string | null> {
332
- const file = this._zip.file(`skills/${name}/resources/${filename}`)
333
- return file ? file.async('string') : null
334
- }
335
-
336
- /** Writes a resource file for the given skill, creating it if needed. */
337
- async setSkillResource(name: string, filename: string, content: string): Promise<void> {
338
- this._zip.file(`skills/${name}/resources/${filename}`, content)
339
- }
340
-
341
- /** Removes a skill's SKILL.md and all its resources from the archive. No-op if not found. */
342
- removeSkill(name: string): void {
343
- const prefix = `skills/${name}/`
344
- const toDelete: string[] = []
345
- this._zip.forEach((path) => { if (path.startsWith(prefix)) toDelete.push(path) })
346
- toDelete.forEach(path => this._zip.remove(path))
347
- }
348
-
349
- /** Removes a single resource file from a skill. No-op if not found. */
350
- removeSkillResource(name: string, filename: string): void {
351
- this._zip.remove(`skills/${name}/resources/${filename}`)
352
- }
353
-
354
- // ─── Type generation ──────────────────────────────────────────────────────
355
-
356
- /**
357
- * Generates a TypeScript declaration string with typed contracts for this BEP.
358
- * Write the output to
359
- * a `.d.ts` file to get full type safety when writing a runtime.
360
- *
361
- * @example
362
- * import { writeFileSync } from 'node:fs'
363
- * writeFileSync('bep.d.ts', bep.generateRuntimeTypes())
364
- */
365
- generateRuntimeTypes(): string {
366
- const tsType = (t: string) => t === 'url' ? 'string' : t
367
-
368
- const jsdoc = (description: string) => ` /** ${description} */\n`
369
-
370
- const inlineType = (fields: { key: string; type: string; required: boolean }[]): string =>
371
- `{ ${fields.map(f => `${f.key}${f.required ? '' : '?'}: ${tsType(f.type)}`).join('; ')} }`
372
-
373
- const effectSig = (e: { payload?: { key: string; type: string; required: boolean }[] }): string => {
374
- if (!e.payload || e.payload.length === 0) return '() => void'
375
- return `(payload: ${inlineType(e.payload)}) => void`
376
- }
377
-
378
- const automationSig = (a: { payload?: { key: string; type: string; required: boolean }[]; output: { key: string; type: string; required: boolean }[] }): string => {
379
- const param = a.payload && a.payload.length > 0 ? `payload: ${inlineType(a.payload)}` : ''
380
- const ret = a.output.length === 0
381
- ? '{ eventId: string }'
382
- : `{ eventId: string; ${a.output.map(f => `${f.key}${f.required ? '' : '?'}: ${tsType(f.type)}`).join('; ')} }`
383
- return `(${param}) => ${ret}`
384
- }
385
-
386
- const resolverSig = (r: { envKeys: string[] }): string => {
387
- if (r.envKeys.length === 0) return '(url: string) => unknown'
388
- const envType = `{ ${r.envKeys.map(k => `${k}: string`).join('; ')} }`
389
- return `(url: string, env: ${envType}) => unknown`
390
- }
391
-
392
- const effectLines = this._data.effects.length
393
- ? this._data.effects.map(e => `${jsdoc(e.description)} '${e.id}': ${effectSig(e)}`).join('\n')
394
- : ' [key: string]: () => void'
395
-
396
- const automationLines = this._data.automations.length
397
- ? this._data.automations.map(a => `${jsdoc(a.description)} '${a.id}': ${automationSig(a)}`).join('\n')
398
- : ' [key: string]: () => { eventId: string }'
399
-
400
- const resolverLines = this._data.resolvers.length
401
- ? this._data.resolvers.map(r => `${jsdoc(r.description)} '${r.id}': ${resolverSig(r)}`).join('\n')
402
- : ' [key: string]: (url: string) => unknown'
403
-
404
- const adapterLines = this._data.adapters.length
405
- ? this._data.adapters.map(a => `${jsdoc(a.description)} '${a.id}': (data: unknown) => unknown`).join('\n')
406
- : ' [key: string]: (data: unknown) => unknown'
407
-
408
- return [
409
- '// Generated by bep.generateRuntimeTypes() — do not edit manually',
410
- '',
411
- '// ─── Effects ──────────────────────────────────────────────────────────────────',
412
- '',
413
- 'export interface BepEffects {',
414
- effectLines,
415
- '}',
416
- '',
417
- '// ─── Automations ─────────────────────────────────────────────────────────────',
418
- '',
419
- 'export interface BepAutomations {',
420
- automationLines,
421
- '}',
422
- '',
423
- '// ─── Resolvers ────────────────────────────────────────────────────────────────',
424
- '',
425
- 'export interface BepResolvers {',
426
- resolverLines,
427
- '}',
428
- '',
429
- '// ─── Adapters ─────────────────────────────────────────────────────────────────',
430
- '',
431
- 'export interface BepAdapters {',
432
- adapterLines,
433
- '}',
434
- '',
435
- '// ─── Combined ─────────────────────────────────────────────────────────────────',
436
- '',
437
- 'export interface BepTypes {',
438
- ' effects: BepEffects',
439
- ' automations: BepAutomations',
440
- ' resolvers: BepResolvers',
441
- ' adapters: BepAdapters',
442
- '}',
443
- '',
444
- ].join('\n')
445
- }
446
-
447
- // ─── Serialization ────────────────────────────────────────────────────────
448
-
449
- /**
450
- * Serializes the .bep archive to a Uint8Array.
451
- * The caller is responsible for persisting it (fs.writeFile in Node,
452
- * a download link in the browser, etc.).
453
- */
454
- async save(): Promise<Uint8Array> {
455
- this._zip.file('bep.json', JSON.stringify(this._data, null, 2))
456
- return this._zip.generateAsync({ type: 'uint8array' })
457
- }
458
- }
459
-
460
- export * from "./base"
461
- export * from './entities'
462
- export * from './utils'
463
- export * from './types'
464
- export * from './runtime'