@contractspec/module.lifecycle-core 3.7.5 → 3.7.7

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/README.md CHANGED
@@ -1,77 +1,67 @@
1
1
  # @contractspec/module.lifecycle-core
2
2
 
3
- Website: https://contractspec.io/
4
-
5
-
6
- Signal collection + scoring module for ContractSpec lifecycle assessments. It wraps analytics/questionnaire adapters, applies weighting logic, and produces normalized `LifecycleAssessment` objects.
7
-
8
- ## Features
9
-
10
- - Adapter-driven signal collector (analytics, questionnaires, intent logs)
11
- - Configurable stage scoring weights
12
- - Milestone planner backed by JSON catalog
13
- - Lifecycle orchestrator that returns assessments + scorecards
14
-
15
- ## Usage
16
-
17
- ```ts
18
- import {
19
- LifecycleOrchestrator,
20
- StageSignalCollector,
21
- StageScorer,
22
- LifecycleMilestonePlanner,
23
- } from '@contractspec/module.lifecycle-core';
24
-
25
- const collector = new StageSignalCollector({
26
- analyticsAdapter,
27
- questionnaireAdapter,
28
- });
29
-
30
- const scorer = new StageScorer();
31
- const planner = new LifecycleMilestonePlanner();
32
-
33
- const orchestrator = new LifecycleOrchestrator({
34
- collector,
35
- scorer,
36
- planner,
37
- });
38
-
39
- const assessment = await orchestrator.run({
40
- questionnaireAnswers: answers,
41
- });
42
-
43
- console.log(assessment.stage, assessment.confidence);
44
- ```
45
-
46
- Adapters are interfaces—you can implement them inside bundles, Studio services, or examples without touching this module.*** End Patch
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
3
+ Website: https://contractspec.io
59
4
 
5
+ **Core lifecycle stage definitions and transitions.**
60
6
 
7
+ ## What It Provides
61
8
 
9
+ - **Layer**: module.
10
+ - **Consumers**: modules (lifecycle-advisor), bundles (library, contractspec-studio), apps (web-landing, cli).
11
+ - `src/adapters/` contains runtime, provider, or environment-specific adapters.
12
+ - Related ContractSpec packages include `@contractspec/lib.contracts-spec`, `@contractspec/lib.lifecycle`, `@contractspec/tool.bun`, `@contractspec/tool.typescript`.
13
+ - `src/adapters/` contains runtime, provider, or environment-specific adapters.
62
14
 
15
+ ## Installation
63
16
 
17
+ `npm install @contractspec/module.lifecycle-core`
64
18
 
19
+ or
65
20
 
21
+ `bun add @contractspec/module.lifecycle-core`
66
22
 
23
+ ## Usage
67
24
 
25
+ Import the root entrypoint from `@contractspec/module.lifecycle-core`, or choose a documented subpath when you only need one part of the package surface.
68
26
 
27
+ ## Architecture
69
28
 
29
+ - `src/adapters/` contains runtime, provider, or environment-specific adapters.
30
+ - `src/collectors` is part of the package's public or composition surface.
31
+ - `src/data/` contains static content, registries, and package-local datasets.
32
+ - `src/i18n` is part of the package's public or composition surface.
33
+ - `src/index.ts` is the root public barrel and package entrypoint.
34
+ - `src/orchestrator` is part of the package's public or composition surface.
35
+ - `src/planning` is part of the package's public or composition surface.
70
36
 
37
+ ## Public Entry Points
71
38
 
39
+ - Export `.` resolves through `./src/index.ts`.
72
40
 
41
+ ## Local Commands
73
42
 
43
+ - `bun run dev` — contractspec-bun-build dev
44
+ - `bun run build` — bun run prebuild && bun run build:bundle && bun run build:types
45
+ - `bun run test` — bun test
46
+ - `bun run lint` — bun lint:fix
47
+ - `bun run lint:check` — biome check .
48
+ - `bun run lint:fix` — biome check --write --unsafe --only=nursery/useSortedClasses . && biome check --write .
49
+ - `bun run typecheck` — tsc --noEmit
50
+ - `bun run publish:pkg` — bun publish --tolerate-republish --ignore-scripts --verbose
51
+ - `bun run publish:pkg:canary` — bun publish:pkg --tag canary
52
+ - `bun run clean` — rimraf dist .turbo
53
+ - `bun run build:bundle` — contractspec-bun-build transpile
54
+ - `bun run build:types` — contractspec-bun-build types
55
+ - `bun run prebuild` — contractspec-bun-build prebuild
74
56
 
