@sage-protocol/cli 0.3.2 → 0.3.3

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.
@@ -593,6 +593,72 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
593
593
  required: ['manifest']
594
594
  }
595
595
  },
596
+ {
597
+ name: 'list_templates',
598
+ description: 'List available prompt templates for quick creation.',
599
+ inputSchema: {
600
+ type: 'object',
601
+ properties: {
602
+ category: { type: 'string', description: 'Optional category filter (design, development, analysis, etc.)' },
603
+ search: { type: 'string', description: 'Optional text search over template key/name/description' }
604
+ },
605
+ required: []
606
+ }
607
+ },
608
+ {
609
+ name: 'get_template',
610
+ description: 'Get detailed information about a specific prompt template.',
611
+ inputSchema: {
612
+ type: 'object',
613
+ properties: {
614
+ key: { type: 'string', description: 'Template key' }
615
+ },
616
+ required: ['key']
617
+ }
618
+ },
619
+ {
620
+ name: 'create_from_template',
621
+ description: 'Create a new prompt from a template and save it into a local library via quick_create_prompt.',
622
+ inputSchema: {
623
+ type: 'object',
624
+ properties: {
625
+ template: { type: 'string', description: 'Template key' },
626
+ customize: {
627
+ type: 'object',
628
+ description: 'Values to substitute into the template variables'
629
+ },
630
+ library: {
631
+ type: 'string',
632
+ description: 'Target library name or CID (optional, default: My Library)'
633
+ },
634
+ name: {
635
+ type: 'string',
636
+ description: 'Override prompt display name (optional)'
637
+ }
638
+ },
639
+ required: ['template', 'customize']
640
+ }
641
+ },
642
+ {
643
+ name: 'analyze_dependencies',
644
+ description: 'Analyze variable usage across all prompts in a pinned library.',
645
+ inputSchema: {
646
+ type: 'object',
647
+ properties: {
648
+ library: {
649
+ type: 'string',
650
+ description: 'Pinned library name or CID'
651
+ },
652
+ analysis_type: {
653
+ type: 'string',
654
+ enum: ['variables', 'all'],
655
+ description: 'Type of analysis (v1 supports variables)',
656
+ default: 'variables'
657
+ }
658
+ },
659
+ required: ['library']
660
+ }
661
+ },
596
662
  {
597
663
  name: 'update_library_metadata',
598
664
  description: 'Update library-level metadata (name/description/tags) and optionally propagate tags to prompts.',
@@ -670,74 +736,33 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
670
736
  }
671
737
  },
