dev-workflows 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 (80) hide show
  1. package/bin/devw.js +2 -0
  2. package/content/blocks/nextjs-approuter.yml +37 -0
  3. package/content/blocks/react-conventions.yml +36 -0
  4. package/content/blocks/supabase-rls.yml +30 -0
  5. package/content/blocks/tailwind.yml +28 -0
  6. package/content/blocks/testing-basics.yml +36 -0
  7. package/content/blocks/typescript-strict.yml +33 -0
  8. package/dist/blocks/installer.d.ts +4 -0
  9. package/dist/blocks/installer.d.ts.map +1 -0
  10. package/dist/blocks/installer.js +119 -0
  11. package/dist/blocks/installer.js.map +1 -0
  12. package/dist/blocks/registry.d.ts +18 -0
  13. package/dist/blocks/registry.d.ts.map +1 -0
  14. package/dist/blocks/registry.js +85 -0
  15. package/dist/blocks/registry.js.map +1 -0
  16. package/dist/bridges/claude.d.ts +3 -0
  17. package/dist/bridges/claude.d.ts.map +1 -0
  18. package/dist/bridges/claude.js +54 -0
  19. package/dist/bridges/claude.js.map +1 -0
  20. package/dist/bridges/cursor.d.ts +3 -0
  21. package/dist/bridges/cursor.d.ts.map +1 -0
  22. package/dist/bridges/cursor.js +61 -0
  23. package/dist/bridges/cursor.js.map +1 -0
  24. package/dist/bridges/gemini.d.ts +3 -0
  25. package/dist/bridges/gemini.d.ts.map +1 -0
  26. package/dist/bridges/gemini.js +54 -0
  27. package/dist/bridges/gemini.js.map +1 -0
  28. package/dist/bridges/types.d.ts +25 -0
  29. package/dist/bridges/types.d.ts.map +1 -0
  30. package/dist/bridges/types.js +2 -0
  31. package/dist/bridges/types.js.map +1 -0
  32. package/dist/commands/add.d.ts +7 -0
  33. package/dist/commands/add.d.ts.map +1 -0
  34. package/dist/commands/add.js +64 -0
  35. package/dist/commands/add.js.map +1 -0
  36. package/dist/commands/compile.d.ts +9 -0
  37. package/dist/commands/compile.d.ts.map +1 -0
  38. package/dist/commands/compile.js +130 -0
  39. package/dist/commands/compile.js.map +1 -0
  40. package/dist/commands/doctor.d.ts +16 -0
  41. package/dist/commands/doctor.d.ts.map +1 -0
  42. package/dist/commands/doctor.js +229 -0
  43. package/dist/commands/doctor.js.map +1 -0
  44. package/dist/commands/init.d.ts +8 -0
  45. package/dist/commands/init.d.ts.map +1 -0
  46. package/dist/commands/init.js +159 -0
  47. package/dist/commands/init.js.map +1 -0
  48. package/dist/commands/list.d.ts +3 -0
  49. package/dist/commands/list.d.ts.map +1 -0
  50. package/dist/commands/list.js +106 -0
  51. package/dist/commands/list.js.map +1 -0
  52. package/dist/commands/remove.d.ts +3 -0
  53. package/dist/commands/remove.d.ts.map +1 -0
  54. package/dist/commands/remove.js +40 -0
  55. package/dist/commands/remove.js.map +1 -0
  56. package/dist/core/hash.d.ts +5 -0
  57. package/dist/core/hash.d.ts.map +1 -0
  58. package/dist/core/hash.js +24 -0
  59. package/dist/core/hash.js.map +1 -0
  60. package/dist/core/markers.d.ts +4 -0
  61. package/dist/core/markers.d.ts.map +1 -0
  62. package/dist/core/markers.js +18 -0
  63. package/dist/core/markers.js.map +1 -0
  64. package/dist/core/parser.d.ts +4 -0
  65. package/dist/core/parser.d.ts.map +1 -0
  66. package/dist/core/parser.js +82 -0
  67. package/dist/core/parser.js.map +1 -0
  68. package/dist/index.d.ts +4 -0
  69. package/dist/index.d.ts.map +1 -0
  70. package/dist/index.js +21 -0
  71. package/dist/index.js.map +1 -0
  72. package/dist/utils/detect-tools.d.ts +8 -0
  73. package/dist/utils/detect-tools.d.ts.map +1 -0
  74. package/dist/utils/detect-tools.js +28 -0
  75. package/dist/utils/detect-tools.js.map +1 -0
  76. package/dist/utils/prompt.d.ts +3 -0
  77. package/dist/utils/prompt.d.ts.map +1 -0
  78. package/dist/utils/prompt.js +21 -0
  79. package/dist/utils/prompt.js.map +1 -0
  80. package/package.json +42 -0
