@planu/cli 1.12.0 → 1.13.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 (128) hide show
  1. package/dist/config/ai-tool-registry.json +71 -0
  2. package/dist/config/autopilot-config.json +21 -0
  3. package/dist/config/competitive-catalog.json +83 -0
  4. package/dist/config/license-plans.json +17 -1
  5. package/dist/engine/agent-registry/lifecycle-manager.d.ts +8 -0
  6. package/dist/engine/agent-registry/lifecycle-manager.d.ts.map +1 -0
  7. package/dist/engine/agent-registry/lifecycle-manager.js +81 -0
  8. package/dist/engine/agent-registry/lifecycle-manager.js.map +1 -0
  9. package/dist/engine/agent-registry/role-catalog.d.ts +17 -0
  10. package/dist/engine/agent-registry/role-catalog.d.ts.map +1 -0
  11. package/dist/engine/agent-registry/role-catalog.js +55 -0
  12. package/dist/engine/agent-registry/role-catalog.js.map +1 -0
  13. package/dist/engine/autopilot/action-executor.d.ts +18 -0
  14. package/dist/engine/autopilot/action-executor.d.ts.map +1 -0
  15. package/dist/engine/autopilot/action-executor.js +91 -0
  16. package/dist/engine/autopilot/action-executor.js.map +1 -0
  17. package/dist/engine/autopilot/event-bus.d.ts +8 -0
  18. package/dist/engine/autopilot/event-bus.d.ts.map +1 -0
  19. package/dist/engine/autopilot/event-bus.js +28 -0
  20. package/dist/engine/autopilot/event-bus.js.map +1 -0
  21. package/dist/engine/autopilot/trigger-rules.d.ts +3 -0
  22. package/dist/engine/autopilot/trigger-rules.d.ts.map +1 -0
  23. package/dist/engine/autopilot/trigger-rules.js +125 -0
  24. package/dist/engine/autopilot/trigger-rules.js.map +1 -0
  25. package/dist/engine/competitive/gap-analyzer.d.ts +12 -0
  26. package/dist/engine/competitive/gap-analyzer.d.ts.map +1 -0
  27. package/dist/engine/competitive/gap-analyzer.js +214 -0
  28. package/dist/engine/competitive/gap-analyzer.js.map +1 -0
  29. package/dist/engine/hook-generator/ai-hook-templates.d.ts +8 -0
  30. package/dist/engine/hook-generator/ai-hook-templates.d.ts.map +1 -0
  31. package/dist/engine/hook-generator/ai-hook-templates.js +43 -0
  32. package/dist/engine/hook-generator/ai-hook-templates.js.map +1 -0
  33. package/dist/engine/hook-generator/hook-merger.d.ts +13 -0
  34. package/dist/engine/hook-generator/hook-merger.d.ts.map +1 -0
  35. package/dist/engine/hook-generator/hook-merger.js +148 -0
  36. package/dist/engine/hook-generator/hook-merger.js.map +1 -0
  37. package/dist/engine/hook-generator/stack-hook-templates.d.ts +10 -0
  38. package/dist/engine/hook-generator/stack-hook-templates.d.ts.map +1 -0
  39. package/dist/engine/hook-generator/stack-hook-templates.js +105 -0
  40. package/dist/engine/hook-generator/stack-hook-templates.js.map +1 -0
  41. package/dist/engine/project-dna/ai-tool-detector.d.ts +12 -0
  42. package/dist/engine/project-dna/ai-tool-detector.d.ts.map +1 -0
  43. package/dist/engine/project-dna/ai-tool-detector.js +103 -0
  44. package/dist/engine/project-dna/ai-tool-detector.js.map +1 -0
  45. package/dist/engine/project-dna/rules-generator.d.ts +18 -0
  46. package/dist/engine/project-dna/rules-generator.d.ts.map +1 -0
  47. package/dist/engine/project-dna/rules-generator.js +193 -0
  48. package/dist/engine/project-dna/rules-generator.js.map +1 -0
  49. package/dist/engine/project-dna/stack-detector.d.ts +24 -0
  50. package/dist/engine/project-dna/stack-detector.d.ts.map +1 -0
  51. package/dist/engine/project-dna/stack-detector.js +309 -0
  52. package/dist/engine/project-dna/stack-detector.js.map +1 -0
  53. package/dist/index.js +10 -0
  54. package/dist/index.js.map +1 -1
  55. package/dist/storage/agent-registry-store.d.ts +11 -0
  56. package/dist/storage/agent-registry-store.d.ts.map +1 -0
  57. package/dist/storage/agent-registry-store.js +45 -0
  58. package/dist/storage/agent-registry-store.js.map +1 -0
  59. package/dist/tools/competitive-handlers.d.ts +30 -0
  60. package/dist/tools/competitive-handlers.d.ts.map +1 -0
  61. package/dist/tools/competitive-handlers.js +155 -0
  62. package/dist/tools/competitive-handlers.js.map +1 -0
  63. package/dist/tools/create-spec/post-creation.d.ts +1 -1
  64. package/dist/tools/create-spec/post-creation.d.ts.map +1 -1
  65. package/dist/tools/create-spec/post-creation.js +13 -1
  66. package/dist/tools/create-spec/post-creation.js.map +1 -1
  67. package/dist/tools/create-spec.js +1 -1
  68. package/dist/tools/create-spec.js.map +1 -1
  69. package/dist/tools/hook-generator-handler.d.ts +8 -0
  70. package/dist/tools/hook-generator-handler.d.ts.map +1 -0
  71. package/dist/tools/hook-generator-handler.js +154 -0
  72. package/dist/tools/hook-generator-handler.js.map +1 -0
  73. package/dist/tools/project-dna-handler.d.ts +34 -0
  74. package/dist/tools/project-dna-handler.d.ts.map +1 -0
  75. package/dist/tools/project-dna-handler.js +261 -0
  76. package/dist/tools/project-dna-handler.js.map +1 -0
  77. package/dist/tools/register-agent-registry.d.ts +5 -0
  78. package/dist/tools/register-agent-registry.d.ts.map +1 -0
  79. package/dist/tools/register-agent-registry.js +254 -0
  80. package/dist/tools/register-agent-registry.js.map +1 -0
  81. package/dist/tools/register-autopilot.d.ts +3 -0
  82. package/dist/tools/register-autopilot.d.ts.map +1 -0
  83. package/dist/tools/register-autopilot.js +78 -0
  84. package/dist/tools/register-autopilot.js.map +1 -0
  85. package/dist/tools/register-competitive.d.ts +3 -0
  86. package/dist/tools/register-competitive.d.ts.map +1 -0
  87. package/dist/tools/register-competitive.js +88 -0
  88. package/dist/tools/register-competitive.js.map +1 -0
  89. package/dist/tools/register-hook-generator.d.ts +3 -0
  90. package/dist/tools/register-hook-generator.d.ts.map +1 -0
  91. package/dist/tools/register-hook-generator.js +96 -0
  92. package/dist/tools/register-hook-generator.js.map +1 -0
  93. package/dist/tools/register-project-dna.d.ts +3 -0
  94. package/dist/tools/register-project-dna.d.ts.map +1 -0
  95. package/dist/tools/register-project-dna.js +43 -0
  96. package/dist/tools/register-project-dna.js.map +1 -0
  97. package/dist/tools/update-status/side-effects.d.ts.map +1 -1
  98. package/dist/tools/update-status/side-effects.js +32 -0
  99. package/dist/tools/update-status/side-effects.js.map +1 -1
  100. package/dist/types/agent-registry.d.ts +53 -0
  101. package/dist/types/agent-registry.d.ts.map +1 -0
  102. package/dist/types/agent-registry.js +2 -0
  103. package/dist/types/agent-registry.js.map +1 -0
  104. package/dist/types/autopilot.d.ts +36 -0
  105. package/dist/types/autopilot.d.ts.map +1 -0
  106. package/dist/types/autopilot.js +3 -0
  107. package/dist/types/autopilot.js.map +1 -0
  108. package/dist/types/competitive.d.ts +41 -0
  109. package/dist/types/competitive.d.ts.map +1 -0
  110. package/dist/types/competitive.js +3 -0
  111. package/dist/types/competitive.js.map +1 -0
  112. package/dist/types/hook-generator.d.ts +49 -0
  113. package/dist/types/hook-generator.d.ts.map +1 -0
  114. package/dist/types/hook-generator.js +3 -0
  115. package/dist/types/hook-generator.js.map +1 -0
  116. package/dist/types/index.d.ts +5 -0
  117. package/dist/types/index.d.ts.map +1 -1
  118. package/dist/types/index.js +5 -0
  119. package/dist/types/index.js.map +1 -1
  120. package/dist/types/project-dna.d.ts +46 -0
  121. package/dist/types/project-dna.d.ts.map +1 -0
  122. package/dist/types/project-dna.js +4 -0
  123. package/dist/types/project-dna.js.map +1 -0
  124. package/package.json +1 -1
  125. package/src/config/ai-tool-registry.json +71 -0
  126. package/src/config/autopilot-config.json +21 -0
  127. package/src/config/competitive-catalog.json +83 -0
  128. package/src/config/license-plans.json +17 -1