672
738
  {
673
- name: 'list_templates',
674
- description: 'List available prompt templates for quick creation.',
675
- inputSchema: {
676
- type: 'object',
677
- properties: {
678
- category: { type: 'string', description: 'Optional category filter (design, development, analysis, etc.)' },
679
- search: { type: 'string', description: 'Optional text search over template key/name/description' }
680
- },
681
- required: []
682
- }
683
- },
684
- {
685
- name: 'get_template',
686
- description: 'Get detailed information about a specific prompt template.',
687
- inputSchema: {
688
- type: 'object',
689
- properties: {
690
- key: { type: 'string', description: 'Template key' }
691
- },
692
- required: ['key']
693
- }
694
- },
695
- {
696
- name: 'create_from_template',
697
- description: 'Create a new prompt from a template and save it into a local library via quick_create_prompt.',
739
+ name: 'suggest_subdaos_for_library',
740
+ description: 'Suggest SubDAOs that might be a good fit for publishing a given local library, and provide CLI workflows for creating your own SubDAO and pushing the library.',
698
741
  inputSchema: {
699
742
  type: 'object',
700
743
  properties: {
701
- template: { type: 'string', description: 'Template key' },
702
- customize: {
703
- type: 'object',
704
- description: 'Values to substitute into the template variables'
705
- },
706
744
  library: {
707
745
  type: 'string',
708
- description: 'Target library name or CID (optional, default: My Library)'
746
+ description: 'Local pinned library name or CID'
709
747
  },
710
- name: {
711
- type: 'string',
712
- description: 'Override prompt display name (optional)'
713
- }
714
- },
715
- required: ['template', 'customize']
716
- }
717
- },
718
- {
719
- name: 'analyze_dependencies',
720
- description: 'Analyze variable usage across all prompts in a pinned library.',
721
- inputSchema: {
722
- type: 'object',
723
- properties: {
724
- library: {
725
- type: 'string',
726
- description: 'Pinned library name or CID'
748
+ limit: {
749
+ type: 'number',
750
+ description: 'Max SubDAOs to return (default 5)',
751
+ default: 5
727
752
  },
728
- analysis_type: {
753
+ mode_filter: {
729
754
  type: 'string',
730
- enum: ['variables', 'all'],
731
- description: 'Type of analysis (v1 supports variables)',
732
- default: 'variables'
755
+ enum: ['any', 'creator', 'squad', 'community'],
756
+ description: 'Optional governance mode preference',
757
+ default: 'any'
733
758
  }
734
759
  },
735
760
  required: ['library']
736
761
  }
737
762
  },
738
763
  {
739
- name: 'suggest_subdaos_for_library',
740
- description: 'Suggest SubDAOs that might be a good fit for publishing a given local library, and provide CLI workflows for creating your own SubDAO and pushing the library.',
764
+ name: 'generate_publishing_commands',
765
+ description: 'Generate ready-to-run CLI commands for validating, uploading, and proposing a library manifest on-chain.',
741
766
  inputSchema: {
742
767
  type: 'object',
743
768
  properties: {
@@ -745,16 +770,10 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
745
770
  type: 'string',
746
771
  description: 'Local pinned library name or CID'
747
772
  },
748
- limit: {
749
- type: 'number',
750
- description: 'Max SubDAOs to return (default 5)',
751
- default: 5
752
- },
753
- mode_filter: {
773
+ target: {
754
774
  type: 'string',
755
- enum: ['any', 'creator', 'squad', 'community'],
756
- description: 'Optional governance mode preference',
757
- default: 'any'
775
+ description: 'Target SubDAO address or "auto" to pick a likely candidate',
776
+ default: 'auto'
758
777
  }
759
778
  },
760
779
  required: ['library']
@@ -1015,6 +1034,7 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1015
1034
  'tool:create_from_template': (params) => this.createPromptFromTemplate(params),
1016
1035
  'tool:analyze_dependencies': (params) => this.analyzeDependencies(params),
1017
1036
  'tool:suggest_subdaos_for_library': (params) => this.suggestSubdaosForLibrary(params),
1037
+ 'tool:generate_publishing_commands': (params) => this.generatePublishingCommands(params),
1018
1038
  });
1019
1039
 
1020
1040
  const toolHandlers = {
@@ -1048,6 +1068,50 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1048
1068
  return this.libraryBindingsManager.buildBindingsForSubdao(subdaoAddr);
1049
1069
  }
1050
1070
 
1071
+ async _enrichSubdaos(subdaos) {
1072
+ return Promise.all(subdaos.map(async (s) => {
1073
+ const derivedTags = new Set();
1074
+ let libraryCount = 0;
1075
+
1076
+ try {
1077
+ const libraries = await this.libraryBindingsManager.buildBindingsForSubdao(s.address);
1078
+ libraryCount = libraries.length;
1079
+
1080
+ // Check up to 3 libraries per SubDAO to gather context
1081
+ for (const lib of libraries.slice(0, 3)) {
1082
+ try {
1083
+ const registry = new ethers.Contract(lib.registry, this.libraryRegistryAbi, this.provider);
1084
+ const count = await registry.getManifestCIDCount();
1085
+ if (count > 0) {
1086
+ const cid = await registry.getManifestCID(count - 1n);
1087
+ if (cid) {
1088
+ const { manifest } = await this.manifestFetcher.fetchManifest(cid);
1089
+ if (manifest?.library?.tags) {
1090
+ manifest.library.tags.forEach(t => derivedTags.add(String(t).toLowerCase().trim()));
1091
+ }
1092
+ if (manifest?.prompts) {
1093
+ manifest.prompts.forEach(p => {
1094
+ if (p.tags) p.tags.forEach(t => derivedTags.add(String(t).toLowerCase().trim()));
1095
+ });
1096
+ }
1097
+ }
1098
+ }
1099
+ } catch (e) {
1100
+ // ignore individual library fetch errors
1101
+ }
1102
+ }
1103
+ } catch (e) {
1104
+ // ignore binding fetch errors
1105
+ }
1106
+
1107
+ return {
1108
+ ...s,
1109
+ derivedTags: Array.from(derivedTags),
1110
+ libraryCount
1111
+ };
1112
+ }));
1113
+ }
1114
+
1051
1115
 
1052
1116
  // ───────────────────────────── MCP Prompts helpers ─────────────────────────────
1053
1117
  getDiscoveryClient() {
@@ -1671,7 +1735,8 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1671
1735
  }
1672
1736
  const libTags = Array.from(tagsSet);
1673
1737
 
1674
- const subdaos = await this.getSubDAOList({ limit: 50 });
1738
+ // Fetch candidates - limit to 20 to allow for deeper analysis
1739
+ const subdaos = await this.getSubDAOList({ limit: 20 });
1675
1740
  if (!subdaos || !subdaos.length) {
1676
1741
  const fallbackText =
1677
1742
  'No SubDAOs discovered from subgraph/factory.\n\n' +
@@ -1686,9 +1751,12 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1686
1751
  return { content: [{ type: 'text', text: fallbackText }] };
1687
1752
  }
1688
1753
 
1754
+ // Enrich SubDAOs with tags from their attached libraries
1755
+ const enrichedSubdaos = await this._enrichSubdaos(subdaos);
1756
+
1689
1757
  const modeFilter = mode_filter || 'any';
1690
1758
  const scored = [];
1691
- for (const s of subdaos) {
1759
+ for (const s of enrichedSubdaos) {
1692
1760
  const name = String(s.name || '').toLowerCase();
1693
1761
  const desc = String(s.description || '').toLowerCase();
1694
1762
  const tokens = new Set(
@@ -1697,6 +1765,10 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1697
1765
  .map((t) => t.toLowerCase().trim())
1698
1766
  .filter(Boolean),
1699
1767
  );
1768
+
1769
+ // Add derived tags to tokens for matching
1770
+ s.derivedTags.forEach(t => tokens.add(t));
1771
+
1700
1772
  let matchCount = 0;
1701
1773
  const matchedTags = [];
1702
1774
  for (const tag of libTags) {
@@ -1710,20 +1782,22 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1710
1782
  // Mode-specific filtering can be added in a future iteration.
1711
1783
  }
1712
1784
 
1713
- const libraryCount = Array.isArray(s.registries) ? s.registries.length : 0;
1714
- const fitScore = matchCount + libraryCount * 0.1;
1785
+ // Boost score if we matched on derived tags (stronger signal than just name)
1786
+ const fitScore = matchCount + s.libraryCount * 0.1;
1715
1787
  scored.push({
1716
1788
  address: s.address,
1717
1789
  name: s.name || `SubDAO-${String(s.address).slice(-6)}`,
1718
1790
  description: s.description || '',
1719
1791
  registryAddress: s.registryAddress || null,
1720
1792
  defaultLibraryId: s.defaultLibraryId || 'main',
1721
- libraryCount,
1793
+ libraryCount: s.libraryCount,
1722
1794
  matchedTags,
1723
1795
  fitScore,
1796
+ derivedTags: s.derivedTags // Include for debugging/info
1724
1797
  });
1725
1798
  }
1726
1799
 
1800
+ const anyTagMatches = scored.some((s) => (s.matchedTags || []).length > 0);
1727
1801
  scored.sort((a, b) => (b.fitScore || 0) - (a.fitScore || 0));
1728
1802
  const top = scored.slice(0, limit);
1729
1803
 
@@ -1731,14 +1805,32 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1731
1805
  lines.push(`🎯 Suggested SubDAOs for library "${libName}"`);
1732
1806
  lines.push('');
1733
1807
 
1734
- if (!top.length || !libTags.length) {
1808
+ if (!top.length || !libTags.length || !anyTagMatches) {
1735
1809
  lines.push('No strong SubDAO matches found based on tags and names.');
1810
+ if (top.length) {
1811
+ lines.push('');
1812
+ lines.push('Here are some recent SubDAOs you may consider, but scoring is neutral:');
1813
+ lines.push('');
1814
+ top.forEach((s, idx) => {
1815
+ lines.push(`${idx + 1}. ${s.name} (${s.address})`);
1816
+ lines.push(` • Libraries: ${s.libraryCount}`);
1817
+ if (s.description) {
1818
+ lines.push(` • Description: ${s.description}`);
1819
+ }
1820
+ lines.push('');
1821
+ });
1822
+ }
1736
1823
  } else {
1737
1824
  top.forEach((s, idx) => {
1738
1825
  lines.push(`${idx + 1}. ${s.name} (${s.address})`);
1739
1826
  if (s.matchedTags.length) {
1740
1827
  lines.push(` • Tag overlap: ${s.matchedTags.join(', ')}`);
1741
1828
  }
1829
+ if (s.derivedTags.length > 0) {
1830
+ // Show a few derived tags to explain why it matched
1831
+ const displayTags = s.derivedTags.slice(0, 5).join(', ');
1832
+ lines.push(` • Context: ${displayTags}${s.derivedTags.length > 5 ? '...' : ''}`);
1833
+ }
1742
1834
  lines.push(` • Libraries: ${s.libraryCount}`);
1743
1835
  if (s.description) {
1744
1836
  lines.push(` • Description: ${s.description}`);
@@ -1814,6 +1906,178 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
1814
1906
  }
1815
1907
  }
1816
1908
 
1909
+ async generatePublishingCommands({ library, target = 'auto' } = {}) {
1910
+ try {
1911
+ const lm = this.libraryManager;
1912
+ const pinned = lm.listPinned() || [];
1913
+ const id = String(library || '').trim();
1914
+ if (!id) {
1915
+ return { content: [{ type: 'text', text: 'Error: library parameter is required' }] };
1916
+ }
1917
+
1918
+ let selected = null;
1919
+ let row = pinned.find((r) => r.cid === id);
1920
+ if (row) {
1921
+ selected = lm.loadPinned(row.cid);
1922
+ selected.row = row;
1923
+ } else {
1924
+ const lower = id.toLowerCase();
1925
+ const matches = [];
1926
+ for (const r of pinned) {
1927
+ try {
1928
+ const loaded = lm.loadPinned(r.cid);
1929
+ const libName = String(loaded.manifest?.library?.name || r.name || '').toLowerCase();
1930
+ if (libName === lower) {
1931
+ matches.push({ row: r, ...loaded });
1932
+ }
1933
+ } catch (_) {
1934
+ // ignore corrupt
1935
+ }
1936
+ }
1937
+ if (matches.length === 0) {
1938
+ return {
1939
+ content: [
1940
+ {
1941
+ type: 'text',
1942
+ text: `No pinned library found matching "${library}". Use list_libraries(source="local") to see available libraries.`,
1943
+ },
1944
+ ],
1945
+ };
1946
+ }
1947
+ if (matches.length > 1) {
1948
+ const lines = matches.map(
1949
+ (m) => `- ${m.row.cid} (${m.manifest?.library?.name || m.row.name || 'unnamed'})`,
1950
+ );
1951
+ return {
1952
+ content: [
1953
+ {
1954
+ type: 'text',
1955
+ text:
1956
+ `Ambiguous library match for "${library}". Candidates:\n` +
1957
+ `${lines.join('\n')}\n\nPass an explicit CID to disambiguate.`,
1958
+ },
1959
+ ],
1960
+ };
1961
+ }
1962
+ selected = matches[0];
1963
+ }
1964
+
1965
+ const manifest = selected.manifest;
1966
+ const manifestPath = selected.path;
1967
+ const libName = manifest.library?.name || selected.row?.name || library;
1968
+ const libDescription = manifest.library?.description || '';
1969
+
1970
+ let chosenSubdao = '';
1971
+ let subdaoReason = '';
1972
+ if (target && target !== 'auto') {
1973
+ chosenSubdao = target;
1974
+ subdaoReason = 'Target provided explicitly.';
1975
+ } else {
1976
+ const tagsSet = new Set(
1977
+ (manifest.library?.tags || []).map((t) => String(t).toLowerCase().trim()).filter(Boolean),
1978
+ );
1979
+ for (const p of manifest.prompts || []) {
1980
+ if (!p || !Array.isArray(p.tags)) continue;
1981
+ for (const t of p.tags) {
1982
+ const v = String(t).toLowerCase().trim();
1983
+ if (v) tagsSet.add(v);
1984
+ }
1985
+ }
1986
+ const libTags = Array.from(tagsSet);
1987
+
1988
+ const subdaos = await this.getSubDAOList({ limit: 20 });
1989
+ if (subdaos && subdaos.length && libTags.length) {
1990
+ const enrichedSubdaos = await this._enrichSubdaos(subdaos);
1991
+ const scored = enrichedSubdaos.map((s) => {
1992
+ const name = String(s.name || '').toLowerCase();
1993
+ const desc = String(s.description || '').toLowerCase();
1994
+ const tokens = new Set(
1995
+ (name + ' ' + desc)
1996
+ .split(/[^a-z0-9]+/i)
1997
+ .map((t) => t.toLowerCase().trim())
1998
+ .filter(Boolean),
1999
+ );
2000
+ s.derivedTags.forEach(t => tokens.add(t));
2001
+
2002
+ let matchCount = 0;
2003
+ for (const tag of libTags) {
2004
+ if (tokens.has(tag)) matchCount += 1;
2005
+ }
2006
+ const fitScore = matchCount + s.libraryCount * 0.1;
2007
+ return { subdao: s, fitScore, matchCount, libraryCount: s.libraryCount };
2008
+ });
2009
+ // Only auto-pick if there is at least one SubDAO with tag matches
2010
+ const withMatches = scored.filter((s) => s.matchCount > 0);
2011
+ if (withMatches.length) {
2012
+ withMatches.sort((a, b) => (b.fitScore || 0) - (a.fitScore || 0));
2013
+ const top = withMatches[0];
2014
+ if (top && top.subdao) {
2015
+ chosenSubdao = top.subdao.address;
2016
+ subdaoReason = `Auto-selected based on tag/name overlap and existing libraries (${top.matchCount} matching tag(s)).`;
2017
+ }
2018
+ }
2019
+ }
2020
+ }
2021
+
2022
+ const manifestPathHint = manifestPath || `~/.sage/libraries/${selected.row.cid}.json`;
2023
+ const inspectCmd = `sage library cache view ${selected.row.cid}`;
2024
+ const pushCmd = chosenSubdao
2025
+ ? `sage library push ${manifestPathHint} --subdao ${chosenSubdao} --pin --wait`
2026
+ : `sage library push ${manifestPathHint} --subdao 0xYourSubDAO --pin --wait`;
2027
+ const proposalsCmd = chosenSubdao
2028
+ ? `sage governance proposals --subdao ${chosenSubdao}`
2029
+ : 'sage governance proposals --subdao 0xYourSubDAO';
2030
+
2031
+ const lines = [];
2032
+ lines.push(`📦 Publishing Guide for "${libName}"`);
2033
+ lines.push('');
2034
+ lines.push(`Manifest CID (local cache): ${selected.row.cid}`);
2035
+ lines.push(`Manifest path: ${manifestPathHint}`);
2036
+ if (chosenSubdao) {
2037
+ lines.push(`Target SubDAO: ${chosenSubdao}`);
2038
+ } else {
2039
+ lines.push('Target SubDAO: (not auto-detected; you must choose an address)');
2040
+ }
2041
+ if (subdaoReason) {
2042
+ lines.push(`Reason: ${subdaoReason}`);
2043
+ }
2044
+ lines.push('');
2045
+ lines.push('Step 1: Inspect manifest (optional)');
2046
+ lines.push(` ${inspectCmd}`);
2047
+ lines.push('');
2048
+ lines.push('Step 2: Upload manifest and schedule/propose update');
2049
+ lines.push(` ${pushCmd}`);
2050
+ lines.push('');
2051
+ lines.push('Step 3: Governance follow-up');
2052
+ lines.push(` ${proposalsCmd}`);
2053
+
2054
+ const payload = {
2055
+ library: {
2056
+ cid: selected.row.cid,
2057
+ name: libName,
2058
+ description: libDescription,
2059
+ },
2060
+ targetSubdao: chosenSubdao || null,
2061
+ steps: [
2062
+ { step: 1, title: 'Inspect manifest', command: inspectCmd },
2063
+ { step: 2, title: 'Upload & propose', command: pushCmd },
2064
+ ],
2065
+ extra: {
2066
+ governanceCommands: [proposalsCmd],
2067
+ },
2068
+ };
2069
+
2070
+ return {
2071
+ content: [
2072
+ { type: 'text', text: lines.join('\n') },
2073
+ { type: 'text', text: '```json\n' + JSON.stringify(payload, null, 2) + '\n```' },
2074
+ ],
2075
+ };
2076
+ } catch (error) {
2077
+ return { content: [{ type: 'text', text: `Error generating publishing commands: ${error.message}` }] };
2078
+ }
2079
+ }
2080
+
1817
2081
  async improvePrompt({ key, library = '', pass = 'single', focus = 'all' } = {}) {
1818
2082
  try {
1819
2083
  if (!key) {
@@ -2088,8 +2352,9 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
2088
2352
  publish: `
2089
2353
  **Publishing Prompts**
2090
2354
  1. Ensure your prompts are ready in a local library.
2091
- 2. Use \`publish_manifest_flow\` to pin to IPFS and propose to a SubDAO.
2092
- 3. This makes them available on-chain for others to discover.
2355
+ 2. Use \`publish_manifest_flow\` to validate and build a governance payload.
2356
+ 3. When ready, use \`generate_publishing_commands(library=\"...\")\` to get copy-paste CLI commands for \`sage library push\` and proposal follow-up.
2357
+ 4. This makes them available on-chain for others to discover.
2093
2358
  `,
2094
2359
  versioning: `
2095
2360
  **Versioning**
@@ -2097,6 +2362,22 @@ Note: This tool does NOT sign transactions. It prepares everything so you can ex
2097
2362
  - Prompts are stored as files in \`~/.sage/libraries/prompts/\`, so you can use Git for version control.
2098
2363
  - The \`key\` is a stable identifier used to reference the prompt; \`name\` is the human-readable display name.
2099
2364
  - Use \`rename_prompt(key="old", newKey="new", name="New Name")\` when you truly need to change the key; otherwise, prefer updating \`name\` only.
2365
+ `,
2366
+ improve: `
2367
+ **Improve Prompt**
2368
+ - \`improve_prompt\` analyzes an existing prompt and returns advisory output only. It does not modify files.
2369
+ - Parameters:
2370
+ - \`key\`: prompt key (required)
2371
+ - \`library\`: optional library name or CID for disambiguation
2372
+ - \`pass\` or \`depth\`: "single" (default) or "deep"
2373
+ - \`focus\`: "variables" | "edge-cases" | "output-quality" | "reusability" | "all"
2374
+
2375
+ Behavior:
2376
+ - \`pass="single"\`: light structural checks + suggested improvement areas + generic interview questions.
2377
+ - \`pass="deep"\`: adds heuristic per-dimension scores (structure, variables, edge cases, reusability) plus richer questions.
2378
+
2379
+ Not implemented (advisory only):
2380
+ - There is currently **no** \`auto_apply\` or \`compare_to\` behavior. Use \`improve_prompt\` to design changes, then apply them via \`quick_iterate_prompt\` or \`bulk_update_prompts\`.
2100
2381
  `,
2101
2382
  manifest: `
2102
2383
  **Manifest Structure (v2)**
@@ -73,9 +73,15 @@ function createToolArgsValidator({ zodModule } = {}) {
73
73
  improve_prompt: Z.object({
74
74
  key: Z.string().min(1).max(200),
75
75
  library: Z.string().min(1).max(200).optional(),
76
- pass: Z.enum(['single', 'deep']).optional().default('single'),
76
+ pass: Z.enum(['single', 'deep']).optional(),
77
+ depth: Z.enum(['single', 'deep']).optional(),
77
78
  focus: Z.enum(['variables', 'edge-cases', 'output-quality', 'reusability', 'all']).optional().default('all'),
78
- }),
79
+ }).transform((obj) => ({
80
+ key: obj.key,
81
+ library: obj.library,
82
+ pass: obj.depth || obj.pass || 'single',
83
+ focus: obj.focus,
84
+ })),
79
85
  rename_prompt: Z.object({
80
86
  key: Z.string().min(1).max(200),
81
87
  newKey: Z.string().min(1).max(200).optional(),
@@ -125,6 +131,10 @@ function createToolArgsValidator({ zodModule } = {}) {
125
131
  limit: Z.number().int().min(1).max(20).optional().default(5),
126
132
  mode_filter: Z.enum(['any', 'creator', 'squad', 'community']).optional().default('any'),
127
133
  }),
134
+ generate_publishing_commands: Z.object({
135
+ library: Z.string().min(1).max(200),
136
+ target: Z.string().max(200).optional().default('auto'),
137
+ }),
128
138
  };
129
139
 
130
140
  return function validate(name, args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sage-protocol/cli",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "description": "Sage Protocol CLI for managing AI prompt libraries",
5
5
  "bin": {
6
6
  "sage": "./bin/sage.js"