@lssm/lib.evolution 0.0.0-canary-20251217062139 → 0.0.0-canary-20251217072406

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.
Files changed (29) hide show
  1. package/dist/ai-agent/dist/approval/index.js +1 -1
  2. package/dist/ai-agent/dist/approval/workflow.js +1 -1
  3. package/dist/analyzer/spec-analyzer.js +305 -1
  4. package/dist/approval/integration.js +125 -1
  5. package/dist/generator/ai-spec-generator.js +175 -9
  6. package/dist/generator/spec-generator.js +120 -1
  7. package/dist/index.js +6 -1
  8. package/dist/lifecycle/dist/index.js +4 -1
  9. package/dist/lifecycle/dist/types/milestones.js +1 -1
  10. package/dist/lifecycle/dist/types/signals.js +1 -1
  11. package/dist/lifecycle/dist/types/stages.js +151 -1
  12. package/dist/lifecycle/dist/utils/formatters.js +1 -1
  13. package/dist/observability/dist/index.js +8 -1
  14. package/dist/observability/dist/intent/aggregator.js +4 -0
  15. package/dist/observability/dist/intent/detector.js +1 -1
  16. package/dist/observability/dist/lifecycle/dist/index.js +4 -1
  17. package/dist/observability/dist/lifecycle/dist/types/milestones.js +1 -1
  18. package/dist/observability/dist/lifecycle/dist/types/signals.js +1 -1
  19. package/dist/observability/dist/lifecycle/dist/types/stages.js +142 -1
  20. package/dist/observability/dist/lifecycle/dist/utils/formatters.js +1 -1
  21. package/dist/observability/dist/logging/index.js +39 -1
  22. package/dist/observability/dist/metrics/index.js +22 -1
  23. package/dist/observability/dist/pipeline/evolution-pipeline.js +3 -1
  24. package/dist/observability/dist/pipeline/lifecycle-pipeline.js +4 -1
  25. package/dist/observability/dist/tracing/index.js +1 -1
  26. package/dist/observability/dist/tracing/middleware.js +2 -1
  27. package/package.json +8 -8
  28. package/dist/lifecycle/dist/types/axes.js +0 -1
  29. package/dist/observability/dist/lifecycle/dist/types/axes.js +0 -1
