dw-kit 1.1.0 → 1.2.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dw-kit",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI development workflow toolkit — structured, quality-assured, team-ready. From requirements to dashboard.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -8,15 +8,42 @@
8
8
  },
9
9
  "files": [
10
10
  "bin/",
11
- "src/",
11
+ "src/cli.mjs",
12
+ "src/commands/",
13
+ "src/lib/",
12
14
  ".dw/core/",
13
15
  ".dw/config/",
14
16
  ".dw/adapters/",
15
- "scripts/",
16
17
  ".claude/agents/",
17
18
  ".claude/hooks/",
18
19
  ".claude/rules/",
19
- ".claude/skills/",
20
+ ".claude/skills/dw-arch-review/",
21
+ ".claude/skills/dw-archive/",
22
+ ".claude/skills/dw-commit/",
23
+ ".claude/skills/dw-config-init/",
24
+ ".claude/skills/dw-config-validate/",
25
+ ".claude/skills/dw-dashboard/",
26
+ ".claude/skills/dw-debug/",
27
+ ".claude/skills/dw-docs-update/",
28
+ ".claude/skills/dw-estimate/",
29
+ ".claude/skills/dw-execute/",
30
+ ".claude/skills/dw-flow/",
31
+ ".claude/skills/dw-handoff/",
32
+ ".claude/skills/dw-kit-report/",
33
+ ".claude/skills/dw-log-work/",
34
+ ".claude/skills/dw-onboard/",
35
+ ".claude/skills/dw-plan/",
36
+ ".claude/skills/dw-prompt/",
37
+ ".claude/skills/dw-requirements/",
38
+ ".claude/skills/dw-research/",
39
+ ".claude/skills/dw-retroactive/",
40
+ ".claude/skills/dw-review/",
41
+ ".claude/skills/dw-rollback/",
42
+ ".claude/skills/dw-sprint-review/",
43
+ ".claude/skills/dw-task-init/",
44
+ ".claude/skills/dw-test-plan/",
45
+ ".claude/skills/dw-thinking/",
46
+ ".claude/skills/dw-upgrade/",
20
47
  ".claude/templates/",
21
48
  ".claude/settings.json",
22
49
  "CLAUDE.md"
package/src/cli.mjs CHANGED
@@ -1,92 +1,92 @@
1
- import { Command } from 'commander';
2
- import { createRequire } from 'node:module';
3
- import { fileURLToPath } from 'node:url';
4
- import { dirname, join } from 'node:path';
5
- import chalk from 'chalk';
6
- import { getUpdateNotice, scheduleUpdateCheck } from './lib/update-checker.mjs';
7
-
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = dirname(__filename);
10
- const require = createRequire(import.meta.url);
11
- const pkg = require(join(__dirname, '..', 'package.json'));
12
-
13
- export function run(argv) {
14
- // Show cached update notice (non-blocking), then schedule fresh check in background
15
- const latestVersion = getUpdateNotice(pkg.version);
16
- scheduleUpdateCheck(pkg.version);
17
-
18
- const program = new Command();
19
-
20
- program
21
- .name('dw')
22
- .description('dw-kit — AI development workflow toolkit')
23
- .version(pkg.version, '-v, --version');
24
-
25
- program
26
- .command('init')
27
- .description('Setup dw-kit in current project (interactive wizard)')
28
- .option('-p, --preset <name>', 'Use preset: solo-quick | small-team | enterprise')
29
- .option('-a, --adapter <platform>', 'Target platform: claude-cli | cursor | generic', 'claude-cli')
30
- .option('-s, --silent', 'Non-interactive mode (reads DW_NAME, DW_DEPTH, DW_ROLES, DW_LANG env vars)')
31
- .action(async (opts) => {
32
- const { initCommand } = await import('./commands/init.mjs');
33
- await initCommand(opts);
34
- });
35
-
36
- program
37
- .command('upgrade')
38
- .description('Update dw-kit files in current project')
39
- .option('-n, --dry-run', 'Preview changes without applying')
40
- .option('-c, --check', 'Only check if update is available')
41
- .option('-l, --layer <name>', 'Update specific layer: core | platform | capability | all', 'all')
42
- .action(async (opts) => {
43
- const { upgradeCommand } = await import('./commands/upgrade.mjs');
44
- await upgradeCommand(opts);
45
- });
46
-
47
- program
48
- .command('validate')
49
- .description('Validate .dw/config/dw.config.yml against schema')
50
- .option('-f, --file <path>', 'Config file path', '.dw/config/dw.config.yml')
51
- .action(async (opts) => {
52
- const { validateCommand } = await import('./commands/validate.mjs');
53
- await validateCommand(opts);
54
- });
55
-
56
- program
57
- .command('doctor')
58
- .description('Check dw-kit installation health')
59
- .action(async () => {
60
- const { doctorCommand } = await import('./commands/doctor.mjs');
61
- await doctorCommand();
62
- });
63
-
64
- program
65
- .command('prompt')
66
- .description('Build a well-structured task prompt with autocomplete + guided wizard')
67
- .option('-t, --text <text>', 'Non-interactive: provide description directly')
68
- .action(async (opts) => {
69
- const { promptCommand } = await import('./commands/prompt.mjs');
70
- await promptCommand(opts);
71
- });
72
-
73
- program
74
- .command('claude-vn-fix')
75
- .description('Patch Claude CLI to fix Vietnamese IME (local, with backup/restore)')
76
- .option('--path <file>', 'Path to @anthropic-ai/claude-code/cli.js (optional; auto-detect if omitted)')
77
- .option('--restore', 'Restore from latest backup')
78
- .option('--dry-run', 'Show what would change without writing')
79
- .action(async (opts) => {
80
- const { claudeVnFixCommand } = await import('./commands/claude-vn-fix.mjs');
81
- await claudeVnFixCommand(opts);
82
- });
83
-
84
- program.parse(argv);
85
-
86
- if (latestVersion) {
87
- console.log();
88
- console.log(chalk.yellow(` ↑ Update available`) + ` v${pkg.version} → ` + chalk.green.bold(`v${latestVersion}`));
89
- console.log(` Run ` + chalk.cyan(`npm install -g dw-kit`) + ` to update`);
90
- console.log();
91
- }
92
- }
1
+ import { Command } from 'commander';
2
+ import { createRequire } from 'node:module';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { dirname, join } from 'node:path';
5
+ import chalk from 'chalk';
6
+ import { getUpdateNotice, scheduleUpdateCheck } from './lib/update-checker.mjs';
7
+
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = dirname(__filename);
10
+ const require = createRequire(import.meta.url);
11
+ const pkg = require(join(__dirname, '..', 'package.json'));
12
+
13
+ export function run(argv) {
14
+ // Show cached update notice (non-blocking), then schedule fresh check in background
15
+ const latestVersion = getUpdateNotice(pkg.version);
16
+ scheduleUpdateCheck(pkg.version);
17
+
18
+ const program = new Command();
19
+
20
+ program
21
+ .name('dw')
22
+ .description('dw-kit — AI development workflow toolkit')
23
+ .version(pkg.version, '-v, --version');
24
+
25
+ program
26
+ .command('init')
27
+ .description('Setup dw-kit in current project (interactive wizard)')
28
+ .option('-p, --preset <name>', 'Use preset: solo-quick | small-team | enterprise')
29
+ .option('-a, --adapter <platform>', 'Target platform: claude-cli | cursor | generic', 'claude-cli')
30
+ .option('-s, --silent', 'Non-interactive mode (reads DW_NAME, DW_DEPTH, DW_ROLES, DW_LANG env vars)')
31
+ .action(async (opts) => {
32
+ const { initCommand } = await import('./commands/init.mjs');
33
+ await initCommand(opts);
34
+ });
35
+
36
+ program
37
+ .command('upgrade')
38
+ .description('Update dw-kit files in current project')
39
+ .option('-n, --dry-run', 'Preview changes without applying')
40
+ .option('-c, --check', 'Only check if update is available')
41
+ .option('-l, --layer <name>', 'Update specific layer: core | platform | capability | all', 'all')
42
+ .action(async (opts) => {
43
+ const { upgradeCommand } = await import('./commands/upgrade.mjs');
44
+ await upgradeCommand(opts);
45
+ });
46
+
47
+ program
48
+ .command('validate')
49
+ .description('Validate .dw/config/dw.config.yml against schema')
50
+ .option('-f, --file <path>', 'Config file path', '.dw/config/dw.config.yml')
51
+ .action(async (opts) => {
52
+ const { validateCommand } = await import('./commands/validate.mjs');
53
+ await validateCommand(opts);
54
+ });
55
+
56
+ program
57
+ .command('doctor')
58
+ .description('Check dw-kit installation health')
59
+ .action(async () => {
60
+ const { doctorCommand } = await import('./commands/doctor.mjs');
61
+ await doctorCommand();
62
+ });
63
+
64
+ program
65
+ .command('prompt')
66
+ .description('Build a well-structured task prompt with autocomplete + guided wizard')
67
+ .option('-t, --text <text>', 'Non-interactive: provide description directly')
68
+ .action(async (opts) => {
69
+ const { promptCommand } = await import('./commands/prompt.mjs');
70
+ await promptCommand(opts);
71
+ });
72
+
73
+ program
74
+ .command('claude-vn-fix')
75
+ .description('Patch Claude CLI to fix Vietnamese IME (local, with backup/restore)')
76
+ .option('--path <file>', 'Path to @anthropic-ai/claude-code/cli.js (optional; auto-detect if omitted)')
77
+ .option('--restore', 'Restore from latest backup')
78
+ .option('--dry-run', 'Show what would change without writing')
79
+ .action(async (opts) => {
80
+ const { claudeVnFixCommand } = await import('./commands/claude-vn-fix.mjs');
81
+ await claudeVnFixCommand(opts);
82
+ });
83
+
84
+ program.parse(argv);
85
+
86
+ if (latestVersion) {
87
+ console.log();
88
+ console.log(chalk.yellow(` ↑ Update available`) + ` v${pkg.version} → ` + chalk.green.bold(`v${latestVersion}`));
89
+ console.log(` Run ` + chalk.cyan(`npm install -g dw-kit`) + ` to update`);
90
+ console.log();
91
+ }
92
+ }
@@ -135,7 +135,7 @@ async function setupProject(projectDir, { projectName, depth, roles, language, a
135
135
 
136
136
  if (adapter === 'claude-cli') {
137
137
  copyClaudeFiles(projectDir);
138
- copyCLAUDEmd(projectDir);
138
+ createMinimalCLAUDEmd(projectDir, projectName);
139
139
  } else if (adapter === 'cursor') {
140
140
  copyCursorFiles(projectDir);
141
141
  copyGenericAdapter(projectDir);
@@ -191,34 +191,34 @@ function copyClaudeFiles(projectDir) {
191
191
  if (skipCount > 0) log(` ${skipCount} existing files preserved`);
192
192
  }
193
193
 
194
- function copyCLAUDEmd(projectDir) {
195
- const src = join(TOOLKIT_ROOT, 'CLAUDE.md');
194
+ function createMinimalCLAUDEmd(projectDir, projectName) {
196
195
  const dst = join(projectDir, 'CLAUDE.md');
197
196
 
198
197
  if (existsSync(dst)) {
199
- warn('CLAUDE.md already exists skipping (review manually if needed)');
198
+ // User already has their own CLAUDE.md — leave it completely alone
200
199
  return;
201
200
  }
202
201
 
203
- copyFile(src, dst);
202
+ const content = `# ${projectName}
203
+
204
+ > Add your project description here.
204
205
 
205
- const techStackSection = `
206
206
  ---
207
207
 
208
208
  ## Tech Stack
209
209
 
210
210
  <!-- Update with your project's actual stack -->
211
- - Framework: [e.g. NestJS / Django / Laravel / Next.js]
212
- - Database: [e.g. PostgreSQL / MySQL / MongoDB]
213
- - Testing: [e.g. Jest / Pytest / PHPUnit]
211
+ - Framework:
212
+ - Database:
213
+ - Testing:
214
214
 
215
215
  ## Project-Specific Rules
216
216
 
217
- <!-- Add project-specific rules -->
218
- - [Rule 1]
217
+ <!-- Add project-specific rules here -->
218
+ <!-- dw workflow rules are auto-loaded from .claude/rules/ -->
219
219
  `;
220
- appendFileSync(dst, techStackSection, 'utf-8');
221
- ok('CLAUDE.md (with Tech Stack template section)');
220
+ writeFileSync(dst, content, 'utf-8');
221
+ ok('CLAUDE.md (minimal project template — dw rules are in .claude/rules/)');
222
222
  }
223
223
 
224
224
  function copyCursorFiles(projectDir) {
@@ -276,7 +276,7 @@ function createRuntimeDirs(projectDir) {
276
276
 
277
277
  function updateGitignore(projectDir) {
278
278
  const gitignorePath = join(projectDir, '.gitignore');
279
- const entriesToAdd = ['CLAUDE.local.md', '.claude/settings.local.json'];
279
+ const entriesToAdd = ['CLAUDE.local.md', '.claude/settings.local.json', '.dw/config/dw.config.local.yml'];
280
280
 
281
281
  if (existsSync(gitignorePath)) {
282
282
  const content = readFileSync(gitignorePath, 'utf-8');
@@ -304,8 +304,8 @@ function printSummary({ projectName, depth, roles, language, adapter }) {
304
304
  console.log(` Files created:`);
305
305
  console.log(` .dw/ — core/, config/, adapters/, tasks, docs`);
306
306
  if (adapter === 'claude-cli') {
307
- console.log(` .claude/ — skills, agents, hooks, rules`);
308
- console.log(` CLAUDE.md`);
307
+ console.log(` .claude/ — skills, agents, hooks, rules/`);
308
+ console.log(` CLAUDE.md — minimal project template (dw rules in .claude/rules/)`);
309
309
  } else if (adapter === 'cursor') {
310
310
  console.log(` .cursor/rules/ — workflow rules for Cursor`);
311
311
  console.log(` AGENT.md — methodology reference`);
@@ -317,7 +317,7 @@ function printSummary({ projectName, depth, roles, language, adapter }) {
317
317
  console.log(` Next steps:`);
318
318
  console.log(` Run: claude (to open Claude Code in this directory in terminal)`);
319
319
  console.log(` Run: /dw-flow [task-name]`);
320
- console.log(` Suggested: Update Tech Stack in CLAUDE.md (optional, recommended)`);
320
+ console.log(` Suggested: Update Tech Stack + rules in CLAUDE.md`);
321
321
  } else if (adapter === 'cursor') {
322
322
  console.log(` Next steps:`);
323
323
  console.log(` 1. Open Cursor in this directory`);
@@ -7,6 +7,35 @@ export function loadConfig(configPath) {
7
7
  return yaml.load(content);
8
8
  }
9
9
 
10
+ /**
11
+ * Load config với local override (v1.2+).
12
+ * dw.config.yml — shared, committed
13
+ * dw.config.local.yml — machine-specific, gitignored
14
+ * Local values win over base values (shallow merge per top-level key).
15
+ */
16
+ export function loadConfigWithLocal(configDir) {
17
+ const basePath = `${configDir}/dw.config.yml`;
18
+ const localPath = `${configDir}/dw.config.local.yml`;
19
+
20
+ const base = loadConfig(basePath);
21
+ if (!base) return null;
22
+
23
+ if (!existsSync(localPath)) return base;
24
+
25
+ const local = loadConfig(localPath);
26
+ if (!local) return base;
27
+
28
+ const merged = { ...base };
29
+ for (const key of Object.keys(local)) {
30
+ if (typeof local[key] === 'object' && !Array.isArray(local[key]) && local[key] !== null) {
31
+ merged[key] = { ...(merged[key] || {}), ...local[key] };
32
+ } else {
33
+ merged[key] = local[key];
34
+ }
35
+ }
36
+ return merged;
37
+ }
38
+
10
39
  export function writeConfig(configPath, data) {
11
40
  const content = yaml.dump(data, {
12
41
  indent: 2,
@@ -57,9 +86,9 @@ export function buildConfig({ projectName, language, depth, roles }) {
57
86
  mcp: [],
58
87
  },
59
88
  _toolkit: {
60
- core_version: '1.0',
89
+ core_version: '1.2',
61
90
  platform_version: '1.0',
62
- capability_version: '1.0',
91
+ capability_version: '1.2',
63
92
  installed: today,
64
93
  last_upgrade: today,
65
94
  },
@@ -1,75 +0,0 @@
1
- #!/bin/bash
2
- # scripts/e2e-local-check.sh
3
- # End-to-end local publish check (pack -> install -> run CLI)
4
-
5
- set -euo pipefail
6
-
7
- ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
- cd "$ROOT_DIR"
9
-
10
- log() { echo " $*"; }
11
- info() { echo ""; echo "▶ $*"; }
12
- ok() { echo " ✓ $*"; }
13
- warn() { echo " ⚠ $*"; }
14
-
15
- cleanup() {
16
- if [ -n "${TMP_DIR:-}" ] && [ -d "${TMP_DIR:-}" ]; then
17
- rm -rf "$TMP_DIR"
18
- fi
19
- if [ -n "${PACK_FILE:-}" ] && [ -f "${PACK_FILE:-}" ]; then
20
- rm -f "$PACK_FILE"
21
- fi
22
- }
23
- trap cleanup EXIT
24
-
25
- info "Step 1: Run smoke tests"
26
- npm test
27
- ok "Smoke tests passed"
28
-
29
- info "Step 2: Build npm package tarball"
30
- PACK_OUTPUT="$(npm pack)"
31
- PACK_FILE="$(echo "$PACK_OUTPUT" | tail -n 1 | tr -d '\r')"
32
- if [ ! -f "$PACK_FILE" ]; then
33
- echo " ✗ Failed to produce package tarball"
34
- exit 1
35
- fi
36
- ok "Tarball: $PACK_FILE"
37
-
38
- info "Step 3: Create isolated test project"
39
- TMP_DIR="$(mktemp -d 2>/dev/null || true)"
40
- if [ -z "${TMP_DIR}" ]; then
41
- TMP_DIR=".tmp-e2e-local-check"
42
- rm -rf "$TMP_DIR"
43
- mkdir -p "$TMP_DIR"
44
- fi
45
- TEST_DIR="$TMP_DIR/e2e-project"
46
- mkdir -p "$TEST_DIR"
47
- cd "$TEST_DIR"
48
- npm init -y >/dev/null 2>&1
49
- git init >/dev/null 2>&1 || true
50
- ok "Created isolated project at $TEST_DIR"
51
-
52
- info "Step 4: Install from local tarball"
53
- npm install "$ROOT_DIR/$PACK_FILE" >/dev/null
54
- ok "Installed package from tarball"
55
-
56
- info "Step 5: Run CLI checks in isolated project"
57
- VERSION_OUT="$(npx dw --version | tr -d '\r')"
58
- log "dw --version: $VERSION_OUT"
59
- npx dw init --preset small-team
60
- npx dw validate
61
- npx dw doctor
62
- npx dw upgrade --check
63
-
64
- info "Step 6: Verify task-depth override guidance artifacts"
65
- grep -q "Task-Level Depth Override" ".dw/core/WORKFLOW.md"
66
- grep -q "Depth Source: default (from config) | override (task-specific)" ".dw/core/templates/vi/task-context.md"
67
- ok "Depth override guidance exists in generated artifacts"
68
-
69
- ok "CLI flow passed in isolated project"
70
-
71
- echo ""
72
- echo "══════════════════════════════════════════"
73
- echo " E2E local check passed"
74
- echo "══════════════════════════════════════════"
75
- echo ""
@@ -1,15 +0,0 @@
1
- // Minimal fixture that contains the known Vietnamese IME bug pattern.
2
- // This is NOT the real Claude CLI; only used for testing the patcher logic.
3
- //
4
- // IMPORTANT: The comment below must contain both '@anthropic-ai' and 'claude-code'
5
- // to pass the bundle signature guard in patchCliJs(). Do not remove it.
6
- // @anthropic-ai/claude-code bundle stub
7
-
8
- function demo(INPUT) {
9
- if(INPUT.includes("\x7f")){
10
- let COUNT=(INPUT.match(/\x7f/g)||[]).length,STATE=CURSTATE;
11
- UPDATETEXT(STATE.text);UPDATEOFFSET(STATE.offset)
12
- return;
13
- }
14
- }
15
-