@hacksmith/doraval 0.2.20 → 0.2.21

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 (3) hide show
  1. package/README.md +2 -0
  2. package/bin/doraval.js +288 -100
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -142,6 +142,8 @@ doraval journal update # pull latest from remote
142
142
 
143
143
  Requires the GitHub CLI (`gh`). Journal lives in a private GitHub repo you control.
144
144
 
145
+ doraval claude new # interactive wizard for skills/plugins (follows official table)
146
+
145
147
  ## Options
146
148
 
147
149
  | Flag | Short | Description |
package/bin/doraval.js CHANGED
@@ -2588,8 +2588,183 @@ var init_sync = __esm(() => {
2588
2588
  });
2589
2589
  });
2590
2590
 
2591
+ // src/cli/commands/claude/context.ts
2592
+ import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
2593
+ import { join as join7 } from "path";
2594
+ function detectContext(cwd = process.cwd()) {
2595
+ const hasClaudeDir = existsSync8(join7(cwd, ".claude"));
2596
+ const hasPluginManifest = existsSync8(join7(cwd, ".claude-plugin", "plugin.json"));
2597
+ let looseSkillFiles = [];
2598
+ try {
2599
+ const files = readdirSync3(cwd);
2600
+ looseSkillFiles = files.filter((f) => {
2601
+ if (!f.endsWith(".md") || f.startsWith("."))
2602
+ return false;
2603
+ const lower = f.toLowerCase();
2604
+ if (lower === "readme.md" || lower === "changelog.md" || lower === "license.md" || lower.includes("contributing"))
2605
+ return false;
2606
+ return lower.includes("skill") || lower === "skill.md";
2607
+ });
2608
+ } catch {}
2609
+ const isEmpty = !hasClaudeDir && !hasPluginManifest && looseSkillFiles.length === 0;
2610
+ return {
2611
+ cwd,
2612
+ hasClaudeDir,
2613
+ hasPluginManifest,
2614
+ looseSkillFiles,
2615
+ isEmpty
2616
+ };
2617
+ }
2618
+ var init_context = () => {};
2619
+
2620
+ // src/cli/commands/claude/new.ts
2621
+ var exports_new = {};
2622
+ __export(exports_new, {
2623
+ scaffold: () => scaffold,
2624
+ default: () => new_default,
2625
+ decidePath: () => decidePath
2626
+ });
2627
+ import { join as join8 } from "path";
2628
+ import { mkdirSync as mkdirSync2, writeFileSync, existsSync as existsSync9 } from "fs";
2629
+ function decidePath(ctx, intent, providedName) {
2630
+ const rawName = providedName || "";
2631
+ let path = "standalone";
2632
+ let targetDir = ctx.cwd;
2633
+ let shouldCreateDir = false;
2634
+ let migrateExisting = false;
2635
+ const useCurrentDirAsRoot = rawName === "." || rawName === path.basename(ctx.cwd) || !rawName;
2636
+ if (intent === "distribute" || intent === "self-later" && ctx.looseSkillFiles.length > 0 && !ctx.hasClaudeDir) {
2637
+ path = "plugin";
2638
+ if (useCurrentDirAsRoot) {
2639
+ targetDir = ctx.cwd;
2640
+ shouldCreateDir = false;
2641
+ } else {
2642
+ targetDir = join8(ctx.cwd, rawName);
2643
+ shouldCreateDir = true;
2644
+ }
2645
+ migrateExisting = ctx.looseSkillFiles.length > 0;
2646
+ } else if (intent === "self-later" && !ctx.hasClaudeDir) {
2647
+ path = "plugin";
2648
+ if (useCurrentDirAsRoot) {
2649
+ targetDir = ctx.cwd;
2650
+ shouldCreateDir = false;
2651
+ } else {
2652
+ targetDir = join8(ctx.cwd, rawName);
2653
+ shouldCreateDir = true;
2654
+ }
2655
+ } else if (path === "standalone") {
2656
+ if (useCurrentDirAsRoot) {
2657
+ targetDir = ctx.cwd;
2658
+ shouldCreateDir = false;
2659
+ } else {
2660
+ targetDir = join8(ctx.cwd, rawName);
2661
+ shouldCreateDir = true;
2662
+ }
2663
+ }
2664
+ return { path, targetDir, shouldCreateDir, migrateExisting };
2665
+ }
2666
+ function scaffold(decision, ctx, migrateContent) {
2667
+ const { targetDir, path, shouldCreateDir } = decision;
2668
+ if (existsSync9(targetDir) && shouldCreateDir) {
2669
+ ui.fail("Target already exists");
2670
+ process.exit(1);
2671
+ }
2672
+ if (shouldCreateDir) {
2673
+ mkdirSync2(targetDir, { recursive: true });
2674
+ }
2675
+ if (path === "plugin") {
2676
+ const pluginJson = {
2677
+ name: decision.targetDir.split("/").pop(),
2678
+ description: "Scaffolded by doraval claude new",
2679
+ version: "0.1.0"
2680
+ };
2681
+ mkdirSync2(join8(targetDir, ".claude-plugin"), { recursive: true });
2682
+ writeFileSync(join8(targetDir, ".claude-plugin", "plugin.json"), JSON.stringify(pluginJson, null, 2));
2683
+ mkdirSync2(join8(targetDir, "skills", "my-skill"), { recursive: true });
2684
+ const skillBody = migrateContent || `# My Skill
2685
+
2686
+ Basic starter skill.`;
2687
+ writeFileSync(join8(targetDir, "skills", "my-skill", "SKILL.md"), `---
2688
+ name: my-skill
2689
+ description: Starter skill
2690
+ ---
2691
+
2692
+ ${skillBody}`);
2693
+ writeFileSync(join8(targetDir, "README.md"), "# " + pluginJson.name + `
2694
+
2695
+ Claude Code plugin scaffolded by doraval.`);
2696
+ } else {
2697
+ mkdirSync2(join8(targetDir, ".claude", "skills", "my-skill"), { recursive: true });
2698
+ const skillBody = migrateContent || `# My Skill
2699
+
2700
+ Basic starter.`;
2701
+ writeFileSync(join8(targetDir, ".claude", "skills", "my-skill", "SKILL.md"), `---
2702
+ name: my-skill
2703
+ description: Starter
2704
+ ---
2705
+
2706
+ ${skillBody}`);
2707
+ }
2708
+ }
2709
+ var import_picocolors10, new_default;
2710
+ var init_new = __esm(() => {
2711
+ init_dist();
2712
+ init_out();
2713
+ init_context();
2714
+ init_prompt();
2715
+ import_picocolors10 = __toESM(require_picocolors(), 1);
2716
+ new_default = defineCommand({
2717
+ meta: {
2718
+ name: "new",
2719
+ description: "Create a new skill or plugin following Claude Code packaging rules"
2720
+ },
2721
+ args: {
2722
+ name: {
2723
+ type: "positional",
2724
+ description: "Optional name for the skill or plugin",
2725
+ required: false
2726
+ },
2727
+ yes: {
2728
+ type: "boolean",
2729
+ description: "Skip interactive prompts (use defaults and flags)",
2730
+ default: false
2731
+ },
2732
+ intent: {
2733
+ type: "string",
2734
+ description: 'Intent: "self" | "self-later" | "distribute"',
2735
+ required: false
2736
+ }
2737
+ },
2738
+ run({ args }) {
2739
+ ui.heading("doraval claude new \u2014 Context-aware scaffolding");
2740
+ const ctx = detectContext();
2741
+ let intent = args.intent || "self-later";
2742
+ if (!args.yes) {
2743
+ const ans = prompt(" Intent (self | self-later | distribute)", intent);
2744
+ intent = ans || intent;
2745
+ }
2746
+ const decision = decidePath(ctx, intent, args.name);
2747
+ ui.info(` Decision: path=${decision.path}, target=${decision.targetDir}`);
2748
+ let migrateContent;
2749
+ if (decision.migrateExisting && !args.yes) {
2750
+ migrateContent = "Content from your existing SKILL.md (user-confirmed).";
2751
+ }
2752
+ scaffold(decision, ctx, migrateContent);
2753
+ ui.write(`
2754
+ ${import_picocolors10.default.green("\u2713")} Created ${decision.path} at ${import_picocolors10.default.bold(decision.targetDir)}`);
2755
+ ui.info(` Command: ${decision.path === "plugin" ? `/${decision.targetDir.split("/").pop()}:my-skill` : "/my-skill"}`);
2756
+ ui.info(` Test: claude --plugin-dir ${decision.targetDir} (or use normally for standalone)`);
2757
+ ui.info(` Validate: doraval validate ${decision.targetDir}`);
2758
+ if (decision.path === "plugin" && decision.migrateExisting) {
2759
+ ui.info(" (Existing content migrated where confirmed.)");
2760
+ }
2761
+ process.exit(0);
2762
+ }
2763
+ });
2764
+ });
2765
+
2591
2766
  // src/validators/claude/skill.ts