@@ -1 +1 @@
1
- import"./workflow.js";
1
+ import "./workflow.js";
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";
1
+ import { randomUUID } from "node:crypto";
@@ -1 +1,305 @@
1
- import"../observability/dist/index.js";import{e}from"../lifecycle/dist/types/stages.js";import"../lifecycle/dist/index.js";import{randomUUID as t}from"node:crypto";const n={minSampleSize:50,errorRateThreshold:.05,latencyP99ThresholdMs:750};var r=class{logger;minSampleSize;errorRateThreshold;latencyP99ThresholdMs;throughputDropThreshold;constructor(e={}){this.logger=e.logger,this.minSampleSize=e.minSampleSize??n.minSampleSize,this.errorRateThreshold=e.errorRateThreshold??n.errorRateThreshold,this.latencyP99ThresholdMs=e.latencyP99ThresholdMs??n.latencyP99ThresholdMs,this.throughputDropThreshold=e.throughputDropThreshold??.2}analyzeSpecUsage(e){if(!e.length)return this.logger?.debug(`SpecAnalyzer.analyzeSpecUsage.skip`,{reason:`no-samples`}),[];let t=new Map;for(let n of e){let e=this.operationKey(n),r=t.get(e)??[];r.push(n),t.set(e,r)}return[...t.values()].filter(e=>{let t=e.length>=this.minSampleSize;return t||this.logger?.debug(`SpecAnalyzer.analyzeSpecUsage.skipOperation`,{operation:this.operationKey(e[0]),sampleSize:e.length,minSampleSize:this.minSampleSize}),t}).map(e=>this.buildUsageStats(e))}detectAnomalies(e,t){let n=[];if(!e.length)return this.logger?.debug(`SpecAnalyzer.detectAnomalies.skip`,{reason:`no-stats`}),n;let r=new Map((t??[]).map(e=>[this.operationKey(e.operation),e]));for(let t of e){let e=[];if(t.errorRate>=this.errorRateThreshold){e.push({type:`telemetry`,description:`Error rate ${t.errorRate.toFixed(2)} exceeded threshold ${this.errorRateThreshold}`,data:{errorRate:t.errorRate}}),n.push({operation:t.operation,severity:this.toSeverity(t.errorRate/this.errorRateThreshold),metric:`error-rate`,description:`Error rate spike`,detectedAt:new Date,threshold:this.errorRateThreshold,observedValue:t.errorRate,evidence:e});continue}if(t.p99LatencyMs>=this.latencyP99ThresholdMs){e.push({type:`telemetry`,description:`P99 latency ${t.p99LatencyMs}ms exceeded threshold ${this.latencyP99ThresholdMs}ms`,data:{p99LatencyMs:t.p99LatencyMs}}),n.push({operation:t.operation,severity:this.toSeverity(t.p99LatencyMs/this.latencyP99ThresholdMs),metric:`latency`,description:`Latency regression detected`,detectedAt:new Date,threshold:this.latencyP99ThresholdMs,observedValue:t.p99LatencyMs,evidence:e});continue}let i=r.get(this.operationKey(t.operation));if(i){let r=(i.totalCalls-t.totalCalls)/i.totalCalls;r>=this.throughputDropThreshold&&(e.push({type:`telemetry`,description:`Throughput dropped by ${(r*100).toFixed(1)}% compared to baseline`,data:{baselineCalls:i.totalCalls,currentCalls:t.totalCalls}}),n.push({operation:t.operation,severity:this.toSeverity(r/this.throughputDropThreshold),metric:`throughput`,description:`Usage drop detected`,detectedAt:new Date,threshold:this.throughputDropThreshold,observedValue:r,evidence:e}))}}return n}toIntentPatterns(e,n){let r=new Map(n.map(e=>[this.operationKey(e.operation),e]));return e.map(e=>{let n=r.get(this.operationKey(e.operation)),i={score:Math.min(1,(e.observedValue??0)/(e.threshold??1)),sampleSize:n?.totalCalls??0,pValue:void 0};return{id:t(),type:this.mapMetricToIntent(e.metric),description:e.description,operation:e.operation,confidence:i,metadata:{observedValue:e.observedValue,threshold:e.threshold},evidence:e.evidence}})}suggestOptimizations(e,t,n){let r=new Map(this.groupByOperation(t)),i=[];for(let t of e){let e=this.operationKey(t.operation),a=r.get(e)??[];for(let e of a)if(e.metric===`latency`)i.push(this.applyLifecycleContext({operation:t.operation,category:`performance`,summary:`Latency regression detected`,justification:`P99 latency at ${t.p99LatencyMs}ms`,recommendedActions:[`Add batching or caching layer`,`Replay golden tests to capture slow inputs`]},n?.stage));else if(e.metric===`error-rate`){let e=Object.entries(t.topErrors).sort((e,t)=>t[1]-e[1])[0]?.[0];i.push(this.applyLifecycleContext({operation:t.operation,category:`error-handling`,summary:`Error spike detected`,justification:e?`Dominant error code ${e}`:`Increase in failures`,recommendedActions:[`Generate regression spec from failing payloads`,`Add policy guardrails before rollout`]},n?.stage))}else e.metric===`throughput`&&i.push(this.applyLifecycleContext({operation:t.operation,category:`performance`,summary:`Throughput drop detected`,justification:`Significant traffic reduction relative to baseline`,recommendedActions:[`Validate routing + feature flag bucketing`,`Backfill spec variant to rehydrate demand`]},n?.stage))}return i}operationKey(e){let t=`operation`in e?e.operation:e;return`${t.name}.v${t.version}${t.tenantId?`@${t.tenantId}`:``}`}buildUsageStats(e){let t=e.map(e=>e.durationMs).sort((e,t)=>e-t),n=e.filter(e=>!e.success),r=e.length,a=(r-n.length)/r,o=n.length/r,s=t.reduce((e,t)=>e+t,0)/r,c=n.reduce((e,t)=>(t.errorCode&&(e[t.errorCode]=(e[t.errorCode]??0)+1),e),{}),l=e.map(e=>e.timestamp.getTime()),u=new Date(Math.min(...l)),d=new Date(Math.max(...l));return{operation:e[0].operation,totalCalls:r,successRate:a,errorRate:o,averageLatencyMs:s,p95LatencyMs:i(t,.95),p99LatencyMs:i(t,.99),maxLatencyMs:Math.max(...t),lastSeenAt:d,windowStart:u,windowEnd:d,topErrors:c}}toSeverity(e){return e>=2?`high`:e>=1.3?`medium`:`low`}mapMetricToIntent(e){switch(e){case`error-rate`:return`error-spike`;case`latency`:return`latency-regression`;case`throughput`:return`throughput-drop`;default:return`schema-mismatch`}}groupByOperation(e){let t=new Map;for(let n of e){let e=this.operationKey(n.operation),r=t.get(e)??[];r.push(n),t.set(e,r)}return t}applyLifecycleContext(e,t){if(t===void 0)return e;let n=o[a(t)]?.[e.category];return n?{...e,lifecycleStage:t,lifecycleNotes:n.message,recommendedActions:s([...e.recommendedActions,...n.supplementalActions])}:{...e,lifecycleStage:t}}};function i(e,t){return e.length?e.length===1?e[0]:e[Math.min(e.length-1,Math.floor(t*e.length))]:0}const a=t=>t<=2?`early`:t===e.ProductMarketFit?`pmf`:t===e.GrowthScaleUp||t===e.ExpansionPlatform?`scale`:`mature`,o={early:{performance:{message:`Favor guardrails that protect learning velocity before heavy rewrites.`,supplementalActions:[`Wrap risky changes behind progressive delivery flags`]},"error-handling":{message:`Make failures loud and recoverable so you can learn faster.`,supplementalActions:[`Add auto-rollbacks or manual kill switches`]}},pmf:{performance:{message:`Stabilize the core use case to avoid regressions while demand grows.`,supplementalActions:[`Instrument regression tests on critical specs`]}},scale:{performance:{message:`Prioritize resilience and multi-tenant safety as volumes expand.`,supplementalActions:[`Introduce workload partitioning or isolation per tenant`]},"error-handling":{message:`Contain blast radius with policy fallbacks and circuit breakers.`,supplementalActions:[`Add circuit breakers to high-risk operations`]}},mature:{performance:{message:`Optimize for margins and predictable SLAs.`,supplementalActions:[`Capture unit-cost impacts alongside latency fixes`]},"error-handling":{message:`Prevent regressions with automated regression specs before deploy.`,supplementalActions:[`Run auto-evolution simulations on renewal scenarios`]}}},s=e=>{let t=new Set,n=[];for(let r of e)t.has(r)||(t.add(r),n.push(r));return n};export{r as SpecAnalyzer};
1
+ import "../observability/dist/index.js";
2
+ import { LifecycleStage } from "../lifecycle/dist/types/stages.js";
3
+ import "../lifecycle/dist/index.js";
4
+ import { randomUUID } from "node:crypto";
5
+
6
+ //#region src/analyzer/spec-analyzer.ts
7
+ const DEFAULT_OPTIONS = {
8
+ minSampleSize: 50,
9
+ errorRateThreshold: .05,
10
+ latencyP99ThresholdMs: 750
11
+ };
12
+ var SpecAnalyzer = class {
13
+ logger;
14
+ minSampleSize;
15
+ errorRateThreshold;
16
+ latencyP99ThresholdMs;
17
+ throughputDropThreshold;
18
+ constructor(options = {}) {
19
+ this.logger = options.logger;
20
+ this.minSampleSize = options.minSampleSize ?? DEFAULT_OPTIONS.minSampleSize;
21
+ this.errorRateThreshold = options.errorRateThreshold ?? DEFAULT_OPTIONS.errorRateThreshold;
22
+ this.latencyP99ThresholdMs = options.latencyP99ThresholdMs ?? DEFAULT_OPTIONS.latencyP99ThresholdMs;
23
+ this.throughputDropThreshold = options.throughputDropThreshold ?? .2;
24
+ }
25
+ analyzeSpecUsage(samples) {
26
+ if (!samples.length) {
27
+ this.logger?.debug("SpecAnalyzer.analyzeSpecUsage.skip", { reason: "no-samples" });
28
+ return [];
29
+ }
30
+ const groups = /* @__PURE__ */ new Map();
31
+ for (const sample of samples) {
32
+ const key = this.operationKey(sample);
33
+ const arr = groups.get(key) ?? [];
34
+ arr.push(sample);
35
+ groups.set(key, arr);
36
+ }
37
+ return [...groups.values()].filter((samplesForOp) => {
38
+ const valid = samplesForOp.length >= this.minSampleSize;
39
+ if (!valid) this.logger?.debug("SpecAnalyzer.analyzeSpecUsage.skipOperation", {
40
+ operation: this.operationKey(samplesForOp[0]),
41
+ sampleSize: samplesForOp.length,
42
+ minSampleSize: this.minSampleSize
43
+ });
44
+ return valid;
45
+ }).map((operationSamples) => this.buildUsageStats(operationSamples));
46
+ }
47
+ detectAnomalies(stats, baseline) {
48
+ const anomalies = [];
49
+ if (!stats.length) {
50
+ this.logger?.debug("SpecAnalyzer.detectAnomalies.skip", { reason: "no-stats" });
51
+ return anomalies;
52
+ }
53
+ const baselineByOp = new Map((baseline ?? []).map((item) => [this.operationKey(item.operation), item]));
54
+ for (const stat of stats) {
55
+ const evidence = [];
56
+ if (stat.errorRate >= this.errorRateThreshold) {
57
+ evidence.push({
58
+ type: "telemetry",
59
+ description: `Error rate ${stat.errorRate.toFixed(2)} exceeded threshold ${this.errorRateThreshold}`,
60
+ data: { errorRate: stat.errorRate }
61
+ });
62
+ anomalies.push({
63
+ operation: stat.operation,
64
+ severity: this.toSeverity(stat.errorRate / this.errorRateThreshold),
65
+ metric: "error-rate",
66
+ description: "Error rate spike",
67
+ detectedAt: /* @__PURE__ */ new Date(),
68
+ threshold: this.errorRateThreshold,
69
+ observedValue: stat.errorRate,
70
+ evidence
71
+ });
72
+ continue;
73
+ }
74
+ if (stat.p99LatencyMs >= this.latencyP99ThresholdMs) {
75
+ evidence.push({
76
+ type: "telemetry",
77
+ description: `P99 latency ${stat.p99LatencyMs}ms exceeded threshold ${this.latencyP99ThresholdMs}ms`,
78
+ data: { p99LatencyMs: stat.p99LatencyMs }
79
+ });
80
+ anomalies.push({
81
+ operation: stat.operation,
82
+ severity: this.toSeverity(stat.p99LatencyMs / this.latencyP99ThresholdMs),
83
+ metric: "latency",
84
+ description: "Latency regression detected",
85
+ detectedAt: /* @__PURE__ */ new Date(),
86
+ threshold: this.latencyP99ThresholdMs,
87
+ observedValue: stat.p99LatencyMs,
88
+ evidence
89
+ });
90
+ continue;
91
+ }
92
+ const baselineStat = baselineByOp.get(this.operationKey(stat.operation));
93
+ if (baselineStat) {
94
+ const drop = (baselineStat.totalCalls - stat.totalCalls) / baselineStat.totalCalls;
95
+ if (drop >= this.throughputDropThreshold) {
96
+ evidence.push({
97
+ type: "telemetry",
98
+ description: `Throughput dropped by ${(drop * 100).toFixed(1)}% compared to baseline`,
99
+ data: {
100
+ baselineCalls: baselineStat.totalCalls,
101
+ currentCalls: stat.totalCalls
102
+ }
103
+ });
104
+ anomalies.push({
105
+ operation: stat.operation,
106
+ severity: this.toSeverity(drop / this.throughputDropThreshold),
107
+ metric: "throughput",
108
+ description: "Usage drop detected",
109
+ detectedAt: /* @__PURE__ */ new Date(),
110
+ threshold: this.throughputDropThreshold,
111
+ observedValue: drop,
112
+ evidence
113
+ });
114
+ }
115
+ }
116
+ }
117
+ return anomalies;
118
+ }
119
+ toIntentPatterns(anomalies, stats) {
120
+ const statsByOp = new Map(stats.map((item) => [this.operationKey(item.operation), item]));
121
+ return anomalies.map((anomaly) => {
122
+ const stat = statsByOp.get(this.operationKey(anomaly.operation));
123
+ const confidence = {
124
+ score: Math.min(1, (anomaly.observedValue ?? 0) / (anomaly.threshold ?? 1)),
125
+ sampleSize: stat?.totalCalls ?? 0,
126
+ pValue: void 0
127
+ };
128
+ return {
129
+ id: randomUUID(),
130
+ type: this.mapMetricToIntent(anomaly.metric),
131
+ description: anomaly.description,
132
+ operation: anomaly.operation,
133
+ confidence,
134
+ metadata: {
135
+ observedValue: anomaly.observedValue,
136
+ threshold: anomaly.threshold
137
+ },
138
+ evidence: anomaly.evidence
139
+ };
140
+ });
141
+ }
142
+ suggestOptimizations(stats, anomalies, lifecycleContext) {
143
+ const anomaliesByOp = new Map(this.groupByOperation(anomalies));
144
+ const hints = [];
145
+ for (const stat of stats) {
146
+ const opKey = this.operationKey(stat.operation);
147
+ const opAnomalies = anomaliesByOp.get(opKey) ?? [];
148
+ for (const anomaly of opAnomalies) if (anomaly.metric === "latency") hints.push(this.applyLifecycleContext({
149
+ operation: stat.operation,
150
+ category: "performance",
151
+ summary: "Latency regression detected",
152
+ justification: `P99 latency at ${stat.p99LatencyMs}ms`,
153
+ recommendedActions: ["Add batching or caching layer", "Replay golden tests to capture slow inputs"]
154
+ }, lifecycleContext?.stage));
155
+ else if (anomaly.metric === "error-rate") {
156
+ const topError = Object.entries(stat.topErrors).sort((a, b) => b[1] - a[1])[0]?.[0];
157
+ hints.push(this.applyLifecycleContext({
158
+ operation: stat.operation,
159
+ category: "error-handling",
160
+ summary: "Error spike detected",
161
+ justification: topError ? `Dominant error code ${topError}` : "Increase in failures",
162
+ recommendedActions: ["Generate regression spec from failing payloads", "Add policy guardrails before rollout"]
163
+ }, lifecycleContext?.stage));
164
+ } else if (anomaly.metric === "throughput") hints.push(this.applyLifecycleContext({
165
+ operation: stat.operation,
166
+ category: "performance",
167
+ summary: "Throughput drop detected",
168
+ justification: "Significant traffic reduction relative to baseline",
169
+ recommendedActions: ["Validate routing + feature flag bucketing", "Backfill spec variant to rehydrate demand"]
170
+ }, lifecycleContext?.stage));
171
+ }
172
+ return hints;
173
+ }
174
+ operationKey(op) {
175
+ const coordinate = "operation" in op ? op.operation : op;
176
+ return `${coordinate.name}.v${coordinate.version}${coordinate.tenantId ? `@${coordinate.tenantId}` : ""}`;
177
+ }
178
+ buildUsageStats(samples) {
179
+ const durations = samples.map((s) => s.durationMs).sort((a, b) => a - b);
180
+ const errors = samples.filter((s) => !s.success);
181
+ const totalCalls = samples.length;
182
+ const successRate = (totalCalls - errors.length) / totalCalls;
183
+ const errorRate = errors.length / totalCalls;
184
+ const averageLatencyMs = durations.reduce((sum, value) => sum + value, 0) / totalCalls;
185
+ const topErrors = errors.reduce((acc, sample) => {
186
+ if (!sample.errorCode) return acc;
187
+ acc[sample.errorCode] = (acc[sample.errorCode] ?? 0) + 1;
188
+ return acc;
189
+ }, {});
190
+ const timestamps = samples.map((s) => s.timestamp.getTime());
191
+ const windowStart = new Date(Math.min(...timestamps));
192
+ const windowEnd = new Date(Math.max(...timestamps));
193
+ return {
194
+ operation: samples[0].operation,
195
+ totalCalls,
196
+ successRate,
197
+ errorRate,
198
+ averageLatencyMs,
199
+ p95LatencyMs: percentile(durations, .95),
200
+ p99LatencyMs: percentile(durations, .99),
201
+ maxLatencyMs: Math.max(...durations),
202
+ lastSeenAt: windowEnd,
203
+ windowStart,
204
+ windowEnd,
205
+ topErrors
206
+ };
207
+ }
208
+ toSeverity(ratio) {
209
+ if (ratio >= 2) return "high";
210
+ if (ratio >= 1.3) return "medium";
211
+ return "low";
212
+ }
213
+ mapMetricToIntent(metric) {
214
+ switch (metric) {
215
+ case "error-rate": return "error-spike";
216
+ case "latency": return "latency-regression";
217
+ case "throughput": return "throughput-drop";
218
+ default: return "schema-mismatch";
219
+ }
220
+ }
221
+ groupByOperation(items) {
222
+ const map = /* @__PURE__ */ new Map();
223
+ for (const item of items) {
224
+ const key = this.operationKey(item.operation);
225
+ const arr = map.get(key) ?? [];
226
+ arr.push(item);
227
+ map.set(key, arr);
228
+ }
229
+ return map;
230
+ }
231
+ applyLifecycleContext(hint, stage) {
232
+ if (stage === void 0) return hint;
233
+ const advice = LIFECYCLE_HINTS[mapStageBand(stage)]?.[hint.category];
234
+ if (!advice) return {
235
+ ...hint,
236
+ lifecycleStage: stage
237
+ };
238
+ return {
239
+ ...hint,
240
+ lifecycleStage: stage,
241
+ lifecycleNotes: advice.message,
242
+ recommendedActions: dedupeActions([...hint.recommendedActions, ...advice.supplementalActions])
243
+ };
244
+ }
245
+ };
246
+ function percentile(values, p) {
247
+ if (!values.length) return 0;
248
+ if (values.length === 1) return values[0];
249
+ return values[Math.min(values.length - 1, Math.floor(p * values.length))];
250
+ }
251
+ const mapStageBand = (stage) => {
252
+ if (stage <= 2) return "early";
253
+ if (stage === LifecycleStage.ProductMarketFit) return "pmf";
254
+ if (stage === LifecycleStage.GrowthScaleUp || stage === LifecycleStage.ExpansionPlatform) return "scale";
255
+ return "mature";
256
+ };
257
+ const LIFECYCLE_HINTS = {
258
+ early: {
259
+ performance: {
260
+ message: "Favor guardrails that protect learning velocity before heavy rewrites.",
261
+ supplementalActions: ["Wrap risky changes behind progressive delivery flags"]
262
+ },
263
+ "error-handling": {
264
+ message: "Make failures loud and recoverable so you can learn faster.",
265
+ supplementalActions: ["Add auto-rollbacks or manual kill switches"]
266
+ }
267
+ },
268
+ pmf: { performance: {
269
+ message: "Stabilize the core use case to avoid regressions while demand grows.",
270
+ supplementalActions: ["Instrument regression tests on critical specs"]
271
+ } },
272
+ scale: {
273
+ performance: {
274
+ message: "Prioritize resilience and multi-tenant safety as volumes expand.",
275
+ supplementalActions: ["Introduce workload partitioning or isolation per tenant"]
276
+ },
277
+ "error-handling": {
278
+ message: "Contain blast radius with policy fallbacks and circuit breakers.",
279
+ supplementalActions: ["Add circuit breakers to high-risk operations"]
280
+ }
281
+ },
282
+ mature: {
283
+ performance: {
284
+ message: "Optimize for margins and predictable SLAs.",
285
+ supplementalActions: ["Capture unit-cost impacts alongside latency fixes"]
286
+ },
287
+ "error-handling": {
288
+ message: "Prevent regressions with automated regression specs before deploy.",
289
+ supplementalActions: ["Run auto-evolution simulations on renewal scenarios"]
290
+ }
291
+ }
292
+ };
293
+ const dedupeActions = (actions) => {
294
+ const seen = /* @__PURE__ */ new Set();
295
+ const ordered = [];
296
+ for (const action of actions) {
297
+ if (seen.has(action)) continue;
298
+ seen.add(action);
299
+ ordered.push(action);
300
+ }
301
+ return ordered;
302
+ };
303
+
304
+ //#endregion
305
+ export { SpecAnalyzer };
@@ -1 +1,125 @@
1
- import"../ai-agent/dist/approval/index.js";import{mkdir as e,writeFile as t}from"node:fs/promises";import{join as n}from"node:path";var r=class{constructor(e){this.options=e}async submit(e,t,n){return await this.options.repository.create(e),t&&this.options.approval&&await this.options.approval.requestApproval({sessionId:t.sessionId,agentId:t.agentId,tenantId:t.tenantId,toolName:`evolution.apply_suggestion`,toolCallId:e.id,toolArgs:{suggestionId:e.id},reason:n??e.proposal.summary,payload:{suggestionId:e.id}}),e}async approve(e,t,n){let r=await this.ensureSuggestion(e);await this.options.repository.updateStatus(e,`approved`,{reviewer:t,notes:n,decidedAt:new Date}),this.options.writer&&await this.options.writer.write({...r,status:`approved`,approvals:{reviewer:t,notes:n,decidedAt:new Date,status:`approved`}})}async reject(e,t,n){await this.options.repository.updateStatus(e,`rejected`,{reviewer:t,notes:n,decidedAt:new Date})}list(e){return this.options.repository.list(e)}async ensureSuggestion(e){let t=await this.options.repository.getById(e);if(!t)throw Error(`Spec suggestion ${e} not found`);return t}},i=class{outputDir;filenameTemplate;constructor(e={}){this.outputDir=e.outputDir??n(process.cwd(),`packages/libs/contracts/src/generated`),this.filenameTemplate=e.filenameTemplate??(e=>`${e.target?.name??e.intent.id}.v${e.target?.version??`next`}.suggestion.json`)}async write(r){await e(this.outputDir,{recursive:!0});let i=this.filenameTemplate(r),a=n(this.outputDir,i),s=o(r);return await t(a,JSON.stringify(s,null,2)),a}},a=class{items=new Map;async create(e){this.items.set(e.id,e)}async getById(e){return this.items.get(e)}async updateStatus(e,t,n){let r=await this.getById(e);r&&this.items.set(e,{...r,status:t,approvals:{reviewer:n?.reviewer,notes:n?.notes,decidedAt:n?.decidedAt,status:t}})}async list(e){let t=[...this.items.values()];return e?t.filter(t=>!(e.status&&t.status!==e.status||e.operationName&&t.target?.name!==e.operationName)):t}};function o(e){let{proposal:t,...n}=e,{spec:r,...i}=t;return{...n,proposal:{...i,specMeta:r?.meta},createdAt:e.createdAt.toISOString(),intent:{...e.intent,confidence:{...e.intent.confidence},evidence:e.intent.evidence}}}export{i as FileSystemSuggestionWriter,a as InMemorySpecSuggestionRepository,r as SpecSuggestionOrchestrator};
1
+ import "../ai-agent/dist/approval/index.js";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+
5
+ //#region src/approval/integration.ts
6
+ var SpecSuggestionOrchestrator = class {
7
+ constructor(options) {
8
+ this.options = options;
9
+ }
10
+ async submit(suggestion, session, approvalReason) {
11
+ await this.options.repository.create(suggestion);
12
+ if (session && this.options.approval) await this.options.approval.requestApproval({
13
+ sessionId: session.sessionId,
14
+ agentId: session.agentId,
15
+ tenantId: session.tenantId,
16
+ toolName: "evolution.apply_suggestion",
17
+ toolCallId: suggestion.id,
18
+ toolArgs: { suggestionId: suggestion.id },
19
+ reason: approvalReason ?? suggestion.proposal.summary,
20
+ payload: { suggestionId: suggestion.id }
21
+ });
22
+ return suggestion;
23
+ }
24
+ async approve(id, reviewer, notes) {
25
+ const suggestion = await this.ensureSuggestion(id);
26
+ await this.options.repository.updateStatus(id, "approved", {
27
+ reviewer,
28
+ notes,
29
+ decidedAt: /* @__PURE__ */ new Date()
30
+ });
31
+ if (this.options.writer) await this.options.writer.write({
32
+ ...suggestion,
33
+ status: "approved",
34
+ approvals: {
35
+ reviewer,
36
+ notes,
37
+ decidedAt: /* @__PURE__ */ new Date(),
38
+ status: "approved"
39
+ }
40
+ });
41
+ }
42
+ async reject(id, reviewer, notes) {
43
+ await this.options.repository.updateStatus(id, "rejected", {
44
+ reviewer,
45
+ notes,
46
+ decidedAt: /* @__PURE__ */ new Date()
47
+ });
48
+ }
49
+ list(filters) {
50
+ return this.options.repository.list(filters);
51
+ }
52
+ async ensureSuggestion(id) {
53
+ const suggestion = await this.options.repository.getById(id);
54
+ if (!suggestion) throw new Error(`Spec suggestion ${id} not found`);
55
+ return suggestion;
56
+ }
57
+ };
58
+ var FileSystemSuggestionWriter = class {
59
+ outputDir;
60
+ filenameTemplate;
61
+ constructor(options = {}) {
62
+ this.outputDir = options.outputDir ?? join(process.cwd(), "packages/libs/contracts/src/generated");
63
+ this.filenameTemplate = options.filenameTemplate ?? ((suggestion) => `${suggestion.target?.name ?? suggestion.intent.id}.v${suggestion.target?.version ?? "next"}.suggestion.json`);
64
+ }
65
+ async write(suggestion) {
66
+ await mkdir(this.outputDir, { recursive: true });
67
+ const filename = this.filenameTemplate(suggestion);
68
+ const filepath = join(this.outputDir, filename);
69
+ const payload = serializeSuggestion(suggestion);
70
+ await writeFile(filepath, JSON.stringify(payload, null, 2));
71
+ return filepath;
72
+ }
73
+ };
74
+ var InMemorySpecSuggestionRepository = class {
75
+ items = /* @__PURE__ */ new Map();
76
+ async create(suggestion) {
77
+ this.items.set(suggestion.id, suggestion);
78
+ }
79
+ async getById(id) {
80
+ return this.items.get(id);
81
+ }
82
+ async updateStatus(id, status, metadata) {
83
+ const suggestion = await this.getById(id);
84
+ if (!suggestion) return;
85
+ this.items.set(id, {
86
+ ...suggestion,
87
+ status,
88
+ approvals: {
89
+ reviewer: metadata?.reviewer,
90
+ notes: metadata?.notes,
91
+ decidedAt: metadata?.decidedAt,
92
+ status
93
+ }
94
+ });
95
+ }
96
+ async list(filters) {
97
+ const values = [...this.items.values()];
98
+ if (!filters) return values;
99
+ return values.filter((item) => {
100
+ if (filters.status && item.status !== filters.status) return false;
101
+ if (filters.operationName && item.target?.name !== filters.operationName) return false;
102
+ return true;
103
+ });
104
+ }
105
+ };
106
+ function serializeSuggestion(suggestion) {
107
+ const { proposal, ...rest } = suggestion;
108
+ const { spec, ...proposalRest } = proposal;
109
+ return {
110
+ ...rest,
111
+ proposal: {
112
+ ...proposalRest,
113
+ specMeta: spec?.meta
114
+ },
115
+ createdAt: suggestion.createdAt.toISOString(),
116
+ intent: {
117
+ ...suggestion.intent,
118
+ confidence: { ...suggestion.intent.confidence },
119
+ evidence: suggestion.intent.evidence
120
+ }
121
+ };
122
+ }
123
+
124
+ //#endregion
125
+ export { FileSystemSuggestionWriter, InMemorySpecSuggestionRepository, SpecSuggestionOrchestrator };
@@ -1,19 +1,185 @@
1
- import{randomUUID as e}from"node:crypto";import{Output as t,generateText as n}from"ai";import*as r from"zod";const i=r.object({summary:r.string().describe(`Brief summary of the proposed change`),rationale:r.string().describe(`Detailed explanation of why this change is needed`),changeType:r.enum([`new-spec`,`revision`,`policy-update`,`schema-update`]).describe(`Type of change being proposed`),recommendedActions:r.array(r.string()).describe(`List of specific actions to implement the change`),estimatedImpact:r.enum([`low`,`medium`,`high`]).describe(`Estimated impact of implementing this change`),riskLevel:r.enum([`low`,`medium`,`high`]).describe(`Risk level associated with this change`),diff:r.string().optional().describe(`Optional diff or code snippet showing the change`)});var a=class{model;config;systemPrompt;constructor(e){this.model=e.model,this.config=e.evolutionConfig??{},this.systemPrompt=e.systemPrompt??`You are a ContractSpec evolution expert. Your role is to analyze telemetry data, anomalies, and usage patterns to suggest improvements to API contracts and specifications.
1
+ import { randomUUID } from "node:crypto";
2
+ import { Output, generateText } from "ai";
3
+ import * as z from "zod";
4
+
5
+ //#region src/generator/ai-spec-generator.ts
6
+ /**
7
+ * Zod schema for AI-generated spec suggestions.
8
+ */
9
+ const SpecSuggestionProposalSchema = z.object({
10
+ summary: z.string().describe("Brief summary of the proposed change"),
11
+ rationale: z.string().describe("Detailed explanation of why this change is needed"),
12
+ changeType: z.enum([
13
+ "new-spec",
14
+ "revision",
15
+ "policy-update",
16
+ "schema-update"
17
+ ]).describe("Type of change being proposed"),
18
+ recommendedActions: z.array(z.string()).describe("List of specific actions to implement the change"),
19
+ estimatedImpact: z.enum([
20
+ "low",
21
+ "medium",
22
+ "high"
23
+ ]).describe("Estimated impact of implementing this change"),
24
+ riskLevel: z.enum([
25
+ "low",
26
+ "medium",
27
+ "high"
28
+ ]).describe("Risk level associated with this change"),
29
+ diff: z.string().optional().describe("Optional diff or code snippet showing the change")
30
+ });
31
+ /**
32
+ * AI-powered spec generator using AI SDK v6.
33
+ *
34
+ * Uses structured output (Output.object) to generate
35
+ * well-formed spec suggestions from intent patterns.
36
+ */
37
+ var AISpecGenerator = class {
38
+ model;
39
+ config;
40
+ systemPrompt;
41
+ constructor(options) {
42
+ this.model = options.model;
43
+ this.config = options.evolutionConfig ?? {};
44
+ this.systemPrompt = options.systemPrompt ?? `You are a ContractSpec evolution expert. Your role is to analyze telemetry data, anomalies, and usage patterns to suggest improvements to API contracts and specifications.
2
45
 
3
46
  When generating suggestions:
4
47
  1. Be specific and actionable
5
48
  2. Consider backwards compatibility
6
49
  3. Prioritize stability and reliability
7
50
  4. Explain the rationale clearly
8
- 5. Estimate impact and risk accurately`}async generateFromIntent(e,r={}){let a=this.buildPrompt(e,r),{output:o}=await n({model:this.model,system:this.systemPrompt,prompt:a,output:t.object({schema:i})});return this.buildSuggestion(e,o)}async generateBatch(e,t={}){let n=t.maxConcurrent??3,r=[];for(let t=0;t<e.length;t+=n){let i=e.slice(t,t+n),a=await Promise.all(i.map(e=>this.generateFromIntent(e)));r.push(...a)}return r}async enhanceSuggestion(e){let r=`Review and enhance this spec suggestion:
51
+ 5. Estimate impact and risk accurately`;
52
+ }
53
+ /**
54
+ * Generate a spec suggestion from an intent pattern using AI.
55
+ */
56
+ async generateFromIntent(intent, options = {}) {
57
+ const prompt = this.buildPrompt(intent, options);
58
+ const { output } = await generateText({
59
+ model: this.model,
60
+ system: this.systemPrompt,
61
+ prompt,
62
+ output: Output.object({ schema: SpecSuggestionProposalSchema })
63
+ });
64
+ return this.buildSuggestion(intent, output);
65
+ }
66
+ /**
67
+ * Generate multiple suggestions for a batch of intents.
68
+ */
69
+ async generateBatch(intents, options = {}) {
70
+ const maxConcurrent = options.maxConcurrent ?? 3;
71
+ const results = [];
72
+ for (let i = 0; i < intents.length; i += maxConcurrent) {
73
+ const batch = intents.slice(i, i + maxConcurrent);
74
+ const batchResults = await Promise.all(batch.map((intent) => this.generateFromIntent(intent)));
75
+ results.push(...batchResults);
76
+ }
77
+ return results;
78
+ }
79
+ /**
80
+ * Validate and enhance an existing suggestion using AI.
81
+ */
82
+ async enhanceSuggestion(suggestion) {
83
+ const prompt = `Review and enhance this spec suggestion:
9
84
 
10
- Intent: ${e.intent.type} - ${e.intent.description}
11
- Current Summary: ${e.proposal.summary}
12
- Current Rationale: ${e.proposal.rationale}
85
+ Intent: ${suggestion.intent.type} - ${suggestion.intent.description}
86
+ Current Summary: ${suggestion.proposal.summary}
87
+ Current Rationale: ${suggestion.proposal.rationale}
13
88
 
14
89
  Evidence:
15
- ${e.evidence.map(e=>`- ${e.type}: ${e.description}`).join(`
16
- `)}
90
+ ${suggestion.evidence.map((e) => `- ${e.type}: ${e.description}`).join("\n")}
91
+
92
+ Please provide an improved version with more specific recommendations.`;
93
+ const { output } = await generateText({
94
+ model: this.model,
95
+ system: this.systemPrompt,
96
+ prompt,
97
+ output: Output.object({ schema: SpecSuggestionProposalSchema })
98
+ });
99
+ return {
100
+ ...suggestion,
101
+ proposal: {
102
+ ...suggestion.proposal,
103
+ summary: output.summary,
104
+ rationale: output.rationale,
105
+ changeType: output.changeType,
106
+ diff: output.diff,
107
+ metadata: {
108
+ ...suggestion.proposal.metadata,
109
+ aiEnhanced: true,
110
+ recommendedActions: output.recommendedActions,
111
+ estimatedImpact: output.estimatedImpact,
112
+ riskLevel: output.riskLevel
113
+ }
114
+ }
115
+ };
116
+ }
117
+ buildPrompt(intent, options) {
118
+ const parts = [
119
+ `Analyze this intent pattern and generate a spec suggestion:`,
120
+ ``,
121
+ `Intent Type: ${intent.type}`,
122
+ `Description: ${intent.description}`,
123
+ `Confidence: ${(intent.confidence.score * 100).toFixed(0)}% (sample size: ${intent.confidence.sampleSize})`
124
+ ];
125
+ if (intent.operation) parts.push(`Operation: ${intent.operation.name} v${intent.operation.version}`);
126
+ if (intent.evidence.length > 0) {
127
+ parts.push(``, `Evidence:`);
128
+ for (const evidence of intent.evidence) parts.push(`- [${evidence.type}] ${evidence.description}`);
129
+ }
130
+ if (intent.metadata) parts.push(``, `Metadata: ${JSON.stringify(intent.metadata, null, 2)}`);
131
+ if (options.existingSpec) parts.push(``, `Existing Spec:`, "```json", JSON.stringify(options.existingSpec, null, 2), "```");
132
+ if (options.additionalContext) parts.push(``, `Additional Context:`, options.additionalContext);
133
+ return parts.join("\n");
134
+ }
135
+ buildSuggestion(intent, aiOutput) {
136
+ const now = /* @__PURE__ */ new Date();
137
+ const proposal = {
138
+ summary: aiOutput.summary,
139
+ rationale: aiOutput.rationale,
140
+ changeType: aiOutput.changeType,
141
+ diff: aiOutput.diff,
142
+ metadata: {
143
+ aiGenerated: true,
144
+ recommendedActions: aiOutput.recommendedActions,
145
+ estimatedImpact: aiOutput.estimatedImpact,
146
+ riskLevel: aiOutput.riskLevel
147
+ }
148
+ };
149
+ return {
150
+ id: randomUUID(),
151
+ intent,
152
+ target: intent.operation,
153
+ proposal,
154
+ confidence: intent.confidence.score,
155
+ priority: this.calculatePriority(intent, aiOutput),
156
+ createdAt: now,
157
+ createdBy: "ai-spec-generator",
158
+ status: this.determineInitialStatus(intent),
159
+ evidence: intent.evidence,
160
+ tags: ["ai-generated", intent.type]
161
+ };
162
+ }
163
+ calculatePriority(intent, aiOutput) {
164
+ const impactScore = aiOutput.estimatedImpact === "high" ? 1 : aiOutput.estimatedImpact === "medium" ? .5 : .25;
165
+ const intentScore = intent.confidence.score;
166
+ const urgency = intent.type === "error-spike" ? .3 : intent.type === "latency-regression" ? .2 : 0;
167
+ const combined = impactScore * .4 + intentScore * .4 + urgency;
168
+ if (combined >= .7) return "high";
169
+ if (combined >= .4) return "medium";
170
+ return "low";
171
+ }
172
+ determineInitialStatus(intent) {
173
+ if (this.config.autoApproveThreshold && intent.confidence.score >= this.config.autoApproveThreshold && !this.config.requireApproval) return "approved";
174
+ return "pending";
175
+ }
176
+ };
177
+ /**
178
+ * Create an AI-powered spec generator.
179
+ */
180
+ function createAISpecGenerator(config) {
181
+ return new AISpecGenerator(config);
182
+ }
17
183
 
18
- Please provide an improved version with more specific recommendations.`,{output:a}=await n({model:this.model,system:this.systemPrompt,prompt:r,output:t.object({schema:i})});return{...e,proposal:{...e.proposal,summary:a.summary,rationale:a.rationale,changeType:a.changeType,diff:a.diff,metadata:{...e.proposal.metadata,aiEnhanced:!0,recommendedActions:a.recommendedActions,estimatedImpact:a.estimatedImpact,riskLevel:a.riskLevel}}}}buildPrompt(e,t){let n=[`Analyze this intent pattern and generate a spec suggestion:`,``,`Intent Type: ${e.type}`,`Description: ${e.description}`,`Confidence: ${(e.confidence.score*100).toFixed(0)}% (sample size: ${e.confidence.sampleSize})`];if(e.operation&&n.push(`Operation: ${e.operation.name} v${e.operation.version}`),e.evidence.length>0){n.push(``,`Evidence:`);for(let t of e.evidence)n.push(`- [${t.type}] ${t.description}`)}return e.metadata&&n.push(``,`Metadata: ${JSON.stringify(e.metadata,null,2)}`),t.existingSpec&&n.push(``,`Existing Spec:`,"```json",JSON.stringify(t.existingSpec,null,2),"```"),t.additionalContext&&n.push(``,`Additional Context:`,t.additionalContext),n.join(`
19
- `)}buildSuggestion(t,n){let r=new Date,i={summary:n.summary,rationale:n.rationale,changeType:n.changeType,diff:n.diff,metadata:{aiGenerated:!0,recommendedActions:n.recommendedActions,estimatedImpact:n.estimatedImpact,riskLevel:n.riskLevel}};return{id:e(),intent:t,target:t.operation,proposal:i,confidence:t.confidence.score,priority:this.calculatePriority(t,n),createdAt:r,createdBy:`ai-spec-generator`,status:this.determineInitialStatus(t),evidence:t.evidence,tags:[`ai-generated`,t.type]}}calculatePriority(e,t){let n=t.estimatedImpact===`high`?1:t.estimatedImpact===`medium`?.5:.25,r=e.confidence.score,i=e.type===`error-spike`?.3:e.type===`latency-regression`?.2:0,a=n*.4+r*.4+i;return a>=.7?`high`:a>=.4?`medium`:`low`}determineInitialStatus(e){return this.config.autoApproveThreshold&&e.confidence.score>=this.config.autoApproveThreshold&&!this.config.requireApproval?`approved`:`pending`}};function o(e){return new a(e)}export{a as AISpecGenerator,o as createAISpecGenerator};
184
+ //#endregion
185
+ export { AISpecGenerator, createAISpecGenerator };
@@ -1 +1,120 @@
1
- import"../observability/dist/index.js";import{randomUUID as e}from"node:crypto";var t=class{config;logger;clock;getSpec;constructor(e={}){this.config=e.config??{},this.logger=e.logger,this.clock=e.clock??(()=>new Date),this.getSpec=e.getSpec}generateFromIntent(t,n={}){let r=this.clock(),i=n.summary??`${this.intentToVerb(t.type)} ${t.operation?.name??`operation`}`,a=n.rationale??[t.description,t.metadata?.observedValue?`Observed ${t.metadata.observedValue}`:void 0].filter(Boolean).join(` — `);return{id:e(),intent:t,target:t.operation,proposal:{summary:i,rationale:a,changeType:n.changeType??this.inferChangeType(t),kind:n.kind,spec:n.spec,diff:n.diff,metadata:n.metadata},confidence:t.confidence.score,priority:this.intentToPriority(t),createdAt:r,createdBy:n.createdBy??`auto-evolution`,status:n.status??`pending`,evidence:t.evidence,tags:n.tags}}generateVariant(e,t,r,i={}){if(!this.getSpec)throw Error(`SpecGenerator requires getSpec() to generate variants`);let a=this.getSpec(e.name,e.version);if(!a)throw Error(`Cannot generate variant; spec ${e.name}.v${e.version} not found`);let o=n(a,t);return this.generateFromIntent(r,{...i,spec:o})}validateSuggestion(e,t=this.config){let n=[];t.minConfidence!=null&&e.confidence<t.minConfidence&&n.push(`Confidence ${e.confidence.toFixed(2)} below minimum ${t.minConfidence}`),t.requireApproval&&e.status===`approved`&&n.push(`Suggestion cannot be auto-approved when approval is required`),e.proposal.spec&&!e.proposal.spec.meta?.name&&n.push(`Proposal spec must include meta.name`),e.proposal.summary||n.push(`Proposal summary is required`);let r=n.length===0;return r||this.logger?.warn(`SpecGenerator.validateSuggestion.failed`,{suggestionId:e.id,reasons:n}),{ok:r,reasons:n}}intentToVerb(e){switch(e){case`error-spike`:return`Stabilize`;case`latency-regression`:return`Optimize`;case`missing-operation`:return`Introduce`;case`throughput-drop`:return`Rebalance`;default:return`Adjust`}}intentToPriority(e){let t=e.confidence.score;return e.type===`error-spike`||t>=.8?`high`:t>=.5?`medium`:`low`}inferChangeType(e){switch(e.type){case`missing-operation`:return`new-spec`;case`schema-mismatch`:return`schema-update`;case`error-spike`:return`policy-update`;default:return`revision`}}};function n(e,t){return{...e,...t,meta:{...e.meta,...t.meta},io:{...e.io,...t.io},policy:{...e.policy,...t.policy},telemetry:{...e.telemetry,...t.telemetry},sideEffects:{...e.sideEffects,...t.sideEffects}}}export{t as SpecGenerator};
1
+ import "../observability/dist/index.js";
2
+ import { randomUUID } from "node:crypto";
3
+
4
+ //#region src/generator/spec-generator.ts
5
+ var SpecGenerator = class {
6
+ config;
7
+ logger;
8
+ clock;
9
+ getSpec;
10
+ constructor(options = {}) {
11
+ this.config = options.config ?? {};
12
+ this.logger = options.logger;
13
+ this.clock = options.clock ?? (() => /* @__PURE__ */ new Date());
14
+ this.getSpec = options.getSpec;
15
+ }
16
+ generateFromIntent(intent, options = {}) {
17
+ const now = this.clock();
18
+ const summary = options.summary ?? `${this.intentToVerb(intent.type)} ${intent.operation?.name ?? "operation"}`;
19
+ const rationale = options.rationale ?? [intent.description, intent.metadata?.observedValue ? `Observed ${intent.metadata.observedValue}` : void 0].filter(Boolean).join(" — ");
20
+ return {
21
+ id: randomUUID(),
22
+ intent,
23
+ target: intent.operation,
24
+ proposal: {
25
+ summary,
26
+ rationale,
27
+ changeType: options.changeType ?? this.inferChangeType(intent),
28
+ kind: options.kind,
29
+ spec: options.spec,
30
+ diff: options.diff,
31
+ metadata: options.metadata
32
+ },
33
+ confidence: intent.confidence.score,
34
+ priority: this.intentToPriority(intent),
35
+ createdAt: now,
36
+ createdBy: options.createdBy ?? "auto-evolution",
37
+ status: options.status ?? "pending",
38
+ evidence: intent.evidence,
39
+ tags: options.tags
40
+ };
41
+ }
42
+ generateVariant(operation, patch, intent, options = {}) {
43
+ if (!this.getSpec) throw new Error("SpecGenerator requires getSpec() to generate variants");
44
+ const base = this.getSpec(operation.name, operation.version);
45
+ if (!base) throw new Error(`Cannot generate variant; spec ${operation.name}.v${operation.version} not found`);
46
+ const merged = mergeContract(base, patch);
47
+ return this.generateFromIntent(intent, {
48
+ ...options,
49
+ spec: merged
50
+ });
51
+ }
52
+ validateSuggestion(suggestion, config = this.config) {
53
+ const reasons = [];
54
+ if (config.minConfidence != null && suggestion.confidence < config.minConfidence) reasons.push(`Confidence ${suggestion.confidence.toFixed(2)} below minimum ${config.minConfidence}`);
55
+ if (config.requireApproval && suggestion.status === "approved") reasons.push("Suggestion cannot be auto-approved when approval is required");
56
+ if (suggestion.proposal.spec && !suggestion.proposal.spec.meta?.name) reasons.push("Proposal spec must include meta.name");
57
+ if (!suggestion.proposal.summary) reasons.push("Proposal summary is required");
58
+ const ok = reasons.length === 0;
59
+ if (!ok) this.logger?.warn("SpecGenerator.validateSuggestion.failed", {
60
+ suggestionId: suggestion.id,
61
+ reasons
62
+ });
63
+ return {
64
+ ok,
65
+ reasons
66
+ };
67
+ }
68
+ intentToVerb(intent) {
69
+ switch (intent) {
70
+ case "error-spike": return "Stabilize";
71
+ case "latency-regression": return "Optimize";
72
+ case "missing-operation": return "Introduce";
73
+ case "throughput-drop": return "Rebalance";
74
+ default: return "Adjust";
75
+ }
76
+ }
77
+ intentToPriority(intent) {
78
+ const severity = intent.confidence.score;
79
+ if (intent.type === "error-spike" || severity >= .8) return "high";
80
+ if (severity >= .5) return "medium";
81
+ return "low";
82
+ }
83
+ inferChangeType(intent) {
84
+ switch (intent.type) {
85
+ case "missing-operation": return "new-spec";
86
+ case "schema-mismatch": return "schema-update";
87
+ case "error-spike": return "policy-update";
88
+ default: return "revision";
89
+ }
90
+ }
91
+ };
92
+ function mergeContract(base, patch) {
93
+ return {
94
+ ...base,
95
+ ...patch,
96
+ meta: {
97
+ ...base.meta,
98
+ ...patch.meta
99
+ },
100
+ io: {
101
+ ...base.io,
102
+ ...patch.io
103
+ },
104
+ policy: {
105
+ ...base.policy,
106
+ ...patch.policy
107
+ },
108
+ telemetry: {
109
+ ...base.telemetry,
110
+ ...patch.telemetry
111
+ },
112
+ sideEffects: {
113
+ ...base.sideEffects,
114
+ ...patch.sideEffects
115
+ }
116
+ };
117
+ }
118
+
119
+ //#endregion
120
+ export { SpecGenerator };
package/dist/index.js CHANGED
@@ -1 +1,6 @@
1
- import{SpecAnalyzer as e}from"./analyzer/spec-analyzer.js";import{SpecGenerator as t}from"./generator/spec-generator.js";import{AISpecGenerator as n,createAISpecGenerator as r}from"./generator/ai-spec-generator.js";import{FileSystemSuggestionWriter as i,InMemorySpecSuggestionRepository as a,SpecSuggestionOrchestrator as o}from"./approval/integration.js";export{n as AISpecGenerator,i as FileSystemSuggestionWriter,a as InMemorySpecSuggestionRepository,e as SpecAnalyzer,t as SpecGenerator,o as SpecSuggestionOrchestrator,r as createAISpecGenerator};
1
+ import { SpecAnalyzer } from "./analyzer/spec-analyzer.js";
2
+ import { SpecGenerator } from "./generator/spec-generator.js";
3
+ import { AISpecGenerator, createAISpecGenerator } from "./generator/ai-spec-generator.js";
4
+ import { FileSystemSuggestionWriter, InMemorySpecSuggestionRepository, SpecSuggestionOrchestrator } from "./approval/integration.js";
5
+
6
+ export { AISpecGenerator, FileSystemSuggestionWriter, InMemorySpecSuggestionRepository, SpecAnalyzer, SpecGenerator, SpecSuggestionOrchestrator, createAISpecGenerator };
@@ -1 +1,4 @@
1
- import{e,n as t}from"./types/stages.js";import"./types/axes.js";import"./types/signals.js";import"./types/milestones.js";import"./utils/formatters.js";
1
+ import { LifecycleStage } from "./types/stages.js";
2
+ import "./types/signals.js";
3
+ import "./types/milestones.js";
4
+ import "./utils/formatters.js";
@@ -1 +1 @@
1
- import"./stages.js";
1
+ import "./stages.js";
@@ -1 +1 @@
1
- import"./stages.js";
1
+ import "./stages.js";
@@ -1 +1,151 @@
1
- let e=function(e){return e[e.Exploration=0]=`Exploration`,e[e.ProblemSolutionFit=1]=`ProblemSolutionFit`,e[e.MvpEarlyTraction=2]=`MvpEarlyTraction`,e[e.ProductMarketFit=3]=`ProductMarketFit`,e[e.GrowthScaleUp=4]=`GrowthScaleUp`,e[e.ExpansionPlatform=5]=`ExpansionPlatform`,e[e.MaturityRenewal=6]=`MaturityRenewal`,e}({});e.Exploration,e.ProblemSolutionFit,e.MvpEarlyTraction,e.ProductMarketFit,e.GrowthScaleUp,e.ExpansionPlatform,e.MaturityRenewal;const t={[e.Exploration]:{id:e.Exploration,order:0,slug:`exploration`,name:`Exploration / Ideation`,question:`Is there a problem worth my time?`,signals:[`20+ discovery interviews`,`Clear problem statement`,`Named ICP`],traps:[`Branding before discovery`,`Premature tooling decisions`],focusAreas:[`Customer discovery`,`Problem definition`,`Segment clarity`]},[e.ProblemSolutionFit]:{id:e.ProblemSolutionFit,order:1,slug:`problem-solution-fit`,name:`Problem–Solution Fit`,question:`Do people care enough about this solution?`,signals:[`Prototype reuse`,`Referral energy`,`Pre-pay interest`],traps:[`“Market is huge” without users`,`Skipping qualitative loops`],focusAreas:[`Solution hypothesis`,`Value messaging`,`Feedback capture`]},[e.MvpEarlyTraction]:{id:e.MvpEarlyTraction,order:2,slug:`mvp-early-traction`,name:`MVP & Early Traction`,question:`Can we get real usage and learn fast?`,signals:[`20–50 named active users`,`Weekly releases`,`Noisy feedback`],traps:[`Overbuilt infra for 10 users`,`Undefined retention metric`],focusAreas:[`Activation`,`Cohort tracking`,`Feedback rituals`]},[e.ProductMarketFit]:{id:e.ProductMarketFit,order:3,slug:`product-market-fit`,name:`Product–Market Fit`,question:`Is this pulling us forward?`,signals:[`Retention without heroics`,`Organic word-of-mouth`,`Value stories`],traps:[`Hero growth that does not scale`,`Ignoring churn signals`],focusAreas:[`Retention`,`Reliability`,`ICP clarity`]},[e.GrowthScaleUp]:{id:e.GrowthScaleUp,order:4,slug:`growth-scale-up`,name:`Growth / Scale-up`,question:`Can we grow this repeatably?`,signals:[`Predictable channels`,`Specialized hires`,`Unit economics on track`],traps:[`Paid spend masking retention gaps`,`Infra debt blocking launches`],focusAreas:[`Ops systems`,`Growth loops`,`Reliability engineering`]},[e.ExpansionPlatform]:{id:e.ExpansionPlatform,order:5,slug:`expansion-platform`,name:`Expansion / Platform`,question:`What is the next growth curve?`,signals:[`Stable core metrics`,`Partner/API demand`,`Ecosystem pull`],traps:[`Platform theater before wedge is solid`],focusAreas:[`Partnerships`,`APIs`,`New market validation`]},[e.MaturityRenewal]:{id:e.MaturityRenewal,order:6,slug:`maturity-renewal`,name:`Maturity / Renewal`,question:`Optimize, reinvent, or sunset?`,signals:[`Margin focus`,`Portfolio bets`,`Narrative refresh`],traps:[`Assuming past success is enough`],focusAreas:[`Cost optimization`,`Reinvention bets`,`Sunset planning`]}};export{e,t as n};
1
+ //#region ../lifecycle/dist/types/stages.js
2
+ let LifecycleStage = /* @__PURE__ */ function(LifecycleStage$1) {
3
+ LifecycleStage$1[LifecycleStage$1["Exploration"] = 0] = "Exploration";
4
+ LifecycleStage$1[LifecycleStage$1["ProblemSolutionFit"] = 1] = "ProblemSolutionFit";
5
+ LifecycleStage$1[LifecycleStage$1["MvpEarlyTraction"] = 2] = "MvpEarlyTraction";
6
+ LifecycleStage$1[LifecycleStage$1["ProductMarketFit"] = 3] = "ProductMarketFit";
7
+ LifecycleStage$1[LifecycleStage$1["GrowthScaleUp"] = 4] = "GrowthScaleUp";
8
+ LifecycleStage$1[LifecycleStage$1["ExpansionPlatform"] = 5] = "ExpansionPlatform";
9
+ LifecycleStage$1[LifecycleStage$1["MaturityRenewal"] = 6] = "MaturityRenewal";
10
+ return LifecycleStage$1;
11
+ }({});
12
+ const LIFECYCLE_STAGE_ORDER = [
13
+ LifecycleStage.Exploration,
14
+ LifecycleStage.ProblemSolutionFit,
15
+ LifecycleStage.MvpEarlyTraction,
16
+ LifecycleStage.ProductMarketFit,
17
+ LifecycleStage.GrowthScaleUp,
18
+ LifecycleStage.ExpansionPlatform,
19
+ LifecycleStage.MaturityRenewal
20
+ ];
21
+ const LIFECYCLE_STAGE_META = {
22
+ [LifecycleStage.Exploration]: {
23
+ id: LifecycleStage.Exploration,
24
+ order: 0,
25
+ slug: "exploration",
26
+ name: "Exploration / Ideation",
27
+ question: "Is there a problem worth my time?",
28
+ signals: [
29
+ "20+ discovery interviews",
30
+ "Clear problem statement",
31
+ "Named ICP"
32
+ ],
33
+ traps: ["Branding before discovery", "Premature tooling decisions"],
34
+ focusAreas: [
35
+ "Customer discovery",
36
+ "Problem definition",
37
+ "Segment clarity"
38
+ ]
39
+ },
40
+ [LifecycleStage.ProblemSolutionFit]: {
41
+ id: LifecycleStage.ProblemSolutionFit,
42
+ order: 1,
43
+ slug: "problem-solution-fit",
44
+ name: "Problem–Solution Fit",
45
+ question: "Do people care enough about this solution?",
46
+ signals: [
47
+ "Prototype reuse",
48
+ "Referral energy",
49
+ "Pre-pay interest"
50
+ ],
51
+ traps: ["“Market is huge” without users", "Skipping qualitative loops"],
52
+ focusAreas: [
53
+ "Solution hypothesis",
54
+ "Value messaging",
55
+ "Feedback capture"
56
+ ]
57
+ },
58
+ [LifecycleStage.MvpEarlyTraction]: {
59
+ id: LifecycleStage.MvpEarlyTraction,
60
+ order: 2,
61
+ slug: "mvp-early-traction",
62
+ name: "MVP & Early Traction",
63
+ question: "Can we get real usage and learn fast?",
64
+ signals: [
65
+ "20–50 named active users",
66
+ "Weekly releases",
67
+ "Noisy feedback"
68
+ ],
69
+ traps: ["Overbuilt infra for 10 users", "Undefined retention metric"],
70
+ focusAreas: [
71
+ "Activation",
72
+ "Cohort tracking",
73
+ "Feedback rituals"
74
+ ]
75
+ },
76
+ [LifecycleStage.ProductMarketFit]: {
77
+ id: LifecycleStage.ProductMarketFit,
78
+ order: 3,
79
+ slug: "product-market-fit",
80
+ name: "Product–Market Fit",
81
+ question: "Is this pulling us forward?",
82
+ signals: [
83
+ "Retention without heroics",
84
+ "Organic word-of-mouth",
85
+ "Value stories"
86
+ ],
87
+ traps: ["Hero growth that does not scale", "Ignoring churn signals"],
88
+ focusAreas: [
89
+ "Retention",
90
+ "Reliability",
91
+ "ICP clarity"
92
+ ]
93
+ },
94
+ [LifecycleStage.GrowthScaleUp]: {
95
+ id: LifecycleStage.GrowthScaleUp,
96
+ order: 4,
97
+ slug: "growth-scale-up",
98
+ name: "Growth / Scale-up",
99
+ question: "Can we grow this repeatably?",
100
+ signals: [
101
+ "Predictable channels",
102
+ "Specialized hires",
103
+ "Unit economics on track"
104
+ ],
105
+ traps: ["Paid spend masking retention gaps", "Infra debt blocking launches"],
106
+ focusAreas: [
107
+ "Ops systems",
108
+ "Growth loops",
109
+ "Reliability engineering"
110
+ ]
111
+ },
112
+ [LifecycleStage.ExpansionPlatform]: {
113
+ id: LifecycleStage.ExpansionPlatform,
114
+ order: 5,
115
+ slug: "expansion-platform",
116
+ name: "Expansion / Platform",
117
+ question: "What is the next growth curve?",
118
+ signals: [
119
+ "Stable core metrics",
120
+ "Partner/API demand",
121
+ "Ecosystem pull"
122
+ ],
123
+ traps: ["Platform theater before wedge is solid"],
124
+ focusAreas: [
125
+ "Partnerships",
126
+ "APIs",
127
+ "New market validation"
128
+ ]
129
+ },
130
+ [LifecycleStage.MaturityRenewal]: {
131
+ id: LifecycleStage.MaturityRenewal,
132
+ order: 6,
133
+ slug: "maturity-renewal",
134
+ name: "Maturity / Renewal",
135
+ question: "Optimize, reinvent, or sunset?",
136
+ signals: [
137
+ "Margin focus",
138
+ "Portfolio bets",
139
+ "Narrative refresh"
140
+ ],
141
+ traps: ["Assuming past success is enough"],
142
+ focusAreas: [
143
+ "Cost optimization",
144
+ "Reinvention bets",
145
+ "Sunset planning"
146
+ ]
147
+ }
148
+ };
149
+
150
+ //#endregion
151
+ export { LifecycleStage };
@@ -1 +1 @@
1
- import"../types/stages.js";
1
+ import "../types/stages.js";
@@ -1 +1,8 @@
1
- import"./tracing/index.js";import{i as e,n as t,t as n}from"./metrics/index.js";import{n as r}from"./logging/index.js";import"./tracing/middleware.js";import"./intent/detector.js";import"./pipeline/evolution-pipeline.js";import"./pipeline/lifecycle-pipeline.js";
1
+ import "./tracing/index.js";
2
+ import { createCounter, createHistogram, getMeter } from "./metrics/index.js";
3
+ import { Logger } from "./logging/index.js";
4
+ import "./tracing/middleware.js";
5
+ import "./intent/aggregator.js";
6
+ import "./intent/detector.js";
7
+ import "./pipeline/evolution-pipeline.js";
8
+ import "./pipeline/lifecycle-pipeline.js";
@@ -0,0 +1,4 @@
1
+ //#region ../observability/dist/intent/aggregator.mjs
2
+ const DEFAULT_WINDOW_MS = 900 * 1e3;
3
+
4
+ //#endregion
@@ -1 +1 @@
1
- import{randomUUID as e}from"node:crypto";
1
+ import { randomUUID } from "node:crypto";
@@ -1 +1,4 @@
1
- import"./types/stages.js";import"./utils/formatters.js";import"./types/axes.js";import"./types/signals.js";import"./types/milestones.js";
1
+ import "./types/stages.js";
2
+ import "./utils/formatters.js";
3
+ import "./types/signals.js";
4
+ import "./types/milestones.js";
@@ -1 +1 @@
1
- import"./stages.js";
1
+ import "./stages.js";
@@ -1 +1 @@
1
- import"./stages.js";
1
+ import "./stages.js";
@@ -1 +1,142 @@
1
- let e=function(e){return e[e.Exploration=0]=`Exploration`,e[e.ProblemSolutionFit=1]=`ProblemSolutionFit`,e[e.MvpEarlyTraction=2]=`MvpEarlyTraction`,e[e.ProductMarketFit=3]=`ProductMarketFit`,e[e.GrowthScaleUp=4]=`GrowthScaleUp`,e[e.ExpansionPlatform=5]=`ExpansionPlatform`,e[e.MaturityRenewal=6]=`MaturityRenewal`,e}({});e.Exploration,e.ProblemSolutionFit,e.MvpEarlyTraction,e.ProductMarketFit,e.GrowthScaleUp,e.ExpansionPlatform,e.MaturityRenewal,e.Exploration,e.Exploration,e.ProblemSolutionFit,e.ProblemSolutionFit,e.MvpEarlyTraction,e.MvpEarlyTraction,e.ProductMarketFit,e.ProductMarketFit,e.GrowthScaleUp,e.GrowthScaleUp,e.ExpansionPlatform,e.ExpansionPlatform,e.MaturityRenewal,e.MaturityRenewal;
1
+ //#region ../observability/dist/lifecycle/dist/types/stages.mjs
2
+ let LifecycleStage = /* @__PURE__ */ function(LifecycleStage$1) {
3
+ LifecycleStage$1[LifecycleStage$1["Exploration"] = 0] = "Exploration";
4
+ LifecycleStage$1[LifecycleStage$1["ProblemSolutionFit"] = 1] = "ProblemSolutionFit";
5
+ LifecycleStage$1[LifecycleStage$1["MvpEarlyTraction"] = 2] = "MvpEarlyTraction";
6
+ LifecycleStage$1[LifecycleStage$1["ProductMarketFit"] = 3] = "ProductMarketFit";
7
+ LifecycleStage$1[LifecycleStage$1["GrowthScaleUp"] = 4] = "GrowthScaleUp";
8
+ LifecycleStage$1[LifecycleStage$1["ExpansionPlatform"] = 5] = "ExpansionPlatform";
9
+ LifecycleStage$1[LifecycleStage$1["MaturityRenewal"] = 6] = "MaturityRenewal";
10
+ return LifecycleStage$1;
11
+ }({});
12
+ LifecycleStage.Exploration, LifecycleStage.ProblemSolutionFit, LifecycleStage.MvpEarlyTraction, LifecycleStage.ProductMarketFit, LifecycleStage.GrowthScaleUp, LifecycleStage.ExpansionPlatform, LifecycleStage.MaturityRenewal;
13
+ const LIFECYCLE_STAGE_META = {
14
+ [LifecycleStage.Exploration]: {
15
+ id: LifecycleStage.Exploration,
16
+ order: 0,
17
+ slug: "exploration",
18
+ name: "Exploration / Ideation",
19
+ question: "Is there a problem worth my time?",
20
+ signals: [
21
+ "20+ discovery interviews",
22
+ "Clear problem statement",
23
+ "Named ICP"
24
+ ],
25
+ traps: ["Branding before discovery", "Premature tooling decisions"],
26
+ focusAreas: [
27
+ "Customer discovery",
28
+ "Problem definition",
29
+ "Segment clarity"
30
+ ]
31
+ },
32
+ [LifecycleStage.ProblemSolutionFit]: {
33
+ id: LifecycleStage.ProblemSolutionFit,
34
+ order: 1,
35
+ slug: "problem-solution-fit",
36
+ name: "Problem–Solution Fit",
37
+ question: "Do people care enough about this solution?",
38
+ signals: [
39
+ "Prototype reuse",
40
+ "Referral energy",
41
+ "Pre-pay interest"
42
+ ],
43
+ traps: ["“Market is huge” without users", "Skipping qualitative loops"],
44
+ focusAreas: [
45
+ "Solution hypothesis",
46
+ "Value messaging",
47
+ "Feedback capture"
48
+ ]
49
+ },
50
+ [LifecycleStage.MvpEarlyTraction]: {
51
+ id: LifecycleStage.MvpEarlyTraction,
52
+ order: 2,
53
+ slug: "mvp-early-traction",
54
+ name: "MVP & Early Traction",
55
+ question: "Can we get real usage and learn fast?",
56
+ signals: [
57
+ "20–50 named active users",
58
+ "Weekly releases",
59
+ "Noisy feedback"
60
+ ],
61
+ traps: ["Overbuilt infra for 10 users", "Undefined retention metric"],
62
+ focusAreas: [
63
+ "Activation",
64
+ "Cohort tracking",
65
+ "Feedback rituals"
66
+ ]
67
+ },
68
+ [LifecycleStage.ProductMarketFit]: {
69
+ id: LifecycleStage.ProductMarketFit,
70
+ order: 3,
71
+ slug: "product-market-fit",
72
+ name: "Product–Market Fit",
73
+ question: "Is this pulling us forward?",
74
+ signals: [
75
+ "Retention without heroics",
76
+ "Organic word-of-mouth",
77
+ "Value stories"
78
+ ],
79
+ traps: ["Hero growth that does not scale", "Ignoring churn signals"],
80
+ focusAreas: [
81
+ "Retention",
82
+ "Reliability",
83
+ "ICP clarity"
84
+ ]
85
+ },
86
+ [LifecycleStage.GrowthScaleUp]: {
87
+ id: LifecycleStage.GrowthScaleUp,
88
+ order: 4,
89
+ slug: "growth-scale-up",
90
+ name: "Growth / Scale-up",
91
+ question: "Can we grow this repeatably?",
92
+ signals: [
93
+ "Predictable channels",
94
+ "Specialized hires",
95
+ "Unit economics on track"
96
+ ],
97
+ traps: ["Paid spend masking retention gaps", "Infra debt blocking launches"],
98
+ focusAreas: [
99
+ "Ops systems",
100
+ "Growth loops",
101
+ "Reliability engineering"
102
+ ]
103
+ },
104
+ [LifecycleStage.ExpansionPlatform]: {
105
+ id: LifecycleStage.ExpansionPlatform,
106
+ order: 5,
107
+ slug: "expansion-platform",
108
+ name: "Expansion / Platform",
109
+ question: "What is the next growth curve?",
110
+ signals: [
111
+ "Stable core metrics",
112
+ "Partner/API demand",
113
+ "Ecosystem pull"
114
+ ],
115
+ traps: ["Platform theater before wedge is solid"],
116
+ focusAreas: [
117
+ "Partnerships",
118
+ "APIs",
119
+ "New market validation"
120
+ ]
121
+ },
122
+ [LifecycleStage.MaturityRenewal]: {
123
+ id: LifecycleStage.MaturityRenewal,
124
+ order: 6,
125
+ slug: "maturity-renewal",
126
+ name: "Maturity / Renewal",
127
+ question: "Optimize, reinvent, or sunset?",
128
+ signals: [
129
+ "Margin focus",
130
+ "Portfolio bets",
131
+ "Narrative refresh"
132
+ ],
133
+ traps: ["Assuming past success is enough"],
134
+ focusAreas: [
135
+ "Cost optimization",
136
+ "Reinvention bets",
137
+ "Sunset planning"
138
+ ]
139
+ }
140
+ };
141
+
142
+ //#endregion
@@ -1 +1 @@
1
- import"../types/stages.js";
1
+ import "../types/stages.js";
@@ -1 +1,39 @@
1
- import{context as e,trace as t}from"@opentelemetry/api";var n=class{constructor(e){this.serviceName=e}log(n,r,i={}){let a=t.getSpan(e.active()),o=a?.spanContext().traceId,s=a?.spanContext().spanId,c={timestamp:new Date().toISOString(),service:this.serviceName,level:n,message:r,traceId:o,spanId:s,...i};console.log(JSON.stringify(c))}debug(e,t){this.log(`debug`,e,t)}info(e,t){this.log(`info`,e,t)}warn(e,t){this.log(`warn`,e,t)}error(e,t){this.log(`error`,e,t)}};new n(process.env.OTEL_SERVICE_NAME||`unknown-service`);export{n};
1
+ import { context, trace } from "@opentelemetry/api";
2
+
3
+ //#region ../observability/dist/logging/index.mjs
4
+ var Logger = class {
5
+ constructor(serviceName) {
6
+ this.serviceName = serviceName;
7
+ }
8
+ log(level, message, meta = {}) {
9
+ const span = trace.getSpan(context.active());
10
+ const traceId = span?.spanContext().traceId;
11
+ const spanId = span?.spanContext().spanId;
12
+ const entry = {
13
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14
+ service: this.serviceName,
15
+ level,
16
+ message,
17
+ traceId,
18
+ spanId,
19
+ ...meta
20
+ };
21
+ console.log(JSON.stringify(entry));
22
+ }
23
+ debug(message, meta) {
24
+ this.log("debug", message, meta);
25
+ }
26
+ info(message, meta) {
27
+ this.log("info", message, meta);
28
+ }
29
+ warn(message, meta) {
30
+ this.log("warn", message, meta);
31
+ }
32
+ error(message, meta) {
33
+ this.log("error", message, meta);
34
+ }
35
+ };
36
+ const logger = new Logger(process.env.OTEL_SERVICE_NAME || "unknown-service");
37
+
38
+ //#endregion
39
+ export { Logger };
@@ -1 +1,22 @@
1
- import{metrics as e}from"@opentelemetry/api";function t(t=`@lssm/lib.observability`){return e.getMeter(t)}function n(e,n,r){return t(r).createCounter(e,{description:n})}function r(e,n,r){return t(r).createHistogram(e,{description:n})}n(`http_requests_total`,`Total HTTP requests`),r(`http_request_duration_seconds`,`HTTP request duration`),n(`operation_errors_total`,`Total operation errors`),r(`workflow_duration_seconds`,`Workflow execution duration`);export{r as i,n,t};
1
+ import { metrics } from "@opentelemetry/api";
2
+
3
+ //#region ../observability/dist/metrics/index.mjs
4
+ const DEFAULT_METER_NAME = "@lssm/lib.observability";
5
+ function getMeter(name = DEFAULT_METER_NAME) {
6
+ return metrics.getMeter(name);
7
+ }
8
+ function createCounter(name, description, meterName) {
9
+ return getMeter(meterName).createCounter(name, { description });
10
+ }
11
+ function createHistogram(name, description, meterName) {
12
+ return getMeter(meterName).createHistogram(name, { description });
13
+ }
14
+ const standardMetrics = {
15
+ httpRequests: createCounter("http_requests_total", "Total HTTP requests"),
16
+ httpDuration: createHistogram("http_request_duration_seconds", "HTTP request duration"),
17
+ operationErrors: createCounter("operation_errors_total", "Total operation errors"),
18
+ workflowDuration: createHistogram("workflow_duration_seconds", "Workflow execution duration")
19
+ };
20
+
21
+ //#endregion
22
+ export { createCounter, createHistogram, getMeter };
@@ -1 +1,3 @@
1
- import"../intent/detector.js";import"node:events";
1
+ import "../intent/aggregator.js";
2
+ import "../intent/detector.js";
3
+ import "node:events";
@@ -1 +1,4 @@
1
- import"../metrics/index.js";import"../lifecycle/dist/utils/formatters.js";import"../lifecycle/dist/index.js";import"node:events";
1
+ import "../metrics/index.js";
2
+ import "../lifecycle/dist/utils/formatters.js";
3
+ import "../lifecycle/dist/index.js";
4
+ import "node:events";
@@ -1 +1 @@
1
- import{trace as e}from"@opentelemetry/api";
1
+ import { trace } from "@opentelemetry/api";
@@ -1 +1,2 @@
1
- import"./index.js";import"../metrics/index.js";
1
+ import "./index.js";
2
+ import "../metrics/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lssm/lib.evolution",
3
- "version": "0.0.0-canary-20251217062139",
3
+ "version": "0.0.0-canary-20251217072406",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -25,18 +25,18 @@
25
25
  "dependencies": {
26
26
  "ai": "beta",
27
27
  "zod": "^4.1.13",
28
- "@lssm/lib.ai-agent": "0.0.0-canary-20251217062139",
29
- "@lssm/lib.contracts": "0.0.0-canary-20251217062139",
30
- "@lssm/lib.lifecycle": "0.0.0-canary-20251217062139",
31
- "@lssm/lib.observability": "0.0.0-canary-20251217062139",
32
- "@lssm/lib.schema": "0.0.0-canary-20251217062139"
28
+ "@lssm/lib.ai-agent": "0.0.0-canary-20251217072406",
29
+ "@lssm/lib.contracts": "0.0.0-canary-20251217072406",
30
+ "@lssm/lib.lifecycle": "0.0.0-canary-20251217072406",
31
+ "@lssm/lib.observability": "0.0.0-canary-20251217072406",
32
+ "@lssm/lib.schema": "0.0.0-canary-20251217072406"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@prisma/client": "7.1.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@lssm/tool.tsdown": "0.0.0-canary-20251217062139",
39
- "@lssm/tool.typescript": "0.0.0-canary-20251217062139",
38
+ "@lssm/tool.tsdown": "0.0.0-canary-20251217072406",
39
+ "@lssm/tool.typescript": "0.0.0-canary-20251217072406",
40
40
  "tsdown": "^0.17.4",
41
41
  "typescript": "^5.9.3"
42
42
  },
