@contractspec/module.lifecycle-core 3.7.6 → 3.7.10

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/index.js CHANGED
@@ -79,11 +79,168 @@ var dedupeSignals = (signals) => {
79
79
  return true;
80
80
  });
81
81
  };
82
- // src/scoring/stage-scorer.ts
82
+ // src/orchestrator/lifecycle-orchestrator.ts
83
83
  import {
84
+ getLocalizedStageMeta,
84
85
  LIFECYCLE_STAGE_META,
85
86
  LifecycleStage
86
87
  } from "@contractspec/lib.lifecycle";
88
+
89
+ class LifecycleOrchestrator {
90
+ collector;
91
+ scorer;
92
+ planner;
93
+ locale;
94
+ constructor(options) {
95
+ this.collector = options.collector;
96
+ this.scorer = options.scorer;
97
+ this.planner = options.milestonePlanner;
98
+ this.locale = options.locale;
99
+ }
100
+ async run(input) {
101
+ const collected = await this.collector.collect(input);
102
+ const scorecard = this.scorer.score({
103
+ metrics: collected.metrics,
104
+ signals: collected.signals
105
+ });
106
+ const top = scorecard[0] ?? fallbackScore();
107
+ const stageMeta = this.locale ? getLocalizedStageMeta(this.locale) : LIFECYCLE_STAGE_META;
108
+ const meta = stageMeta[top.stage];
109
+ return {
110
+ stage: top.stage,
111
+ confidence: top.confidence,
112
+ axes: collected.axes,
113
+ signals: collected.signals,
114
+ metrics: toMetricRecord(collected.metrics),
115
+ gaps: meta.focusAreas.slice(0, 3),
116
+ focusAreas: meta.focusAreas,
117
+ scorecard,
118
+ generatedAt: new Date().toISOString()
119
+ };
120
+ }
121
+ getUpcomingMilestones(stage, completedMilestoneIds = [], limit = 5) {
122
+ if (!this.planner)
123
+ return [];
124
+ return this.planner.getUpcoming(stage, completedMilestoneIds, limit);
125
+ }
126
+ }
127
+ var fallbackScore = () => ({
128
+ stage: LifecycleStage.Exploration,
129
+ score: 0.3,
130
+ confidence: 0.3,
131
+ supportingSignals: []
132
+ });
133
+ var toMetricRecord = (snapshot) => Object.entries(snapshot ?? {}).reduce((acc, [key, value]) => {
134
+ if (typeof value === "number") {
135
+ acc[key] = value;
136
+ }
137
+ return acc;
138
+ }, {});
139
+ // src/data/milestones-catalog.json
140
+ var milestones_catalog_default = [
141
+ {
142
+ id: "stage0-problem-statement",
143
+ stage: 0,
144
+ category: "product",
145
+ title: "Write the pain statement",
146
+ description: "Capture the clearest description of the top problem in the customer\u2019s own words.",
147
+ priority: 1,
148
+ actionItems: [
149
+ "Interview at least 5 ideal customers",
150
+ "Synthesize quotes into a one-page brief"
151
+ ]
152
+ },
153
+ {
154
+ id: "stage1-prototype-loop",
155
+ stage: 1,
156
+ category: "product",
157
+ title: "Prototype feedback loop",
158
+ description: "Ship a clickable prototype and gather 3 rounds of feedback.",
159
+ priority: 2,
160
+ actionItems: [
161
+ "Create a low-fidelity prototype",
162
+ "Schedule standing feedback calls"
163
+ ]
164
+ },
165
+ {
166
+ id: "stage2-activation",
167
+ stage: 2,
168
+ category: "operations",
169
+ title: "Activation checklist",
170
+ description: "Define the minimum steps required for a new user to succeed.",
171
+ priority: 1,
172
+ actionItems: [
173
+ "Document onboarding flow",
174
+ "Instrument activation analytics"
175
+ ]
176
+ },
177
+ {
178
+ id: "stage3-retention-narrative",
179
+ stage: 3,
180
+ category: "product",
181
+ title: "Retention narrative",
182
+ description: "Create the before/after story that proves why users stay.",
183
+ priority: 2,
184
+ actionItems: [
185
+ "Interview 3 retained users",
186
+ "Publish a one-pager with concrete metrics"
187
+ ]
188
+ },
189
+ {
190
+ id: "stage4-growth-loop",
191
+ stage: 4,
192
+ category: "growth",
193
+ title: "Install a growth loop",
194
+ description: "Stand up a repeatable acquisition \u2192 activation \u2192 referral motion.",
195
+ priority: 1,
196
+ actionItems: [
197
+ "Define loop metrics",
198
+ "Assign owners for each stage",
199
+ "Review weekly"
200
+ ]
201
+ },
202
+ {
203
+ id: "stage5-platform-blueprint",
204
+ stage: 5,
205
+ category: "product",
206
+ title: "Platform blueprint",
207
+ description: "Align on APIs, integrations, and governance for partners.",
208
+ priority: 2,
209
+ actionItems: [
210
+ "Create integration scoring rubric",
211
+ "Publish partner onboarding checklist"
212
+ ]
213
+ },
214
+ {
215
+ id: "stage6-renewal-ops",
216
+ stage: 6,
217
+ category: "operations",
218
+ title: "Renewal operating rhythm",
219
+ description: "Decide whether to optimize, reinvest, or sunset each major surface.",
220
+ priority: 1,
221
+ actionItems: [
222
+ "Hold quarterly renewal review",
223
+ "Document reinvestment bets"
224
+ ]
225
+ }
226
+ ];
227
+
228
+ // src/planning/milestone-planner.ts
229
+ class LifecycleMilestonePlanner {
230
+ milestones;
231
+ constructor(customCatalog) {
232
+ this.milestones = customCatalog ?? milestones_catalog_default;
233
+ }
234
+ getUpcoming(stage, completedIds = [], limit = 5) {
235
+ const completedSet = new Set(completedIds);
236
+ return this.milestones.filter((milestone) => milestone.stage === stage && !completedSet.has(milestone.id)).sort((a, b) => a.priority - b.priority).slice(0, limit);
237
+ }
238
+ }
239
+ // src/scoring/stage-scorer.ts
240
+ import {
241
+ LIFECYCLE_STAGE_META as LIFECYCLE_STAGE_META2,
242
+ LifecycleStage as LifecycleStage2
243
+ } from "@contractspec/lib.lifecycle";
87
244
  // src/data/stage-weights.json
