@baselineos/frame 0.1.0

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/src/system.ts ADDED
@@ -0,0 +1,677 @@
1
+ /**
2
+ * Baseline Frame System
3
+ *
4
+ * The context and control layer of the Baseline Protocol that manages
5
+ * intent recognition, mode switching, environment context, and authority
6
+ * management.
7
+ *
8
+ * @license Apache-2.0
9
+ */
10
+
11
+ import frameSystemConfig from './config/frame-system-config.json' with { type: 'json' };
12
+
13
+ // ─── Types ──────────────────────────────────────────────────────────
14
+
15
+ export interface FrameSystemConfig {
16
+ system: { name: string; version: string; description: string };
17
+ modes: Record<string, ModeConfig>;
18
+ contexts: Record<string, ContextConfig>;
19
+ authorities: Record<string, AuthorityConfig>;
20
+ environments?: Record<string, EnvironmentEntry>;
21
+ }
22
+
23
+ export interface ModeConfig {
24
+ description: string;
25
+ permissions: string[];
26
+ environment: string;
27
+ features: string[];
28
+ }
29
+
30
+ export interface ContextConfig {
31
+ description: string;
32
+ mode: string;
33
+ environment: string;
34
+ permissions: string[];
35
+ authority?: string;
36
+ }
37
+
38
+ export interface AuthorityConfig {
39
+ level: number;
40
+ permissions: string[];
41
+ description: string;
42
+ }
43
+
44
+ export interface ContextEntry {
45
+ name: string;
46
+ description: string;
47
+ mode: string;
48
+ environment: string;
49
+ permissions: string[];
50
+ authority: string;
51
+ status: 'active' | 'inactive' | 'archived';
52
+ createdAt: number;
53
+ updatedAt: number;
54
+ lastActivatedAt?: number;
55
+ archivedAt?: number;
56
+ }
57
+
58
+ export interface ModeEntry {
59
+ name: string;
60
+ description: string;
61
+ permissions: string[];
62
+ environment: string;
63
+ features: string[];
64
+ }
65
+
66
+ export interface AuthorityEntry {
67
+ name: string;
68
+ level: number;
69
+ permissions: string[];
70
+ description: string;
71
+ }
72
+
73
+ export interface EnvironmentEntry {
74
+ name: string;
75
+ type: string;
76
+ description: string;
77
+ variables: Record<string, string>;
78
+ features?: string[];
79
+ }
80
+
81
+ export interface FrameCommandResult {
82
+ success: boolean;
83
+ command?: string;
84
+ context?: string;
85
+ mode?: string | ModeEntry | null;
86
+ authority?: string;
87
+ environment?: string;
88
+ result?: unknown;
89
+ error?: string;
90
+ details?: string;
91
+ required?: string[];
92
+ current?: string;
93
+ available?: string[];
94
+ description?: string;
95
+ permissions?: string[] | { context: string[]; mode: string[] };
96
+ timestamp?: string;
97
+ }
98
+
99
+ export interface FrameStatus {
100
+ initialized: boolean;
101
+ contextHistory: number;
102
+ currentMode: ModeEntry | null;
103
+ currentEnvironment: string | undefined;
104
+ activeContexts: number;
105
+ systemName: string;
106
+ version: string;
107
+ currentAuthority?: string | null;
108
+ }
109
+
110
+ function extractRequiredPermissions(options: Record<string, unknown>): string[] | null {
111
+ const candidate = options.requiredPermissions;
112
+ if (!Array.isArray(candidate)) {
113
+ return null;
114
+ }
115
+ if (candidate.every(permission => typeof permission === 'string')) {
116
+ return candidate;
117
+ }
118
+ return null;
119
+ }
120
+
121
+ // ─── Context Manager ────────────────────────────────────────────────
122
+
123
+ export class ContextManager {
124
+ private contexts = new Map<string, ContextEntry>();
125
+ private currentContext: ContextEntry | null = null;
126
+ private history: Array<{ name: string; action: 'create' | 'activate' | 'archive'; timestamp: number }> = [];
127
+
128
+ initialize(contextConfig: Record<string, ContextConfig>): void {
129
+ for (const [name, config] of Object.entries(contextConfig)) {
130
+ this.contexts.set(name, {
131
+ name,
132
+ description: config.description,
133
+ mode: config.mode,
134
+ environment: config.environment,
135
+ permissions: config.permissions,
136
+ authority: config.authority || 'user',
137
+ status: 'inactive',
138
+ createdAt: Date.now(),
139
+ updatedAt: Date.now(),
140
+ });
141
+ }
142
+ }
143
+
144
+ createContext(name: string, config: ContextConfig): boolean {
145
+ if (this.contexts.has(name)) return false;
146
+ this.contexts.set(name, {
147
+ name,
148
+ description: config.description,
149
+ mode: config.mode,
150
+ environment: config.environment,
151
+ permissions: config.permissions,
152
+ authority: config.authority || 'user',
153
+ status: 'inactive',
154
+ createdAt: Date.now(),
155
+ updatedAt: Date.now(),
156
+ });
157
+ this.history.push({ name, action: 'create', timestamp: Date.now() });
158
+ return true;
159
+ }
160
+
161
+ setContext(contextName: string): boolean {
162
+ return this.activateContext(contextName);
163
+ }
164
+
165
+ activateContext(contextName: string): boolean {
166
+ const ctx = this.contexts.get(contextName);
167
+ if (!ctx || ctx.status === 'archived') return false;
168
+ // deactivate current
169
+ if (this.currentContext) {
170
+ this.currentContext.status = 'inactive';
171
+ this.currentContext.updatedAt = Date.now();
172
+ }
173
+ ctx.status = 'active';
174
+ ctx.updatedAt = Date.now();
175
+ ctx.lastActivatedAt = Date.now();
176
+ this.currentContext = ctx;
177
+ this.history.push({ name: contextName, action: 'activate', timestamp: Date.now() });
178
+ return true;
179
+ }
180
+
181
+ archiveContext(contextName: string): boolean {
182
+ const ctx = this.contexts.get(contextName);
183
+ if (!ctx) return false;
184
+ ctx.status = 'archived';
185
+ ctx.archivedAt = Date.now();
186
+ ctx.updatedAt = Date.now();
187
+ if (this.currentContext?.name === contextName) {
188
+ this.currentContext = null;
189
+ }
190
+ this.history.push({ name: contextName, action: 'archive', timestamp: Date.now() });
191
+ return true;
192
+ }
193
+
194
+ getCurrentContext(): ContextEntry | null {
195
+ return this.currentContext;
196
+ }
197
+
198
+ getContext(contextName: string): ContextEntry | undefined {
199
+ return this.contexts.get(contextName);
200
+ }
201
+
202
+ listContexts(): string[] {
203
+ return Array.from(this.contexts.keys());
204
+ }
205
+
206
+ getContextHistory(): string[] {
207
+ return this.history.map(item => item.name);
208
+ }
209
+
210
+ getActiveContexts(): ContextEntry[] {
211
+ return this.currentContext ? [this.currentContext] : [];
212
+ }
213
+
214
+ getContextTimeline(): Array<{ name: string; action: 'create' | 'activate' | 'archive'; timestamp: number }> {
215
+ return [...this.history];
216
+ }
217
+ }
218
+
219
+ // ─── Mode Manager ───────────────────────────────────────────────────
220
+
221
+ export class ModeManager {
222
+ private modes = new Map<string, ModeEntry>();
223
+ private currentMode: ModeEntry | null = null;
224
+
225
+ initialize(modeConfig: Record<string, ModeConfig>): void {
226
+ for (const [name, config] of Object.entries(modeConfig)) {
227
+ this.modes.set(name, {
228
+ name,
229
+ description: config.description,
230
+ permissions: config.permissions,
231
+ environment: config.environment,
232
+ features: config.features,
233
+ });
234
+ }
235
+ }
236
+
237
+ setMode(modeName: string): boolean {
238
+ if (this.modes.has(modeName)) {
239
+ this.currentMode = this.modes.get(modeName)!;
240
+ return true;
241
+ }
242
+ return false;
243
+ }
244
+
245
+ getCurrentMode(): ModeEntry | null {
246
+ return this.currentMode;
247
+ }
248
+
249
+ getMode(modeName: string): ModeEntry | undefined {
250
+ return this.modes.get(modeName);
251
+ }
252
+
253
+ processInMode(
254
+ modeName: string,
255
+ command: string,
256
+ options: Record<string, unknown>,
257
+ args: string[],
258
+ ): Record<string, unknown> {
259
+ const mode = this.modes.get(modeName);
260
+ if (!mode) {
261
+ throw new Error(`Mode "${modeName}" not found`);
262
+ }
263
+
264
+ return {
265
+ mode: modeName,
266
+ command,
267
+ options,
268
+ arguments: args,
269
+ permissions: mode.permissions,
270
+ environment: mode.environment,
271
+ result: `Command executed in ${modeName} mode`,
272
+ };
273
+ }
274
+ }
275
+
276
+ // ─── Authority Manager ──────────────────────────────────────────────
277
+
278
+ export class AuthorityManager {
279
+ private authorities = new Map<string, AuthorityEntry>();
280
+ private currentAuthority: AuthorityEntry | null = null;
281
+
282
+ initialize(authorityConfig: Record<string, AuthorityConfig>): void {
283
+ for (const [name, config] of Object.entries(authorityConfig)) {
284
+ this.authorities.set(name, {
285
+ name,
286
+ level: config.level,
287
+ permissions: config.permissions,
288
+ description: config.description,
289
+ });
290
+ }
291
+ this.currentAuthority = this.authorities.get('user') || null;
292
+ }
293
+
294
+ getCurrentAuthority(): AuthorityEntry | null {
295
+ return this.currentAuthority;
296
+ }
297
+
298
+ setAuthority(authorityName: string): boolean {
299
+ if (this.authorities.has(authorityName)) {
300
+ this.currentAuthority = this.authorities.get(authorityName)!;
301
+ return true;
302
+ }
303
+ return false;
304
+ }
305
+
306
+ checkPermission(
307
+ authorityName: string,
308
+ command: string,
309
+ options: Record<string, unknown>,
310
+ ): boolean {
311
+ const authority = this.authorities.get(authorityName);
312
+ if (!authority) return false;
313
+ const required = this.getRequiredPermissions(command, options);
314
+ return required.every(perm => authority.permissions.includes(perm));
315
+ }
316
+
317
+ getRequiredPermissions(command: string, options?: Record<string, unknown>): string[] {
318
+ if (options) {
319
+ const fromOptions = extractRequiredPermissions(options);
320
+ if (fromOptions) {
321
+ return fromOptions;
322
+ }
323
+ }
324
+
325
+ const cmd = command.toLowerCase();
326
+ if (cmd.includes('admin') || cmd.includes('system') || cmd.includes('override')) {
327
+ return ['admin'];
328
+ }
329
+ if (cmd.includes('deploy')) {
330
+ return ['deploy'];
331
+ }
332
+ if (cmd.includes('write') || cmd.includes('create') || cmd.includes('set') || cmd.includes('update') || cmd.includes('archive')) {
333
+ return ['write'];
334
+ }
335
+ if (cmd.includes('run') || cmd.includes('execute') || cmd.includes('start')) {
336
+ return ['execute'];
337
+ }
338
+ return ['read'];
339
+ }
340
+ }
341
+
342
+ // ─── Environment Manager ────────────────────────────────────────────
343
+
344
+ export class EnvironmentManager {
345
+ private environments = new Map<string, EnvironmentEntry>();
346
+ private currentEnvironment: EnvironmentEntry | null = null;
347
+
348
+ initialize(envConfig?: Record<string, EnvironmentEntry>): void {
349
+ if (envConfig && Object.keys(envConfig).length > 0) {
350
+ for (const [name, env] of Object.entries(envConfig)) {
351
+ this.environments.set(name, env);
352
+ }
353
+ this.currentEnvironment = this.environments.values().next().value ?? null;
354
+ return;
355
+ }
356
+
357
+ this.environments.set('dev', {
358
+ name: 'dev',
359
+ type: 'development',
360
+ description: 'Development environment',
361
+ variables: { NODE_ENV: 'development', DEBUG: 'true', LOG_LEVEL: 'debug' },
362
+ });
363
+
364
+ this.environments.set('prod', {
365
+ name: 'prod',
366
+ type: 'production',
367
+ description: 'Production environment',
368
+ variables: { NODE_ENV: 'production', DEBUG: 'false', LOG_LEVEL: 'info' },
369
+ });
370
+
371
+ this.environments.set('test', {
372
+ name: 'test',
373
+ type: 'testing',
374
+ description: 'Testing environment',
375
+ variables: { NODE_ENV: 'test', DEBUG: 'true', LOG_LEVEL: 'debug' },
376
+ });
377
+
378
+ this.currentEnvironment = this.environments.get('dev') || null;
379
+ }
380
+
381
+ getCurrentEnvironment(): EnvironmentEntry | null {
382
+ return this.currentEnvironment;
383
+ }
384
+
385
+ setEnvironment(envName: string): boolean {
386
+ if (this.environments.has(envName)) {
387
+ this.currentEnvironment = this.environments.get(envName)!;
388
+ return true;
389
+ }
390
+ return false;
391
+ }
392
+
393
+ getEnvironmentVariable(name: string): string | undefined {
394
+ return this.currentEnvironment?.variables[name];
395
+ }
396
+ }
397
+
398
+ // ─── Baseline Frame System ──────────────────────────────────────────
399
+
400
+ export class BaselineFrameSystem {
401
+ private config: FrameSystemConfig;
402
+ private context: ContextManager;
403
+ private modeManager: ModeManager;
404
+ private authorityManager: AuthorityManager;
405
+ private environmentManager: EnvironmentManager;
406
+ private initialized = false;
407
+
408
+ constructor() {
409
+ this.config = this.loadConfiguration();
410
+ this.context = new ContextManager();
411
+ this.modeManager = new ModeManager();
412
+ this.authorityManager = new AuthorityManager();
413
+ this.environmentManager = new EnvironmentManager();
414
+ this.initializeSystem();
415
+ }
416
+
417
+ private loadConfiguration(): FrameSystemConfig {
418
+ const cfg = frameSystemConfig as {
419
+ system?: Record<string, string>;
420
+ modes?: Record<string, { description?: string; permissions?: string[]; environment?: string; features?: string[] }>;
421
+ contexts?: Record<string, { description?: string; mode?: string; environment?: string; permissions?: string[] }>;
422
+ authorities?: Record<string, { level?: number; permissions?: string[]; description?: string }>;
423
+ environments?: Record<string, EnvironmentEntry>;
424
+ };
425
+
426
+ const modes: FrameSystemConfig['modes'] = {};
427
+ for (const [name, mode] of Object.entries(cfg.modes ?? {})) {
428
+ modes[name] = {
429
+ description: mode.description ?? '',
430
+ permissions: mode.permissions ?? [],
431
+ environment: mode.environment ?? 'dev',
432
+ features: mode.features ?? [],
433
+ };
434
+ }
435
+
436
+ const contexts: FrameSystemConfig['contexts'] = {};
437
+ for (const [name, ctx] of Object.entries(cfg.contexts ?? {})) {
438
+ contexts[name] = {
439
+ description: ctx.description ?? '',
440
+ mode: ctx.mode ?? 'development',
441
+ environment: ctx.environment ?? 'dev',
442
+ permissions: ctx.permissions ?? [],
443
+ };
444
+ }
445
+
446
+ const authorities: FrameSystemConfig['authorities'] = {};
447
+ for (const [name, auth] of Object.entries(cfg.authorities ?? {})) {
448
+ authorities[name] = {
449
+ level: auth.level ?? 1,
450
+ permissions: auth.permissions ?? [],
451
+ description: auth.description ?? '',
452
+ };
453
+ }
454
+
455
+ return {
456
+ system: {
457
+ name: cfg.system?.name ?? 'Baseline Frame System',
458
+ version: cfg.system?.version ?? '1.0.0',
459
+ description: cfg.system?.description ?? 'Context and control layer for Baseline Protocol',
460
+ },
461
+ modes,
462
+ contexts,
463
+ authorities,
464
+ environments: cfg.environments ?? {},
465
+ };
466
+ }
467
+
468
+ private initializeSystem(): void {
469
+ this.context.initialize(this.config.contexts);
470
+ this.modeManager.initialize(this.config.modes);
471
+ this.authorityManager.initialize(this.config.authorities);
472
+ this.environmentManager.initialize(this.config.environments);
473
+ this.context.setContext('default');
474
+
475
+ const defaultContext = this.context.getCurrentContext();
476
+ if (defaultContext?.mode) {
477
+ this.modeManager.setMode(defaultContext.mode);
478
+ } else {
479
+ this.modeManager.setMode('development');
480
+ }
481
+
482
+ if (defaultContext?.authority) {
483
+ this.authorityManager.setAuthority(defaultContext.authority);
484
+ }
485
+
486
+ if (defaultContext?.environment) {
487
+ this.environmentManager.setEnvironment(defaultContext.environment);
488
+ }
489
+
490
+ this.initialized = true;
491
+ }
492
+
493
+ processCommand(
494
+ command: string,
495
+ options: Record<string, unknown> = {},
496
+ args: string[] = [],
497
+ ): FrameCommandResult {
498
+ try {
499
+ const currentContext = this.context.getCurrentContext();
500
+ if (!currentContext) {
501
+ return { success: false, error: 'No context set' };
502
+ }
503
+
504
+ const hasPermission = this.authorityManager.checkPermission(
505
+ currentContext.authority,
506
+ command,
507
+ options,
508
+ );
509
+
510
+ if (!hasPermission) {
511
+ return {
512
+ success: false,
513
+ error: 'Insufficient permissions for this command',
514
+ context: currentContext.name,
515
+ required: this.authorityManager.getRequiredPermissions(command),
516
+ current: currentContext.authority,
517
+ };
518
+ }
519
+
520
+ const requiredPermissions = this.authorityManager.getRequiredPermissions(command, options);
521
+ const currentMode = this.modeManager.getCurrentMode();
522
+ const modePermissions = currentMode?.permissions ?? [];
523
+ const contextPermissions = currentContext.permissions ?? [];
524
+ const missingFromContext = requiredPermissions.filter(p => !contextPermissions.includes(p));
525
+ const missingFromMode = requiredPermissions.filter(p => !modePermissions.includes(p));
526
+
527
+ if (missingFromContext.length > 0 || missingFromMode.length > 0) {
528
+ return {
529
+ success: false,
530
+ error: 'Permission denied by context/mode',
531
+ context: currentContext.name,
532
+ required: requiredPermissions,
533
+ current: currentContext.authority,
534
+ permissions: {
535
+ context: contextPermissions,
536
+ mode: modePermissions,
537
+ },
538
+ };
539
+ }
540
+
541
+ const result = this.modeManager.processInMode(
542
+ currentContext.mode,
543
+ command,
544
+ options,
545
+ args,
546
+ );
547
+
548
+ return {
549
+ success: true,
550
+ command,
551
+ context: currentContext.name,
552
+ mode: currentContext.mode,
553
+ result,
554
+ timestamp: new Date().toISOString(),
555
+ };
556
+ } catch (error) {
557
+ const msg = error instanceof Error ? error.message : String(error);
558
+ return {
559
+ success: false,
560
+ error: 'Command processing failed',
561
+ details: msg,
562
+ context: this.context.getCurrentContext()?.name || 'unknown',
563
+ };
564
+ }
565
+ }
566
+
567
+ switchContext(contextName: string): FrameCommandResult {
568
+ const target = this.context.getContext(contextName);
569
+ if (!target || target.status === 'archived') {
570
+ return {
571
+ success: false,
572
+ error: `Context "${contextName}" not found`,
573
+ available: Object.keys(this.config.contexts),
574
+ };
575
+ }
576
+
577
+ const mode = this.modeManager.getMode(target.mode);
578
+ if (!mode) {
579
+ return {
580
+ success: false,
581
+ error: `Mode "${target.mode}" not found`,
582
+ available: Object.keys(this.config.modes),
583
+ };
584
+ }
585
+
586
+ if (mode.environment !== target.environment) {
587
+ return {
588
+ success: false,
589
+ error: `Context environment "${target.environment}" does not match mode environment "${mode.environment}"`,
590
+ };
591
+ }
592
+
593
+ const success = this.context.activateContext(contextName);
594
+ if (!success) {
595
+ return {
596
+ success: false,
597
+ error: `Context "${contextName}" not found`,
598
+ available: Object.keys(this.config.contexts),
599
+ };
600
+ }
601
+
602
+ const newContext = this.context.getCurrentContext()!;
603
+ this.authorityManager.setAuthority(newContext.authority);
604
+ this.modeManager.setMode(newContext.mode);
605
+ this.environmentManager.setEnvironment(newContext.environment);
606
+
607
+ return {
608
+ success: true,
609
+ context: newContext.name,
610
+ mode: newContext.mode,
611
+ authority: newContext.authority,
612
+ environment: newContext.environment,
613
+ };
614
+ }
615
+
616
+ switchMode(modeName: string): FrameCommandResult {
617
+ const currentMode = this.modeManager.getCurrentMode();
618
+ const success = this.modeManager.setMode(modeName);
619
+
620
+ if (!success) {
621
+ return {
622
+ success: false,
623
+ error: `Mode "${modeName}" not found`,
624
+ available: Object.keys(this.config.modes),
625
+ };
626
+ }
627
+
628
+ const newMode = this.modeManager.getCurrentMode()!;
629
+ const currentContext = this.context.getCurrentContext();
630
+ if (currentContext && currentContext.environment !== newMode.environment) {
631
+ // revert
632
+ if (currentMode) this.modeManager.setMode(currentMode.name);
633
+ return {
634
+ success: false,
635
+ error: `Mode environment "${newMode.environment}" does not match context environment "${currentContext.environment}"`,
636
+ };
637
+ }
638
+
639
+ this.environmentManager.setEnvironment(newMode.environment);
640
+ return {
641
+ success: true,
642
+ mode: newMode,
643
+ description: newMode.description,
644
+ permissions: newMode.permissions,
645
+ environment: newMode.environment,
646
+ };
647
+ }
648
+
649
+ getStatus(): FrameStatus {
650
+ return {
651
+ initialized: this.initialized,
652
+ contextHistory: this.context.getContextHistory().length,
653
+ currentMode: this.modeManager.getCurrentMode(),
654
+ currentEnvironment: this.environmentManager.getCurrentEnvironment()?.name,
655
+ activeContexts: this.context.getActiveContexts().length,
656
+ systemName: this.config.system.name,
657
+ version: this.config.system.version,
658
+ currentAuthority: this.authorityManager.getCurrentAuthority()?.name ?? null,
659
+ };
660
+ }
661
+
662
+ getContextManager(): ContextManager {
663
+ return this.context;
664
+ }
665
+
666
+ getModeManager(): ModeManager {
667
+ return this.modeManager;
668
+ }
669
+
670
+ getAuthorityManager(): AuthorityManager {
671
+ return this.authorityManager;
672
+ }
673
+
674
+ getEnvironmentManager(): EnvironmentManager {
675
+ return this.environmentManager;
676
+ }
677
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src/**/*.ts"],
8
+ "exclude": ["node_modules", "dist", "**/*.test.ts"]
9
+ }