claudekit-cli 3.41.4-dev.16 → 3.41.4-dev.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -10624,352 +10624,6 @@ var init_direct_copy = __esm(() => {
10624
10624
  };
10625
10625
  });
10626
10626
 
10627
- // src/commands/portable/converters/fm-strip.ts
10628
- function convertFmStrip(item, provider) {
10629
- const warnings = [];
10630
- const heading = item.frontmatter.name || item.name;
10631
- const isMergeProvider = ["goose", "gemini-cli", "amp"].includes(provider);
10632
- let content;
10633
- if (isMergeProvider) {
10634
- content = `## Agent: ${heading}
10635
-
10636
- ${item.body}
10637
- `;
10638
- } else {
10639
- content = `# ${heading}
10640
-
10641
- ${item.body}
10642
- `;
10643
- }
10644
- if (provider === "windsurf" && content.length > 12000) {
10645
- const originalLen = content.length;
10646
- const truncated = content.slice(0, 11950);
10647
- content = `${truncated}
10648
-
10649
- [truncated — original ${originalLen} chars exceeded 12K limit]
10650
- `;
10651
- warnings.push(`Content truncated from ${originalLen} to 12K chars for Windsurf`);
10652
- }
10653
- return {
10654
- content,
10655
- filename: isMergeProvider ? "AGENTS.md" : `${item.name}.md`,
10656
- warnings
10657
- };
10658
- }
10659
- function buildMergedAgentsMd(sections, providerName) {
10660
- const header = `# Agents
10661
-
10662
- > Ported from Claude Code agents via ClaudeKit CLI (ck agents)
10663
- > Target: ${providerName}
10664
-
10665
- `;
10666
- return header + sections.join(`
10667
- ---
10668
-
10669
- `);
10670
- }
10671
-
10672
- // src/commands/portable/converters/fm-to-fm.ts
10673
- function convertForCopilot(item) {
10674
- const warnings = [];
10675
- const fm = {};
10676
- fm.name = item.frontmatter.name || item.name;
10677
- if (item.description)
10678
- fm.description = item.description;
10679
- if (item.frontmatter.model)
10680
- fm.model = item.frontmatter.model;
10681
- if (item.frontmatter.tools) {
10682
- const sourceTools = item.frontmatter.tools.split(",").map((t) => t.trim());
10683
- const mappedTools = new Set;
10684
- for (const tool of sourceTools) {
10685
- const mapped = COPILOT_TOOL_MAP[tool];
10686
- if (mapped) {
10687
- mappedTools.add(mapped);
10688
- }
10689
- }
10690
- if (mappedTools.size > 0) {
10691
- fm.tools = Array.from(mappedTools);
10692
- }
10693
- }
10694
- const fmLines = ["---"];
10695
- for (const [key, value] of Object.entries(fm)) {
10696
- if (Array.isArray(value)) {
10697
- fmLines.push(`${key}:`);
10698
- for (const v2 of value) {
10699
- fmLines.push(` - ${v2}`);
10700
- }
10701
- } else {
10702
- fmLines.push(`${key}: ${JSON.stringify(value)}`);
10703
- }
10704
- }
10705
- fmLines.push("---");
10706
- const content = `${fmLines.join(`
10707
- `)}
10708
-
10709
- ${item.body}
10710
- `;
10711
- if (content.length > 30000) {
10712
- warnings.push(`Content exceeds Copilot 30K char limit (${content.length} chars)`);
10713
- }
10714
- return {
10715
- content,
10716
- filename: `${item.name}.agent.md`,
10717
- warnings
10718
- };
10719
- }
10720
- function convertForCursor(item) {
10721
- const fm = {};
10722
- if (item.description)
10723
- fm.description = item.description;
10724
- fm.alwaysApply = false;
10725
- const fmLines = ["---"];
10726
- for (const [key, value] of Object.entries(fm)) {
10727
- fmLines.push(`${key}: ${JSON.stringify(value)}`);
10728
- }
10729
- fmLines.push("---");
10730
- const content = `${fmLines.join(`
10731
- `)}
10732
-
10733
- ${item.body}
10734
- `;
10735
- return {
10736
- content,
10737
- filename: `${item.name}.mdc`,
10738
- warnings: []
10739
- };
10740
- }
10741
- function replaceClaudePathsForOpenCode(content) {
10742
- return content.replace(/\.claude\//g, ".opencode/");
10743
- }
10744
- function convertOpenCodeAgent(item) {
10745
- const warnings = [];
10746
- const agentName = item.frontmatter.name || item.name;
10747
- const mode = agentName === "brainstormer" ? "primary" : "subagent";
10748
- let toolsObj = null;
10749
- if (item.frontmatter.tools) {
10750
- const sourceTools = item.frontmatter.tools.split(",").map((t) => t.trim());
10751
- const mapped = new Set;
10752
- for (const tool of sourceTools) {
10753
- const key = OPENCODE_TOOL_MAP[tool];
10754
- if (key)
10755
- mapped.add(key);
10756
- }
10757
- if (mapped.size > 0) {
10758
- toolsObj = {};
10759
- for (const key of mapped) {
10760
- toolsObj[key] = true;
10761
- }
10762
- }
10763
- }
10764
- const fmLines = ["---"];
10765
- const desc = (item.description || `Agent: ${agentName}`).replace(/\n/g, " ").trim();
10766
- const truncatedDesc = desc.length > 200 ? `${desc.slice(0, 197)}...` : desc;
10767
- fmLines.push(`description: ${JSON.stringify(truncatedDesc)}`);
10768
- fmLines.push(`mode: ${mode}`);
10769
- if (toolsObj) {
10770
- fmLines.push("tools:");
10771
- for (const [key, val] of Object.entries(toolsObj)) {
10772
- fmLines.push(` ${key}: ${val}`);
10773
- }
10774
- }
10775
- fmLines.push("---");
10776
- const body = replaceClaudePathsForOpenCode(item.body);
10777
- const content = `${fmLines.join(`
10778
- `)}
10779
-
10780
- ${body}
10781
- `;
10782
- return {
10783
- content,
10784
- filename: `${item.name}.md`,
10785
- warnings
10786
- };
10787
- }
10788
- function convertOpenCodeCommand(item) {
10789
- const fmLines = ["---"];
10790
- const desc = (item.description || `Command: ${item.name}`).replace(/\n/g, " ").trim();
10791
- const truncatedDesc = desc.length > 200 ? `${desc.slice(0, 197)}...` : desc;
10792
- fmLines.push(`description: ${JSON.stringify(truncatedDesc)}`);
10793
- if (item.frontmatter.agent) {
10794
- fmLines.push(`agent: ${JSON.stringify(item.frontmatter.agent)}`);
10795
- }
10796
- fmLines.push("---");
10797
- const body = replaceClaudePathsForOpenCode(item.body);
10798
- const content = `${fmLines.join(`
10799
- `)}
10800
-
10801
- ${body}
10802
- `;
10803
- return {
10804
- content,
10805
- filename: `${item.name}.md`,
10806
- warnings: []
10807
- };
10808
- }
10809
- function convertFmToFm(item, provider) {
10810
- switch (provider) {
10811
- case "github-copilot":
10812
- return convertForCopilot(item);
10813
- case "cursor":
10814
- return convertForCursor(item);
10815
- case "opencode":
10816
- if (item.type === "command")
10817
- return convertOpenCodeCommand(item);
10818
- return convertOpenCodeAgent(item);
10819
- default:
10820
- return {
10821
- content: item.body,
10822
- filename: `${item.name}.md`,
10823
- warnings: [`No FM-to-FM converter for provider "${provider}", using body only`]
10824
- };
10825
- }
10826
- }
10827
- var COPILOT_TOOL_MAP, OPENCODE_TOOL_MAP;
10828
- var init_fm_to_fm = __esm(() => {
10829
- COPILOT_TOOL_MAP = {
10830
- Read: "read",
10831
- Glob: "search",
10832
- Grep: "search",
10833
- Edit: "edit",
10834
- Write: "edit",
10835
- MultiEdit: "edit",
10836
- Bash: "run_in_terminal",
10837
- WebFetch: "fetch",
10838
- WebSearch: "fetch"
10839
- };
10840
- OPENCODE_TOOL_MAP = {
10841
- Read: "read",
10842
- Glob: "glob",
10843
- Grep: "grep",
10844
- Edit: "edit",
10845
- Write: "write",
10846
- MultiEdit: "patch",
10847
- Bash: "bash",
10848
- WebFetch: "webfetch",
10849
- WebSearch: "websearch",
10850
- NotebookEdit: "edit"
10851
- };
10852
- });
10853
-
10854
- // src/commands/portable/converters/fm-to-json.ts
10855
- function mapToolsToGroups(toolsStr) {
10856
- const tools = toolsStr.split(",").map((t) => t.trim());
10857
- const groups = new Set;
10858
- for (const tool of tools) {
10859
- const group = CLINE_GROUP_MAP[tool];
10860
- if (group)
10861
- groups.add(group);
10862
- }
10863
- if (groups.size > 0)
10864
- groups.add("mcp");
10865
- return Array.from(groups);
10866
- }
10867
- function toSlug(name) {
10868
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
10869
- }
10870
- function convertFmToJson(item) {
10871
- const mode = {
10872
- slug: toSlug(item.name),
10873
- name: item.frontmatter.name || item.name,
10874
- roleDefinition: item.body,
10875
- groups: item.frontmatter.tools ? mapToolsToGroups(item.frontmatter.tools) : ["read", "edit", "command", "mcp"],
10876
- customInstructions: ""
10877
- };
10878
- return {
10879
- content: JSON.stringify(mode, null, 2),
10880
- filename: `${toSlug(item.name)}.json`,
10881
- warnings: []
10882
- };
10883
- }
10884
- function buildClineModesJson(modes) {
10885
- return JSON.stringify({ customModes: modes }, null, 2);
10886
- }
10887
- var CLINE_GROUP_MAP;
10888
- var init_fm_to_json = __esm(() => {
10889
- CLINE_GROUP_MAP = {
10890
- Read: "read",
10891
- Glob: "read",
10892
- Grep: "read",
10893
- Edit: "edit",
10894
- Write: "edit",
10895
- MultiEdit: "edit",
10896
- Bash: "command",
10897
- WebFetch: "browser",
10898
- WebSearch: "browser"
10899
- };
10900
- });
10901
-
10902
- // src/commands/portable/converters/fm-to-yaml.ts
10903
- function mapToolsToGroups2(toolsStr) {
10904
- const tools = toolsStr.split(",").map((t) => t.trim());
10905
- const groups = new Set;
10906
- for (const tool of tools) {
10907
- const group = TOOL_GROUP_MAP[tool];
10908
- if (group)
10909
- groups.add(group);
10910
- }
10911
- if (groups.size > 0)
10912
- groups.add("mcp");
10913
- return Array.from(groups);
10914
- }
10915
- function toSlug2(name) {
10916
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
10917
- }
10918
- function yamlEscape(str2) {
10919
- return str2.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
10920
- }
10921
- function convertFmToYaml(item) {
10922
- const slug = toSlug2(item.name);
10923
- const displayName = item.frontmatter.name || item.name;
10924
- const description = item.description || "";
10925
- const groups = item.frontmatter.tools ? mapToolsToGroups2(item.frontmatter.tools) : ["read", "edit", "command", "browser", "mcp"];
10926
- const lines = [];
10927
- lines.push(` - slug: "${slug}"`);
10928
- lines.push(` name: "${yamlEscape(displayName)}"`);
10929
- if (description) {
10930
- lines.push(` description: "${yamlEscape(description.slice(0, 200))}"`);
10931
- }
10932
- lines.push(" roleDefinition: |");
10933
- for (const line of item.body.split(`
10934
- `)) {
10935
- lines.push(` ${line}`);
10936
- }
10937
- lines.push(' customInstructions: ""');
10938
- lines.push(" groups:");
10939
- for (const group of groups) {
10940
- lines.push(` - ${group}`);
10941
- }
10942
- return {
10943
- content: lines.join(`
10944
- `),
10945
- filename: slug,
10946
- warnings: []
10947
- };
10948
- }
10949
- function buildYamlModesFile(convertedEntries) {
10950
- const lines = ["customModes:"];
10951
- for (const entry of convertedEntries) {
10952
- lines.push(entry);
10953
- }
10954
- return `${lines.join(`
10955
- `)}
10956
- `;
10957
- }
10958
- var TOOL_GROUP_MAP;
10959
- var init_fm_to_yaml = __esm(() => {
10960
- TOOL_GROUP_MAP = {
10961
- Read: "read",
10962
- Glob: "read",
10963
- Grep: "read",
10964
- Edit: "edit",
10965
- Write: "edit",
10966
- MultiEdit: "edit",
10967
- Bash: "command",
10968
- WebFetch: "browser",
10969
- WebSearch: "browser"
10970
- };
10971
- });
10972
-
10973
10627
  // src/commands/portable/provider-registry.ts
10974
10628
  var exports_provider_registry = {};
10975
10629
  __export(exports_provider_registry, {
@@ -11669,8 +11323,17 @@ var init_provider_registry = __esm(() => {
11669
11323
  writeStrategy: "merge-single",
11670
11324
  fileExtension: ".md"
11671
11325
  },
11672
- hooks: null,
11673
- settingsJsonPath: null,
11326
+ hooks: {
11327
+ projectPath: ".gemini/hooks",
11328
+ globalPath: join(home, ".gemini/hooks"),
11329
+ format: "direct-copy",
11330
+ writeStrategy: "per-file",
11331
+ fileExtension: ""
11332
+ },
11333
+ settingsJsonPath: {
11334
+ projectPath: ".gemini/settings.json",
11335
+ globalPath: join(home, ".gemini/settings.json")
11336
+ },
11674
11337
  detect: async () => hasAnyInstallSignal([
11675
11338
  join(cwd, ".gemini/commands"),
11676
11339
  join(cwd, "GEMINI.md"),
@@ -12132,6 +11795,363 @@ var init_md_strip = __esm(() => {
12132
11795
  init_provider_registry();
12133
11796
  });
12134
11797
 
11798
+ // src/commands/portable/converters/fm-strip.ts
11799
+ function convertFmStrip(item, provider) {
11800
+ const warnings = [];
11801
+ const heading = item.frontmatter.name || item.name;
11802
+ const isMergeProvider = ["goose", "gemini-cli", "amp"].includes(provider);
11803
+ let body = item.body;
11804
+ if (PROVIDERS_WITH_BODY_REWRITING.includes(provider)) {
11805
+ const stripped = stripClaudeRefs(body, { provider });
11806
+ body = stripped.content;
11807
+ warnings.push(...stripped.warnings);
11808
+ }
11809
+ let content;
11810
+ if (isMergeProvider) {
11811
+ content = `## Agent: ${heading}
11812
+
11813
+ ${body}
11814
+ `;
11815
+ } else {
11816
+ content = `# ${heading}
11817
+
11818
+ ${body}
11819
+ `;
11820
+ }
11821
+ if (provider === "windsurf" && content.length > 12000) {
11822
+ const originalLen = content.length;
11823
+ const truncated = content.slice(0, 11950);
11824
+ content = `${truncated}
11825
+
11826
+ [truncated — original ${originalLen} chars exceeded 12K limit]
11827
+ `;
11828
+ warnings.push(`Content truncated from ${originalLen} to 12K chars for Windsurf`);
11829
+ }
11830
+ return {
11831
+ content,
11832
+ filename: isMergeProvider ? "AGENTS.md" : `${item.name}.md`,
11833
+ warnings
11834
+ };
11835
+ }
11836
+ function buildMergedAgentsMd(sections, providerName) {
11837
+ const header = `# Agents
11838
+
11839
+ > Ported from Claude Code agents via ClaudeKit CLI (ck agents)
11840
+ > Target: ${providerName}
11841
+
11842
+ `;
11843
+ return header + sections.join(`
11844
+ ---
11845
+
11846
+ `);
11847
+ }
11848
+ var PROVIDERS_WITH_BODY_REWRITING;
11849
+ var init_fm_strip = __esm(() => {
11850
+ init_md_strip();
11851
+ PROVIDERS_WITH_BODY_REWRITING = ["gemini-cli"];
11852
+ });
11853
+
11854
+ // src/commands/portable/converters/fm-to-fm.ts
11855
+ function convertForCopilot(item) {
11856
+ const warnings = [];
11857
+ const fm = {};
11858
+ fm.name = item.frontmatter.name || item.name;
11859
+ if (item.description)
11860
+ fm.description = item.description;
11861
+ if (item.frontmatter.model)
11862
+ fm.model = item.frontmatter.model;
11863
+ if (item.frontmatter.tools) {
11864
+ const sourceTools = item.frontmatter.tools.split(",").map((t) => t.trim());
11865
+ const mappedTools = new Set;
11866
+ for (const tool of sourceTools) {
11867
+ const mapped = COPILOT_TOOL_MAP[tool];
11868
+ if (mapped) {
11869
+ mappedTools.add(mapped);
11870
+ }
11871
+ }
11872
+ if (mappedTools.size > 0) {
11873
+ fm.tools = Array.from(mappedTools);
11874
+ }
11875
+ }
11876
+ const fmLines = ["---"];
11877
+ for (const [key, value] of Object.entries(fm)) {
11878
+ if (Array.isArray(value)) {
11879
+ fmLines.push(`${key}:`);
11880
+ for (const v2 of value) {
11881
+ fmLines.push(` - ${v2}`);
11882
+ }
11883
+ } else {
11884
+ fmLines.push(`${key}: ${JSON.stringify(value)}`);
11885
+ }
11886
+ }
11887
+ fmLines.push("---");
11888
+ const content = `${fmLines.join(`
11889
+ `)}
11890
+
11891
+ ${item.body}
11892
+ `;
11893
+ if (content.length > 30000) {
11894
+ warnings.push(`Content exceeds Copilot 30K char limit (${content.length} chars)`);
11895
+ }
11896
+ return {
11897
+ content,
11898
+ filename: `${item.name}.agent.md`,
11899
+ warnings
11900
+ };
11901
+ }
11902
+ function convertForCursor(item) {
11903
+ const fm = {};
11904
+ if (item.description)
11905
+ fm.description = item.description;
11906
+ fm.alwaysApply = false;
11907
+ const fmLines = ["---"];
11908
+ for (const [key, value] of Object.entries(fm)) {
11909
+ fmLines.push(`${key}: ${JSON.stringify(value)}`);
11910
+ }
11911
+ fmLines.push("---");
11912
+ const content = `${fmLines.join(`
11913
+ `)}
11914
+
11915
+ ${item.body}
11916
+ `;
11917
+ return {
11918
+ content,
11919
+ filename: `${item.name}.mdc`,
11920
+ warnings: []
11921
+ };
11922
+ }
11923
+ function replaceClaudePathsForOpenCode(content) {
11924
+ return content.replace(/\.claude\//g, ".opencode/");
11925
+ }
11926
+ function convertOpenCodeAgent(item) {
11927
+ const warnings = [];
11928
+ const agentName = item.frontmatter.name || item.name;
11929
+ const mode = agentName === "brainstormer" ? "primary" : "subagent";
11930
+ let toolsObj = null;
11931
+ if (item.frontmatter.tools) {
11932
+ const sourceTools = item.frontmatter.tools.split(",").map((t) => t.trim());
11933
+ const mapped = new Set;
11934
+ for (const tool of sourceTools) {
11935
+ const key = OPENCODE_TOOL_MAP[tool];
11936
+ if (key)
11937
+ mapped.add(key);
11938
+ }
11939
+ if (mapped.size > 0) {
11940
+ toolsObj = {};
11941
+ for (const key of mapped) {
11942
+ toolsObj[key] = true;
11943
+ }
11944
+ }
11945
+ }
11946
+ const fmLines = ["---"];
11947
+ const desc = (item.description || `Agent: ${agentName}`).replace(/\n/g, " ").trim();
11948
+ const truncatedDesc = desc.length > 200 ? `${desc.slice(0, 197)}...` : desc;
11949
+ fmLines.push(`description: ${JSON.stringify(truncatedDesc)}`);
11950
+ fmLines.push(`mode: ${mode}`);
11951
+ if (toolsObj) {
11952
+ fmLines.push("tools:");
11953
+ for (const [key, val] of Object.entries(toolsObj)) {
11954
+ fmLines.push(` ${key}: ${val}`);
11955
+ }
11956
+ }
11957
+ fmLines.push("---");
11958
+ const body = replaceClaudePathsForOpenCode(item.body);
11959
+ const content = `${fmLines.join(`
11960
+ `)}
11961
+
11962
+ ${body}
11963
+ `;
11964
+ return {
11965
+ content,
11966
+ filename: `${item.name}.md`,
11967
+ warnings
11968
+ };
11969
+ }
11970
+ function convertOpenCodeCommand(item) {
11971
+ const fmLines = ["---"];
11972
+ const desc = (item.description || `Command: ${item.name}`).replace(/\n/g, " ").trim();
11973
+ const truncatedDesc = desc.length > 200 ? `${desc.slice(0, 197)}...` : desc;
11974
+ fmLines.push(`description: ${JSON.stringify(truncatedDesc)}`);
11975
+ if (item.frontmatter.agent) {
11976
+ fmLines.push(`agent: ${JSON.stringify(item.frontmatter.agent)}`);
11977
+ }
11978
+ fmLines.push("---");
11979
+ const body = replaceClaudePathsForOpenCode(item.body);
11980
+ const content = `${fmLines.join(`
11981
+ `)}
11982
+
11983
+ ${body}
11984
+ `;
11985
+ return {
11986
+ content,
11987
+ filename: `${item.name}.md`,
11988
+ warnings: []
11989
+ };
11990
+ }
11991
+ function convertFmToFm(item, provider) {
11992
+ switch (provider) {
11993
+ case "github-copilot":
11994
+ return convertForCopilot(item);
11995
+ case "cursor":
11996
+ return convertForCursor(item);
11997
+ case "opencode":
11998
+ if (item.type === "command")
11999
+ return convertOpenCodeCommand(item);
12000
+ return convertOpenCodeAgent(item);
12001
+ default:
12002
+ return {
12003
+ content: item.body,
12004
+ filename: `${item.name}.md`,
12005
+ warnings: [`No FM-to-FM converter for provider "${provider}", using body only`]
12006
+ };
12007
+ }
12008
+ }
12009
+ var COPILOT_TOOL_MAP, OPENCODE_TOOL_MAP;
12010
+ var init_fm_to_fm = __esm(() => {
12011
+ COPILOT_TOOL_MAP = {
12012
+ Read: "read",
12013
+ Glob: "search",
12014
+ Grep: "search",
12015
+ Edit: "edit",
12016
+ Write: "edit",
12017
+ MultiEdit: "edit",
12018
+ Bash: "run_in_terminal",
12019
+ WebFetch: "fetch",
12020
+ WebSearch: "fetch"
12021
+ };
12022
+ OPENCODE_TOOL_MAP = {
12023
+ Read: "read",
12024
+ Glob: "glob",
12025
+ Grep: "grep",
12026
+ Edit: "edit",
12027
+ Write: "write",
12028
+ MultiEdit: "patch",
12029
+ Bash: "bash",
12030
+ WebFetch: "webfetch",
12031
+ WebSearch: "websearch",
12032
+ NotebookEdit: "edit"
12033
+ };
12034
+ });
12035
+
12036
+ // src/commands/portable/converters/fm-to-json.ts
12037
+ function mapToolsToGroups(toolsStr) {
12038
+ const tools = toolsStr.split(",").map((t) => t.trim());
12039
+ const groups = new Set;
12040
+ for (const tool of tools) {
12041
+ const group = CLINE_GROUP_MAP[tool];
12042
+ if (group)
12043
+ groups.add(group);
12044
+ }
12045
+ if (groups.size > 0)
12046
+ groups.add("mcp");
12047
+ return Array.from(groups);
12048
+ }
12049
+ function toSlug(name) {
12050
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
12051
+ }
12052
+ function convertFmToJson(item) {
12053
+ const mode = {
12054
+ slug: toSlug(item.name),
12055
+ name: item.frontmatter.name || item.name,
12056
+ roleDefinition: item.body,
12057
+ groups: item.frontmatter.tools ? mapToolsToGroups(item.frontmatter.tools) : ["read", "edit", "command", "mcp"],
12058
+ customInstructions: ""
12059
+ };
12060
+ return {
12061
+ content: JSON.stringify(mode, null, 2),
12062
+ filename: `${toSlug(item.name)}.json`,
12063
+ warnings: []
12064
+ };
12065
+ }
12066
+ function buildClineModesJson(modes) {
12067
+ return JSON.stringify({ customModes: modes }, null, 2);
12068
+ }
12069
+ var CLINE_GROUP_MAP;
12070
+ var init_fm_to_json = __esm(() => {
12071
+ CLINE_GROUP_MAP = {
12072
+ Read: "read",
12073
+ Glob: "read",
12074
+ Grep: "read",
12075
+ Edit: "edit",
12076
+ Write: "edit",
12077
+ MultiEdit: "edit",
12078
+ Bash: "command",
12079
+ WebFetch: "browser",
12080
+ WebSearch: "browser"
12081
+ };
12082
+ });
12083
+
12084
+ // src/commands/portable/converters/fm-to-yaml.ts
12085
+ function mapToolsToGroups2(toolsStr) {
12086
+ const tools = toolsStr.split(",").map((t) => t.trim());
12087
+ const groups = new Set;
12088
+ for (const tool of tools) {
12089
+ const group = TOOL_GROUP_MAP[tool];
12090
+ if (group)
12091
+ groups.add(group);
12092
+ }
12093
+ if (groups.size > 0)
12094
+ groups.add("mcp");
12095
+ return Array.from(groups);
12096
+ }
12097
+ function toSlug2(name) {
12098
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
12099
+ }
12100
+ function yamlEscape(str2) {
12101
+ return str2.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
12102
+ }
12103
+ function convertFmToYaml(item) {
12104
+ const slug = toSlug2(item.name);
12105
+ const displayName = item.frontmatter.name || item.name;
12106
+ const description = item.description || "";
12107
+ const groups = item.frontmatter.tools ? mapToolsToGroups2(item.frontmatter.tools) : ["read", "edit", "command", "browser", "mcp"];
12108
+ const lines = [];
12109
+ lines.push(` - slug: "${slug}"`);
12110
+ lines.push(` name: "${yamlEscape(displayName)}"`);
12111
+ if (description) {
12112
+ lines.push(` description: "${yamlEscape(description.slice(0, 200))}"`);
12113
+ }
12114
+ lines.push(" roleDefinition: |");
12115
+ for (const line of item.body.split(`
12116
+ `)) {
12117
+ lines.push(` ${line}`);
12118
+ }
12119
+ lines.push(' customInstructions: ""');
12120
+ lines.push(" groups:");
12121
+ for (const group of groups) {
12122
+ lines.push(` - ${group}`);
12123
+ }
12124
+ return {
12125
+ content: lines.join(`
12126
+ `),
12127
+ filename: slug,
12128
+ warnings: []
12129
+ };
12130
+ }
12131
+ function buildYamlModesFile(convertedEntries) {
12132
+ const lines = ["customModes:"];
12133
+ for (const entry of convertedEntries) {
12134
+ lines.push(entry);
12135
+ }
12136
+ return `${lines.join(`
12137
+ `)}
12138
+ `;
12139
+ }
12140
+ var TOOL_GROUP_MAP;
12141
+ var init_fm_to_yaml = __esm(() => {
12142
+ TOOL_GROUP_MAP = {
12143
+ Read: "read",
12144
+ Glob: "read",
12145
+ Grep: "read",
12146
+ Edit: "edit",
12147
+ Write: "edit",
12148
+ MultiEdit: "edit",
12149
+ Bash: "command",
12150
+ WebFetch: "browser",
12151
+ WebSearch: "browser"
12152
+ };
12153
+ });
12154
+
12135
12155
  // src/commands/portable/converters/md-to-kiro-steering.ts
12136
12156
  function detectLanguageGlob(itemName) {
12137
12157
  const normalized = itemName.toLowerCase();
@@ -12341,6 +12361,7 @@ function convertItem(item, format, provider) {
12341
12361
  }
12342
12362
  var init_converters = __esm(() => {
12343
12363
  init_direct_copy();
12364
+ init_fm_strip();
12344
12365
  init_fm_to_codex_toml();
12345
12366
  init_fm_to_fm();
12346
12367
  init_fm_to_json();
@@ -14425,6 +14446,7 @@ var init_portable_installer = __esm(() => {
14425
14446
  init_zod();
14426
14447
  init_checksum_utils();
14427
14448
  init_codex_toml_installer();
14449
+ init_fm_strip();
14428
14450
  init_fm_to_json();
14429
14451
  init_fm_to_yaml();
14430
14452
  init_converters();
@@ -51075,6 +51097,52 @@ var init_config_discovery = __esm(() => {
51075
51097
  SHELL_HOOK_EXTENSIONS = new Set([".sh", ".ps1", ".bat", ".cmd"]);
51076
51098
  });
51077
51099
 
51100
+ // src/commands/portable/converters/gemini-hook-event-map.ts
51101
+ function mapEventName(claudeEvent) {
51102
+ return GEMINI_EVENT_MAP[claudeEvent] ?? claudeEvent;
51103
+ }
51104
+ function rewriteMatcherToolNames(matcher) {
51105
+ if (!matcher)
51106
+ return matcher;
51107
+ const parts = matcher.split("|").map((p) => p.trim());
51108
+ const mapped = new Set;
51109
+ for (const part of parts) {
51110
+ const directMap = GEMINI_TOOL_NAME_MAP[part];
51111
+ if (directMap) {
51112
+ mapped.add(directMap);
51113
+ } else {
51114
+ mapped.add(part);
51115
+ }
51116
+ }
51117
+ return Array.from(mapped).join("|");
51118
+ }
51119
+ function requiresHookMapping(provider) {
51120
+ return provider === "gemini-cli";
51121
+ }
51122
+ var GEMINI_EVENT_MAP, GEMINI_TOOL_NAME_MAP;
51123
+ var init_gemini_hook_event_map = __esm(() => {
51124
+ GEMINI_EVENT_MAP = {
51125
+ PreToolUse: "BeforeTool",
51126
+ PostToolUse: "AfterTool",
51127
+ SubagentStart: "BeforeAgent",
51128
+ SubagentStop: "AfterAgent",
51129
+ Stop: "SessionEnd",
51130
+ Notification: "Notification",
51131
+ PreCompact: "PreCompress"
51132
+ };
51133
+ GEMINI_TOOL_NAME_MAP = {
51134
+ Read: "read_file",
51135
+ Glob: "glob",
51136
+ Grep: "grep_search",
51137
+ Edit: "replace",
51138
+ Write: "write_file",
51139
+ MultiEdit: "replace",
51140
+ Bash: "run_shell_command",
51141
+ WebFetch: "web_fetch",
51142
+ WebSearch: "google_web_search"
51143
+ };
51144
+ });
51145
+
51078
51146
  // src/commands/portable/hooks-settings-merger.ts
51079
51147
  import { existsSync as existsSync24, mkdirSync, renameSync, rmSync, writeFileSync as writeFileSync2 } from "node:fs";
51080
51148
  import { readFile as readFile20 } from "node:fs/promises";
@@ -51134,6 +51202,24 @@ function filterToInstalledHooks(hooks, installedFiles) {
51134
51202
  }
51135
51203
  return filtered;
51136
51204
  }
51205
+ function mapHookEventsForProvider(hooks, targetProvider) {
51206
+ if (!requiresHookMapping(targetProvider))
51207
+ return hooks;
51208
+ const mapped = {};
51209
+ for (const [event, groups] of Object.entries(hooks)) {
51210
+ const mappedEvent = mapEventName(event);
51211
+ const mappedGroups = groups.map((group) => ({
51212
+ ...group,
51213
+ matcher: group.matcher ? rewriteMatcherToolNames(group.matcher) : group.matcher
51214
+ }));
51215
+ if (mapped[mappedEvent]) {
51216
+ mapped[mappedEvent].push(...mappedGroups);
51217
+ } else {
51218
+ mapped[mappedEvent] = mappedGroups;
51219
+ }
51220
+ }
51221
+ return mapped;
51222
+ }
51137
51223
  function extractFilenameFromCommand(command) {
51138
51224
  const normalized = command.replace(/\s*[|>&].*$/, "").trim();
51139
51225
  const quotedMatch = normalized.match(/["']([^"']+\.(?:js|cjs|mjs|ts))["']/);
@@ -51154,13 +51240,11 @@ async function mergeHooksIntoSettings(targetSettingsPath, newHooks) {
51154
51240
  let existingSettings = {};
51155
51241
  let backupPath = null;
51156
51242
  if (existsSync24(targetSettingsPath)) {
51157
- let raw;
51243
+ const raw = await readFile20(targetSettingsPath, "utf8");
51158
51244
  try {
51159
- raw = await readFile20(targetSettingsPath, "utf8");
51160
51245
  existingSettings = JSON.parse(raw);
51161
51246
  } catch {
51162
51247
  existingSettings = {};
51163
- raw = "";
51164
51248
  }
51165
51249
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
51166
51250
  backupPath = `${targetSettingsPath}.${timestamp}.bak`;
@@ -51311,8 +51395,9 @@ async function migrateHooksSettings(options2) {
51311
51395
  const targetHooksDir = isGlobal ? targetConfig.hooks?.globalPath ?? "" : targetConfig.hooks?.projectPath ?? "";
51312
51396
  const filtered = filterToInstalledHooks(sourceHooks, installedHookFiles);
51313
51397
  const rewritten = rewriteHookPaths(filtered, sourceHooksDir, targetHooksDir);
51398
+ const eventMapped = mapHookEventsForProvider(rewritten, targetProvider);
51314
51399
  let hooksRegistered = 0;
51315
- for (const groups of Object.values(rewritten)) {
51400
+ for (const groups of Object.values(eventMapped)) {
51316
51401
  for (const group of groups) {
51317
51402
  hooksRegistered += group.hooks.length;
51318
51403
  }
@@ -51329,7 +51414,7 @@ async function migrateHooksSettings(options2) {
51329
51414
  };
51330
51415
  }
51331
51416
  try {
51332
- const { backupPath } = await mergeHooksIntoSettings(resolvedTargetPath, rewritten);
51417
+ const { backupPath } = await mergeHooksIntoSettings(resolvedTargetPath, eventMapped);
51333
51418
  return {
51334
51419
  status: "registered",
51335
51420
  success: true,
@@ -51351,6 +51436,7 @@ async function migrateHooksSettings(options2) {
51351
51436
  }
51352
51437
  }
51353
51438
  var init_hooks_settings_merger = __esm(() => {
51439
+ init_gemini_hook_event_map();
51354
51440
  init_provider_registry();
51355
51441
  });
51356
51442
 
@@ -56717,7 +56803,7 @@ function trackPhaseUnchecked(planDir, phaseId, source) {
56717
56803
  }
56718
56804
 
56719
56805
  // src/domains/plan-parser/plan-types.ts
56720
- var PhaseStatusSchema, PlanBoardStatusSchema, PlanScopeSchema, PlanPhaseSchema, ParseOptionsSchema, ValidationIssueSchema, ValidationResultSchema2, PhaseInputSchema, PlanSourceSchema, CreatePlanOptionsSchema, PlanSummarySchema, TimelinePhaseSchema, TimelineDataSchema, HeatmapCellSchema, HeatmapDataSchema, PlansRegistryEntrySchema, PlansRegistryStatsSchema, PlansRegistrySchema;
56806
+ var PhaseStatusSchema, PlanBoardStatusSchema, PlanScopeSchema, PlanPhaseSchema, ParseOptionsSchema, ValidationIssueSchema, ValidationResultSchema2, PhaseInputSchema, PlanSourceSchema, CreatePlanOptionsSchema, PlanSummarySchema, ProjectPlanListItemSchema, ProjectPlansEntrySchema, MultiProjectPlansResponseSchema, TimelinePhaseSchema, TimelineDataSchema, HeatmapCellSchema, HeatmapDataSchema, PlansRegistryEntrySchema, PlansRegistryStatsSchema, PlansRegistrySchema;
56721
56807
  var init_plan_types = __esm(() => {
56722
56808
  init_zod();
56723
56809
  PhaseStatusSchema = exports_external.enum(["completed", "in-progress", "pending"]);
@@ -56791,6 +56877,24 @@ var init_plan_types = __esm(() => {
56791
56877
  progressPct: exports_external.number().int().min(0).max(100),
56792
56878
  phases: exports_external.array(PlanPhaseSchema)
56793
56879
  });
56880
+ ProjectPlanListItemSchema = exports_external.object({
56881
+ file: exports_external.string(),
56882
+ name: exports_external.string(),
56883
+ slug: exports_external.string(),
56884
+ summary: PlanSummarySchema
56885
+ });
56886
+ ProjectPlansEntrySchema = exports_external.object({
56887
+ id: exports_external.string(),
56888
+ name: exports_external.string(),
56889
+ path: exports_external.string(),
56890
+ plansDir: exports_external.string(),
56891
+ error: exports_external.string().optional(),
56892
+ plans: exports_external.array(ProjectPlanListItemSchema)
56893
+ });
56894
+ MultiProjectPlansResponseSchema = exports_external.object({
56895
+ projects: exports_external.array(ProjectPlansEntrySchema),
56896
+ totalPlans: exports_external.number().int().min(0)
56897
+ });
56794
56898
  TimelinePhaseSchema = exports_external.object({
56795
56899
  phaseId: exports_external.string(),
56796
56900
  name: exports_external.string(),
@@ -57140,8 +57244,154 @@ var init_action_signal = __esm(() => {
57140
57244
  cleanupTimers = new Map;
57141
57245
  });
57142
57246
 
57247
+ // node_modules/yocto-queue/index.js
57248
+ class Node {
57249
+ value;
57250
+ next;
57251
+ constructor(value) {
57252
+ this.value = value;
57253
+ }
57254
+ }
57255
+ var Queue;
57256
+ var init_yocto_queue = __esm(() => {
57257
+ Queue = class Queue {
57258
+ #head;
57259
+ #tail;
57260
+ #size;
57261
+ constructor() {
57262
+ this.clear();
57263
+ }
57264
+ enqueue(value) {
57265
+ const node = new Node(value);
57266
+ if (this.#head) {
57267
+ this.#tail.next = node;
57268
+ this.#tail = node;
57269
+ } else {
57270
+ this.#head = node;
57271
+ this.#tail = node;
57272
+ }
57273
+ this.#size++;
57274
+ }
57275
+ dequeue() {
57276
+ const current = this.#head;
57277
+ if (!current) {
57278
+ return;
57279
+ }
57280
+ this.#head = this.#head.next;
57281
+ this.#size--;
57282
+ if (!this.#head) {
57283
+ this.#tail = undefined;
57284
+ }
57285
+ return current.value;
57286
+ }
57287
+ peek() {
57288
+ if (!this.#head) {
57289
+ return;
57290
+ }
57291
+ return this.#head.value;
57292
+ }
57293
+ clear() {
57294
+ this.#head = undefined;
57295
+ this.#tail = undefined;
57296
+ this.#size = 0;
57297
+ }
57298
+ get size() {
57299
+ return this.#size;
57300
+ }
57301
+ *[Symbol.iterator]() {
57302
+ let current = this.#head;
57303
+ while (current) {
57304
+ yield current.value;
57305
+ current = current.next;
57306
+ }
57307
+ }
57308
+ *drain() {
57309
+ while (this.#head) {
57310
+ yield this.dequeue();
57311
+ }
57312
+ }
57313
+ };
57314
+ });
57315
+
57316
+ // node_modules/p-limit/index.js
57317
+ function pLimit(concurrency) {
57318
+ validateConcurrency(concurrency);
57319
+ const queue = new Queue;
57320
+ let activeCount = 0;
57321
+ const resumeNext = () => {
57322
+ if (activeCount < concurrency && queue.size > 0) {
57323
+ activeCount++;
57324
+ queue.dequeue()();
57325
+ }
57326
+ };
57327
+ const next = () => {
57328
+ activeCount--;
57329
+ resumeNext();
57330
+ };
57331
+ const run = async (function_, resolve17, arguments_) => {
57332
+ const result = (async () => function_(...arguments_))();
57333
+ resolve17(result);
57334
+ try {
57335
+ await result;
57336
+ } catch {}
57337
+ next();
57338
+ };
57339
+ const enqueue = (function_, resolve17, arguments_) => {
57340
+ new Promise((internalResolve) => {
57341
+ queue.enqueue(internalResolve);
57342
+ }).then(run.bind(undefined, function_, resolve17, arguments_));
57343
+ if (activeCount < concurrency) {
57344
+ resumeNext();
57345
+ }
57346
+ };
57347
+ const generator = (function_, ...arguments_) => new Promise((resolve17) => {
57348
+ enqueue(function_, resolve17, arguments_);
57349
+ });
57350
+ Object.defineProperties(generator, {
57351
+ activeCount: {
57352
+ get: () => activeCount
57353
+ },
57354
+ pendingCount: {
57355
+ get: () => queue.size
57356
+ },
57357
+ clearQueue: {
57358
+ value() {
57359
+ queue.clear();
57360
+ }
57361
+ },
57362
+ concurrency: {
57363
+ get: () => concurrency,
57364
+ set(newConcurrency) {
57365
+ validateConcurrency(newConcurrency);
57366
+ concurrency = newConcurrency;
57367
+ queueMicrotask(() => {
57368
+ while (activeCount < concurrency && queue.size > 0) {
57369
+ resumeNext();
57370
+ }
57371
+ });
57372
+ }
57373
+ },
57374
+ map: {
57375
+ async value(iterable, function_) {
57376
+ const promises = Array.from(iterable, (value, index) => this(function_, value, index));
57377
+ return Promise.all(promises);
57378
+ }
57379
+ }
57380
+ });
57381
+ return generator;
57382
+ }
57383
+ function validateConcurrency(concurrency) {
57384
+ if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
57385
+ throw new TypeError("Expected `concurrency` to be a number from 1 and up");
57386
+ }
57387
+ }
57388
+ var init_p_limit = __esm(() => {
57389
+ init_yocto_queue();
57390
+ });
57391
+
57143
57392
  // src/domains/web-server/routes/plan-routes.ts
57144
57393
  import { existsSync as existsSync33, readFileSync as readFileSync11, realpathSync } from "node:fs";
57394
+ import { homedir as homedir28 } from "node:os";
57145
57395
  import { basename as basename16, dirname as dirname18, join as join52, relative as relative11, resolve as resolve17, sep as sep6 } from "node:path";
57146
57396
  function sanitizeError(err) {
57147
57397
  if (err instanceof Error) {
@@ -57211,7 +57461,19 @@ async function getProjectPathForRequest(projectId) {
57211
57461
  return null;
57212
57462
  if (projectId.startsWith("discovered-")) {
57213
57463
  try {
57214
- return Buffer.from(projectId.slice("discovered-".length), "base64url").toString("utf-8");
57464
+ const decodedPath = Buffer.from(projectId.slice("discovered-".length), "base64url").toString("utf-8");
57465
+ if (!decodedPath)
57466
+ return null;
57467
+ const now = Date.now();
57468
+ const discoveredPaths = cachedDiscoveredProjectKeys && cachedDiscoveredProjectKeys.expiresAt > now ? cachedDiscoveredProjectKeys.value : new Set(scanClaudeProjects().map((project) => toProjectPathKey(project.path)));
57469
+ if (!cachedDiscoveredProjectKeys || cachedDiscoveredProjectKeys.expiresAt <= now) {
57470
+ cachedDiscoveredProjectKeys = {
57471
+ value: discoveredPaths,
57472
+ expiresAt: now + GLOBAL_PLAN_ROOT_CACHE_TTL_MS
57473
+ };
57474
+ }
57475
+ const projectPath = toProjectPathKey(decodedPath);
57476
+ return discoveredPaths.has(projectPath) ? projectPath : null;
57215
57477
  } catch {
57216
57478
  return null;
57217
57479
  }
@@ -57226,8 +57488,9 @@ async function getAllowedRoots(projectId) {
57226
57488
  return roots;
57227
57489
  try {
57228
57490
  const { config } = await CkConfigManager.loadFull(projectPath);
57229
- roots.push(resolveProjectPlansDir(projectPath, config));
57230
- roots.push(resolveGlobalPlansDir(config));
57491
+ const projectPlansDir = projectId?.startsWith("discovered-") ? resolveSafeDiscoveredProjectPlansDir(projectPath, config) : resolveProjectPlansDir(projectPath, config);
57492
+ roots.push(projectPlansDir);
57493
+ roots.push(getGlobalPlanRoot());
57231
57494
  } catch {}
57232
57495
  return Array.from(new Set(roots.map((root) => resolve17(root))));
57233
57496
  }
@@ -57263,6 +57526,70 @@ function getPlanDirPath(value, res, projectId) {
57263
57526
  function getPlanFilePath(value, res, projectId) {
57264
57527
  return getSafePath(value, "file", res, projectId);
57265
57528
  }
57529
+ function toProjectPathKey(projectPath) {
57530
+ const resolvedPath = resolve17(projectPath);
57531
+ if (!existsSync33(resolvedPath)) {
57532
+ return resolvedPath;
57533
+ }
57534
+ try {
57535
+ return realpathSync(resolvedPath);
57536
+ } catch {
57537
+ return resolvedPath;
57538
+ }
57539
+ }
57540
+ function createDiscoveredProjectId(projectPath) {
57541
+ return `discovered-${Buffer.from(projectPath).toString("base64url")}`;
57542
+ }
57543
+ function toProjectPlanListItem(summary, plansDir) {
57544
+ return {
57545
+ file: relative11(plansDir, summary.planFile),
57546
+ name: basename16(dirname18(summary.planFile)),
57547
+ slug: basename16(dirname18(summary.planFile)),
57548
+ summary: {
57549
+ ...summary,
57550
+ planDir: relative11(plansDir, summary.planDir),
57551
+ planFile: relative11(plansDir, summary.planFile)
57552
+ }
57553
+ };
57554
+ }
57555
+ async function buildProjectPlansEntry(target) {
57556
+ const projectPath = toProjectPathKey(target.path);
57557
+ const { config } = await CkConfigManager.loadFull(projectPath);
57558
+ const plansDir = target.id.startsWith("discovered-") ? resolveSafeDiscoveredProjectPlansDir(projectPath, config) : resolveProjectPlansDir(projectPath, config);
57559
+ const plans = buildPlanSummaries(scanPlanDir(plansDir)).map((summary) => toProjectPlanListItem(summary, plansDir));
57560
+ return {
57561
+ id: target.id,
57562
+ name: target.name,
57563
+ path: projectPath,
57564
+ plansDir,
57565
+ plans
57566
+ };
57567
+ }
57568
+ function withTimeout(promiseFactory, timeoutMs, label) {
57569
+ return new Promise((resolvePromise, rejectPromise) => {
57570
+ const timer = setTimeout(() => {
57571
+ rejectPromise(new Error(`${label} scan timed out`));
57572
+ }, timeoutMs);
57573
+ promiseFactory().then((value) => {
57574
+ clearTimeout(timer);
57575
+ resolvePromise(value);
57576
+ }, (error) => {
57577
+ clearTimeout(timer);
57578
+ rejectPromise(error);
57579
+ });
57580
+ });
57581
+ }
57582
+ function isCurrentProjectFallbackCandidate(currentPath, globalProjectKey) {
57583
+ if (toProjectPathKey(currentPath) === globalProjectKey)
57584
+ return false;
57585
+ if (toProjectPathKey(currentPath) === toProjectPathKey(homedir28()))
57586
+ return false;
57587
+ return existsSync33(join52(currentPath, ".git")) || existsSync33(CkConfigManager.getProjectConfigPath(currentPath)) || existsSync33(join52(currentPath, "plans"));
57588
+ }
57589
+ function resolveSafeDiscoveredProjectPlansDir(projectPath, config) {
57590
+ const configuredPlansDir = resolveProjectPlansDir(projectPath, config);
57591
+ return isWithinBase(configuredPlansDir, projectPath) ? configuredPlansDir : resolveProjectPlansDir(projectPath);
57592
+ }
57266
57593
  function registerPlanRoutes(app) {
57267
57594
  app.get("/api/plan/parse", async (req, res) => {
57268
57595
  const projectId = String(req.query.projectId ?? "") || undefined;
@@ -57318,6 +57645,74 @@ function registerPlanRoutes(app) {
57318
57645
  res.status(500).json({ error: sanitizeError(err) });
57319
57646
  }
57320
57647
  });
57648
+ app.get("/api/plan/list-all", async (_req, res) => {
57649
+ try {
57650
+ const globalProjectKey = toProjectPathKey(join52(homedir28(), ".claude"));
57651
+ const seenProjectKeys = new Set;
57652
+ const scanTargets = [];
57653
+ for (const project of await ProjectsRegistryManager.listProjects()) {
57654
+ if (!existsSync33(resolve17(project.path)))
57655
+ continue;
57656
+ const projectKey = toProjectPathKey(project.path);
57657
+ if (projectKey === globalProjectKey || seenProjectKeys.has(projectKey))
57658
+ continue;
57659
+ seenProjectKeys.add(projectKey);
57660
+ scanTargets.push({
57661
+ id: project.id,
57662
+ name: project.alias,
57663
+ path: project.path
57664
+ });
57665
+ }
57666
+ for (const project of scanClaudeProjects()) {
57667
+ const projectKey = toProjectPathKey(project.path);
57668
+ if (projectKey === globalProjectKey || seenProjectKeys.has(projectKey))
57669
+ continue;
57670
+ seenProjectKeys.add(projectKey);
57671
+ scanTargets.push({
57672
+ id: createDiscoveredProjectId(project.path),
57673
+ name: basename16(project.path),
57674
+ path: project.path
57675
+ });
57676
+ }
57677
+ const currentPath = resolve17(process.cwd());
57678
+ const currentProjectKey = toProjectPathKey(currentPath);
57679
+ if (isCurrentProjectFallbackCandidate(currentPath, globalProjectKey) && !seenProjectKeys.has(currentProjectKey)) {
57680
+ scanTargets.push({
57681
+ id: "current",
57682
+ name: basename16(currentPath),
57683
+ path: currentPath
57684
+ });
57685
+ }
57686
+ if (scanTargets.length === 0) {
57687
+ res.json({ projects: [], totalPlans: 0 });
57688
+ return;
57689
+ }
57690
+ const limit = pLimit(PROJECT_SCAN_CONCURRENCY);
57691
+ const results = await Promise.allSettled(scanTargets.map((target) => limit(() => withTimeout(() => buildProjectPlansEntry(target), PROJECT_SCAN_TIMEOUT_MS, target.name))));
57692
+ const projects = results.flatMap((result, index) => {
57693
+ if (result.status === "fulfilled") {
57694
+ return [result.value];
57695
+ }
57696
+ return [
57697
+ {
57698
+ id: scanTargets[index]?.id ?? `unknown-${index}`,
57699
+ name: scanTargets[index]?.name ?? `Project ${index + 1}`,
57700
+ path: scanTargets[index]?.path ?? "",
57701
+ plansDir: resolveProjectPlansDir(scanTargets[index]?.path ?? process.cwd()),
57702
+ plans: [],
57703
+ error: sanitizeError(result.reason)
57704
+ }
57705
+ ];
57706
+ });
57707
+ const response = {
57708
+ projects,
57709
+ totalPlans: projects.reduce((total, project) => total + project.plans.length, 0)
57710
+ };
57711
+ res.json(response);
57712
+ } catch (err) {
57713
+ res.status(500).json({ error: sanitizeError(err) });
57714
+ }
57715
+ });
57321
57716
  app.get("/api/plan/summary", async (req, res) => {
57322
57717
  const projectId = String(req.query.projectId ?? "") || undefined;
57323
57718
  const file = await getPlanFilePath(String(req.query.file ?? ""), res, projectId);
@@ -57422,14 +57817,16 @@ function registerPlanRoutes(app) {
57422
57817
  res.json(signal);
57423
57818
  });
57424
57819
  }
57425
- var import_gray_matter10, PaginationQuerySchema, ActionRequestSchema, GLOBAL_PLAN_ROOT_CACHE_TTL_MS = 5000, cachedGlobalPlanRoot = null;
57820
+ var import_gray_matter10, PaginationQuerySchema, ActionRequestSchema, GLOBAL_PLAN_ROOT_CACHE_TTL_MS = 5000, PROJECT_SCAN_CONCURRENCY = 5, PROJECT_SCAN_TIMEOUT_MS = 1e4, cachedGlobalPlanRoot = null, cachedDiscoveredProjectKeys = null;
57426
57821
  var init_plan_routes = __esm(() => {
57822
+ init_claudekit_data2();
57427
57823
  init_claudekit_data2();
57428
57824
  init_config();
57429
57825
  init_action_executor();
57430
57826
  init_action_signal();
57431
57827
  init_plan_parser();
57432
57828
  init_types3();
57829
+ init_p_limit();
57433
57830
  init_zod();
57434
57831
  import_gray_matter10 = __toESM(require_gray_matter(), 1);
57435
57832
  PaginationQuerySchema = exports_external.object({
@@ -57497,7 +57894,7 @@ var init_project_plan_data = __esm(() => {
57497
57894
  // src/domains/web-server/routes/project-routes.ts
57498
57895
  import { existsSync as existsSync34 } from "node:fs";
57499
57896
  import { readFile as readFile25 } from "node:fs/promises";
57500
- import { homedir as homedir28 } from "node:os";
57897
+ import { homedir as homedir29 } from "node:os";
57501
57898
  import { basename as basename17, join as join53, resolve as resolve18 } from "node:path";
57502
57899
  function registerProjectRoutes(app) {
57503
57900
  app.get("/api/projects", async (req, res) => {
@@ -57518,7 +57915,7 @@ function registerProjectRoutes(app) {
57518
57915
  for (const discovered of discoveredProjects) {
57519
57916
  if (registeredPaths.has(discovered.path))
57520
57917
  continue;
57521
- if (discovered.path === join53(homedir28(), ".claude"))
57918
+ if (discovered.path === join53(homedir29(), ".claude"))
57522
57919
  continue;
57523
57920
  const projectInfo = await detectAndBuildProjectInfo(discovered.path, `discovered-${discovered.path}`, cachedSettings, cachedSkills, false);
57524
57921
  if (projectInfo) {
@@ -57534,7 +57931,7 @@ function registerProjectRoutes(app) {
57534
57931
  if (cwdProject) {
57535
57932
  projects.push(cwdProject);
57536
57933
  }
57537
- const globalDir = join53(homedir28(), ".claude");
57934
+ const globalDir = join53(homedir29(), ".claude");
57538
57935
  const globalProject = await detectAndBuildProjectInfo(globalDir, "global", undefined, undefined, false);
57539
57936
  if (globalProject) {
57540
57937
  projects.push(globalProject);
@@ -57606,12 +58003,12 @@ function registerProjectRoutes(app) {
57606
58003
  const body = validation.data;
57607
58004
  let projectPath = body.path;
57608
58005
  if (projectPath.startsWith("~/") || projectPath === "~") {
57609
- projectPath = join53(homedir28(), projectPath.slice(1));
58006
+ projectPath = join53(homedir29(), projectPath.slice(1));
57610
58007
  } else if (projectPath.startsWith("~\\")) {
57611
- projectPath = join53(homedir28(), projectPath.slice(1));
58008
+ projectPath = join53(homedir29(), projectPath.slice(1));
57612
58009
  }
57613
58010
  projectPath = resolve18(projectPath);
57614
- const homeDir = homedir28();
58011
+ const homeDir = homedir29();
57615
58012
  if (projectPath.includes("..") || !projectPath.startsWith(homeDir)) {
57616
58013
  res.status(400).json({ error: "Invalid path after expansion" });
57617
58014
  return;
@@ -57668,7 +58065,7 @@ function registerProjectRoutes(app) {
57668
58065
  if (id === "current") {
57669
58066
  projectPath = process.cwd();
57670
58067
  } else if (id === "global") {
57671
- projectPath = join53(homedir28(), ".claude");
58068
+ projectPath = join53(homedir29(), ".claude");
57672
58069
  } else {
57673
58070
  res.status(404).json({ error: "Project not found" });
57674
58071
  return;
@@ -57748,7 +58145,7 @@ async function buildProjectInfoFromRegistry(registered, cachedSettings, cachedSk
57748
58145
  const hasLocalConfig = hasClaudeDir && CkConfigManager.projectConfigExists(registered.path, false);
57749
58146
  const settings = cachedSettings !== undefined ? cachedSettings : await readSettings();
57750
58147
  const skills = cachedSkills !== undefined ? cachedSkills : await scanSkills();
57751
- const settingsPath = join53(homedir28(), ".claude", "settings.json");
58148
+ const settingsPath = join53(homedir29(), ".claude", "settings.json");
57752
58149
  const health = existsSync34(settingsPath) ? "healthy" : "warning";
57753
58150
  const model = getCurrentModel() || settings?.model || "claude-sonnet-4";
57754
58151
  const planData = includePlanData ? await buildProjectPlanData(registered.path, "project") : null;
@@ -57790,7 +58187,7 @@ async function detectAndBuildProjectInfo(path5, id, cachedSettings, cachedSkills
57790
58187
  const hasLocalConfig = CkConfigManager.projectConfigExists(path5, id === "global");
57791
58188
  const settings = cachedSettings !== undefined ? cachedSettings : await readSettings();
57792
58189
  const skills = cachedSkills !== undefined ? cachedSkills : await scanSkills();
57793
- const settingsPath = join53(homedir28(), ".claude", "settings.json");
58190
+ const settingsPath = join53(homedir29(), ".claude", "settings.json");
57794
58191
  const health = existsSync34(settingsPath) ? "healthy" : "warning";
57795
58192
  const model = getCurrentModel() || settings?.model || "claude-sonnet-4";
57796
58193
  const scope = id === "global" ? "global" : "project";
@@ -57838,7 +58235,7 @@ var init_project_routes = __esm(() => {
57838
58235
  // src/domains/web-server/routes/session-routes.ts
57839
58236
  import { existsSync as existsSync35 } from "node:fs";
57840
58237
  import { readFile as readFile26, readdir as readdir14, stat as stat9 } from "node:fs/promises";
57841
- import { homedir as homedir29 } from "node:os";
58238
+ import { homedir as homedir30 } from "node:os";
57842
58239
  import { basename as basename18, join as join54 } from "node:path";
57843
58240
  function toDateStr(d3) {
57844
58241
  const y3 = d3.getFullYear();
@@ -57847,7 +58244,7 @@ function toDateStr(d3) {
57847
58244
  return `${y3}-${m2}-${day}`;
57848
58245
  }
57849
58246
  async function scanActivityMetrics(periodDays) {
57850
- const home7 = homedir29();
58247
+ const home7 = homedir30();
57851
58248
  const projectsDir2 = join54(home7, ".claude", "projects");
57852
58249
  const cutoff = new Date;
57853
58250
  cutoff.setDate(cutoff.getDate() - periodDays);
@@ -57918,7 +58315,7 @@ async function scanActivityMetrics(periodDays) {
57918
58315
  return { totalSessions, projects: projectActivities, dailyCounts };
57919
58316
  }
57920
58317
  async function resolveSessionDir(projectId) {
57921
- const home7 = homedir29();
58318
+ const home7 = homedir30();
57922
58319
  if (projectId.startsWith("discovered-")) {
57923
58320
  try {
57924
58321
  const encodedPathB64 = projectId.slice("discovered-".length);
@@ -58092,7 +58489,7 @@ async function parseSessionDetail(filePath, limit, offset) {
58092
58489
  }
58093
58490
  function registerSessionRoutes(app) {
58094
58491
  app.get("/api/sessions", async (_req, res) => {
58095
- const home7 = homedir29();
58492
+ const home7 = homedir30();
58096
58493
  const projectsDir2 = join54(home7, ".claude", "projects");
58097
58494
  if (!existsSync35(projectsDir2)) {
58098
58495
  res.json({ projects: [] });
@@ -58161,7 +58558,7 @@ function registerSessionRoutes(app) {
58161
58558
  res.status(404).json({ error: "Project not found" });
58162
58559
  return;
58163
58560
  }
58164
- const allowedBase = join54(homedir29(), ".claude", "projects");
58561
+ const allowedBase = join54(homedir30(), ".claude", "projects");
58165
58562
  if (!projectDir.startsWith(allowedBase)) {
58166
58563
  res.status(403).json({ error: "Access denied" });
58167
58564
  return;
@@ -58191,7 +58588,7 @@ function registerSessionRoutes(app) {
58191
58588
  res.status(404).json({ error: "Project not found" });
58192
58589
  return;
58193
58590
  }
58194
- const allowedBase = join54(homedir29(), ".claude", "projects");
58591
+ const allowedBase = join54(homedir30(), ".claude", "projects");
58195
58592
  if (!projectDir.startsWith(allowedBase)) {
58196
58593
  res.status(403).json({ error: "Access denied" });
58197
58594
  return;
@@ -58225,7 +58622,7 @@ var init_session_routes = __esm(() => {
58225
58622
  });
58226
58623
 
58227
58624
  // src/domains/web-server/routes/settings-routes.ts
58228
- import { homedir as homedir30 } from "node:os";
58625
+ import { homedir as homedir31 } from "node:os";
58229
58626
  function registerSettingsRoutes(app) {
58230
58627
  app.get("/api/settings", async (_req, res) => {
58231
58628
  try {
@@ -58281,7 +58678,7 @@ function registerSettingsRoutes(app) {
58281
58678
  res.json({
58282
58679
  success: true,
58283
58680
  path: "~/.claude/settings.json",
58284
- backupPath: saveResult.backupPath ? saveResult.backupPath.replace(homedir30(), "~") : null,
58681
+ backupPath: saveResult.backupPath ? saveResult.backupPath.replace(homedir31(), "~") : null,
58285
58682
  absolutePath: getSettingsPath()
58286
58683
  });
58287
58684
  } catch (error) {
@@ -58315,7 +58712,7 @@ var init_settings_routes = __esm(() => {
58315
58712
 
58316
58713
  // src/domains/skills/skill-catalog-generator.ts
58317
58714
  import { mkdir as mkdir11, readFile as readFile27, readdir as readdir15, rename as rename7, stat as stat10, writeFile as writeFile11 } from "node:fs/promises";
58318
- import { homedir as homedir31 } from "node:os";
58715
+ import { homedir as homedir32 } from "node:os";
58319
58716
  import { dirname as dirname19, join as join55, relative as relative12 } from "node:path";
58320
58717
  async function hasScripts(skillPath) {
58321
58718
  try {
@@ -58458,7 +58855,7 @@ var CATALOG_PATH, CATALOG_VERSION = "1.0.0", SKIP_DIRS4, skillCatalogGenerator;
58458
58855
  var init_skill_catalog_generator = __esm(() => {
58459
58856
  init_skills_discovery();
58460
58857
  init_logger();
58461
- CATALOG_PATH = join55(homedir31(), ".claude", ".skills-catalog.json");
58858
+ CATALOG_PATH = join55(homedir32(), ".claude", ".skills-catalog.json");
58462
58859
  SKIP_DIRS4 = [".venv", "__pycache__", "node_modules", ".git"];
58463
58860
  skillCatalogGenerator = new SkillCatalogGenerator;
58464
58861
  });
@@ -58748,7 +59145,7 @@ var init_skill_browser_routes = __esm(() => {
58748
59145
 
58749
59146
  // src/commands/skills/agents.ts
58750
59147
  import { existsSync as existsSync36, readdirSync as readdirSync5, statSync as statSync7 } from "node:fs";
58751
- import { homedir as homedir33, platform as platform5 } from "node:os";
59148
+ import { homedir as homedir34, platform as platform5 } from "node:os";
58752
59149
  import { join as join57 } from "node:path";
58753
59150
  function hasInstallSignal2(path6) {
58754
59151
  if (!path6 || !existsSync36(path6)) {
@@ -58805,7 +59202,7 @@ function isSkillInstalled(skillName, agent, options2) {
58805
59202
  }
58806
59203
  var home7, OPENCODE_BINARY_NAME2, agents;
58807
59204
  var init_agents = __esm(() => {
58808
- home7 = homedir33();
59205
+ home7 = homedir34();
58809
59206
  OPENCODE_BINARY_NAME2 = platform5() === "win32" ? "opencode.exe" : "opencode";
58810
59207
  agents = {
58811
59208
  "claude-code": {
@@ -58912,7 +59309,7 @@ var init_agents = __esm(() => {
58912
59309
  // src/commands/skills/skills-registry.ts
58913
59310
  import { existsSync as existsSync37 } from "node:fs";
58914
59311
  import { mkdir as mkdir12, readFile as readFile29, writeFile as writeFile12 } from "node:fs/promises";
58915
- import { homedir as homedir34 } from "node:os";
59312
+ import { homedir as homedir35 } from "node:os";
58916
59313
  import { dirname as dirname20, join as join58, sep as sep8 } from "node:path";
58917
59314
  function getCliVersion3() {
58918
59315
  try {
@@ -59024,7 +59421,7 @@ async function syncRegistry() {
59024
59421
  var home8, REGISTRY_PATH3, SkillInstallationSchema, SkillRegistrySchema, REGISTRY_PATH_MIGRATIONS;
59025
59422
  var init_skills_registry = __esm(() => {
59026
59423
  init_zod();
59027
- home8 = homedir34();
59424
+ home8 = homedir35();
59028
59425
  REGISTRY_PATH3 = join58(home8, ".claudekit", "skill-registry.json");
59029
59426
  SkillInstallationSchema = exports_external.object({
59030
59427
  skill: exports_external.string(),
@@ -59056,7 +59453,7 @@ var init_skills_registry = __esm(() => {
59056
59453
  // src/commands/skills/skills-installer.ts
59057
59454
  import { existsSync as existsSync38 } from "node:fs";
59058
59455
  import { cp as cp2, mkdir as mkdir13, rm as rm7, stat as stat11 } from "node:fs/promises";
59059
- import { homedir as homedir35 } from "node:os";
59456
+ import { homedir as homedir36 } from "node:os";
59060
59457
  import { dirname as dirname21, join as join59, resolve as resolve20 } from "node:path";
59061
59458
  function isSamePath2(path1, path22) {
59062
59459
  try {
@@ -59187,7 +59584,7 @@ var init_skills_installer = __esm(() => {
59187
59584
  LEGACY_SKILL_PATHS = {
59188
59585
  "gemini-cli": {
59189
59586
  project: ".gemini/skills",
59190
- global: join59(homedir35(), ".gemini/skills")
59587
+ global: join59(homedir36(), ".gemini/skills")
59191
59588
  }
59192
59589
  };
59193
59590
  });
@@ -60136,7 +60533,7 @@ var package_default;
60136
60533
  var init_package = __esm(() => {
60137
60534
  package_default = {
60138
60535
  name: "claudekit-cli",
60139
- version: "3.41.4-dev.16",
60536
+ version: "3.41.4-dev.18",
60140
60537
  description: "CLI tool for bootstrapping and updating ClaudeKit projects",
60141
60538
  type: "module",
60142
60539
  repository: {
@@ -60163,6 +60560,8 @@ var init_package = __esm(() => {
60163
60560
  "dashboard:dev": "cd src/ui && bun install --silent && cd ../.. && bun run src/index.ts config ui --dev",
60164
60561
  "dashboard:tauri": "cd src/ui && bun install --silent && cd ../.. && bun run src/index.ts config ui --dev --no-open --port 3456",
60165
60562
  "ui:build": "cd src/ui && bun install --silent && bun run build",
60563
+ "ui:test": "cd src/ui && bun install --silent && bun run test",
60564
+ "ui:test:plans": "cd src/ui && bun install --silent && bunx vitest run src/hooks/__tests__/use-plans-dashboard.vitest.ts src/pages/__tests__/PlansPage.vitest.tsx src/pages/__tests__/PlanDetailPage.vitest.tsx",
60166
60565
  "ui:dev": "cd src/ui && bun run dev",
60167
60566
  build: `bun build src/index.ts --outdir dist --target node --external @octokit/rest --external better-sqlite3 && node -e "const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf-8');fs.writeFileSync(f,c.replace(/^#!.*\\n\\/\\/ @bun\\n/,''))"`,
60168
60567
  "verify:package": "node scripts/prepublish-check.js",
@@ -60178,7 +60577,7 @@ var init_package = __esm(() => {
60178
60577
  "dev:quick": "./scripts/dev-quick-start.sh",
60179
60578
  "dev:all": "./scripts/dev-quick-start.sh all",
60180
60579
  metrics: "bun run scripts/workflow-metrics.ts",
60181
- validate: "bun run typecheck && bun run lint && bun test && bun run build",
60580
+ validate: "bun run typecheck && bun run lint && bun test && bun run ui:test && bun run build",
60182
60581
  "install:hooks": "./.githooks/install.sh",
60183
60582
  prepare: `node -e "try{require('child_process').execSync('git rev-parse --git-dir',{stdio:'ignore'});require('child_process').execSync('bash .githooks/install.sh',{stdio:'inherit'})}catch(e){console.warn('[i] Hook install skipped:',e.message)}"`
60184
60583
  },
@@ -62714,7 +63113,7 @@ import { spawn as spawn3 } from "node:child_process";
62714
63113
  import { execFile as execFile7 } from "node:child_process";
62715
63114
  import { existsSync as existsSync42 } from "node:fs";
62716
63115
  import { readFile as readFile36 } from "node:fs/promises";
62717
- import { cpus, homedir as homedir36, totalmem } from "node:os";
63116
+ import { cpus, homedir as homedir37, totalmem } from "node:os";
62718
63117
  import { join as join67 } from "node:path";
62719
63118
  function runCommand(cmd, args, fallback2) {
62720
63119
  return new Promise((resolve22) => {
@@ -62880,7 +63279,7 @@ function registerSystemRoutes(app) {
62880
63279
  gitVersion,
62881
63280
  ghVersion,
62882
63281
  shell: process.env.SHELL ?? process.env.ComSpec ?? "unknown",
62883
- homeDir: homedir36(),
63282
+ homeDir: homedir37(),
62884
63283
  cpuCores: cpus().length,
62885
63284
  totalMemoryGb: (totalmem() / 1024 ** 3).toFixed(1)
62886
63285
  };
@@ -68770,10 +69169,10 @@ var init_config_manager2 = __esm(() => {
68770
69169
 
68771
69170
  // src/services/package-installer/gemini-mcp/validation.ts
68772
69171
  import { existsSync as existsSync56, lstatSync, readlinkSync } from "node:fs";
68773
- import { homedir as homedir40 } from "node:os";
69172
+ import { homedir as homedir41 } from "node:os";
68774
69173
  import { join as join89 } from "node:path";
68775
69174
  function getGlobalMcpConfigPath() {
68776
- return join89(homedir40(), ".claude", ".mcp.json");
69175
+ return join89(homedir41(), ".claude", ".mcp.json");
68777
69176
  }
68778
69177
  function getLocalMcpConfigPath(projectDir) {
68779
69178
  return join89(projectDir, ".mcp.json");
@@ -68794,7 +69193,7 @@ function findMcpConfigPath(projectDir) {
68794
69193
  }
68795
69194
  function getGeminiSettingsPath(projectDir, isGlobal) {
68796
69195
  if (isGlobal) {
68797
- return join89(homedir40(), ".gemini", "settings.json");
69196
+ return join89(homedir41(), ".gemini", "settings.json");
68798
69197
  }
68799
69198
  return join89(projectDir, ".gemini", "settings.json");
68800
69199
  }
@@ -71422,7 +71821,7 @@ var init_content_validator = __esm(() => {
71422
71821
  import { createHash as createHash7 } from "node:crypto";
71423
71822
  import { existsSync as existsSync72, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync10, statSync as statSync13 } from "node:fs";
71424
71823
  import { rename as rename11, writeFile as writeFile35 } from "node:fs/promises";
71425
- import { homedir as homedir45 } from "node:os";
71824
+ import { homedir as homedir46 } from "node:os";
71426
71825
  import { basename as basename27, join as join151 } from "node:path";
71427
71826
  function getCachedContext(repoPath) {
71428
71827
  const cachePath = getCacheFilePath(repoPath);
@@ -71497,7 +71896,7 @@ function getCacheFilePath(repoPath) {
71497
71896
  }
71498
71897
  var CACHE_DIR, CACHE_TTL_MS4;
71499
71898
  var init_context_cache_manager = __esm(() => {
71500
- CACHE_DIR = join151(homedir45(), ".claudekit", "cache");
71899
+ CACHE_DIR = join151(homedir46(), ".claudekit", "cache");
71501
71900
  CACHE_TTL_MS4 = 24 * 60 * 60 * 1000;
71502
71901
  });
71503
71902
 
@@ -71951,10 +72350,10 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
71951
72350
  // src/commands/content/phases/photo-generator.ts
71952
72351
  import { execSync as execSync8 } from "node:child_process";
71953
72352
  import { existsSync as existsSync74, mkdirSync as mkdirSync6, readdirSync as readdirSync12 } from "node:fs";
71954
- import { homedir as homedir46 } from "node:os";
72353
+ import { homedir as homedir47 } from "node:os";
71955
72354
  import { join as join153 } from "node:path";
71956
72355
  async function generatePhoto(_content, context, config, platform16, contentId, contentLogger) {
71957
- const mediaDir = join153(config.contentDir.replace(/^~/, homedir46()), "media", String(contentId));
72356
+ const mediaDir = join153(config.contentDir.replace(/^~/, homedir47()), "media", String(contentId));
71958
72357
  if (!existsSync74(mediaDir)) {
71959
72358
  mkdirSync6(mediaDir, { recursive: true });
71960
72359
  }
@@ -72068,7 +72467,7 @@ var init_content_creator = __esm(() => {
72068
72467
 
72069
72468
  // src/commands/content/phases/content-logger.ts
72070
72469
  import { createWriteStream as createWriteStream4, existsSync as existsSync75, mkdirSync as mkdirSync7, statSync as statSync14 } from "node:fs";
72071
- import { homedir as homedir47 } from "node:os";
72470
+ import { homedir as homedir48 } from "node:os";
72072
72471
  import { join as join154 } from "node:path";
72073
72472
 
72074
72473
  class ContentLogger {
@@ -72077,7 +72476,7 @@ class ContentLogger {
72077
72476
  logDir;
72078
72477
  maxBytes;
72079
72478
  constructor(maxBytes = 0) {
72080
- this.logDir = join154(homedir47(), ".claudekit", "logs");
72479
+ this.logDir = join154(homedir48(), ".claudekit", "logs");
72081
72480
  this.maxBytes = maxBytes;
72082
72481
  }
72083
72482
  init() {
@@ -73688,11 +74087,11 @@ var init_setup_wizard = __esm(() => {
73688
74087
 
73689
74088
  // src/commands/content/content-review-commands.ts
73690
74089
  import { existsSync as existsSync79 } from "node:fs";
73691
- import { homedir as homedir48 } from "node:os";
74090
+ import { homedir as homedir49 } from "node:os";
73692
74091
  async function queueContent() {
73693
74092
  const cwd2 = process.cwd();
73694
74093
  const config = await loadContentConfig(cwd2);
73695
- const dbPath = config.dbPath.replace(/^~/, homedir48());
74094
+ const dbPath = config.dbPath.replace(/^~/, homedir49());
73696
74095
  if (!existsSync79(dbPath)) {
73697
74096
  logger.info("No content database found. Run 'ck content setup' first.");
73698
74097
  return;
@@ -73719,7 +74118,7 @@ async function queueContent() {
73719
74118
  async function approveContentCmd(id) {
73720
74119
  const cwd2 = process.cwd();
73721
74120
  const config = await loadContentConfig(cwd2);
73722
- const dbPath = config.dbPath.replace(/^~/, homedir48());
74121
+ const dbPath = config.dbPath.replace(/^~/, homedir49());
73723
74122
  const db = initDatabase(dbPath);
73724
74123
  try {
73725
74124
  approveContent(db, Number.parseInt(id, 10));
@@ -73731,7 +74130,7 @@ async function approveContentCmd(id) {
73731
74130
  async function rejectContentCmd(id, reason) {
73732
74131
  const cwd2 = process.cwd();
73733
74132
  const config = await loadContentConfig(cwd2);
73734
- const dbPath = config.dbPath.replace(/^~/, homedir48());
74133
+ const dbPath = config.dbPath.replace(/^~/, homedir49());
73735
74134
  const db = initDatabase(dbPath);
73736
74135
  try {
73737
74136
  rejectContent(db, Number.parseInt(id, 10), reason);
@@ -73762,7 +74161,7 @@ __export(exports_content_subcommands, {
73762
74161
  approveContentCmd: () => approveContentCmd
73763
74162
  });
73764
74163
  import { existsSync as existsSync80, readFileSync as readFileSync21, unlinkSync as unlinkSync5 } from "node:fs";
73765
- import { homedir as homedir49 } from "node:os";
74164
+ import { homedir as homedir50 } from "node:os";
73766
74165
  import { join as join159 } from "node:path";
73767
74166
  function isDaemonRunning() {
73768
74167
  const lockFile = join159(LOCK_DIR, `${LOCK_NAME2}.lock`);
@@ -73836,7 +74235,7 @@ async function statusContent() {
73836
74235
  } catch {}
73837
74236
  }
73838
74237
  async function logsContent(options2) {
73839
- const logDir = join159(homedir49(), ".claudekit", "logs");
74238
+ const logDir = join159(homedir50(), ".claudekit", "logs");
73840
74239
  const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
73841
74240
  const logPath = join159(logDir, `content-${dateStr}.log`);
73842
74241
  if (!existsSync80(logPath)) {
@@ -73870,12 +74269,12 @@ var init_content_subcommands = __esm(() => {
73870
74269
  init_setup_wizard();
73871
74270
  init_state_manager();
73872
74271
  init_content_review_commands();
73873
- LOCK_DIR = join159(homedir49(), ".claudekit", "locks");
74272
+ LOCK_DIR = join159(homedir50(), ".claudekit", "locks");
73874
74273
  });
73875
74274
 
73876
74275
  // src/commands/content/content-command.ts
73877
74276
  import { existsSync as existsSync81, mkdirSync as mkdirSync9, unlinkSync as unlinkSync6, writeFileSync as writeFileSync7 } from "node:fs";
73878
- import { homedir as homedir50 } from "node:os";
74277
+ import { homedir as homedir51 } from "node:os";
73879
74278
  import { join as join160 } from "node:path";
73880
74279
  async function contentCommand(options2) {
73881
74280
  const cwd2 = process.cwd();
@@ -73908,7 +74307,7 @@ async function contentCommand(options2) {
73908
74307
  if (!existsSync81(LOCK_DIR2))
73909
74308
  mkdirSync9(LOCK_DIR2, { recursive: true });
73910
74309
  writeFileSync7(LOCK_FILE, String(process.pid), "utf-8");
73911
- const dbPath = config.dbPath.replace(/^~/, homedir50());
74310
+ const dbPath = config.dbPath.replace(/^~/, homedir51());
73912
74311
  const db = initDatabase(dbPath);
73913
74312
  contentLogger.info(`Database initialised at ${dbPath}`);
73914
74313
  const adapters = initializeAdapters(config);
@@ -74054,7 +74453,7 @@ var init_content_command = __esm(() => {
74054
74453
  init_publisher();
74055
74454
  init_review_manager();
74056
74455
  init_state_manager();
74057
- LOCK_DIR2 = join160(homedir50(), ".claudekit", "locks");
74456
+ LOCK_DIR2 = join160(homedir51(), ".claudekit", "locks");
74058
74457
  LOCK_FILE = join160(LOCK_DIR2, "ck-content.lock");
74059
74458
  });
74060
74459
 
@@ -81343,7 +81742,7 @@ init_logger();
81343
81742
  init_path_resolver();
81344
81743
  import { existsSync as existsSync50 } from "node:fs";
81345
81744
  import { readFile as readFile38 } from "node:fs/promises";
81346
- import { homedir as homedir37 } from "node:os";
81745
+ import { homedir as homedir38 } from "node:os";
81347
81746
  import { dirname as dirname23, join as join75, normalize as normalize6, resolve as resolve23 } from "node:path";
81348
81747
  async function checkPathRefsValid(projectDir) {
81349
81748
  const globalClaudeMd = join75(PathResolver.getGlobalKitDir(), "CLAUDE.md");
@@ -81376,7 +81775,7 @@ async function checkPathRefsValid(projectDir) {
81376
81775
  };
81377
81776
  }
81378
81777
  const baseDir = dirname23(claudeMdPath);
81379
- const home9 = homedir37();
81778
+ const home9 = homedir38();
81380
81779
  const broken = [];
81381
81780
  for (const ref of refs) {
81382
81781
  let refPath;
@@ -81960,7 +82359,7 @@ init_path_resolver();
81960
82359
  import { spawnSync as spawnSync3 } from "node:child_process";
81961
82360
  import { existsSync as existsSync52, readFileSync as readFileSync15, statSync as statSync9, writeFileSync as writeFileSync5 } from "node:fs";
81962
82361
  import { readdir as readdir20 } from "node:fs/promises";
81963
- import { homedir as homedir38, tmpdir } from "node:os";
82362
+ import { homedir as homedir39, tmpdir } from "node:os";
81964
82363
  import { join as join79, resolve as resolve24 } from "node:path";
81965
82364
  var HOOK_CHECK_TIMEOUT_MS = 5000;
81966
82365
  var PYTHON_CHECK_TIMEOUT_MS = 3000;
@@ -81979,7 +82378,7 @@ function isPathWithin(filePath, parentDir) {
81979
82378
  }
81980
82379
  function getCanonicalGlobalCommandRoot() {
81981
82380
  const configuredGlobalDir = PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "");
81982
- const defaultGlobalDir = join79(homedir38(), ".claude").replace(/\\/g, "/");
82381
+ const defaultGlobalDir = join79(homedir39(), ".claude").replace(/\\/g, "/");
81983
82382
  return configuredGlobalDir === defaultGlobalDir ? "$HOME" : configuredGlobalDir;
81984
82383
  }
81985
82384
  function getClaudeSettingsFiles(projectDir) {
@@ -83339,7 +83738,7 @@ import { platform as platform8 } from "node:os";
83339
83738
  init_environment();
83340
83739
  init_path_resolver();
83341
83740
  import { constants as constants3, access as access4, mkdir as mkdir17, readFile as readFile40, unlink as unlink9, writeFile as writeFile18 } from "node:fs/promises";
83342
- import { arch as arch2, homedir as homedir39, platform as platform7 } from "node:os";
83741
+ import { arch as arch2, homedir as homedir40, platform as platform7 } from "node:os";
83343
83742
  import { join as join81, normalize as normalize7 } from "node:path";
83344
83743
  function shouldSkipExpensiveOperations4() {
83345
83744
  return shouldSkipExpensiveOperations();
@@ -83362,7 +83761,7 @@ async function checkPlatformDetect() {
83362
83761
  };
83363
83762
  }
83364
83763
  async function checkHomeDirResolution() {
83365
- const nodeHome = normalize7(homedir39());
83764
+ const nodeHome = normalize7(homedir40());
83366
83765
  const rawEnvHome = getHomeDirectoryFromEnv(platform7());
83367
83766
  const envHome = rawEnvHome ? normalize7(rawEnvHome) : "";
83368
83767
  const match = nodeHome === envHome && envHome !== "";
@@ -84337,147 +84736,8 @@ import { createReadStream as createReadStream2 } from "node:fs";
84337
84736
  import { stat as stat12 } from "node:fs/promises";
84338
84737
  import { relative as relative13 } from "node:path";
84339
84738
 
84340
- // node_modules/yocto-queue/index.js
84341
- class Node {
84342
- value;
84343
- next;
84344
- constructor(value) {
84345
- this.value = value;
84346
- }
84347
- }
84348
-
84349
- class Queue {
84350
- #head;
84351
- #tail;
84352
- #size;
84353
- constructor() {
84354
- this.clear();
84355
- }
84356
- enqueue(value) {
84357
- const node = new Node(value);
84358
- if (this.#head) {
84359
- this.#tail.next = node;
84360
- this.#tail = node;
84361
- } else {
84362
- this.#head = node;
84363
- this.#tail = node;
84364
- }
84365
- this.#size++;
84366
- }
84367
- dequeue() {
84368
- const current = this.#head;
84369
- if (!current) {
84370
- return;
84371
- }
84372
- this.#head = this.#head.next;
84373
- this.#size--;
84374
- if (!this.#head) {
84375
- this.#tail = undefined;
84376
- }
84377
- return current.value;
84378
- }
84379
- peek() {
84380
- if (!this.#head) {
84381
- return;
84382
- }
84383
- return this.#head.value;
84384
- }
84385
- clear() {
84386
- this.#head = undefined;
84387
- this.#tail = undefined;
84388
- this.#size = 0;
84389
- }
84390
- get size() {
84391
- return this.#size;
84392
- }
84393
- *[Symbol.iterator]() {
84394
- let current = this.#head;
84395
- while (current) {
84396
- yield current.value;
84397
- current = current.next;
84398
- }
84399
- }
84400
- *drain() {
84401
- while (this.#head) {
84402
- yield this.dequeue();
84403
- }
84404
- }
84405
- }
84406
-
84407
- // node_modules/p-limit/index.js
84408
- function pLimit(concurrency) {
84409
- validateConcurrency(concurrency);
84410
- const queue = new Queue;
84411
- let activeCount = 0;
84412
- const resumeNext = () => {
84413
- if (activeCount < concurrency && queue.size > 0) {
84414
- activeCount++;
84415
- queue.dequeue()();
84416
- }
84417
- };
84418
- const next = () => {
84419
- activeCount--;
84420
- resumeNext();
84421
- };
84422
- const run = async (function_, resolve25, arguments_) => {
84423
- const result = (async () => function_(...arguments_))();
84424
- resolve25(result);
84425
- try {
84426
- await result;
84427
- } catch {}
84428
- next();
84429
- };
84430
- const enqueue = (function_, resolve25, arguments_) => {
84431
- new Promise((internalResolve) => {
84432
- queue.enqueue(internalResolve);
84433
- }).then(run.bind(undefined, function_, resolve25, arguments_));
84434
- if (activeCount < concurrency) {
84435
- resumeNext();
84436
- }
84437
- };
84438
- const generator = (function_, ...arguments_) => new Promise((resolve25) => {
84439
- enqueue(function_, resolve25, arguments_);
84440
- });
84441
- Object.defineProperties(generator, {
84442
- activeCount: {
84443
- get: () => activeCount
84444
- },
84445
- pendingCount: {
84446
- get: () => queue.size
84447
- },
84448
- clearQueue: {
84449
- value() {
84450
- queue.clear();
84451
- }
84452
- },
84453
- concurrency: {
84454
- get: () => concurrency,
84455
- set(newConcurrency) {
84456
- validateConcurrency(newConcurrency);
84457
- concurrency = newConcurrency;
84458
- queueMicrotask(() => {
84459
- while (activeCount < concurrency && queue.size > 0) {
84460
- resumeNext();
84461
- }
84462
- });
84463
- }
84464
- },
84465
- map: {
84466
- async value(iterable, function_) {
84467
- const promises2 = Array.from(iterable, (value, index) => this(function_, value, index));
84468
- return Promise.all(promises2);
84469
- }
84470
- }
84471
- });
84472
- return generator;
84473
- }
84474
- function validateConcurrency(concurrency) {
84475
- if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
84476
- throw new TypeError("Expected `concurrency` to be a number from 1 and up");
84477
- }
84478
- }
84479
-
84480
84739
  // src/shared/concurrent-file-ops.ts
84740
+ init_p_limit();
84481
84741
  var DEFAULT_CONCURRENCY = 50;
84482
84742
  async function mapWithLimit(items, fn, concurrency = DEFAULT_CONCURRENCY) {
84483
84743
  const limit = pLimit(concurrency);
@@ -97202,7 +97462,7 @@ class FileScanner {
97202
97462
 
97203
97463
  // src/domains/installation/merger/settings-processor.ts
97204
97464
  import { execSync as execSync5 } from "node:child_process";
97205
- import { homedir as homedir41 } from "node:os";
97465
+ import { homedir as homedir42 } from "node:os";
97206
97466
  import { dirname as dirname31, join as join105 } from "node:path";
97207
97467
 
97208
97468
  // src/domains/config/installed-settings-tracker.ts
@@ -97688,7 +97948,7 @@ class SettingsProcessor {
97688
97948
  return false;
97689
97949
  }
97690
97950
  const configuredGlobalDir = PathResolver.getGlobalKitDir().replace(/\\/g, "/").replace(/\/+$/, "");
97691
- const defaultGlobalDir = join105(homedir41(), ".claude").replace(/\\/g, "/");
97951
+ const defaultGlobalDir = join105(homedir42(), ".claude").replace(/\\/g, "/");
97692
97952
  return configuredGlobalDir !== defaultGlobalDir;
97693
97953
  }
97694
97954
  getClaudeCommandRoot() {
@@ -98107,6 +98367,7 @@ class ReleaseManifestLoader {
98107
98367
  init_environment();
98108
98368
  init_logger();
98109
98369
  init_safe_spinner();
98370
+ init_p_limit();
98110
98371
 
98111
98372
  // src/services/file-operations/manifest/manifest-updater.ts
98112
98373
  init_metadata_migration();
@@ -102340,7 +102601,7 @@ async function transformFolderPaths(extractDir, folders, options2 = {}) {
102340
102601
  // src/services/transformers/global-path-transformer.ts
102341
102602
  init_logger();
102342
102603
  import { readFile as readFile57, readdir as readdir41, writeFile as writeFile32 } from "node:fs/promises";
102343
- import { homedir as homedir42, platform as platform15 } from "node:os";
102604
+ import { homedir as homedir43, platform as platform15 } from "node:os";
102344
102605
  import { extname as extname6, join as join133 } from "node:path";
102345
102606
  var IS_WINDOWS3 = platform15() === "win32";
102346
102607
  var HOME_PREFIX = IS_WINDOWS3 ? "%USERPROFILE%" : "$HOME";
@@ -102351,7 +102612,7 @@ function normalizeInstallPath(path16) {
102351
102612
  return path16.replace(/\\/g, "/").replace(/\/+$/, "");
102352
102613
  }
102353
102614
  function getDefaultGlobalClaudeDir() {
102354
- return normalizeInstallPath(join133(homedir42(), ".claude"));
102615
+ return normalizeInstallPath(join133(homedir43(), ".claude"));
102355
102616
  }
102356
102617
  function getCustomGlobalClaudeDir(targetClaudeDir) {
102357
102618
  if (!targetClaudeDir)
@@ -102762,7 +103023,7 @@ init_dist2();
102762
103023
  var import_picocolors28 = __toESM(require_picocolors(), 1);
102763
103024
  import { existsSync as existsSync61 } from "node:fs";
102764
103025
  import { readFile as readFile58, rm as rm15, unlink as unlink12 } from "node:fs/promises";
102765
- import { homedir as homedir43 } from "node:os";
103026
+ import { homedir as homedir44 } from "node:os";
102766
103027
  import { basename as basename23, join as join135, resolve as resolve34 } from "node:path";
102767
103028
  init_logger();
102768
103029
  init_agents_discovery();
@@ -103201,7 +103462,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
103201
103462
  }
103202
103463
  if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
103203
103464
  return;
103204
- const claudeDir3 = installGlobally ? join135(homedir43(), ".claude") : join135(process.cwd(), ".claude");
103465
+ const claudeDir3 = installGlobally ? join135(homedir44(), ".claude") : join135(process.cwd(), ".claude");
103205
103466
  if (!existsSync61(claudeDir3))
103206
103467
  return;
103207
103468
  try {
@@ -103357,7 +103618,7 @@ async function migrateCommand(options2) {
103357
103618
  let installGlobally = options2.global ?? false;
103358
103619
  if (options2.global === undefined && !options2.yes) {
103359
103620
  const projectTarget = join135(process.cwd(), ".claude");
103360
- const globalTarget = join135(homedir43(), ".claude");
103621
+ const globalTarget = join135(homedir44(), ".claude");
103361
103622
  const scopeChoice = await ie({
103362
103623
  message: "Installation scope",
103363
103624
  options: [
@@ -103409,7 +103670,7 @@ async function migrateCommand(options2) {
103409
103670
  }
103410
103671
  const providerNames = selectedProviders.map((prov) => import_picocolors28.default.cyan(providers[prov].displayName)).join(", ");
103411
103672
  f2.message(` Providers: ${providerNames}`);
103412
- const targetDir = installGlobally ? join135(homedir43(), ".claude") : join135(process.cwd(), ".claude");
103673
+ const targetDir = installGlobally ? join135(homedir44(), ".claude") : join135(process.cwd(), ".claude");
103413
103674
  f2.message(` Scope: ${installGlobally ? "Global" : "Project"} ${import_picocolors28.default.dim(`-> ${targetDir}`)}`);
103414
103675
  const cmdProviders = getProvidersSupporting("commands");
103415
103676
  const unsupportedCmd = selectedProviders.filter((pv) => !cmdProviders.includes(pv));
@@ -104498,7 +104759,7 @@ async function handleKanban(target, options2) {
104498
104759
  process.exitCode = 1;
104499
104760
  return;
104500
104761
  }
104501
- logger.info("Starting ClaudeKit Dashboard (Kanban view)...");
104762
+ logger.info("Starting ClaudeKit Dashboard (Plans kanban view)...");
104502
104763
  const { port, dev = false } = options2;
104503
104764
  const noOpen = options2.open === false;
104504
104765
  let server;
@@ -104510,7 +104771,7 @@ async function handleKanban(target, options2) {
104510
104771
  process.exitCode = 1;
104511
104772
  return;
104512
104773
  }
104513
- const route = `/plans/${encodeURIComponent(basename24(dirname36(planFile)))}?dir=${encodeURIComponent(dirname36(dirname36(planFile)))}`;
104774
+ const route = `/plans?dir=${encodeURIComponent(dirname36(dirname36(planFile)))}&view=kanban`;
104514
104775
  const url = `http://localhost:${server.port}${route}`;
104515
104776
  console.log();
104516
104777
  console.log(import_picocolors30.default.bold(" ClaudeKit Dashboard — Plans"));
@@ -108067,7 +108328,7 @@ async function scanForRepos(parentDir) {
108067
108328
  init_logger();
108068
108329
  import { spawnSync as spawnSync8 } from "node:child_process";
108069
108330
  import { existsSync as existsSync69 } from "node:fs";
108070
- import { homedir as homedir44 } from "node:os";
108331
+ import { homedir as homedir45 } from "node:os";
108071
108332
  import { join as join148 } from "node:path";
108072
108333
  async function validateSetup(cwd2) {
108073
108334
  const workDir = cwd2 ?? process.cwd();
@@ -108099,7 +108360,7 @@ Run this command from a directory with a GitHub remote.`);
108099
108360
  } catch {
108100
108361
  throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
108101
108362
  }
108102
- const skillsPath = join148(homedir44(), ".claude", "skills");
108363
+ const skillsPath = join148(homedir45(), ".claude", "skills");
108103
108364
  const skillsAvailable = existsSync69(skillsPath);
108104
108365
  if (!skillsAvailable) {
108105
108366
  logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);