faf-cli 6.7.0 → 6.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ /** Validate a parsed .faf object */
2
+ export declare function validateFaf(data: unknown): {
3
+ valid: boolean;
4
+ errors: string[];
5
+ };
@@ -0,0 +1,23 @@
1
+ import type { KernelScoreResult, ScoreResult } from './types.js';
2
+ /** Convert kernel result into enriched ScoreResult */
3
+ export declare function enrichScore(kernel: KernelScoreResult): ScoreResult;
4
+ /**
5
+ * Score a .faf YAML string with About-Repo short-circuit.
6
+ *
7
+ * About Repos (app_type: about) are documentation surfaces, not apps.
8
+ * They DISPLAY the source codebase's Trophy, they don't earn one. The
9
+ * scorer reads `about.source_score` from the project.faf and emits that
10
+ * directly — no slot scoring, no kernel call.
11
+ *
12
+ * Truth-printing is preserved by owner accountability: the score is
13
+ * their attestation of the source's score; they're on the hook if it's wrong.
14
+ *
15
+ * Required for about: `app_type: about` + `about.represents: <owner>/<repo>`.
16
+ * Optional: `about.source_score: <number>` — without it, score is -1
17
+ * (renders as "—" honest unknown).
18
+ *
19
+ * Doctrine: memory/private-source-public-about-pattern.md.
20
+ *
21
+ * For non-about types: delegates to kernel.score() + enrichScore().
22
+ */
23
+ export declare function scoreFafYaml(yaml: string): ScoreResult;
@@ -0,0 +1,44 @@
1
+ import type { SlotDef, SlotCategory } from './types.js';
2
+ /** All 33 Mk4 canonical slots */
3
+ export declare const SLOTS: SlotDef[];
4
+ /** Slot lookup by path — dual-keyed (current on-wire `path` AND Mk4 `canonical`
5
+ * where defined) so callers can look up by either name. See issue #66. */
6
+ export declare const SLOT_BY_PATH: Map<string, SlotDef>;
7
+ /** Mk4 canonical → current on-wire path. Used by read helpers to resolve
8
+ * a canonical name back to the path that read/write/kernel actually uses
9
+ * today. Empty for slots whose path is already canonical. */
10
+ export declare const CANONICAL_TO_CURRENT: ReadonlyMap<string, string>;
11
+ /** Current on-wire path → Mk4 canonical. Used by display helpers when the
12
+ * UI wants to surface the forward-spec name. */
13
+ export declare const CURRENT_TO_CANONICAL: ReadonlyMap<string, string>;
14
+ /** Resolve any path (legacy or canonical) to the slot definition. */
15
+ export declare function getSlotByAnyPath(path: string): SlotDef | undefined;
16
+ /** Read a value from a .faf data object, checking both the slot's current
17
+ * `path` and its Mk4 `canonical` (if defined). Returns the first non-undefined
18
+ * value. Lets the cli read .faf files that contain either legacy or canonical
19
+ * keys without forcing a migration. */
20
+ export declare function readSlotValue(data: Record<string, unknown>, slot: SlotDef): unknown;
21
+ /** Slots grouped by category */
22
+ export declare function slotsByCategory(category: SlotCategory): SlotDef[];
23
+ /** Base-tier slots (1-21) — used by score_faf */
24
+ export declare const BASE_SLOTS: SlotDef[];
25
+ /** Enterprise-tier slots (1-33) — used by score_faf_enterprise */
26
+ export declare const ENTERPRISE_SLOTS: SlotDef[];
27
+ /** Placeholder values treated as Empty */
28
+ export declare const PLACEHOLDERS: Set<string>;
29
+ /** Check if a value is a placeholder (empty) */
30
+ export declare function isPlaceholder(value: unknown): boolean;
31
+ /** App-type to active category mapping. The canonical 21-type ladder —
32
+ * 19 detectable apps + `about` (non-app, 0 slots, owner-attested)
33
+ * + `encyclopedia` (curated knowledge surface, FAFipedia and similar).
34
+ * (See v6.6.md doctrine memory + fafipedia-vs-grokipedia-architecture.)
35
+ * Sorted ascending by active slot count for readability.
36
+ *
37
+ * v6.5.0 changes vs prior:
38
+ * - Added `universal` to cli / library / mcp / frontend / data-science.
39
+ * These types ship/build/CI somewhere — slotignoring those slots was
40
+ * losing real signal. (cli/library: 9→12; mcp/data-science: 14→17;
41
+ * frontend: 13→16.)
42
+ * - Order is by ascending slot count, not insertion order.
43
+ */
44
+ export declare const APP_TYPE_CATEGORIES: Record<string, SlotCategory[]>;
@@ -0,0 +1,19 @@
1
+ import type { TierInfo } from './types.js';
2
+ /** Tier boundaries — ordered from highest to lowest
3
+ *
4
+ * Indicators:
5
+ * 🏆 trophy (earned at 100%)
6
+ * ★ filled star (gold — orange)
7
+ * ◆ filled diamond (silver — cyan)
8
+ * ◇ open diamond (bronze — deep cyan, one rung below silver)
9
+ * ● filled circle (mid tiers)
10
+ * ○ open circle (low — dim)
11
+ * ♡ heart (empty — good luck)
12
+ */
13
+ export declare const TIERS: TierInfo[];
14
+ /** Get the display badge for a tier */
15
+ export declare function tierBadge(tier: TierInfo): string;
16
+ /** Get tier info for a given score */
17
+ export declare function getTier(score: number): TierInfo;
18
+ /** Get the next tier above the current score (for progress display) */
19
+ export declare function getNextTier(score: number): TierInfo | null;
@@ -0,0 +1,148 @@
1
+ /** State of a single slot in a .faf file */
2
+ export type SlotState = 'populated' | 'empty' | 'slotignored';
3
+ /** Category grouping for slots */
4
+ export type SlotCategory = 'project' | 'human' | 'frontend' | 'backend' | 'universal' | 'enterprise_infra' | 'enterprise_app' | 'enterprise_ops';
5
+ /** A single slot definition */
6
+ export interface SlotDef {
7
+ /** Slot number (1-33) */
8
+ index: number;
9
+ /** Dot-path in .faf YAML (e.g. "project.name") — current on-wire identifier
10
+ * used for read/write and kernel scoring. */
11
+ path: string;
12
+ /** Mk4 canonical dot-path (forward spec). Defined for slots where the
13
+ * current `path` is a legacy name pending lockstep rename with
14
+ * faf-scoring-kernel + xai-faf-rust. See issue #66. */
15
+ canonical?: string;
16
+ /** Human description */
17
+ description: string;
18
+ /** Category this slot belongs to */
19
+ category: SlotCategory;
20
+ }
21
+ /** Result from WASM kernel score_faf / score_faf_enterprise */
22
+ export interface KernelScoreResult {
23
+ score: number;
24
+ tier: string;
25
+ populated: number;
26
+ empty: number;
27
+ ignored: number;
28
+ active: number;
29
+ total: number;
30
+ slots: Record<string, SlotState>;
31
+ }
32
+ /** Enriched score result for display */
33
+ export interface ScoreResult {
34
+ score: number;
35
+ tier: TierInfo;
36
+ populated: number;
37
+ empty: number;
38
+ ignored: number;
39
+ active: number;
40
+ total: number;
41
+ slots: Record<string, SlotState>;
42
+ /**
43
+ * When true, the score is INHERITED from a source codebase (declared via
44
+ * `app_type: about` + `about.source_score` in project.faf). The scorer
45
+ * did NOT calculate this — the owner attested to it. About Repos are
46
+ * documentation surfaces, not apps.
47
+ *
48
+ * Set by scoreFafYaml when the input declares `app_type: about`.
49
+ * Consumers (TAF receipt generation, display logic) should distinguish
50
+ * inherited scores from calculated ones — they're qualitatively different
51
+ * artifacts. See memory/private-source-public-about-pattern.md.
52
+ */
53
+ inherited?: boolean;
54
+ /**
55
+ * For inherited scores: the owner/repo the About Repo represents.
56
+ * Format: "owner/repo" (e.g. "Wolfe-Jam/faf-mcpaas"). Required when
57
+ * `inherited: true` per schema validation.
58
+ */
59
+ represents?: string;
60
+ }
61
+ /** Tier boundary info */
62
+ export interface TierInfo {
63
+ name: string;
64
+ threshold: number;
65
+ /** Display indicator (branded glyphs + ANSI color) */
66
+ indicator: string;
67
+ }
68
+ /** Parsed .faf file data */
69
+ export interface FafData {
70
+ faf_version?: string;
71
+ project?: {
72
+ name?: string;
73
+ goal?: string;
74
+ main_language?: string;
75
+ type?: string;
76
+ [key: string]: unknown;
77
+ };
78
+ /**
79
+ * Top-level app_type — drives slot selection in APP_TYPE_CATEGORIES.
80
+ * Special value `'about'` is a non-app representation (see `about` block).
81
+ */
82
+ app_type?: string;
83
+ /**
84
+ * About Repo declaration block. Present when `app_type: about`. Lets the
85
+ * repo represent a private codebase: scorer short-circuits and emits
86
+ * `source_score` as the score. See memory/private-source-public-about-pattern.md.
87
+ */
88
+ about?: {
89
+ /** Required: "owner/repo" pointing at the private source codebase. */
90
+ represents?: string;
91
+ /** Optional: owner-attested score of the source (0-100). Missing = score "—". */
92
+ source_score?: number;
93
+ };
94
+ stack?: Record<string, unknown>;
95
+ human_context?: Record<string, unknown>;
96
+ monorepo?: Record<string, unknown>;
97
+ scores?: Record<string, unknown>;
98
+ /** TECH_STACK section content — flat list of technology components */
99
+ tech_stack?: string[];
100
+ /** KEY_FILES section — list of important file paths */
101
+ key_files?: string[];
102
+ /** COMMANDS section — build/test/lint/dev command map */
103
+ commands?: Record<string, string>;
104
+ /** ARCHITECTURE section — free-form structural description (user-fill) */
105
+ architecture?: string;
106
+ /** CONTEXT section — free-form additional signal (user-fill, NOT human_context) */
107
+ context?: string;
108
+ [key: string]: unknown;
109
+ }
110
+ /** FAFb binary info from kernel */
111
+ export interface FafbInfo {
112
+ header: {
113
+ magic: string;
114
+ version: number;
115
+ flags: number;
116
+ section_count: number;
117
+ crc32: number;
118
+ };
119
+ sections: Array<{
120
+ name: string;
121
+ priority: number;
122
+ offset: number;
123
+ length: number;
124
+ classification: string;
125
+ }>;
126
+ content?: string;
127
+ }
128
+ /** Framework detection result */
129
+ export interface DetectedFramework {
130
+ name: string;
131
+ slug: string;
132
+ category: string;
133
+ confidence: number;
134
+ version?: string;
135
+ }
136
+ /** Signal types for framework detection */
137
+ export type SignalType = 'dependency' | 'file' | 'devDependency';
138
+ export interface Signal {
139
+ type: SignalType;
140
+ key?: string;
141
+ pattern?: string;
142
+ }
143
+ export interface FrameworkSignature {
144
+ name: string;
145
+ slug: string;
146
+ category: string;
147
+ signals: Signal[];
148
+ }
@@ -0,0 +1,9 @@
1
+ export type { SlotState, SlotCategory, SlotDef, KernelScoreResult, ScoreResult, TierInfo, FafData, FafbInfo, DetectedFramework, FrameworkSignature, Signal, SignalType, } from './core/types.js';
2
+ export { SLOTS, BASE_SLOTS, ENTERPRISE_SLOTS, SLOT_BY_PATH, slotsByCategory, PLACEHOLDERS, isPlaceholder } from './core/slots.js';
3
+ export { TIERS, getTier, getNextTier } from './core/tiers.js';
4
+ export { FAF_HEX } from './ui/colors.js';
5
+ export { enrichScore, scoreFafYaml } from './core/scorer.js';
6
+ export { validateFaf } from './core/schema.js';
7
+ export { findFafFile, readFaf, readFafRaw } from './interop/faf.js';
8
+ export { generateProjectHtml, writeProjectHtml } from './interop/projecthtml.js';
9
+ export * as kernel from './wasm/kernel.js';
package/dist/index.js CHANGED
@@ -136,10 +136,10 @@ ${$.comment}`:$.comment}this.doc.range[2]=$.offset;break}default:this.errors.pus
136
136
  `)+1;while($!==0)this.onNewLine(this.offset+$),$=this.source.indexOf(`
137
137
  `,$)+1}yield*this.pop();break;default:yield*this.pop(),yield*this.step()}}*blockMap(q){let $=q.items[q.items.length-1];switch(this.type){case"newline":if(this.onKeyLine=!1,$.value){let U="end"in $.value?$.value.end:void 0;if((Array.isArray(U)?U[U.length-1]:void 0)?.type==="comment")U?.push(this.sourceToken);else q.items.push({start:[this.sourceToken]})}else if($.sep)$.sep.push(this.sourceToken);else $.start.push(this.sourceToken);return;case"space":case"comment":if($.value)q.items.push({start:[this.sourceToken]});else if($.sep)$.sep.push(this.sourceToken);else{if(this.atIndentedComment($.start,q.indent)){let Z=q.items[q.items.length-2]?.value?.end;if(Array.isArray(Z)){Array.prototype.push.apply(Z,$.start),Z.push(this.sourceToken),q.items.pop();return}}$.start.push(this.sourceToken)}return}if(this.indent>=q.indent){let U=!this.onKeyLine&&this.indent===q.indent,Z=U&&($.sep||$.explicitKey)&&this.type!=="seq-item-ind",H=[];if(Z&&$.sep&&!$.value){let z=[];for(let X=0;X<$.sep.length;++X){let G=$.sep[X];switch(G.type){case"newline":z.push(X);break;case"space":break;case"comment":if(G.indent>q.indent)z.length=0;break;default:z.length=0}}if(z.length>=2)H=$.sep.splice(z[1])}switch(this.type){case"anchor":case"tag":if(Z||$.value)H.push(this.sourceToken),q.items.push({start:H}),this.onKeyLine=!0;else if($.sep)$.sep.push(this.sourceToken);else $.start.push(this.sourceToken);return;case"explicit-key-ind":if(!$.sep&&!$.explicitKey)$.start.push(this.sourceToken),$.explicitKey=!0;else if(Z||$.value)H.push(this.sourceToken),q.items.push({start:H,explicitKey:!0});else this.stack.push({type:"block-map",offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken],explicitKey:!0}]});this.onKeyLine=!0;return;case"map-value-ind":if($.explicitKey)if(!$.sep)if(n($.start,"newline"))Object.assign($,{key:null,sep:[this.sourceToken]});else{let z=_0($.start);this.stack.push({type:"block-map",offset:this.offset,indent:this.indent,items:[{start:z,key:null,sep:[this.sourceToken]}]})}else if($.value)q.items.push({start:[],key:null,sep:[this.sourceToken]});else if(n($.sep,"map-value-ind"))this.stack.push({type:"block-map",offset:this.offset,indent:this.indent,items:[{start:H,key:null,sep:[this.sourceToken]}]});else if(H9($.key)&&!n($.sep,"newline")){let z=_0($.start),X=$.key,G=$.sep;G.push(this.sourceToken),delete $.key,delete $.sep,this.stack.push({type:"block-map",offset:this.offset,indent:this.indent,items:[{start:z,key:X,sep:G}]})}else if(H.length>0)$.sep=$.sep.concat(H,this.sourceToken);else $.sep.push(this.sourceToken);else if(!$.sep)Object.assign($,{key:null,sep:[this.sourceToken]});else if($.value||Z)q.items.push({start:H,key:null,sep:[this.sourceToken]});else if(n($.sep,"map-value-ind"))this.stack.push({type:"block-map",offset:this.offset,indent:this.indent,items:[{start:[],key:null,sep:[this.sourceToken]}]});else $.sep.push(this.sourceToken);this.onKeyLine=!0;return;case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":{let z=this.flowScalar(this.type);if(Z||$.value)q.items.push({start:H,key:z,sep:[]}),this.onKeyLine=!0;else if($.sep)this.stack.push(z);else Object.assign($,{key:z,sep:[]}),this.onKeyLine=!0;return}default:{let z=this.startBlockValue(q);if(z){if(z.type==="block-seq"){if(!$.explicitKey&&$.sep&&!n($.sep,"newline")){yield*this.pop({type:"error",offset:this.offset,message:"Unexpected block-seq-ind on same line with key",source:this.source});return}}else if(U)q.items.push({start:H});this.stack.push(z);return}}}}yield*this.pop(),yield*this.step()}*blockSequence(q){let $=q.items[q.items.length-1];switch(this.type){case"newline":if($.value){let U="end"in $.value?$.value.end:void 0;if((Array.isArray(U)?U[U.length-1]:void 0)?.type==="comment")U?.push(this.sourceToken);else q.items.push({start:[this.sourceToken]})}else $.start.push(this.sourceToken);return;case"space":case"comment":if($.value)q.items.push({start:[this.sourceToken]});else{if(this.atIndentedComment($.start,q.indent)){let Z=q.items[q.items.length-2]?.value?.end;if(Array.isArray(Z)){Array.prototype.push.apply(Z,$.start),Z.push(this.sourceToken),q.items.pop();return}}$.start.push(this.sourceToken)}return;case"anchor":case"tag":if($.value||this.indent<=q.indent)break;$.start.push(this.sourceToken);return;case"seq-item-ind":if(this.indent!==q.indent)break;if($.value||n($.start,"seq-item-ind"))q.items.push({start:[this.sourceToken]});else $.start.push(this.sourceToken);return}if(this.indent>q.indent){let U=this.startBlockValue(q);if(U){this.stack.push(U);return}}yield*this.pop(),yield*this.step()}*flowCollection(q){let $=q.items[q.items.length-1];if(this.type==="flow-error-end"){let U;do yield*this.pop(),U=this.peek(1);while(U?.type==="flow-collection")}else if(q.end.length===0){switch(this.type){case"comma":case"explicit-key-ind":if(!$||$.sep)q.items.push({start:[this.sourceToken]});else $.start.push(this.sourceToken);return;case"map-value-ind":if(!$||$.value)q.items.push({start:[],key:null,sep:[this.sourceToken]});else if($.sep)$.sep.push(this.sourceToken);else Object.assign($,{key:null,sep:[this.sourceToken]});return;case"space":case"comment":case"newline":case"anchor":case"tag":if(!$||$.value)q.items.push({start:[this.sourceToken]});else if($.sep)$.sep.push(this.sourceToken);else $.start.push(this.sourceToken);return;case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":{let Z=this.flowScalar(this.type);if(!$||$.value)q.items.push({start:[],key:Z,sep:[]});else if($.sep)this.stack.push(Z);else Object.assign($,{key:Z,sep:[]});return}case"flow-map-end":case"flow-seq-end":q.end.push(this.sourceToken);return}let U=this.startBlockValue(q);if(U)this.stack.push(U);else yield*this.pop(),yield*this.step()}else{let U=this.peek(2);if(U.type==="block-map"&&(this.type==="map-value-ind"&&U.indent===q.indent||this.type==="newline"&&!U.items[U.items.length-1].sep))yield*this.pop(),yield*this.step();else if(this.type==="map-value-ind"&&U.type!=="flow-collection"){let Z=gq(U),H=_0(Z);Z9(q);let z=q.end.splice(1,q.end.length);z.push(this.sourceToken);let X={type:"block-map",offset:q.offset,indent:q.indent,items:[{start:H,key:q,sep:z}]};this.onKeyLine=!0,this.stack[this.stack.length-1]=X}else yield*this.lineEnd(q)}}flowScalar(q){if(this.onNewLine){let $=this.source.indexOf(`
138
138
  `)+1;while($!==0)this.onNewLine(this.offset+$),$=this.source.indexOf(`
139
- `,$)+1}return{type:q,offset:this.offset,indent:this.indent,source:this.source}}startBlockValue(q){switch(this.type){case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":return this.flowScalar(this.type);case"block-scalar-header":return{type:"block-scalar",offset:this.offset,indent:this.indent,props:[this.sourceToken],source:""};case"flow-map-start":case"flow-seq-start":return{type:"flow-collection",offset:this.offset,indent:this.indent,start:this.sourceToken,items:[],end:[]};case"seq-item-ind":return{type:"block-seq",offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken]}]};case"explicit-key-ind":{this.onKeyLine=!0;let $=gq(q),U=_0($);return U.push(this.sourceToken),{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:U,explicitKey:!0}]}}case"map-value-ind":{this.onKeyLine=!0;let $=gq(q),U=_0($);return{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:U,key:null,sep:[this.sourceToken]}]}}}return null}atIndentedComment(q,$){if(this.type!=="comment")return!1;if(this.indent<=$)return!1;return q.every((U)=>U.type==="newline"||U.type==="space")}*documentEnd(q){if(this.type!=="doc-mode"){if(q.end)q.end.push(this.sourceToken);else q.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}*lineEnd(q){switch(this.type){case"comma":case"doc-start":case"doc-end":case"flow-seq-end":case"flow-map-end":case"map-value-ind":yield*this.pop(),yield*this.step();break;case"newline":this.onKeyLine=!1;case"space":case"comment":default:if(q.end)q.end.push(this.sourceToken);else q.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}}h1.Parser=z9});var B9=T((a1)=>{var X9=m$(),k1=v0(),a0=m0(),v1=oq(),m1=w(),p1=o$(),G9=t$();function J9(q){let $=q.prettyErrors!==!1;return{lineCounter:q.lineCounter||$&&new p1.LineCounter||null,prettyErrors:$}}function d1(q,$={}){let{lineCounter:U,prettyErrors:Z}=J9($),H=new G9.Parser(U?.addNewLine),z=new X9.Composer($),X=Array.from(z.compose(H.parse(q)));if(Z&&U)for(let G of X)G.errors.forEach(a0.prettifyError(q,U)),G.warnings.forEach(a0.prettifyError(q,U));if(X.length>0)return X;return Object.assign([],{empty:!0},z.streamInfo())}function Q9(q,$={}){let{lineCounter:U,prettyErrors:Z}=J9($),H=new G9.Parser(U?.addNewLine),z=new X9.Composer($),X=null;for(let G of z.compose(H.parse(q),!0,q.length))if(!X)X=G;else if(X.options.logLevel!=="silent"){X.errors.push(new a0.YAMLParseError(G.range.slice(0,2),"MULTIPLE_DOCS","Source contains multiple documents; please use YAML.parseAllDocuments()"));break}if(Z&&U)X.errors.forEach(a0.prettifyError(q,U)),X.warnings.forEach(a0.prettifyError(q,U));return X}function l1(q,$,U){let Z=void 0;if(typeof $==="function")Z=$;else if(U===void 0&&$&&typeof $==="object")U=$;let H=Q9(q,U);if(!H)return null;if(H.warnings.forEach((z)=>v1.warn(H.options.logLevel,z)),H.errors.length>0)if(H.options.logLevel!=="silent")throw H.errors[0];else H.errors=[];return H.toJS(Object.assign({reviver:Z},U))}function c1(q,$,U){let Z=null;if(typeof $==="function"||Array.isArray($))Z=$;else if(U===void 0&&$)U=$;if(typeof U==="string")U=U.length;if(typeof U==="number"){let H=Math.round(U);U=H<1?void 0:H>8?{indent:8}:{indent:H}}if(q===void 0){let{keepUndefined:H}=U??$??{};if(!H)return}if(m1.isDocument(q)&&!Z)return q.toString(U);return new k1.Document(q,Z,U).toString(U)}a1.parse=l1;a1.parseAllDocuments=d1;a1.parseDocument=Q9;a1.stringify=c1});var t=[{index:1,path:"project.name",description:"Project name",category:"project"},{index:2,path:"project.goal",description:"Goal (use case)",category:"project"},{index:3,path:"project.main_language",description:"Primary language",category:"project"},{index:4,path:"human_context.who",description:"Who is this for?",category:"human"},{index:5,path:"human_context.what",description:"What are they building",category:"human"},{index:6,path:"human_context.why",description:"Why does it exist",category:"human"},{index:7,path:"human_context.where",description:"Where does it run",category:"human"},{index:8,path:"human_context.when",description:"When was it started / timeline",category:"human"},{index:9,path:"human_context.how",description:"How is it built",category:"human"},{index:10,path:"stack.frontend",canonical:"stack.framework",description:"Framework (React, Svelte, etc.)",category:"frontend"},{index:11,path:"stack.css_framework",canonical:"stack.css",description:"CSS framework",category:"frontend"},{index:12,path:"stack.ui_library",description:"UI component library",category:"frontend"},{index:13,path:"stack.state_management",canonical:"stack.state",description:"State management",category:"frontend"},{index:14,path:"stack.backend",description:"Backend framework",category:"backend"},{index:15,path:"stack.api_type",canonical:"stack.api",description:"API style (REST, GraphQL, etc.)",category:"backend"},{index:16,path:"stack.runtime",description:"Runtime (Node, Bun, Python, etc.)",category:"backend"},{index:17,path:"stack.database",canonical:"stack.db",description:"Database",category:"backend"},{index:18,path:"stack.connection",description:"Connection method (Prisma, etc.)",category:"backend"},{index:19,path:"stack.hosting",description:"Hosting platform",category:"universal"},{index:20,path:"stack.build",description:"Build tool",category:"universal"},{index:21,path:"stack.cicd",description:"CI/CD",category:"universal"},{index:22,path:"stack.monorepo_tool",description:"Monorepo tool",category:"enterprise_infra"},{index:23,path:"stack.package_manager",canonical:"stack.pkg_manager",description:"Package manager",category:"enterprise_infra"},{index:24,path:"stack.workspaces",description:"Workspace configuration",category:"enterprise_infra"},{index:25,path:"monorepo.packages_count",description:"Number of packages",category:"enterprise_infra"},{index:26,path:"monorepo.build_orchestrator",description:"Build orchestration tool",category:"enterprise_infra"},{index:27,path:"stack.admin",description:"Admin panel",category:"enterprise_app"},{index:28,path:"stack.cache",description:"Caching layer",category:"enterprise_app"},{index:29,path:"stack.search",description:"Search engine",category:"enterprise_app"},{index:30,path:"stack.storage",description:"Object storage",category:"enterprise_app"},{index:31,path:"monorepo.versioning_strategy",description:"Version strategy",category:"enterprise_ops"},{index:32,path:"monorepo.shared_configs",description:"Shared configs",category:"enterprise_ops"},{index:33,path:"monorepo.remote_cache",description:"Remote build cache",category:"enterprise_ops"}],w9=new Map(t.flatMap((q)=>q.canonical?[[q.path,q],[q.canonical,q]]:[[q.path,q]])),r7=new Map(t.filter((q)=>q.canonical).map((q)=>[q.canonical,q.path])),n7=new Map(t.filter((q)=>q.canonical).map((q)=>[q.path,q.canonical]));function K9(q){return t.filter(($)=>$.category===q)}var N9=t.filter((q)=>q.index<=21),b9=t,UU=new Set(["describe your project goal","development teams","cloud platform","null","none","unknown","n/a","not applicable"]);function S9(q){if(q===null||q===void 0||q==="")return!0;if(typeof q==="string")return UU.has(q.toLowerCase().trim());if(Array.isArray(q)&&q.length===0)return!0;if(typeof q==="object"&&Object.keys(q).length===0)return!0;return!1}var xq=(q)=>($)=>`\x1B[${q}m${$}\x1B[0m`,hq=xq("1"),s0=xq("2"),t7=xq("3"),R0={cyan:"#00D4D4",cyanDeep:"#0E8C8C",orange:"#FF6B35"},uq=(q)=>`\x1B[38;2;0;212;212m${q}\x1B[0m`,kq=(q)=>`\x1B[38;2;14;140;140m${q}\x1B[0m`,P0=(q)=>`\x1B[38;5;208m${q}\x1B[0m`;var u=[{name:"TROPHY",indicator:`${P0("\uD83C\uDFC6")} ${P0("TROPHY")}`,threshold:100},{name:"GOLD",indicator:`${P0(hq("★"))} ${P0("GOLD")}`,threshold:99},{name:"SILVER",indicator:`${uq("◆")} ${uq("SILVER")}`,threshold:95},{name:"BRONZE",indicator:`${kq("◇")} ${kq("BRONZE")}`,threshold:85},{name:"GREEN",indicator:`${hq("●")} GREEN`,threshold:70},{name:"YELLOW",indicator:`${s0("●")} YELLOW`,threshold:55},{name:"RED",indicator:`${s0("○")} RED`,threshold:1},{name:"WHITE",indicator:`${s0("♡")}`,threshold:0}];function F0(q){for(let $ of u)if(q>=$.threshold)return $;return u[u.length-1]}function j9(q){let $=F0(q),U=u.indexOf($);return U>0?u[U-1]:null}var pq={};A9(pq,{validate:()=>E9,sdkVersion:()=>h9,scoreFafb:()=>x9,scoreEnterprise:()=>C9,score:()=>mq,fafbInfo:()=>y9,decompile:()=>f9,compile:()=>g9});var vq=null;function p(){if(!vq)try{vq=I0("faf-scoring-kernel")}catch{throw Error(`faf-scoring-kernel not installed.
139
+ `,$)+1}return{type:q,offset:this.offset,indent:this.indent,source:this.source}}startBlockValue(q){switch(this.type){case"alias":case"scalar":case"single-quoted-scalar":case"double-quoted-scalar":return this.flowScalar(this.type);case"block-scalar-header":return{type:"block-scalar",offset:this.offset,indent:this.indent,props:[this.sourceToken],source:""};case"flow-map-start":case"flow-seq-start":return{type:"flow-collection",offset:this.offset,indent:this.indent,start:this.sourceToken,items:[],end:[]};case"seq-item-ind":return{type:"block-seq",offset:this.offset,indent:this.indent,items:[{start:[this.sourceToken]}]};case"explicit-key-ind":{this.onKeyLine=!0;let $=gq(q),U=_0($);return U.push(this.sourceToken),{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:U,explicitKey:!0}]}}case"map-value-ind":{this.onKeyLine=!0;let $=gq(q),U=_0($);return{type:"block-map",offset:this.offset,indent:this.indent,items:[{start:U,key:null,sep:[this.sourceToken]}]}}}return null}atIndentedComment(q,$){if(this.type!=="comment")return!1;if(this.indent<=$)return!1;return q.every((U)=>U.type==="newline"||U.type==="space")}*documentEnd(q){if(this.type!=="doc-mode"){if(q.end)q.end.push(this.sourceToken);else q.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}*lineEnd(q){switch(this.type){case"comma":case"doc-start":case"doc-end":case"flow-seq-end":case"flow-map-end":case"map-value-ind":yield*this.pop(),yield*this.step();break;case"newline":this.onKeyLine=!1;case"space":case"comment":default:if(q.end)q.end.push(this.sourceToken);else q.end=[this.sourceToken];if(this.type==="newline")yield*this.pop()}}}h1.Parser=z9});var B9=T((a1)=>{var X9=m$(),k1=v0(),a0=m0(),v1=oq(),m1=w(),p1=o$(),G9=t$();function J9(q){let $=q.prettyErrors!==!1;return{lineCounter:q.lineCounter||$&&new p1.LineCounter||null,prettyErrors:$}}function d1(q,$={}){let{lineCounter:U,prettyErrors:Z}=J9($),H=new G9.Parser(U?.addNewLine),z=new X9.Composer($),X=Array.from(z.compose(H.parse(q)));if(Z&&U)for(let G of X)G.errors.forEach(a0.prettifyError(q,U)),G.warnings.forEach(a0.prettifyError(q,U));if(X.length>0)return X;return Object.assign([],{empty:!0},z.streamInfo())}function Q9(q,$={}){let{lineCounter:U,prettyErrors:Z}=J9($),H=new G9.Parser(U?.addNewLine),z=new X9.Composer($),X=null;for(let G of z.compose(H.parse(q),!0,q.length))if(!X)X=G;else if(X.options.logLevel!=="silent"){X.errors.push(new a0.YAMLParseError(G.range.slice(0,2),"MULTIPLE_DOCS","Source contains multiple documents; please use YAML.parseAllDocuments()"));break}if(Z&&U)X.errors.forEach(a0.prettifyError(q,U)),X.warnings.forEach(a0.prettifyError(q,U));return X}function l1(q,$,U){let Z=void 0;if(typeof $==="function")Z=$;else if(U===void 0&&$&&typeof $==="object")U=$;let H=Q9(q,U);if(!H)return null;if(H.warnings.forEach((z)=>v1.warn(H.options.logLevel,z)),H.errors.length>0)if(H.options.logLevel!=="silent")throw H.errors[0];else H.errors=[];return H.toJS(Object.assign({reviver:Z},U))}function c1(q,$,U){let Z=null;if(typeof $==="function"||Array.isArray($))Z=$;else if(U===void 0&&$)U=$;if(typeof U==="string")U=U.length;if(typeof U==="number"){let H=Math.round(U);U=H<1?void 0:H>8?{indent:8}:{indent:H}}if(q===void 0){let{keepUndefined:H}=U??$??{};if(!H)return}if(m1.isDocument(q)&&!Z)return q.toString(U);return new k1.Document(q,Z,U).toString(U)}a1.parse=l1;a1.parseAllDocuments=d1;a1.parseDocument=Q9;a1.stringify=c1});var t=[{index:1,path:"project.name",description:"Project name",category:"project"},{index:2,path:"project.goal",description:"Goal (use case)",category:"project"},{index:3,path:"project.main_language",description:"Primary language",category:"project"},{index:4,path:"human_context.who",description:"Who is this for?",category:"human"},{index:5,path:"human_context.what",description:"What are they building",category:"human"},{index:6,path:"human_context.why",description:"Why does it exist",category:"human"},{index:7,path:"human_context.where",description:"Where does it run",category:"human"},{index:8,path:"human_context.when",description:"When was it started / timeline",category:"human"},{index:9,path:"human_context.how",description:"How is it built",category:"human"},{index:10,path:"stack.frontend",canonical:"stack.framework",description:"Framework (React, Svelte, etc.)",category:"frontend"},{index:11,path:"stack.css_framework",canonical:"stack.css",description:"CSS framework",category:"frontend"},{index:12,path:"stack.ui_library",description:"UI component library",category:"frontend"},{index:13,path:"stack.state_management",canonical:"stack.state",description:"State management",category:"frontend"},{index:14,path:"stack.backend",description:"Backend framework",category:"backend"},{index:15,path:"stack.api_type",canonical:"stack.api",description:"API style (REST, GraphQL, etc.)",category:"backend"},{index:16,path:"stack.runtime",description:"Runtime (Node, Bun, Python, etc.)",category:"backend"},{index:17,path:"stack.database",canonical:"stack.db",description:"Database",category:"backend"},{index:18,path:"stack.connection",description:"Connection method (Prisma, etc.)",category:"backend"},{index:19,path:"stack.hosting",description:"Hosting platform",category:"universal"},{index:20,path:"stack.build",description:"Build tool",category:"universal"},{index:21,path:"stack.cicd",description:"CI/CD",category:"universal"},{index:22,path:"stack.monorepo_tool",description:"Monorepo tool",category:"enterprise_infra"},{index:23,path:"stack.package_manager",canonical:"stack.pkg_manager",description:"Package manager",category:"enterprise_infra"},{index:24,path:"stack.workspaces",description:"Workspace configuration",category:"enterprise_infra"},{index:25,path:"monorepo.packages_count",description:"Number of packages",category:"enterprise_infra"},{index:26,path:"monorepo.build_orchestrator",description:"Build orchestration tool",category:"enterprise_infra"},{index:27,path:"stack.admin",description:"Admin panel",category:"enterprise_app"},{index:28,path:"stack.cache",description:"Caching layer",category:"enterprise_app"},{index:29,path:"stack.search",description:"Search engine",category:"enterprise_app"},{index:30,path:"stack.storage",description:"Object storage",category:"enterprise_app"},{index:31,path:"monorepo.versioning_strategy",description:"Version strategy",category:"enterprise_ops"},{index:32,path:"monorepo.shared_configs",description:"Shared configs",category:"enterprise_ops"},{index:33,path:"monorepo.remote_cache",description:"Remote build cache",category:"enterprise_ops"}],w9=new Map(t.flatMap((q)=>q.canonical?[[q.path,q],[q.canonical,q]]:[[q.path,q]])),r7=new Map(t.filter((q)=>q.canonical).map((q)=>[q.canonical,q.path])),n7=new Map(t.filter((q)=>q.canonical).map((q)=>[q.path,q.canonical]));function K9(q){return t.filter(($)=>$.category===q)}var N9=t.filter((q)=>q.index<=21),b9=t,UU=new Set(["describe your project goal","development teams","cloud platform","null","none","unknown","n/a","not applicable"]);function S9(q){if(q===null||q===void 0||q==="")return!0;if(typeof q==="string")return UU.has(q.toLowerCase().trim());if(Array.isArray(q)&&q.length===0)return!0;if(typeof q==="object"&&Object.keys(q).length===0)return!0;return!1}var xq=(q)=>($)=>`\x1B[${q}m${$}\x1B[0m`,hq=xq("1"),s0=xq("2"),t7=xq("3"),R0={cyan:"#00D4D4",cyanDeep:"#0E8C8C",orange:"#FF6B35"},uq=(q)=>`\x1B[38;2;0;212;212m${q}\x1B[0m`,kq=(q)=>`\x1B[38;2;14;140;140m${q}\x1B[0m`,P0=(q)=>`\x1B[38;5;208m${q}\x1B[0m`;var u=[{name:"TROPHY",indicator:`${P0("\uD83C\uDFC6")} ${P0("TROPHY")}`,threshold:100},{name:"GOLD",indicator:`${P0(hq("★"))} ${P0("GOLD")}`,threshold:99},{name:"SILVER",indicator:`${uq("◆")} ${uq("SILVER")}`,threshold:95},{name:"BRONZE",indicator:`${kq("◇")} ${kq("BRONZE")}`,threshold:85},{name:"GREEN",indicator:`${hq("●")} GREEN`,threshold:70},{name:"YELLOW",indicator:`${s0("●")} YELLOW`,threshold:55},{name:"RED",indicator:`${s0("○")} RED`,threshold:1},{name:"WHITE",indicator:`${s0("♡")}`,threshold:0}];function F0(q){for(let $ of u)if(q>=$.threshold)return $;return u[u.length-1]}function j9(q){let $=F0(q),U=u.indexOf($);return U>0?u[U-1]:null}var pq={};A9(pq,{validate:()=>E9,sdkVersion:()=>h9,scoreFafb:()=>x9,scoreEnterprise:()=>C9,score:()=>mq,fafbInfo:()=>y9,decompile:()=>f9,compile:()=>g9});var vq=null;function p(){if(vq)return vq;try{let q=I0("faf-scoring-kernel");return vq=q,q}catch{throw Error(`faf-scoring-kernel not installed.
140
140
 
141
141
  Run: npm install faf-scoring-kernel
142
- `)}return vq}function mq(q){return JSON.parse(p().score_faf(q))}function C9(q){return JSON.parse(p().score_faf_enterprise(q))}function E9(q){return p().validate_faf(q)}function g9(q){return p().compile_fafb(q)}function f9(q){return JSON.parse(p().decompile_fafb(q))}function y9(q){return JSON.parse(p().fafb_info(q))}function x9(q){return JSON.parse(p().score_fafb(q))}function h9(){return p().sdk_version()}function ZU(q){return{score:q.score,tier:F0(q.score),populated:q.populated,empty:q.empty,ignored:q.ignored,active:q.active,total:q.total,slots:q.slots}}function u9(q){if(/^\s*app_type:\s*about\s*$/m.test(q)){let U=q.match(/^\s+source_score:\s*(\d+)\s*$/m),Z=U?parseInt(U[1],10):-1,H=Z>=0&&Z<=100?Z:-1,z=q.match(/^\s+represents:\s*(\S+)\s*$/m),X=z?z[1]:void 0;return{score:H,tier:H>=0?F0(H):u[u.length-1],populated:0,empty:0,ignored:0,active:0,total:0,slots:{},inherited:!0,represents:X}}return ZU(mq(q))}function k9(q){let $=[];if(!q||typeof q!=="object")return $.push("File is not a valid YAML mapping"),{valid:!1,errors:$};let U=q;if(!U.faf_version)$.push("Missing required field: faf_version");if(!U.project?.name)$.push("Missing required field: project.name");if(U.app_type==="about"){if(!U.about?.represents)$.push("app_type 'about' requires about.represents (owner/repo of the source codebase)");else if(!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(U.about.represents))$.push(`about.represents must be "owner/repo" format (got: ${U.about.represents})`);if(U.about?.source_score!==void 0){let Z=U.about.source_score;if(typeof Z!=="number"||Z<0||Z>100)$.push(`about.source_score must be a number 0-100 (got: ${Z})`)}}return{valid:$.length===0,errors:$}}import{readFileSync as L9,writeFileSync as wX,existsSync as W9}from"fs";import{join as O9,dirname as f7}from"path";var o1=m$(),t1=v0(),e1=w$(),e$=m0(),q7=w0(),o=w(),$7=a(),U7=N(),Z7=i(),H7=r(),FX=Cq(),z7=n$(),X7=o$(),G7=t$(),fq=B9(),Y9=A0();var J7=o1.Composer,Q7=t1.Document,B7=e1.Schema,Y7=e$.YAMLError,V7=e$.YAMLParseError,W7=e$.YAMLWarning,O7=q7.Alias,L7=o.isAlias,T7=o.isCollection,_7=o.isDocument,D7=o.isMap,I7=o.isNode,R7=o.isPair,P7=o.isScalar,F7=o.isSeq,A7=$7.Pair,M7=U7.Scalar,w7=Z7.YAMLMap,K7=H7.YAMLSeq;var N7=z7.Lexer,b7=X7.LineCounter,S7=G7.Parser,qU=fq.parse,j7=fq.parseAllDocuments,C7=fq.parseDocument,V9=fq.stringify,E7=Y9.visit,g7=Y9.visitAsync;function y7(q){let $=L9(q,"utf-8");return qU($)}function x7(q){return L9(q,"utf-8")}function h7(q=process.cwd()){let $=["project.faf",".faf"];for(let Z of $){let H=O9(q,Z);if(W9(H))return H}let U=f7(q);if(U!==q)for(let Z of $){let H=O9(U,Z);if(W9(H))return H}return null}import{writeFileSync as u7}from"fs";import{join as k7}from"path";var T9=R0.orange,v7=R0.cyan,m7=R0.cyanDeep,p7="#FF9500",d7="#FF3B30",l7="#E6EDF3",c7="#6E7681",_9={TROPHY:{glyph:"\uD83C\uDFC6",color:T9},GOLD:{glyph:"★",color:T9},SILVER:{glyph:"◆",color:v7},BRONZE:{glyph:"◇",color:m7},GREEN:{glyph:"●",color:l7},YELLOW:{glyph:"●",color:p7},RED:{glyph:"○",color:d7},WHITE:{glyph:"♡",color:c7}};function D0(q){return String(q??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}var D9=["who","what","why","where","when","how"];function yq(q){return q.filter(([,$])=>$!==void 0&&$!==null&&String($).trim()!=="").map(([$,U])=>`<div class="row"><div class="k">${D0($)}</div><div class="v">${D0(U)}</div></div>`).join(`
142
+ `)}}function mq(q){return JSON.parse(p().score_faf(q))}function C9(q){return JSON.parse(p().score_faf_enterprise(q))}function E9(q){return p().validate_faf(q)}function g9(q){return p().compile_fafb(q)}function f9(q){return JSON.parse(p().decompile_fafb(q))}function y9(q){return JSON.parse(p().fafb_info(q))}function x9(q){return JSON.parse(p().score_fafb(q))}function h9(){return p().sdk_version()}function ZU(q){return{score:q.score,tier:F0(q.score),populated:q.populated,empty:q.empty,ignored:q.ignored,active:q.active,total:q.total,slots:q.slots}}function u9(q){if(/^\s*app_type:\s*about\s*$/m.test(q)){let U=q.match(/^\s+source_score:\s*(\d+)\s*$/m),Z=U?parseInt(U[1],10):-1,H=Z>=0&&Z<=100?Z:-1,z=q.match(/^\s+represents:\s*(\S+)\s*$/m),X=z?z[1]:void 0;return{score:H,tier:H>=0?F0(H):u[u.length-1],populated:0,empty:0,ignored:0,active:0,total:0,slots:{},inherited:!0,represents:X}}return ZU(mq(q))}function k9(q){let $=[];if(!q||typeof q!=="object")return $.push("File is not a valid YAML mapping"),{valid:!1,errors:$};let U=q;if(!U.faf_version)$.push("Missing required field: faf_version");if(!U.project?.name)$.push("Missing required field: project.name");if(U.app_type==="about"){if(!U.about?.represents)$.push("app_type 'about' requires about.represents (owner/repo of the source codebase)");else if(!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(U.about.represents))$.push(`about.represents must be "owner/repo" format (got: ${U.about.represents})`);if(U.about?.source_score!==void 0){let Z=U.about.source_score;if(typeof Z!=="number"||Z<0||Z>100)$.push(`about.source_score must be a number 0-100 (got: ${Z})`)}}return{valid:$.length===0,errors:$}}import{readFileSync as L9,writeFileSync as wX,existsSync as W9}from"fs";import{join as O9,dirname as f7}from"path";var o1=m$(),t1=v0(),e1=w$(),e$=m0(),q7=w0(),o=w(),$7=a(),U7=N(),Z7=i(),H7=r(),FX=Cq(),z7=n$(),X7=o$(),G7=t$(),fq=B9(),Y9=A0();var J7=o1.Composer,Q7=t1.Document,B7=e1.Schema,Y7=e$.YAMLError,V7=e$.YAMLParseError,W7=e$.YAMLWarning,O7=q7.Alias,L7=o.isAlias,T7=o.isCollection,_7=o.isDocument,D7=o.isMap,I7=o.isNode,R7=o.isPair,P7=o.isScalar,F7=o.isSeq,A7=$7.Pair,M7=U7.Scalar,w7=Z7.YAMLMap,K7=H7.YAMLSeq;var N7=z7.Lexer,b7=X7.LineCounter,S7=G7.Parser,qU=fq.parse,j7=fq.parseAllDocuments,C7=fq.parseDocument,V9=fq.stringify,E7=Y9.visit,g7=Y9.visitAsync;function y7(q){let $=L9(q,"utf-8");return qU($)}function x7(q){return L9(q,"utf-8")}function h7(q=process.cwd()){let $=["project.faf",".faf"];for(let Z of $){let H=O9(q,Z);if(W9(H))return H}let U=f7(q);if(U!==q)for(let Z of $){let H=O9(U,Z);if(W9(H))return H}return null}import{writeFileSync as u7}from"fs";import{join as k7}from"path";var T9=R0.orange,v7=R0.cyan,m7=R0.cyanDeep,p7="#FF9500",d7="#FF3B30",l7="#E6EDF3",c7="#6E7681",_9={TROPHY:{glyph:"\uD83C\uDFC6",color:T9},GOLD:{glyph:"★",color:T9},SILVER:{glyph:"◆",color:v7},BRONZE:{glyph:"◇",color:m7},GREEN:{glyph:"●",color:l7},YELLOW:{glyph:"●",color:p7},RED:{glyph:"○",color:d7},WHITE:{glyph:"♡",color:c7}};function D0(q){return String(q??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}var D9=["who","what","why","where","when","how"];function yq(q){return q.filter(([,$])=>$!==void 0&&$!==null&&String($).trim()!=="").map(([$,U])=>`<div class="row"><div class="k">${D0($)}</div><div class="v">${D0(U)}</div></div>`).join(`
143
143
  `)}function I9(q,$,U="project.faf"){let Z=D0(q.project?.name??"Project"),H=$.tier?.name??"WHITE",z=_9[H]??_9.WHITE,X=$.inherited?$.represents?`inherited from ${D0($.represents)}`:"inherited":`${$.score}%`,G=H==="TROPHY"&&!$.inherited,J=q.human_context??{},Q=D9.map((V)=>[V,J[V]]),W=Object.entries(J).filter(([V])=>!D9.includes(V)),B=[["goal",q.project?.goal],["main_language",q.project?.main_language],["type",q.project?.type],["framework",q.project?.framework],["faf_version",q.faf_version]],Y=Object.entries(q.stack??{}),L=Y.filter(([,V])=>V&&V!=="slotignored"&&String(V).trim()!==""),_=Y.filter(([,V])=>V==="slotignored").length;return`<!DOCTYPE html>
144
144
  <html lang="en">
145
145
  <head>
@@ -212,5 +212,5 @@ Rendered on-demand from your current <strong>${D0(U)}</strong><br>
212
212
  </html>
213
213
  `}function a7(q,$,U,Z="project.faf"){u7(k7(q,"project.html"),I9($,U,Z),"utf-8")}export{a7 as writeProjectHtml,k9 as validateFaf,K9 as slotsByCategory,u9 as scoreFafYaml,x7 as readFafRaw,y7 as readFaf,pq as kernel,S9 as isPlaceholder,F0 as getTier,j9 as getNextTier,I9 as generateProjectHtml,h7 as findFafFile,ZU as enrichScore,u as TIERS,w9 as SLOT_BY_PATH,t as SLOTS,UU as PLACEHOLDERS,R0 as FAF_HEX,b9 as ENTERPRISE_SLOTS,N9 as BASE_SLOTS};
214
214
 
215
- //# debugId=E66C13716307F8C864756E2164756E21
215
+ //# debugId=1373A6DAC8B91EBA64756E2164756E21
216
216
  //# sourceMappingURL=index.js.map