dw-kit 1.2.1 → 1.3.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 (58) hide show
  1. package/.claude/hooks/post-write.sh +64 -58
  2. package/.claude/hooks/pre-commit-gate.sh +96 -90
  3. package/.claude/hooks/privacy-block.sh +99 -94
  4. package/.claude/hooks/progress-ping.sh +53 -47
  5. package/.claude/hooks/safety-guard.sh +60 -54
  6. package/.claude/hooks/scout-block.sh +88 -82
  7. package/.claude/hooks/session-init.sh +6 -0
  8. package/.claude/hooks/stop-check.sh +88 -36
  9. package/.claude/hooks/telemetry-log.sh +34 -0
  10. package/.claude/rules/dw.md +136 -0
  11. package/.claude/settings.json +20 -1
  12. package/.claude/skills/dw-arch-review/SKILL.md +119 -119
  13. package/.claude/skills/dw-archive/SKILL.md +81 -81
  14. package/.claude/skills/dw-commit/SKILL.md +81 -81
  15. package/.claude/skills/dw-config-init/SKILL.md +91 -91
  16. package/.claude/skills/dw-config-validate/SKILL.md +75 -75
  17. package/.claude/skills/dw-dashboard/SKILL.md +209 -209
  18. package/.claude/skills/dw-debug/SKILL.md +97 -97
  19. package/.claude/skills/dw-decision/SKILL.md +116 -0
  20. package/.claude/skills/dw-docs-update/SKILL.md +125 -125
  21. package/.claude/skills/dw-estimate/SKILL.md +90 -90
  22. package/.claude/skills/dw-execute/SKILL.md +98 -98
  23. package/.claude/skills/dw-flow/SKILL.md +274 -274
  24. package/.claude/skills/dw-handoff/SKILL.md +81 -81
  25. package/.claude/skills/dw-kit-report/SKILL.md +152 -152
  26. package/.claude/skills/dw-log-work/SKILL.md +69 -69
  27. package/.claude/skills/dw-onboard/SKILL.md +201 -201
  28. package/.claude/skills/dw-plan/SKILL.md +125 -125
  29. package/.claude/skills/dw-prompt/SKILL.md +62 -62
  30. package/.claude/skills/dw-requirements/SKILL.md +98 -98
  31. package/.claude/skills/dw-research/SKILL.md +114 -114
  32. package/.claude/skills/dw-retroactive/SKILL.md +311 -311
  33. package/.claude/skills/dw-review/SKILL.md +66 -66
  34. package/.claude/skills/dw-rollback/SKILL.md +90 -90
  35. package/.claude/skills/dw-sprint-review/SKILL.md +99 -99
  36. package/.claude/skills/dw-task-init/SKILL.md +59 -59
  37. package/.claude/skills/dw-test-plan/SKILL.md +113 -113
  38. package/.claude/skills/dw-thinking/SKILL.md +70 -70
  39. package/.claude/skills/dw-upgrade/SKILL.md +72 -72
  40. package/.dw/core/PILLARS.md +122 -0
  41. package/.dw/core/templates/v2/spec.md +68 -0
  42. package/.dw/core/templates/v2/tracking.md +62 -0
  43. package/.dw/core/v14-evaluation-protocol.md +118 -0
  44. package/CLAUDE.md +42 -39
  45. package/MIGRATION-v1.3.md +201 -0
  46. package/README.md +35 -6
  47. package/package.json +4 -2
  48. package/src/cli.mjs +29 -1
  49. package/src/commands/dashboard.mjs +116 -0
  50. package/src/commands/doctor.mjs +165 -149
  51. package/src/commands/init.mjs +339 -332
  52. package/src/commands/metrics.mjs +165 -0
  53. package/src/lib/active-index.mjs +87 -0
  54. package/src/lib/cut-analysis.mjs +161 -0
  55. package/src/lib/telemetry.mjs +80 -0
  56. package/.claude/rules/dw-core.md +0 -100
  57. package/.claude/rules/dw-skills.md +0 -53
  58. package/.claude/rules/workflow-rules.md +0 -77
