@contractspec/module.lifecycle-core 1.46.2 → 1.47.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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signal-collector.js","names":[
|
|
1
|
+
{"version":3,"file":"signal-collector.js","names":[],"sources":["../../src/collectors/signal-collector.ts"],"sourcesContent":["import type {\n LifecycleAssessmentInput,\n LifecycleAxes,\n LifecycleMetricSnapshot,\n LifecycleSignal,\n} from '@contractspec/lib.lifecycle';\nimport {\n CapitalPhase,\n CompanyPhase,\n ProductPhase,\n} from '@contractspec/lib.lifecycle';\nimport type { AnalyticsAdapter } from '../adapters/analytics-adapter';\nimport type { QuestionnaireAdapter } from '../adapters/questionnaire-adapter';\nimport type { IntentAdapter } from '../adapters/intent-adapter';\n\nconst DEFAULT_AXES: LifecycleAxes = {\n product: ProductPhase.Sketch,\n company: CompanyPhase.Solo,\n capital: CapitalPhase.Bootstrapped,\n};\n\nexport interface StageSignalCollectorOptions {\n analyticsAdapter?: AnalyticsAdapter;\n questionnaireAdapter?: QuestionnaireAdapter;\n intentAdapter?: IntentAdapter;\n}\n\nexport interface StageSignalCollectorResult {\n axes: LifecycleAxes;\n metrics: LifecycleMetricSnapshot;\n signals: LifecycleSignal[];\n questionnaireAnswers?: Record<string, unknown>;\n}\n\nexport class StageSignalCollector {\n private readonly options: StageSignalCollectorOptions;\n\n constructor(options: StageSignalCollectorOptions) {\n this.options = options;\n }\n\n async collect(\n input: LifecycleAssessmentInput = {}\n ): Promise<StageSignalCollectorResult> {\n const axes: LifecycleAxes = {\n ...DEFAULT_AXES,\n ...(input.axes ?? {}),\n };\n const metricsSnapshots: LifecycleMetricSnapshot[] = [];\n const aggregatedSignals: LifecycleSignal[] = [...(input.signals ?? [])];\n const questionnaireAnswers: Record<string, unknown> = {\n ...(input.questionnaireAnswers ?? {}),\n };\n\n if (input.metrics) {\n metricsSnapshots.push(input.metrics);\n }\n\n if (this.options.analyticsAdapter) {\n const result = await this.options.analyticsAdapter.fetch();\n if (result.axes) Object.assign(axes, result.axes);\n if (result.metrics) metricsSnapshots.push(result.metrics);\n if (result.signals) aggregatedSignals.push(...result.signals);\n }\n\n if (this.options.questionnaireAdapter) {\n const result = await this.options.questionnaireAdapter.fetch();\n if (result.axes) Object.assign(axes, result.axes);\n if (result.signals) aggregatedSignals.push(...result.signals);\n Object.assign(questionnaireAnswers, result.answers);\n }\n\n if (this.options.intentAdapter) {\n const result = await this.options.intentAdapter.fetch();\n if (result.signals) aggregatedSignals.push(...result.signals);\n }\n\n const metrics = mergeMetricSnapshots(metricsSnapshots);\n\n return {\n axes,\n metrics,\n signals: dedupeSignals(aggregatedSignals),\n questionnaireAnswers: Object.keys(questionnaireAnswers).length\n ? questionnaireAnswers\n : undefined,\n };\n }\n}\n\nconst mergeMetricSnapshots = (\n snapshots: LifecycleMetricSnapshot[]\n): LifecycleMetricSnapshot =>\n snapshots.reduce<LifecycleMetricSnapshot>((acc, snapshot) => {\n Object.entries(snapshot ?? {}).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n acc[key as keyof LifecycleMetricSnapshot] = value as never;\n }\n });\n return acc;\n }, {});\n\nconst dedupeSignals = (signals: LifecycleSignal[]): LifecycleSignal[] => {\n const seen = new Set<string>();\n return signals.filter((signal) => {\n if (!signal.id) return true;\n if (seen.has(signal.id)) return false;\n seen.add(signal.id);\n return true;\n });\n};\n"],"mappings":";;;AAeA,MAAM,eAA8B;CAClC,SAAS,aAAa;CACtB,SAAS,aAAa;CACtB,SAAS,aAAa;CACvB;AAeD,IAAa,uBAAb,MAAkC;CAChC,AAAiB;CAEjB,YAAY,SAAsC;AAChD,OAAK,UAAU;;CAGjB,MAAM,QACJ,QAAkC,EAAE,EACC;EACrC,MAAM,OAAsB;GAC1B,GAAG;GACH,GAAI,MAAM,QAAQ,EAAE;GACrB;EACD,MAAM,mBAA8C,EAAE;EACtD,MAAM,oBAAuC,CAAC,GAAI,MAAM,WAAW,EAAE,CAAE;EACvE,MAAM,uBAAgD,EACpD,GAAI,MAAM,wBAAwB,EAAE,EACrC;AAED,MAAI,MAAM,QACR,kBAAiB,KAAK,MAAM,QAAQ;AAGtC,MAAI,KAAK,QAAQ,kBAAkB;GACjC,MAAM,SAAS,MAAM,KAAK,QAAQ,iBAAiB,OAAO;AAC1D,OAAI,OAAO,KAAM,QAAO,OAAO,MAAM,OAAO,KAAK;AACjD,OAAI,OAAO,QAAS,kBAAiB,KAAK,OAAO,QAAQ;AACzD,OAAI,OAAO,QAAS,mBAAkB,KAAK,GAAG,OAAO,QAAQ;;AAG/D,MAAI,KAAK,QAAQ,sBAAsB;GACrC,MAAM,SAAS,MAAM,KAAK,QAAQ,qBAAqB,OAAO;AAC9D,OAAI,OAAO,KAAM,QAAO,OAAO,MAAM,OAAO,KAAK;AACjD,OAAI,OAAO,QAAS,mBAAkB,KAAK,GAAG,OAAO,QAAQ;AAC7D,UAAO,OAAO,sBAAsB,OAAO,QAAQ;;AAGrD,MAAI,KAAK,QAAQ,eAAe;GAC9B,MAAM,SAAS,MAAM,KAAK,QAAQ,cAAc,OAAO;AACvD,OAAI,OAAO,QAAS,mBAAkB,KAAK,GAAG,OAAO,QAAQ;;AAK/D,SAAO;GACL;GACA,SAJc,qBAAqB,iBAAiB;GAKpD,SAAS,cAAc,kBAAkB;GACzC,sBAAsB,OAAO,KAAK,qBAAqB,CAAC,SACpD,uBACA;GACL;;;AAIL,MAAM,wBACJ,cAEA,UAAU,QAAiC,KAAK,aAAa;AAC3D,QAAO,QAAQ,YAAY,EAAE,CAAC,CAAC,SAAS,CAAC,KAAK,WAAW;AACvD,MAAI,UAAU,UAAa,UAAU,KACnC,KAAI,OAAwC;GAE9C;AACF,QAAO;GACN,EAAE,CAAC;AAER,MAAM,iBAAiB,YAAkD;CACvE,MAAM,uBAAO,IAAI,KAAa;AAC9B,QAAO,QAAQ,QAAQ,WAAW;AAChC,MAAI,CAAC,OAAO,GAAI,QAAO;AACvB,MAAI,KAAK,IAAI,OAAO,GAAG,CAAE,QAAO;AAChC,OAAK,IAAI,OAAO,GAAG;AACnB,SAAO;GACP"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stage-scorer.js","names":["stageWeights"
|
|
1
|
+
{"version":3,"file":"stage-scorer.js","names":["stageWeights"],"sources":["../../src/scoring/stage-scorer.ts"],"sourcesContent":["import type {\n LifecycleMetricSnapshot,\n LifecycleScore,\n LifecycleSignal,\n} from '@contractspec/lib.lifecycle';\nimport {\n LIFECYCLE_STAGE_META,\n LifecycleStage,\n} from '@contractspec/lib.lifecycle';\nimport stageWeights from '../data/stage-weights.json' assert { type: 'json' };\n\ntype NumericMetricKey = Extract<\n {\n [Key in keyof LifecycleMetricSnapshot]: LifecycleMetricSnapshot[Key] extends\n | number\n | undefined\n ? Key\n : never;\n }[keyof LifecycleMetricSnapshot],\n string\n>;\n\ninterface MetricWeightConfig {\n weight: number;\n threshold: number;\n direction?: 'gte' | 'lte';\n}\n\ninterface StageWeightConfig {\n base: number;\n metrics?: Partial<Record<NumericMetricKey, MetricWeightConfig>>;\n signalKinds?: Partial<Record<string, number>>;\n}\n\ntype StageWeights = Record<string, StageWeightConfig>;\n\nconst DEFAULT_WEIGHTS = stageWeights as StageWeights;\n\nexport interface StageScoreInput {\n metrics: LifecycleMetricSnapshot;\n signals: LifecycleSignal[];\n}\n\nexport class StageScorer {\n private readonly weights: StageWeights;\n\n constructor(weights: StageWeights = DEFAULT_WEIGHTS) {\n this.weights = weights;\n }\n\n score(input: StageScoreInput): LifecycleScore[] {\n const kindStrength = evaluateSignalKinds(input.signals);\n\n const scores = Object.values(LifecycleStage)\n .filter(isStageValue)\n .map((stage) => {\n const stageName = LifecycleStage[stage];\n const config = this.weights[stageName] ?? { base: 0.5 };\n let score = config.base ?? 0.5;\n let contributions = 0;\n const totalPossible =\n Object.keys(config.metrics ?? {}).length +\n Object.keys(config.signalKinds ?? {}).length || 1;\n const supportingSignals: string[] = [];\n\n if (config.metrics) {\n Object.entries(config.metrics).forEach(\n ([metricKey, metricConfig]) => {\n const value = input.metrics[metricKey as NumericMetricKey];\n if (value === undefined || value === null) return;\n if (passesThreshold(value, metricConfig)) {\n score += metricConfig.weight;\n contributions += 1;\n supportingSignals.push(`metric:${metricKey}`);\n } else {\n score += metricConfig.weight * 0.25;\n }\n }\n );\n }\n\n if (config.signalKinds) {\n Object.entries(config.signalKinds).forEach(([kind, weight]) => {\n const strength = kindStrength[kind] ?? 0;\n if (strength > 0 && typeof weight === 'number') {\n score += weight;\n contributions += 1;\n supportingSignals.push(`signal:${kind}`);\n }\n });\n }\n\n score = clamp(score, 0, 1.25); // allow slight overage before clamp\n const confidence = clamp(contributions / totalPossible, 0.1, 1);\n\n return {\n stage,\n score,\n confidence,\n supportingSignals,\n };\n });\n\n return scores.sort((a, b) => {\n if (b.score === a.score) {\n return b.confidence - a.confidence;\n }\n return b.score - a.score;\n });\n }\n}\n\nconst passesThreshold = (\n value: number,\n config: MetricWeightConfig\n): boolean => {\n const direction = config.direction ?? 'gte';\n if (direction === 'gte') {\n return value >= config.threshold;\n }\n return value <= config.threshold;\n};\n\nconst clamp = (value: number, min: number, max: number): number =>\n Math.min(Math.max(value, min), max);\n\nconst evaluateSignalKinds = (\n signals: LifecycleSignal[]\n): Record<string, number> =>\n signals.reduce<Record<string, number>>((acc, signal) => {\n const key = signal.kind ?? 'unknown';\n acc[key] = (acc[key] ?? 0) + (signal.weight ?? 1);\n return acc;\n }, {});\n\nconst isStageValue = (\n value: string | LifecycleStage\n): value is LifecycleStage =>\n typeof value === 'number' && value in LIFECYCLE_STAGE_META;\n"],"mappings":";;;;AAoCA,MAAM,kBAAkBA;AAOxB,IAAa,cAAb,MAAyB;CACvB,AAAiB;CAEjB,YAAY,UAAwB,iBAAiB;AACnD,OAAK,UAAU;;CAGjB,MAAM,OAA0C;EAC9C,MAAM,eAAe,oBAAoB,MAAM,QAAQ;AAoDvD,SAlDe,OAAO,OAAO,eAAe,CACzC,OAAO,aAAa,CACpB,KAAK,UAAU;GACd,MAAM,YAAY,eAAe;GACjC,MAAM,SAAS,KAAK,QAAQ,cAAc,EAAE,MAAM,IAAK;GACvD,IAAI,QAAQ,OAAO,QAAQ;GAC3B,IAAI,gBAAgB;GACpB,MAAM,gBACJ,OAAO,KAAK,OAAO,WAAW,EAAE,CAAC,CAAC,SAChC,OAAO,KAAK,OAAO,eAAe,EAAE,CAAC,CAAC,UAAU;GACpD,MAAM,oBAA8B,EAAE;AAEtC,OAAI,OAAO,QACT,QAAO,QAAQ,OAAO,QAAQ,CAAC,SAC5B,CAAC,WAAW,kBAAkB;IAC7B,MAAM,QAAQ,MAAM,QAAQ;AAC5B,QAAI,UAAU,UAAa,UAAU,KAAM;AAC3C,QAAI,gBAAgB,OAAO,aAAa,EAAE;AACxC,cAAS,aAAa;AACtB,sBAAiB;AACjB,uBAAkB,KAAK,UAAU,YAAY;UAE7C,UAAS,aAAa,SAAS;KAGpC;AAGH,OAAI,OAAO,YACT,QAAO,QAAQ,OAAO,YAAY,CAAC,SAAS,CAAC,MAAM,YAAY;AAE7D,SADiB,aAAa,SAAS,KACxB,KAAK,OAAO,WAAW,UAAU;AAC9C,cAAS;AACT,sBAAiB;AACjB,uBAAkB,KAAK,UAAU,OAAO;;KAE1C;AAGJ,WAAQ,MAAM,OAAO,GAAG,KAAK;GAC7B,MAAM,aAAa,MAAM,gBAAgB,eAAe,IAAK,EAAE;AAE/D,UAAO;IACL;IACA;IACA;IACA;IACD;IACD,CAEU,MAAM,GAAG,MAAM;AAC3B,OAAI,EAAE,UAAU,EAAE,MAChB,QAAO,EAAE,aAAa,EAAE;AAE1B,UAAO,EAAE,QAAQ,EAAE;IACnB;;;AAIN,MAAM,mBACJ,OACA,WACY;AAEZ,MADkB,OAAO,aAAa,WACpB,MAChB,QAAO,SAAS,OAAO;AAEzB,QAAO,SAAS,OAAO;;AAGzB,MAAM,SAAS,OAAe,KAAa,QACzC,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI,EAAE,IAAI;AAErC,MAAM,uBACJ,YAEA,QAAQ,QAAgC,KAAK,WAAW;CACtD,MAAM,MAAM,OAAO,QAAQ;AAC3B,KAAI,QAAQ,IAAI,QAAQ,MAAM,OAAO,UAAU;AAC/C,QAAO;GACN,EAAE,CAAC;AAER,MAAM,gBACJ,UAEA,OAAO,UAAU,YAAY,SAAS"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contractspec/module.lifecycle-core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.47.0",
|
|
4
4
|
"description": "Core lifecycle stage definitions and transitions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"contractspec",
|
|
@@ -11,8 +11,6 @@
|
|
|
11
11
|
"typescript"
|
|
12
12
|
],
|
|
13
13
|
"type": "module",
|
|
14
|
-
"main": "./dist/index.js",
|
|
15
|
-
"module": "./dist/index.js",
|
|
16
14
|
"types": "./dist/index.d.ts",
|
|
17
15
|
"files": [
|
|
18
16
|
"dist",
|
|
@@ -30,15 +28,15 @@
|
|
|
30
28
|
"lint": "bun lint:fix",
|
|
31
29
|
"lint:fix": "eslint src --fix",
|
|
32
30
|
"lint:check": "eslint src",
|
|
33
|
-
"test": "bun
|
|
31
|
+
"test": "bun test"
|
|
34
32
|
},
|
|
35
33
|
"dependencies": {
|
|
36
|
-
"@contractspec/lib.lifecycle": "1.
|
|
34
|
+
"@contractspec/lib.lifecycle": "1.47.0"
|
|
37
35
|
},
|
|
38
36
|
"devDependencies": {
|
|
39
|
-
"@contractspec/tool.tsdown": "1.
|
|
40
|
-
"@contractspec/tool.typescript": "1.
|
|
41
|
-
"tsdown": "^0.
|
|
37
|
+
"@contractspec/tool.tsdown": "1.47.0",
|
|
38
|
+
"@contractspec/tool.typescript": "1.47.0",
|
|
39
|
+
"tsdown": "^0.19.0",
|
|
42
40
|
"typescript": "^5.9.3"
|
|
43
41
|
},
|
|
44
42
|
"exports": {
|