guardian-framework 0.1.25 → 0.1.26

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/cli.js CHANGED
@@ -1335,7 +1335,7 @@ __export(exports_package, {
1335
1335
  bin: () => bin,
1336
1336
  author: () => author
1337
1337
  });
1338
- var name = "guardian-framework", version = "0.1.25", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1338
+ var name = "guardian-framework", version = "0.1.26", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
1339
1339
  var init_package = __esm(() => {
1340
1340
  exports = {
1341
1341
  ".": {
@@ -9821,6 +9821,115 @@ Respond with ONLY valid JSON matching this exact structure. Do not include markd
9821
9821
  "aggregateRoots": "Which entities are aggregate roots and why"
9822
9822
  }`;
9823
9823
  }
9824
+ function buildFrontendExplorationPrompt(context) {
9825
+ const sanitized = sanitizeBusinessContext(context);
9826
+ return `You are a frontend architecture expert. Analyze the following web application description and extract a structured model focused on user experience, UI concepts, and design principles.
9827
+
9828
+ Business Context:
9829
+ ${sanitized}
9830
+
9831
+ Respond with ONLY valid JSON matching this exact structure. Do not include markdown formatting, code fences, or explanatory text:
9832
+
9833
+ {
9834
+ "sessionId": "auto-generated-uuid",
9835
+ "businessContext": "original description",
9836
+ "status": "draft",
9837
+ "actors": [
9838
+ {
9839
+ "name": "UserRole",
9840
+ "description": "Who this user is",
9841
+ "interactions": "What they do in the application"
9842
+ }
9843
+ ],
9844
+ "functionalRequirements": [
9845
+ {
9846
+ "id": "FR-001",
9847
+ "requirement": "The user shall be able to...",
9848
+ "priority": "critical|high|medium|low",
9849
+ "boundedContext": "FeatureName"
9850
+ }
9851
+ ],
9852
+ "nonFunctionalRequirements": [
9853
+ {
9854
+ "id": "NFR-001",
9855
+ "requirement": "The application shall...",
9856
+ "category": "performance|accessibility|usability|security|maintainability",
9857
+ "target": "Specific measurable target"
9858
+ }
9859
+ ],
9860
+ "assumptions": [
9861
+ {
9862
+ "assumption": "We assume that...",
9863
+ "impactIfWrong": "What breaks if this is false",
9864
+ "mitigation": "How we handle it being wrong"
9865
+ }
9866
+ ],
9867
+ "boundedContexts": [
9868
+ {
9869
+ "name": "FeatureName",
9870
+ "description": "Brief description of this app feature/section",
9871
+ "entities": ["UIConcept1", "UIConcept2"]
9872
+ }
9873
+ ],
9874
+ "entities": [
9875
+ {
9876
+ "name": "UIConceptName",
9877
+ "context": "FeatureName",
9878
+ "type": "ui-concept | user-intent | design-token | app-shell | value-object",
9879
+ "description": "What this UI concept represents"
9880
+ }
9881
+ ],
9882
+ "userIntents": [
9883
+ {
9884
+ "name": "UserIntentName",
9885
+ "context": "FeatureName",
9886
+ "description": "What the user is trying to do",
9887
+ "triggeredBy": "What UI action triggers this intent"
9888
+ }
9889
+ ],
9890
+ "designPrinciples": [
9891
+ {
9892
+ "principle": "The application is...",
9893
+ "description": "What this principle means in practice",
9894
+ "rationale": "Why this principle exists"
9895
+ }
9896
+ ],
9897
+ "navigationPhilosophy": {
9898
+ "contextPreservation": "How the user never loses context",
9899
+ "deepLinking": "How every page is deep-linkable",
9900
+ "multiTab": "How multiple tabs are supported"
9901
+ },
9902
+ "appShell": {
9903
+ "navigation": "Navigation structure",
9904
+ "header": "Header content",
9905
+ "sidebar": "Sidebar content",
9906
+ "commandPalette": "Command palette actions",
9907
+ "globalSearch": "Global search behavior"
9908
+ },
9909
+ "degradationStrategy": [
9910
+ {
9911
+ "feature": "FeatureName",
9912
+ "whenUnavailable": "What happens when this feature's API is down",
9913
+ "degradesTo": "What still works"
9914
+ }
9915
+ ],
9916
+ "ubiquitousLanguage": [
9917
+ {
9918
+ "term": "CanonicalTerm",
9919
+ "definition": "Clear definition",
9920
+ "boundedContext": "FeatureName",
9921
+ "aliases": ["AlternativeName1"],
9922
+ "examples": "Usage example"
9923
+ }
9924
+ ],
9925
+ "openQuestions": "Any open questions about the application",
9926
+ "designSystem": {
9927
+ "componentLibrary": "Which component library or approach (Tailwind, MUI, custom)",
9928
+ "theming": "How theming works (dark mode, branding)",
9929
+ "accessibility": "Accessibility requirements"
9930
+ }
9931
+ }`;
9932
+ }
9824
9933
  function parseExplorationResponse(rawResponse, sessionId) {
9825
9934
  try {
9826
9935
  let cleaned = rawResponse.trim();
@@ -9902,6 +10011,14 @@ function coerceEntityType(val) {
9902
10011
  return "value-object";
9903
10012
  if (val === "aggregate-root")
9904
10013
  return "aggregate-root";
10014
+ if (val === "ui-concept")
10015
+ return "ui-concept";
10016
+ if (val === "user-intent")
10017
+ return "user-intent";
10018
+ if (val === "design-token")
10019
+ return "design-token";
10020
+ if (val === "app-shell")
10021
+ return "app-shell";
9905
10022
  return "entity";
9906
10023
  }
9907
10024
  function coerceFrPriority(val) {
@@ -9986,8 +10103,20 @@ async function exploreDomain(context, options) {
9986
10103
  if (!fs.existsSync(explorationDir)) {
9987
10104
  fs.mkdirSync(explorationDir, { recursive: true });
9988
10105
  }
10106
+ let lang = options?.language;
10107
+ if (!lang) {
10108
+ try {
10109
+ const manifestPath = path.join(projectDir, "guardian-manifest.json");
10110
+ if (fs.existsSync(manifestPath)) {
10111
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
10112
+ if (manifest.language)
10113
+ lang = manifest.language;
10114
+ }
10115
+ } catch {}
10116
+ }
9989
10117
  const sanitized = sanitizeBusinessContext(context);
9990
- const prompt = buildExplorationPrompt(sanitized);
10118
+ const isFrontend = lang === "nextjs" || lang === "angular";
10119
+ const prompt = isFrontend ? buildFrontendExplorationPrompt(sanitized) : buildExplorationPrompt(sanitized);
9991
10120
  const promptContent = [
9992
10121
  "# Domain Exploration Prompt",
9993
10122
  "",
@@ -10140,6 +10269,18 @@ function extractTable(body, sectionName) {
10140
10269
  function scaffoldFromExploration(sessionId, options) {
10141
10270
  const projectDir = options?.projectDir ?? process.cwd();
10142
10271
  const dryRun = options?.dryRun ?? false;
10272
+ let lang = options?.language;
10273
+ if (!lang) {
10274
+ try {
10275
+ const manifestPath = path.join(projectDir, "guardian-manifest.json");
10276
+ if (fs.existsSync(manifestPath)) {
10277
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf-8"));
10278
+ if (manifest.language)
10279
+ lang = manifest.language;
10280
+ }
10281
+ } catch {}
10282
+ }
10283
+ const isFrontend = lang === "nextjs" || lang === "angular";
10143
10284
  const sessionResult = readExplorationSession(sessionId, projectDir);
10144
10285
  if (!sessionResult) {
10145
10286
  throw new Error(`Exploration session not found: ${sessionId}`);
@@ -10261,76 +10402,239 @@ function scaffoldFromExploration(sessionId, options) {
10261
10402
  `;
10262
10403
  }
10263
10404
  }
10264
- let content = `# ${bc.name}
10405
+ let content = "";
10406
+ if (isFrontend) {
10407
+ const uiConcepts = contextEntities.filter((e2) => e2.type === "ui-concept");
10408
+ const userIntents = contextEntities.filter((e2) => e2.type === "user-intent");
10409
+ const designTokens = contextEntities.filter((e2) => e2.type === "design-token");
10410
+ const appShells = contextEntities.filter((e2) => e2.type === "app-shell");
10411
+ content = `# ${bc.name}
10265
10412
 
10266
10413
  `;
10267
- content += `## Module Status
10414
+ content += `## Module Status
10268
10415
 
10269
10416
  `;
10270
- content += `**Status:** Planned
10417
+ content += `**Status:** Planned
10271
10418
  `;
10272
- content += `**Last reviewed:** ${timestamp}
10419
+ content += `**Last reviewed:** ${timestamp}
10273
10420
  `;
10274
- content += `**Source session:** ${sessionId}
10421
+ content += `**Source session:** ${sessionId}
10275
10422
 
10276
10423
  `;
10277
- content += `## Description
10424
+ content += `## Description
10278
10425
 
10279
10426
  ${bc.description}
10280
10427
 
10281
10428
  `;
10282
- content += `## Components
10429
+ content += `## UI Concepts
10283
10430
 
10284
- ${componentsSection}
10285
10431
  `;
10286
- content += `## Domain Events
10432
+ if (uiConcepts.length === 0) {
10433
+ content += `None defined yet.
10287
10434
 
10288
10435
  `;
10289
- if (contextEvents.length === 0) {
10290
- content += `None defined yet.
10436
+ } else {
10437
+ for (const uc of uiConcepts) {
10438
+ content += `### ${uc.name}
10439
+ `;
10440
+ content += `**Description:** ${uc.description}
10291
10441
 
10292
10442
  `;
10293
- } else {
10294
- for (const ev of contextEvents) {
10295
- content += `- **${ev.name}** - ${ev.description} (triggered by: ${ev.triggeredBy})
10443
+ }
10444
+ }
10445
+ content += `## User Intents
10446
+
10296
10447
  `;
10448
+ if (userIntents.length === 0) {
10449
+ content += `None defined yet.
10450
+
10451
+ `;
10452
+ } else {
10453
+ for (const ui of userIntents) {
10454
+ content += `### ${ui.name}
10455
+ `;
10456
+ content += `**Description:** ${ui.description}
10457
+
10458
+ `;
10459
+ }
10297
10460
  }
10461
+ if (designTokens.length > 0) {
10462
+ content += `## Design Tokens
10463
+
10464
+ `;
10465
+ for (const dt of designTokens) {
10466
+ content += `- **${dt.name}** - ${dt.description}
10467
+ `;
10468
+ }
10469
+ content += `
10470
+ `;
10471
+ }
10472
+ if (appShells.length > 0) {
10473
+ content += `## App Shell Integration
10474
+
10475
+ `;
10476
+ for (const as of appShells) {
10477
+ content += `- **${as.name}** - ${as.description}
10478
+ `;
10479
+ }
10480
+ content += `
10481
+ `;
10482
+ }
10483
+ content += `## Design Principles
10484
+
10485
+ `;
10486
+ content += `- The Web application is not responsible for enforcing business rules.
10487
+ `;
10488
+ content += `- The Web application is optimistic.
10489
+ `;
10490
+ content += `- The Web application is resilient.
10491
+ `;
10492
+ content += `- The Web application is accessible.
10493
+ `;
10494
+ content += `- The Web application is stateless whenever possible.
10495
+ `;
10496
+ content += `- The Web application delegates authority to Enterprise.
10497
+ `;
10498
+ content += `- The Web application enhances productivity rather than exposing implementation details.
10499
+ `;
10298
10500
  content += `
10299
10501
  `;
10300
- }
10301
- content += `## Ubiquitous Language
10502
+ content += `## Navigation Philosophy
10503
+
10504
+ `;
10505
+ content += `- The user shall never lose context.
10506
+ `;
10507
+ content += `- Every screen belongs to a Brain. Every Brain belongs to a Workspace.
10508
+ `;
10509
+ content += `- Every action should expose the current path.
10510
+ `;
10511
+ content += `- Deep linking shall exist for every page.
10512
+ `;
10513
+ content += `- Browser navigation shall always work.
10514
+ `;
10515
+ content += `- Multiple tabs shall be supported.
10516
+ `;
10517
+ content += `
10518
+ `;
10519
+ content += `## Degradation Strategy
10520
+
10521
+ `;
10522
+ content += `- If a feature API is unavailable, navigation still works.
10523
+ `;
10524
+ content += `- Editing still works.
10525
+ `;
10526
+ content += `- AI features are disabled gracefully, not causing errors.
10527
+ `;
10528
+ content += `- The application renders a degraded UI instead of crashing.
10529
+ `;
10530
+ content += `
10531
+ `;
10532
+ content += `## Ubiquitous Language
10302
10533
 