57
+ ## Recent Updates
75
58
 
59
+ - Replace eslint+prettier by biomejs to optimize speed.
60
+ - Resolve lint/test regressions after voice capability updates.
61
+ - Add full i18n support across all 10 packages (en/fr/es, 460 keys).
76
62
 
63
+ ## Notes
77
64
 
65
+ - Depends on `lib.lifecycle` for foundational types -- this module adds orchestration on top.
66
+ - Stage transition rules are the source of truth; changes here cascade to lifecycle-advisor and all consuming bundles.
67
+ - Stage data in `src/data/` must remain backward-compatible to avoid breaking persisted project states.
@@ -78,11 +78,168 @@ var dedupeSignals = (signals) => {
78
78
  return true;
79
79
  });
80
80
  };
81
- // src/scoring/stage-scorer.ts
81
+ // src/orchestrator/lifecycle-orchestrator.ts
82
82
  import {
83
+ getLocalizedStageMeta,
83
84
  LIFECYCLE_STAGE_META,
84
85
  LifecycleStage
85
86
  } from "@contractspec/lib.lifecycle";
87
+
88
+ class LifecycleOrchestrator {
89
+ collector;
90
+ scorer;
91
+ planner;
92
+ locale;
93
+ constructor(options) {
94
+ this.collector = options.collector;
95
+ this.scorer = options.scorer;
96
+ this.planner = options.milestonePlanner;
97
+ this.locale = options.locale;
98
+ }
99
+ async run(input) {
100
+ const collected = await this.collector.collect(input);
101
+ const scorecard = this.scorer.score({
102
+ metrics: collected.metrics,
103
+ signals: collected.signals
104
+ });
105
+ const top = scorecard[0] ?? fallbackScore();
106
+ const stageMeta = this.locale ? getLocalizedStageMeta(this.locale) : LIFECYCLE_STAGE_META;
107
+ const meta = stageMeta[top.stage];
108
+ return {
109
+ stage: top.stage,
110
+ confidence: top.confidence,
111
+ axes: collected.axes,
112
+ signals: collected.signals,
113
+ metrics: toMetricRecord(collected.metrics),
114
+ gaps: meta.focusAreas.slice(0, 3),
115
+ focusAreas: meta.focusAreas,
116
+ scorecard,
117
+ generatedAt: new Date().toISOString()
118
+ };
119
+ }
120
+ getUpcomingMilestones(stage, completedMilestoneIds = [], limit = 5) {
121
+ if (!this.planner)
122
+ return [];
123
+ return this.planner.getUpcoming(stage, completedMilestoneIds, limit);
124
+ }
125
+ }
126
+ var fallbackScore = () => ({
127
+ stage: LifecycleStage.Exploration,
128
+ score: 0.3,
129
+ confidence: 0.3,
130
+ supportingSignals: []
131
+ });
132
+ var toMetricRecord = (snapshot) => Object.entries(snapshot ?? {}).reduce((acc, [key, value]) => {
133
+ if (typeof value === "number") {
134
+ acc[key] = value;
135
+ }
136
+ return acc;
137
+ }, {});
138
+ // src/data/milestones-catalog.json
139
+ var milestones_catalog_default = [
140
+ {
141
+ id: "stage0-problem-statement",
142
+ stage: 0,
143
+ category: "product",
144
+ title: "Write the pain statement",
145
+ description: "Capture the clearest description of the top problem in the customer’s own words.",
146
+ priority: 1,
147
+ actionItems: [
148
+ "Interview at least 5 ideal customers",
149
+ "Synthesize quotes into a one-page brief"
150
+ ]
151
+ },
152
+ {
153
+ id: "stage1-prototype-loop",
154
+ stage: 1,
155
+ category: "product",
156
+ title: "Prototype feedback loop",
157
+ description: "Ship a clickable prototype and gather 3 rounds of feedback.",
158
+ priority: 2,
159
+ actionItems: [
160
+ "Create a low-fidelity prototype",
161
+ "Schedule standing feedback calls"
162
+ ]
163
+ },
164
+ {
165
+ id: "stage2-activation",
166
+ stage: 2,
167
+ category: "operations",
168
+ title: "Activation checklist",
169
+ description: "Define the minimum steps required for a new user to succeed.",
170
+ priority: 1,
171
+ actionItems: [
172
+ "Document onboarding flow",
173
+ "Instrument activation analytics"
174
+ ]
175
+ },
176
+ {
177
+ id: "stage3-retention-narrative",
178
+ stage: 3,
179
+ category: "product",
180
+ title: "Retention narrative",
181
+ description: "Create the before/after story that proves why users stay.",
182
+ priority: 2,
183
+ actionItems: [
184
+ "Interview 3 retained users",
185
+ "Publish a one-pager with concrete metrics"
186
+ ]
187
+ },
188
+ {
189
+ id: "stage4-growth-loop",
190
+ stage: 4,
191
+ category: "growth",
192
+ title: "Install a growth loop",
193
+ description: "Stand up a repeatable acquisition → activation → referral motion.",
194
+ priority: 1,
195
+ actionItems: [
196
+ "Define loop metrics",
197
+ "Assign owners for each stage",
198
+ "Review weekly"
199
+ ]
200
+ },
201
+ {
202
+ id: "stage5-platform-blueprint",
203
+ stage: 5,
204
+ category: "product",
205
+ title: "Platform blueprint",
206
+ description: "Align on APIs, integrations, and governance for partners.",
207
+ priority: 2,
208
+ actionItems: [
209
+ "Create integration scoring rubric",
210
+ "Publish partner onboarding checklist"
211
+ ]
212
+ },
213
+ {
214
+ id: "stage6-renewal-ops",
215
+ stage: 6,
216
+ category: "operations",
217
+ title: "Renewal operating rhythm",
218
+ description: "Decide whether to optimize, reinvest, or sunset each major surface.",
219
+ priority: 1,
220
+ actionItems: [
221
+ "Hold quarterly renewal review",
222
+ "Document reinvestment bets"
223
+ ]
224
+ }
225
+ ];
226
+
227
+ // src/planning/milestone-planner.ts
228
+ class LifecycleMilestonePlanner {
229
+ milestones;
230
+ constructor(customCatalog) {
231
+ this.milestones = customCatalog ?? milestones_catalog_default;
232
+ }
233
+ getUpcoming(stage, completedIds = [], limit = 5) {
234
+ const completedSet = new Set(completedIds);
235
+ return this.milestones.filter((milestone) => milestone.stage === stage && !completedSet.has(milestone.id)).sort((a, b) => a.priority - b.priority).slice(0, limit);
236
+ }
237
+ }
238
+ // src/scoring/stage-scorer.ts
239
+ import {
240
+ LIFECYCLE_STAGE_META as LIFECYCLE_STAGE_META2,
241
+ LifecycleStage as LifecycleStage2
242
+ } from "@contractspec/lib.lifecycle";
86
243
  // src/data/stage-weights.json
