openplanr 0.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 (146) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +168 -0
  3. package/bin/planr.js +2 -0
  4. package/dist/cli/commands/checklist.d.ts +3 -0
  5. package/dist/cli/commands/checklist.d.ts.map +1 -0
  6. package/dist/cli/commands/checklist.js +34 -0
  7. package/dist/cli/commands/checklist.js.map +1 -0
  8. package/dist/cli/commands/epic.d.ts +3 -0
  9. package/dist/cli/commands/epic.d.ts.map +1 -0
  10. package/dist/cli/commands/epic.js +61 -0
  11. package/dist/cli/commands/epic.js.map +1 -0
  12. package/dist/cli/commands/feature.d.ts +3 -0
  13. package/dist/cli/commands/feature.d.ts.map +1 -0
  14. package/dist/cli/commands/feature.js +65 -0
  15. package/dist/cli/commands/feature.js.map +1 -0
  16. package/dist/cli/commands/init.d.ts +3 -0
  17. package/dist/cli/commands/init.d.ts.map +1 -0
  18. package/dist/cli/commands/init.js +49 -0
  19. package/dist/cli/commands/init.js.map +1 -0
  20. package/dist/cli/commands/rules.d.ts +3 -0
  21. package/dist/cli/commands/rules.d.ts.map +1 -0
  22. package/dist/cli/commands/rules.js +48 -0
  23. package/dist/cli/commands/rules.js.map +1 -0
  24. package/dist/cli/commands/status.d.ts +3 -0
  25. package/dist/cli/commands/status.d.ts.map +1 -0
  26. package/dist/cli/commands/status.js +38 -0
  27. package/dist/cli/commands/status.js.map +1 -0
  28. package/dist/cli/commands/story.d.ts +3 -0
  29. package/dist/cli/commands/story.d.ts.map +1 -0
  30. package/dist/cli/commands/story.js +81 -0
  31. package/dist/cli/commands/story.js.map +1 -0
  32. package/dist/cli/commands/task.d.ts +3 -0
  33. package/dist/cli/commands/task.d.ts.map +1 -0
  34. package/dist/cli/commands/task.js +76 -0
  35. package/dist/cli/commands/task.js.map +1 -0
  36. package/dist/cli/index.d.ts +2 -0
  37. package/dist/cli/index.d.ts.map +1 -0
  38. package/dist/cli/index.js +27 -0
  39. package/dist/cli/index.js.map +1 -0
  40. package/dist/generators/base-generator.d.ts +9 -0
  41. package/dist/generators/base-generator.d.ts.map +1 -0
  42. package/dist/generators/base-generator.js +9 -0
  43. package/dist/generators/base-generator.js.map +1 -0
  44. package/dist/generators/claude-generator.d.ts +7 -0
  45. package/dist/generators/claude-generator.d.ts.map +1 -0
  46. package/dist/generators/claude-generator.js +27 -0
  47. package/dist/generators/claude-generator.js.map +1 -0
  48. package/dist/generators/codex-generator.d.ts +7 -0
  49. package/dist/generators/codex-generator.d.ts.map +1 -0
  50. package/dist/generators/codex-generator.js +22 -0
  51. package/dist/generators/codex-generator.js.map +1 -0
  52. package/dist/generators/cursor-generator.d.ts +7 -0
  53. package/dist/generators/cursor-generator.d.ts.map +1 -0
  54. package/dist/generators/cursor-generator.js +37 -0
  55. package/dist/generators/cursor-generator.js.map +1 -0
  56. package/dist/generators/generator-factory.d.ts +5 -0
  57. package/dist/generators/generator-factory.d.ts.map +1 -0
  58. package/dist/generators/generator-factory.js +19 -0
  59. package/dist/generators/generator-factory.js.map +1 -0
  60. package/dist/generators/generator-types.d.ts +4 -0
  61. package/dist/generators/generator-types.d.ts.map +1 -0
  62. package/dist/generators/generator-types.js +2 -0
  63. package/dist/generators/generator-types.js.map +1 -0
  64. package/dist/models/schema.d.ts +79 -0
  65. package/dist/models/schema.d.ts.map +1 -0
  66. package/dist/models/schema.js +22 -0
  67. package/dist/models/schema.js.map +1 -0
  68. package/dist/models/types.d.ts +78 -0
  69. package/dist/models/types.d.ts.map +1 -0
  70. package/dist/models/types.js +2 -0
  71. package/dist/models/types.js.map +1 -0
  72. package/dist/services/artifact-service.d.ts +17 -0
  73. package/dist/services/artifact-service.d.ts.map +1 -0
  74. package/dist/services/artifact-service.js +63 -0
  75. package/dist/services/artifact-service.js.map +1 -0
  76. package/dist/services/checklist-service.d.ts +6 -0
  77. package/dist/services/checklist-service.d.ts.map +1 -0
  78. package/dist/services/checklist-service.js +26 -0
  79. package/dist/services/checklist-service.js.map +1 -0
  80. package/dist/services/config-service.d.ts +5 -0
  81. package/dist/services/config-service.d.ts.map +1 -0
  82. package/dist/services/config-service.js +38 -0
  83. package/dist/services/config-service.js.map +1 -0
  84. package/dist/services/id-service.d.ts +6 -0
  85. package/dist/services/id-service.d.ts.map +1 -0
  86. package/dist/services/id-service.js +22 -0
  87. package/dist/services/id-service.js.map +1 -0
  88. package/dist/services/prompt-service.d.ts +9 -0
  89. package/dist/services/prompt-service.d.ts.map +1 -0
  90. package/dist/services/prompt-service.js +23 -0
  91. package/dist/services/prompt-service.js.map +1 -0
  92. package/dist/services/template-service.d.ts +2 -0
  93. package/dist/services/template-service.d.ts.map +1 -0
  94. package/dist/services/template-service.js +32 -0
  95. package/dist/services/template-service.js.map +1 -0
  96. package/dist/templates/adrs/adr-general.md.hbs +46 -0
  97. package/dist/templates/checklists/agile-checklist.md.hbs +49 -0
  98. package/dist/templates/epics/epic.md.hbs +46 -0
  99. package/dist/templates/features/feature.md.hbs +42 -0
  100. package/dist/templates/rules/claude/CLAUDE.md.hbs +63 -0
  101. package/dist/templates/rules/codex/AGENTS.md.hbs +28 -0
  102. package/dist/templates/rules/cursor/2000-agile-checklist.mdc.hbs +33 -0
  103. package/dist/templates/rules/cursor/2001-agile-create-epic.mdc.hbs +35 -0
  104. package/dist/templates/rules/cursor/2002-agile-create-features.mdc.hbs +35 -0
  105. package/dist/templates/rules/cursor/2003-agile-create-user-story.mdc.hbs +31 -0
  106. package/dist/templates/rules/cursor/2100-create-task-list.mdc.hbs +36 -0
  107. package/dist/templates/rules/cursor/2101-implement-task-list.mdc.hbs +28 -0
  108. package/dist/templates/stories/gherkin.feature.hbs +13 -0
  109. package/dist/templates/stories/user-story.md.hbs +28 -0
  110. package/dist/templates/tasks/task-list.md.hbs +24 -0
  111. package/dist/templates/templates/adrs/adr-general.md.hbs +46 -0
  112. package/dist/templates/templates/checklists/agile-checklist.md.hbs +49 -0
  113. package/dist/templates/templates/epics/epic.md.hbs +46 -0
  114. package/dist/templates/templates/features/feature.md.hbs +42 -0
  115. package/dist/templates/templates/rules/claude/CLAUDE.md.hbs +63 -0
  116. package/dist/templates/templates/rules/codex/AGENTS.md.hbs +28 -0
  117. package/dist/templates/templates/rules/cursor/2000-agile-checklist.mdc.hbs +33 -0
  118. package/dist/templates/templates/rules/cursor/2001-agile-create-epic.mdc.hbs +35 -0
  119. package/dist/templates/templates/rules/cursor/2002-agile-create-features.mdc.hbs +35 -0
  120. package/dist/templates/templates/rules/cursor/2003-agile-create-user-story.mdc.hbs +31 -0
  121. package/dist/templates/templates/rules/cursor/2100-create-task-list.mdc.hbs +36 -0
  122. package/dist/templates/templates/rules/cursor/2101-implement-task-list.mdc.hbs +28 -0
  123. package/dist/templates/templates/stories/gherkin.feature.hbs +13 -0
  124. package/dist/templates/templates/stories/user-story.md.hbs +28 -0
  125. package/dist/templates/templates/tasks/task-list.md.hbs +24 -0
  126. package/dist/utils/constants.d.ts +20 -0
  127. package/dist/utils/constants.d.ts.map +1 -0
  128. package/dist/utils/constants.js +26 -0
  129. package/dist/utils/constants.js.map +1 -0
  130. package/dist/utils/fs.d.ts +6 -0
  131. package/dist/utils/fs.d.ts.map +1 -0
  132. package/dist/utils/fs.js +26 -0
  133. package/dist/utils/fs.js.map +1 -0
  134. package/dist/utils/logger.d.ts +9 -0
  135. package/dist/utils/logger.d.ts.map +1 -0
  136. package/dist/utils/logger.js +22 -0
  137. package/dist/utils/logger.js.map +1 -0
  138. package/dist/utils/markdown.d.ts +7 -0
  139. package/dist/utils/markdown.d.ts.map +1 -0
  140. package/dist/utils/markdown.js +9 -0
  141. package/dist/utils/markdown.js.map +1 -0
  142. package/dist/utils/slugify.d.ts +2 -0
  143. package/dist/utils/slugify.d.ts.map +1 -0
  144. package/dist/utils/slugify.js +10 -0
  145. package/dist/utils/slugify.js.map +1 -0
  146. package/package.json +68 -0
