@eskoubar95/spec 0.1.0 → 0.1.2
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/commands/help.d.ts +5 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +23 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +30 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.d.ts +5 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +88 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/update.d.ts +5 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +72 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/workspace.d.ts +5 -0
- package/dist/commands/workspace.d.ts.map +1 -0
- package/dist/commands/workspace.js +17 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/index.js +42 -9
- package/dist/index.js.map +1 -1
- package/dist/lib/backup-cursor.d.ts +16 -0
- package/dist/lib/backup-cursor.d.ts.map +1 -0
- package/dist/lib/backup-cursor.js +50 -0
- package/dist/lib/backup-cursor.js.map +1 -0
- package/dist/lib/copy-template.d.ts +9 -1
- package/dist/lib/copy-template.d.ts.map +1 -1
- package/dist/lib/copy-template.js +94 -3
- package/dist/lib/copy-template.js.map +1 -1
- package/dist/lib/cursor-detection.d.ts +6 -0
- package/dist/lib/cursor-detection.d.ts.map +1 -0
- package/dist/lib/cursor-detection.js +31 -0
- package/dist/lib/cursor-detection.js.map +1 -0
- package/dist/lib/detection.d.ts +25 -0
- package/dist/lib/detection.d.ts.map +1 -0
- package/dist/lib/detection.js +186 -0
- package/dist/lib/detection.js.map +1 -0
- package/dist/lib/install-existing.d.ts +6 -0
- package/dist/lib/install-existing.d.ts.map +1 -0
- package/dist/lib/install-existing.js +63 -0
- package/dist/lib/install-existing.js.map +1 -0
- package/dist/lib/project-name.d.ts +7 -0
- package/dist/lib/project-name.d.ts.map +1 -0
- package/dist/lib/project-name.js +13 -0
- package/dist/lib/project-name.js.map +1 -0
- package/dist/lib/prompts.d.ts +6 -5
- package/dist/lib/prompts.d.ts.map +1 -1
- package/dist/lib/prompts.js +114 -0
- package/dist/lib/prompts.js.map +1 -1
- package/dist/lib/version-check.d.ts +21 -0
- package/dist/lib/version-check.d.ts.map +1 -0
- package/dist/lib/version-check.js +49 -0
- package/dist/lib/version-check.js.map +1 -0
- package/dist/lib/workspace.d.ts +7 -0
- package/dist/lib/workspace.d.ts.map +1 -0
- package/dist/lib/workspace.js +38 -0
- package/dist/lib/workspace.js.map +1 -0
- package/dist/types.d.ts +32 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +2 -2
- package/template/.cursor/commands/_shared/activation.md +220 -0
- package/template/.cursor/commands/_shared/coderabbit-integration.md +278 -0
- package/template/.cursor/commands/_shared/command-stacks.md +124 -0
- package/template/.cursor/commands/_shared/deployment-detection.md +294 -0
- package/template/.cursor/commands/_shared/detection.md +277 -0
- package/template/.cursor/commands/_shared/documentation-lookup.md +321 -0
- package/template/.cursor/commands/_shared/git-workflow.md +288 -0
- package/template/.cursor/commands/_shared/github-helpers.md +337 -0
- package/template/.cursor/commands/_shared/github-workflows.md +351 -0
- package/template/.cursor/commands/_shared/helper-metadata.md +481 -0
- package/template/.cursor/commands/_shared/linear-automation.md +388 -0
- package/template/.cursor/commands/_shared/linear-helpers.md +254 -0
- package/template/.cursor/commands/_shared/performance-monitoring.md +369 -0
- package/template/.cursor/commands/_shared/pr-description.md +279 -0
- package/template/.cursor/commands/_shared/retrospective-spec-creation.md +977 -0
- package/template/.cursor/commands/_shared/scaling.md +264 -0
- package/template/.cursor/commands/_shared/state-assertions.md +174 -0
- package/template/.cursor/commands/_shared/test-automation.md +388 -0
- package/template/.cursor/commands/_shared/verification-checkpoints.md +145 -0
- package/template/.cursor/commands/spec/audit.md +240 -0
- package/template/.cursor/commands/spec/evolve.md +163 -0
- package/template/.cursor/commands/spec/sync.md +196 -0
- package/template/.cursor/commands/tools/refactor.md +555 -0
- package/template/.cursor/rules/10-engineering.mdc +149 -0
- package/template/.cursor/rules/11-design.mdc +129 -0
- package/template/.cursor/rules/12-business.mdc +132 -0
- package/template/.cursor/rules/20-nextjs.mdc +146 -0
- package/template/.cursor/rules/21-api-design.mdc +176 -0
- package/template/.cursor/rules/30-database.mdc +183 -0
- package/template/.cursor/rules/31-testing.mdc +191 -0
- package/template/.cursor/scripts/validate-helpers.js +254 -0
- package/template/.sdd/detection-cache.json +1 -0
- package/template/.sdd/install-info.json +1 -0
- package/template/.sdd/version +1 -0
- package/template/spec/00-root-spec.md +8 -1
- package/template/work/backlog/tasks.local.md +92 -0
package/dist/lib/prompts.js
CHANGED
|
@@ -1,8 +1,31 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
|
+
import { normalizeProjectName } from './project-name.js';
|
|
3
|
+
import { isRunningInCursor } from './cursor-detection.js';
|
|
4
|
+
import { isExistingProject } from './detection.js';
|
|
2
5
|
/**
|
|
3
6
|
* Prompts the user for project initialization options
|
|
4
7
|
*/
|
|
5
8
|
export async function promptInit() {
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
// Smart mode detection: Check if in Cursor + existing project
|
|
11
|
+
const inCursor = isRunningInCursor();
|
|
12
|
+
const isExisting = await isExistingProject(cwd);
|
|
13
|
+
if (inCursor && isExisting) {
|
|
14
|
+
// Auto-suggest install mode
|
|
15
|
+
const { shouldInstall } = await inquirer.prompt([
|
|
16
|
+
{
|
|
17
|
+
type: 'confirm',
|
|
18
|
+
name: 'shouldInstall',
|
|
19
|
+
message: 'Detected you\'re in an existing project in Cursor. Install SDD to this project?',
|
|
20
|
+
default: true,
|
|
21
|
+
},
|
|
22
|
+
]);
|
|
23
|
+
if (shouldInstall) {
|
|
24
|
+
// This will be handled by the init command
|
|
25
|
+
throw new Error('SWITCH_TO_INSTALL');
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// Normal init flow
|
|
6
29
|
const answers = await inquirer.prompt([
|
|
7
30
|
{
|
|
8
31
|
type: 'input',
|
|
@@ -18,6 +41,14 @@ export async function promptInit() {
|
|
|
18
41
|
}
|
|
19
42
|
return true;
|
|
20
43
|
},
|
|
44
|
+
filter: (input) => {
|
|
45
|
+
// Normalize project name: convert spaces to hyphens, lowercase
|
|
46
|
+
return normalizeProjectName(input);
|
|
47
|
+
},
|
|
48
|
+
transformer: (input) => {
|
|
49
|
+
// Show normalized version while typing
|
|
50
|
+
return normalizeProjectName(input);
|
|
51
|
+
},
|
|
21
52
|
},
|
|
22
53
|
{
|
|
23
54
|
type: 'list',
|
|
@@ -35,7 +66,90 @@ export async function promptInit() {
|
|
|
35
66
|
message: 'Initialize git repository?',
|
|
36
67
|
default: true,
|
|
37
68
|
},
|
|
69
|
+
...(isRunningInCursor() ? [] : [
|
|
70
|
+
{
|
|
71
|
+
type: 'confirm',
|
|
72
|
+
name: 'openInCursor',
|
|
73
|
+
message: 'Open in Cursor?',
|
|
74
|
+
default: true,
|
|
75
|
+
},
|
|
76
|
+
]),
|
|
38
77
|
]);
|
|
39
78
|
return answers;
|
|
40
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Prompts the user for installation options
|
|
82
|
+
*/
|
|
83
|
+
export async function promptInstall(projectPath) {
|
|
84
|
+
const inCursor = isRunningInCursor();
|
|
85
|
+
const isExisting = await isExistingProject(projectPath);
|
|
86
|
+
// Auto-detect project path if in Cursor and current directory is a project
|
|
87
|
+
let finalProjectPath = projectPath;
|
|
88
|
+
if (inCursor && isExisting && projectPath === process.cwd()) {
|
|
89
|
+
// Use current directory automatically
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
const { path: selectedPath } = await inquirer.prompt([
|
|
93
|
+
{
|
|
94
|
+
type: 'input',
|
|
95
|
+
name: 'path',
|
|
96
|
+
message: 'Project path:',
|
|
97
|
+
default: projectPath,
|
|
98
|
+
validate: (input) => {
|
|
99
|
+
if (!input.trim()) {
|
|
100
|
+
return 'Project path cannot be empty';
|
|
101
|
+
}
|
|
102
|
+
return true;
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
]);
|
|
106
|
+
finalProjectPath = selectedPath;
|
|
107
|
+
}
|
|
108
|
+
// Check if .cursor folder exists
|
|
109
|
+
const { hasCursorFolder } = await import('./backup-cursor.js').then(m => m.checkCursorFolder(finalProjectPath));
|
|
110
|
+
const answers = await inquirer.prompt([
|
|
111
|
+
{
|
|
112
|
+
type: 'list',
|
|
113
|
+
name: 'backupStrategy',
|
|
114
|
+
message: hasCursorFolder ? 'Backup existing .cursor folder or merge?' : 'Backup strategy:',
|
|
115
|
+
choices: [
|
|
116
|
+
{ name: 'Backup existing .cursor folder', value: 'backup' },
|
|
117
|
+
{ name: 'Merge with existing', value: 'merge' },
|
|
118
|
+
],
|
|
119
|
+
default: 'backup',
|
|
120
|
+
when: hasCursorFolder,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
type: 'confirm',
|
|
124
|
+
name: 'installSpecFolders',
|
|
125
|
+
message: 'Install spec/ and work/ folders?',
|
|
126
|
+
default: true,
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
type: 'confirm',
|
|
130
|
+
name: 'createRootSpec',
|
|
131
|
+
message: 'Create spec/00-root-spec.md if missing?',
|
|
132
|
+
default: true,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: 'confirm',
|
|
136
|
+
name: 'initializeDetection',
|
|
137
|
+
message: 'Initialize detection cache?',
|
|
138
|
+
default: true,
|
|
139
|
+
},
|
|
140
|
+
...(isRunningInCursor() ? [] : [
|
|
141
|
+
{
|
|
142
|
+
type: 'confirm',
|
|
143
|
+
name: 'openInCursor',
|
|
144
|
+
message: 'Open in Cursor?',
|
|
145
|
+
default: true,
|
|
146
|
+
},
|
|
147
|
+
]),
|
|
148
|
+
]);
|
|
149
|
+
return {
|
|
150
|
+
...answers,
|
|
151
|
+
projectPath: finalProjectPath,
|
|
152
|
+
backupStrategy: answers.backupStrategy || 'backup', // Default if not asked
|
|
153
|
+
};
|
|
154
|
+
}
|
|
41
155
|
//# sourceMappingURL=prompts.js.map
|
package/dist/lib/prompts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.js","sourceRoot":"","sources":["../../src/lib/prompts.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface VersionInfo {
|
|
2
|
+
currentVersion?: string;
|
|
3
|
+
latestVersion: string;
|
|
4
|
+
needsUpdate: boolean;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Gets the current package version from package.json
|
|
8
|
+
*/
|
|
9
|
+
export declare function getPackageVersion(): Promise<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Checks the current version and determines if an update is needed
|
|
12
|
+
* @param projectPath - Path to the project
|
|
13
|
+
*/
|
|
14
|
+
export declare function checkVersion(projectPath: string): Promise<VersionInfo>;
|
|
15
|
+
/**
|
|
16
|
+
* Updates the version file in the project
|
|
17
|
+
* @param projectPath - Path to the project
|
|
18
|
+
* @param version - Version string to write
|
|
19
|
+
*/
|
|
20
|
+
export declare function updateVersionFile(projectPath: string, version: string): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=version-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../src/lib/version-check.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CASzD;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAoB5E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI3F"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
/**
|
|
4
|
+
* Gets the current package version from package.json
|
|
5
|
+
*/
|
|
6
|
+
export async function getPackageVersion() {
|
|
7
|
+
const packageJsonPath = path.resolve(import.meta.url.replace('file://', ''), '../../../package.json');
|
|
8
|
+
try {
|
|
9
|
+
const packageJson = await fs.readJson(packageJsonPath);
|
|
10
|
+
return packageJson.version || '0.1.0';
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return '0.1.0'; // Fallback
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Checks the current version and determines if an update is needed
|
|
18
|
+
* @param projectPath - Path to the project
|
|
19
|
+
*/
|
|
20
|
+
export async function checkVersion(projectPath) {
|
|
21
|
+
const versionPath = path.join(projectPath, '.sdd', 'version');
|
|
22
|
+
const latestVersion = await getPackageVersion();
|
|
23
|
+
let currentVersion;
|
|
24
|
+
if (await fs.pathExists(versionPath)) {
|
|
25
|
+
try {
|
|
26
|
+
currentVersion = (await fs.readFile(versionPath, 'utf-8')).trim();
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// Ignore read errors
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const needsUpdate = currentVersion !== undefined && currentVersion !== latestVersion;
|
|
33
|
+
return {
|
|
34
|
+
currentVersion,
|
|
35
|
+
latestVersion,
|
|
36
|
+
needsUpdate,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Updates the version file in the project
|
|
41
|
+
* @param projectPath - Path to the project
|
|
42
|
+
* @param version - Version string to write
|
|
43
|
+
*/
|
|
44
|
+
export async function updateVersionFile(projectPath, version) {
|
|
45
|
+
const versionPath = path.join(projectPath, '.sdd', 'version');
|
|
46
|
+
await fs.ensureDir(path.dirname(versionPath));
|
|
47
|
+
await fs.writeFile(versionPath, version, 'utf-8');
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../src/lib/version-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1B,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAC;IAEtG,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;QACvD,OAAO,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC,CAAC,WAAW;IAC7B,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB;IACpD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,MAAM,iBAAiB,EAAE,CAAC;IAEhD,IAAI,cAAkC,CAAC;IACvC,IAAI,MAAM,EAAE,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,cAAc,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACpE,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,cAAc,KAAK,SAAS,IAAI,cAAc,KAAK,aAAa,CAAC;IAErF,OAAO;QACL,cAAc;QACd,aAAa;QACb,WAAW;KACZ,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,WAAmB,EAAE,OAAe;IAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC9D,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opens a project in Cursor IDE
|
|
3
|
+
* @param projectPath - Path to the project to open
|
|
4
|
+
* @param skipIfAlreadyInCursor - Skip if already running in Cursor (default: true)
|
|
5
|
+
*/
|
|
6
|
+
export declare function openInCursor(projectPath: string, skipIfAlreadyInCursor?: boolean): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=workspace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/lib/workspace.ts"],"names":[],"mappings":"AAMA;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,qBAAqB,GAAE,OAAc,GACpC,OAAO,CAAC,IAAI,CAAC,CA2Bf"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { exec } from 'child_process';
|
|
2
|
+
import { promisify } from 'util';
|
|
3
|
+
import { isRunningInCursor } from './cursor-detection.js';
|
|
4
|
+
const execAsync = promisify(exec);
|
|
5
|
+
/**
|
|
6
|
+
* Opens a project in Cursor IDE
|
|
7
|
+
* @param projectPath - Path to the project to open
|
|
8
|
+
* @param skipIfAlreadyInCursor - Skip if already running in Cursor (default: true)
|
|
9
|
+
*/
|
|
10
|
+
export async function openInCursor(projectPath, skipIfAlreadyInCursor = true) {
|
|
11
|
+
// Check if already in Cursor
|
|
12
|
+
if (skipIfAlreadyInCursor && isRunningInCursor()) {
|
|
13
|
+
console.log('\n✓ You are already in Cursor. No need to open the project.\n');
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
// Check if cursor command is available
|
|
17
|
+
try {
|
|
18
|
+
await execAsync('which cursor');
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
console.log('\n⚠️ Cursor command not found in PATH.');
|
|
22
|
+
console.log(' Please open the project manually in Cursor IDE.');
|
|
23
|
+
console.log(` Path: ${projectPath}\n`);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// Open project in Cursor
|
|
27
|
+
try {
|
|
28
|
+
await execAsync(`cursor "${projectPath}"`);
|
|
29
|
+
console.log(`\n✓ Opening project in Cursor...\n`);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
console.error('\n❌ Error opening project in Cursor:');
|
|
33
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
34
|
+
console.log(`\n Please open the project manually in Cursor IDE.`);
|
|
35
|
+
console.log(` Path: ${projectPath}\n`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=workspace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/lib/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,SAAS,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;AAElC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAAmB,EACnB,wBAAiC,IAAI;IAErC,6BAA6B;IAC7B,IAAI,qBAAqB,IAAI,iBAAiB,EAAE,EAAE,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;QAC7E,OAAO;IACT,CAAC;IAED,uCAAuC;IACvC,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,cAAc,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;QACvD,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,IAAI,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,WAAW,WAAW,GAAG,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,MAAM,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC9E,OAAO,CAAC,GAAG,CAAC,sDAAsD,CAAC,CAAC;QACpE,OAAO,CAAC,GAAG,CAAC,YAAY,WAAW,IAAI,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface InitAnswers {
|
|
2
|
+
projectName: string;
|
|
3
|
+
taskMode: 'local' | 'linear';
|
|
4
|
+
gitInit: boolean;
|
|
5
|
+
openInCursor?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface InstallAnswers {
|
|
8
|
+
projectPath: string;
|
|
9
|
+
backupStrategy: 'backup' | 'merge';
|
|
10
|
+
installSpecFolders: boolean;
|
|
11
|
+
createRootSpec: boolean;
|
|
12
|
+
initializeDetection: boolean;
|
|
13
|
+
openInCursor?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface ProjectInfo {
|
|
16
|
+
hasCursorFolder: boolean;
|
|
17
|
+
hasCodebase: boolean;
|
|
18
|
+
projectType?: string;
|
|
19
|
+
techStack?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface DetectionResults {
|
|
22
|
+
projectType: string;
|
|
23
|
+
projectSize: 'small' | 'medium' | 'large' | 'enterprise';
|
|
24
|
+
technologies: string[];
|
|
25
|
+
phase?: 'initialization' | 'expansion' | 'maintenance' | 'migration' | 'legacy';
|
|
26
|
+
}
|
|
27
|
+
export interface VersionInfo {
|
|
28
|
+
currentVersion?: string;
|
|
29
|
+
latestVersion: string;
|
|
30
|
+
needsUpdate: boolean;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,QAAQ,GAAG,OAAO,CAAC;IACnC,kBAAkB,EAAE,OAAO,CAAC;IAC5B,cAAc,EAAE,OAAO,CAAC;IACxB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,YAAY,CAAC;IACzD,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,CAAC,EAAE,gBAAgB,GAAG,WAAW,GAAG,aAAa,GAAG,WAAW,GAAG,QAAQ,CAAC;CACjF;AAED,MAAM,WAAW,WAAW;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
CHANGED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
helper_id: activation
|
|
3
|
+
load_when:
|
|
4
|
+
- always
|
|
5
|
+
sections:
|
|
6
|
+
matching:
|
|
7
|
+
title: "Match detection results"
|
|
8
|
+
lines: [1, 50]
|
|
9
|
+
dependencies:
|
|
10
|
+
title: "Check rule dependencies"
|
|
11
|
+
lines: [51, 100]
|
|
12
|
+
activation:
|
|
13
|
+
title: "Activate matching rules"
|
|
14
|
+
lines: [101, 150]
|
|
15
|
+
always_load: true
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Rule Activation Engine
|
|
19
|
+
|
|
20
|
+
This engine activates relevant rules based on project detection results.
|
|
21
|
+
|
|
22
|
+
## Purpose
|
|
23
|
+
|
|
24
|
+
After project detection, this engine:
|
|
25
|
+
- Matches detection results against rule metadata
|
|
26
|
+
- Activates relevant rules based on activation conditions
|
|
27
|
+
- Handles rule dependencies (requires field)
|
|
28
|
+
- Outputs active rule list with categories
|
|
29
|
+
|
|
30
|
+
## Activation Algorithm
|
|
31
|
+
|
|
32
|
+
**Step 1: Always activate foundation rules**
|
|
33
|
+
- `00-pos.mdc` - Project Operating System (always apply)
|
|
34
|
+
- `01-sdd.mdc` - Spec-Driven Development (always apply)
|
|
35
|
+
- `02-work-mode.mdc` - Work Mode (always apply)
|
|
36
|
+
|
|
37
|
+
**Step 2: Match detection results against rule metadata**
|
|
38
|
+
|
|
39
|
+
**2.1: Check for tech stack in spec (if available)**
|
|
40
|
+
- Read tech stack from `spec/08-infrastructure.md` or `spec/02-architecture.md`
|
|
41
|
+
- If tech stack found → use it as primary source for framework/tool detection
|
|
42
|
+
- For each framework/tool in tech stack:
|
|
43
|
+
- Check if rule exists (e.g., `20-nextjs.mdc` for "Next.js")
|
|
44
|
+
- If rule exists → add to activation queue
|
|
45
|
+
- If rule doesn't exist → note for user guidance: "Framework [X] detected but no specific rule exists. Should I create a framework-specific rule, or use general patterns with Context7 documentation lookup?"
|
|
46
|
+
|
|
47
|
+
**2.2: Match detection results against rule metadata**
|
|
48
|
+
|
|
49
|
+
**Rule Metadata Cache Strategy:**
|
|
50
|
+
|
|
51
|
+
1. **Check cache validity:**
|
|
52
|
+
- Check if `.sdd/rule-metadata-cache.json` exists
|
|
53
|
+
- Check if cache is valid (compare rule file modification times with cache timestamp)
|
|
54
|
+
- If cache valid → use cached metadata
|
|
55
|
+
- If cache invalid or missing → rebuild cache
|
|
56
|
+
|
|
57
|
+
2. **Rebuild cache (if needed):**
|
|
58
|
+
- Scan all rule files in `.cursor/rules/`
|
|
59
|
+
- Extract metadata (activation conditions, requires, etc.)
|
|
60
|
+
- Store in `.sdd/rule-metadata-cache.json`:
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"rules": {
|
|
64
|
+
"20-nextjs.mdc": {
|
|
65
|
+
"activation": {
|
|
66
|
+
"projectTypes": ["web-app"],
|
|
67
|
+
"technologies": ["nextjs"]
|
|
68
|
+
},
|
|
69
|
+
"requires": ["10-engineering"]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"last_updated": "2026-01-07T12:00:00Z",
|
|
73
|
+
"rule_files": {
|
|
74
|
+
"20-nextjs.mdc": {
|
|
75
|
+
"mtime": 1704633600000
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
3. **Match detection results against cached metadata:**
|
|
82
|
+
- For each rule in cache:
|
|
83
|
+
- Check if rule matches detection:
|
|
84
|
+
- `projectTypes` contains detected project type
|
|
85
|
+
- `projectSizes` contains detected project size
|
|
86
|
+
- `projectPhases` contains detected project phase
|
|
87
|
+
- `technologies` contains any detected technology (from package.json or spec tech stack)
|
|
88
|
+
- If match → add to activation queue
|
|
89
|
+
|
|
90
|
+
**Cache Invalidation:**
|
|
91
|
+
- Invalidate cache if any rule file is modified (compare mtime)
|
|
92
|
+
- Invalidate cache if new rule files are added
|
|
93
|
+
- Invalidate cache if rule files are deleted
|
|
94
|
+
- Rebuild cache automatically when invalid
|
|
95
|
+
|
|
96
|
+
**Step 3: Check rule dependencies**
|
|
97
|
+
|
|
98
|
+
For each rule in activation queue:
|
|
99
|
+
1. Check `requires` field
|
|
100
|
+
2. If required rules not active → activate them first
|
|
101
|
+
3. Handle circular dependencies (warn and break cycle)
|
|
102
|
+
|
|
103
|
+
**Step 4: Activate matching rules**
|
|
104
|
+
|
|
105
|
+
Activate rules in dependency order:
|
|
106
|
+
1. Foundation rules (already active)
|
|
107
|
+
2. Domain rules (10-engineering, 11-design, 12-business)
|
|
108
|
+
3. Technology rules (20-nextjs, 21-api-design, 30-database, etc.)
|
|
109
|
+
|
|
110
|
+
**Step 5: Output active rule list**
|
|
111
|
+
|
|
112
|
+
```markdown
|
|
113
|
+
**Active Rule Sets:**
|
|
114
|
+
|
|
115
|
+
**Foundation (always active):**
|
|
116
|
+
- 00-pos.mdc - Project Operating System
|
|
117
|
+
- 01-sdd.mdc - Spec-Driven Development
|
|
118
|
+
- 02-work-mode.mdc - Work Mode
|
|
119
|
+
|
|
120
|
+
**Domain (context-based):**
|
|
121
|
+
- 10-engineering.mdc - Engineering patterns
|
|
122
|
+
- 11-design.mdc - Design patterns
|
|
123
|
+
|
|
124
|
+
**Technology (auto-activated):**
|
|
125
|
+
- 20-nextjs.mdc - Next.js patterns
|
|
126
|
+
- 21-api-design.mdc - API design patterns
|
|
127
|
+
- 30-database.mdc - Database patterns
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Rule Metadata Format
|
|
131
|
+
|
|
132
|
+
Each rule file should include activation metadata:
|
|
133
|
+
|
|
134
|
+
```markdown
|
|
135
|
+
---
|
|
136
|
+
title: [Rule Title]
|
|
137
|
+
description: [Description]
|
|
138
|
+
owner: sdd-system
|
|
139
|
+
severity: warn
|
|
140
|
+
globs: [File patterns - optional]
|
|
141
|
+
alwaysApply: false
|
|
142
|
+
activation:
|
|
143
|
+
projectTypes: [web-app, cli-tool, library, api-service, mobile-app, monorepo]
|
|
144
|
+
projectSizes: [small, medium, large, enterprise]
|
|
145
|
+
projectPhases: [initialization, expansion, maintenance, migration, legacy]
|
|
146
|
+
technologies: [nextjs, react, postgres, clerk, tailwindcss, jest]
|
|
147
|
+
requires: [10-engineering, 11-design]
|
|
148
|
+
---
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Activation Logic Examples
|
|
152
|
+
|
|
153
|
+
**Example 1: Next.js web app (medium, expansion)**
|
|
154
|
+
- Foundation: 00-pos, 01-sdd, 02-work-mode
|
|
155
|
+
- Domain: 10-engineering, 11-design
|
|
156
|
+
- Technology: 20-nextjs, 21-api-design (if API routes exist), 30-database (if database detected)
|
|
157
|
+
|
|
158
|
+
**Example 2: CLI tool (small, initialization)**
|
|
159
|
+
- Foundation: 00-pos, 01-sdd, 02-work-mode
|
|
160
|
+
- Domain: 10-engineering
|
|
161
|
+
- Technology: 40-cli-patterns (if exists)
|
|
162
|
+
|
|
163
|
+
**Example 3: Legacy Express API (large, maintenance)**
|
|
164
|
+
- Foundation: 00-pos, 01-sdd, 02-work-mode
|
|
165
|
+
- Domain: 10-engineering
|
|
166
|
+
- Technology: 21-api-design, 30-database
|
|
167
|
+
|
|
168
|
+
## User Override
|
|
169
|
+
|
|
170
|
+
Users can override activation:
|
|
171
|
+
- Manually activate/deactivate specific rules
|
|
172
|
+
- Force activation of rules that didn't match
|
|
173
|
+
- Disable auto-activation for specific rules
|
|
174
|
+
|
|
175
|
+
## Rule Metadata Cache
|
|
176
|
+
|
|
177
|
+
**Cache Location:** `.sdd/rule-metadata-cache.json`
|
|
178
|
+
|
|
179
|
+
**Cache Structure:**
|
|
180
|
+
```json
|
|
181
|
+
{
|
|
182
|
+
"rules": {
|
|
183
|
+
"20-nextjs.mdc": {
|
|
184
|
+
"activation": {
|
|
185
|
+
"projectTypes": ["web-app"],
|
|
186
|
+
"projectSizes": ["small", "medium", "large"],
|
|
187
|
+
"projectPhases": ["initialization", "expansion"],
|
|
188
|
+
"technologies": ["nextjs", "react"]
|
|
189
|
+
},
|
|
190
|
+
"requires": ["10-engineering"]
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
"last_updated": "2026-01-07T12:00:00Z",
|
|
194
|
+
"rule_files": {
|
|
195
|
+
"20-nextjs.mdc": {
|
|
196
|
+
"mtime": 1704633600000
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Cache Management:**
|
|
203
|
+
- **Build cache:** Parse all rule files, extract metadata, store in cache
|
|
204
|
+
- **Validate cache:** Compare rule file mtimes with cache mtimes
|
|
205
|
+
- **Invalidate cache:** If any rule file modified, rebuild cache
|
|
206
|
+
- **Use cache:** Read from cache instead of scanning all rule files
|
|
207
|
+
|
|
208
|
+
**Benefits:**
|
|
209
|
+
- Faster activation (read from cache instead of scanning all files)
|
|
210
|
+
- Reduced token consumption (cache is small JSON file)
|
|
211
|
+
- Automatic invalidation ensures cache stays current
|
|
212
|
+
|
|
213
|
+
## Usage in Commands
|
|
214
|
+
|
|
215
|
+
All SDD commands should:
|
|
216
|
+
1. Run detection (or read from cache)
|
|
217
|
+
2. Run activation engine (use rule metadata cache)
|
|
218
|
+
3. Include active rule list in state assertion
|
|
219
|
+
4. Apply active rules during execution
|
|
220
|
+
|