@planu/cli 0.97.2 → 0.99.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/license-plans.json +8 -3
- package/dist/config/mobile-ci-templates/android-github-actions.yml +149 -0
- package/dist/config/mobile-ci-templates/ios-github-actions.yml +120 -0
- package/dist/engine/api-validation/graphql-schema-validator.d.ts +3 -0
- package/dist/engine/api-validation/graphql-schema-validator.d.ts.map +1 -0
- package/dist/engine/api-validation/graphql-schema-validator.js +134 -0
- package/dist/engine/api-validation/graphql-schema-validator.js.map +1 -0
- package/dist/engine/api-validation/index.d.ts +3 -0
- package/dist/engine/api-validation/index.d.ts.map +1 -0
- package/dist/engine/api-validation/index.js +4 -0
- package/dist/engine/api-validation/index.js.map +1 -0
- package/dist/engine/api-validation/openapi-impl-validator.d.ts +3 -0
- package/dist/engine/api-validation/openapi-impl-validator.d.ts.map +1 -0
- package/dist/engine/api-validation/openapi-impl-validator.js +205 -0
- package/dist/engine/api-validation/openapi-impl-validator.js.map +1 -0
- package/dist/engine/ci-generator/android-jobs.d.ts +17 -0
- package/dist/engine/ci-generator/android-jobs.d.ts.map +1 -0
- package/dist/engine/ci-generator/android-jobs.js +168 -0
- package/dist/engine/ci-generator/android-jobs.js.map +1 -0
- package/dist/engine/ci-generator/ios-jobs.d.ts +17 -0
- package/dist/engine/ci-generator/ios-jobs.d.ts.map +1 -0
- package/dist/engine/ci-generator/ios-jobs.js +151 -0
- package/dist/engine/ci-generator/ios-jobs.js.map +1 -0
- package/dist/engine/ci-generator/yaml-builder.d.ts +10 -1
- package/dist/engine/ci-generator/yaml-builder.d.ts.map +1 -1
- package/dist/engine/ci-generator/yaml-builder.js +46 -1
- package/dist/engine/ci-generator/yaml-builder.js.map +1 -1
- package/dist/engine/coverage-gap-analyzer.d.ts +6 -0
- package/dist/engine/coverage-gap-analyzer.d.ts.map +1 -0
- package/dist/engine/coverage-gap-analyzer.js +177 -0
- package/dist/engine/coverage-gap-analyzer.js.map +1 -0
- package/dist/engine/dashboard/templates-kanban.d.ts.map +1 -1
- package/dist/engine/dashboard/templates-kanban.js +22 -0
- package/dist/engine/dashboard/templates-kanban.js.map +1 -1
- package/dist/engine/dashboard/templates-layout.d.ts.map +1 -1
- package/dist/engine/dashboard/templates-layout.js +59 -7
- package/dist/engine/dashboard/templates-layout.js.map +1 -1
- package/dist/engine/mutation-config-generator.d.ts +6 -0
- package/dist/engine/mutation-config-generator.d.ts.map +1 -0
- package/dist/engine/mutation-config-generator.js +111 -0
- package/dist/engine/mutation-config-generator.js.map +1 -0
- package/dist/engine/product-intelligence/index.d.ts +7 -0
- package/dist/engine/product-intelligence/index.d.ts.map +1 -0
- package/dist/engine/product-intelligence/index.js +211 -0
- package/dist/engine/product-intelligence/index.js.map +1 -0
- package/dist/engine/tdd-scaffold-generator.d.ts +7 -0
- package/dist/engine/tdd-scaffold-generator.d.ts.map +1 -0
- package/dist/engine/tdd-scaffold-generator.js +252 -0
- package/dist/engine/tdd-scaffold-generator.js.map +1 -0
- package/dist/engine/telemetry/error-reporter.d.ts +9 -2
- package/dist/engine/telemetry/error-reporter.d.ts.map +1 -1
- package/dist/engine/telemetry/error-reporter.js +31 -4
- package/dist/engine/telemetry/error-reporter.js.map +1 -1
- package/dist/engine/version-resolver.d.ts +10 -0
- package/dist/engine/version-resolver.d.ts.map +1 -0
- package/dist/engine/version-resolver.js +144 -0
- package/dist/engine/version-resolver.js.map +1 -0
- package/dist/engine/web-fetcher/stack-advisor.d.ts.map +1 -1
- package/dist/engine/web-fetcher/stack-advisor.js +32 -4
- package/dist/engine/web-fetcher/stack-advisor.js.map +1 -1
- package/dist/index.js +9 -11
- package/dist/index.js.map +1 -1
- package/dist/tools/checkpoint-handler.d.ts.map +1 -1
- package/dist/tools/checkpoint-handler.js +24 -1
- package/dist/tools/checkpoint-handler.js.map +1 -1
- package/dist/tools/dashboard.d.ts.map +1 -1
- package/dist/tools/dashboard.js +2 -0
- package/dist/tools/dashboard.js.map +1 -1
- package/dist/tools/product-insights-handler.d.ts +11 -0
- package/dist/tools/product-insights-handler.d.ts.map +1 -0
- package/dist/tools/product-insights-handler.js +102 -0
- package/dist/tools/product-insights-handler.js.map +1 -0
- package/dist/tools/register-product-insights-tools.d.ts +3 -0
- package/dist/tools/register-product-insights-tools.d.ts.map +1 -0
- package/dist/tools/register-product-insights-tools.js +22 -0
- package/dist/tools/register-product-insights-tools.js.map +1 -0
- package/dist/tools/register-spec-322-tools.d.ts +3 -0
- package/dist/tools/register-spec-322-tools.d.ts.map +1 -0
- package/dist/tools/register-spec-322-tools.js +41 -0
- package/dist/tools/register-spec-322-tools.js.map +1 -0
- package/dist/tools/register-spec-323-tools.d.ts +3 -0
- package/dist/tools/register-spec-323-tools.d.ts.map +1 -0
- package/dist/tools/register-spec-323-tools.js +57 -0
- package/dist/tools/register-spec-323-tools.js.map +1 -0
- package/dist/tools/safe-handler.d.ts.map +1 -1
- package/dist/tools/safe-handler.js +19 -1
- package/dist/tools/safe-handler.js.map +1 -1
- package/dist/tools/tdd-scaffold-handler.d.ts +5 -0
- package/dist/tools/tdd-scaffold-handler.d.ts.map +1 -0
- package/dist/tools/tdd-scaffold-handler.js +92 -0
- package/dist/tools/tdd-scaffold-handler.js.map +1 -0
- package/dist/tools/validate-api-contract-handler.d.ts +3 -0
- package/dist/tools/validate-api-contract-handler.d.ts.map +1 -0
- package/dist/tools/validate-api-contract-handler.js +74 -0
- package/dist/tools/validate-api-contract-handler.js.map +1 -0
- package/dist/tools/validate.d.ts.map +1 -1
- package/dist/tools/validate.js +24 -2
- package/dist/tools/validate.js.map +1 -1
- package/dist/types/api-contract.d.ts +58 -0
- package/dist/types/api-contract.d.ts.map +1 -1
- package/dist/types/ci.d.ts +8 -0
- package/dist/types/ci.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/product-intelligence.d.ts +60 -0
- package/dist/types/product-intelligence.d.ts.map +1 -0
- package/dist/types/product-intelligence.js +3 -0
- package/dist/types/product-intelligence.js.map +1 -0
- package/dist/types/telemetry.d.ts +1 -1
- package/dist/types/telemetry.d.ts.map +1 -1
- package/dist/types/testing.d.ts +60 -0
- package/dist/types/testing.d.ts.map +1 -1
- package/dist/types/version-resolution.d.ts +23 -0
- package/dist/types/version-resolution.d.ts.map +1 -0
- package/dist/types/version-resolution.js +3 -0
- package/dist/types/version-resolution.js.map +1 -0
- package/package.json +1 -1
- package/src/config/license-plans.json +8 -3
- package/src/config/mobile-ci-templates/android-github-actions.yml +149 -0
- package/src/config/mobile-ci-templates/ios-github-actions.yml +120 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// engine/mutation-config-generator.ts — SPEC-323
|
|
2
|
+
// Detects project stack and generates the appropriate mutation testing config file.
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { getMutationTool, generateMutationConfig as buildMutationConfig, } from './advanced-testing/mutation-advisor.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Stack detection
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
async function detectStack(projectPath) {
|
|
10
|
+
const pkgPath = join(projectPath, 'package.json');
|
|
11
|
+
try {
|
|
12
|
+
const raw = await readFile(pkgPath, 'utf8');
|
|
13
|
+
const pkg = JSON.parse(raw);
|
|
14
|
+
const deps = {
|
|
15
|
+
...(pkg.dependencies ?? {}),
|
|
16
|
+
...(pkg.devDependencies ?? {}),
|
|
17
|
+
};
|
|
18
|
+
const language = 'typescript' in deps ? 'typescript' : 'javascript';
|
|
19
|
+
let testFramework = 'unknown';
|
|
20
|
+
if ('vitest' in deps) {
|
|
21
|
+
testFramework = 'vitest';
|
|
22
|
+
}
|
|
23
|
+
else if ('jest' in deps) {
|
|
24
|
+
testFramework = 'jest';
|
|
25
|
+
}
|
|
26
|
+
else if ('mocha' in deps) {
|
|
27
|
+
testFramework = 'mocha';
|
|
28
|
+
}
|
|
29
|
+
return { language, testFramework };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
const hasPython = (await readFile(join(projectPath, 'setup.py'), 'utf8').catch(() => null)) !== null ||
|
|
33
|
+
(await readFile(join(projectPath, 'pyproject.toml'), 'utf8').catch(() => null)) !== null;
|
|
34
|
+
if (hasPython) {
|
|
35
|
+
return { language: 'python', testFramework: 'pytest' };
|
|
36
|
+
}
|
|
37
|
+
const hasMaven = (await readFile(join(projectPath, 'pom.xml'), 'utf8').catch(() => null)) !== null;
|
|
38
|
+
if (hasMaven) {
|
|
39
|
+
return { language: 'java', testFramework: 'junit' };
|
|
40
|
+
}
|
|
41
|
+
return { language: 'typescript', testFramework: 'unknown' };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Config file name resolution
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
function resolveConfigFileName(tool) {
|
|
48
|
+
switch (tool) {
|
|
49
|
+
case 'stryker':
|
|
50
|
+
return 'stryker.config.mjs';
|
|
51
|
+
case 'mutmut':
|
|
52
|
+
case 'cosmic-ray':
|
|
53
|
+
return 'setup.cfg';
|
|
54
|
+
case 'pitest':
|
|
55
|
+
return 'pom.xml (add mutation plugin section)';
|
|
56
|
+
case 'cargo-mutants':
|
|
57
|
+
return '.cargo-mutants.toml';
|
|
58
|
+
case 'gremlins':
|
|
59
|
+
return '.gremlins.yaml';
|
|
60
|
+
case 'stryker4s':
|
|
61
|
+
return 'stryker4s.conf';
|
|
62
|
+
case 'stryker-dotnet':
|
|
63
|
+
return 'stryker-config.json';
|
|
64
|
+
default:
|
|
65
|
+
return 'stryker.config.mjs';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// CI step generation
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
function buildCiStep(tool) {
|
|
72
|
+
switch (tool) {
|
|
73
|
+
case 'stryker':
|
|
74
|
+
return 'npx stryker run';
|
|
75
|
+
case 'mutmut':
|
|
76
|
+
return 'python -m mutmut run && python -m mutmut results';
|
|
77
|
+
case 'pitest':
|
|
78
|
+
return 'mvn test-compile org.pitest:pitest-maven:mutationCoverage';
|
|
79
|
+
case 'cargo-mutants':
|
|
80
|
+
return 'cargo mutants';
|
|
81
|
+
case 'gremlins':
|
|
82
|
+
return 'gremlins unleash ./...';
|
|
83
|
+
case 'stryker4s':
|
|
84
|
+
return 'sbt stryker';
|
|
85
|
+
case 'stryker-dotnet':
|
|
86
|
+
return 'dotnet stryker';
|
|
87
|
+
default:
|
|
88
|
+
return 'npx stryker run';
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Public API
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Detect project stack and generate the appropriate mutation testing config.
|
|
96
|
+
*/
|
|
97
|
+
export async function generateMutationConfig(projectPath) {
|
|
98
|
+
const stack = await detectStack(projectPath);
|
|
99
|
+
const tool = getMutationTool(stack.language);
|
|
100
|
+
const mutationConfig = buildMutationConfig(tool, stack.language);
|
|
101
|
+
const configFileName = resolveConfigFileName(tool);
|
|
102
|
+
const ciStep = buildCiStep(tool);
|
|
103
|
+
return {
|
|
104
|
+
configFileName,
|
|
105
|
+
configContent: mutationConfig.configFile,
|
|
106
|
+
ciStep,
|
|
107
|
+
framework: stack.testFramework,
|
|
108
|
+
tool,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=mutation-config-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutation-config-generator.js","sourceRoot":"","sources":["../../src/engine/mutation-config-generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ProductInsightsReport, ProductInsightsReport_Report } from '../../types/product-intelligence.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generates a product insights report by querying Supabase telemetry_events.
|
|
4
|
+
* Throws if the HTTP request fails — caller should handle and return isError.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateProductInsights(report: ProductInsightsReport_Report, periodDays?: number): Promise<ProductInsightsReport>;
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/product-intelligence/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EACrB,4BAA4B,EAO7B,MAAM,qCAAqC,CAAC;AAkN7C;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,4BAA4B,EACpC,UAAU,SAAK,GACd,OAAO,CAAC,qBAAqB,CAAC,CAiChC"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
// engine/product-intelligence/index.ts — SPEC-328: Product Intelligence Layer engine.
|
|
2
|
+
// Queries Supabase telemetry_events to generate product insights reports.
|
|
3
|
+
// Uses the same auth pattern as telemetry-client.ts (fire-and-forget-friendly).
|
|
4
|
+
import { PLANU_VERSION } from '../../config/version.js';
|
|
5
|
+
const SUPABASE_URL = process.env.PLANU_SUPABASE_URL ?? 'https://canusqigtzldstnjddio.supabase.co';
|
|
6
|
+
const SUPABASE_KEY = process.env.PLANU_SUPABASE_KEY ??
|
|
7
|
+
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNhbnVzcWlndHpsZHN0bmpkZGlvIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzI3NTk2MjgsImV4cCI6MjA4ODMzNTYyOH0.Thw1Xgf9_iabOD75J00u35d2k5NsIpUBU9PrqOShxMU';
|
|
8
|
+
const TELEMETRY_TABLE = `${SUPABASE_URL}/rest/v1/telemetry_events`;
|
|
9
|
+
/** Core tools expected to be active — used for dead-tool detection. */
|
|
10
|
+
const KNOWN_CORE_TOOLS = [
|
|
11
|
+
'create_spec',
|
|
12
|
+
'list_specs',
|
|
13
|
+
'update_status',
|
|
14
|
+
'validate',
|
|
15
|
+
'estimate',
|
|
16
|
+
'init_project',
|
|
17
|
+
'suggest_stack',
|
|
18
|
+
'generate_tests',
|
|
19
|
+
'generate_docs',
|
|
20
|
+
'challenge_spec',
|
|
21
|
+
'check_readiness',
|
|
22
|
+
'decompose_spec',
|
|
23
|
+
'scan_project',
|
|
24
|
+
'manage_git',
|
|
25
|
+
'product_insights',
|
|
26
|
+
];
|
|
27
|
+
function strProp(props, key) {
|
|
28
|
+
const val = props[key];
|
|
29
|
+
return typeof val === 'string' ? val : '';
|
|
30
|
+
}
|
|
31
|
+
async function fetchEvents(sinceIso) {
|
|
32
|
+
const url = new URL(TELEMETRY_TABLE);
|
|
33
|
+
url.searchParams.set('created_at', `gte.${sinceIso}`);
|
|
34
|
+
url.searchParams.set('select', 'event_name,properties,installation_id,created_at');
|
|
35
|
+
url.searchParams.set('limit', '50000');
|
|
36
|
+
const res = await fetch(url.toString(), {
|
|
37
|
+
headers: {
|
|
38
|
+
apikey: SUPABASE_KEY,
|
|
39
|
+
Authorization: `Bearer ${SUPABASE_KEY}`,
|
|
40
|
+
Accept: 'application/json',
|
|
41
|
+
},
|
|
42
|
+
signal: AbortSignal.timeout(15_000),
|
|
43
|
+
});
|
|
44
|
+
if (!res.ok) {
|
|
45
|
+
throw new Error(`Supabase query failed: ${res.status} ${res.statusText}`);
|
|
46
|
+
}
|
|
47
|
+
return (await res.json());
|
|
48
|
+
}
|
|
49
|
+
function buildAdoption(rows, sinceIso) {
|
|
50
|
+
const map = new Map();
|
|
51
|
+
for (const row of rows) {
|
|
52
|
+
const tool = strProp(row.properties, 'tool');
|
|
53
|
+
if (!tool) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const event = row.event_name;
|
|
57
|
+
if (!['tool_used', 'tool_error', 'tool_blocked'].includes(event)) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
let stats = map.get(tool);
|
|
61
|
+
if (stats === undefined) {
|
|
62
|
+
stats = { total: 0, installs: new Set(), errors: 0, blocked: 0, lastSeen: sinceIso };
|
|
63
|
+
map.set(tool, stats);
|
|
64
|
+
}
|
|
65
|
+
stats.total += 1;
|
|
66
|
+
stats.installs.add(row.installation_id);
|
|
67
|
+
if (event === 'tool_error') {
|
|
68
|
+
stats.errors += 1;
|
|
69
|
+
}
|
|
70
|
+
if (event === 'tool_blocked') {
|
|
71
|
+
stats.blocked += 1;
|
|
72
|
+
}
|
|
73
|
+
if (row.created_at > stats.lastSeen) {
|
|
74
|
+
stats.lastSeen = row.created_at;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Array.from(map.entries()).map(([tool, s]) => ({
|
|
78
|
+
tool,
|
|
79
|
+
totalCalls: s.total,
|
|
80
|
+
uniqueInstalls: s.installs.size,
|
|
81
|
+
errorRate: s.total > 0 ? s.errors / s.total : 0,
|
|
82
|
+
blockedRate: s.total > 0 ? s.blocked / s.total : 0,
|
|
83
|
+
lastSeenAt: s.lastSeen,
|
|
84
|
+
trend: s.total === 1 ? 'new' : 'stable',
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
function buildFriction(rows) {
|
|
88
|
+
const map = new Map();
|
|
89
|
+
for (const row of rows) {
|
|
90
|
+
const tool = strProp(row.properties, 'tool');
|
|
91
|
+
if (!tool) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
if (!['tool_used', 'tool_blocked'].includes(row.event_name)) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
let s = map.get(tool);
|
|
98
|
+
if (s === undefined) {
|
|
99
|
+
s = { blocked: 0, total: 0, messages: [] };
|
|
100
|
+
map.set(tool, s);
|
|
101
|
+
}
|
|
102
|
+
s.total += 1;
|
|
103
|
+
if (row.event_name === 'tool_blocked') {
|
|
104
|
+
s.blocked += 1;
|
|
105
|
+
const msg = strProp(row.properties, 'message');
|
|
106
|
+
if (msg) {
|
|
107
|
+
s.messages.push(msg);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return Array.from(map.entries())
|
|
112
|
+
.filter(([, s]) => s.blocked > 0)
|
|
113
|
+
.map(([tool, s]) => {
|
|
114
|
+
const msgCounts = new Map();
|
|
115
|
+
for (const m of s.messages) {
|
|
116
|
+
msgCounts.set(m, (msgCounts.get(m) ?? 0) + 1);
|
|
117
|
+
}
|
|
118
|
+
let topMessage = null;
|
|
119
|
+
let maxCount = 0;
|
|
120
|
+
for (const [m, c] of msgCounts.entries()) {
|
|
121
|
+
if (c > maxCount) {
|
|
122
|
+
maxCount = c;
|
|
123
|
+
topMessage = m;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
tool,
|
|
128
|
+
blockedCount: s.blocked,
|
|
129
|
+
totalCalls: s.total,
|
|
130
|
+
blockedRate: s.total > 0 ? s.blocked / s.total : 0,
|
|
131
|
+
topMessage,
|
|
132
|
+
};
|
|
133
|
+
})
|
|
134
|
+
.sort((a, b) => b.blockedRate - a.blockedRate);
|
|
135
|
+
}
|
|
136
|
+
function buildVersionAdoption(rows) {
|
|
137
|
+
const map = new Map();
|
|
138
|
+
for (const row of rows) {
|
|
139
|
+
const ver = strProp(row.properties, 'planVersion');
|
|
140
|
+
if (!ver) {
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
let installs = map.get(ver);
|
|
144
|
+
if (installs === undefined) {
|
|
145
|
+
installs = new Set();
|
|
146
|
+
map.set(ver, installs);
|
|
147
|
+
}
|
|
148
|
+
installs.add(row.installation_id);
|
|
149
|
+
}
|
|
150
|
+
const total = Array.from(map.values()).reduce((sum, s) => sum + s.size, 0);
|
|
151
|
+
return Array.from(map.entries())
|
|
152
|
+
.map(([planVersion, installs]) => ({
|
|
153
|
+
planVersion,
|
|
154
|
+
userCount: installs.size,
|
|
155
|
+
pct: total > 0 ? installs.size / total : 0,
|
|
156
|
+
isLatest: planVersion === PLANU_VERSION,
|
|
157
|
+
}))
|
|
158
|
+
.sort((a, b) => b.userCount - a.userCount);
|
|
159
|
+
}
|
|
160
|
+
function buildDeadTools(adoption, sinceIso) {
|
|
161
|
+
const recentlyActive = new Set(adoption.filter((r) => r.lastSeenAt >= sinceIso).map((r) => r.tool));
|
|
162
|
+
return KNOWN_CORE_TOOLS.filter((t) => !recentlyActive.has(t));
|
|
163
|
+
}
|
|
164
|
+
function buildSummary(report) {
|
|
165
|
+
const topTool = report.adoption[0];
|
|
166
|
+
const topFriction = report.frictionPoints[0];
|
|
167
|
+
const lines = [
|
|
168
|
+
`Period: ${report.periodDays}d | Events: ${report.totalEvents} | Installs: ${report.uniqueInstalls}`,
|
|
169
|
+
];
|
|
170
|
+
if (topTool !== undefined) {
|
|
171
|
+
lines.push(`Most used: ${topTool.tool} (${topTool.totalCalls} calls)`);
|
|
172
|
+
}
|
|
173
|
+
if (topFriction !== undefined) {
|
|
174
|
+
lines.push(`Top friction: ${topFriction.tool} (${(topFriction.blockedRate * 100).toFixed(1)}% blocked)`);
|
|
175
|
+
}
|
|
176
|
+
if (report.deadTools.length > 0) {
|
|
177
|
+
lines.push(`Dead tools: ${report.deadTools.join(', ')}`);
|
|
178
|
+
}
|
|
179
|
+
return lines.join(' | ');
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Generates a product insights report by querying Supabase telemetry_events.
|
|
183
|
+
* Throws if the HTTP request fails — caller should handle and return isError.
|
|
184
|
+
*/
|
|
185
|
+
export async function generateProductInsights(report, periodDays = 30) {
|
|
186
|
+
const since = new Date(Date.now() - periodDays * 24 * 60 * 60 * 1000);
|
|
187
|
+
const sinceIso = since.toISOString();
|
|
188
|
+
const rows = await fetchEvents(sinceIso);
|
|
189
|
+
const uniqueInstalls = new Set(rows.map((r) => r.installation_id)).size;
|
|
190
|
+
const adoption = report === 'friction' ? [] : buildAdoption(rows, sinceIso);
|
|
191
|
+
const frictionPoints = report === 'versions' || report === 'dead_tools' ? [] : buildFriction(rows);
|
|
192
|
+
const versionAdoption = report === 'adoption' || report === 'friction' || report === 'dead_tools'
|
|
193
|
+
? []
|
|
194
|
+
: buildVersionAdoption(rows);
|
|
195
|
+
const baseAdoption = adoption.length > 0 ? adoption : buildAdoption(rows, sinceIso);
|
|
196
|
+
const deadTools = report === 'adoption' || report === 'friction' || report === 'versions'
|
|
197
|
+
? []
|
|
198
|
+
: buildDeadTools(baseAdoption, sinceIso);
|
|
199
|
+
const partial = {
|
|
200
|
+
generatedAt: new Date().toISOString(),
|
|
201
|
+
periodDays,
|
|
202
|
+
totalEvents: rows.length,
|
|
203
|
+
uniqueInstalls,
|
|
204
|
+
adoption,
|
|
205
|
+
frictionPoints,
|
|
206
|
+
versionAdoption,
|
|
207
|
+
deadTools,
|
|
208
|
+
};
|
|
209
|
+
return { ...partial, summary: buildSummary(partial) };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/product-intelligence/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TddScaffoldResult } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a TDD scaffold from a spec's acceptance criteria.
|
|
4
|
+
* Returns paths and content for a failing test file and an impl skeleton.
|
|
5
|
+
*/
|
|
6
|
+
export declare function generateTddScaffold(specPath: string, projectPath: string): Promise<TddScaffoldResult>;
|
|
7
|
+
//# sourceMappingURL=tdd-scaffold-generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tdd-scaffold-generator.d.ts","sourceRoot":"","sources":["../../src/engine/tdd-scaffold-generator.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,iBAAiB,EAAiC,MAAM,mBAAmB,CAAC;AAiO1F;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,iBAAiB,CAAC,CA4C5B"}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
// engine/tdd-scaffold-generator.ts — SPEC-323
|
|
2
|
+
// Generates TDD scaffold (failing test stubs + impl skeleton) from spec ACs.
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Internal helpers
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
/** Extract checkbox ACs from spec.md content: lines starting with "- [ ]". */
|
|
9
|
+
function extractAcceptanceCriteria(specContent) {
|
|
10
|
+
const lines = specContent.split('\n');
|
|
11
|
+
const criteria = [];
|
|
12
|
+
for (const line of lines) {
|
|
13
|
+
const match = /^\s*-\s*\[\s*\]\s+(.+)$/.exec(line);
|
|
14
|
+
if (match?.[1]) {
|
|
15
|
+
criteria.push(match[1].trim());
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return criteria;
|
|
19
|
+
}
|
|
20
|
+
/** Convert a criterion string to a camelCase test name. */
|
|
21
|
+
function criterionToTestName(criterion) {
|
|
22
|
+
const cleaned = criterion
|
|
23
|
+
.replace(/[^\w\s]/g, ' ')
|
|
24
|
+
.replace(/\s+/g, ' ')
|
|
25
|
+
.trim()
|
|
26
|
+
.toLowerCase();
|
|
27
|
+
const words = cleaned.split(' ').filter(Boolean);
|
|
28
|
+
if (words.length === 0) {
|
|
29
|
+
return 'criterion';
|
|
30
|
+
}
|
|
31
|
+
const [first, ...rest] = words;
|
|
32
|
+
return ((first ?? 'criterion') + rest.map((w) => (w[0]?.toUpperCase() ?? '') + w.slice(1)).join(''));
|
|
33
|
+
}
|
|
34
|
+
/** Detect test framework from package.json devDependencies / dependencies. */
|
|
35
|
+
async function detectFramework(projectPath) {
|
|
36
|
+
const pkgPath = join(projectPath, 'package.json');
|
|
37
|
+
try {
|
|
38
|
+
const raw = await readFile(pkgPath, 'utf8');
|
|
39
|
+
const pkg = JSON.parse(raw);
|
|
40
|
+
const deps = {
|
|
41
|
+
...(pkg.dependencies ?? {}),
|
|
42
|
+
...(pkg.devDependencies ?? {}),
|
|
43
|
+
};
|
|
44
|
+
if ('vitest' in deps) {
|
|
45
|
+
return 'vitest';
|
|
46
|
+
}
|
|
47
|
+
if ('jest' in deps) {
|
|
48
|
+
return 'jest';
|
|
49
|
+
}
|
|
50
|
+
if ('mocha' in deps) {
|
|
51
|
+
return 'mocha';
|
|
52
|
+
}
|
|
53
|
+
return 'unknown';
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Check for Python or Java markers
|
|
57
|
+
const setup = await readFile(join(projectPath, 'setup.py'), 'utf8').catch(() => null);
|
|
58
|
+
if (setup !== null) {
|
|
59
|
+
return 'pytest';
|
|
60
|
+
}
|
|
61
|
+
const pom = await readFile(join(projectPath, 'pom.xml'), 'utf8').catch(() => null);
|
|
62
|
+
if (pom !== null) {
|
|
63
|
+
return 'junit';
|
|
64
|
+
}
|
|
65
|
+
return 'unknown';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Extract spec slug from path for naming generated files. */
|
|
69
|
+
function specSlugFromPath(specPath) {
|
|
70
|
+
const parts = specPath.replace(/\\/g, '/').split('/');
|
|
71
|
+
// Try to find SPEC-XXX pattern in path
|
|
72
|
+
for (const part of [...parts].reverse()) {
|
|
73
|
+
if (/SPEC-\d+/.test(part)) {
|
|
74
|
+
return part.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return 'spec-unknown';
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// Test content builders
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
function buildVitestContent(stubs) {
|
|
83
|
+
const lines = [
|
|
84
|
+
"import { describe, it, expect } from 'vitest';",
|
|
85
|
+
'',
|
|
86
|
+
'// TDD scaffold — generated by Planu (SPEC-323)',
|
|
87
|
+
'// Each test is a FAILING STUB. Implement the production code to make them pass.',
|
|
88
|
+
'',
|
|
89
|
+
'describe("Acceptance Criteria", () => {',
|
|
90
|
+
];
|
|
91
|
+
for (const stub of stubs) {
|
|
92
|
+
lines.push(` it("should ${stub.testName}", () => {`);
|
|
93
|
+
lines.push(` // AC: ${stub.criterion}`);
|
|
94
|
+
lines.push(' expect.fail("Not implemented — write the implementation first");');
|
|
95
|
+
lines.push(' });');
|
|
96
|
+
lines.push('');
|
|
97
|
+
}
|
|
98
|
+
lines.push('});');
|
|
99
|
+
return lines.join('\n');
|
|
100
|
+
}
|
|
101
|
+
function buildJestContent(stubs) {
|
|
102
|
+
const lines = [
|
|
103
|
+
'// TDD scaffold — generated by Planu (SPEC-323)',
|
|
104
|
+
'// Each test is a FAILING STUB. Implement the production code to make them pass.',
|
|
105
|
+
'',
|
|
106
|
+
'describe("Acceptance Criteria", () => {',
|
|
107
|
+
];
|
|
108
|
+
for (const stub of stubs) {
|
|
109
|
+
lines.push(` it("should ${stub.testName}", () => {`);
|
|
110
|
+
lines.push(` // AC: ${stub.criterion}`);
|
|
111
|
+
lines.push(' throw new Error("Not implemented — write the implementation first");');
|
|
112
|
+
lines.push(' });');
|
|
113
|
+
lines.push('');
|
|
114
|
+
}
|
|
115
|
+
lines.push('});');
|
|
116
|
+
return lines.join('\n');
|
|
117
|
+
}
|
|
118
|
+
function buildMochaContent(stubs) {
|
|
119
|
+
const lines = [
|
|
120
|
+
"import assert from 'node:assert';",
|
|
121
|
+
'',
|
|
122
|
+
'// TDD scaffold — generated by Planu (SPEC-323)',
|
|
123
|
+
'',
|
|
124
|
+
'describe("Acceptance Criteria", function () {',
|
|
125
|
+
];
|
|
126
|
+
for (const stub of stubs) {
|
|
127
|
+
lines.push(` it("should ${stub.testName}", function () {`);
|
|
128
|
+
lines.push(` // AC: ${stub.criterion}`);
|
|
129
|
+
lines.push(' assert.fail("Not implemented — write the implementation first");');
|
|
130
|
+
lines.push(' });');
|
|
131
|
+
lines.push('');
|
|
132
|
+
}
|
|
133
|
+
lines.push('});');
|
|
134
|
+
return lines.join('\n');
|
|
135
|
+
}
|
|
136
|
+
function buildPytestContent(stubs) {
|
|
137
|
+
const lines = [
|
|
138
|
+
'# TDD scaffold — generated by Planu (SPEC-323)',
|
|
139
|
+
'# Each test is a FAILING STUB. Implement the production code to make them pass.',
|
|
140
|
+
'',
|
|
141
|
+
'import pytest',
|
|
142
|
+
'',
|
|
143
|
+
];
|
|
144
|
+
for (const stub of stubs) {
|
|
145
|
+
const fnName = stub.testName.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
146
|
+
lines.push(`def test_${fnName}():`);
|
|
147
|
+
lines.push(` # AC: ${stub.criterion}`);
|
|
148
|
+
lines.push(' raise NotImplementedError("Not implemented — write the implementation first")');
|
|
149
|
+
lines.push('');
|
|
150
|
+
}
|
|
151
|
+
return lines.join('\n');
|
|
152
|
+
}
|
|
153
|
+
function buildJunitContent(stubs) {
|
|
154
|
+
const lines = [
|
|
155
|
+
'// TDD scaffold — generated by Planu (SPEC-323)',
|
|
156
|
+
'import org.junit.jupiter.api.Test;',
|
|
157
|
+
'import static org.junit.jupiter.api.Assertions.*;',
|
|
158
|
+
'',
|
|
159
|
+
'class AcceptanceCriteriaTest {',
|
|
160
|
+
];
|
|
161
|
+
for (const stub of stubs) {
|
|
162
|
+
const method = stub.testName.replace(/[^a-zA-Z0-9]/g, '');
|
|
163
|
+
const first = method[0]?.toUpperCase() ?? '';
|
|
164
|
+
const rest = method.slice(1);
|
|
165
|
+
lines.push(' @Test');
|
|
166
|
+
lines.push(` void should${first}${rest}() {`);
|
|
167
|
+
lines.push(` // AC: ${stub.criterion}`);
|
|
168
|
+
lines.push(' fail("Not implemented — write the implementation first");');
|
|
169
|
+
lines.push(' }');
|
|
170
|
+
lines.push('');
|
|
171
|
+
}
|
|
172
|
+
lines.push('}');
|
|
173
|
+
return lines.join('\n');
|
|
174
|
+
}
|
|
175
|
+
function buildTestContent(stubs, framework) {
|
|
176
|
+
switch (framework) {
|
|
177
|
+
case 'vitest':
|
|
178
|
+
return buildVitestContent(stubs);
|
|
179
|
+
case 'jest':
|
|
180
|
+
return buildJestContent(stubs);
|
|
181
|
+
case 'mocha':
|
|
182
|
+
return buildMochaContent(stubs);
|
|
183
|
+
case 'pytest':
|
|
184
|
+
return buildPytestContent(stubs);
|
|
185
|
+
case 'junit':
|
|
186
|
+
return buildJunitContent(stubs);
|
|
187
|
+
case 'unknown':
|
|
188
|
+
return buildVitestContent(stubs);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// ---------------------------------------------------------------------------
|
|
192
|
+
// Implementation skeleton builder
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
function buildImplSkeleton(stubs, slug) {
|
|
195
|
+
const lines = [
|
|
196
|
+
`// ${slug}.ts — implementation skeleton generated by Planu (SPEC-323)`,
|
|
197
|
+
'// TODO: implement each function to make the TDD stubs pass.',
|
|
198
|
+
'',
|
|
199
|
+
];
|
|
200
|
+
for (const stub of stubs) {
|
|
201
|
+
lines.push(`// AC: ${stub.criterion}`);
|
|
202
|
+
lines.push(`export function ${stub.testName}(): void {`);
|
|
203
|
+
lines.push(' throw new Error("Not implemented");');
|
|
204
|
+
lines.push('}');
|
|
205
|
+
lines.push('');
|
|
206
|
+
}
|
|
207
|
+
return lines.join('\n');
|
|
208
|
+
}
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Public API
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
/**
|
|
213
|
+
* Generate a TDD scaffold from a spec's acceptance criteria.
|
|
214
|
+
* Returns paths and content for a failing test file and an impl skeleton.
|
|
215
|
+
*/
|
|
216
|
+
export async function generateTddScaffold(specPath, projectPath) {
|
|
217
|
+
const specContent = await readFile(join(specPath, 'spec.md'), 'utf8').catch(() => readFile(specPath, 'utf8'));
|
|
218
|
+
const criteria = extractAcceptanceCriteria(specContent);
|
|
219
|
+
const framework = await detectFramework(projectPath);
|
|
220
|
+
const slug = specSlugFromPath(specPath);
|
|
221
|
+
const stubs = criteria.map((criterion) => ({
|
|
222
|
+
criterion,
|
|
223
|
+
testName: criterionToTestName(criterion),
|
|
224
|
+
framework,
|
|
225
|
+
}));
|
|
226
|
+
const ext = framework === 'pytest' ? 'py' : framework === 'junit' ? 'java' : 'ts';
|
|
227
|
+
const testExt = framework === 'pytest' ? '_test.py' : framework === 'junit' ? 'Test.java' : '.test.ts';
|
|
228
|
+
const testDir = framework === 'pytest' ? 'tests' : framework === 'junit' ? 'src/test' : 'tests';
|
|
229
|
+
const testFilePath = join(projectPath, testDir, `${slug}${testExt}`);
|
|
230
|
+
const implFilePath = join(projectPath, 'src', `${slug}.${ext}`);
|
|
231
|
+
const testContent = buildTestContent(stubs, framework);
|
|
232
|
+
const implContent = buildImplSkeleton(stubs, slug);
|
|
233
|
+
const instructions = [
|
|
234
|
+
`Test file: ${testFilePath}`,
|
|
235
|
+
`Implementation skeleton: ${implFilePath}`,
|
|
236
|
+
`Framework detected: ${framework}`,
|
|
237
|
+
`Generated ${stubs.length} failing stub(s) from acceptance criteria.`,
|
|
238
|
+
'Run the tests — they should ALL fail (red phase).',
|
|
239
|
+
'Implement each function in the skeleton until all tests pass (green phase).',
|
|
240
|
+
'Refactor for clarity while keeping all tests green.',
|
|
241
|
+
];
|
|
242
|
+
return {
|
|
243
|
+
testFilePath,
|
|
244
|
+
implFilePath,
|
|
245
|
+
testContent,
|
|
246
|
+
implContent,
|
|
247
|
+
stubs,
|
|
248
|
+
instructions,
|
|
249
|
+
framework,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=tdd-scaffold-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tdd-scaffold-generator.js","sourceRoot":"","sources":["../../src/engine/tdd-scaffold-generator.ts"],"names":[],"mappings":"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"}
|