@@ -0,0 +1,116 @@
1
+ import { readEvents, summarize } from '../lib/telemetry.mjs';
2
+ import { generateActiveIndex } from '../lib/active-index.mjs';
3
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
4
+ import { join } from 'node:path';
5
+ import { banner, log, info, warn, ok } from '../lib/ui.mjs';
6
+ import chalk from 'chalk';
7
+
8
+ export async function dashboardCommand(opts) {
9
+ banner('dw-kit Dashboard');
10
+
11
+ const rootDir = process.cwd();
12
+
13
+ log(chalk.bold('📋 Active Tasks'));
14
+ log('');
15
+ const activeContent = generateActiveIndex(rootDir);
16
+ const taskLines = activeContent.split('\n').filter((l) => l.startsWith('- `'));
17
+ if (taskLines.length === 0) {
18
+ log(' (none)');
19
+ } else {
20
+ taskLines.forEach((l) => log(' ' + l));
21
+ }
22
+ log('');
23
+
24
+ log(chalk.bold('🗂️ Decisions (ADRs)'));
25
+ log('');
26
+ const decisionsDir = join(rootDir, '.dw/decisions');
27
+ if (existsSync(decisionsDir)) {
28
+ const adrs = readdirSync(decisionsDir).filter((f) => /^\d{4}-.*\.md$/.test(f));
29
+ if (adrs.length === 0) {
30
+ log(' (none)');
31
+ } else {
32
+ adrs.sort().forEach((f) => {
33
+ try {
34
+ const content = readFileSync(join(decisionsDir, f), 'utf8');
35
+ const statusMatch = content.match(/^status:\s*(.+)$/m);
36
+ const titleMatch = content.match(/^title:\s*(.+)$/m);
37
+ const status = statusMatch ? statusMatch[1].trim() : 'unknown';
38
+ const title = titleMatch ? titleMatch[1].trim() : f;
39
+ const statusColor =
40
+ status === 'Accepted'
41
+ ? chalk.green
42
+ : status.startsWith('Proposed')
43
+ ? chalk.yellow
44
+ : status === 'Deprecated'
45
+ ? chalk.gray
46
+ : chalk.white;
47
+ log(` ${chalk.cyan(f.replace(/\.md$/, ''))} · ${statusColor(status)}`);
48
+ log(` ${chalk.dim(title)}`);
49
+ } catch {
50
+ log(` ${f} · (unreadable)`);
51
+ }
52
+ });
53
+ }
54
+ } else {
55
+ log(' (decisions layer not initialized — run `/dw:decision` to create first ADR)');
56
+ }
57
+ log('');
58
+
59
+ log(chalk.bold('📊 Telemetry Summary'));
60
+ log('');
61
+ if (process.env.DW_NO_TELEMETRY === '1') {
62
+ warn('Telemetry disabled (DW_NO_TELEMETRY=1)');
63
+ } else {
64
+ const events = readEvents(rootDir);
65
+ if (events.length === 0) {
66
+ log(' No events yet. Use dw-kit normally to populate.');
67
+ } else {
68
+ const s = summarize(events);
69
+ log(` Total events: ${s.totalEvents}`);
70
+ if (s.dateRange) {
71
+ log(` Range: ${s.dateRange.from.slice(0, 10)} → ${s.dateRange.to.slice(0, 10)}`);
72
+ }
73
+
74
+ const topSkills = Object.entries(s.bySkill)
75
+ .sort((a, b) => b[1] - a[1])
76
+ .slice(0, 5);
77
+ if (topSkills.length > 0) {
78
+ log('');
79
+ log(chalk.dim(' Top 5 skills:'));
80
+ topSkills.forEach(([n, c]) => log(` ${c.toString().padStart(4)}× /${n}`));
81
+ }
82
+
83
+ const topHooks = Object.entries(s.byHook)
84
+ .sort((a, b) => b[1] - a[1])
85
+ .slice(0, 5);
86
+ if (topHooks.length > 0) {
87
+ log('');
88
+ log(chalk.dim(' Top 5 hooks:'));
89
+ topHooks.forEach(([n, c]) => log(` ${c.toString().padStart(4)}× ${n}`));
90
+ }
91
+ }
92
+ }
93
+ log('');
94
+
95
+ log(chalk.bold('🔧 Health'));
96
+ log('');
97
+ const checks = [
98
+ { path: '.dw/config/dw.config.yml', label: 'Config' },
99
+ { path: '.dw/tasks/ACTIVE.md', label: 'ACTIVE index' },
100
+ { path: '.dw/decisions', label: 'Decisions layer' },
101
+ { path: '.claude/hooks/privacy-block.sh', label: 'Privacy guard' },
102
+ { path: '.claude/hooks/pre-commit-gate.sh', label: 'Commit gate' },
103
+ ];
104
+
105
+ for (const c of checks) {
106
+ const full = join(rootDir, c.path);
107
+ if (existsSync(full)) {
108
+ ok(`${c.label}: ${c.path}`);
109
+ } else {
110
+ warn(`${c.label}: missing (${c.path})`);
111
+ }
112
+ }
113
+
114
+ log('');
115
+ info('Run `dw metrics show` for detailed telemetry, `dw doctor` for full health check.');
116
+ }
@@ -1,149 +1,165 @@
1
- import { existsSync, readFileSync } from 'node:fs';
2
- import { join, resolve } from 'node:path';
3
- import { fileURLToPath } from 'node:url';
4
- import { header, ok, warn, err, info, log } from '../lib/ui.mjs';
5
- import { loadConfig, getToolkitVersions } from '../lib/config.mjs';
6
- import { detectPlatform, platformLabel } from '../lib/platform.mjs';
7
-
8
- const TOOLKIT_ROOT = resolve(fileURLToPath(import.meta.url), '..', '..', '..');
9
-
10
- const CORE_FILES = [
11
- '.dw/core/WORKFLOW.md',
12
- '.dw/core/THINKING.md',
13
- '.dw/core/QUALITY.md',
14
- '.dw/core/ROLES.md',
15
- ];
16
-
17
- const CONFIG_FILES = [
18
- '.dw/config/dw.config.yml',
19
- '.dw/config/config.schema.json',
20
- ];
21
-
22
- const CLAUDE_ESSENTIAL = [
23
- '.claude/settings.json',
24
- '.claude/hooks/pre-commit-gate.sh',
25
- '.claude/hooks/safety-guard.sh',
26
- ];
27
-
28
- export async function doctorCommand() {
29
- const projectDir = process.cwd();
30
-
31
- header('dw-kit Doctor');
32
- let issues = 0;
33
- let warnings = 0;
34
-
35
- info('Environment');
36
- log(`Node.js : ${process.version}`);
37
- log(`Platform : ${process.platform} ${process.arch}`);
38
- log(`Working dir : ${projectDir}`);
39
-
40
- const pkg = JSON.parse(readFileSync(join(TOOLKIT_ROOT, 'package.json'), 'utf-8'));
41
- log(`dw-kit CLI : v${pkg.version}`);
42
-
43
- const platform = detectPlatform(projectDir);
44
- log(`AI Platform : ${platformLabel(platform)}`);
45
-
46
- info('Core Files (Layer 0)');
47
- for (const file of CORE_FILES) {
48
- const fullPath = join(projectDir, file);
49
- if (existsSync(fullPath)) {
50
- ok(file);
51
- } else {
52
- err(`${file} — MISSING`);
53
- issues++;
54
- }
55
- }
56
-
57
- info('Config (Layer 2)');
58
- for (const file of CONFIG_FILES) {
59
- const fullPath = join(projectDir, file);
60
- if (existsSync(fullPath)) {
61
- ok(file);
62
- } else {
63
- err(`${file} — MISSING`);
64
- issues++;
65
- }
66
- }
67
-
68
- const configPath = join(projectDir, '.dw', 'config', 'dw.config.yml');
69
- if (existsSync(configPath)) {
70
- const config = loadConfig(configPath);
71
- if (config) {
72
- const versions = getToolkitVersions(config);
73
- log(` Core version : ${versions.core}`);
74
- log(` Platform version : ${versions.platform}`);
75
-
76
- const toolkitConfig = loadConfig(join(TOOLKIT_ROOT, '.dw', 'config', 'dw.config.yml'));
77
- if (toolkitConfig) {
78
- const toolkitVersions = getToolkitVersions(toolkitConfig);
79
- if (versions.core !== toolkitVersions.core) {
80
- warn(`Update available: ${versions.core} → ${toolkitVersions.core} (run \`dw upgrade\`)`);
81
- warnings++;
82
- }
83
- }
84
- } else {
85
- err('.dw/config/dw.config.yml YAML parse error');
86
- issues++;
87
- }
88
- }
89
-
90
- info('Claude Files (Layer 1)');
91
- if (platform === 'claude-cli' || existsSync(join(projectDir, '.claude'))) {
92
- for (const file of CLAUDE_ESSENTIAL) {
93
- const fullPath = join(projectDir, file);
94
- if (existsSync(fullPath)) {
95
- ok(file);
96
- } else {
97
- warn(`${file} missing (optional for non-Claude platforms)`);
98
- warnings++;
99
- }
100
- }
101
-
102
- if (existsSync(join(projectDir, 'CLAUDE.md'))) {
103
- ok('CLAUDE.md');
104
- } else {
105
- warn('CLAUDE.md — missing');
106
- warnings++;
107
- }
108
- } else {
109
- log('Skipped — not a Claude CLI project');
110
- }
111
-
112
- info('Adapter Structure (Layer 3)');
113
- const adapterDirs = [
114
- '.dw/adapters/claude-cli/generated',
115
- '.dw/adapters/claude-cli/overrides',
116
- '.dw/adapters/claude-cli/extensions',
117
- ];
118
- for (const dir of adapterDirs) {
119
- if (existsSync(join(projectDir, dir))) {
120
- ok(dir);
121
- } else {
122
- warn(`${dir} — missing`);
123
- warnings++;
124
- }
125
- }
126
-
127
- info('Runtime Directories');
128
- for (const dir of ['.dw/tasks', '.dw/docs']) {
129
- if (existsSync(join(projectDir, dir))) {
130
- ok(dir);
131
- } else {
132
- warn(`${dir} — missing (will be created on first use)`);
133
- warnings++;
134
- }
135
- }
136
-
137
- console.log();
138
- header('Diagnosis');
139
- if (issues === 0 && warnings === 0) {
140
- ok('Everything looks good!');
141
- } else if (issues === 0) {
142
- warn(`${warnings} warning(s), 0 errors — mostly fine`);
143
- } else {
144
- err(`${issues} error(s), ${warnings} warning(s) — run \`dw init\` to fix`);
145
- }
146
- console.log();
147
-
148
- process.exit(issues > 0 ? 1 : 0);
149
- }
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join, resolve } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { header, ok, warn, err, info, log } from '../lib/ui.mjs';
5
+ import { loadConfig, getToolkitVersions } from '../lib/config.mjs';
6
+ import { detectPlatform, platformLabel } from '../lib/platform.mjs';
7
+
8
+ const TOOLKIT_ROOT = resolve(fileURLToPath(import.meta.url), '..', '..', '..');
9
+
10
+ const CORE_FILES = [
11
+ '.dw/core/WORKFLOW.md',
12
+ '.dw/core/THINKING.md',
13
+ '.dw/core/QUALITY.md',
14
+ '.dw/core/ROLES.md',
15
+ ];
16
+
17
+ const V2_OPTIONAL = [
18
+ '.dw/core/PILLARS.md',
19
+ '.dw/decisions',
20
+ '.dw/tasks/ACTIVE.md',
21
+ '.dw/metrics',
22
+ ];
23
+
24
+ const CONFIG_FILES = [
25
+ '.dw/config/dw.config.yml',
26
+ '.dw/config/config.schema.json',
27
+ ];
28
+
29
+ const CLAUDE_ESSENTIAL = [
30
+ '.claude/settings.json',
31
+ '.claude/hooks/pre-commit-gate.sh',
32
+ '.claude/hooks/safety-guard.sh',
33
+ ];
34
+
35
+ export async function doctorCommand() {
36
+ const projectDir = process.cwd();
37
+
38
+ header('dw-kit Doctor');
39
+ let issues = 0;
40
+ let warnings = 0;
41
+
42
+ info('Environment');
43
+ log(`Node.js : ${process.version}`);
44
+ log(`Platform : ${process.platform} ${process.arch}`);
45
+ log(`Working dir : ${projectDir}`);
46
+
47
+ const pkg = JSON.parse(readFileSync(join(TOOLKIT_ROOT, 'package.json'), 'utf-8'));
48
+ log(`dw-kit CLI : v${pkg.version}`);
49
+
50
+ const platform = detectPlatform(projectDir);
51
+ log(`AI Platform : ${platformLabel(platform)}`);
52
+
53
+ info('Core Files (Layer 0)');
54
+ for (const file of CORE_FILES) {
55
+ const fullPath = join(projectDir, file);
56
+ if (existsSync(fullPath)) {
57
+ ok(file);
58
+ } else {
59
+ err(`${file} MISSING`);
60
+ issues++;
61
+ }
62
+ }
63
+
64
+ info('Config (Layer 2)');
65
+ for (const file of CONFIG_FILES) {
66
+ const fullPath = join(projectDir, file);
67
+ if (existsSync(fullPath)) {
68
+ ok(file);
69
+ } else {
70
+ err(`${file} MISSING`);
71
+ issues++;
72
+ }
73
+ }
74
+
75
+ const configPath = join(projectDir, '.dw', 'config', 'dw.config.yml');
76
+ if (existsSync(configPath)) {
77
+ const config = loadConfig(configPath);
78
+ if (config) {
79
+ const versions = getToolkitVersions(config);
80
+ log(` Core version : ${versions.core}`);
81
+ log(` Platform version : ${versions.platform}`);
82
+
83
+ const toolkitConfig = loadConfig(join(TOOLKIT_ROOT, '.dw', 'config', 'dw.config.yml'));
84
+ if (toolkitConfig) {
85
+ const toolkitVersions = getToolkitVersions(toolkitConfig);
86
+ if (versions.core !== toolkitVersions.core) {
87
+ warn(`Update available: ${versions.core} → ${toolkitVersions.core} (run \`dw upgrade\`)`);
88
+ warnings++;
89
+ }
90
+ }
91
+ } else {
92
+ err('.dw/config/dw.config.yml YAML parse error');
93
+ issues++;
94
+ }
95
+ }
96
+
97
+ info('Claude Files (Layer 1)');
98
+ if (platform === 'claude-cli' || existsSync(join(projectDir, '.claude'))) {
99
+ for (const file of CLAUDE_ESSENTIAL) {
100
+ const fullPath = join(projectDir, file);
101
+ if (existsSync(fullPath)) {
102
+ ok(file);
103
+ } else {
104
+ warn(`${file} missing (optional for non-Claude platforms)`);
105
+ warnings++;
106
+ }
107
+ }
108
+
109
+ if (existsSync(join(projectDir, 'CLAUDE.md'))) {
110
+ ok('CLAUDE.md');
111
+ } else {
112
+ warn('CLAUDE.md missing');
113
+ warnings++;
114
+ }
115
+ } else {
116
+ log('Skipped — not a Claude CLI project');
117
+ }
118
+
119
+ info('Adapter Structure (Layer 3)');
120
+ const adapterDirs = [
121
+ '.dw/adapters/claude-cli/generated',
122
+ '.dw/adapters/claude-cli/overrides',
123
+ '.dw/adapters/claude-cli/extensions',
124
+ ];
125
+ for (const dir of adapterDirs) {
126
+ if (existsSync(join(projectDir, dir))) {
127
+ ok(dir);
128
+ } else {
129
+ warn(`${dir} — missing`);
130
+ warnings++;
131
+ }
132
+ }
133
+
134
+ info('Runtime Directories');
135
+ for (const dir of ['.dw/tasks', '.dw/docs']) {
136
+ if (existsSync(join(projectDir, dir))) {
137
+ ok(dir);
138
+ } else {
139
+ warn(`${dir} — missing (will be created on first use)`);
140
+ warnings++;
141
+ }
142
+ }
143
+
144
+ info('v2 Artifacts (optional)');
145
+ for (const path of V2_OPTIONAL) {
146
+ if (existsSync(join(projectDir, path))) {
147
+ ok(path);
148
+ } else {
149
+ log(` ${path} — not yet created (opt-in)`);
150
+ }
151
+ }
152
+
153
+ console.log();
154
+ header('Diagnosis');
155
+ if (issues === 0 && warnings === 0) {
156
+ ok('Everything looks good!');
157
+ } else if (issues === 0) {
158
+ warn(`${warnings} warning(s), 0 errors — mostly fine`);
159
+ } else {
160
+ err(`${issues} error(s), ${warnings} warning(s) — run \`dw init\` to fix`);
161
+ }
162
+ console.log();
163
+
164
+ process.exit(issues > 0 ? 1 : 0);
165
+ }