@@ -0,0 +1,105 @@
1
+ // engine/hook-generator/stack-hook-templates.ts — Git hook templates per stack (SPEC-416)
2
+ // ---------------------------------------------------------------------------
3
+ // Marker helpers — used by hook-merger for idempotent injection
4
+ // ---------------------------------------------------------------------------
5
+ export function markerStart(id) {
6
+ return `# <!-- planu:generated:${id} -->`;
7
+ }
8
+ export function markerEnd(id) {
9
+ return `# <!-- /planu:generated:${id} -->`;
10
+ }
11
+ // ---------------------------------------------------------------------------
12
+ // Templates
13
+ // ---------------------------------------------------------------------------
14
+ export const STACK_HOOK_TEMPLATES = {
15
+ typescript: [
16
+ {
17
+ id: 'typescript-typecheck',
18
+ phase: 'pre-commit',
19
+ stack: 'typescript',
20
+ content: 'pnpm typecheck || exit 1',
21
+ description: 'TypeScript type checking',
22
+ },
23
+ ],
24
+ eslint: [
25
+ {
26
+ id: 'eslint-fix',
27
+ phase: 'pre-commit',
28
+ stack: 'eslint',
29
+ content: 'pnpm lint --fix || exit 1',
30
+ description: 'ESLint auto-fix',
31
+ },
32
+ ],
33
+ prettier: [
34
+ {
35
+ id: 'prettier-format',
36
+ phase: 'pre-commit',
37
+ stack: 'prettier',
38
+ content: 'pnpm format || exit 1',
39
+ description: 'Prettier formatting',
40
+ },
41
+ ],
42
+ vitest: [
43
+ {
44
+ id: 'vitest-coverage',
45
+ phase: 'pre-push',
46
+ stack: 'vitest',
47
+ content: 'pnpm test:coverage || exit 1',
48
+ description: 'Vitest coverage threshold check',
49
+ },
50
+ ],
51
+ jest: [
52
+ {
53
+ id: 'jest-coverage',
54
+ phase: 'pre-push',
55
+ stack: 'jest',
56
+ content: 'pnpm test --coverage || exit 1',
57
+ description: 'Jest coverage check',
58
+ },
59
+ ],
60
+ python: [
61
+ {
62
+ id: 'python-ruff',
63
+ phase: 'pre-commit',
64
+ stack: 'python',
65
+ content: 'ruff check --fix . || exit 1',
66
+ description: 'Python ruff linting',
67
+ },
68
+ ],
69
+ go: [
70
+ {
71
+ id: 'go-vet',
72
+ phase: 'pre-commit',
73
+ stack: 'go',
74
+ content: 'go vet ./... || exit 1',
75
+ description: 'Go vet check',
76
+ },
77
+ ],
78
+ commitlint: [
79
+ {
80
+ id: 'commitlint',
81
+ phase: 'commit-msg',
82
+ stack: 'commitlint',
83
+ content: 'npx --no -- commitlint --edit "$1" || exit 1',
84
+ description: 'Conventional commits validation',
85
+ },
86
+ ],
87
+ };
88
+ // ---------------------------------------------------------------------------
89
+ // Public helper
90
+ // ---------------------------------------------------------------------------
91
+ /**
92
+ * Returns all HookSection entries matching the requested stack tokens.
93
+ * Unknown tokens are silently skipped.
94
+ */
95
+ export function getHookSectionsForStack(stack) {
96
+ const sections = [];
97
+ for (const token of stack) {
98
+ const templates = STACK_HOOK_TEMPLATES[token];
99
+ if (templates !== undefined) {
100
+ sections.push(...templates);
101
+ }
102
+ }
103
+ return sections;
104
+ }
105
+ //# sourceMappingURL=stack-hook-templates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-hook-templates.js","sourceRoot":"","sources":["../../../src/engine/hook-generator/stack-hook-templates.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAI1F,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAE9E,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,0BAA0B,EAAE,MAAM,CAAC;AAC5C,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,OAAO,2BAA2B,EAAE,MAAM,CAAC;AAC7C,CAAC;AAED,8EAA8E;AAC9E,YAAY;AACZ,8EAA8E;AAE9E,MAAM,CAAC,MAAM,oBAAoB,GAAkC;IACjE,UAAU,EAAE;QACV;YACE,EAAE,EAAE,sBAAsB;YAC1B,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,0BAA0B;YACnC,WAAW,EAAE,0BAA0B;SACxC;KACF;IACD,MAAM,EAAE;QACN;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,2BAA2B;YACpC,WAAW,EAAE,iBAAiB;SAC/B;KACF;IACD,QAAQ,EAAE;QACR;YACE,EAAE,EAAE,iBAAiB;YACrB,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,UAAU;YACjB,OAAO,EAAE,uBAAuB;YAChC,WAAW,EAAE,qBAAqB;SACnC;KACF;IACD,MAAM,EAAE;QACN;YACE,EAAE,EAAE,iBAAiB;YACrB,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,8BAA8B;YACvC,WAAW,EAAE,iCAAiC;SAC/C;KACF;IACD,IAAI,EAAE;QACJ;YACE,EAAE,EAAE,eAAe;YACnB,KAAK,EAAE,UAAU;YACjB,KAAK,EAAE,MAAM;YACb,OAAO,EAAE,gCAAgC;YACzC,WAAW,EAAE,qBAAqB;SACnC;KACF;IACD,MAAM,EAAE;QACN;YACE,EAAE,EAAE,aAAa;YACjB,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,QAAQ;YACf,OAAO,EAAE,8BAA8B;YACvC,WAAW,EAAE,qBAAqB;SACnC;KACF;IACD,EAAE,EAAE;QACF;YACE,EAAE,EAAE,QAAQ;YACZ,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,IAAI;YACX,OAAO,EAAE,wBAAwB;YACjC,WAAW,EAAE,cAAc;SAC5B;KACF;IACD,UAAU,EAAE;QACV;YACE,EAAE,EAAE,YAAY;YAChB,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,YAAY;YACnB,OAAO,EAAE,8CAA8C;YACvD,WAAW,EAAE,iCAAiC;SAC/C;KACF;CACF,CAAC;AAEF,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAe;IACrD,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,KAAK,EAAE,CAAC;QAC1B,MAAM,SAAS,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { AIToolId, AIToolProfile } from '../../types/index.js';
2
+ /**
3
+ * Detects which AI tool is active by checking detection files in priority order.
4
+ * Returns 'unknown' if no known AI tool is detected.
5
+ */
6
+ export declare function detectAITool(projectPath: string): Promise<AIToolId>;
7
+ /**
8
+ * Loads the full AI tool profile from the registry for a given tool ID.
9
+ * Returns an 'unknown' profile if the tool ID is not found.
10
+ */
11
+ export declare function loadAIToolProfile(toolId: AIToolId): Promise<AIToolProfile>;
12
+ //# sourceMappingURL=ai-tool-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-tool-detector.d.ts","sourceRoot":"","sources":["../../../src/engine/project-dna/ai-tool-detector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAqFpE;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAazE;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAoBhF"}
@@ -0,0 +1,103 @@
1
+ // Planu — project-dna/ai-tool-detector.ts
2
+ // Detects which AI tool is active in a project by checking detection files.
3
+ import { access, readFile } from 'node:fs/promises';
4
+ import { join, dirname } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ const REGISTRY_PATH = join(dirname(fileURLToPath(import.meta.url)), '../../config/ai-tool-registry.json');
7
+ let cachedRegistry = null;
8
+ async function loadRegistry() {
9
+ if (cachedRegistry !== null) {
10
+ return cachedRegistry;
11
+ }
12
+ const raw = await readFile(REGISTRY_PATH, 'utf-8');
13
+ cachedRegistry = JSON.parse(raw);
14
+ return cachedRegistry;
15
+ }
16
+ // ---------------------------------------------------------------------------
17
+ // Detection order (priority: highest first)
18
+ // ---------------------------------------------------------------------------
19
+ const DETECTION_ORDER = [
20
+ 'claude',
21
+ 'cursor',
22
+ 'windsurf',
23
+ 'gemini',
24
+ 'kiro',
25
+ 'cline',
26
+ 'copilot',
27
+ 'aider',
28
+ ];
29
+ // ---------------------------------------------------------------------------
30
+ // Helpers
31
+ // ---------------------------------------------------------------------------
32
+ async function pathExists(filePath) {
33
+ try {
34
+ await access(filePath);
35
+ return true;
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ async function anyDetectionFileExists(projectPath, detectionFiles) {
42
+ for (const f of detectionFiles) {
43
+ if (await pathExists(join(projectPath, f))) {
44
+ return true;
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+ // ---------------------------------------------------------------------------
50
+ // Public API
51
+ // ---------------------------------------------------------------------------
52
+ /**
53
+ * Detects which AI tool is active by checking detection files in priority order.
54
+ * Returns 'unknown' if no known AI tool is detected.
55
+ */
56
+ export async function detectAITool(projectPath) {
57
+ const registry = await loadRegistry();
58
+ for (const toolId of DETECTION_ORDER) {
59
+ const entry = registry.tools[toolId];
60
+ if (entry === undefined) {
61
+ continue;
62
+ }
63
+ if (await anyDetectionFileExists(projectPath, entry.detectionFiles)) {
64
+ return toolId;
65
+ }
66
+ }
67
+ return 'unknown';
68
+ }
69
+ /**
70
+ * Loads the full AI tool profile from the registry for a given tool ID.
71
+ * Returns an 'unknown' profile if the tool ID is not found.
72
+ */
73
+ export async function loadAIToolProfile(toolId) {
74
+ if (toolId === 'unknown') {
75
+ return buildUnknownProfile();
76
+ }
77
+ const registry = await loadRegistry();
78
+ const entry = registry.tools[toolId];
79
+ if (entry === undefined) {
80
+ return buildUnknownProfile();
81
+ }
82
+ return {
83
+ id: toolId,
84
+ name: entry.name,
85
+ detectionFiles: entry.detectionFiles,
86
+ rulesDir: entry.rulesDir,
87
+ rulesFile: entry.rulesFile,
88
+ rulesFormat: entry.rulesFormat,
89
+ docsUrl: entry.docsUrl,
90
+ configFile: entry.configFile,
91
+ frontmatterRequired: entry.frontmatterRequired,
92
+ };
93
+ }
94
+ function buildUnknownProfile() {
95
+ return {
96
+ id: 'unknown',
97
+ name: 'Unknown AI Tool',
98
+ detectionFiles: [],
99
+ rulesFormat: 'markdown',
100
+ docsUrl: '',
101
+ };
102
+ }
103
+ //# sourceMappingURL=ai-tool-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-tool-detector.js","sourceRoot":"","sources":["../../../src/engine/project-dna/ai-tool-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ProjectDNA, AIToolProfile } from '../../types/index.js';
2
+ /**
3
+ * Generates a rules file for a given stack token formatted for the AI tool.
4
+ * Returns null if no rule template exists for the given stack token.
5
+ */
6
+ export declare function generateRulesForStack(dna: ProjectDNA, stackToken: string): Promise<{
7
+ filePath: string;
8
+ content: string;
9
+ } | null>;
10
+ /**
11
+ * Formats rule content according to the AI tool's expected format.
12
+ */
13
+ export declare function formatRuleForAI(ruleContent: string, profile: AIToolProfile, stackToken: string): Promise<string>;
14
+ /**
15
+ * Returns the list of stack tokens that have rule templates available.
16
+ */
17
+ export declare function getSupportedStackTokens(): string[];
18
+ //# sourceMappingURL=rules-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules-generator.d.ts","sourceRoot":"","sources":["../../../src/engine/project-dna/rules-generator.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAoJtE;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAevD;AAED;;GAEG;AAEH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,aAAa,EACtB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAsBjB;AAwBD;;GAEG;AACH,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAElD"}
@@ -0,0 +1,193 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Rule templates (hardcoded — project conventions, not fetched)
3
+ // ---------------------------------------------------------------------------
4
+ const RULE_TEMPLATES = {
5
+ supabase: `# Supabase Patterns
6
+ - Always use { data, error } destructuring — never .then()
7
+ - Check error before using data: if (error) throw error
8
+ - Never expose service role key in client code
9
+ - Use RLS policies as primary auth layer
10
+ - Prefer supabase.auth.getUser() over getSession() for server-side`,
11
+ typescript: `# TypeScript Strict Patterns
12
+ - Use import type for type-only imports
13
+ - Prefer unknown over any
14
+ - Always declare return types explicitly
15
+ - Use noUncheckedIndexedAccess — array[i] is T | undefined`,
16
+ nextjs: `# Next.js App Router Patterns
17
+ - Prefer Server Components by default, Client Components only when needed
18
+ - Use server actions for mutations (not API routes)
19
+ - Call revalidatePath() after mutations
20
+ - Never use useEffect for data fetching — use async Server Components`,
21
+ vitest: `# Vitest Testing Patterns
22
+ - Use vi.mock() at module level, not inside tests
23
+ - Use vi.clearAllMocks() in beforeEach
24
+ - Prefer mockReturnValue for sync, mockResolvedValue for async
25
+ - Group with describe, test cases with it()`,
26
+ react: `# React Patterns
27
+ - Prefer functional components with hooks over class components
28
+ - Use React.memo() for expensive pure components
29
+ - Avoid prop drilling — use Context or state management
30
+ - Keep components small and single-responsibility`,
31
+ prisma: `# Prisma Patterns
32
+ - Always handle Prisma errors — catch PrismaClientKnownRequestError
33
+ - Use transactions for multi-step writes
34
+ - Never expose raw database IDs — use UUIDs or slugs
35
+ - Run prisma generate after schema changes`,
36
+ zod: `# Zod Validation Patterns
37
+ - Parse at boundaries — never trust external input without validation
38
+ - Use z.infer<typeof schema> for derived types
39
+ - Prefer .safeParse() over .parse() for user input
40
+ - Add .describe() on all fields used in LLM/MCP contexts`,
41
+ stripe: `# Stripe Patterns
42
+ - Never trust client-side amount — always verify on server
43
+ - Use webhook events for fulfillment — not redirect callbacks
44
+ - Store Stripe customer IDs, never raw card data
45
+ - Test with test mode keys, never live keys in development`,
46
+ jest: `# Jest Testing Patterns
47
+ - Use jest.mock() at module level
48
+ - Use beforeEach/afterEach for setup and cleanup
49
+ - Prefer mockResolvedValue for async mocks
50
+ - Use describe blocks to group related tests`,
51
+ fastapi: `# FastAPI Patterns
52
+ - Use Pydantic models for request/response validation
53
+ - Prefer async endpoints for I/O bound operations
54
+ - Use dependency injection for database sessions
55
+ - Add response_model to all endpoints`,
56
+ django: `# Django Patterns
57
+ - Use select_related/prefetch_related to avoid N+1 queries
58
+ - Keep views thin — move logic to services or managers
59
+ - Use Django forms or serializers for input validation
60
+ - Always use CSRF protection for state-changing endpoints`,
61
+ flask: `# Flask Patterns
62
+ - Use application factory pattern for testability
63
+ - Use blueprints to organize routes by domain
64
+ - Validate all input with marshmallow or wtforms
65
+ - Use Flask-SQLAlchemy for ORM integration`,
66
+ gin: `# Gin (Go) Patterns
67
+ - Use context cancellation — respect ctx.Done()
68
+ - Bind request data with ShouldBind — check errors
69
+ - Use middleware for cross-cutting concerns (auth, logging)
70
+ - Return consistent error responses with gin.H{}`,
71
+ axum: `# Axum (Rust) Patterns
72
+ - Use extractors for request parsing — never raw body
73
+ - Return impl IntoResponse for handler flexibility
74
+ - Use AppState for shared dependencies
75
+ - Propagate errors with ? and map_err`,
76
+ tailwind: `# Tailwind CSS Patterns
77
+ - Use semantic class groupings — layout, spacing, typography
78
+ - Extract repeated patterns to components, not @apply
79
+ - Use responsive prefixes consistently (sm/md/lg/xl)
80
+ - Avoid arbitrary values — prefer design tokens`,
81
+ };
82
+ // ---------------------------------------------------------------------------
83
+ // Glob patterns by stack token
84
+ // ---------------------------------------------------------------------------
85
+ const GLOB_PATTERNS = {
86
+ supabase: ['**/*.ts', '**/*.tsx'],
87
+ typescript: ['**/*.ts', '**/*.tsx'],
88
+ nextjs: ['**/*.ts', '**/*.tsx', '**/*.js', '**/*.jsx'],
89
+ vitest: ['**/*.test.ts', '**/*.spec.ts', '**/*.test.tsx'],
90
+ react: ['**/*.tsx', '**/*.jsx'],
91
+ prisma: ['prisma/**', '**/*.ts'],
92
+ zod: ['**/*.ts', '**/*.tsx'],
93
+ stripe: ['**/*.ts', '**/*.tsx'],
94
+ jest: ['**/*.test.ts', '**/*.test.js', '**/*.spec.ts'],
95
+ fastapi: ['**/*.py'],
96
+ django: ['**/*.py'],
97
+ flask: ['**/*.py'],
98
+ gin: ['**/*.go'],
99
+ axum: ['**/*.rs'],
100
+ tailwind: ['**/*.tsx', '**/*.jsx', '**/*.html'],
101
+ };
102
+ // ---------------------------------------------------------------------------
103
+ // Format helpers
104
+ // ---------------------------------------------------------------------------
105
+ function buildMdcFrontmatter(stackToken, globs) {
106
+ const globsJson = JSON.stringify(globs);
107
+ const description = `${capitalize(stackToken)} patterns for this project`;
108
+ return `---\ndescription: ${description}\nalwaysApply: false\nglobs: ${globsJson}\n---\n\n`;
109
+ }
110
+ function capitalize(s) {
111
+ if (s.length === 0) {
112
+ return s;
113
+ }
114
+ return s.charAt(0).toUpperCase() + s.slice(1);
115
+ }
116
+ function buildAppendMarkers(stackToken, content) {
117
+ const marker = `<!-- planu:${stackToken} -->`;
118
+ const endMarker = `<!-- /planu:${stackToken} -->`;
119
+ return `\n${marker}\n${content}\n${endMarker}\n`;
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Public API
123
+ // ---------------------------------------------------------------------------
124
+ /**
125
+ * Generates a rules file for a given stack token formatted for the AI tool.
126
+ * Returns null if no rule template exists for the given stack token.
127
+ */
128
+ export async function generateRulesForStack(dna, stackToken) {
129
+ const template = RULE_TEMPLATES[stackToken];
130
+ if (template === undefined) {
131
+ return null;
132
+ }
133
+ const { aiToolProfile } = dna;
134
+ const content = await formatRuleForAI(template, aiToolProfile, stackToken);
135
+ const filePath = resolveFilePath(aiToolProfile, stackToken);
136
+ if (filePath === null) {
137
+ return null;
138
+ }
139
+ return { filePath, content };
140
+ }
141
+ /**
142
+ * Formats rule content according to the AI tool's expected format.
143
+ */
144
+ // eslint-disable-next-line @typescript-eslint/require-await
145
+ export async function formatRuleForAI(ruleContent, profile, stackToken) {
146
+ switch (profile.rulesFormat) {
147
+ case 'mdc': {
148
+ const globs = GLOB_PATTERNS[stackToken] ?? ['**/*.ts'];
149
+ return buildMdcFrontmatter(stackToken, globs) + ruleContent;
150
+ }
151
+ case 'markdown-append': {
152
+ return buildAppendMarkers(stackToken, ruleContent);
153
+ }
154
+ case 'yaml': {
155
+ // For aider: wrap content as a YAML comment block
156
+ const lines = ruleContent
157
+ .split('\n')
158
+ .map((l) => `# ${l}`)
159
+ .join('\n');
160
+ return `\n# === Planu: ${capitalize(stackToken)} Patterns ===\n${lines}\n`;
161
+ }
162
+ case 'markdown':
163
+ default: {
164
+ return ruleContent + '\n';
165
+ }
166
+ }
167
+ }
168
+ /**
169
+ * Resolves the file path where the rule should be written for a given AI tool.
170
+ */
171
+ function resolveFilePath(profile, stackToken) {
172
+ if (profile.rulesFormat === 'mdc' && profile.rulesDir !== undefined) {
173
+ return `${profile.rulesDir}${stackToken}.mdc`;
174
+ }
175
+ if (profile.rulesFormat === 'markdown' && profile.rulesDir !== undefined) {
176
+ return `${profile.rulesDir}${stackToken}.md`;
177
+ }
178
+ if ((profile.rulesFormat === 'markdown-append' || profile.rulesFormat === 'yaml') &&
179
+ profile.rulesFile !== undefined) {
180
+ return profile.rulesFile;
181
+ }
182
+ if (profile.rulesFormat === 'markdown' && profile.configFile !== undefined) {
183
+ return profile.configFile;
184
+ }
185
+ return null;
186
+ }
187
+ /**
188
+ * Returns the list of stack tokens that have rule templates available.
189
+ */
190
+ export function getSupportedStackTokens() {
191
+ return Object.keys(RULE_TEMPLATES);
192
+ }
193
+ //# sourceMappingURL=rules-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rules-generator.js","sourceRoot":"","sources":["../../../src/engine/project-dna/rules-generator.ts"],"names":[],"mappings":"AAIA,8EAA8E;AAC9E,gEAAgE;AAChE,8EAA8E;AAE9E,MAAM,cAAc,GAA2B;IAC7C,QAAQ,EAAE;;;;;mEAKuD;IAEjE,UAAU,EAAE;;;;2DAI6C;IAEzD,MAAM,EAAE;;;;sEAI4D;IAEpE,MAAM,EAAE;;;;4CAIkC;IAE1C,KAAK,EAAE;;;;kDAIyC;IAEhD,MAAM,EAAE;;;;2CAIiC;IAEzC,GAAG,EAAE;;;;yDAIkD;IAEvD,MAAM,EAAE;;;;2DAIiD;IAEzD,IAAI,EAAE;;;;6CAIqC;IAE3C,OAAO,EAAE;;;;sCAI2B;IAEpC,MAAM,EAAE;;;;0DAIgD;IAExD,KAAK,EAAE;;;;2CAIkC;IAEzC,GAAG,EAAE;;;;iDAI0C;IAE/C,IAAI,EAAE;;;;sCAI8B;IAEpC,QAAQ,EAAE;;;;gDAIoC;CAC/C,CAAC;AAEF,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAE9E,MAAM,aAAa,GAA6B;IAC9C,QAAQ,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IACjC,UAAU,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IACnC,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,CAAC;IACtD,MAAM,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,eAAe,CAAC;IACzD,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC;IAC/B,MAAM,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;IAChC,GAAG,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAC5B,MAAM,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,IAAI,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,cAAc,CAAC;IACtD,OAAO,EAAE,CAAC,SAAS,CAAC;IACpB,MAAM,EAAE,CAAC,SAAS,CAAC;IACnB,KAAK,EAAE,CAAC,SAAS,CAAC;IAClB,GAAG,EAAE,CAAC,SAAS,CAAC;IAChB,IAAI,EAAE,CAAC,SAAS,CAAC;IACjB,QAAQ,EAAE,CAAC,UAAU,EAAE,UAAU,EAAE,WAAW,CAAC;CAChD,CAAC;AAEF,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,SAAS,mBAAmB,CAAC,UAAkB,EAAE,KAAe;IAC9D,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,GAAG,UAAU,CAAC,UAAU,CAAC,4BAA4B,CAAC;IAC1E,OAAO,qBAAqB,WAAW,gCAAgC,SAAS,WAAW,CAAC;AAC9F,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,OAAO,CAAC,CAAC;IACX,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,kBAAkB,CAAC,UAAkB,EAAE,OAAe;IAC7D,MAAM,MAAM,GAAG,cAAc,UAAU,MAAM,CAAC;IAC9C,MAAM,SAAS,GAAG,eAAe,UAAU,MAAM,CAAC;IAClD,OAAO,KAAK,MAAM,KAAK,OAAO,KAAK,SAAS,IAAI,CAAC;AACnD,CAAC;AAED,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAe,EACf,UAAkB;IAElB,MAAM,QAAQ,GAAG,cAAc,CAAC,UAAU,CAAC,CAAC;IAC5C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IAE3E,MAAM,QAAQ,GAAG,eAAe,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAC5D,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED;;GAEG;AACH,4DAA4D;AAC5D,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,WAAmB,EACnB,OAAsB,EACtB,UAAkB;IAElB,QAAQ,OAAO,CAAC,WAAW,EAAE,CAAC;QAC5B,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,KAAK,GAAG,aAAa,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,OAAO,mBAAmB,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,WAAW,CAAC;QAC9D,CAAC;QACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,OAAO,kBAAkB,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;QACrD,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,kDAAkD;YAClD,MAAM,KAAK,GAAG,WAAW;iBACtB,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC;iBACpB,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO,kBAAkB,UAAU,CAAC,UAAU,CAAC,kBAAkB,KAAK,IAAI,CAAC;QAC7E,CAAC;QACD,KAAK,UAAU,CAAC;QAChB,OAAO,CAAC,CAAC,CAAC;YACR,OAAO,WAAW,GAAG,IAAI,CAAC;QAC5B,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,eAAe,CAAC,OAAsB,EAAE,UAAkB;IACjE,IAAI,OAAO,CAAC,WAAW,KAAK,KAAK,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACpE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,UAAU,MAAM,CAAC;IAChD,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,KAAK,UAAU,IAAI,OAAO,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QACzE,OAAO,GAAG,OAAO,CAAC,QAAQ,GAAG,UAAU,KAAK,CAAC;IAC/C,CAAC;IACD,IACE,CAAC,OAAO,CAAC,WAAW,KAAK,iBAAiB,IAAI,OAAO,CAAC,WAAW,KAAK,MAAM,CAAC;QAC7E,OAAO,CAAC,SAAS,KAAK,SAAS,EAC/B,CAAC;QACD,OAAO,OAAO,CAAC,SAAS,CAAC;IAC3B,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,KAAK,UAAU,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QAC3E,OAAO,OAAO,CAAC,UAAU,CAAC;IAC5B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB;IACrC,OAAO,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Detects the technology stack by reading common manifest files.
3
+ * Returns normalized stack tokens (e.g. 'nextjs', 'supabase', 'vitest').
4
+ */
5
+ export declare function detectStack(projectPath: string): Promise<string[]>;
6
+ type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun' | 'pip' | 'cargo' | 'go' | 'unknown';
7
+ /**
8
+ * Detects the package manager by checking lock files and manifests.
9
+ */
10
+ export declare function detectPackageManager(projectPath: string): Promise<PackageManager>;
11
+ /**
12
+ * Detects the primary testing framework based on stack tokens and config files.
13
+ */
14
+ export declare function detectTestingFramework(projectPath: string, stack: string[]): Promise<string | undefined>;
15
+ /**
16
+ * Detects the primary linter based on config files and stack tokens.
17
+ */
18
+ export declare function detectLinter(projectPath: string, stack: string[]): Promise<string | undefined>;
19
+ /**
20
+ * Detects the primary code formatter based on config files and stack tokens.
21
+ */
22
+ export declare function detectFormatter(projectPath: string, stack: string[]): Promise<string | undefined>;
23
+ export {};
24
+ //# sourceMappingURL=stack-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack-detector.d.ts","sourceRoot":"","sources":["../../../src/engine/project-dna/stack-detector.ts"],"names":[],"mappings":"AA8BA;;;GAGG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAWxE;AAmKD,KAAK,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAE3F;;GAEG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBvF;AAMD;;GAEG;AACH,wBAAsB,sBAAsB,CAC1C,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAe7B;AAMD;;GAEG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA+B7B;AAMD;;GAEG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwB7B"}