@@ -0,0 +1,54 @@
1
+ function filterRules(rules) {
2
+ return rules.filter((r) => r.enabled && r.severity !== 'info');
3
+ }
4
+ function groupByScope(rules) {
5
+ const groups = new Map();
6
+ for (const rule of rules) {
7
+ const existing = groups.get(rule.scope);
8
+ if (existing) {
9
+ existing.push(rule);
10
+ }
11
+ else {
12
+ groups.set(rule.scope, [rule]);
13
+ }
14
+ }
15
+ return groups;
16
+ }
17
+ function capitalize(s) {
18
+ return s.charAt(0).toUpperCase() + s.slice(1);
19
+ }
20
+ function buildMarkdown(rules) {
21
+ const lines = [
22
+ '# Project Rules',
23
+ ];
24
+ const filtered = filterRules(rules);
25
+ const grouped = groupByScope(filtered);
26
+ for (const [scope, scopeRules] of grouped) {
27
+ lines.push('', `## ${capitalize(scope)}`);
28
+ for (const rule of scopeRules) {
29
+ const contentLines = rule.content.split('\n');
30
+ const first = contentLines[0];
31
+ if (first !== undefined) {
32
+ lines.push('', `- ${first}`);
33
+ }
34
+ for (let i = 1; i < contentLines.length; i++) {
35
+ const line = contentLines[i];
36
+ if (line !== undefined) {
37
+ lines.push(` ${line}`);
38
+ }
39
+ }
40
+ }
41
+ }
42
+ lines.push('');
43
+ return lines.join('\n');
44
+ }
45
+ export const geminiBridge = {
46
+ id: 'gemini',
47
+ outputPaths: ['GEMINI.md'],
48
+ compile(rules, _config) {
49
+ const output = new Map();
50
+ output.set('GEMINI.md', buildMarkdown(rules));
51
+ return output;
52
+ },
53
+ };
54
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/bridges/gemini.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,QAAQ,EAAE,CAAC;YACb,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,aAAa,CAAC,KAAa;IAClC,MAAM,KAAK,GAAa;QACtB,iBAAiB;KAClB,CAAC;IAEF,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEvC,KAAK,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,IAAI,OAAO,EAAE,CAAC;QAC1C,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC1C,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;YAC9B,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,KAAK,EAAE,CAAC,CAAC;YAC/B,CAAC;YACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC;gBAC7B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;oBACvB,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAW;IAClC,EAAE,EAAE,QAAQ;IACZ,WAAW,EAAE,CAAC,WAAW,CAAC;IAE1B,OAAO,CAAC,KAAa,EAAE,OAAsB;QAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QACzC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,OAAO,MAAM,CAAC;IAChB,CAAC;CACF,CAAC"}
@@ -0,0 +1,25 @@
1
+ export interface Rule {
2
+ id: string;
3
+ scope: string;
4
+ severity: 'error' | 'warning' | 'info';
5
+ content: string;
6
+ tags?: string[];
7
+ enabled: boolean;
8
+ sourceBlock?: string;
9
+ }
10
+ export interface ProjectConfig {
11
+ version: string;
12
+ project: {
13
+ name: string;
14
+ description?: string;
15
+ };
16
+ tools: string[];
17
+ mode: 'copy' | 'link';
18
+ blocks: string[];
19
+ }
20
+ export interface Bridge {
21
+ id: string;
22
+ outputPaths: string[];
23
+ compile(rules: Rule[], config: ProjectConfig): Map<string, string>;
24
+ }
25
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bridges/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,aAAa,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpE"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/bridges/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ import type { Command } from 'commander';
2
+ export interface AddOptions {
3
+ list?: boolean;
4
+ noCompile?: boolean;
5
+ }
6
+ export declare function registerAddCommand(program: Command): void;
7
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA4DD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQzD"}
@@ -0,0 +1,64 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { loadAllBlocks, loadBlock } from '../blocks/registry.js';
5
+ import { installBlock } from '../blocks/installer.js';
6
+ async function fileExists(filePath) {
7
+ try {
8
+ await access(filePath);
9
+ return true;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ async function listAvailableBlocks() {
16
+ const blocks = await loadAllBlocks();
17
+ if (blocks.length === 0) {
18
+ console.log(chalk.yellow('No blocks available.'));
19
+ return;
20
+ }
21
+ console.log(chalk.bold('Available blocks:\n'));
22
+ for (const block of blocks) {
23
+ console.log(` ${chalk.cyan(block.id)} — ${block.description}`);
24
+ console.log(` ${chalk.dim(`${String(block.rules.length)} rules | v${block.version}`)}`);
25
+ console.log('');
26
+ }
27
+ }
28
+ async function runAdd(blockId, options) {
29
+ if (options.list || !blockId) {
30
+ await listAvailableBlocks();
31
+ return;
32
+ }
33
+ const cwd = process.cwd();
34
+ if (!(await fileExists(join(cwd, '.dwf', 'config.yml')))) {
35
+ console.error(chalk.red('Error: .dwf/config.yml not found.'));
36
+ console.error('Run "devw init" first.');
37
+ process.exitCode = 1;
38
+ return;
39
+ }
40
+ const block = await loadBlock(blockId);
41
+ if (!block) {
42
+ console.error(chalk.red(`Error: block "${blockId}" not found.`));
43
+ console.error('Run "devw add --list" to see available blocks.');
44
+ process.exitCode = 1;
45
+ return;
46
+ }
47
+ const rulesAdded = await installBlock(cwd, block);
48
+ console.log(chalk.green(`Added block "${block.name}" (${String(rulesAdded)} rules).`));
49
+ if (!options.noCompile) {
50
+ // Dynamic import to avoid circular dependency
51
+ const { runCompileFromAdd } = await import('./compile.js');
52
+ await runCompileFromAdd();
53
+ }
54
+ }
55
+ export function registerAddCommand(program) {
56
+ program
57
+ .command('add')
58
+ .argument('[block]', 'Block ID to install')
59
+ .description('Install a prebuilt rule block')
60
+ .option('--list', 'List all available blocks')
61
+ .option('--no-compile', 'Skip auto-compile after adding')
62
+ .action((blockId, options) => runAdd(blockId, options));
63
+ }
64
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Command } from 'commander';
2
+ export interface CompileOptions {
3
+ tool?: string;
4
+ dryRun?: boolean;
5
+ verbose?: boolean;
6
+ }
7
+ export declare function runCompileFromAdd(): Promise<void>;
8
+ export declare function registerCompileCommand(program: Command): void;
9
+ //# sourceMappingURL=compile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/commands/compile.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUzC,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAkID,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAEvD;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ7D"}
@@ -0,0 +1,130 @@
1
+ import { mkdir, writeFile, readFile, symlink, unlink, access } from 'node:fs/promises';
2
+ import { join, dirname } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { readConfig, readRules } from '../core/parser.js';
5
+ import { computeRulesHash, writeHash } from '../core/hash.js';
6
+ import { claudeBridge } from '../bridges/claude.js';
7
+ import { cursorBridge } from '../bridges/cursor.js';
8
+ import { geminiBridge } from '../bridges/gemini.js';
9
+ import { mergeMarkedContent } from '../core/markers.js';
10
+ const BRIDGES = [claudeBridge, cursorBridge, geminiBridge];
11
+ function getBridge(id) {
12
+ return BRIDGES.find((b) => b.id === id);
13
+ }
14
+ async function fileExists(filePath) {
15
+ try {
16
+ await access(filePath);
17
+ return true;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ }
23
+ async function runCompile(options) {
24
+ const cwd = process.cwd();
25
+ if (!(await fileExists(join(cwd, '.dwf', 'config.yml')))) {
26
+ console.error(chalk.red('Error: .dwf/config.yml not found.'));
27
+ console.error('Run "devw init" first.');
28
+ process.exitCode = 1;
29
+ return;
30
+ }
31
+ const config = await readConfig(cwd);
32
+ const rules = await readRules(cwd);
33
+ // Determine which tools to compile
34
+ let toolIds = config.tools;
35
+ if (options.tool) {
36
+ if (!config.tools.includes(options.tool)) {
37
+ console.error(chalk.red(`Error: tool "${options.tool}" is not configured in .dwf/config.yml`));
38
+ console.error(`Configured tools: ${config.tools.join(', ')}`);
39
+ process.exitCode = 1;
40
+ return;
41
+ }
42
+ toolIds = [options.tool];
43
+ }
44
+ if (options.verbose) {
45
+ console.log(chalk.dim(`Project: ${config.project.name}`));
46
+ console.log(chalk.dim(`Mode: ${config.mode}`));
47
+ console.log(chalk.dim(`Rules loaded: ${String(rules.length)}`));
48
+ console.log(chalk.dim(`Tools: ${toolIds.join(', ')}`));
49
+ console.log('');
50
+ }
51
+ const activeRules = rules.filter((r) => r.enabled);
52
+ if (activeRules.length === 0) {
53
+ console.log(chalk.yellow('No active rules found in .dwf/rules/. Nothing to compile.'));
54
+ return;
55
+ }
56
+ let filesWritten = 0;
57
+ for (const toolId of toolIds) {
58
+ const bridge = getBridge(toolId);
59
+ if (!bridge) {
60
+ console.warn(chalk.yellow(`Warning: no bridge for tool "${toolId}", skipping.`));
61
+ continue;
62
+ }
63
+ const outputs = bridge.compile(rules, config);
64
+ for (const [relativePath, rawContent] of outputs) {
65
+ const isMarkdownBridge = rawContent.startsWith('# Project Rules');
66
+ let content = rawContent;
67
+ if (isMarkdownBridge && !options.dryRun) {
68
+ const absoluteCheck = join(cwd, relativePath);
69
+ let existing = null;
70
+ try {
71
+ existing = await readFile(absoluteCheck, 'utf-8');
72
+ }
73
+ catch {
74
+ existing = null;
75
+ }
76
+ content = mergeMarkedContent(existing, rawContent);
77
+ }
78
+ if (options.dryRun) {
79
+ console.log(chalk.cyan(`--- ${relativePath} ---`));
80
+ console.log(content);
81
+ continue;
82
+ }
83
+ const absolutePath = join(cwd, relativePath);
84
+ await mkdir(dirname(absolutePath), { recursive: true });
85
+ if (config.mode === 'link') {
86
+ // Write to .dwf/.cache/, then symlink
87
+ const cachePath = join(cwd, '.dwf', '.cache', relativePath);
88
+ await mkdir(dirname(cachePath), { recursive: true });
89
+ await writeFile(cachePath, content, 'utf-8');
90
+ // Remove existing file/symlink before creating new one
91
+ if (await fileExists(absolutePath)) {
92
+ await unlink(absolutePath);
93
+ }
94
+ await symlink(cachePath, absolutePath);
95
+ if (options.verbose) {
96
+ console.log(` ${chalk.dim(relativePath)} -> ${chalk.dim(`.dwf/.cache/${relativePath}`)}`);
97
+ }
98
+ }
99
+ else {
100
+ await writeFile(absolutePath, content, 'utf-8');
101
+ if (options.verbose) {
102
+ console.log(` ${chalk.dim(relativePath)}`);
103
+ }
104
+ }
105
+ filesWritten++;
106
+ }
107
+ }
108
+ if (!options.dryRun) {
109
+ const hash = computeRulesHash(activeRules);
110
+ await writeHash(cwd, hash);
111
+ console.log('');
112
+ console.log(chalk.green(`Compiled ${String(filesWritten)} file${filesWritten !== 1 ? 's' : ''} successfully.`));
113
+ if (options.verbose) {
114
+ console.log(chalk.dim(`Mode: ${config.mode}`));
115
+ }
116
+ }
117
+ }
118
+ export async function runCompileFromAdd() {
119
+ await runCompile({});
120
+ }
121
+ export function registerCompileCommand(program) {
122
+ program
123
+ .command('compile')
124
+ .description('Compile .dwf/ rules into editor-specific config files')
125
+ .option('--tool <tool>', 'Compile only a specific bridge (claude, cursor, gemini)')
126
+ .option('--dry-run', 'Show output without writing files')
127
+ .option('--verbose', 'Show detailed output')
128
+ .action((options) => runCompile(options));
129
+ }
130
+ //# sourceMappingURL=compile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compile.js","sourceRoot":"","sources":["../../src/commands/compile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { Command } from 'commander';
2
+ import type { ProjectConfig, Rule } from '../bridges/types.js';
3
+ export interface CheckResult {
4
+ passed: boolean;
5
+ message: string;
6
+ skipped?: boolean;
7
+ }
8
+ export declare function checkConfigExists(cwd: string): Promise<CheckResult>;
9
+ export declare function checkConfigValid(cwd: string): Promise<CheckResult>;
10
+ export declare function checkRulesValid(cwd: string): Promise<CheckResult>;
11
+ export declare function checkDuplicateIds(rules: Rule[]): CheckResult;
12
+ export declare function checkBridgesAvailable(config: ProjectConfig): CheckResult;
13
+ export declare function checkSymlinks(cwd: string, config: ProjectConfig): Promise<CheckResult>;
14
+ export declare function checkHashSync(cwd: string, rules: Rule[]): Promise<CheckResult>;
15
+ export declare function registerDoctorCommand(program: Command): void;
16
+ //# sourceMappingURL=doctor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,OAAO,KAAK,EAAU,aAAa,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAKvE,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAWD,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAKzE;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAQxE;AAED,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA2CvE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,WAAW,CAmB5D;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAWxE;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC,CAkC5F;AAED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAmBpF;AAiFD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK5D"}
@@ -0,0 +1,229 @@
1
+ import { access, lstat, readFile, readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import chalk from 'chalk';
4
+ import { parse } from 'yaml';
5
+ import { readConfig, readRules } from '../core/parser.js';
6
+ import { computeRulesHash, readStoredHash } from '../core/hash.js';
7
+ import { claudeBridge } from '../bridges/claude.js';
8
+ import { cursorBridge } from '../bridges/cursor.js';
9
+ import { geminiBridge } from '../bridges/gemini.js';
10
+ const BRIDGES = [claudeBridge, cursorBridge, geminiBridge];
11
+ const BRIDGE_IDS = new Set(BRIDGES.map((b) => b.id));
12
+ async function fileExists(filePath) {
13
+ try {
14
+ await access(filePath);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
19
+ }
20
+ }
21
+ export async function checkConfigExists(cwd) {
22
+ const exists = await fileExists(join(cwd, '.dwf', 'config.yml'));
23
+ return exists
24
+ ? { passed: true, message: '.dwf/config.yml exists' }
25
+ : { passed: false, message: '.dwf/config.yml not found — run "devw init"' };
26
+ }
27
+ export async function checkConfigValid(cwd) {
28
+ try {
29
+ await readConfig(cwd);
30
+ return { passed: true, message: 'config.yml is valid' };
31
+ }
32
+ catch (err) {
33
+ const msg = err instanceof Error ? err.message : String(err);
34
+ return { passed: false, message: `config.yml is invalid: ${msg}` };
35
+ }
36
+ }
37
+ export async function checkRulesValid(cwd) {
38
+ const rulesDir = join(cwd, '.dwf', 'rules');
39
+ let entries;
40
+ try {
41
+ entries = await readdir(rulesDir);
42
+ }
43
+ catch {
44
+ return { passed: true, message: 'No rules directory found (0 rules loaded)' };
45
+ }
46
+ const ymlFiles = entries.filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'));
47
+ if (ymlFiles.length === 0) {
48
+ return { passed: true, message: 'Rule files are valid YAML (0 rules loaded)' };
49
+ }
50
+ const invalidFiles = [];
51
+ let totalRules = 0;
52
+ for (const file of ymlFiles) {
53
+ try {
54
+ const raw = await readFile(join(rulesDir, file), 'utf-8');
55
+ const parsed = parse(raw);
56
+ if (parsed && typeof parsed === 'object') {
57
+ const doc = parsed;
58
+ if (Array.isArray(doc['rules'])) {
59
+ totalRules += doc['rules'].length;
60
+ }
61
+ }
62
+ }
63
+ catch {
64
+ invalidFiles.push(file);
65
+ }
66
+ }
67
+ if (invalidFiles.length > 0) {
68
+ return {
69
+ passed: false,
70
+ message: `Invalid YAML in: ${invalidFiles.join(', ')}`,
71
+ };
72
+ }
73
+ return {
74
+ passed: true,
75
+ message: `Rule files are valid YAML (${String(totalRules)} rules loaded)`,
76
+ };
77
+ }
78
+ export function checkDuplicateIds(rules) {
79
+ const seen = new Set();
80
+ const duplicates = new Set();
81
+ for (const rule of rules) {
82
+ if (seen.has(rule.id)) {
83
+ duplicates.add(rule.id);
84
+ }
85
+ seen.add(rule.id);
86
+ }
87
+ if (duplicates.size > 0) {
88
+ return {
89
+ passed: false,
90
+ message: `Duplicate rule IDs found: ${[...duplicates].join(', ')}`,
91
+ };
92
+ }
93
+ return { passed: true, message: 'No duplicate rule IDs' };
94
+ }
95
+ export function checkBridgesAvailable(config) {
96
+ const missing = config.tools.filter((t) => !BRIDGE_IDS.has(t));
97
+ if (missing.length > 0) {
98
+ return {
99
+ passed: false,
100
+ message: `No bridge available for: ${missing.join(', ')}`,
101
+ };
102
+ }
103
+ return { passed: true, message: 'All configured tools have bridges' };
104
+ }
105
+ export async function checkSymlinks(cwd, config) {
106
+ if (config.mode !== 'link') {
107
+ return { passed: true, message: 'Symlink check skipped (mode: copy)', skipped: true };
108
+ }
109
+ const brokenLinks = [];
110
+ for (const bridge of BRIDGES) {
111
+ if (!config.tools.includes(bridge.id))
112
+ continue;
113
+ for (const outputPath of bridge.outputPaths) {
114
+ const absolutePath = join(cwd, outputPath);
115
+ try {
116
+ const stat = await lstat(absolutePath);
117
+ if (stat.isSymbolicLink()) {
118
+ const targetExists = await fileExists(absolutePath);
119
+ if (!targetExists) {
120
+ brokenLinks.push(outputPath);
121
+ }
122
+ }
123
+ }
124
+ catch {
125
+ // File doesn't exist at all — not necessarily an error for this check
126
+ }
127
+ }
128
+ }
129
+ if (brokenLinks.length > 0) {
130
+ return {
131
+ passed: false,
132
+ message: `Broken symlinks: ${brokenLinks.join(', ')}`,
133
+ };
134
+ }
135
+ return { passed: true, message: 'Symlinks are valid' };
136
+ }
137
+ export async function checkHashSync(cwd, rules) {
138
+ const storedHash = await readStoredHash(cwd);
139
+ if (storedHash === null) {
140
+ return {
141
+ passed: true,
142
+ message: 'Hash check skipped (no compiled files found)',
143
+ skipped: true,
144
+ };
145
+ }
146
+ const currentHash = computeRulesHash(rules);
147
+ if (storedHash === currentHash) {
148
+ return { passed: true, message: 'Compiled files are in sync' };
149
+ }
150
+ return {
151
+ passed: false,
152
+ message: 'Compiled files out of sync — run "devw compile"',
153
+ };
154
+ }
155
+ function formatResult(result) {
156
+ if (result.skipped) {
157
+ return `${chalk.dim('-')} ${chalk.dim(result.message)}`;
158
+ }
159
+ const icon = result.passed ? chalk.green('✓') : chalk.red('✗');
160
+ const text = result.passed ? result.message : chalk.red(result.message);
161
+ return `${icon} ${text}`;
162
+ }
163
+ async function runDoctor() {
164
+ const cwd = process.cwd();
165
+ const results = [];
166
+ let hasFailed = false;
167
+ // Check 1: .dwf/config.yml exists
168
+ const configExistsResult = await checkConfigExists(cwd);
169
+ results.push(configExistsResult);
170
+ if (!configExistsResult.passed) {
171
+ for (const r of results)
172
+ console.log(formatResult(r));
173
+ process.exitCode = 1;
174
+ return;
175
+ }
176
+ // Check 2: config.yml is valid
177
+ const configValidResult = await checkConfigValid(cwd);
178
+ results.push(configValidResult);
179
+ let config = null;
180
+ if (configValidResult.passed) {
181
+ config = await readConfig(cwd);
182
+ }
183
+ // Check 3: Rule files are valid YAML
184
+ const rulesValidResult = await checkRulesValid(cwd);
185
+ results.push(rulesValidResult);
186
+ if (!configValidResult.passed) {
187
+ for (const r of results)
188
+ console.log(formatResult(r));
189
+ process.exitCode = 1;
190
+ return;
191
+ }
192
+ // Load rules for remaining checks
193
+ let rules = [];
194
+ try {
195
+ rules = await readRules(cwd);
196
+ }
197
+ catch {
198
+ // readRules may fail if rules dir is missing; that's ok
199
+ }
200
+ // Check 4: No duplicate rule IDs
201
+ const dupResult = checkDuplicateIds(rules);
202
+ results.push(dupResult);
203
+ // Check 5: Tools have bridges
204
+ // config is guaranteed non-null here since configValidResult.passed
205
+ const bridgeResult = checkBridgesAvailable(config);
206
+ results.push(bridgeResult);
207
+ // Check 6: Symlinks valid (conditional on mode)
208
+ const symlinkResult = await checkSymlinks(cwd, config);
209
+ results.push(symlinkResult);
210
+ // Check 7: Hash sync (conditional on compiled files existing)
211
+ const hashResult = await checkHashSync(cwd, rules);
212
+ results.push(hashResult);
213
+ // Output
214
+ for (const r of results) {
215
+ console.log(formatResult(r));
216
+ if (!r.passed)
217
+ hasFailed = true;
218
+ }
219
+ if (hasFailed) {
220
+ process.exitCode = 1;
221
+ }
222
+ }
223
+ export function registerDoctorCommand(program) {
224
+ program
225
+ .command('doctor')
226
+ .description('Validate .dwf/ configuration and check for issues')
227
+ .action(() => runDoctor());
228
+ }
229
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { Command } from 'commander';
2
+ export interface InitOptions {
3
+ tools?: string;
4
+ mode?: 'copy' | 'link';
5
+ yes?: boolean;
6
+ }
7
+ export declare function registerInitCommand(program: Command): void;
8
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOzC,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAoKD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAQ1D"}