@planu/cli 1.0.11 → 1.1.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.
Files changed (94) hide show
  1. package/dist/config/domain-bundles.json +134 -0
  2. package/dist/config/license-plans.json +7 -1
  3. package/dist/engine/bundle-installer.d.ts +24 -0
  4. package/dist/engine/bundle-installer.d.ts.map +1 -0
  5. package/dist/engine/bundle-installer.js +131 -0
  6. package/dist/engine/bundle-installer.js.map +1 -0
  7. package/dist/engine/git-hook-injector.d.ts +5 -0
  8. package/dist/engine/git-hook-injector.d.ts.map +1 -0
  9. package/dist/engine/git-hook-injector.js +86 -0
  10. package/dist/engine/git-hook-injector.js.map +1 -0
  11. package/dist/engine/merge-risk-assessor/analyzers.d.ts +22 -0
  12. package/dist/engine/merge-risk-assessor/analyzers.d.ts.map +1 -0
  13. package/dist/engine/merge-risk-assessor/analyzers.js +150 -0
  14. package/dist/engine/merge-risk-assessor/analyzers.js.map +1 -0
  15. package/dist/engine/merge-risk-assessor/git-diff-parser.d.ts +16 -0
  16. package/dist/engine/merge-risk-assessor/git-diff-parser.d.ts.map +1 -0
  17. package/dist/engine/merge-risk-assessor/git-diff-parser.js +48 -0
  18. package/dist/engine/merge-risk-assessor/git-diff-parser.js.map +1 -0
  19. package/dist/engine/merge-risk-assessor/index.d.ts +7 -0
  20. package/dist/engine/merge-risk-assessor/index.d.ts.map +1 -0
  21. package/dist/engine/merge-risk-assessor/index.js +98 -0
  22. package/dist/engine/merge-risk-assessor/index.js.map +1 -0
  23. package/dist/engine/spec-prompt-generator.d.ts +12 -0
  24. package/dist/engine/spec-prompt-generator.d.ts.map +1 -0
  25. package/dist/engine/spec-prompt-generator.js +69 -0
  26. package/dist/engine/spec-prompt-generator.js.map +1 -0
  27. package/dist/engine/telemetry/health-checker.d.ts +5 -0
  28. package/dist/engine/telemetry/health-checker.d.ts.map +1 -0
  29. package/dist/engine/telemetry/health-checker.js +297 -0
  30. package/dist/engine/telemetry/health-checker.js.map +1 -0
  31. package/dist/engine/telemetry/index.d.ts +1 -0
  32. package/dist/engine/telemetry/index.d.ts.map +1 -1
  33. package/dist/engine/telemetry/index.js +1 -0
  34. package/dist/engine/telemetry/index.js.map +1 -1
  35. package/dist/index.js +12 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/tools/domain-bundle-handler.d.ts +37 -0
  38. package/dist/tools/domain-bundle-handler.d.ts.map +1 -0
  39. package/dist/tools/domain-bundle-handler.js +84 -0
  40. package/dist/tools/domain-bundle-handler.js.map +1 -0
  41. package/dist/tools/init-project/handler.d.ts.map +1 -1
  42. package/dist/tools/init-project/handler.js +2 -1
  43. package/dist/tools/init-project/handler.js.map +1 -1
  44. package/dist/tools/init-project/scaffold-writer.d.ts +1 -0
  45. package/dist/tools/init-project/scaffold-writer.d.ts.map +1 -1
  46. package/dist/tools/init-project/scaffold-writer.js +11 -0
  47. package/dist/tools/init-project/scaffold-writer.js.map +1 -1
  48. package/dist/tools/merge-risk-handler.d.ts +3 -0
  49. package/dist/tools/merge-risk-handler.d.ts.map +1 -0
  50. package/dist/tools/merge-risk-handler.js +83 -0
  51. package/dist/tools/merge-risk-handler.js.map +1 -0
  52. package/dist/tools/register-domain-bundle-tools.d.ts +3 -0
  53. package/dist/tools/register-domain-bundle-tools.d.ts.map +1 -0
  54. package/dist/tools/register-domain-bundle-tools.js +27 -0
  55. package/dist/tools/register-domain-bundle-tools.js.map +1 -0
  56. package/dist/tools/register-merge-risk-tools.d.ts +5 -0
  57. package/dist/tools/register-merge-risk-tools.d.ts.map +1 -0
  58. package/dist/tools/register-merge-risk-tools.js +6 -0
  59. package/dist/tools/register-merge-risk-tools.js.map +1 -0
  60. package/dist/tools/register-spec-prompt-tools.d.ts +3 -0
  61. package/dist/tools/register-spec-prompt-tools.d.ts.map +1 -0
  62. package/dist/tools/register-spec-prompt-tools.js +5 -0
  63. package/dist/tools/register-spec-prompt-tools.js.map +1 -0
  64. package/dist/tools/register-telemetry-health-tools.d.ts +3 -0
  65. package/dist/tools/register-telemetry-health-tools.d.ts.map +1 -0
  66. package/dist/tools/register-telemetry-health-tools.js +27 -0
  67. package/dist/tools/register-telemetry-health-tools.js.map +1 -0
  68. package/dist/tools/spec-prompt-handler.d.ts +5 -0
  69. package/dist/tools/spec-prompt-handler.d.ts.map +1 -0
  70. package/dist/tools/spec-prompt-handler.js +142 -0
  71. package/dist/tools/spec-prompt-handler.js.map +1 -0
  72. package/dist/tools/telemetry-health-handler.d.ts +3 -0
  73. package/dist/tools/telemetry-health-handler.d.ts.map +1 -0
  74. package/dist/tools/telemetry-health-handler.js +49 -0
  75. package/dist/tools/telemetry-health-handler.js.map +1 -0
  76. package/dist/types/git.d.ts +58 -0
  77. package/dist/types/git.d.ts.map +1 -1
  78. package/dist/types/mcp.d.ts +29 -0
  79. package/dist/types/mcp.d.ts.map +1 -1
  80. package/dist/types/project/planu-config.d.ts +2 -0
  81. package/dist/types/project/planu-config.d.ts.map +1 -1
  82. package/dist/types/telemetry.d.ts +15 -0
  83. package/dist/types/telemetry.d.ts.map +1 -1
  84. package/dist/types/tooling/bundles.d.ts +34 -0
  85. package/dist/types/tooling/bundles.d.ts.map +1 -0
  86. package/dist/types/tooling/bundles.js +3 -0
  87. package/dist/types/tooling/bundles.js.map +1 -0
  88. package/dist/types/tooling/index.d.ts +1 -0
  89. package/dist/types/tooling/index.d.ts.map +1 -1
  90. package/dist/types/tooling.d.ts +1 -1
  91. package/dist/types/tooling.d.ts.map +1 -1
  92. package/package.json +1 -1
  93. package/src/config/domain-bundles.json +134 -0
  94. package/src/config/license-plans.json +7 -1