88
245
  var stage_weights_default = {
89
246
  Exploration: {
@@ -205,8 +362,8 @@ class StageScorer {
205
362
  }
206
363
  score(input) {
207
364
  const kindStrength = evaluateSignalKinds(input.signals);
208
- const scores = Object.values(LifecycleStage).filter(isStageValue).map((stage) => {
209
- const stageName = LifecycleStage[stage];
365
+ const scores = Object.values(LifecycleStage2).filter(isStageValue).map((stage) => {
366
+ const stageName = LifecycleStage2[stage];
210
367
  const config = this.weights[stageName] ?? { base: 0.5 };
211
368
  let score = config.base ?? 0.5;
212
369
  let contributions = 0;
@@ -266,164 +423,7 @@ var evaluateSignalKinds = (signals) => signals.reduce((acc, signal) => {
266
423
  acc[key] = (acc[key] ?? 0) + (signal.weight ?? 1);
267
424
  return acc;
268
425
  }, {});
269
- var isStageValue = (value) => typeof value === "number" && (value in LIFECYCLE_STAGE_META);
270
- // src/orchestrator/lifecycle-orchestrator.ts
271
- import {
272
- LIFECYCLE_STAGE_META as LIFECYCLE_STAGE_META2,
273
- LifecycleStage as LifecycleStage2,
274
- getLocalizedStageMeta
275
- } from "@contractspec/lib.lifecycle";
276
-
277
- class LifecycleOrchestrator {
278
- collector;
279
- scorer;
280
- planner;
281
- locale;
282
- constructor(options) {
283
- this.collector = options.collector;
284
- this.scorer = options.scorer;
285
- this.planner = options.milestonePlanner;
286
- this.locale = options.locale;
287
- }
288
- async run(input) {
289
- const collected = await this.collector.collect(input);
290
- const scorecard = this.scorer.score({
291
- metrics: collected.metrics,
292
- signals: collected.signals
293
- });
294
- const top = scorecard[0] ?? fallbackScore();
295
- const stageMeta = this.locale ? getLocalizedStageMeta(this.locale) : LIFECYCLE_STAGE_META2;
296
- const meta = stageMeta[top.stage];
297
- return {
298
- stage: top.stage,
299
- confidence: top.confidence,
300
- axes: collected.axes,
301
- signals: collected.signals,
302
- metrics: toMetricRecord(collected.metrics),
303
- gaps: meta.focusAreas.slice(0, 3),
304
- focusAreas: meta.focusAreas,
305
- scorecard,
306
- generatedAt: new Date().toISOString()
307
- };
308
- }
309
- getUpcomingMilestones(stage, completedMilestoneIds = [], limit = 5) {
310
- if (!this.planner)
311
- return [];
312
- return this.planner.getUpcoming(stage, completedMilestoneIds, limit);
313
- }
314
- }
315
- var fallbackScore = () => ({
316
- stage: LifecycleStage2.Exploration,
317
- score: 0.3,
318
- confidence: 0.3,
319
- supportingSignals: []
320
- });
321
- var toMetricRecord = (snapshot) => Object.entries(snapshot ?? {}).reduce((acc, [key, value]) => {
322
- if (typeof value === "number") {
323
- acc[key] = value;
324
- }
325
- return acc;
326
- }, {});
327
- // src/data/milestones-catalog.json
328
- var milestones_catalog_default = [
329
- {
330
- id: "stage0-problem-statement",
331
- stage: 0,
332
- category: "product",
333
- title: "Write the pain statement",
334
- description: "Capture the clearest description of the top problem in the customer\u2019s own words.",
335
- priority: 1,
336
- actionItems: [
337
- "Interview at least 5 ideal customers",
338
- "Synthesize quotes into a one-page brief"
339
- ]
340
- },
341
- {
342
- id: "stage1-prototype-loop",
343
- stage: 1,
344
- category: "product",
345
- title: "Prototype feedback loop",
346
- description: "Ship a clickable prototype and gather 3 rounds of feedback.",
347
- priority: 2,
348
- actionItems: [
349
- "Create a low-fidelity prototype",
350
- "Schedule standing feedback calls"
351
- ]
352
- },
353
- {
354
- id: "stage2-activation",
355
- stage: 2,
356
- category: "operations",
357
- title: "Activation checklist",
358
- description: "Define the minimum steps required for a new user to succeed.",
359
- priority: 1,
360
- actionItems: [
361
- "Document onboarding flow",
362
- "Instrument activation analytics"
363
- ]
364
- },
365
- {
366
- id: "stage3-retention-narrative",
367
- stage: 3,
368
- category: "product",
369
- title: "Retention narrative",
370
- description: "Create the before/after story that proves why users stay.",
371
- priority: 2,
372
- actionItems: [
373
- "Interview 3 retained users",
374
- "Publish a one-pager with concrete metrics"
375
- ]
376
- },
377
- {
378
- id: "stage4-growth-loop",
379
- stage: 4,
380
- category: "growth",
381
- title: "Install a growth loop",
382
- description: "Stand up a repeatable acquisition \u2192 activation \u2192 referral motion.",
383
- priority: 1,
384
- actionItems: [
385
- "Define loop metrics",
386
- "Assign owners for each stage",
387
- "Review weekly"
388
- ]
389
- },
390
- {
391
- id: "stage5-platform-blueprint",
392
- stage: 5,
393
- category: "product",
394
- title: "Platform blueprint",
395
- description: "Align on APIs, integrations, and governance for partners.",
396
- priority: 2,
397
- actionItems: [
398
- "Create integration scoring rubric",
399
- "Publish partner onboarding checklist"
400
- ]
401
- },
402
- {
403
- id: "stage6-renewal-ops",
404
- stage: 6,
405
- category: "operations",
406
- title: "Renewal operating rhythm",
407
- description: "Decide whether to optimize, reinvest, or sunset each major surface.",
408
- priority: 1,
409
- actionItems: [
410
- "Hold quarterly renewal review",
411
- "Document reinvestment bets"
412
- ]
413
- }
414
- ];
415
-
416
- // src/planning/milestone-planner.ts
417
- class LifecycleMilestonePlanner {
418
- milestones;
419
- constructor(customCatalog) {
420
- this.milestones = customCatalog ?? milestones_catalog_default;
421
- }
422
- getUpcoming(stage, completedIds = [], limit = 5) {
423
- const completedSet = new Set(completedIds);
424
- return this.milestones.filter((milestone) => milestone.stage === stage && !completedSet.has(milestone.id)).sort((a, b) => a.priority - b.priority).slice(0, limit);
425
- }
426
- }
426
+ var isStageValue = (value) => typeof value === "number" && (value in LIFECYCLE_STAGE_META2);
427
427
  export {
428
428
  StageSignalCollector,
429
429
  StageScorer,
@@ -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,8 +1,8 @@
1
1
  import type { LifecycleAssessment, LifecycleAssessmentInput, LifecycleMilestone } from '@contractspec/lib.lifecycle';
2
2
  import { LifecycleStage } from '@contractspec/lib.lifecycle';
3
3
  import { StageSignalCollector } from '../collectors/signal-collector';
4
- import { StageScorer } from '../scoring/stage-scorer';
5
4
  import { LifecycleMilestonePlanner } from '../planning/milestone-planner';
5
+ import { StageScorer } from '../scoring/stage-scorer';
6
6
  export interface LifecycleOrchestratorOptions {
7
7
  collector: StageSignalCollector;
8
8
  scorer: StageScorer;