2592
- import { existsSync as existsSync8 } from "fs";
2767
+ import { existsSync as existsSync10 } from "fs";
2593
2768
  import { resolve as resolve3 } from "path";
2594
2769
  var OPTIONAL_DIRS2, claudeSkillValidator;
2595
2770
  var init_skill = __esm(() => {
@@ -2602,7 +2777,7 @@ var init_skill = __esm(() => {
2602
2777
  name: "Claude Skill",
2603
2778
  description: "Validates SKILL.md per current Claude Code spec: frontmatter (name/description relaxed to recommended; directory name usually provides the /command), body, supporting files, dynamic injection (!`cmd`), substitutions ($ARGUMENTS, ${CLAUDE_*}), and advanced fields (allowed-tools, context, disable-model-invocation, when_to_use, etc.)",
2604
2779
  detect(dir) {
2605
- return existsSync8(resolve3(dir, "SKILL.md"));
2780
+ return existsSync10(resolve3(dir, "SKILL.md"));
2606
2781
  },
2607
2782
  async validate(dir, _opts) {
2608
2783
  const skillMd = resolve3(dir, "SKILL.md");
@@ -2617,15 +2792,15 @@ var init_skill = __esm(() => {
2617
2792
  passes: []
2618
2793
  };
2619
2794
  }
2620
- const existingDirs = OPTIONAL_DIRS2.filter((d) => existsSync8(resolve3(dir, d)));
2795
+ const existingDirs = OPTIONAL_DIRS2.filter((d) => existsSync10(resolve3(dir, d)));
2621
2796
  return validateSkillModel(parsed, { existingDirs: [...existingDirs] });
2622
2797
  }
2623
2798
  };
2624
2799
  });
2625
2800
 
2626
2801
  // src/validators/claude/plugin.ts
2627
- import { existsSync as existsSync9, readdirSync as readdirSync3 } from "fs";
2628
- import { resolve as resolve4, join as join7 } from "path";
2802
+ import { existsSync as existsSync11, readdirSync as readdirSync4 } from "fs";
2803
+ import { resolve as resolve4, join as join9 } from "path";
2629
2804
  var NAME_REGEX2, RELATIVE_PATH_REGEX, claudePluginValidator;
2630
2805
  var init_plugin = __esm(() => {
2631
2806
  NAME_REGEX2 = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
@@ -2636,7 +2811,7 @@ var init_plugin = __esm(() => {
2636
2811
  name: "Claude Plugin",
2637
2812
  description: "Validates .claude-plugin/plugin.json manifest, component directories, and structure",
2638
2813
  detect(dir) {
2639
- return existsSync9(resolve4(dir, ".claude-plugin", "plugin.json"));
2814
+ return existsSync11(resolve4(dir, ".claude-plugin", "plugin.json"));
2640
2815
  },
2641
2816
  async validate(dir, _opts) {
2642
2817
  const errors = [];
@@ -2686,7 +2861,7 @@ var init_plugin = __esm(() => {
2686
2861
  errors.push(`${field}: path "${s}" must start with "./" (relative)`);
2687
2862
  } else if (s.includes("..")) {
2688
2863
  errors.push(`${field}: path "${s}" must not use ".." (no parent traversal)`);
2689
- } else if (existsSync9(resolve4(dir, s))) {
2864
+ } else if (existsSync11(resolve4(dir, s))) {
2690
2865
  passes.push(`${field}: path "${s}" exists`);
2691
2866
  } else {
2692
2867
  warnings.push(`${field}: path "${s}" does not exist on disk`);
@@ -2699,11 +2874,11 @@ var init_plugin = __esm(() => {
2699
2874
  }
2700
2875
  }
2701
2876
  const skillsDir = resolve4(dir, "skills");
2702
- if (existsSync9(skillsDir)) {
2703
- const skillEntries = readdirSync3(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory());
2877
+ if (existsSync11(skillsDir)) {
2878
+ const skillEntries = readdirSync4(skillsDir, { withFileTypes: true }).filter((e) => e.isDirectory());
2704
2879
  for (const skill of skillEntries) {
2705
- const skillMd = join7(skillsDir, skill.name, "SKILL.md");
2706
- if (existsSync9(skillMd)) {
2880
+ const skillMd = join9(skillsDir, skill.name, "SKILL.md");
2881
+ if (existsSync11(skillMd)) {
2707
2882
  passes.push(`skills/${skill.name}/SKILL.md exists`);
2708
2883
  } else {
2709
2884
  errors.push(`skills/${skill.name}/ missing SKILL.md`);
@@ -2711,8 +2886,8 @@ var init_plugin = __esm(() => {
2711
2886
  }
2712
2887
  }
2713
2888
  const commandsDir = resolve4(dir, "commands");
2714
- if (existsSync9(commandsDir)) {
2715
- const mdFiles = readdirSync3(commandsDir).filter((f) => f.endsWith(".md"));
2889
+ if (existsSync11(commandsDir)) {
2890
+ const mdFiles = readdirSync4(commandsDir).filter((f) => f.endsWith(".md"));
2716
2891
  if (mdFiles.length > 0) {
2717
2892
  passes.push(`commands/ has ${mdFiles.length} .md file(s)`);
2718
2893
  } else {
@@ -2720,8 +2895,8 @@ var init_plugin = __esm(() => {
2720
2895
  }
2721
2896
  }
2722
2897
  const agentsDir = resolve4(dir, "agents");
2723
- if (existsSync9(agentsDir)) {
2724
- const mdFiles = readdirSync3(agentsDir).filter((f) => f.endsWith(".md"));
2898
+ if (existsSync11(agentsDir)) {
2899
+ const mdFiles = readdirSync4(agentsDir).filter((f) => f.endsWith(".md"));
2725
2900
  if (mdFiles.length > 0) {
2726
2901
  passes.push(`agents/ has ${mdFiles.length} .md file(s)`);
2727
2902
  } else {
@@ -2734,8 +2909,8 @@ var init_plugin = __esm(() => {
2734
2909
  });
2735
2910
 
2736
2911
  // src/validators/claude/marketplace.ts
2737
- import { existsSync as existsSync10, readdirSync as readdirSync4 } from "fs";
2738
- import { resolve as resolve5, join as join8 } from "path";
2912
+ import { existsSync as existsSync12, readdirSync as readdirSync5 } from "fs";
2913
+ import { resolve as resolve5, join as join10 } from "path";
2739
2914
  var claudeMarketplaceValidator;
2740
2915
  var init_marketplace = __esm(() => {
2741
2916
  claudeMarketplaceValidator = {
@@ -2745,15 +2920,15 @@ var init_marketplace = __esm(() => {
2745
2920
  description: "Validates marketplace structure: plugins/ directory with valid plugin subdirectories",
2746
2921
  detect(dir) {
2747
2922
  const pluginsDir = resolve5(dir, "plugins");
2748
- if (!existsSync10(pluginsDir))
2923
+ if (!existsSync12(pluginsDir))
2749
2924
  return false;
2750
2925
  try {
2751
- const entries = readdirSync4(pluginsDir, { withFileTypes: true });
2926
+ const entries = readdirSync5(pluginsDir, { withFileTypes: true });
2752
2927
  for (const entry of entries) {
2753
2928
  if (!entry.isDirectory())
2754
2929
  continue;
2755
- const hasSkills = existsSync10(join8(pluginsDir, entry.name, "skills"));
2756
- const hasManifest = existsSync10(join8(pluginsDir, entry.name, ".claude-plugin", "plugin.json"));
2930
+ const hasSkills = existsSync12(join10(pluginsDir, entry.name, "skills"));
2931
+ const hasManifest = existsSync12(join10(pluginsDir, entry.name, ".claude-plugin", "plugin.json"));
2757
2932
  if (hasSkills || hasManifest)
2758
2933
  return true;
2759
2934
  }
@@ -2765,32 +2940,32 @@ var init_marketplace = __esm(() => {
2765
2940
  const warnings = [];
2766
2941
  const passes = [];
2767
2942
  const pluginsDir = resolve5(dir, "plugins");
2768
- if (!existsSync10(pluginsDir)) {
2943
+ if (!existsSync12(pluginsDir)) {
2769
2944
  errors.push("Missing plugins/ directory");
2770
2945
  return { errors, warnings, passes };
2771
2946
  }
2772
2947
  passes.push("plugins/ directory exists");
2773
- const pluginEntries = readdirSync4(pluginsDir, { withFileTypes: true }).filter((e) => e.isDirectory());
2948
+ const pluginEntries = readdirSync5(pluginsDir, { withFileTypes: true }).filter((e) => e.isDirectory());
2774
2949
  if (pluginEntries.length === 0) {
2775
2950
  errors.push("plugins/ directory is empty \u2014 expected at least one plugin");
2776
2951
  return { errors, warnings, passes };
2777
2952
  }
2778
2953
  passes.push(`${pluginEntries.length} plugin(s) found`);
2779
- if (existsSync10(resolve5(dir, "README.md"))) {
2954
+ if (existsSync12(resolve5(dir, "README.md"))) {
2780
2955
  passes.push("README.md exists at marketplace root");
2781
2956
  } else {
2782
2957
  warnings.push("No README.md at marketplace root \u2014 recommended for discoverability");
2783
2958
  }
2784
- if (existsSync10(resolve5(dir, "LICENSE"))) {
2959
+ if (existsSync12(resolve5(dir, "LICENSE"))) {
2785
2960
  passes.push("LICENSE exists at marketplace root");
2786
2961
  } else {
2787
2962
  warnings.push("No LICENSE at marketplace root \u2014 recommended");
2788
2963
  }
2789
2964
  for (const plugin of pluginEntries) {
2790
- const pluginPath = join8(pluginsDir, plugin.name);
2791
- const hasSkills = existsSync10(join8(pluginPath, "skills"));
2792
- const hasManifest = existsSync10(join8(pluginPath, ".claude-plugin", "plugin.json"));
2793
- const hasReadme = existsSync10(join8(pluginPath, "README.md"));
2965
+ const pluginPath = join10(pluginsDir, plugin.name);
2966
+ const hasSkills = existsSync12(join10(pluginPath, "skills"));
2967
+ const hasManifest = existsSync12(join10(pluginPath, ".claude-plugin", "plugin.json"));
2968
+ const hasReadme = existsSync12(join10(pluginPath, "README.md"));
2794
2969
  if (hasManifest || hasSkills) {
2795
2970
  passes.push(`Plugin "${plugin.name}" has ${hasManifest ? "manifest" : "skills/"}`);
2796
2971
  } else {
@@ -2806,7 +2981,7 @@ var init_marketplace = __esm(() => {
2806
2981
  });
2807
2982
 
2808
2983
  // src/validators/claude/hooks.ts
2809
- import { existsSync as existsSync11 } from "fs";
2984
+ import { existsSync as existsSync13 } from "fs";
2810
2985
  import { resolve as resolve6 } from "path";
2811
2986
  var KNOWN_EVENTS, claudeHooksValidator;
2812
2987
  var init_hooks = __esm(() => {
@@ -2828,13 +3003,13 @@ var init_hooks = __esm(() => {
2828
3003
  name: "Claude Hooks",
2829
3004
  description: "Validates hooks/hooks.json: event names, matcher structure, hook types",
2830
3005
  detect(dir) {
2831
- return existsSync11(resolve6(dir, "hooks", "hooks.json")) || existsSync11(resolve6(dir, "hooks.json"));
3006
+ return existsSync13(resolve6(dir, "hooks", "hooks.json")) || existsSync13(resolve6(dir, "hooks.json"));
2832
3007
  },
2833
3008
  async validate(dir, _opts) {
2834
3009
  const errors = [];
2835
3010
  const warnings = [];
2836
3011
  const passes = [];
2837
- const hooksPath = existsSync11(resolve6(dir, "hooks", "hooks.json")) ? resolve6(dir, "hooks", "hooks.json") : resolve6(dir, "hooks.json");
3012
+ const hooksPath = existsSync13(resolve6(dir, "hooks", "hooks.json")) ? resolve6(dir, "hooks", "hooks.json") : resolve6(dir, "hooks.json");
2838
3013
  let config;
2839
3014
  try {
2840
3015
  const raw = await Bun.file(hooksPath).text();
@@ -2858,7 +3033,7 @@ var init_hooks = __esm(() => {
2858
3033
  });
2859
3034
 
2860
3035
  // src/validators/claude/mcp.ts
2861
- import { existsSync as existsSync12 } from "fs";
3036
+ import { existsSync as existsSync14 } from "fs";
2862
3037
  import { resolve as resolve7 } from "path";
2863
3038
  var claudeMcpValidator;
2864
3039
  var init_mcp = __esm(() => {
@@ -2868,7 +3043,7 @@ var init_mcp = __esm(() => {
2868
3043
  name: "Claude MCP Config",
2869
3044
  description: "Validates .mcp.json: server definitions, required fields, path portability",
2870
3045
  detect(dir) {
2871
- return existsSync12(resolve7(dir, ".mcp.json"));
3046
+ return existsSync14(resolve7(dir, ".mcp.json"));
2872
3047
  },
2873
3048
  async validate(dir, _opts) {
2874
3049
  const errors = [];
@@ -2900,8 +3075,8 @@ var init_mcp = __esm(() => {
2900
3075
  });
2901
3076
 
2902
3077
  // src/validators/claude/subagent.ts
2903
- import { existsSync as existsSync13, readdirSync as readdirSync5 } from "fs";
2904
- import { resolve as resolve8, join as join9 } from "path";
3078
+ import { existsSync as existsSync15, readdirSync as readdirSync6 } from "fs";
3079
+ import { resolve as resolve8, join as join11 } from "path";
2905
3080
  var claudeSubagentValidator;
2906
3081
  var init_subagent = __esm(() => {
2907
3082
  init_frontmatter();
@@ -2912,10 +3087,10 @@ var init_subagent = __esm(() => {
2912
3087
  description: "Validates agents/ directory: .md files with frontmatter and description",
2913
3088
  detect(dir) {
2914
3089
  const agentsDir = resolve8(dir, "agents");
2915
- if (!existsSync13(agentsDir))
3090
+ if (!existsSync15(agentsDir))
2916
3091
  return false;
2917
3092
  try {
2918
- return readdirSync5(agentsDir).some((f) => f.endsWith(".md"));
3093
+ return readdirSync6(agentsDir).some((f) => f.endsWith(".md"));
2919
3094
  } catch {
2920
3095
  return false;
2921
3096
  }
@@ -2925,14 +3100,14 @@ var init_subagent = __esm(() => {
2925
3100
  const warnings = [];
2926
3101
  const passes = [];
2927
3102
  const agentsDir = resolve8(dir, "agents");
2928
- const mdFiles = readdirSync5(agentsDir).filter((f) => f.endsWith(".md"));
3103
+ const mdFiles = readdirSync6(agentsDir).filter((f) => f.endsWith(".md"));
2929
3104
  if (mdFiles.length === 0) {
2930
3105
  errors.push("agents/ directory has no .md files");
2931
3106
  return { errors, warnings, passes };
2932
3107
  }
2933
3108
  passes.push(`${mdFiles.length} agent definition(s) found`);
2934
3109
  for (const file of mdFiles) {
2935
- const filePath = join9(agentsDir, file);
3110
+ const filePath = join11(agentsDir, file);
2936
3111
  const raw = await Bun.file(filePath).text();
2937
3112
  try {
2938
3113
  const parsed = parseFrontmatter(raw);
@@ -2956,8 +3131,8 @@ var init_subagent = __esm(() => {
2956
3131
  });
2957
3132
 
2958
3133
  // src/validators/claude/command.ts
2959
- import { existsSync as existsSync14, readdirSync as readdirSync6 } from "fs";
2960
- import { resolve as resolve9, join as join10 } from "path";
3134
+ import { existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
3135
+ import { resolve as resolve9, join as join12 } from "path";
2961
3136
  var claudeCommandValidator;
2962
3137
  var init_command = __esm(() => {
2963
3138
  init_frontmatter();
@@ -2968,10 +3143,10 @@ var init_command = __esm(() => {
2968
3143
  description: "Validates commands/ (or legacy .claude/commands/) .md files: frontmatter (including rich skill fields), description, body",
2969
3144
  detect(dir) {
2970
3145
  const commandsDir = resolve9(dir, "commands");
2971
- if (!existsSync14(commandsDir))
3146
+ if (!existsSync16(commandsDir))
2972
3147
  return false;
2973
3148
  try {
2974
- return readdirSync6(commandsDir).some((f) => f.endsWith(".md"));
3149
+ return readdirSync7(commandsDir).some((f) => f.endsWith(".md"));
2975
3150
  } catch {
2976
3151
  return false;
2977
3152
  }
@@ -2981,14 +3156,14 @@ var init_command = __esm(() => {
2981
3156
  const warnings = [];
2982
3157
  const passes = [];
2983
3158
  const commandsDir = resolve9(dir, "commands");
2984
- const mdFiles = readdirSync6(commandsDir).filter((f) => f.endsWith(".md"));
3159
+ const mdFiles = readdirSync7(commandsDir).filter((f) => f.endsWith(".md"));
2985
3160
  if (mdFiles.length === 0) {
2986
3161
  errors.push("commands/ directory has no .md files");
2987
3162
  return { errors, warnings, passes };
2988
3163
  }
2989
3164
  passes.push(`${mdFiles.length} command definition(s) found`);
2990
3165
  for (const file of mdFiles) {
2991
- const filePath = join10(commandsDir, file);
3166
+ const filePath = join12(commandsDir, file);
2992
3167
  const raw = await Bun.file(filePath).text();
2993
3168
  try {
2994
3169
  const parsed = parseFrontmatter(raw);
@@ -3017,7 +3192,7 @@ var init_command = __esm(() => {
3017
3192
  });
3018
3193
 
3019
3194
  // src/validators/claude/memory.ts
3020
- import { existsSync as existsSync15 } from "fs";
3195
+ import { existsSync as existsSync17 } from "fs";
3021
3196
  import { resolve as resolve10 } from "path";
3022
3197
  var claudeMemoryValidator;
3023
3198
  var init_memory = __esm(() => {
@@ -3027,7 +3202,7 @@ var init_memory = __esm(() => {
3027
3202
  name: "Claude CLAUDE.md",
3028
3203
  description: "Validates CLAUDE.md: non-empty, length recommendations, @path imports",
3029
3204
  detect(dir) {
3030
- return existsSync15(resolve10(dir, "CLAUDE.md"));
3205
+ return existsSync17(resolve10(dir, "CLAUDE.md"));
3031
3206
  },
3032
3207
  async validate(dir, _opts) {
3033
3208
  const errors = [];
@@ -3052,7 +3227,7 @@ var init_memory = __esm(() => {
3052
3227
  while ((match = importRegex.exec(raw)) !== null) {
3053
3228
  const importPath = match[1];
3054
3229
  const resolvedImport = resolve10(dir, importPath);
3055
- if (existsSync15(resolvedImport)) {
3230
+ if (existsSync17(resolvedImport)) {
3056
3231
  passes.push(`@import "${importPath}" exists`);
3057
3232
  } else {
3058
3233
  warnings.push(`@import "${importPath}" \u2014 file not found at ${resolvedImport}`);
@@ -3112,7 +3287,7 @@ var init_validators = __esm(() => {
3112
3287
  // src/core/remote.ts
3113
3288
  import { spawnSync as spawnSync4 } from "child_process";
3114
3289
  import { mkdtempSync, rmSync } from "fs";
3115
- import { join as join11 } from "path";
3290
+ import { join as join13 } from "path";
3116
3291
  import { tmpdir } from "os";
3117
3292
  function parseRemoteUrl(input) {
3118
3293
  if (input.startsWith(".") || input.startsWith("/") || input.startsWith("~")) {
@@ -3149,7 +3324,7 @@ function isGhAvailable() {
3149
3324
  return ghAvailable;
3150
3325
  }
3151
3326
  async function cloneToTemp(parsed) {
3152
- const tmpDir = mkdtempSync(join11(tmpdir(), "dora-"));
3327
+ const tmpDir = mkdtempSync(join13(tmpdir(), "dora-"));
3153
3328
  const cleanup = () => {
3154
3329
  try {
3155
3330
  rmSync(tmpDir, { recursive: true, force: true });
@@ -3197,15 +3372,15 @@ var exports_validate_top = {};
3197
3372
  __export(exports_validate_top, {
3198
3373
  default: () => validate_top_default
3199
3374
  });
3200
- import { existsSync as existsSync17 } from "fs";
3375
+ import { existsSync as existsSync19 } from "fs";
3201
3376
  import { resolve as resolve11 } from "path";
3202
- var import_picocolors10, validate_top_default;
3377
+ var import_picocolors11, validate_top_default;
3203
3378
  var init_validate_top = __esm(() => {
3204
3379
  init_dist();
3205
3380
  init_out();
3206
3381
  init_validators();
3207
3382
  init_remote();
3208
- import_picocolors10 = __toESM(require_picocolors(), 1);
3383
+ import_picocolors11 = __toESM(require_picocolors(), 1);
3209
3384
  validate_top_default = defineCommand({
3210
3385
  meta: {
3211
3386
  name: "validate",
@@ -3245,7 +3420,7 @@ var init_validate_top = __esm(() => {
3245
3420
  let cleanup;
3246
3421
  if (remote) {
3247
3422
  ui.info(`
3248
- Cloning ${import_picocolors10.default.dim(args.path)}...`);
3423
+ Cloning ${import_picocolors11.default.dim(args.path)}...`);
3249
3424
  try {
3250
3425
  const result = await cloneToTemp(remote);
3251
3426
  fullPath = remote.subpath ? resolve11(result.dir, remote.subpath) : result.dir;
@@ -3255,14 +3430,14 @@ var init_validate_top = __esm(() => {
3255
3430
  ui.fail(msg);
3256
3431
  process.exit(1);
3257
3432
  }
3258
- if (!existsSync17(fullPath)) {
3433
+ if (!existsSync19(fullPath)) {
3259
3434
  cleanup();
3260
3435
  ui.fail(`Subdirectory not found in repo: ${remote.subpath}`);
3261
3436
  process.exit(1);
3262
3437
  }
3263
3438
  } else {
3264
3439
  fullPath = resolve11(args.path);
3265
- if (!existsSync17(fullPath)) {
3440
+ if (!existsSync19(fullPath)) {
3266
3441
  ui.fail(`Path not found: ${args.path}
3267
3442
 
3268
3443
  Check that the path is correct and the directory exists.`);
@@ -3293,13 +3468,13 @@ Check that the path is correct and the directory exists.`);
3293
3468
  ` + `Available providers:
3294
3469
  ` + providers.map((p) => {
3295
3470
  const pvs = validators.filter((v) => v.provider === p);
3296
- return ` ${import_picocolors10.default.bold(p)}
3297
- ` + pvs.map((v) => ` \u2022 ${import_picocolors10.default.dim(v.id)} \u2014 ${v.description}`).join(`
3471
+ return ` ${import_picocolors11.default.bold(p)}
3472
+ ` + pvs.map((v) => ` \u2022 ${import_picocolors11.default.dim(v.id)} \u2014 ${v.description}`).join(`
3298
3473
  `);
3299
3474
  }).join(`
3300
3475
  `) + `
3301
3476
 
3302
- Use ${import_picocolors10.default.dim("--for <provider>")} or ${import_picocolors10.default.dim("--for <provider:type>")} to target explicitly.`);
3477
+ Use ${import_picocolors11.default.dim("--for <provider>")} or ${import_picocolors11.default.dim("--for <provider:type>")} to target explicitly.`);
3303
3478
  process.exit(1);
3304
3479
  }
3305
3480
  const allResults = [];
@@ -3320,7 +3495,7 @@ Use ${import_picocolors10.default.dim("--for <provider>")} or ${import_picocolor
3320
3495
  } else {
3321
3496
  for (const { id, name, result } of allResults) {
3322
3497
  ui.write(`
3323
- ${import_picocolors10.default.bold("dora validate")} \u2014 ${import_picocolors10.default.white(name)} ${import_picocolors10.default.dim(`(${id})`)}
3498
+ ${import_picocolors11.default.bold("dora validate")} \u2014 ${import_picocolors11.default.white(name)} ${import_picocolors11.default.dim(`(${id})`)}
3324
3499
  `);
3325
3500
  ui.info(` Path: ${args.path}
3326
3501
  `);
@@ -3335,7 +3510,7 @@ Use ${import_picocolors10.default.dim("--for <provider>")} or ${import_picocolor
3335
3510
  }
3336
3511
  if (result.errors.length === 0 && result.warnings.length === 0) {
3337
3512
  ui.write(`
3338
- ${import_picocolors10.default.green("\u2713")} ${import_picocolors10.default.white("All checks passed.")}
3513
+ ${import_picocolors11.default.green("\u2713")} ${import_picocolors11.default.white("All checks passed.")}
3339
3514
  `);
3340
3515
  } else {
3341
3516
  ui.info(`
@@ -3357,16 +3532,16 @@ var exports_init2 = {};
3357
3532
  __export(exports_init2, {
3358
3533
  default: () => init_default2
3359
3534
  });
3360
- import { basename as basename2, join as join12 } from "path";
3535
+ import { basename as basename2, join as join14 } from "path";
3361
3536
  var {spawnSync: spawnSync5 } = globalThis.Bun;
3362
- var import_picocolors11, init_default2;
3537
+ var import_picocolors12, init_default2;
3363
3538
  var init_init2 = __esm(() => {
3364
3539
  init_dist();
3365
3540
  init_out();
3366
3541
  init_journal_config();
3367
3542
  init_journal_remote();
3368
3543
  init_prompt();
3369
- import_picocolors11 = __toESM(require_picocolors(), 1);
3544
+ import_picocolors12 = __toESM(require_picocolors(), 1);
3370
3545
  init_default2 = defineCommand({
3371
3546
  meta: {
3372
3547
  name: "init",
@@ -3393,17 +3568,17 @@ var init_init2 = __esm(() => {
3393
3568
  ui.heading("dora init \u2014 Set up doraval, your journal, and the coding agent dora should use on the fly");
3394
3569
  const ghCheck = ensureGhCli();
3395
3570
  if (!ghCheck.ok) {
3396
- ui.write(` ${import_picocolors11.default.red("\u2717")} ${import_picocolors11.default.white("The GitHub CLI (")}${import_picocolors11.default.bold("gh")}${import_picocolors11.default.white(") is not installed.")}
3571
+ ui.write(` ${import_picocolors12.default.red("\u2717")} ${import_picocolors12.default.white("The GitHub CLI (")}${import_picocolors12.default.bold("gh")}${import_picocolors12.default.white(") is not installed.")}
3397
3572
  `);
3398
- ui.info(` doraval uses ${import_picocolors11.default.bold("gh")} to fetch and sync journal files with GitHub.
3573
+ ui.info(` doraval uses ${import_picocolors12.default.bold("gh")} to fetch and sync journal files with GitHub.
3399
3574
  `);
3400
3575
  ui.info(` Install it:
3401
3576
  `);
3402
- ui.info(` macOS: ${import_picocolors11.default.dim("brew install gh")}`);
3403
- ui.info(` Linux: ${import_picocolors11.default.dim("https://github.com/cli/cli/blob/trunk/docs/install_linux.md")}`);
3404
- ui.info(` Windows: ${import_picocolors11.default.dim("winget install --id GitHub.cli")}
3577
+ ui.info(` macOS: ${import_picocolors12.default.dim("brew install gh")}`);
3578
+ ui.info(` Linux: ${import_picocolors12.default.dim("https://github.com/cli/cli/blob/trunk/docs/install_linux.md")}`);
3579
+ ui.info(` Windows: ${import_picocolors12.default.dim("winget install --id GitHub.cli")}
3405
3580
  `);
3406
- ui.info(` Then authenticate: ${import_picocolors11.default.dim("gh auth login")}
3581
+ ui.info(` Then authenticate: ${import_picocolors12.default.dim("gh auth login")}
3407
3582
  `);
3408
3583
  process.exit(1);
3409
3584
  }
@@ -3416,28 +3591,28 @@ var init_init2 = __esm(() => {
3416
3591
  if (gitOwner) {
3417
3592
  defaultRepo = `${gitOwner}/${gitOwner}.md`;
3418
3593
  if (ghLogin && ghLogin !== gitOwner) {
3419
- sourceNote = ` ${import_picocolors11.default.dim("(from git remote; your active gh account is " + ghLogin + ")")}
3594
+ sourceNote = ` ${import_picocolors12.default.dim("(from git remote; your active gh account is " + ghLogin + ")")}
3420
3595
  `;
3421
3596
  } else {
3422
- sourceNote = ` ${import_picocolors11.default.dim("(from git remote)")}
3597
+ sourceNote = ` ${import_picocolors12.default.dim("(from git remote)")}
3423
3598
  `;
3424
3599
  }
3425
3600
  } else if (ghLogin) {
3426
3601
  defaultRepo = `${ghLogin}/${ghLogin}.md`;
3427
- sourceNote = ` ${import_picocolors11.default.dim("(from your active gh account)")}
3602
+ sourceNote = ` ${import_picocolors12.default.dim("(from your active gh account)")}
3428
3603
  `;
3429
3604
  } else {
3430
- ui.warn(`Not logged in to GitHub. Run ${import_picocolors11.default.dim("gh auth login")} first.
3605
+ ui.warn(`Not logged in to GitHub. Run ${import_picocolors12.default.dim("gh auth login")} first.
3431
3606
  `);
3432
3607
  process.exit(1);
3433
3608
  }
3434
3609
  const existingConfig = await readConfig();
3435
3610
  if (existingConfig?.journal.repo) {
3436
3611
  defaultRepo = existingConfig.journal.repo;
3437
- sourceNote = ` ${import_picocolors11.default.dim("(from your previous journal setup)")}
3612
+ sourceNote = ` ${import_picocolors12.default.dim("(from your previous journal setup)")}
3438
3613
  `;
3439
3614
  }
3440
- ui.info(` Journal repo ${import_picocolors11.default.dim("(owner/name)")}`);
3615
+ ui.info(` Journal repo ${import_picocolors12.default.dim("(owner/name)")}`);
3441
3616
  if (sourceNote)
3442
3617
  ui.write(sourceNote);
3443
3618
  repo = prompt(" >", defaultRepo);
@@ -3449,11 +3624,11 @@ var init_init2 = __esm(() => {
3449
3624
  }
3450
3625
  project = sanitizeProjectName(project);
3451
3626
  if (!repoExists(repo)) {
3452
- ui.write(` ${import_picocolors11.default.red("\u2717")} ${import_picocolors11.default.white("Repository")} ${import_picocolors11.default.bold(repo)} ${import_picocolors11.default.white("not found on GitHub.")}
3627
+ ui.write(` ${import_picocolors12.default.red("\u2717")} ${import_picocolors12.default.white("Repository")} ${import_picocolors12.default.bold(repo)} ${import_picocolors12.default.white("not found on GitHub.")}
3453
3628
  `);
3454
3629
  ui.info(` Create it first:
3455
3630
  `);
3456
- ui.info(` ${import_picocolors11.default.dim(`gh repo create ${repo} --private --description "Personal journal for agent decisions"`)}
3631
+ ui.info(` ${import_picocolors12.default.dim(`gh repo create ${repo} --private --description "Personal journal for agent decisions"`)}
3457
3632
  `);
3458
3633
  process.exit(1);
3459
3634
  }
@@ -3461,16 +3636,16 @@ var init_init2 = __esm(() => {
3461
3636
  const alreadyRegistered = existing?.journal.projects[project];
3462
3637
  const isRefresh = alreadyRegistered && args.refresh;
3463
3638
  if (alreadyRegistered && !isRefresh) {
3464
- ui.write(` ${import_picocolors11.default.yellow("\u26A0")} ${import_picocolors11.default.white("Project")} ${import_picocolors11.default.bold(project)} ${import_picocolors11.default.white("is already registered.")}
3639
+ ui.write(` ${import_picocolors12.default.yellow("\u26A0")} ${import_picocolors12.default.white("Project")} ${import_picocolors12.default.bold(project)} ${import_picocolors12.default.white("is already registered.")}
3465
3640
  `);
3466
3641
  ui.info(` Repo: ${existing.journal.repo}
3467
3642
  `);
3468
- ui.info(` To refresh journal files, use ${import_picocolors11.default.dim("dora journal update")} (or ${import_picocolors11.default.dim("dora init --refresh")}).
3643
+ ui.info(` To refresh journal files, use ${import_picocolors12.default.dim("dora journal update")} (or ${import_picocolors12.default.dim("dora init --refresh")}).
3469
3644
  `);
3470
3645
  }
3471
3646
  const journalsDir = getJournalsDir();
3472
3647
  const remotePath = `projects/${project}.md`;
3473
- const localPath = join12(journalsDir, `${project}.md`);
3648
+ const localPath = join14(journalsDir, `${project}.md`);
3474
3649
  const effectiveRepo = isRefresh && !args.repo ? existing.journal.repo : repo;
3475
3650
  const config = existing ?? {
3476
3651
  journal: { repo: effectiveRepo, projects: {} }
@@ -3481,9 +3656,9 @@ var init_init2 = __esm(() => {
3481
3656
  local_path: localPath
3482
3657
  };
3483
3658
  ensureDoravalDirs();
3484
- ui.write(` ${import_picocolors11.default.dim(import_picocolors11.default.gray("Fetching journal files from"))} ${import_picocolors11.default.gray(effectiveRepo)}${import_picocolors11.default.dim(import_picocolors11.default.gray("..."))}
3659
+ ui.write(` ${import_picocolors12.default.dim(import_picocolors12.default.gray("Fetching journal files from"))} ${import_picocolors12.default.gray(effectiveRepo)}${import_picocolors12.default.dim(import_picocolors12.default.gray("..."))}
3485
3660
  `);
3486
- const globalDest = join12(journalsDir, "global.md");
3661
+ const globalDest = join14(journalsDir, "global.md");
3487
3662
  const refreshGlobalRes = await refreshLocalJournalFile(effectiveRepo, "global.md", globalDest);
3488
3663
  let wroteGlobal;
3489
3664
  if (!refreshGlobalRes.ok) {
@@ -3500,7 +3675,7 @@ var init_init2 = __esm(() => {
3500
3675
  if (wroteGlobal) {
3501
3676
  ui.success("global.md");
3502
3677
  } else {
3503
- ui.write(` ${import_picocolors11.default.dim("\xB7")} global.md ${import_picocolors11.default.dim("(not found \u2014 will be created on first sync)")}`);
3678
+ ui.write(` ${import_picocolors12.default.dim("\xB7")} global.md ${import_picocolors12.default.dim("(not found \u2014 will be created on first sync)")}`);
3504
3679
  await Bun.write(globalDest, `# Global Journal
3505
3680
 
3506
3681
  Cross-project principles.
@@ -3522,7 +3697,7 @@ Cross-project principles.
3522
3697
  if (wroteProject) {
3523
3698
  ui.success(remotePath);
3524
3699
  } else {
3525
- ui.write(` ${import_picocolors11.default.dim("\xB7")} ${remotePath} ${import_picocolors11.default.dim("(not found \u2014 will be created on first sync)")}`);
3700
+ ui.write(` ${import_picocolors12.default.dim("\xB7")} ${remotePath} ${import_picocolors12.default.dim("(not found \u2014 will be created on first sync)")}`);
3526
3701
  await Bun.write(localPath, `# ${project} Journal
3527
3702
 
3528
3703
  Project-specific decisions.
@@ -3530,13 +3705,13 @@ Project-specific decisions.
3530
3705
  }
3531
3706
  await writeConfig(config);
3532
3707
  ui.write(`
3533
- ${import_picocolors11.default.green("\u2713")} ${import_picocolors11.default.white("Journal ready for project")} ${import_picocolors11.default.bold(import_picocolors11.default.white(project))}.
3708
+ ${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.white("Journal ready for project")} ${import_picocolors12.default.bold(import_picocolors12.default.white(project))}.
3534
3709
  `);
3535
3710
  const existingAgent = (await readConfig())?.agent;
3536
3711
  if (existingAgent?.command) {
3537
- ui.write(` ${import_picocolors11.default.bold(import_picocolors11.default.white("Coding agent (already configured)"))}
3712
+ ui.write(` ${import_picocolors12.default.bold(import_picocolors12.default.white("Coding agent (already configured)"))}
3538
3713
  `);
3539
- ui.write(` Current: ${import_picocolors11.default.dim(import_picocolors11.default.gray(existingAgent.command))} template: ${import_picocolors11.default.dim(import_picocolors11.default.gray(existingAgent.prompt_template || "(default)"))}
3714
+ ui.write(` Current: ${import_picocolors12.default.dim(import_picocolors12.default.gray(existingAgent.command))} template: ${import_picocolors12.default.dim(import_picocolors12.default.gray(existingAgent.prompt_template || "(default)"))}
3540
3715
  `);
3541
3716
  const change = prompt(" Reconfigure / change the coding agent for on-the-fly enrichment? (y/N)", "n");
3542
3717
  if (!/^y/i.test(String(change))) {
@@ -3546,16 +3721,16 @@ Project-specific decisions.
3546
3721
  if (existingAgent)
3547
3722
  cfg.agent = existingAgent;
3548
3723
  await writeConfig(cfg);
3549
- ui.write(` ${import_picocolors11.default.green("\u2713")} ${import_picocolors11.default.white("Try:")} ${import_picocolors11.default.dim(import_picocolors11.default.gray('dora journal add "short decision"'))}
3724
+ ui.write(` ${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.white("Try:")} ${import_picocolors12.default.dim(import_picocolors12.default.gray('dora journal add "short decision"'))}
3550
3725
  `);
3551
3726
  process.exit(0);
3552
3727
  return;
3553
3728
  }
3554
3729
  ui.blank();
3555
3730
  } else {
3556
- ui.write(` ${import_picocolors11.default.bold(import_picocolors11.default.white("Coding agent for journal add"))}
3731
+ ui.write(` ${import_picocolors12.default.bold(import_picocolors12.default.white("Coding agent for journal add"))}
3557
3732
  `);
3558
- ui.info(` When configured, ${import_picocolors11.default.dim(import_picocolors11.default.gray('dora journal add ".."'))} will use your agent to enrich entries with tags and rationale automatically.
3733
+ ui.info(` When configured, ${import_picocolors12.default.dim(import_picocolors12.default.gray('dora journal add ".."'))} will use your agent to enrich entries with tags and rationale automatically.
3559
3734
  `);
3560
3735
  }
3561
3736
  const common = [
@@ -3574,7 +3749,7 @@ Project-specific decisions.
3574
3749
  }
3575
3750
  }
3576
3751
  let agentCmd = detected || "claude";
3577
- ui.write(` Detected / default agent command: ${import_picocolors11.default.dim(import_picocolors11.default.gray(agentCmd))}`);
3752
+ ui.write(` Detected / default agent command: ${import_picocolors12.default.dim(import_picocolors12.default.gray(agentCmd))}`);
3578
3753
  agentCmd = prompt(" Agent command (the binary you run for prompts)", agentCmd);
3579
3754
  let template = detected ? common.find((c) => c.name === detected)?.template || '-p "{{prompt}}" --output-format json' : '-p "{{prompt}}" --output-format json';
3580
3755
  ui.info(` Prompt template (use {{prompt}} placeholder):`);
@@ -3586,11 +3761,11 @@ Project-specific decisions.
3586
3761
  };
3587
3762
  await writeConfig(finalConfig);
3588
3763
  ui.write(`
3589
- ${import_picocolors11.default.green("\u2713")} ${import_picocolors11.default.white("Agent configured.")}
3764
+ ${import_picocolors12.default.green("\u2713")} ${import_picocolors12.default.white("Agent configured.")}
3590
3765
  `);
3591
- ui.info(` Re-run ${import_picocolors11.default.dim(import_picocolors11.default.gray("dora init"))} anytime to change it.
3766
+ ui.info(` Re-run ${import_picocolors12.default.dim(import_picocolors12.default.gray("dora init"))} anytime to change it.
3592
3767
  `);
3593
- ui.info(` Next: ${import_picocolors11.default.dim(import_picocolors11.default.gray('dora journal add ".."'))}, ${import_picocolors11.default.dim(import_picocolors11.default.gray("dora journal list"))}, or ${import_picocolors11.default.dim(import_picocolors11.default.gray("dora journal update"))}.
3768
+ ui.info(` Next: ${import_picocolors12.default.dim(import_picocolors12.default.gray('dora journal add ".."'))}, ${import_picocolors12.default.dim(import_picocolors12.default.gray("dora journal list"))}, or ${import_picocolors12.default.dim(import_picocolors12.default.gray("dora journal update"))}.
3594
3769
  `);
3595
3770
  process.exit(0);
3596
3771
  }
@@ -3602,7 +3777,7 @@ init_dist();
3602
3777
  // package.json
3603
3778
  var package_default = {
3604
3779
  name: "@hacksmith/doraval",
3605
- version: "0.2.20",
3780
+ version: "0.2.21",
3606
3781
  author: "Saif",
3607
3782
  repository: {
3608
3783
  type: "git",
@@ -3663,7 +3838,7 @@ var package_default = {
3663
3838
  };
3664
3839
 
3665
3840
  // src/cli/index.ts
3666
- var import_picocolors12 = __toESM(require_picocolors(), 1);
3841
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
3667
3842
  var skill = defineCommand({
3668
3843
  meta: {
3669
3844
  name: "skill",
@@ -3694,6 +3869,18 @@ var journal = defineCommand({
3694
3869
  showUsage(journal);
3695
3870
  }
3696
3871
  });
3872
+ var claude = defineCommand({
3873
+ meta: {
3874
+ name: "claude",
3875
+ description: "Claude Code-specific commands (packaging, scaffolding, distribution)"
3876
+ },
3877
+ subCommands: {
3878
+ new: () => Promise.resolve().then(() => (init_new(), exports_new)).then((m) => m.default)
3879
+ },
3880
+ run() {
3881
+ showUsage(claude);
3882
+ }
3883
+ });
3697
3884
  var doraemonArt = `
3698
3885
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28E0\u28E4\u28F4\u28F6\u28F6\u28F6\u28F6\u28F6\u2836\u28F6\u28E4\u28E4\u28C0\u2800\u2800\u2800\u2800\u2800\u2800
3699
3886
  \u2800\u2800\u2800\u2800\u2800\u2800\u2800\u2880\u28E4\u28FE\u28FF\u28FF\u28FF\u2801\u2800\u2880\u2808\u28BF\u2880\u28C0\u2800\u2839\u28FF\u28FF\u28FF\u28E6\u28C4\u2800\u2800\u2800
@@ -3716,11 +3903,12 @@ var main = defineCommand({
3716
3903
  validate: () => Promise.resolve().then(() => (init_validate_top(), exports_validate_top)).then((m) => m.default),
3717
3904
  init: () => Promise.resolve().then(() => (init_init2(), exports_init2)).then((m) => m.default),
3718
3905
  skill: () => Promise.resolve(skill),
3719
- journal: () => Promise.resolve(journal)
3906
+ journal: () => Promise.resolve(journal),
3907
+ claude: () => Promise.resolve(claude)
3720
3908
  },
3721
3909
  run() {
3722
3910
  console.log(`
3723
- ` + import_picocolors12.default.blue(doraemonArt) + `
3911
+ ` + import_picocolors13.default.blue(doraemonArt) + `
3724
3912
  `);
3725
3913
  showUsage(main);
3726
3914
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hacksmith/doraval",
3
- "version": "0.2.20",
3
+ "version": "0.2.21",
4
4
  "author": "Saif",
5
5
  "repository": {
6
6
  "type": "git",