@@ -0,0 +1,48 @@
1
+ // Planu — git diff parser for merge risk assessor
2
+ import { execFile } from 'node:child_process';
3
+ import { promisify } from 'node:util';
4
+ const execFileAsync = promisify(execFile);
5
+ /**
6
+ * Runs `git diff --stat {baseBranch}...{branch}` and parses the output.
7
+ * Uses execFile (not exec) to prevent shell injection.
8
+ */
9
+ export async function getDiffStats(projectPath, branch, baseBranch) {
10
+ const { stdout } = await execFileAsync('git', ['diff', '--stat', `${baseBranch}...${branch}`], { cwd: projectPath });
11
+ return parseDiffStatOutput(stdout);
12
+ }
13
+ /**
14
+ * Parses the output of `git diff --stat` into structured stats.
15
+ * Example output:
16
+ * src/foo.ts | 10 +++--
17
+ * src/bar.ts | 4 +
18
+ * 2 files changed, 11 insertions(+), 4 deletions(-)
19
+ */
20
+ export function parseDiffStatOutput(output) {
21
+ const lines = output.trim().split('\n').filter(Boolean);
22
+ if (lines.length === 0) {
23
+ return { filesChanged: 0, linesAdded: 0, linesRemoved: 0, files: [] };
24
+ }
25
+ const files = [];
26
+ for (const line of lines) {
27
+ // File lines contain a pipe character
28
+ if (line.includes('|')) {
29
+ const filePart = line.split('|')[0];
30
+ if (filePart !== undefined) {
31
+ const fileName = filePart.trim();
32
+ if (fileName) {
33
+ files.push(fileName);
34
+ }
35
+ }
36
+ }
37
+ }
38
+ // Summary line: "N files changed, X insertions(+), Y deletions(-)"
39
+ const summaryLine = lines[lines.length - 1] ?? '';
40
+ const filesMatch = /(\d+) files? changed/.exec(summaryLine);
41
+ const insertionsMatch = /(\d+) insertions?/.exec(summaryLine);
42
+ const deletionsMatch = /(\d+) deletions?/.exec(summaryLine);
43
+ const filesChanged = filesMatch?.[1] ? parseInt(filesMatch[1], 10) : files.length;
44
+ const linesAdded = insertionsMatch?.[1] ? parseInt(insertionsMatch[1], 10) : 0;
45
+ const linesRemoved = deletionsMatch?.[1] ? parseInt(deletionsMatch[1], 10) : 0;
46
+ return { filesChanged, linesAdded, linesRemoved, files };
47
+ }
48
+ //# sourceMappingURL=git-diff-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-diff-parser.js","sourceRoot":"","sources":["../../../src/engine/merge-risk-assessor/git-diff-parser.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAKtC,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAmB,EACnB,MAAc,EACd,UAAkB;IAElB,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,aAAa,CACpC,KAAK,EACL,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,MAAM,MAAM,EAAE,CAAC,EAC/C,EAAE,GAAG,EAAE,WAAW,EAAE,CACrB,CAAC;IAEF,OAAO,mBAAmB,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAc;IAChD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAExD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,EAAE,YAAY,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACxE,CAAC;IAED,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,sCAAsC;QACtC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC3B,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACjC,IAAI,QAAQ,EAAE,CAAC;oBACb,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,mEAAmE;IACnE,MAAM,WAAW,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,sBAAsB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC5D,MAAM,eAAe,GAAG,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAE5D,MAAM,YAAY,GAAG,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC;IAClF,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAG,cAAc,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE/E,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { MergeRiskResult, AssessMergeRiskOptions } from '../../types/index.js';
2
+ /**
3
+ * Main orchestrator: runs all analyzers, computes weighted risk score,
4
+ * and returns a structured MergeRiskResult.
5
+ */
6
+ export declare function assessMergeRisk(projectPath: string, options: AssessMergeRiskOptions): Promise<MergeRiskResult>;
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/merge-risk-assessor/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,eAAe,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAyDnG;;;GAGG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,eAAe,CAAC,CAyE1B"}
@@ -0,0 +1,98 @@
1
+ import { getDiffStats } from './git-diff-parser.js';
2
+ import { analyzeSecuritySurface, analyzeCoverageDelta, analyzeBlastRadius, analyzeReversibility, analyzeSpecCompliance, } from './analyzers.js';
3
+ import { execFile } from 'node:child_process';
4
+ import { promisify } from 'node:util';
5
+ const execFileAsync = promisify(execFile);
6
+ async function getCurrentBranch(projectPath) {
7
+ const { stdout } = await execFileAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], {
8
+ cwd: projectPath,
9
+ });
10
+ return stdout.trim();
11
+ }
12
+ async function getDiff(projectPath, branch, baseBranch) {
13
+ const { stdout } = await execFileAsync('git', ['diff', `${baseBranch}...${branch}`], { cwd: projectPath });
14
+ return stdout;
15
+ }
16
+ function buildRecommendation(score) {
17
+ if (score <= 30) {
18
+ return 'auto-merge';
19
+ }
20
+ if (score <= 70) {
21
+ return 'human-review';
22
+ }
23
+ return 'block';
24
+ }
25
+ function buildHumanSummary(score, recommendation, topReason) {
26
+ const recommendationLabel = recommendation === 'auto-merge'
27
+ ? 'Safe to auto-merge'
28
+ : recommendation === 'human-review'
29
+ ? 'Human review required'
30
+ : 'Blocked — high risk';
31
+ return `Risk score ${score}/100 — ${recommendationLabel}. ${topReason}`;
32
+ }
33
+ /**
34
+ * Main orchestrator: runs all analyzers, computes weighted risk score,
35
+ * and returns a structured MergeRiskResult.
36
+ */
37
+ export async function assessMergeRisk(projectPath, options) {
38
+ const baseBranch = options.baseBranch ?? 'main';
39
+ const branch = options.branch ?? (await getCurrentBranch(projectPath));
40
+ const [diffStats, diff] = await Promise.all([
41
+ getDiffStats(projectPath, branch, baseBranch),
42
+ getDiff(projectPath, branch, baseBranch),
43
+ ]);
44
+ const { filesChanged, linesAdded, linesRemoved, files } = diffStats;
45
+ const securityResult = analyzeSecuritySurface(files, diff);
46
+ const coverageResult = analyzeCoverageDelta(linesAdded, files);
47
+ const blastResult = analyzeBlastRadius(filesChanged, files);
48
+ const reversibilityResult = analyzeReversibility(files, diff);
49
+ const complianceResult = analyzeSpecCompliance(files, options.context);
50
+ const breakdown = [
51
+ {
52
+ category: 'Security Surface',
53
+ score: securityResult.score,
54
+ weight: 0.3,
55
+ reason: securityResult.reason,
56
+ },
57
+ {
58
+ category: 'Coverage Delta',
59
+ score: coverageResult.score,
60
+ weight: 0.25,
61
+ reason: coverageResult.reason,
62
+ },
63
+ {
64
+ category: 'Blast Radius',
65
+ score: blastResult.score,
66
+ weight: 0.2,
67
+ reason: blastResult.reason,
68
+ },
69
+ {
70
+ category: 'Reversibility',
71
+ score: reversibilityResult.score,
72
+ weight: 0.15,
73
+ reason: reversibilityResult.reason,
74
+ },
75
+ {
76
+ category: 'Spec Compliance',
77
+ score: complianceResult.score,
78
+ weight: 0.1,
79
+ reason: complianceResult.reason,
80
+ },
81
+ ];
82
+ const riskScore = Math.round(breakdown.reduce((acc, b) => acc + b.score * b.weight, 0));
83
+ const recommendation = buildRecommendation(riskScore);
84
+ // Top reason = highest weighted contribution
85
+ const topBreakdown = [...breakdown].sort((a, b) => b.score * b.weight - a.score * a.weight)[0];
86
+ const topReason = topBreakdown?.reason ?? 'No significant risk factors';
87
+ const humanSummary = buildHumanSummary(riskScore, recommendation, topReason);
88
+ return {
89
+ riskScore,
90
+ recommendation,
91
+ breakdown,
92
+ filesChanged,
93
+ linesAdded,
94
+ linesRemoved,
95
+ humanSummary,
96
+ };
97
+ }
98
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/merge-risk-assessor/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { SpecPromptDefinition, SpecPromptInput } from '../types/index.js';
2
+ /**
3
+ * Builds the prompt name from spec id and slug, truncated to MAX_NAME_LENGTH.
4
+ * Format: `planu:{id}-{slug}` (e.g. `planu:SPEC-342-export-pdf`)
5
+ */
6
+ export declare function buildPromptName(id: string, slug: string): string;
7
+ /**
8
+ * Generates a SpecPromptDefinition from a Planu spec.
9
+ * The resulting definition can be registered as an MCP prompt via server.prompt().
10
+ */
11
+ export declare function generatePromptFromSpec(spec: SpecPromptInput): SpecPromptDefinition;
12
+ //# sourceMappingURL=spec-prompt-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-prompt-generator.d.ts","sourceRoot":"","sources":["../../src/engine/spec-prompt-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AA8B/E;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhE;AAMD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,eAAe,GAAG,oBAAoB,CAgClF"}
@@ -0,0 +1,69 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Constants
3
+ // ---------------------------------------------------------------------------
4
+ const MAX_NAME_LENGTH = 64;
5
+ const CONTEXT_ARGUMENT = {
6
+ name: 'context',
7
+ description: 'Additional context for this spec execution',
8
+ required: false,
9
+ };
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ /**
14
+ * Sanitizes a string into a valid MCP prompt name segment.
15
+ * Lowercases, replaces non-alphanumeric chars with hyphens,
16
+ * collapses repeated hyphens, and strips leading/trailing hyphens.
17
+ */
18
+ function sanitizeSegment(value) {
19
+ return value
20
+ .toLowerCase()
21
+ .replace(/[^a-z0-9-]/g, '-')
22
+ .replace(/-{2,}/g, '-')
23
+ .replace(/^-+|-+$/g, '');
24
+ }
25
+ /**
26
+ * Builds the prompt name from spec id and slug, truncated to MAX_NAME_LENGTH.
27
+ * Format: `planu:{id}-{slug}` (e.g. `planu:SPEC-342-export-pdf`)
28
+ */
29
+ export function buildPromptName(id, slug) {
30
+ const idPart = sanitizeSegment(id);
31
+ const slugPart = sanitizeSegment(slug);
32
+ const full = `planu:${idPart}-${slugPart}`;
33
+ return full.slice(0, MAX_NAME_LENGTH);
34
+ }
35
+ // ---------------------------------------------------------------------------
36
+ // Public API
37
+ // ---------------------------------------------------------------------------
38
+ /**
39
+ * Generates a SpecPromptDefinition from a Planu spec.
40
+ * The resulting definition can be registered as an MCP prompt via server.prompt().
41
+ */
42
+ export function generatePromptFromSpec(spec) {
43
+ const name = buildPromptName(spec.id, spec.slug);
44
+ const firstCriterion = spec.criteria?.[0];
45
+ const descriptionHint = firstCriterion !== undefined ? ` | ${firstCriterion}` : '';
46
+ const description = `${spec.title}${descriptionHint}`;
47
+ const criteriaLines = spec.criteria !== undefined && spec.criteria.length > 0
48
+ ? spec.criteria.map((c, i) => `${i + 1}. ${c}`).join('\n')
49
+ : 'No acceptance criteria defined.';
50
+ const summarySection = spec.summary !== undefined ? `\n\nSummary: ${spec.summary}` : '';
51
+ const template = [
52
+ `You are implementing spec ${spec.id}: ${spec.title}.`,
53
+ summarySection,
54
+ '',
55
+ 'Acceptance criteria:',
56
+ criteriaLines,
57
+ '',
58
+ 'Follow each criterion exactly. When done, run validate to confirm compliance.',
59
+ ]
60
+ .join('\n')
61
+ .trim();
62
+ return {
63
+ name,
64
+ description,
65
+ arguments: [{ ...CONTEXT_ARGUMENT }],
66
+ template,
67
+ };
68
+ }
69
+ //# sourceMappingURL=spec-prompt-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-prompt-generator.js","sourceRoot":"","sources":["../../src/engine/spec-prompt-generator.ts"],"names":[],"mappings":"AAIA,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,gBAAgB,GAAG;IACvB,IAAI,EAAE,SAAS;IACf,WAAW,EAAE,4CAA4C;IACzD,QAAQ,EAAE,KAAK;CACP,CAAC;AAEX,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,OAAO,KAAK;SACT,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAAU,EAAE,IAAY;IACtD,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,CAAC,CAAC;IACnC,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,SAAS,MAAM,IAAI,QAAQ,EAAE,CAAC;IAC3C,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;AACxC,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAqB;IAC1D,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjD,MAAM,cAAc,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,eAAe,GAAG,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACnF,MAAM,WAAW,GAAG,GAAG,IAAI,CAAC,KAAK,GAAG,eAAe,EAAE,CAAC;IAEtD,MAAM,aAAa,GACjB,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QACrD,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QAC1D,CAAC,CAAC,iCAAiC,CAAC;IAExC,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,gBAAgB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAExF,MAAM,QAAQ,GAAG;QACf,6BAA6B,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,KAAK,GAAG;QACtD,cAAc;QACd,EAAE;QACF,sBAAsB;QACtB,aAAa;QACb,EAAE;QACF,+EAA+E;KAChF;SACE,IAAI,CAAC,IAAI,CAAC;SACV,IAAI,EAAE,CAAC;IAEV,OAAO;QACL,IAAI;QACJ,WAAW;QACX,SAAS,EAAE,CAAC,EAAE,GAAG,gBAAgB,EAAE,CAAC;QACpC,QAAQ;KACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { TelemetryHealthResult } from '../../types/index.js';
2
+ export declare function checkTelemetryHealth(projectPath: string, options?: {
3
+ sendTestEvent?: boolean;
4
+ }): Promise<TelemetryHealthResult>;
5
+ //# sourceMappingURL=health-checker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-checker.d.ts","sourceRoot":"","sources":["../../../src/engine/telemetry/health-checker.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAkB,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AA2SlF,wBAAsB,oBAAoB,CACxC,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAE,GACpC,OAAO,CAAC,qBAAqB,CAAC,CAkDhC"}
@@ -0,0 +1,297 @@
1
+ // engine/telemetry/health-checker.ts — SPEC-346: Diagnose why telemetry data is not reaching the dashboard.
2
+ import { readFile } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { readTelemetryConfig } from './telemetry-store.js';
5
+ import { sendTelemetryEvent } from './telemetry-client.js';
6
+ const NETWORK_TIMEOUT_MS = 5_000;
7
+ const RECENT_EVENT_THRESHOLD_DAYS = 7;
8
+ // ---------------------------------------------------------------------------
9
+ // Individual checks
10
+ // ---------------------------------------------------------------------------
11
+ async function checkConfigEnabled() {
12
+ const config = await readTelemetryConfig();
13
+ if (!config?.enabled) {
14
+ return {
15
+ check: {
16
+ name: 'config-enabled',
17
+ status: 'fail',
18
+ detail: 'Telemetry is disabled in ~/.planu/telemetry.json',
19
+ },
20
+ enabled: false,
21
+ };
22
+ }
23
+ return {
24
+ check: {
25
+ name: 'config-enabled',
26
+ status: 'ok',
27
+ detail: 'Telemetry is enabled',
28
+ },
29
+ enabled: true,
30
+ };
31
+ }
32
+ function checkEndpointConfigured(endpoint) {
33
+ if (!endpoint || endpoint.trim() === '') {
34
+ return {
35
+ name: 'endpoint-configured',
36
+ status: 'fail',
37
+ detail: 'No telemetry endpoint configured. Set PLANU_TELEMETRY_ENDPOINT env var.',
38
+ };
39
+ }
40
+ return {
41
+ name: 'endpoint-configured',
42
+ status: 'ok',
43
+ detail: `Endpoint: ${endpoint}`,
44
+ };
45
+ }
46
+ async function checkNetworkReachable(endpoint) {
47
+ if (!endpoint) {
48
+ return {
49
+ name: 'network-reachable',
50
+ status: 'skip',
51
+ detail: 'Skipped — no endpoint to test',
52
+ };
53
+ }
54
+ try {
55
+ const response = await fetch(endpoint, {
56
+ method: 'GET',
57
+ signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS),
58
+ });
59
+ if (response.ok || response.status < 500) {
60
+ return {
61
+ name: 'network-reachable',
62
+ status: 'ok',
63
+ detail: `Endpoint responded with HTTP ${response.status}`,
64
+ };
65
+ }
66
+ return {
67
+ name: 'network-reachable',
68
+ status: 'warn',
69
+ detail: `Endpoint returned HTTP ${response.status} — server may be experiencing issues`,
70
+ };
71
+ }
72
+ catch (err) {
73
+ const message = err instanceof Error ? err.message : String(err);
74
+ return {
75
+ name: 'network-reachable',
76
+ status: 'warn',
77
+ detail: `Could not reach endpoint: ${message}`,
78
+ };
79
+ }
80
+ }
81
+ async function checkLastEvent(projectPath) {
82
+ const candidates = [
83
+ join(projectPath, 'data', 'telemetry-events.json'),
84
+ join(projectPath, '.planu', 'telemetry-events.json'),
85
+ join(projectPath, 'data', 'telemetry.json'),
86
+ ];
87
+ for (const candidate of candidates) {
88
+ try {
89
+ const raw = await readFile(candidate, 'utf-8');
90
+ const parsed = JSON.parse(raw);
91
+ if (!Array.isArray(parsed) || parsed.length === 0) {
92
+ continue;
93
+ }
94
+ const last = parsed[parsed.length - 1];
95
+ const ts = typeof last.timestamp === 'string' ? last.timestamp : undefined;
96
+ if (!ts) {
97
+ return {
98
+ name: 'last-event',
99
+ status: 'warn',
100
+ detail: `Found event log at ${candidate} but last event has no timestamp`,
101
+ };
102
+ }
103
+ const daysAgo = (Date.now() - new Date(ts).getTime()) / (1000 * 60 * 60 * 24);
104
+ if (daysAgo > RECENT_EVENT_THRESHOLD_DAYS) {
105
+ return {
106
+ name: 'last-event',
107
+ status: 'warn',
108
+ detail: `Last event was ${Math.floor(daysAgo)} days ago (${ts})`,
109
+ };
110
+ }
111
+ return {
112
+ name: 'last-event',
113
+ status: 'ok',
114
+ detail: `Last event: ${ts} (${Math.floor(daysAgo)} days ago)`,
115
+ };
116
+ }
117
+ catch {
118
+ // try next candidate
119
+ }
120
+ }
121
+ return {
122
+ name: 'last-event',
123
+ status: 'warn',
124
+ detail: 'No event log found — no events have been sent yet',
125
+ };
126
+ }
127
+ async function checkErrorLog(projectPath) {
128
+ const candidates = [
129
+ join(projectPath, 'data', 'telemetry-errors.json'),
130
+ join(projectPath, '.planu', 'telemetry-errors.json'),
131
+ ];
132
+ for (const candidate of candidates) {
133
+ try {
134
+ const raw = await readFile(candidate, 'utf-8');
135
+ const parsed = JSON.parse(raw);
136
+ if (!Array.isArray(parsed)) {
137
+ continue;
138
+ }
139
+ const recent = parsed.slice(-5);
140
+ if (recent.length === 0) {
141
+ return {
142
+ name: 'error-log',
143
+ status: 'ok',
144
+ detail: 'No telemetry errors recorded',
145
+ };
146
+ }
147
+ const summary = recent
148
+ .map((e) => {
149
+ if (typeof e.message === 'string') {
150
+ return e.message;
151
+ }
152
+ if (typeof e.error === 'string') {
153
+ return e.error;
154
+ }
155
+ return '[unknown error]';
156
+ })
157
+ .join('; ');
158
+ return {
159
+ name: 'error-log',
160
+ status: 'warn',
161
+ detail: `${recent.length} recent error(s): ${summary}`,
162
+ };
163
+ }
164
+ catch {
165
+ // try next candidate
166
+ }
167
+ }
168
+ return {
169
+ name: 'error-log',
170
+ status: 'ok',
171
+ detail: 'No error log found',
172
+ };
173
+ }
174
+ async function checkClientVersion(projectPath) {
175
+ const pkgPath = join(projectPath, 'package.json');
176
+ try {
177
+ const raw = await readFile(pkgPath, 'utf-8');
178
+ const pkg = JSON.parse(raw);
179
+ const version = typeof pkg.version === 'string' ? pkg.version : 'unknown';
180
+ const name = typeof pkg.name === 'string' ? pkg.name : 'unknown';
181
+ return {
182
+ name: 'version',
183
+ status: 'ok',
184
+ detail: `Client: ${name}@${version}`,
185
+ };
186
+ }
187
+ catch {
188
+ return {
189
+ name: 'version',
190
+ status: 'warn',
191
+ detail: `Could not read package.json at ${pkgPath}`,
192
+ };
193
+ }
194
+ }
195
+ // ---------------------------------------------------------------------------
196
+ // Test event
197
+ // ---------------------------------------------------------------------------
198
+ function sendTestDiagnosticEvent(installationId) {
199
+ sendTelemetryEvent({
200
+ event: 'tool_used',
201
+ properties: {
202
+ tool: 'telemetry_health',
203
+ diagnostic: true,
204
+ timestamp: new Date().toISOString(),
205
+ },
206
+ installationId,
207
+ });
208
+ }
209
+ // ---------------------------------------------------------------------------
210
+ // Status helpers
211
+ // ---------------------------------------------------------------------------
212
+ function buildRecommendation(status) {
213
+ switch (status) {
214
+ case 'disabled':
215
+ return 'Run configure_telemetry to enable usage tracking';
216
+ case 'misconfigured':
217
+ return 'Set PLANU_TELEMETRY_ENDPOINT or run configure_telemetry';
218
+ case 'degraded':
219
+ return 'Check network connectivity or firewall rules blocking outbound requests';
220
+ case 'healthy':
221
+ return 'Telemetry is working. If no data shows in dashboard, check the dashboard filters.';
222
+ }
223
+ }
224
+ function buildHumanSummary(status, checks) {
225
+ const warnCount = checks.filter((c) => c.status === 'warn').length;
226
+ switch (status) {
227
+ case 'disabled':
228
+ return 'Telemetry is turned off — no usage data is being collected.';
229
+ case 'misconfigured':
230
+ return 'Telemetry cannot send data: configuration issue needs fixing.';
231
+ case 'degraded':
232
+ return `Telemetry is configured but ${warnCount} issue(s) may be preventing data from reaching the dashboard.`;
233
+ case 'healthy':
234
+ return 'Telemetry appears healthy. Data should be reaching the dashboard.';
235
+ }
236
+ }
237
+ function computeStatus(isEnabled, checks) {
238
+ if (!isEnabled) {
239
+ return 'disabled';
240
+ }
241
+ const endpointCheck = checks.find((c) => c.name === 'endpoint-configured');
242
+ if (endpointCheck?.status === 'fail') {
243
+ return 'misconfigured';
244
+ }
245
+ const hasWarn = checks.some((c) => c.status === 'warn');
246
+ if (hasWarn) {
247
+ return 'degraded';
248
+ }
249
+ return 'healthy';
250
+ }
251
+ // ---------------------------------------------------------------------------
252
+ // Public API
253
+ // ---------------------------------------------------------------------------
254
+ export async function checkTelemetryHealth(projectPath, options) {
255
+ const { check: enabledCheck, enabled } = await checkConfigEnabled();
256
+ if (!enabled) {
257
+ const checks = [enabledCheck];
258
+ const status = 'disabled';
259
+ return {
260
+ status,
261
+ checks,
262
+ recommendation: buildRecommendation(status),
263
+ humanSummary: buildHumanSummary(status, checks),
264
+ };
265
+ }
266
+ // Default endpoint from telemetry-client
267
+ const defaultEndpoint = 'https://canusqigtzldstnjddio.supabase.co/rest/v1/telemetry_events';
268
+ const endpoint = process.env.PLANU_TELEMETRY_ENDPOINT?.trim() ?? defaultEndpoint;
269
+ const [networkCheck, lastEventCheck, errorLogCheck, versionCheck] = await Promise.all([
270
+ checkNetworkReachable(endpoint),
271
+ checkLastEvent(projectPath),
272
+ checkErrorLog(projectPath),
273
+ checkClientVersion(projectPath),
274
+ ]);
275
+ const endpointCheck = checkEndpointConfigured(endpoint);
276
+ const checks = [
277
+ enabledCheck,
278
+ endpointCheck,
279
+ networkCheck,
280
+ lastEventCheck,
281
+ errorLogCheck,
282
+ versionCheck,
283
+ ];
284
+ const status = computeStatus(enabled, checks);
285
+ if (options?.sendTestEvent === true) {
286
+ const config = await readTelemetryConfig();
287
+ const installationId = config?.installationId ?? 'anonymous';
288
+ sendTestDiagnosticEvent(installationId);
289
+ }
290
+ return {
291
+ status,
292
+ checks,
293
+ recommendation: buildRecommendation(status),
294
+ humanSummary: buildHumanSummary(status, checks),
295
+ };
296
+ }
297
+ //# sourceMappingURL=health-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-checker.js","sourceRoot":"","sources":["../../../src/engine/telemetry/health-checker.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
1
  export * from './telemetry-store.js';