@@ -1 +0,0 @@
1
- (function(e){return e.Sketch=`Sketch`,e.Prototype=`Prototype`,e.Mvp=`MVP`,e.V1=`V1`,e.Ecosystem=`Ecosystem`,e})({}),function(e){return e.Solo=`Solo`,e.TinyTeam=`TinyTeam`,e.FunctionalOrg=`FunctionalOrg`,e.MultiTeam=`MultiTeam`,e.Bureaucratic=`Bureaucratic`,e}({}),function(e){return e.Bootstrapped=`Bootstrapped`,e.PreSeed=`PreSeed`,e.Seed=`Seed`,e.SeriesAorB=`SeriesAorB`,e.LateStage=`LateStage`,e}({});
@@ -1 +0,0 @@
1
- (function(e){return e.Sketch=`Sketch`,e.Prototype=`Prototype`,e.Mvp=`MVP`,e.V1=`V1`,e.Ecosystem=`Ecosystem`,e})({}),function(e){return e.Solo=`Solo`,e.TinyTeam=`TinyTeam`,e.FunctionalOrg=`FunctionalOrg`,e.MultiTeam=`MultiTeam`,e.Bureaucratic=`Bureaucratic`,e}({}),function(e){return e.Bootstrapped=`Bootstrapped`,e.PreSeed=`PreSeed`,e.Seed=`Seed`,e.SeriesAorB=`SeriesAorB`,e.LateStage=`LateStage`,e}({});