10303
10534
  `;
10304
- if (contextTerms.length === 0) {
10305
- content += `None defined yet.
10535
+ if (contextTerms.length === 0) {
10536
+ content += `None defined yet.
10537
+
10538
+ `;
10539
+ } else {
10540
+ content += `| Term | Definition | Aliases |
10541
+ `;
10542
+ content += `|------|-----------|---------|
10543
+ `;
10544
+ for (const t of contextTerms) {
10545
+ content += `| ${t.term} | ${t.definition} | ${t.aliases.join(", ")} |
10546
+ `;
10547
+ }
10548
+ content += `
10549
+ `;
10550
+ }
10551
+ content += `## Dependencies
10552
+
10553
+ `;
10554
+ content += `${depsSection}
10555
+ `;
10556
+ content += `## Key Files
10557
+
10558
+ None yet
10559
+
10560
+ `;
10561
+ content += `## ADRs
10562
+
10563
+ None yet
10306
10564
 
10307
10565
  `;
10308
10566
  } else {
10309
- content += `| Term | Definition | Aliases |
10567
+ content = `# ${bc.name}
10568
+
10310
10569
  `;
10311
- content += `|------|-----------|---------|
10570
+ content += `## Module Status
10571
+
10572
+ `;
10573
+ content += `**Status:** Planned
10574
+ `;
10575
+ content += `**Last reviewed:** ${timestamp}
10312
10576
  `;
10313
- for (const t of contextTerms) {
10314
- content += `| ${t.term} | ${t.definition} | ${t.aliases.join(", ")} |
10577
+ content += `**Source session:** ${sessionId}
10578
+
10579
+ `;
10580
+ content += `## Description
10581
+
10582
+ ${bc.description}
10583
+
10584
+ `;
10585
+ content += `## Components
10586
+
10587
+ ${componentsSection}
10588
+ `;
10589
+ content += `## Domain Events
10590
+
10591
+ `;
10592
+ if (contextEvents.length === 0) {
10593
+ content += `None defined yet.
10594
+
10595
+ `;
10596
+ } else {
10597
+ for (const ev of contextEvents) {
10598
+ content += `- **${ev.name}** - ${ev.description} (triggered by: ${ev.triggeredBy})
10599
+ `;
10600
+ }
10601
+ content += `
10315
10602
  `;
10316
10603
  }
10317
- content += `
10604
+ content += `## Ubiquitous Language
10605
+
10318
10606
  `;
10319
- }
10320
- content += `## Dependencies
10607
+ if (contextTerms.length === 0) {
10608
+ content += `None defined yet.
10609
+
10610
+ `;
10611
+ } else {
10612
+ content += `| Term | Definition | Aliases |
10613
+ `;
10614
+ content += `|------|-----------|---------|
10615
+ `;
10616
+ for (const t of contextTerms) {
10617
+ content += `| ${t.term} | ${t.definition} | ${t.aliases.join(", ")} |
10618
+ `;
10619
+ }
10620
+ content += `
10621
+ `;
10622
+ }
10623
+ content += `## Dependencies
10321
10624
 
10322
10625
  ${depsSection}
10323
10626
  `;
10324
- content += `## Key Files
10627
+ content += `## Key Files
10325
10628
 
10326
10629
  None yet
10327
10630
 
10328
10631
  `;
10329
- content += `## ADRs
10632
+ content += `## ADRs
10330
10633
 
10331
10634
  None yet
10332
10635
 
10333
10636
  `;
10637
+ }
10334
10638
  if (!dryRun) {
10335
10639
  fs.mkdirSync(modulesDir, { recursive: true });
10336
10640
  const tempPath = `${filePath}.tmp`;