2
2
  export * from './telemetry-client.js';
3
+ export * from './health-checker.js';
3
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/telemetry/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/engine/telemetry/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
@@ -1,4 +1,5 @@
1
1
  // engine/telemetry/index.ts — SPEC-200: Barrel export for telemetry engine
2
2
  export * from './telemetry-store.js';
3
3
  export * from './telemetry-client.js';
4
+ export * from './health-checker.js';
4
5
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/telemetry/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/engine/telemetry/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -156,6 +156,10 @@ import { registerFilesystemHooksTools } from './tools/register-filesystem-hooks-
156
156
  import { registerSkillsEvalTools } from './tools/register-skills-eval-tools.js';
157
157
  import { registerTrialTools } from './tools/register-trial-tools.js';
158
158
  import { registerDepAuditTools } from './tools/register-dep-audit-tools.js';
159
+ import { registerSpecPromptTools } from './tools/register-spec-prompt-tools.js';
160
+ import { registerTelemetryHealthTools } from './tools/register-telemetry-health-tools.js';
161
+ import { registerMergeRiskTools } from './tools/register-merge-risk-tools.js';
162
+ import { registerDomainBundleTools } from './tools/register-domain-bundle-tools.js';
159
163
  // Server setup
160
164
  const SERVER_INSTRUCTIONS = [
161
165
  'CONTEXT — Why structured specs matter:',
@@ -377,11 +381,18 @@ function registerExtendedTools(s) {
377
381
  registerSpec323Tools(s);
378
382
  registerProductInsightsTools(s);
379
383
  registerSpec331Tools(s);
384
+ registerLatestSpecTools(s);
385
+ registerPrompts(s);
386
+ }
387
+ function registerLatestSpecTools(s) {
380
388
  registerFilesystemHooksTools(s);
381
389
  registerSkillsEvalTools(s);
382
390
  registerTrialTools(s);
383
391
  registerDepAuditTools(s);
384
- registerPrompts(s);
392
+ registerSpecPromptTools(s);
393
+ registerTelemetryHealthTools(s);
394
+ registerMergeRiskTools(s);
395
+ registerDomainBundleTools(s);
385
396
  }
386
397
  function createMcpServer() {
387
398
  const s = withToolTracking(new McpServer({ name: 'planu', version: PLANU_VERSION }, { instructions: SERVER_INSTRUCTIONS }));