@@ -0,0 +1,78 @@
1
+ export type ArtifactType = 'epic' | 'feature' | 'story' | 'task' | 'adr' | 'checklist';
2
+ export type TargetCLI = 'cursor' | 'claude' | 'codex';
3
+ export type TaskStatus = 'pending' | 'in-progress' | 'done';
4
+ export interface OpenPlanrConfig {
5
+ projectName: string;
6
+ targets: TargetCLI[];
7
+ outputPaths: {
8
+ agile: string;
9
+ cursorRules: string;
10
+ claudeConfig: string;
11
+ codexConfig: string;
12
+ };
13
+ idPrefix: {
14
+ epic: string;
15
+ feature: string;
16
+ story: string;
17
+ task: string;
18
+ };
19
+ templateOverrides?: string;
20
+ author?: string;
21
+ createdAt: string;
22
+ }
23
+ export interface BaseArtifact {
24
+ id: string;
25
+ title: string;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ filePath: string;
29
+ }
30
+ export interface Epic extends BaseArtifact {
31
+ owner: string;
32
+ businessValue: string;
33
+ targetUsers: string;
34
+ problemStatement: string;
35
+ solutionOverview: string;
36
+ successCriteria: string;
37
+ keyFeatures: string[];
38
+ dependencies: string;
39
+ risks: string;
40
+ featureIds: string[];
41
+ }
42
+ export interface Feature extends BaseArtifact {
43
+ epicId: string;
44
+ owner: string;
45
+ status: TaskStatus;
46
+ overview: string;
47
+ functionalRequirements: string[];
48
+ storyIds: string[];
49
+ }
50
+ export interface UserStory extends BaseArtifact {
51
+ featureId: string;
52
+ role: string;
53
+ goal: string;
54
+ benefit: string;
55
+ acceptanceCriteria: string;
56
+ additionalNotes?: string;
57
+ }
58
+ export interface TaskItem {
59
+ id: string;
60
+ title: string;
61
+ status: TaskStatus;
62
+ subtasks: TaskItem[];
63
+ }
64
+ export interface TaskList extends BaseArtifact {
65
+ storyId: string;
66
+ tasks: TaskItem[];
67
+ }
68
+ export interface ArtifactCollection {
69
+ epics: Epic[];
70
+ features: Feature[];
71
+ stories: UserStory[];
72
+ tasks: TaskList[];
73
+ }
74
+ export interface GeneratedFile {
75
+ path: string;
76
+ content: string;
77
+ }
78
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,GAAG,WAAW,CAAC;AACvF,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AACtD,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,aAAa,GAAG,MAAM,CAAC;AAE5D,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;IACF,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,IAAK,SAAQ,YAAY;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,gBAAgB,EAAE,MAAM,CAAC;IACzB,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,OAAQ,SAAQ,YAAY;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,sBAAsB,EAAE,MAAM,EAAE,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,QAAQ,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,QAAS,SAAQ,YAAY;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/models/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import type { OpenPlanrConfig, ArtifactType } from '../models/types.js';
2
+ export declare function getArtifactDir(config: OpenPlanrConfig, type: ArtifactType): string;
3
+ export declare function createArtifact(projectDir: string, config: OpenPlanrConfig, type: ArtifactType, templateFile: string, data: Record<string, unknown>): Promise<{
4
+ id: string;
5
+ filePath: string;
6
+ }>;
7
+ export declare function listArtifacts(projectDir: string, config: OpenPlanrConfig, type: ArtifactType): Promise<Array<{
8
+ id: string;
9
+ title: string;
10
+ filename: string;
11
+ }>>;
12
+ export declare function readArtifact(projectDir: string, config: OpenPlanrConfig, type: ArtifactType, id: string): Promise<{
13
+ data: Record<string, unknown>;
14
+ content: string;
15
+ filePath: string;
16
+ } | null>;
17
+ //# sourceMappingURL=artifact-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-service.d.ts","sourceRoot":"","sources":["../../src/services/artifact-service.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAWxE,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,CAElF;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,YAAY,EAClB,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAqB3C;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,KAAK,CAAC;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAgBjE;AAED,wBAAsB,YAAY,CAChC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,YAAY,EAClB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAStF"}
@@ -0,0 +1,63 @@
1
+ import path from 'node:path';
2
+ import { ensureDir, writeFile, readFile, listFiles } from '../utils/fs.js';
3
+ import { slugify } from '../utils/slugify.js';
4
+ import { parseMarkdown } from '../utils/markdown.js';
5
+ import { getNextId } from './id-service.js';
6
+ import { renderTemplate } from './template-service.js';
7
+ const ARTIFACT_DIR_MAP = {
8
+ epic: 'epics',
9
+ feature: 'features',
10
+ story: 'stories',
11
+ task: 'tasks',
12
+ adr: 'adrs',
13
+ checklist: 'checklists',
14
+ };
15
+ export function getArtifactDir(config, type) {
16
+ return path.join(config.outputPaths.agile, ARTIFACT_DIR_MAP[type] || type);
17
+ }
18
+ export async function createArtifact(projectDir, config, type, templateFile, data) {
19
+ const dir = path.join(projectDir, getArtifactDir(config, type));
20
+ await ensureDir(dir);
21
+ const prefixKey = type;
22
+ const prefix = config.idPrefix[prefixKey] || type.toUpperCase();
23
+ const id = await getNextId(dir, prefix);
24
+ const title = data.title || 'untitled';
25
+ const slug = slugify(title);
26
+ const filename = `${id}-${slug}.md`;
27
+ const filePath = path.join(dir, filename);
28
+ const content = await renderTemplate(templateFile, {
29
+ ...data,
30
+ id,
31
+ date: new Date().toISOString().split('T')[0],
32
+ projectName: config.projectName,
33
+ }, config.templateOverrides);
34
+ await writeFile(filePath, content);
35
+ return { id, filePath };
36
+ }
37
+ export async function listArtifacts(projectDir, config, type) {
38
+ const dir = path.join(projectDir, getArtifactDir(config, type));
39
+ const files = await listFiles(dir, /\.md$/);
40
+ const results = [];
41
+ for (const filename of files.sort()) {
42
+ const match = filename.match(/^([A-Z]+-\d{3})-(.+)\.md$/);
43
+ if (match) {
44
+ results.push({
45
+ id: match[1],
46
+ title: match[2].replace(/-/g, ' '),
47
+ filename,
48
+ });
49
+ }
50
+ }
51
+ return results;
52
+ }
53
+ export async function readArtifact(projectDir, config, type, id) {
54
+ const dir = path.join(projectDir, getArtifactDir(config, type));
55
+ const files = await listFiles(dir, new RegExp(`^${id}-.*\\.md$`));
56
+ if (files.length === 0)
57
+ return null;
58
+ const filePath = path.join(dir, files[0]);
59
+ const raw = await readFile(filePath);
60
+ const parsed = parseMarkdown(raw);
61
+ return { ...parsed, filePath };
62
+ }
63
+ //# sourceMappingURL=artifact-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-service.js","sourceRoot":"","sources":["../../src/services/artifact-service.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3E,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,MAAM,gBAAgB,GAA2B;IAC/C,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,UAAU;IACnB,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,OAAO;IACb,GAAG,EAAE,MAAM;IACX,SAAS,EAAE,YAAY;CACxB,CAAC;AAEF,MAAM,UAAU,cAAc,CAAC,MAAuB,EAAE,IAAkB;IACxE,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAkB,EAClB,MAAuB,EACvB,IAAkB,EAClB,YAAoB,EACpB,IAA6B;IAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;IAErB,MAAM,SAAS,GAAG,IAAoC,CAAC;IACvD,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;IAChE,MAAM,EAAE,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACxC,MAAM,KAAK,GAAI,IAAI,CAAC,KAAgB,IAAI,UAAU,CAAC;IACnD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,QAAQ,GAAG,GAAG,EAAE,IAAI,IAAI,KAAK,CAAC;IACpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,YAAY,EAAE;QACjD,GAAG,IAAI;QACP,EAAE;QACF,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5C,WAAW,EAAE,MAAM,CAAC,WAAW;KAChC,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE7B,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAkB,EAClB,MAAuB,EACvB,IAAkB;IAElB,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC5C,MAAM,OAAO,GAA2D,EAAE,CAAC;IAE3E,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;QACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC1D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC;gBACX,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC;gBACZ,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC;gBAClC,QAAQ;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,UAAkB,EAClB,MAAuB,EACvB,IAAkB,EAClB,EAAU;IAEV,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;IAChE,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEpC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAClC,OAAO,EAAE,GAAG,MAAM,EAAE,QAAQ,EAAE,CAAC;AACjC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { OpenPlanrConfig } from '../models/types.js';
2
+ export declare function getChecklistPath(projectDir: string, config: OpenPlanrConfig): string;
3
+ export declare function createChecklist(projectDir: string, config: OpenPlanrConfig): Promise<string>;
4
+ export declare function readChecklist(projectDir: string, config: OpenPlanrConfig): Promise<string | null>;
5
+ export declare function resetChecklist(projectDir: string, config: OpenPlanrConfig): Promise<string>;
6
+ //# sourceMappingURL=checklist-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-service.d.ts","sourceRoot":"","sources":["../../src/services/checklist-service.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI1D,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAEpF;AAED,wBAAsB,eAAe,CACnC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAIxB;AAED,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,MAAM,CAAC,CAEjB"}
@@ -0,0 +1,26 @@
1
+ import path from 'node:path';
2
+ import { fileExists, readFile, writeFile } from '../utils/fs.js';
3
+ import { renderTemplate } from './template-service.js';
4
+ const CHECKLIST_FILENAME = 'AGILE-DEVELOPMENT-GUIDE.md';
5
+ export function getChecklistPath(projectDir, config) {
6
+ return path.join(projectDir, config.outputPaths.agile, 'checklists', CHECKLIST_FILENAME);
7
+ }
8
+ export async function createChecklist(projectDir, config) {
9
+ const filePath = getChecklistPath(projectDir, config);
10
+ const content = await renderTemplate('checklists/agile-checklist.md.hbs', {
11
+ projectName: config.projectName,
12
+ date: new Date().toISOString().split('T')[0],
13
+ }, config.templateOverrides);
14
+ await writeFile(filePath, content);
15
+ return filePath;
16
+ }
17
+ export async function readChecklist(projectDir, config) {
18
+ const filePath = getChecklistPath(projectDir, config);
19
+ if (!(await fileExists(filePath)))
20
+ return null;
21
+ return readFile(filePath);
22
+ }
23
+ export async function resetChecklist(projectDir, config) {
24
+ return createChecklist(projectDir, config);
25
+ }
26
+ //# sourceMappingURL=checklist-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checklist-service.js","sourceRoot":"","sources":["../../src/services/checklist-service.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAGvD,MAAM,kBAAkB,GAAG,4BAA4B,CAAC;AAExD,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,MAAuB;IAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,kBAAkB,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,UAAkB,EAClB,MAAuB;IAEvB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,OAAO,GAAG,MAAM,cAAc,CAClC,mCAAmC,EACnC;QACE,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAC7C,EACD,MAAM,CAAC,iBAAiB,CACzB,CAAC;IACF,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnC,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,UAAkB,EAClB,MAAuB;IAEvB,MAAM,QAAQ,GAAG,gBAAgB,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IACtD,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,QAAQ,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/C,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,UAAkB,EAClB,MAAuB;IAEvB,OAAO,eAAe,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { OpenPlanrConfig } from '../models/types.js';
2
+ export declare function loadConfig(projectDir: string): Promise<OpenPlanrConfig>;
3
+ export declare function saveConfig(projectDir: string, config: OpenPlanrConfig): Promise<void>;
4
+ export declare function createDefaultConfig(projectName: string): OpenPlanrConfig;
5
+ //# sourceMappingURL=config-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-service.d.ts","sourceRoot":"","sources":["../../src/services/config-service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE1D,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAW7E;AAED,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAG3F;AAED,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,eAAe,CAkBxE"}
@@ -0,0 +1,38 @@
1
+ import path from 'node:path';
2
+ import { CONFIG_FILENAME } from '../utils/constants.js';
3
+ import { fileExists, readFile, writeFile } from '../utils/fs.js';
4
+ import { configSchema } from '../models/schema.js';
5
+ export async function loadConfig(projectDir) {
6
+ const configPath = path.join(projectDir, CONFIG_FILENAME);
7
+ const exists = await fileExists(configPath);
8
+ if (!exists) {
9
+ throw new Error(`No ${CONFIG_FILENAME} found in ${projectDir}. Run "planr init" first.`);
10
+ }
11
+ const raw = await readFile(configPath);
12
+ const parsed = JSON.parse(raw);
13
+ return configSchema.parse(parsed);
14
+ }
15
+ export async function saveConfig(projectDir, config) {
16
+ const configPath = path.join(projectDir, CONFIG_FILENAME);
17
+ await writeFile(configPath, JSON.stringify(config, null, 2) + '\n');
18
+ }
19
+ export function createDefaultConfig(projectName) {
20
+ return {
21
+ projectName,
22
+ targets: ['cursor', 'claude', 'codex'],
23
+ outputPaths: {
24
+ agile: 'docs/agile',
25
+ cursorRules: '.cursor/rules',
26
+ claudeConfig: '.',
27
+ codexConfig: '.',
28
+ },
29
+ idPrefix: {
30
+ epic: 'EPIC',
31
+ feature: 'FEAT',
32
+ story: 'US',
33
+ task: 'TASK',
34
+ },
35
+ createdAt: new Date().toISOString().split('T')[0],
36
+ };
37
+ }
38
+ //# sourceMappingURL=config-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-service.js","sourceRoot":"","sources":["../../src/services/config-service.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB;IACjD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,MAAM,eAAe,aAAa,UAAU,2BAA2B,CACxE,CAAC;IACJ,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,UAAU,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,YAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,UAAkB,EAAE,MAAuB;IAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC;IAC1D,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,WAAmB;IACrD,OAAO;QACL,WAAW;QACX,OAAO,EAAE,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,CAAC;QACtC,WAAW,EAAE;YACX,KAAK,EAAE,YAAY;YACnB,WAAW,EAAE,eAAe;YAC5B,YAAY,EAAE,GAAG;YACjB,WAAW,EAAE,GAAG;SACjB;QACD,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,MAAM;YACf,KAAK,EAAE,IAAI;YACX,IAAI,EAAE,MAAM;SACb;QACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;KAClD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ export declare function getNextId(dir: string, prefix: string): Promise<string>;
2
+ export declare function parseId(id: string): {
3
+ prefix: string;
4
+ num: number;
5
+ } | null;
6
+ //# sourceMappingURL=id-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-service.d.ts","sourceRoot":"","sources":["../../src/services/id-service.ts"],"names":[],"mappings":"AAGA,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5E;AAED,wBAAgB,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAI1E"}
@@ -0,0 +1,22 @@
1
+ import { listFiles } from '../utils/fs.js';
2
+ export async function getNextId(dir, prefix) {
3
+ const files = await listFiles(dir, new RegExp(`^${prefix}-\\d{3}`));
4
+ let maxId = 0;
5
+ for (const file of files) {
6
+ const match = file.match(new RegExp(`^${prefix}-(\\d{3})`));
7
+ if (match) {
8
+ const num = parseInt(match[1], 10);
9
+ if (num > maxId)
10
+ maxId = num;
11
+ }
12
+ }
13
+ const nextNum = (maxId + 1).toString().padStart(3, '0');
14
+ return `${prefix}-${nextNum}`;
15
+ }
16
+ export function parseId(id) {
17
+ const match = id.match(/^([A-Z]+)-(\d{3})$/);
18
+ if (!match)
19
+ return null;
20
+ return { prefix: match[1], num: parseInt(match[2], 10) };
21
+ }
22
+ //# sourceMappingURL=id-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id-service.js","sourceRoot":"","sources":["../../src/services/id-service.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACzD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,IAAI,MAAM,CAAC,IAAI,MAAM,SAAS,CAAC,CAAC,CAAC;IACpE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,MAAM,WAAW,CAAC,CAAC,CAAC;QAC5D,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACnC,IAAI,GAAG,GAAG,KAAK;gBAAE,KAAK,GAAG,GAAG,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,MAAM,OAAO,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACxD,OAAO,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,EAAU;IAChC,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,9 @@
1
+ export declare function promptText(message: string, defaultValue?: string): Promise<string>;
2
+ export declare function promptSelect<T extends string>(message: string, choices: Array<{
3
+ name: string;
4
+ value: T;
5
+ }>): Promise<T>;
6
+ export declare function promptConfirm(message: string, defaultValue?: boolean): Promise<boolean>;
7
+ export declare function promptEditor(message: string, defaultValue?: string): Promise<string>;
8
+ export declare function promptMultiText(message: string, hint?: string): Promise<string[]>;
9
+ //# sourceMappingURL=prompt-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-service.d.ts","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"AAEA,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExF;AAED,wBAAsB,YAAY,CAAC,CAAC,SAAS,MAAM,EACjD,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,CAAC,CAAA;CAAE,CAAC,GACzC,OAAO,CAAC,CAAC,CAAC,CAEZ;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAE1F;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAE1F;AAED,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQvF"}
@@ -0,0 +1,23 @@
1
+ import { input, select, confirm, editor } from '@inquirer/prompts';
2
+ export async function promptText(message, defaultValue) {
3
+ return input({ message, default: defaultValue });
4
+ }
5
+ export async function promptSelect(message, choices) {
6
+ return select({ message, choices });
7
+ }
8
+ export async function promptConfirm(message, defaultValue = true) {
9
+ return confirm({ message, default: defaultValue });
10
+ }
11
+ export async function promptEditor(message, defaultValue) {
12
+ return editor({ message, default: defaultValue });
13
+ }
14
+ export async function promptMultiText(message, hint) {
15
+ const result = await input({
16
+ message: `${message}${hint ? ` (${hint})` : ''}`,
17
+ });
18
+ return result
19
+ .split(',')
20
+ .map((s) => s.trim())
21
+ .filter(Boolean);
22
+ }
23
+ //# sourceMappingURL=prompt-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt-service.js","sourceRoot":"","sources":["../../src/services/prompt-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAe,EAAE,YAAqB;IACrE,OAAO,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,OAA0C;IAE1C,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAe,EAAE,YAAY,GAAG,IAAI;IACtE,OAAO,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,YAAqB;IACvE,OAAO,MAAM,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe,EAAE,IAAa;IAClE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;QACzB,OAAO,EAAE,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;KACjD,CAAC,CAAC;IACH,OAAO,MAAM;SACV,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function renderTemplate(templatePath: string, data: Record<string, unknown>, overrideDir?: string): Promise<string>;
2
+ //# sourceMappingURL=template-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-service.d.ts","sourceRoot":"","sources":["../../src/services/template-service.ts"],"names":[],"mappings":"AAkBA,wBAAsB,cAAc,CAClC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CASjB"}
@@ -0,0 +1,32 @@
1
+ import path from 'node:path';
2
+ import Handlebars from 'handlebars';
3
+ import { readFile, fileExists } from '../utils/fs.js';
4
+ import { getTemplatesDir } from '../utils/constants.js';
5
+ const compiledCache = new Map();
6
+ Handlebars.registerHelper('date', () => new Date().toISOString().split('T')[0]);
7
+ Handlebars.registerHelper('uppercase', (str) => typeof str === 'string' ? str.toUpperCase() : '');
8
+ Handlebars.registerHelper('checkboxList', (items) => {
9
+ if (!Array.isArray(items))
10
+ return '';
11
+ return items.map((item) => `- [ ] ${item}`).join('\n');
12
+ });
13
+ export async function renderTemplate(templatePath, data, overrideDir) {
14
+ const fullPath = await resolveTemplatePath(templatePath, overrideDir);
15
+ let compiled = compiledCache.get(fullPath);
16
+ if (!compiled) {
17
+ const raw = await readFile(fullPath);
18
+ compiled = Handlebars.compile(raw, { noEscape: true });
19
+ compiledCache.set(fullPath, compiled);
20
+ }
21
+ return compiled(data);
22
+ }
23
+ async function resolveTemplatePath(templatePath, overrideDir) {
24
+ if (overrideDir) {
25
+ const overrideFull = path.join(overrideDir, templatePath);
26
+ if (await fileExists(overrideFull)) {
27
+ return overrideFull;
28
+ }
29
+ }
30
+ return path.join(getTemplatesDir(), templatePath);
31
+ }
32
+ //# sourceMappingURL=template-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-service.js","sourceRoot":"","sources":["../../src/services/template-service.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,UAAU,MAAM,YAAY,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAsC,CAAC;AAEpE,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,UAAU,CAAC,cAAc,CAAC,WAAW,EAAE,CAAC,GAAW,EAAE,EAAE,CACrD,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CACjD,CAAC;AAEF,UAAU,CAAC,cAAc,CAAC,cAAc,EAAE,CAAC,KAAe,EAAE,EAAE;IAC5D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzD,CAAC,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,YAAoB,EACpB,IAA6B,EAC7B,WAAoB;IAEpB,MAAM,QAAQ,GAAG,MAAM,mBAAmB,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACtE,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,QAAQ,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,aAAa,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC;AACxB,CAAC;AAED,KAAK,UAAU,mBAAmB,CAChC,YAAoB,EACpB,WAAoB;IAEpB,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC1D,IAAI,MAAM,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACnC,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,EAAE,YAAY,CAAC,CAAC;AACpD,CAAC"}
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: "{{id}}"
3
+ title: "{{title}}"
4
+ created: "{{date}}"
5
+ status: "proposed"
6
+ ---
7
+
8
+ # {{id}}: {{title}}
9
+
10
+ ## Context
11
+ {{context}}
12
+
13
+ ## Decision Drivers
14
+ {{#each decisionDrivers}}
15
+ - {{this}}
16
+ {{/each}}
17
+
18
+ ## Considered Options
19
+ {{#each options}}
20
+ ### Option {{@index}}: {{this.name}}
21
+ {{this.description}}
22
+
23
+ **Pros:**
24
+ {{#each this.pros}}
25
+ - {{this}}
26
+ {{/each}}
27
+
28
+ **Cons:**
29
+ {{#each this.cons}}
30
+ - {{this}}
31
+ {{/each}}
32
+ {{/each}}
33
+
34
+ ## Decision
35
+ {{decision}}
36
+
37
+ ## Consequences
38
+ ### Positive
39
+ {{#each positiveConsequences}}
40
+ - {{this}}
41
+ {{/each}}
42
+
43
+ ### Negative
44
+ {{#each negativeConsequences}}
45
+ - {{this}}
46
+ {{/each}}
@@ -0,0 +1,49 @@
1
+ # Agile Development Guide — {{projectName}}
2
+
3
+ > Generated by OpenPlanr on {{date}}
4
+
5
+ ## Phase 1: Requirements Analysis
6
+
7
+ | # | Activity | Command | Status |
8
+ |---|----------|---------|--------|
9
+ | 1 | Create Epic | `openplanr epic create` | [ ] |
10
+ | 2 | Create Features from Epic | `openplanr feature create --epic <ID>` | [ ] |
11
+ | 3 | Create User Stories from Features | `openplanr story create --feature <ID>` | [ ] |
12
+
13
+ ## Phase 2: Technical Design
14
+
15
+ | # | Activity | Artifact | Status |
16
+ |---|----------|----------|--------|
17
+ | 4 | UML Sequence Diagrams | `docs/agile/diagrams/` | [ ] |
18
+ | 5 | C4 Architecture Diagrams | `docs/agile/diagrams/` | [ ] |
19
+
20
+ ## Phase 3: Architecture Decision Records
21
+
22
+ | # | Activity | Command | Status |
23
+ |---|----------|---------|--------|
24
+ | 6 | Functional Requirements ADR (CLI) | `docs/agile/adrs/` | [ ] |
25
+ | 7 | Functional Requirements ADR (REST) | `docs/agile/adrs/` | [ ] |
26
+ | 8 | Acceptance Testing Strategy ADR | `docs/agile/adrs/` | [ ] |
27
+ | 9 | Non-Functional Requirements ADR | `docs/agile/adrs/` | [ ] |
28
+
29
+ ## Phase 4: Solution Planning
30
+
31
+ | # | Activity | Command | Status |
32
+ |---|----------|---------|--------|
33
+ | 10 | Create Task Lists | `openplanr task create --story <ID>` | [ ] |
34
+ | 11 | Implement Tasks | `openplanr task implement <ID>` | [ ] |
35
+ | 12 | Create Definition of Done | `docs/agile/checklists/` | [ ] |
36
+
37
+ ## Phase 5: Solution Review
38
+
39
+ | # | Activity | Artifact | Status |
40
+ |---|----------|----------|--------|
41
+ | 13 | UML Class Diagrams | `docs/agile/diagrams/` | [ ] |
42
+ | 14 | Review & Refactoring | Code review | [ ] |
43
+
44
+ ## Best Practices
45
+
46
+ - Complete each phase before moving to the next
47
+ - All artifacts should be version controlled alongside your code
48
+ - Use `openplanr status` to see overall progress
49
+ - Use `openplanr rules generate` to keep AI agent rules in sync with your artifacts
@@ -0,0 +1,46 @@
1
+ ---
2
+ id: "{{id}}"
3
+ title: "{{title}}"
4
+ owner: "{{owner}}"
5
+ created: "{{date}}"
6
+ updated: "{{date}}"
7
+ status: "planning"
8
+ project: "{{projectName}}"
9
+ ---
10
+
11
+ # {{id}}: {{title}}
12
+
13
+ ## Business Value
14
+ {{businessValue}}
15
+
16
+ ## Target Users
17
+ {{targetUsers}}
18
+
19
+ ## Problem Statement
20
+ {{problemStatement}}
21
+
22
+ ## Solution Overview
23
+ {{solutionOverview}}
24
+
25
+ ## Success Criteria
26
+ {{successCriteria}}
27
+
28
+ ## Key Features
29
+ {{#each keyFeatures}}
30
+ - {{this}}
31
+ {{/each}}
32
+
33
+ ## Dependencies
34
+ {{dependencies}}
35
+
36
+ ## Risks
37
+ {{risks}}
38
+
39
+ ## Features
40
+ {{#if featureIds}}
41
+ {{#each featureIds}}
42
+ - [{{this}}](../features/{{this}}.md)
43
+ {{/each}}
44
+ {{else}}
45
+ _No features created yet. Run `openplanr feature create --epic {{id}}` to break this epic into features._
46
+ {{/if}}
@@ -0,0 +1,42 @@
1
+ ---
2
+ id: "{{id}}"
3
+ title: "{{title}}"
4
+ epicId: "{{epicId}}"
5
+ owner: "{{owner}}"
6
+ created: "{{date}}"
7
+ updated: "{{date}}"
8
+ status: "planning"
9
+ ---
10
+
11
+ # {{id}}: {{title}}
12
+
13
+ **Epic:** [{{epicId}}](../epics/{{epicId}}.md)
14
+
15
+ ## Overview
16
+ {{overview}}
17
+
18
+ ## Functional Requirements
19
+ {{#each functionalRequirements}}
20
+ - {{this}}
21
+ {{/each}}
22
+
23
+ ## User Stories
24
+ {{#if storyIds}}
25
+ {{#each storyIds}}
26
+ - [{{this}}](../stories/{{this}}.md)
27
+ {{/each}}
28
+ {{else}}
29
+ _No user stories created yet. Run `openplanr story create --feature {{id}}` to create user stories._
30
+ {{/if}}
31
+
32
+ ## Dependencies
33
+ {{dependencies}}
34
+
35
+ ## Technical Considerations
36
+ {{technicalConsiderations}}
37
+
38
+ ## Risks
39
+ {{risks}}
40
+
41
+ ## Success Metrics
42
+ {{successMetrics}}