87
244
  var stage_weights_default = {
88
245
  Exploration: {
@@ -204,8 +361,8 @@ class StageScorer {
204
361
  }
205
362
  score(input) {
206
363
  const kindStrength = evaluateSignalKinds(input.signals);
207
- const scores = Object.values(LifecycleStage).filter(isStageValue).map((stage) => {
208
- const stageName = LifecycleStage[stage];
364
+ const scores = Object.values(LifecycleStage2).filter(isStageValue).map((stage) => {
365
+ const stageName = LifecycleStage2[stage];
209
366
  const config = this.weights[stageName] ?? { base: 0.5 };
210
367
  let score = config.base ?? 0.5;
211
368
  let contributions = 0;
@@ -265,164 +422,7 @@ var evaluateSignalKinds = (signals) => signals.reduce((acc, signal) => {
265
422
  acc[key] = (acc[key] ?? 0) + (signal.weight ?? 1);
266
423
  return acc;
267
424
  }, {});
268
- var isStageValue = (value) => typeof value === "number" && (value in LIFECYCLE_STAGE_META);
269
- // src/orchestrator/lifecycle-orchestrator.ts
270
- import {
271
- LIFECYCLE_STAGE_META as LIFECYCLE_STAGE_META2,
272
- LifecycleStage as LifecycleStage2,
273
- getLocalizedStageMeta
274
- } from "@contractspec/lib.lifecycle";
275
-
276
- class LifecycleOrchestrator {
277
- collector;
278
- scorer;
279
- planner;
280
- locale;
281
- constructor(options) {
282
- this.collector = options.collector;
283
- this.scorer = options.scorer;
284
- this.planner = options.milestonePlanner;
285
- this.locale = options.locale;
286
- }
287
- async run(input) {
288
- const collected = await this.collector.collect(input);
289
- const scorecard = this.scorer.score({
290
- metrics: collected.metrics,
291
- signals: collected.signals
292
- });
293
- const top = scorecard[0] ?? fallbackScore();
294
- const stageMeta = this.locale ? getLocalizedStageMeta(this.locale) : LIFECYCLE_STAGE_META2;
295
- const meta = stageMeta[top.stage];
296
- return {
297
- stage: top.stage,
298
- confidence: top.confidence,
299
- axes: collected.axes,
300
- signals: collected.signals,
301
- metrics: toMetricRecord(collected.metrics),
302
- gaps: meta.focusAreas.slice(0, 3),
303
- focusAreas: meta.focusAreas,
304
- scorecard,
305
- generatedAt: new Date().toISOString()
306
- };
307
- }
308
- getUpcomingMilestones(stage, completedMilestoneIds = [], limit = 5) {
309
- if (!this.planner)
310
- return [];
311
- return this.planner.getUpcoming(stage, completedMilestoneIds, limit);
312
- }
313
- }
314
- var fallbackScore = () => ({
315
- stage: LifecycleStage2.Exploration,
316
- score: 0.3,
317
- confidence: 0.3,
318
- supportingSignals: []
319
- });
320
- var toMetricRecord = (snapshot) => Object.entries(snapshot ?? {}).reduce((acc, [key, value]) => {
321
- if (typeof value === "number") {
322
- acc[key] = value;
323
- }
324
- return acc;
325
- }, {});
326
- // src/data/milestones-catalog.json
327
- var milestones_catalog_default = [
328
- {
329
- id: "stage0-problem-statement",
330
- stage: 0,
331
- category: "product",
332
- title: "Write the pain statement",
333
- description: "Capture the clearest description of the top problem in the customer’s own words.",
334
- priority: 1,
335
- actionItems: [
336
- "Interview at least 5 ideal customers",
337
- "Synthesize quotes into a one-page brief"
338
- ]
339
- },
340
- {
341
- id: "stage1-prototype-loop",
342
- stage: 1,
343
- category: "product",
344
- title: "Prototype feedback loop",
345
- description: "Ship a clickable prototype and gather 3 rounds of feedback.",
346
- priority: 2,
347
- actionItems: [
348
- "Create a low-fidelity prototype",
349
- "Schedule standing feedback calls"
350
- ]
351
- },
352
- {
353
- id: "stage2-activation",
354
- stage: 2,
355
- category: "operations",
356
- title: "Activation checklist",
357
- description: "Define the minimum steps required for a new user to succeed.",
358
- priority: 1,
359
- actionItems: [
360
- "Document onboarding flow",
361
- "Instrument activation analytics"
362
- ]
363
- },
364
- {
365
- id: "stage3-retention-narrative",
366
- stage: 3,
367
- category: "product",
368
- title: "Retention narrative",
369
- description: "Create the before/after story that proves why users stay.",
370
- priority: 2,
371
- actionItems: [
372
- "Interview 3 retained users",
373
- "Publish a one-pager with concrete metrics"
374
- ]
375
- },
376
- {
377
- id: "stage4-growth-loop",
378
- stage: 4,
379
- category: "growth",
380
- title: "Install a growth loop",
381
- description: "Stand up a repeatable acquisition → activation → referral motion.",
382
- priority: 1,
383
- actionItems: [
384
- "Define loop metrics",
385
- "Assign owners for each stage",
386
- "Review weekly"
387
- ]
388
- },
389
- {
390
- id: "stage5-platform-blueprint",
391
- stage: 5,
392
- category: "product",
393
- title: "Platform blueprint",
394
- description: "Align on APIs, integrations, and governance for partners.",
395
- priority: 2,
396
- actionItems: [
397
- "Create integration scoring rubric",
398
- "Publish partner onboarding checklist"
399
- ]
400
- },
401
- {
402
- id: "stage6-renewal-ops",
403
- stage: 6,
404
- category: "operations",
405
- title: "Renewal operating rhythm",
406
- description: "Decide whether to optimize, reinvest, or sunset each major surface.",
407
- priority: 1,
408
- actionItems: [
409
- "Hold quarterly renewal review",
410
- "Document reinvestment bets"
411
- ]
412
- }
413
- ];
414
-
415
- // src/planning/milestone-planner.ts
416
- class LifecycleMilestonePlanner {
417
- milestones;
418
- constructor(customCatalog) {
419
- this.milestones = customCatalog ?? milestones_catalog_default;
420
- }
421
- getUpcoming(stage, completedIds = [], limit = 5) {
422
- const completedSet = new Set(completedIds);
423
- return this.milestones.filter((milestone) => milestone.stage === stage && !completedSet.has(milestone.id)).sort((a, b) => a.priority - b.priority).slice(0, limit);
424
- }
425
- }
425
+ var isStageValue = (value) => typeof value === "number" && (value in LIFECYCLE_STAGE_META2);
426
426
  export {
427
427
  StageSignalCollector,
428
428
  StageScorer,
@@ -1,7 +1,7 @@
1
1
  import type { LifecycleAssessmentInput, LifecycleAxes, LifecycleMetricSnapshot, LifecycleSignal } from '@contractspec/lib.lifecycle';
2
2
  import type { AnalyticsAdapter } from '../adapters/analytics-adapter';
3
- import type { QuestionnaireAdapter } from '../adapters/questionnaire-adapter';
4
3
  import type { IntentAdapter } from '../adapters/intent-adapter';
4
+ import type { QuestionnaireAdapter } from '../adapters/questionnaire-adapter';
5
5
  export interface StageSignalCollectorOptions {
6
6
  analyticsAdapter?: AnalyticsAdapter;
7
7
  questionnaireAdapter?: QuestionnaireAdapter;
@@ -4,5 +4,5 @@
4
4
  * @module i18n/catalogs
5
5
  */
6
6
  export { enMessages } from './en';
7
- export { frMessages } from './fr';
8
7
  export { esMessages } from './es';
8
+ export { frMessages } from './fr';
@@ -3,12 +3,12 @@
3
3
  *
4
4
  * @module i18n
5
5
  */
6
- export { createLifecycleCoreI18n, getDefaultI18n, resetI18nRegistry, } from './messages';
7
- export type { LifecycleCoreI18n } from './messages';
8
- export { resolveLocale, isSupportedLocale, DEFAULT_LOCALE, SUPPORTED_LOCALES, } from './locale';
9
- export type { SupportedLocale } from './locale';
10
- export { I18N_KEYS, MILESTONE_KEYS } from './keys';
11
- export type { LifecycleCoreMessageKey } from './keys';
12
6
  export { enMessages } from './catalogs/en';
13
- export { frMessages } from './catalogs/fr';
14
7
  export { esMessages } from './catalogs/es';
8
+ export { frMessages } from './catalogs/fr';
9
+ export type { LifecycleCoreMessageKey } from './keys';
10
+ export { I18N_KEYS, MILESTONE_KEYS } from './keys';
11
+ export type { SupportedLocale } from './locale';
12
+ export { DEFAULT_LOCALE, isSupportedLocale, resolveLocale, SUPPORTED_LOCALES, } from './locale';
13
+ export type { LifecycleCoreI18n } from './messages';
14
+ export { createLifecycleCoreI18n, getDefaultI18n, resetI18nRegistry, } from './messages';
@@ -5,4 +5,4 @@
5
5
  *
6
6
  * @module i18n/locale
7
7
  */
8
- export { DEFAULT_LOCALE, SUPPORTED_LOCALES, resolveLocale, isSupportedLocale, type SupportedLocale, } from '@contractspec/lib.contracts-spec/translations';
8
+ export { DEFAULT_LOCALE, isSupportedLocale, resolveLocale, SUPPORTED_LOCALES, type SupportedLocale, } from '@contractspec/lib.contracts-spec/translations';
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- export * from './collectors/signal-collector';
2
1
  export * from './adapters/analytics-adapter';
3
- export * from './adapters/questionnaire-adapter';
4
2
  export * from './adapters/intent-adapter';
5
- export * from './scoring/stage-scorer';
3
+ export * from './adapters/questionnaire-adapter';
4
+ export * from './collectors/signal-collector';
6
5
  export * from './orchestrator/lifecycle-orchestrator';
7
6
  export * from './planning/milestone-planner';
7
+ export * from './scoring/stage-scorer';