@planu/cli 0.96.4 → 0.97.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/cli/commands/install.d.ts.map +1 -1
- package/dist/cli/commands/install.js +70 -2
- package/dist/cli/commands/install.js.map +1 -1
- package/dist/config/compliance-profiles.json +62 -0
- package/dist/config/license-plans.json +19 -2
- package/dist/config/spec-templates/crud-rest-api/spec.md +35 -0
- package/dist/config/spec-templates/crud-rest-api/template.json +10 -0
- package/dist/config/spec-templates/email-notifications/spec.md +31 -0
- package/dist/config/spec-templates/email-notifications/template.json +10 -0
- package/dist/config/spec-templates/file-upload-s3/spec.md +31 -0
- package/dist/config/spec-templates/file-upload-s3/template.json +11 -0
- package/dist/config/spec-templates/jwt-auth/spec.md +35 -0
- package/dist/config/spec-templates/jwt-auth/template.json +10 -0
- package/dist/config/spec-templates/oauth-social-login/spec.md +31 -0
- package/dist/config/spec-templates/oauth-social-login/template.json +10 -0
- package/dist/config/spec-templates/rate-limiting/spec.md +31 -0
- package/dist/config/spec-templates/rate-limiting/template.json +10 -0
- package/dist/config/spec-templates/stripe-payments/spec.md +32 -0
- package/dist/config/spec-templates/stripe-payments/template.json +10 -0
- package/dist/config/spec-templates/webhook-system/spec.md +36 -0
- package/dist/config/spec-templates/webhook-system/template.json +10 -0
- package/dist/engine/agent-ready-exporter/formatters/devin.d.ts +7 -0
- package/dist/engine/agent-ready-exporter/formatters/devin.d.ts.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/devin.js +23 -0
- package/dist/engine/agent-ready-exporter/formatters/devin.js.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/generic.d.ts +7 -0
- package/dist/engine/agent-ready-exporter/formatters/generic.d.ts.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/generic.js +9 -0
- package/dist/engine/agent-ready-exporter/formatters/generic.js.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/kiro.d.ts +6 -0
- package/dist/engine/agent-ready-exporter/formatters/kiro.d.ts.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/kiro.js +34 -0
- package/dist/engine/agent-ready-exporter/formatters/kiro.js.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/swe-agent.d.ts +6 -0
- package/dist/engine/agent-ready-exporter/formatters/swe-agent.d.ts.map +1 -0
- package/dist/engine/agent-ready-exporter/formatters/swe-agent.js +40 -0
- package/dist/engine/agent-ready-exporter/formatters/swe-agent.js.map +1 -0
- package/dist/engine/agent-ready-exporter.d.ts +11 -0
- package/dist/engine/agent-ready-exporter.d.ts.map +1 -0
- package/dist/engine/agent-ready-exporter.js +86 -0
- package/dist/engine/agent-ready-exporter.js.map +1 -0
- package/dist/engine/compliance-checker.d.ts +19 -0
- package/dist/engine/compliance-checker.d.ts.map +1 -0
- package/dist/engine/compliance-checker.js +145 -0
- package/dist/engine/compliance-checker.js.map +1 -0
- package/dist/engine/generate-tests/generators/property-based-generator.d.ts +12 -0
- package/dist/engine/generate-tests/generators/property-based-generator.d.ts.map +1 -0
- package/dist/engine/generate-tests/generators/property-based-generator.js +159 -0
- package/dist/engine/generate-tests/generators/property-based-generator.js.map +1 -0
- package/dist/engine/jira-exporter.d.ts +39 -0
- package/dist/engine/jira-exporter.d.ts.map +1 -0
- package/dist/engine/jira-exporter.js +190 -0
- package/dist/engine/jira-exporter.js.map +1 -0
- package/dist/engine/linear-exporter.d.ts +32 -0
- package/dist/engine/linear-exporter.d.ts.map +1 -0
- package/dist/engine/linear-exporter.js +184 -0
- package/dist/engine/linear-exporter.js.map +1 -0
- package/dist/engine/planu-config-writer.d.ts +13 -2
- package/dist/engine/planu-config-writer.d.ts.map +1 -1
- package/dist/engine/planu-config-writer.js +32 -1
- package/dist/engine/planu-config-writer.js.map +1 -1
- package/dist/engine/property-test-generator.d.ts +14 -0
- package/dist/engine/property-test-generator.d.ts.map +1 -0
- package/dist/engine/property-test-generator.js +223 -0
- package/dist/engine/property-test-generator.js.map +1 -0
- package/dist/engine/skill-evaluator.d.ts +21 -0
- package/dist/engine/skill-evaluator.d.ts.map +1 -0
- package/dist/engine/skill-evaluator.js +126 -0
- package/dist/engine/skill-evaluator.js.map +1 -0
- package/dist/engine/spec-quality-scorer.d.ts +4 -0
- package/dist/engine/spec-quality-scorer.d.ts.map +1 -0
- package/dist/engine/spec-quality-scorer.js +334 -0
- package/dist/engine/spec-quality-scorer.js.map +1 -0
- package/dist/engine/spec-template-engine.d.ts +26 -0
- package/dist/engine/spec-template-engine.d.ts.map +1 -0
- package/dist/engine/spec-template-engine.js +127 -0
- package/dist/engine/spec-template-engine.js.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/storage/compliance-store.d.ts +11 -0
- package/dist/storage/compliance-store.d.ts.map +1 -0
- package/dist/storage/compliance-store.js +30 -0
- package/dist/storage/compliance-store.js.map +1 -0
- package/dist/storage/jira-store.d.ts +30 -0
- package/dist/storage/jira-store.d.ts.map +1 -0
- package/dist/storage/jira-store.js +84 -0
- package/dist/storage/jira-store.js.map +1 -0
- package/dist/storage/linear-store.d.ts +30 -0
- package/dist/storage/linear-store.d.ts.map +1 -0
- package/dist/storage/linear-store.js +84 -0
- package/dist/storage/linear-store.js.map +1 -0
- package/dist/tools/check-readiness.d.ts.map +1 -1
- package/dist/tools/check-readiness.js +8 -2
- package/dist/tools/check-readiness.js.map +1 -1
- package/dist/tools/compliance-handler.d.ts +6 -0
- package/dist/tools/compliance-handler.d.ts.map +1 -0
- package/dist/tools/compliance-handler.js +99 -0
- package/dist/tools/compliance-handler.js.map +1 -0
- package/dist/tools/eval-skill-handler.d.ts +4 -0
- package/dist/tools/eval-skill-handler.d.ts.map +1 -0
- package/dist/tools/eval-skill-handler.js +26 -0
- package/dist/tools/eval-skill-handler.js.map +1 -0
- package/dist/tools/export-spec.d.ts.map +1 -1
- package/dist/tools/export-spec.js +42 -1
- package/dist/tools/export-spec.js.map +1 -1
- package/dist/tools/generate-tests/generators/property-based-generator.d.ts +11 -0
- package/dist/tools/generate-tests/generators/property-based-generator.d.ts.map +1 -0
- package/dist/tools/generate-tests/generators/property-based-generator.js +27 -0
- package/dist/tools/generate-tests/generators/property-based-generator.js.map +1 -0
- package/dist/tools/generate-tests/spec-dispatcher.d.ts +5 -0
- package/dist/tools/generate-tests/spec-dispatcher.d.ts.map +1 -1
- package/dist/tools/generate-tests/spec-dispatcher.js +18 -1
- package/dist/tools/generate-tests/spec-dispatcher.js.map +1 -1
- package/dist/tools/init-project/config-builder.d.ts +3 -2
- package/dist/tools/init-project/config-builder.d.ts.map +1 -1
- package/dist/tools/init-project/config-builder.js +9 -4
- package/dist/tools/init-project/config-builder.js.map +1 -1
- package/dist/tools/init-project/handler.d.ts.map +1 -1
- package/dist/tools/init-project/handler.js +3 -2
- package/dist/tools/init-project/handler.js.map +1 -1
- package/dist/tools/jira-sync-handler.d.ts +6 -0
- package/dist/tools/jira-sync-handler.d.ts.map +1 -0
- package/dist/tools/jira-sync-handler.js +220 -0
- package/dist/tools/jira-sync-handler.js.map +1 -0
- package/dist/tools/linear-sync-handler.d.ts +6 -0
- package/dist/tools/linear-sync-handler.d.ts.map +1 -0
- package/dist/tools/linear-sync-handler.js +212 -0
- package/dist/tools/linear-sync-handler.js.map +1 -0
- package/dist/tools/register-export-tools.d.ts.map +1 -1
- package/dist/tools/register-export-tools.js +10 -3
- package/dist/tools/register-export-tools.js.map +1 -1
- package/dist/tools/register-spec-314.d.ts +3 -0
- package/dist/tools/register-spec-314.d.ts.map +1 -0
- package/dist/tools/register-spec-314.js +38 -0
- package/dist/tools/register-spec-314.js.map +1 -0
- package/dist/tools/register-spec-316.d.ts +3 -0
- package/dist/tools/register-spec-316.d.ts.map +1 -0
- package/dist/tools/register-spec-316.js +71 -0
- package/dist/tools/register-spec-316.js.map +1 -0
- package/dist/tools/register-spec-317.d.ts +3 -0
- package/dist/tools/register-spec-317.d.ts.map +1 -0
- package/dist/tools/register-spec-317.js +158 -0
- package/dist/tools/register-spec-317.js.map +1 -0
- package/dist/tools/register-spec-319.d.ts +3 -0
- package/dist/tools/register-spec-319.d.ts.map +1 -0
- package/dist/tools/register-spec-319.js +59 -0
- package/dist/tools/register-spec-319.js.map +1 -0
- package/dist/tools/register-spec-320.d.ts +3 -0
- package/dist/tools/register-spec-320.d.ts.map +1 -0
- package/dist/tools/register-spec-320.js +60 -0
- package/dist/tools/register-spec-320.js.map +1 -0
- package/dist/tools/register-spec-tools/core-spec-tools.d.ts.map +1 -1
- package/dist/tools/register-spec-tools/core-spec-tools.js +15 -1
- package/dist/tools/register-spec-tools/core-spec-tools.js.map +1 -1
- package/dist/tools/schemas/index.d.ts +1 -1
- package/dist/tools/schemas/index.d.ts.map +1 -1
- package/dist/tools/schemas/index.js +1 -1
- package/dist/tools/schemas/index.js.map +1 -1
- package/dist/tools/schemas/spec.d.ts +6 -0
- package/dist/tools/schemas/spec.d.ts.map +1 -1
- package/dist/tools/schemas/spec.js +4 -0
- package/dist/tools/schemas/spec.js.map +1 -1
- package/dist/tools/set-work-mode-handler.d.ts +7 -0
- package/dist/tools/set-work-mode-handler.d.ts.map +1 -0
- package/dist/tools/set-work-mode-handler.js +30 -0
- package/dist/tools/set-work-mode-handler.js.map +1 -0
- package/dist/tools/spec-marketplace-handler.d.ts +6 -0
- package/dist/tools/spec-marketplace-handler.d.ts.map +1 -0
- package/dist/tools/spec-marketplace-handler.js +113 -0
- package/dist/tools/spec-marketplace-handler.js.map +1 -0
- package/dist/tools/spec-quality-score-handler.d.ts +7 -0
- package/dist/tools/spec-quality-score-handler.d.ts.map +1 -0
- package/dist/tools/spec-quality-score-handler.js +106 -0
- package/dist/tools/spec-quality-score-handler.js.map +1 -0
- package/dist/tools/status-handler.d.ts.map +1 -1
- package/dist/tools/status-handler.js +12 -3
- package/dist/tools/status-handler.js.map +1 -1
- package/dist/types/agent-ready.d.ts +58 -0
- package/dist/types/agent-ready.d.ts.map +1 -0
- package/dist/types/agent-ready.js +3 -0
- package/dist/types/agent-ready.js.map +1 -0
- package/dist/types/common/primitives.d.ts +2 -0
- package/dist/types/common/primitives.d.ts.map +1 -1
- package/dist/types/compliance.d.ts +44 -0
- package/dist/types/compliance.d.ts.map +1 -0
- package/dist/types/compliance.js +3 -0
- package/dist/types/compliance.js.map +1 -0
- package/dist/types/export.d.ts +5 -1
- package/dist/types/export.d.ts.map +1 -1
- package/dist/types/export.js +1 -1
- package/dist/types/export.js.map +1 -1
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +7 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/jira-linear.d.ts +216 -0
- package/dist/types/jira-linear.d.ts.map +1 -0
- package/dist/types/jira-linear.js +3 -0
- package/dist/types/jira-linear.js.map +1 -0
- package/dist/types/project/inputs.d.ts +3 -1
- package/dist/types/project/inputs.d.ts.map +1 -1
- package/dist/types/project/planu-config.d.ts +2 -0
- package/dist/types/project/planu-config.d.ts.map +1 -1
- package/dist/types/property-testing.d.ts +50 -0
- package/dist/types/property-testing.d.ts.map +1 -0
- package/dist/types/property-testing.js +3 -0
- package/dist/types/property-testing.js.map +1 -0
- package/dist/types/skill-eval.d.ts +41 -0
- package/dist/types/skill-eval.d.ts.map +1 -0
- package/dist/types/skill-eval.js +3 -0
- package/dist/types/skill-eval.js.map +1 -0
- package/dist/types/spec-marketplace.d.ts +31 -0
- package/dist/types/spec-marketplace.d.ts.map +1 -0
- package/dist/types/spec-marketplace.js +3 -0
- package/dist/types/spec-marketplace.js.map +1 -0
- package/dist/types/spec-quality.d.ts +36 -0
- package/dist/types/spec-quality.d.ts.map +1 -0
- package/dist/types/spec-quality.js +3 -0
- package/dist/types/spec-quality.js.map +1 -0
- package/package.json +7 -2
- package/src/config/compliance-profiles.json +62 -0
- package/src/config/license-plans.json +19 -2
- package/src/config/spec-templates/crud-rest-api/spec.md +35 -0
- package/src/config/spec-templates/crud-rest-api/template.json +10 -0
- package/src/config/spec-templates/email-notifications/spec.md +31 -0
- package/src/config/spec-templates/email-notifications/template.json +10 -0
- package/src/config/spec-templates/file-upload-s3/spec.md +31 -0
- package/src/config/spec-templates/file-upload-s3/template.json +11 -0
- package/src/config/spec-templates/jwt-auth/spec.md +35 -0
- package/src/config/spec-templates/jwt-auth/template.json +10 -0
- package/src/config/spec-templates/oauth-social-login/spec.md +31 -0
- package/src/config/spec-templates/oauth-social-login/template.json +10 -0
- package/src/config/spec-templates/rate-limiting/spec.md +31 -0
- package/src/config/spec-templates/rate-limiting/template.json +10 -0
- package/src/config/spec-templates/stripe-payments/spec.md +32 -0
- package/src/config/spec-templates/stripe-payments/template.json +10 -0
- package/src/config/spec-templates/webhook-system/spec.md +36 -0
- package/src/config/spec-templates/webhook-system/template.json +10 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// engine/generate-tests/generators/property-based-generator.ts — SPEC-315
|
|
2
|
+
// High-level generator: produces a full test file string from spec + context.
|
|
3
|
+
import { extractPropertyTests, detectPropertyFramework } from '../../property-test-generator.js';
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// File header builders per framework
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
function buildFastCheckHeader(specTitle) {
|
|
8
|
+
return `// Property-based tests for: ${specTitle}
|
|
9
|
+
// Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
10
|
+
// Framework: fast-check
|
|
11
|
+
|
|
12
|
+
import * as fc from 'fast-check';
|
|
13
|
+
import { describe, it } from 'vitest';
|
|
14
|
+
|
|
15
|
+
describe('${specTitle} — property-based tests', () => {`;
|
|
16
|
+
}
|
|
17
|
+
function buildHypothesisHeader(specTitle) {
|
|
18
|
+
return `# Property-based tests for: ${specTitle}
|
|
19
|
+
# Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
20
|
+
# Framework: hypothesis
|
|
21
|
+
|
|
22
|
+
from hypothesis import given, settings, HealthCheck
|
|
23
|
+
from hypothesis import strategies as st
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class Test${specTitle.replace(/[^a-zA-Z0-9]/g, '')}Properties:
|
|
27
|
+
"""Property-based tests for ${specTitle}."""
|
|
28
|
+
`;
|
|
29
|
+
}
|
|
30
|
+
function buildJqwikHeader(specTitle) {
|
|
31
|
+
const className = specTitle.replace(/[^a-zA-Z0-9]/g, '');
|
|
32
|
+
return `// Property-based tests for: ${specTitle}
|
|
33
|
+
// Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
34
|
+
// Framework: jqwik
|
|
35
|
+
|
|
36
|
+
import net.jqwik.api.*;
|
|
37
|
+
import static org.assertj.core.api.Assertions.assertThat;
|
|
38
|
+
|
|
39
|
+
class ${className}PropertyTest {`;
|
|
40
|
+
}
|
|
41
|
+
function buildGenericHeader(specTitle) {
|
|
42
|
+
return `# Property-based tests for: ${specTitle}
|
|
43
|
+
# Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
44
|
+
# Framework: generic (adapt to your property testing library)
|
|
45
|
+
#
|
|
46
|
+
# Each property below describes an invariant that must hold for ALL valid inputs.
|
|
47
|
+
# Implement using your project's property testing framework.
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Test block builders per framework
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
function buildFastCheckBlock(test, index) {
|
|
54
|
+
return `
|
|
55
|
+
it('property ${index + 1}: ${test.invariant}', () => {
|
|
56
|
+
// Input domain: ${test.inputDomain}
|
|
57
|
+
// Shrink: ${test.shrinkStrategy}
|
|
58
|
+
${test.generatorCode}
|
|
59
|
+
});`;
|
|
60
|
+
}
|
|
61
|
+
function buildHypothesisBlock(test, _index) {
|
|
62
|
+
return `
|
|
63
|
+
${test.generatorCode}
|
|
64
|
+
`;
|
|
65
|
+
}
|
|
66
|
+
function buildJqwikBlock(test, _index) {
|
|
67
|
+
return `
|
|
68
|
+
// Input domain: ${test.inputDomain}
|
|
69
|
+
// Shrink: ${test.shrinkStrategy}
|
|
70
|
+
${test.generatorCode}
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
function buildGenericBlock(test, index) {
|
|
74
|
+
return `
|
|
75
|
+
# Property ${index + 1}
|
|
76
|
+
${test.generatorCode}
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
// ---------------------------------------------------------------------------
|
|
80
|
+
// File footer builders
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
function buildFastCheckFooter() {
|
|
83
|
+
return '\n});\n';
|
|
84
|
+
}
|
|
85
|
+
function buildJqwikFooter() {
|
|
86
|
+
return '\n}\n';
|
|
87
|
+
}
|
|
88
|
+
function buildNoFooter() {
|
|
89
|
+
return '\n';
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// No-properties fallback
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
function buildFallbackContent(specTitle, language) {
|
|
95
|
+
if (language === 'python') {
|
|
96
|
+
return `# Property-based tests for: ${specTitle}
|
|
97
|
+
# Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
98
|
+
# No invariants detected in acceptance criteria.
|
|
99
|
+
# Add criteria with keywords: "must be positive", "idempotent", "for any input", etc.
|
|
100
|
+
`;
|
|
101
|
+
}
|
|
102
|
+
return `// Property-based tests for: ${specTitle}
|
|
103
|
+
// Generated by Planu SDD — strategy:property-based (SPEC-315)
|
|
104
|
+
// No invariants detected in acceptance criteria.
|
|
105
|
+
// Add criteria with keywords: "must be positive", "idempotent", "for any input", etc.
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
// Public API
|
|
110
|
+
// ---------------------------------------------------------------------------
|
|
111
|
+
/**
|
|
112
|
+
* Generate a complete property-based test file as a string.
|
|
113
|
+
* Adapts output to fast-check (JS/TS), hypothesis (Python), jqwik (Java/Kotlin),
|
|
114
|
+
* or pseudo-code generic format based on detected framework.
|
|
115
|
+
*
|
|
116
|
+
* @param spec - The spec metadata (title, id used for file naming/headers).
|
|
117
|
+
* @param context - Project knowledge (language, stack) for framework detection.
|
|
118
|
+
* @param criteria - Acceptance criteria strings extracted from spec.md by the caller.
|
|
119
|
+
*/
|
|
120
|
+
export function generatePropertyBasedTests(spec, context, criteria = []) {
|
|
121
|
+
const framework = detectPropertyFramework(context.language, context.stack);
|
|
122
|
+
const tests = extractPropertyTests({
|
|
123
|
+
criteria,
|
|
124
|
+
language: context.language,
|
|
125
|
+
stack: context.stack,
|
|
126
|
+
});
|
|
127
|
+
if (tests.length === 0) {
|
|
128
|
+
return buildFallbackContent(spec.title, context.language);
|
|
129
|
+
}
|
|
130
|
+
// Build header
|
|
131
|
+
let header;
|
|
132
|
+
let blockBuilder;
|
|
133
|
+
let footer;
|
|
134
|
+
switch (framework) {
|
|
135
|
+
case 'fast-check':
|
|
136
|
+
header = buildFastCheckHeader(spec.title);
|
|
137
|
+
blockBuilder = buildFastCheckBlock;
|
|
138
|
+
footer = buildFastCheckFooter();
|
|
139
|
+
break;
|
|
140
|
+
case 'hypothesis':
|
|
141
|
+
header = buildHypothesisHeader(spec.title);
|
|
142
|
+
blockBuilder = buildHypothesisBlock;
|
|
143
|
+
footer = buildNoFooter();
|
|
144
|
+
break;
|
|
145
|
+
case 'jqwik':
|
|
146
|
+
header = buildJqwikHeader(spec.title);
|
|
147
|
+
blockBuilder = buildJqwikBlock;
|
|
148
|
+
footer = buildJqwikFooter();
|
|
149
|
+
break;
|
|
150
|
+
case 'generic':
|
|
151
|
+
header = buildGenericHeader(spec.title);
|
|
152
|
+
blockBuilder = buildGenericBlock;
|
|
153
|
+
footer = buildNoFooter();
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
const blocks = tests.map((test, i) => blockBuilder(test, i)).join('');
|
|
157
|
+
return `${header}${blocks}${footer}`;
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=property-based-generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"property-based-generator.js","sourceRoot":"","sources":["../../../../src/engine/generate-tests/generators/property-based-generator.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,8EAA8E;AAI9E,OAAO,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAEjG,8EAA8E;AAC9E,qCAAqC;AACrC,8EAA8E;AAE9E,SAAS,oBAAoB,CAAC,SAAiB;IAC7C,OAAO,gCAAgC,SAAS;;;;;;;YAOtC,SAAS,mCAAmC,CAAC;AACzD,CAAC;AAED,SAAS,qBAAqB,CAAC,SAAiB;IAC9C,OAAO,+BAA+B,SAAS;;;;;;;;YAQrC,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;kCAChB,SAAS;CAC1C,CAAC;AACF,CAAC;AAED,SAAS,gBAAgB,CAAC,SAAiB;IACzC,MAAM,SAAS,GAAG,SAAS,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,gCAAgC,SAAS;;;;;;;QAO1C,SAAS,gBAAgB,CAAC;AAClC,CAAC;AAED,SAAS,kBAAkB,CAAC,SAAiB;IAC3C,OAAO,+BAA+B,SAAS;;;;;;CAMhD,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,oCAAoC;AACpC,8EAA8E;AAE9E,SAAS,mBAAmB,CAAC,IAAkB,EAAE,KAAa;IAC5D,OAAO;iBACQ,KAAK,GAAG,CAAC,KAAK,IAAI,CAAC,SAAS;uBACtB,IAAI,CAAC,WAAW;iBACtB,IAAI,CAAC,cAAc;MAC9B,IAAI,CAAC,aAAa;MAClB,CAAC;AACP,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAkB,EAAE,MAAc;IAC9D,OAAO;MACH,IAAI,CAAC,aAAa;CACvB,CAAC;AACF,CAAC;AAED,SAAS,eAAe,CAAC,IAAkB,EAAE,MAAc;IACzD,OAAO;uBACc,IAAI,CAAC,WAAW;iBACtB,IAAI,CAAC,cAAc;MAC9B,IAAI,CAAC,aAAa;CACvB,CAAC;AACF,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAkB,EAAE,KAAa;IAC1D,OAAO;aACI,KAAK,GAAG,CAAC;EACpB,IAAI,CAAC,aAAa;CACnB,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,SAAS,oBAAoB;IAC3B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gBAAgB;IACvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa;IACpB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,SAAS,oBAAoB,CAAC,SAAiB,EAAE,QAAgB;IAC/D,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,+BAA+B,SAAS;;;;CAIlD,CAAC;IACA,CAAC;IACD,OAAO,gCAAgC,SAAS;;;;CAIjD,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;;;;;;GAQG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAU,EACV,OAAyB,EACzB,WAAqB,EAAE;IAEvB,MAAM,SAAS,GAAG,uBAAuB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAG,oBAAoB,CAAC;QACjC,QAAQ;QACR,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;KACrB,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,oBAAoB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5D,CAAC;IAED,eAAe;IACf,IAAI,MAAc,CAAC;IACnB,IAAI,YAA2D,CAAC;IAChE,IAAI,MAAc,CAAC;IAEnB,QAAQ,SAAS,EAAE,CAAC;QAClB,KAAK,YAAY;YACf,MAAM,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1C,YAAY,GAAG,mBAAmB,CAAC;YACnC,MAAM,GAAG,oBAAoB,EAAE,CAAC;YAChC,MAAM;QACR,KAAK,YAAY;YACf,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC3C,YAAY,GAAG,oBAAoB,CAAC;YACpC,MAAM,GAAG,aAAa,EAAE,CAAC;YACzB,MAAM;QACR,KAAK,OAAO;YACV,MAAM,GAAG,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtC,YAAY,GAAG,eAAe,CAAC;YAC/B,MAAM,GAAG,gBAAgB,EAAE,CAAC;YAC5B,MAAM;QACR,KAAK,SAAS;YACZ,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACxC,YAAY,GAAG,iBAAiB,CAAC;YACjC,MAAM,GAAG,aAAa,EAAE,CAAC;YACzB,MAAM;IACV,CAAC;IAED,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACtE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,CAAC;AACvC,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { JiraConfig, JiraIssueRef, JiraApiIssue, Spec } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Map a Planu spec status to a Jira status name.
|
|
4
|
+
*/
|
|
5
|
+
export declare function mapSpecStatusToJira(specStatus: string): string;
|
|
6
|
+
export declare class JiraClient {
|
|
7
|
+
private readonly config;
|
|
8
|
+
private readonly authHeader;
|
|
9
|
+
private readonly baseUrl;
|
|
10
|
+
constructor(config: JiraConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Create an Epic in Jira from a spec.
|
|
13
|
+
* Returns a JiraIssueRef with the new issue details.
|
|
14
|
+
*/
|
|
15
|
+
createEpic(spec: Spec): Promise<JiraIssueRef>;
|
|
16
|
+
/**
|
|
17
|
+
* Create a Story in Jira linked to a parent Epic.
|
|
18
|
+
* Returns a JiraIssueRef for the created story.
|
|
19
|
+
*/
|
|
20
|
+
createStory(specId: string, criterionText: string, epicKey: string): Promise<JiraIssueRef>;
|
|
21
|
+
/**
|
|
22
|
+
* Fetch a Jira issue by key.
|
|
23
|
+
* Returns the issue or null if not found.
|
|
24
|
+
*/
|
|
25
|
+
getIssue(key: string): Promise<JiraApiIssue | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Transition a Jira issue to a target status name.
|
|
28
|
+
* Looks up available transitions and applies the matching one.
|
|
29
|
+
*/
|
|
30
|
+
updateIssueStatus(issueKey: string, targetStatus: string): Promise<void>;
|
|
31
|
+
private getTransitions;
|
|
32
|
+
private postJson;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Build a minimal Atlassian Document Format (ADF) document.
|
|
36
|
+
* Used for Jira issue descriptions in the REST API v3.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildAtlassianDoc(heading: string, bodyText: string): Record<string, unknown>;
|
|
39
|
+
//# sourceMappingURL=jira-exporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-exporter.d.ts","sourceRoot":"","sources":["../../src/engine/jira-exporter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,UAAU,EACV,YAAY,EACZ,YAAY,EAEZ,IAAI,EACL,MAAM,mBAAmB,CAAC;AAc3B;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE9D;AAMD,qBAAa,UAAU;IAIT,OAAO,CAAC,QAAQ,CAAC,MAAM;IAHnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAEJ,MAAM,EAAE,UAAU;IAM/C;;;OAGG;IACG,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,YAAY,CAAC;IA0BnD;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IA2BhG;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAqBzD;;;OAGG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAgChE,cAAc;YAkBd,QAAQ;CAmBvB;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBzB"}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Status mapping: Planu spec status → Jira issue status name
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
const SPEC_STATUS_TO_JIRA = {
|
|
5
|
+
draft: 'To Do',
|
|
6
|
+
review: 'In Review',
|
|
7
|
+
approved: 'Approved',
|
|
8
|
+
implementing: 'In Progress',
|
|
9
|
+
done: 'Done',
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Map a Planu spec status to a Jira status name.
|
|
13
|
+
*/
|
|
14
|
+
export function mapSpecStatusToJira(specStatus) {
|
|
15
|
+
return SPEC_STATUS_TO_JIRA[specStatus] ?? 'To Do';
|
|
16
|
+
}
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
// Jira REST API client
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
export class JiraClient {
|
|
21
|
+
config;
|
|
22
|
+
authHeader;
|
|
23
|
+
baseUrl;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = config;
|
|
26
|
+
const credentials = `${config.email}:${config.apiToken}`;
|
|
27
|
+
this.authHeader = `Basic ${Buffer.from(credentials).toString('base64')}`;
|
|
28
|
+
this.baseUrl = `https://${config.domain}.atlassian.net/rest/api/3`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Create an Epic in Jira from a spec.
|
|
32
|
+
* Returns a JiraIssueRef with the new issue details.
|
|
33
|
+
*/
|
|
34
|
+
async createEpic(spec) {
|
|
35
|
+
const summary = `${spec.id}: ${spec.title}`;
|
|
36
|
+
const description = buildAtlassianDoc(spec.title, `Planu spec ${spec.id} — status: ${spec.status}`);
|
|
37
|
+
const payload = {
|
|
38
|
+
fields: {
|
|
39
|
+
project: { key: this.config.projectKey },
|
|
40
|
+
issuetype: { name: 'Epic' },
|
|
41
|
+
summary,
|
|
42
|
+
description,
|
|
43
|
+
labels: ['planu-spec'],
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const data = await this.postJson('/issue', payload);
|
|
47
|
+
const issueUrl = `https://${this.config.domain}.atlassian.net/browse/${data.key}`;
|
|
48
|
+
return {
|
|
49
|
+
specId: spec.id,
|
|
50
|
+
issueKey: data.key,
|
|
51
|
+
issueUrl,
|
|
52
|
+
summary,
|
|
53
|
+
issueType: 'Epic',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Create a Story in Jira linked to a parent Epic.
|
|
58
|
+
* Returns a JiraIssueRef for the created story.
|
|
59
|
+
*/
|
|
60
|
+
async createStory(specId, criterionText, epicKey) {
|
|
61
|
+
const summary = criterionText.slice(0, 255);
|
|
62
|
+
const description = buildAtlassianDoc('Acceptance Criterion', criterionText);
|
|
63
|
+
const payload = {
|
|
64
|
+
fields: {
|
|
65
|
+
project: { key: this.config.projectKey },
|
|
66
|
+
issuetype: { name: 'Story' },
|
|
67
|
+
summary,
|
|
68
|
+
description,
|
|
69
|
+
labels: ['planu-spec'],
|
|
70
|
+
'Epic Link': epicKey,
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
const data = await this.postJson('/issue', payload);
|
|
74
|
+
const issueUrl = `https://${this.config.domain}.atlassian.net/browse/${data.key}`;
|
|
75
|
+
return {
|
|
76
|
+
specId,
|
|
77
|
+
issueKey: data.key,
|
|
78
|
+
issueUrl,
|
|
79
|
+
summary,
|
|
80
|
+
issueType: 'Story',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Fetch a Jira issue by key.
|
|
85
|
+
* Returns the issue or null if not found.
|
|
86
|
+
*/
|
|
87
|
+
async getIssue(key) {
|
|
88
|
+
const url = `${this.baseUrl}/issue/${encodeURIComponent(key)}`;
|
|
89
|
+
const response = await globalThis.fetch(url, {
|
|
90
|
+
headers: {
|
|
91
|
+
Authorization: this.authHeader,
|
|
92
|
+
'Content-Type': 'application/json',
|
|
93
|
+
},
|
|
94
|
+
signal: AbortSignal.timeout(10_000),
|
|
95
|
+
});
|
|
96
|
+
if (response.status === 404) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
if (!response.ok) {
|
|
100
|
+
throw new Error(`Jira getIssue failed: ${response.status} ${response.statusText}`);
|
|
101
|
+
}
|
|
102
|
+
return (await response.json());
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Transition a Jira issue to a target status name.
|
|
106
|
+
* Looks up available transitions and applies the matching one.
|
|
107
|
+
*/
|
|
108
|
+
async updateIssueStatus(issueKey, targetStatus) {
|
|
109
|
+
const transitions = await this.getTransitions(issueKey);
|
|
110
|
+
const match = transitions.find((t) => t.name.toLowerCase() === targetStatus.toLowerCase());
|
|
111
|
+
if (match === undefined) {
|
|
112
|
+
// Status not available — skip silently (workflow may differ per project)
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const url = `${this.baseUrl}/issue/${encodeURIComponent(issueKey)}/transitions`;
|
|
116
|
+
const response = await globalThis.fetch(url, {
|
|
117
|
+
method: 'POST',
|
|
118
|
+
headers: {
|
|
119
|
+
Authorization: this.authHeader,
|
|
120
|
+
'Content-Type': 'application/json',
|
|
121
|
+
},
|
|
122
|
+
body: JSON.stringify({ transition: { id: match.id } }),
|
|
123
|
+
signal: AbortSignal.timeout(10_000),
|
|
124
|
+
});
|
|
125
|
+
if (!response.ok) {
|
|
126
|
+
const errText = await response.text();
|
|
127
|
+
throw new Error(`Jira updateIssueStatus failed: ${response.status} — ${errText}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
// Private helpers
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
async getTransitions(issueKey) {
|
|
134
|
+
const url = `${this.baseUrl}/issue/${encodeURIComponent(issueKey)}/transitions`;
|
|
135
|
+
const response = await globalThis.fetch(url, {
|
|
136
|
+
headers: {
|
|
137
|
+
Authorization: this.authHeader,
|
|
138
|
+
'Content-Type': 'application/json',
|
|
139
|
+
},
|
|
140
|
+
signal: AbortSignal.timeout(10_000),
|
|
141
|
+
});
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
const data = (await response.json());
|
|
146
|
+
return data.transitions;
|
|
147
|
+
}
|
|
148
|
+
async postJson(path, body) {
|
|
149
|
+
const url = `${this.baseUrl}${path}`;
|
|
150
|
+
const response = await globalThis.fetch(url, {
|
|
151
|
+
method: 'POST',
|
|
152
|
+
headers: {
|
|
153
|
+
Authorization: this.authHeader,
|
|
154
|
+
'Content-Type': 'application/json',
|
|
155
|
+
},
|
|
156
|
+
body: JSON.stringify(body),
|
|
157
|
+
signal: AbortSignal.timeout(15_000),
|
|
158
|
+
});
|
|
159
|
+
if (!response.ok) {
|
|
160
|
+
const errText = await response.text();
|
|
161
|
+
throw new Error(`Jira POST ${path} failed: ${response.status} — ${errText}`);
|
|
162
|
+
}
|
|
163
|
+
return (await response.json());
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Atlassian Document Format (ADF) builder
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
/**
|
|
170
|
+
* Build a minimal Atlassian Document Format (ADF) document.
|
|
171
|
+
* Used for Jira issue descriptions in the REST API v3.
|
|
172
|
+
*/
|
|
173
|
+
export function buildAtlassianDoc(heading, bodyText) {
|
|
174
|
+
return {
|
|
175
|
+
version: 1,
|
|
176
|
+
type: 'doc',
|
|
177
|
+
content: [
|
|
178
|
+
{
|
|
179
|
+
type: 'heading',
|
|
180
|
+
attrs: { level: 2 },
|
|
181
|
+
content: [{ type: 'text', text: heading }],
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
type: 'paragraph',
|
|
185
|
+
content: [{ type: 'text', text: bodyText }],
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=jira-exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jira-exporter.js","sourceRoot":"","sources":["../../src/engine/jira-exporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { LinearConfig, LinearIssueRef, Spec } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Map a Planu spec status to a Linear workflow state name.
|
|
4
|
+
*/
|
|
5
|
+
export declare function mapSpecStatusToLinear(specStatus: string): string;
|
|
6
|
+
export declare class LinearClient {
|
|
7
|
+
private readonly config;
|
|
8
|
+
constructor(config: LinearConfig);
|
|
9
|
+
/**
|
|
10
|
+
* Create a Linear project (as an issue group / label) from a spec.
|
|
11
|
+
* Since Linear uses issues as primary entities, each spec becomes an issue.
|
|
12
|
+
* Returns a LinearIssueRef with the created issue details.
|
|
13
|
+
*/
|
|
14
|
+
createProject(spec: Spec): Promise<LinearIssueRef>;
|
|
15
|
+
/**
|
|
16
|
+
* Create a sub-issue in Linear for a single acceptance criterion.
|
|
17
|
+
* Returns a LinearIssueRef for the created issue.
|
|
18
|
+
*/
|
|
19
|
+
createIssue(specId: string, criterionText: string, parentId?: string): Promise<LinearIssueRef>;
|
|
20
|
+
/**
|
|
21
|
+
* Update the workflow state (status) of a Linear issue.
|
|
22
|
+
* Looks up the state ID by name within the team, then applies it.
|
|
23
|
+
*/
|
|
24
|
+
updateIssueStatus(issueId: string, stateName: string): Promise<void>;
|
|
25
|
+
private findStateId;
|
|
26
|
+
private graphql;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build a Markdown description for a Linear issue from a spec.
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildLinearDescription(spec: Spec): string;
|
|
32
|
+
//# sourceMappingURL=linear-exporter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-exporter.d.ts","sourceRoot":"","sources":["../../src/engine/linear-exporter.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EAId,IAAI,EACL,MAAM,mBAAmB,CAAC;AAgB3B;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAMD,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,YAAY;IAEjD;;;;OAIG;IACG,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,cAAc,CAAC;IAqCxD;;;OAGG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,cAAc,CAAC;IAsC1B;;;OAGG;IACG,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YA6B5D,WAAW;YAuBX,OAAO;CA6BtB;AAMD;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CASzD"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
const LINEAR_GRAPHQL_URL = 'https://api.linear.app/graphql';
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// Status mapping: Planu spec status → Linear workflow state name
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
const SPEC_STATUS_TO_LINEAR = {
|
|
6
|
+
draft: 'Todo',
|
|
7
|
+
review: 'In Review',
|
|
8
|
+
approved: 'Todo',
|
|
9
|
+
implementing: 'In Progress',
|
|
10
|
+
done: 'Done',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Map a Planu spec status to a Linear workflow state name.
|
|
14
|
+
*/
|
|
15
|
+
export function mapSpecStatusToLinear(specStatus) {
|
|
16
|
+
return SPEC_STATUS_TO_LINEAR[specStatus] ?? 'Todo';
|
|
17
|
+
}
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Linear GraphQL client
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
export class LinearClient {
|
|
22
|
+
config;
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.config = config;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Create a Linear project (as an issue group / label) from a spec.
|
|
28
|
+
* Since Linear uses issues as primary entities, each spec becomes an issue.
|
|
29
|
+
* Returns a LinearIssueRef with the created issue details.
|
|
30
|
+
*/
|
|
31
|
+
async createProject(spec) {
|
|
32
|
+
const title = `${spec.id}: ${spec.title}`;
|
|
33
|
+
const description = buildLinearDescription(spec);
|
|
34
|
+
const mutation = `
|
|
35
|
+
mutation CreateIssue($input: IssueCreateInput!) {
|
|
36
|
+
issueCreate(input: $input) {
|
|
37
|
+
success
|
|
38
|
+
issue {
|
|
39
|
+
id
|
|
40
|
+
url
|
|
41
|
+
title
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
const variables = {
|
|
47
|
+
input: {
|
|
48
|
+
teamId: this.config.teamId,
|
|
49
|
+
title,
|
|
50
|
+
description,
|
|
51
|
+
labelNames: ['planu-spec'],
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
const data = await this.graphql(mutation, variables);
|
|
55
|
+
const issue = data.issueCreate.issue;
|
|
56
|
+
return {
|
|
57
|
+
specId: spec.id,
|
|
58
|
+
issueId: issue.id,
|
|
59
|
+
issueUrl: issue.url,
|
|
60
|
+
title: issue.title,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Create a sub-issue in Linear for a single acceptance criterion.
|
|
65
|
+
* Returns a LinearIssueRef for the created issue.
|
|
66
|
+
*/
|
|
67
|
+
async createIssue(specId, criterionText, parentId) {
|
|
68
|
+
const title = criterionText.slice(0, 255);
|
|
69
|
+
const mutation = `
|
|
70
|
+
mutation CreateIssue($input: IssueCreateInput!) {
|
|
71
|
+
issueCreate(input: $input) {
|
|
72
|
+
success
|
|
73
|
+
issue {
|
|
74
|
+
id
|
|
75
|
+
url
|
|
76
|
+
title
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
const input = {
|
|
82
|
+
teamId: this.config.teamId,
|
|
83
|
+
title,
|
|
84
|
+
description: criterionText,
|
|
85
|
+
labelNames: ['planu-spec'],
|
|
86
|
+
};
|
|
87
|
+
if (parentId !== undefined) {
|
|
88
|
+
input.parentId = parentId;
|
|
89
|
+
}
|
|
90
|
+
const data = await this.graphql(mutation, { input });
|
|
91
|
+
const issue = data.issueCreate.issue;
|
|
92
|
+
return {
|
|
93
|
+
specId,
|
|
94
|
+
issueId: issue.id,
|
|
95
|
+
issueUrl: issue.url,
|
|
96
|
+
title: issue.title,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Update the workflow state (status) of a Linear issue.
|
|
101
|
+
* Looks up the state ID by name within the team, then applies it.
|
|
102
|
+
*/
|
|
103
|
+
async updateIssueStatus(issueId, stateName) {
|
|
104
|
+
const stateId = await this.findStateId(stateName);
|
|
105
|
+
if (stateId === null) {
|
|
106
|
+
// State not found — skip silently
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
const mutation = `
|
|
110
|
+
mutation UpdateIssue($id: String!, $input: IssueUpdateInput!) {
|
|
111
|
+
issueUpdate(id: $id, input: $input) {
|
|
112
|
+
success
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
`;
|
|
116
|
+
const data = await this.graphql(mutation, {
|
|
117
|
+
id: issueId,
|
|
118
|
+
input: { stateId },
|
|
119
|
+
});
|
|
120
|
+
if (!data.issueUpdate.success) {
|
|
121
|
+
throw new Error(`Linear updateIssueStatus failed for issue ${issueId}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Private helpers
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
async findStateId(stateName) {
|
|
128
|
+
const query = `
|
|
129
|
+
query WorkflowStates($teamId: String!) {
|
|
130
|
+
workflowStates(filter: { team: { id: { eq: $teamId } } }) {
|
|
131
|
+
nodes {
|
|
132
|
+
id
|
|
133
|
+
name
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
`;
|
|
138
|
+
const data = await this.graphql(query, {
|
|
139
|
+
teamId: this.config.teamId,
|
|
140
|
+
});
|
|
141
|
+
const match = data.workflowStates.nodes.find((s) => s.name.toLowerCase() === stateName.toLowerCase());
|
|
142
|
+
return match?.id ?? null;
|
|
143
|
+
}
|
|
144
|
+
async graphql(query, variables) {
|
|
145
|
+
const response = await globalThis.fetch(LINEAR_GRAPHQL_URL, {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
headers: {
|
|
148
|
+
Authorization: `Bearer ${this.config.apiKey}`,
|
|
149
|
+
'Content-Type': 'application/json',
|
|
150
|
+
},
|
|
151
|
+
body: JSON.stringify({ query, variables }),
|
|
152
|
+
signal: AbortSignal.timeout(15_000),
|
|
153
|
+
});
|
|
154
|
+
if (!response.ok) {
|
|
155
|
+
const errText = await response.text();
|
|
156
|
+
throw new Error(`Linear GraphQL request failed: ${response.status} — ${errText}`);
|
|
157
|
+
}
|
|
158
|
+
const json = (await response.json());
|
|
159
|
+
if (json.errors !== undefined && json.errors.length > 0) {
|
|
160
|
+
const messages = json.errors.map((e) => e.message).join('; ');
|
|
161
|
+
throw new Error(`Linear GraphQL errors: ${messages}`);
|
|
162
|
+
}
|
|
163
|
+
if (json.data === undefined) {
|
|
164
|
+
throw new Error('Linear GraphQL returned no data');
|
|
165
|
+
}
|
|
166
|
+
return json.data;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Description builder
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
/**
|
|
173
|
+
* Build a Markdown description for a Linear issue from a spec.
|
|
174
|
+
*/
|
|
175
|
+
export function buildLinearDescription(spec) {
|
|
176
|
+
const lines = [
|
|
177
|
+
`## ${spec.id}: ${spec.title}`,
|
|
178
|
+
'',
|
|
179
|
+
`**Status:** ${spec.status}`,
|
|
180
|
+
`**Source:** Planu spec`,
|
|
181
|
+
];
|
|
182
|
+
return lines.join('\n');
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=linear-exporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linear-exporter.js","sourceRoot":"","sources":["../../src/engine/linear-exporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
-
import type { PlanuConfig } from '../types/index.js';
|
|
1
|
+
import type { PlanuConfig, WorkMode } from '../types/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* Create a new PlanuConfig with defaults. Always uses modern spec location.
|
|
4
|
+
* SPEC-313: Accepts optional workMode to embed in the generated config.
|
|
4
5
|
*/
|
|
5
|
-
export declare function createPlanuConfig(): PlanuConfig;
|
|
6
|
+
export declare function createPlanuConfig(workMode?: WorkMode): PlanuConfig;
|
|
7
|
+
/**
|
|
8
|
+
* SPEC-313: Read planu.json, update workMode, and write back.
|
|
9
|
+
* Accepts injected readFile/writeFile to keep this function pure/testable.
|
|
10
|
+
*/
|
|
11
|
+
export declare function updatePlanuConfigWorkMode(planuConfigPath: string, workMode: WorkMode, readFile: (path: string, enc: 'utf-8') => Promise<string>, writeFile: (path: string, data: string, enc: 'utf-8') => Promise<void>): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* SPEC-313: Read and parse planu.json to retrieve its config (best-effort).
|
|
14
|
+
* Returns null if the file is absent or malformed.
|
|
15
|
+
*/
|
|
16
|
+
export declare function readPlanuConfig(planuConfigPath: string, readFile: (path: string, enc: 'utf-8') => Promise<string>): Promise<PlanuConfig | null>;
|
|
6
17
|
/**
|
|
7
18
|
* Serialize PlanuConfig to JSON string.
|
|
8
19
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planu-config-writer.d.ts","sourceRoot":"","sources":["../../src/engine/planu-config-writer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"planu-config-writer.d.ts","sourceRoot":"","sources":["../../src/engine/planu-config-writer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAK/D;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,CAAC,EAAE,QAAQ,GAAG,WAAW,CAWlE;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC7C,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,EACzD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GACrE,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,GACxD,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAO7B;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAEhE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG;IAC7D,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAKA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAE9D"}
|