@rely-ai/caliber 1.18.1 → 1.18.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.
- package/README.md +1 -1
- package/dist/bin.js +493 -509
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -26,6 +26,7 @@ __export(config_exports, {
|
|
|
26
26
|
DEFAULT_FAST_MODELS: () => DEFAULT_FAST_MODELS,
|
|
27
27
|
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
28
28
|
getConfigFilePath: () => getConfigFilePath,
|
|
29
|
+
getDisplayModel: () => getDisplayModel,
|
|
29
30
|
getFastModel: () => getFastModel,
|
|
30
31
|
loadConfig: () => loadConfig,
|
|
31
32
|
readConfigFile: () => readConfigFile,
|
|
@@ -105,6 +106,12 @@ function writeConfigFile(config) {
|
|
|
105
106
|
function getConfigFilePath() {
|
|
106
107
|
return CONFIG_FILE;
|
|
107
108
|
}
|
|
109
|
+
function getDisplayModel(config) {
|
|
110
|
+
if (config.model === "default" && config.provider === "claude-cli") {
|
|
111
|
+
return process.env.ANTHROPIC_MODEL || "default (inherited from Claude Code)";
|
|
112
|
+
}
|
|
113
|
+
return config.model;
|
|
114
|
+
}
|
|
108
115
|
function getFastModel() {
|
|
109
116
|
if (process.env.CALIBER_FAST_MODEL) return process.env.CALIBER_FAST_MODEL;
|
|
110
117
|
if (process.env.ANTHROPIC_SMALL_FAST_MODEL) return process.env.ANTHROPIC_SMALL_FAST_MODEL;
|
|
@@ -218,9 +225,8 @@ import { fileURLToPath } from "url";
|
|
|
218
225
|
|
|
219
226
|
// src/commands/init.ts
|
|
220
227
|
import path19 from "path";
|
|
221
|
-
import
|
|
228
|
+
import chalk9 from "chalk";
|
|
222
229
|
import ora2 from "ora";
|
|
223
|
-
import readline3 from "readline";
|
|
224
230
|
import select5 from "@inquirer/select";
|
|
225
231
|
import checkbox from "@inquirer/checkbox";
|
|
226
232
|
import fs24 from "fs";
|
|
@@ -1753,31 +1759,21 @@ async function validateModel(options) {
|
|
|
1753
1759
|
init_config();
|
|
1754
1760
|
|
|
1755
1761
|
// src/ai/prompts.ts
|
|
1756
|
-
var
|
|
1762
|
+
var ROLE_AND_CONTEXT = `You are an expert auditor for coding agent configurations (Claude Code, Cursor, and Codex).
|
|
1757
1763
|
|
|
1758
1764
|
Your job depends on context:
|
|
1759
1765
|
- If no existing configs exist \u2192 generate an initial setup from scratch.
|
|
1760
|
-
- If existing configs are provided \u2192 audit them and suggest targeted improvements. Preserve accurate content \u2014 don't rewrite what's already correct
|
|
1761
|
-
|
|
1762
|
-
You understand these config files:
|
|
1766
|
+
- If existing configs are provided \u2192 audit them and suggest targeted improvements. Preserve accurate content \u2014 don't rewrite what's already correct.`;
|
|
1767
|
+
var CONFIG_FILE_TYPES = `You understand these config files:
|
|
1763
1768
|
- CLAUDE.md: Project context for Claude Code \u2014 build/test commands, architecture, conventions.
|
|
1764
1769
|
- AGENTS.md: Primary instructions file for OpenAI Codex \u2014 same purpose as CLAUDE.md but for the Codex agent. Also serves as a cross-agent coordination file.
|
|
1765
1770
|
- .claude/skills/{name}/SKILL.md: Skill files following the OpenSkills standard (agentskills.io). Each skill is a directory named after the skill, containing a SKILL.md with YAML frontmatter.
|
|
1766
1771
|
- .agents/skills/{name}/SKILL.md: Same OpenSkills format for Codex skills (Codex scans .agents/skills/ for skills).
|
|
1772
|
+
- .cursor/skills/{name}/SKILL.md: Same OpenSkills format for Cursor skills.
|
|
1767
1773
|
- .cursorrules: Coding rules for Cursor (deprecated legacy format \u2014 do NOT generate this).
|
|
1768
|
-
- .cursor/rules/*.mdc: Modern Cursor rules with frontmatter (description, globs, alwaysApply)
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
Audit checklist (when existing configs are provided):
|
|
1772
|
-
1. CLAUDE.md / README accuracy \u2014 do documented commands, paths, and architecture match the actual codebase?
|
|
1773
|
-
2. Missing skills \u2014 are there detected tools/frameworks that should have dedicated skills?
|
|
1774
|
-
3. Duplicate or overlapping skills \u2014 can any be merged or removed?
|
|
1775
|
-
4. Undocumented conventions \u2014 are there code patterns (commit style, async patterns, error handling) not captured in docs?
|
|
1776
|
-
5. Stale references \u2014 do docs mention removed files, renamed commands, or outdated patterns?
|
|
1777
|
-
|
|
1778
|
-
Do NOT generate .claude/settings.json or .claude/settings.local.json \u2014 those are managed by the user directly.
|
|
1779
|
-
|
|
1780
|
-
Your output MUST follow this exact format (no markdown fences):
|
|
1774
|
+
- .cursor/rules/*.mdc: Modern Cursor rules with frontmatter (description, globs, alwaysApply).`;
|
|
1775
|
+
var EXCLUSIONS = `Do NOT generate .claude/settings.json, .claude/settings.local.json, or mcpServers \u2014 those are managed separately.`;
|
|
1776
|
+
var OUTPUT_FORMAT = `Your output MUST follow this exact format (no markdown fences):
|
|
1781
1777
|
|
|
1782
1778
|
1. Exactly 6 short status lines (one per line, prefixed with "STATUS: "). Each should be a creative, specific description of what you're analyzing for THIS project \u2014 reference the project's actual languages, frameworks, or tools.
|
|
1783
1779
|
|
|
@@ -1791,34 +1787,11 @@ EXPLAIN:
|
|
|
1791
1787
|
|
|
1792
1788
|
Omit empty categories. Keep each reason punchy and specific. End with a blank line.
|
|
1793
1789
|
|
|
1794
|
-
3. The JSON object starting with {
|
|
1790
|
+
3. The JSON object starting with {.`;
|
|
1791
|
+
var FILE_DESCRIPTIONS_RULES = `The "fileDescriptions" object MUST include a one-liner for every file that will be created or modified. Use actual file paths as keys (e.g. "CLAUDE.md", "AGENTS.md", ".claude/skills/my-skill/SKILL.md", ".agents/skills/my-skill/SKILL.md", ".cursor/skills/my-skill/SKILL.md", ".cursor/rules/my-rule.mdc"). Each description should explain why the change is needed, be concise and lowercase.
|
|
1795
1792
|
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
"targetAgent": ["claude", "cursor", "codex"] (array of selected agents),
|
|
1799
|
-
"fileDescriptions": {
|
|
1800
|
-
"<file-path>": "reason for this change (max 80 chars)"
|
|
1801
|
-
},
|
|
1802
|
-
"deletions": [
|
|
1803
|
-
{ "filePath": "<path>", "reason": "why remove (max 80 chars)" }
|
|
1804
|
-
],
|
|
1805
|
-
"claude": {
|
|
1806
|
-
"claudeMd": "string (markdown content for CLAUDE.md)",
|
|
1807
|
-
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }]
|
|
1808
|
-
},
|
|
1809
|
-
"codex": {
|
|
1810
|
-
"agentsMd": "string (markdown content for AGENTS.md \u2014 the primary Codex instructions file, same quality/structure as CLAUDE.md)",
|
|
1811
|
-
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }]
|
|
1812
|
-
},
|
|
1813
|
-
"cursor": {
|
|
1814
|
-
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }],
|
|
1815
|
-
"rules": [{ "filename": "string.mdc", "content": "string (with frontmatter)" }]
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
Do NOT generate mcpServers \u2014 MCP configuration is managed separately.
|
|
1820
|
-
|
|
1821
|
-
All skills follow the OpenSkills standard (agentskills.io). Anthropic's official skill guide defines three levels of progressive disclosure:
|
|
1793
|
+
The "deletions" array should list files that should be removed (e.g. duplicate skills, stale configs). Include a reason for each. Omit the array or leave empty if nothing should be deleted.`;
|
|
1794
|
+
var SKILL_FORMAT_RULES = `All skills follow the OpenSkills standard (agentskills.io). Anthropic's official skill guide defines three levels of progressive disclosure:
|
|
1822
1795
|
- Level 1 (YAML frontmatter): Always loaded. Must have enough info for the agent to decide when to activate the skill.
|
|
1823
1796
|
- Level 2 (SKILL.md body): Loaded when the skill is relevant. Contains full instructions.
|
|
1824
1797
|
- Level 3 (references/): Only loaded on demand for deep detail.
|
|
@@ -1834,84 +1807,93 @@ Skill content structure \u2014 follow this template:
|
|
|
1834
1807
|
3. "## Examples" \u2014 at least one example showing: User says \u2192 Actions taken \u2192 Result
|
|
1835
1808
|
4. "## Troubleshooting" (optional) \u2014 common errors and how to fix them
|
|
1836
1809
|
|
|
1837
|
-
Keep skill content under 200 lines. Focus on actionable instructions, not documentation prose
|
|
1838
|
-
|
|
1839
|
-
The "fileDescriptions" object MUST include a one-liner for every file that will be created or modified. Use actual file paths as keys (e.g. "CLAUDE.md", "AGENTS.md", ".claude/skills/my-skill/SKILL.md", ".agents/skills/my-skill/SKILL.md", ".cursor/skills/my-skill/SKILL.md", ".cursor/rules/my-rule.mdc"). Each description should explain why the change is needed, be concise and lowercase.
|
|
1840
|
-
|
|
1841
|
-
The "deletions" array should list files that should be removed (e.g. duplicate skills, stale configs). Include a reason for each. Omit the array or leave empty if nothing should be deleted.
|
|
1842
|
-
|
|
1843
|
-
SCORING CRITERIA \u2014 your output is scored deterministically. Optimize for 100/100:
|
|
1810
|
+
Keep skill content under 200 lines. Focus on actionable instructions, not documentation prose.`;
|
|
1811
|
+
var SCORING_CRITERIA = `SCORING CRITERIA \u2014 your output is scored deterministically against the actual filesystem. Optimize for 100/100:
|
|
1844
1812
|
|
|
1845
1813
|
Existence (25 pts):
|
|
1846
|
-
- CLAUDE.md exists (6 pts) \u2014 always generate for claude
|
|
1847
|
-
- AGENTS.md exists (6 pts) \u2014 always generate for codex target
|
|
1848
|
-
- Skills configured (8 pts) \u2014 generate
|
|
1849
|
-
- MCP servers
|
|
1850
|
-
-
|
|
1814
|
+
- CLAUDE.md exists (6 pts) \u2014 always generate for claude targets
|
|
1815
|
+
- AGENTS.md exists (6 pts) \u2014 always generate for codex target
|
|
1816
|
+
- Skills configured (8 pts) \u2014 generate 3+ skills for full points
|
|
1817
|
+
- MCP servers referenced (3 pts) \u2014 mention detected MCP integrations in your config text
|
|
1818
|
+
- When cursor is targeted: Cursor rules exist (3+3 pts), cross-platform parity (2 pts)
|
|
1851
1819
|
|
|
1852
1820
|
Quality (25 pts):
|
|
1853
|
-
-
|
|
1854
|
-
- Concise
|
|
1855
|
-
-
|
|
1821
|
+
- Executable content (8 pts) \u2014 include 3+ code blocks with actual project commands (3 blocks = full points, 2 = 6pts, 1 = 3pts)
|
|
1822
|
+
- Concise config (6 pts) \u2014 total tokens across ALL config files must be under 2000 for full points (3500=5pts, 5000=4pts, 8000+=low)
|
|
1823
|
+
- Concrete instructions (4 pts) \u2014 every line should reference specific files, paths, or code in backticks. Avoid generic prose like "follow best practices" or "write clean code".
|
|
1856
1824
|
- No directory tree listings (3 pts) \u2014 do NOT include tree-style file listings in code blocks
|
|
1857
|
-
- No
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
-
|
|
1862
|
-
-
|
|
1863
|
-
|
|
1864
|
-
Accuracy (15 pts) \u2014
|
|
1865
|
-
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
Freshness & Safety (10 pts):
|
|
1874
|
-
- No secrets in configs (4 pts) \u2014 never include API keys, tokens, or credentials
|
|
1875
|
-
- Permissions configured (2 pts) \u2014 handled by caliber, not your responsibility
|
|
1876
|
-
|
|
1877
|
-
Bonus (5 pts):
|
|
1878
|
-
- Hooks configured (2 pts), AGENTS.md (1 pt), OpenSkills format (2 pts) \u2014 handled by caliber
|
|
1879
|
-
|
|
1880
|
-
OUTPUT SIZE CONSTRAINTS \u2014 these are critical:
|
|
1825
|
+
- No duplicate content (2 pts) \u2014 don't repeat the same content across CLAUDE.md and cursor rules
|
|
1826
|
+
- Structured with headings (2 pts) \u2014 use at least 3 ## sections and bullet lists
|
|
1827
|
+
|
|
1828
|
+
Grounding (20 pts) \u2014 CRITICAL:
|
|
1829
|
+
- Project grounding (12 pts) \u2014 reference the project's actual directories and files by name. The scoring checks which project dirs/files from the file tree appear in your config. Mention key directories and files. (50%+ coverage = full points, 35% = 9pts, 20% = 6pts, 10% = 3pts)
|
|
1830
|
+
- Reference density (8 pts) \u2014 use backticks and inline code extensively. Every file path, command, or identifier should be in backticks. Higher density of backtick references per line = higher score. (40%+ = full, 25% = 6pts, 15% = 4pts)
|
|
1831
|
+
|
|
1832
|
+
Accuracy (15 pts) \u2014 CRITICAL:
|
|
1833
|
+
- References valid (8 pts) \u2014 ONLY reference file paths that exist in the provided file tree. Every path in backticks is validated against the filesystem. If you write a path that doesn't exist, you LOSE points.
|
|
1834
|
+
- Config drift (7 pts) \u2014 handled automatically by caliber (git-based), not your responsibility.
|
|
1835
|
+
|
|
1836
|
+
Safety: Never include API keys, tokens, or credentials in config files.
|
|
1837
|
+
|
|
1838
|
+
Note: Permissions, hooks, freshness tracking, and OpenSkills frontmatter are scored automatically by caliber \u2014 do not optimize for them.`;
|
|
1839
|
+
var OUTPUT_SIZE_CONSTRAINTS = `OUTPUT SIZE CONSTRAINTS \u2014 these are critical:
|
|
1881
1840
|
- CLAUDE.md / AGENTS.md: MUST be under 150 lines for maximum score. Aim for 100-140 lines. Be concise \u2014 commands, architecture overview, and key conventions. Use bullet points and tables, not prose.
|
|
1882
|
-
- Skills: generate 3-6 skills per target platform based on project complexity. Each skill should cover a distinct tool, workflow, or domain \u2014 don't pad with generic skills.
|
|
1883
1841
|
- Each skill content: max 150 lines. Focus on patterns and examples, not exhaustive docs.
|
|
1884
1842
|
- Cursor rules: max 5 .mdc files.
|
|
1885
1843
|
- If the project is large, prioritize depth on the 3-4 most critical tools over breadth across everything.`;
|
|
1886
|
-
var
|
|
1844
|
+
var GENERATION_SYSTEM_PROMPT = `${ROLE_AND_CONTEXT}
|
|
1887
1845
|
|
|
1888
|
-
|
|
1889
|
-
- If no existing configs exist \u2192 generate an initial setup from scratch.
|
|
1890
|
-
- If existing configs are provided \u2192 audit them and suggest targeted improvements. Preserve accurate content \u2014 don't rewrite what's already correct.
|
|
1846
|
+
${CONFIG_FILE_TYPES}
|
|
1891
1847
|
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1848
|
+
Audit checklist (when existing configs are provided):
|
|
1849
|
+
1. CLAUDE.md / README accuracy \u2014 do documented commands, paths, and architecture match the actual codebase?
|
|
1850
|
+
2. Missing skills \u2014 are there detected tools/frameworks that should have dedicated skills?
|
|
1851
|
+
3. Duplicate or overlapping skills \u2014 can any be merged or removed?
|
|
1852
|
+
4. Undocumented conventions \u2014 are there code patterns (commit style, async patterns, error handling) not captured in docs?
|
|
1853
|
+
5. Stale references \u2014 do docs mention removed files, renamed commands, or outdated patterns?
|
|
1897
1854
|
|
|
1898
|
-
|
|
1855
|
+
${EXCLUSIONS}
|
|
1899
1856
|
|
|
1900
|
-
|
|
1857
|
+
${OUTPUT_FORMAT}
|
|
1901
1858
|
|
|
1902
|
-
|
|
1859
|
+
AgentSetup schema:
|
|
1860
|
+
{
|
|
1861
|
+
"targetAgent": ["claude", "cursor", "codex"] (array of selected agents),
|
|
1862
|
+
"fileDescriptions": {
|
|
1863
|
+
"<file-path>": "reason for this change (max 80 chars)"
|
|
1864
|
+
},
|
|
1865
|
+
"deletions": [
|
|
1866
|
+
{ "filePath": "<path>", "reason": "why remove (max 80 chars)" }
|
|
1867
|
+
],
|
|
1868
|
+
"claude": {
|
|
1869
|
+
"claudeMd": "string (markdown content for CLAUDE.md)",
|
|
1870
|
+
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }]
|
|
1871
|
+
},
|
|
1872
|
+
"codex": {
|
|
1873
|
+
"agentsMd": "string (markdown content for AGENTS.md \u2014 the primary Codex instructions file, same quality/structure as CLAUDE.md)",
|
|
1874
|
+
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }]
|
|
1875
|
+
},
|
|
1876
|
+
"cursor": {
|
|
1877
|
+
"skills": [{ "name": "string (kebab-case, matches directory name)", "description": "string (what this skill does and when to use it)", "content": "string (markdown body \u2014 NO frontmatter, it will be generated from name+description)" }],
|
|
1878
|
+
"rules": [{ "filename": "string.mdc", "content": "string (with frontmatter)" }]
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1903
1881
|
|
|
1904
|
-
|
|
1882
|
+
${SKILL_FORMAT_RULES}
|
|
1905
1883
|
|
|
1906
|
-
|
|
1907
|
-
[Changes]
|
|
1908
|
-
- **file-or-skill-name**: short reason (max 10 words)
|
|
1909
|
-
[Deletions]
|
|
1910
|
-
- **file-path**: short reason (max 10 words)
|
|
1884
|
+
${FILE_DESCRIPTIONS_RULES}
|
|
1911
1885
|
|
|
1912
|
-
|
|
1886
|
+
${SCORING_CRITERIA}
|
|
1913
1887
|
|
|
1914
|
-
|
|
1888
|
+
${OUTPUT_SIZE_CONSTRAINTS}
|
|
1889
|
+
- Skills: generate 3-6 skills per target platform based on project complexity. Each skill should cover a distinct tool, workflow, or domain \u2014 don't pad with generic skills.`;
|
|
1890
|
+
var CORE_GENERATION_PROMPT = `${ROLE_AND_CONTEXT}
|
|
1891
|
+
|
|
1892
|
+
${CONFIG_FILE_TYPES}
|
|
1893
|
+
|
|
1894
|
+
${EXCLUSIONS}
|
|
1895
|
+
|
|
1896
|
+
${OUTPUT_FORMAT}
|
|
1915
1897
|
|
|
1916
1898
|
CoreSetup schema:
|
|
1917
1899
|
{
|
|
@@ -1949,40 +1931,11 @@ Skill topic description MUST follow this formula: [What it does] + [When to use
|
|
|
1949
1931
|
Include specific trigger phrases users would actually say. Also include negative triggers to prevent over-triggering.
|
|
1950
1932
|
Example: "Creates a new API endpoint following the project's route pattern. Handles request validation, error responses, and DB queries. Use when user says 'add endpoint', 'new route', 'create API', or adds files to src/routes/. Do NOT use for modifying existing routes."
|
|
1951
1933
|
|
|
1952
|
-
|
|
1953
|
-
The "deletions" array should list files that should be removed (e.g. stale configs). Omit if empty.
|
|
1954
|
-
|
|
1955
|
-
SCORING CRITERIA \u2014 your output is scored deterministically against the actual filesystem. Optimize for 100/100:
|
|
1956
|
-
|
|
1957
|
-
Existence (25 pts):
|
|
1958
|
-
- CLAUDE.md exists (6 pts) \u2014 always generate for claude targets
|
|
1959
|
-
- AGENTS.md exists (6 pts) \u2014 always generate for codex target
|
|
1960
|
-
- Skills configured (8 pts) \u2014 generate 3+ skill topics for full points
|
|
1961
|
-
- For "both" target: .cursor/rules/ exist (3+3 pts), cross-platform parity (2 pts)
|
|
1962
|
-
|
|
1963
|
-
Quality (25 pts):
|
|
1964
|
-
- Executable content (8 pts) \u2014 include 3+ code blocks with project commands (3 blocks = full points)
|
|
1965
|
-
- Concise config (6 pts) \u2014 total tokens across ALL config files must be under 2000 for full points (5000=4pts, 8000+=low)
|
|
1966
|
-
- Concrete instructions (4 pts) \u2014 every line should reference specific files, paths, or code in backticks. Avoid generic prose.
|
|
1967
|
-
- No directory tree listings (3 pts) \u2014 do NOT include tree-style file listings
|
|
1968
|
-
- Structured with headings (2 pts) \u2014 use at least 3 ## sections and bullet lists
|
|
1934
|
+
${FILE_DESCRIPTIONS_RULES}
|
|
1969
1935
|
|
|
1970
|
-
|
|
1971
|
-
- Project grounding (12 pts) \u2014 reference the project's actual directories and files by name. The scoring checks which project dirs/files appear in your config. Mention key directories from the file tree.
|
|
1972
|
-
- Reference density (8 pts) \u2014 use backticks and inline code extensively. Every file path, command, or identifier should be in backticks. Higher density of specific references = higher score.
|
|
1936
|
+
${SCORING_CRITERIA}
|
|
1973
1937
|
|
|
1974
|
-
|
|
1975
|
-
- References valid (8 pts) \u2014 ONLY reference file paths that exist in the provided file tree. Every path in backticks is validated against the filesystem.
|
|
1976
|
-
- Config drift (7 pts) \u2014 config must match current code state
|
|
1977
|
-
|
|
1978
|
-
Freshness & Safety (10 pts):
|
|
1979
|
-
- No secrets (4 pts), Permissions (2 pts \u2014 handled by caliber), Freshness (4 pts \u2014 handled by caliber)
|
|
1980
|
-
|
|
1981
|
-
Bonus (5 pts): Hooks (2 pts), AGENTS.md (1 pt), OpenSkills format (2 pts) \u2014 handled by caliber
|
|
1982
|
-
|
|
1983
|
-
OUTPUT SIZE CONSTRAINTS:
|
|
1984
|
-
- CLAUDE.md / AGENTS.md: MUST be under 150 lines. Aim for 100-140 lines.
|
|
1985
|
-
- Cursor rules: max 5 .mdc files.
|
|
1938
|
+
${OUTPUT_SIZE_CONSTRAINTS}
|
|
1986
1939
|
- Skill topics: 3-6 per platform based on project complexity (name + description only, no content).`;
|
|
1987
1940
|
var SKILL_GENERATION_PROMPT = `You generate a single skill file for a coding agent (Claude Code, Cursor, or Codex).
|
|
1988
1941
|
|
|
@@ -2047,12 +2000,20 @@ Rules:
|
|
|
2047
2000
|
- Preserve all fields that the user did not ask to change.
|
|
2048
2001
|
- Do NOT generate mcpServers \u2014 MCP configuration is managed separately.
|
|
2049
2002
|
- Skills use OpenSkills format: name is kebab-case directory name, content is markdown body without frontmatter.
|
|
2050
|
-
- Update the "fileDescriptions" to reflect any changes you make
|
|
2003
|
+
- Update the "fileDescriptions" to reflect any changes you make.
|
|
2004
|
+
|
|
2005
|
+
Quality constraints \u2014 your changes are scored, so do not break these:
|
|
2006
|
+
- CLAUDE.md / AGENTS.md: MUST stay under 150 lines. If adding content, remove less important lines to stay within budget.
|
|
2007
|
+
- Avoid vague instructions ("follow best practices", "write clean code", "ensure quality").
|
|
2008
|
+
- Do NOT add directory tree listings in code blocks.
|
|
2009
|
+
- Use backticks for every file path, command, and identifier.
|
|
2010
|
+
- Keep skill content under 150 lines, focused on actionable instructions.
|
|
2011
|
+
- Only reference file paths that actually exist in the project.`;
|
|
2051
2012
|
var REFRESH_SYSTEM_PROMPT = `You are an expert at maintaining coding project documentation. Your job is to update existing documentation files based on code changes (git diffs).
|
|
2052
2013
|
|
|
2053
2014
|
You will receive:
|
|
2054
2015
|
1. Git diffs showing what code changed
|
|
2055
|
-
2. Current contents of documentation files (CLAUDE.md,
|
|
2016
|
+
2. Current contents of documentation files (CLAUDE.md, README.md, skills, cursor rules)
|
|
2056
2017
|
3. Project context (languages, frameworks)
|
|
2057
2018
|
|
|
2058
2019
|
Rules:
|
|
@@ -2062,23 +2023,22 @@ Rules:
|
|
|
2062
2023
|
- Don't add speculative or aspirational content
|
|
2063
2024
|
- Keep managed blocks (<!-- caliber:managed --> ... <!-- /caliber:managed -->) intact
|
|
2064
2025
|
- If a doc doesn't need updating, return null for it
|
|
2065
|
-
- For CLAUDE.md: update commands, architecture notes, conventions, key files if the diffs affect them
|
|
2066
|
-
- For AGENTS.md: same as CLAUDE.md \u2014 this is the primary instructions file for Codex users
|
|
2026
|
+
- For CLAUDE.md: update commands, architecture notes, conventions, key files if the diffs affect them. Keep under 150 lines.
|
|
2067
2027
|
- For README.md: update setup instructions, API docs, or feature descriptions if affected
|
|
2068
|
-
-
|
|
2028
|
+
- Only reference file paths that exist in the project
|
|
2029
|
+
- Use backticks for all file paths, commands, and identifiers
|
|
2069
2030
|
|
|
2070
2031
|
Return a JSON object with this exact shape:
|
|
2071
2032
|
{
|
|
2072
2033
|
"updatedDocs": {
|
|
2073
2034
|
"claudeMd": "<updated content or null>",
|
|
2074
|
-
"agentsMd": "<updated content or null>",
|
|
2075
2035
|
"readmeMd": "<updated content or null>",
|
|
2036
|
+
"cursorrules": "<updated content or null>",
|
|
2076
2037
|
"cursorRules": [{"filename": "name.mdc", "content": "..."}] or null,
|
|
2077
|
-
"cursorSkills": [{"slug": "string", "name": "string", "content": "..."}] or null,
|
|
2078
2038
|
"claudeSkills": [{"filename": "name.md", "content": "..."}] or null
|
|
2079
2039
|
},
|
|
2080
2040
|
"changesSummary": "<1-2 sentence summary of what was updated and why>",
|
|
2081
|
-
"docsUpdated": ["CLAUDE.md", "
|
|
2041
|
+
"docsUpdated": ["CLAUDE.md", "README.md"]
|
|
2082
2042
|
}
|
|
2083
2043
|
|
|
2084
2044
|
Respond with ONLY the JSON object, no markdown fences or extra text.`;
|
|
@@ -2107,7 +2067,7 @@ Rules for the learned section:
|
|
|
2107
2067
|
- Be additive: keep all existing learned items, add new ones, remove duplicates
|
|
2108
2068
|
- Never repeat instructions already present in the main CLAUDE.md
|
|
2109
2069
|
- Each bullet must be specific and actionable \u2014 no vague advice
|
|
2110
|
-
- Maximum ~
|
|
2070
|
+
- Maximum ~30 bullet items total
|
|
2111
2071
|
- Group related items under subheadings if there are many
|
|
2112
2072
|
- If there's nothing meaningful to learn, return null
|
|
2113
2073
|
|
|
@@ -2142,7 +2102,7 @@ Be thorough \u2014 look for signals in:
|
|
|
2142
2102
|
- Configuration files (e.g. next.config.js implies Next.js, .tf files imply Terraform + cloud providers)
|
|
2143
2103
|
- Infrastructure-as-code files (Terraform, CloudFormation, Pulumi, Dockerfiles, k8s manifests)
|
|
2144
2104
|
- CI/CD configs (.github/workflows, .gitlab-ci.yml, Jenkinsfile)
|
|
2145
|
-
-
|
|
2105
|
+
- Dockerfile base images (e.g. FROM python:3.11 implies Python, FROM node:20 implies Node.js)
|
|
2146
2106
|
|
|
2147
2107
|
Only include items you're confident about. Return ONLY the JSON object.`;
|
|
2148
2108
|
|
|
@@ -3449,7 +3409,7 @@ description: ${skill.description}
|
|
|
3449
3409
|
`;
|
|
3450
3410
|
return frontmatter + skill.content;
|
|
3451
3411
|
}
|
|
3452
|
-
function collectSetupFiles(setup) {
|
|
3412
|
+
function collectSetupFiles(setup, targetAgent) {
|
|
3453
3413
|
const files = [];
|
|
3454
3414
|
const claude = setup.claude;
|
|
3455
3415
|
const cursor = setup.cursor;
|
|
@@ -3487,7 +3447,8 @@ function collectSetupFiles(setup) {
|
|
|
3487
3447
|
}
|
|
3488
3448
|
}
|
|
3489
3449
|
}
|
|
3490
|
-
|
|
3450
|
+
const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
|
|
3451
|
+
if (codexTargeted && !fs15.existsSync("AGENTS.md") && !(codex && codex.agentsMd)) {
|
|
3491
3452
|
const agentRefs = [];
|
|
3492
3453
|
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
3493
3454
|
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
@@ -3812,12 +3773,12 @@ var GENERATION_MESSAGES = [
|
|
|
3812
3773
|
"Analyzing your project structure and dependencies...",
|
|
3813
3774
|
"Mapping out build commands and test workflows...",
|
|
3814
3775
|
"Reviewing coding patterns and conventions...",
|
|
3815
|
-
"
|
|
3776
|
+
"Extracting architecture and key file references...",
|
|
3816
3777
|
"Designing skills tailored to your codebase...",
|
|
3817
|
-
"
|
|
3778
|
+
"Writing concise, grounded config content...",
|
|
3818
3779
|
"Optimizing settings for your development workflow...",
|
|
3819
3780
|
"Building coding guidelines from your project style...",
|
|
3820
|
-
"
|
|
3781
|
+
"Cross-referencing project files for accuracy...",
|
|
3821
3782
|
"Assembling your complete agent configuration..."
|
|
3822
3783
|
];
|
|
3823
3784
|
var REFINE_MESSAGES = [
|
|
@@ -3893,15 +3854,9 @@ var SpinnerMessages = class {
|
|
|
3893
3854
|
}
|
|
3894
3855
|
};
|
|
3895
3856
|
|
|
3896
|
-
// src/
|
|
3897
|
-
init_config();
|
|
3898
|
-
|
|
3899
|
-
// src/commands/interactive-provider-setup.ts
|
|
3900
|
-
init_config();
|
|
3857
|
+
// src/utils/prompt.ts
|
|
3901
3858
|
import chalk4 from "chalk";
|
|
3902
3859
|
import readline2 from "readline";
|
|
3903
|
-
import select3 from "@inquirer/select";
|
|
3904
|
-
import confirm from "@inquirer/confirm";
|
|
3905
3860
|
function promptInput(question) {
|
|
3906
3861
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3907
3862
|
return new Promise((resolve2) => {
|
|
@@ -3911,12 +3866,21 @@ function promptInput(question) {
|
|
|
3911
3866
|
});
|
|
3912
3867
|
});
|
|
3913
3868
|
}
|
|
3869
|
+
|
|
3870
|
+
// src/commands/init.ts
|
|
3871
|
+
init_config();
|
|
3872
|
+
|
|
3873
|
+
// src/commands/interactive-provider-setup.ts
|
|
3874
|
+
init_config();
|
|
3875
|
+
import chalk5 from "chalk";
|
|
3876
|
+
import select3 from "@inquirer/select";
|
|
3877
|
+
import confirm from "@inquirer/confirm";
|
|
3914
3878
|
var PROVIDER_CHOICES = [
|
|
3915
|
-
{ name: "Claude Code \u2014
|
|
3916
|
-
{ name: "Cursor
|
|
3917
|
-
{ name: "Anthropic
|
|
3918
|
-
{ name: "Google Vertex AI
|
|
3919
|
-
{ name: "OpenAI
|
|
3879
|
+
{ name: "Claude Code \u2014 use your existing subscription (no API key)", value: "claude-cli" },
|
|
3880
|
+
{ name: "Cursor \u2014 use your existing subscription (no API key)", value: "cursor" },
|
|
3881
|
+
{ name: "Anthropic \u2014 API key from console.anthropic.com", value: "anthropic" },
|
|
3882
|
+
{ name: "Google Vertex AI \u2014 Claude models via GCP", value: "vertex" },
|
|
3883
|
+
{ name: "OpenAI \u2014 or any OpenAI-compatible endpoint", value: "openai" }
|
|
3920
3884
|
];
|
|
3921
3885
|
async function runInteractiveProviderSetup(options) {
|
|
3922
3886
|
const message = options?.selectMessage ?? "Select LLM provider";
|
|
@@ -3929,34 +3893,34 @@ async function runInteractiveProviderSetup(options) {
|
|
|
3929
3893
|
case "claude-cli": {
|
|
3930
3894
|
config.model = "default";
|
|
3931
3895
|
if (!isClaudeCliAvailable()) {
|
|
3932
|
-
console.log(
|
|
3933
|
-
console.log(
|
|
3934
|
-
console.log(
|
|
3896
|
+
console.log(chalk5.yellow("\n Claude Code CLI not found."));
|
|
3897
|
+
console.log(chalk5.dim(" Install it: ") + chalk5.hex("#83D1EB")("npm install -g @anthropic-ai/claude-code"));
|
|
3898
|
+
console.log(chalk5.dim(" Then run ") + chalk5.hex("#83D1EB")("claude") + chalk5.dim(" once to log in.\n"));
|
|
3935
3899
|
const proceed = await confirm({ message: "Continue anyway?" });
|
|
3936
3900
|
if (!proceed) throw new Error("__exit__");
|
|
3937
3901
|
} else {
|
|
3938
|
-
console.log(
|
|
3902
|
+
console.log(chalk5.dim(" Run `claude` once and log in with your Pro/Max/Team account if you haven't."));
|
|
3939
3903
|
}
|
|
3940
3904
|
break;
|
|
3941
3905
|
}
|
|
3942
3906
|
case "cursor": {
|
|
3943
3907
|
config.model = "default";
|
|
3944
3908
|
if (!isCursorAgentAvailable()) {
|
|
3945
|
-
console.log(
|
|
3946
|
-
console.log(
|
|
3947
|
-
console.log(
|
|
3909
|
+
console.log(chalk5.yellow("\n Cursor Agent CLI not found."));
|
|
3910
|
+
console.log(chalk5.dim(" Install it: ") + chalk5.hex("#83D1EB")("curl https://cursor.com/install -fsS | bash"));
|
|
3911
|
+
console.log(chalk5.dim(" Then run ") + chalk5.hex("#83D1EB")("agent login") + chalk5.dim(" to authenticate.\n"));
|
|
3948
3912
|
const proceed = await confirm({ message: "Continue anyway?" });
|
|
3949
3913
|
if (!proceed) throw new Error("__exit__");
|
|
3950
3914
|
} else {
|
|
3951
|
-
console.log(
|
|
3915
|
+
console.log(chalk5.dim(" Run `agent login` if you haven't, or set CURSOR_API_KEY."));
|
|
3952
3916
|
}
|
|
3953
3917
|
break;
|
|
3954
3918
|
}
|
|
3955
3919
|
case "anthropic": {
|
|
3956
|
-
console.log(
|
|
3920
|
+
console.log(chalk5.dim(" Get a key at https://console.anthropic.com (same account as Claude Pro/Team/Max)."));
|
|
3957
3921
|
config.apiKey = await promptInput("Anthropic API key:");
|
|
3958
3922
|
if (!config.apiKey) {
|
|
3959
|
-
console.log(
|
|
3923
|
+
console.log(chalk5.red("API key is required."));
|
|
3960
3924
|
throw new Error("__exit__");
|
|
3961
3925
|
}
|
|
3962
3926
|
config.model = await promptInput(`Model (default: ${DEFAULT_MODELS.anthropic}):`) || DEFAULT_MODELS.anthropic;
|
|
@@ -3965,7 +3929,7 @@ async function runInteractiveProviderSetup(options) {
|
|
|
3965
3929
|
case "vertex": {
|
|
3966
3930
|
config.vertexProjectId = await promptInput("GCP Project ID:");
|
|
3967
3931
|
if (!config.vertexProjectId) {
|
|
3968
|
-
console.log(
|
|
3932
|
+
console.log(chalk5.red("Project ID is required."));
|
|
3969
3933
|
throw new Error("__exit__");
|
|
3970
3934
|
}
|
|
3971
3935
|
config.vertexRegion = await promptInput("Region (default: us-east5):") || "us-east5";
|
|
@@ -3976,7 +3940,7 @@ async function runInteractiveProviderSetup(options) {
|
|
|
3976
3940
|
case "openai": {
|
|
3977
3941
|
config.apiKey = await promptInput("API key:");
|
|
3978
3942
|
if (!config.apiKey) {
|
|
3979
|
-
console.log(
|
|
3943
|
+
console.log(chalk5.red("API key is required."));
|
|
3980
3944
|
throw new Error("__exit__");
|
|
3981
3945
|
}
|
|
3982
3946
|
config.baseUrl = await promptInput("Base URL (leave empty for OpenAI, or enter custom endpoint):") || void 0;
|
|
@@ -5214,7 +5178,7 @@ function computeLocalScore(dir, targetAgent) {
|
|
|
5214
5178
|
}
|
|
5215
5179
|
|
|
5216
5180
|
// src/scoring/display.ts
|
|
5217
|
-
import
|
|
5181
|
+
import chalk6 from "chalk";
|
|
5218
5182
|
var AGENT_DISPLAY_NAMES = {
|
|
5219
5183
|
claude: "Claude Code",
|
|
5220
5184
|
cursor: "Cursor",
|
|
@@ -5232,31 +5196,31 @@ var CATEGORY_ORDER = ["existence", "quality", "grounding", "accuracy", "freshnes
|
|
|
5232
5196
|
function gradeColor(grade) {
|
|
5233
5197
|
switch (grade) {
|
|
5234
5198
|
case "A":
|
|
5235
|
-
return
|
|
5199
|
+
return chalk6.green;
|
|
5236
5200
|
case "B":
|
|
5237
|
-
return
|
|
5201
|
+
return chalk6.greenBright;
|
|
5238
5202
|
case "C":
|
|
5239
|
-
return
|
|
5203
|
+
return chalk6.yellow;
|
|
5240
5204
|
case "D":
|
|
5241
|
-
return
|
|
5205
|
+
return chalk6.hex("#f97316");
|
|
5242
5206
|
case "F":
|
|
5243
|
-
return
|
|
5207
|
+
return chalk6.red;
|
|
5244
5208
|
default:
|
|
5245
|
-
return
|
|
5209
|
+
return chalk6.white;
|
|
5246
5210
|
}
|
|
5247
5211
|
}
|
|
5248
5212
|
function progressBar(score, max, width = 40) {
|
|
5249
5213
|
const filled = Math.round(score / max * width);
|
|
5250
5214
|
const empty = width - filled;
|
|
5251
|
-
const bar =
|
|
5215
|
+
const bar = chalk6.hex("#f97316")("\u2593".repeat(filled)) + chalk6.gray("\u2591".repeat(empty));
|
|
5252
5216
|
return bar;
|
|
5253
5217
|
}
|
|
5254
5218
|
function formatCheck(check) {
|
|
5255
|
-
const icon = check.passed ?
|
|
5256
|
-
const points = check.passed ?
|
|
5257
|
-
const name = check.passed ?
|
|
5258
|
-
const detail = check.detail ?
|
|
5259
|
-
const suggestion = !check.passed && check.suggestion ?
|
|
5219
|
+
const icon = check.passed ? chalk6.green("\u2713") : check.earnedPoints < 0 ? chalk6.red("\u2717") : chalk6.gray("\u2717");
|
|
5220
|
+
const points = check.passed ? chalk6.green(`+${check.earnedPoints}`.padStart(4)) : check.earnedPoints < 0 ? chalk6.red(`${check.earnedPoints}`.padStart(4)) : chalk6.gray(" \u2014");
|
|
5221
|
+
const name = check.passed ? chalk6.white(check.name) : chalk6.gray(check.name);
|
|
5222
|
+
const detail = check.detail ? chalk6.gray(` (${check.detail})`) : "";
|
|
5223
|
+
const suggestion = !check.passed && check.suggestion ? chalk6.gray(`
|
|
5260
5224
|
\u2192 ${check.suggestion}`) : "";
|
|
5261
5225
|
return ` ${icon} ${name.padEnd(38)}${points}${detail}${suggestion}`;
|
|
5262
5226
|
}
|
|
@@ -5264,19 +5228,19 @@ function displayScore(result) {
|
|
|
5264
5228
|
const gc = gradeColor(result.grade);
|
|
5265
5229
|
const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
|
|
5266
5230
|
console.log("");
|
|
5267
|
-
console.log(
|
|
5231
|
+
console.log(chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5268
5232
|
console.log("");
|
|
5269
|
-
console.log(` ${
|
|
5233
|
+
console.log(` ${chalk6.bold("Agent Config Score")} ${gc(chalk6.bold(`${result.score} / ${result.maxScore}`))} Grade ${gc(chalk6.bold(result.grade))}`);
|
|
5270
5234
|
console.log(` ${progressBar(result.score, result.maxScore)}`);
|
|
5271
|
-
console.log(
|
|
5235
|
+
console.log(chalk6.dim(` Target: ${agentLabel}`));
|
|
5272
5236
|
console.log("");
|
|
5273
|
-
console.log(
|
|
5237
|
+
console.log(chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5274
5238
|
console.log("");
|
|
5275
5239
|
for (const category of CATEGORY_ORDER) {
|
|
5276
5240
|
const summary = result.categories[category];
|
|
5277
5241
|
const categoryChecks = result.checks.filter((c) => c.category === category);
|
|
5278
5242
|
console.log(
|
|
5279
|
-
|
|
5243
|
+
chalk6.gray(` ${CATEGORY_LABELS[category]}`) + chalk6.gray(" ".repeat(Math.max(1, 45 - CATEGORY_LABELS[category].length))) + chalk6.white(`${summary.earned}`) + chalk6.gray(` / ${summary.max}`)
|
|
5280
5244
|
);
|
|
5281
5245
|
for (const check of categoryChecks) {
|
|
5282
5246
|
console.log(formatCheck(check));
|
|
@@ -5289,48 +5253,48 @@ function displayScoreSummary(result) {
|
|
|
5289
5253
|
const agentLabel = result.targetAgent.map((a) => AGENT_DISPLAY_NAMES[a] || a).join(" + ");
|
|
5290
5254
|
console.log("");
|
|
5291
5255
|
console.log(
|
|
5292
|
-
|
|
5256
|
+
chalk6.gray(" ") + gc(`${result.score}/${result.maxScore}`) + chalk6.gray(` (Grade ${result.grade})`) + chalk6.gray(` \xB7 ${agentLabel}`) + chalk6.gray(` \xB7 ${progressBar(result.score, result.maxScore, 20)}`)
|
|
5293
5257
|
);
|
|
5294
5258
|
const failing = result.checks.filter((c) => !c.passed);
|
|
5295
5259
|
if (failing.length > 0) {
|
|
5296
5260
|
const shown = failing.slice(0, 5);
|
|
5297
5261
|
for (const check of shown) {
|
|
5298
|
-
console.log(
|
|
5262
|
+
console.log(chalk6.gray(` \u2717 ${check.name}`));
|
|
5299
5263
|
}
|
|
5300
5264
|
const remaining = failing.length - shown.length;
|
|
5301
5265
|
const moreText = remaining > 0 ? ` (+${remaining} more)` : "";
|
|
5302
|
-
console.log(
|
|
5303
|
-
Run ${
|
|
5266
|
+
console.log(chalk6.dim(`
|
|
5267
|
+
Run ${chalk6.hex("#83D1EB")("caliber score")} for details.${moreText}`));
|
|
5304
5268
|
}
|
|
5305
5269
|
console.log("");
|
|
5306
5270
|
}
|
|
5307
5271
|
function displayScoreDelta(before, after) {
|
|
5308
5272
|
const delta = after.score - before.score;
|
|
5309
5273
|
const deltaStr = delta >= 0 ? `+${delta}` : `${delta}`;
|
|
5310
|
-
const deltaColor = delta >= 0 ?
|
|
5274
|
+
const deltaColor = delta >= 0 ? chalk6.green : chalk6.red;
|
|
5311
5275
|
const beforeGc = gradeColor(before.grade);
|
|
5312
5276
|
const afterGc = gradeColor(after.grade);
|
|
5313
5277
|
console.log("");
|
|
5314
|
-
console.log(
|
|
5278
|
+
console.log(chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5315
5279
|
console.log("");
|
|
5316
5280
|
console.log(
|
|
5317
|
-
` Score: ${beforeGc(`${before.score}`)} ${
|
|
5281
|
+
` Score: ${beforeGc(`${before.score}`)} ${chalk6.gray("\u2192")} ${afterGc(`${after.score}`)} ${deltaColor(deltaStr + " pts")} ${beforeGc(before.grade)} ${chalk6.gray("\u2192")} ${afterGc(after.grade)}`
|
|
5318
5282
|
);
|
|
5319
|
-
console.log(` ${progressBar(before.score, before.maxScore, 19)} ${
|
|
5283
|
+
console.log(` ${progressBar(before.score, before.maxScore, 19)} ${chalk6.gray("\u2192")} ${progressBar(after.score, after.maxScore, 19)}`);
|
|
5320
5284
|
console.log("");
|
|
5321
|
-
console.log(
|
|
5285
|
+
console.log(chalk6.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
|
|
5322
5286
|
console.log("");
|
|
5323
5287
|
const improved = after.checks.filter((ac) => {
|
|
5324
5288
|
const bc = before.checks.find((b) => b.id === ac.id);
|
|
5325
5289
|
return bc && ac.earnedPoints > bc.earnedPoints;
|
|
5326
5290
|
});
|
|
5327
5291
|
if (improved.length > 0) {
|
|
5328
|
-
console.log(
|
|
5292
|
+
console.log(chalk6.gray(" What improved:"));
|
|
5329
5293
|
for (const check of improved) {
|
|
5330
5294
|
const bc = before.checks.find((b) => b.id === check.id);
|
|
5331
5295
|
const gain = check.earnedPoints - bc.earnedPoints;
|
|
5332
5296
|
console.log(
|
|
5333
|
-
|
|
5297
|
+
chalk6.green(" +") + chalk6.white(` ${check.name.padEnd(50)}`) + chalk6.green(`+${gain}`)
|
|
5334
5298
|
);
|
|
5335
5299
|
}
|
|
5336
5300
|
console.log("");
|
|
@@ -5338,7 +5302,7 @@ function displayScoreDelta(before, after) {
|
|
|
5338
5302
|
}
|
|
5339
5303
|
|
|
5340
5304
|
// src/commands/recommend.ts
|
|
5341
|
-
import
|
|
5305
|
+
import chalk8 from "chalk";
|
|
5342
5306
|
import ora from "ora";
|
|
5343
5307
|
import select4 from "@inquirer/select";
|
|
5344
5308
|
import { mkdirSync, readFileSync as readFileSync4, readdirSync as readdirSync4, existsSync as existsSync8, writeFileSync } from "fs";
|
|
@@ -5493,7 +5457,7 @@ init_config();
|
|
|
5493
5457
|
|
|
5494
5458
|
// src/telemetry/index.ts
|
|
5495
5459
|
import { PostHog } from "posthog-node";
|
|
5496
|
-
import
|
|
5460
|
+
import chalk7 from "chalk";
|
|
5497
5461
|
|
|
5498
5462
|
// src/telemetry/config.ts
|
|
5499
5463
|
import fs22 from "fs";
|
|
@@ -5565,7 +5529,7 @@ function initTelemetry() {
|
|
|
5565
5529
|
});
|
|
5566
5530
|
if (!wasNoticeShown()) {
|
|
5567
5531
|
console.log(
|
|
5568
|
-
|
|
5532
|
+
chalk7.dim(" Caliber collects anonymous usage data to improve the product.") + "\n" + chalk7.dim(" Disable with --no-traces or CALIBER_TELEMETRY_DISABLED=1\n")
|
|
5569
5533
|
);
|
|
5570
5534
|
markNoticeShown();
|
|
5571
5535
|
}
|
|
@@ -5925,7 +5889,7 @@ async function recommendCommand() {
|
|
|
5925
5889
|
]
|
|
5926
5890
|
});
|
|
5927
5891
|
if (!proceed) {
|
|
5928
|
-
console.log(
|
|
5892
|
+
console.log(chalk8.dim(" Cancelled.\n"));
|
|
5929
5893
|
return;
|
|
5930
5894
|
}
|
|
5931
5895
|
await searchAndInstallSkills();
|
|
@@ -5940,7 +5904,7 @@ async function searchAndInstallSkills() {
|
|
|
5940
5904
|
...extractTopDeps()
|
|
5941
5905
|
].filter(Boolean))];
|
|
5942
5906
|
if (technologies.length === 0) {
|
|
5943
|
-
console.log(
|
|
5907
|
+
console.log(chalk8.yellow("Could not detect any languages or dependencies. Try running from a project root."));
|
|
5944
5908
|
throw new Error("__exit__");
|
|
5945
5909
|
}
|
|
5946
5910
|
const primaryPlatform = platforms.includes("claude") ? "claude" : platforms[0];
|
|
@@ -5957,7 +5921,7 @@ async function searchAndInstallSkills() {
|
|
|
5957
5921
|
return;
|
|
5958
5922
|
}
|
|
5959
5923
|
searchSpinner.succeed(
|
|
5960
|
-
`Found ${allCandidates.length} skills` + (filteredCount > 0 ?
|
|
5924
|
+
`Found ${allCandidates.length} skills` + (filteredCount > 0 ? chalk8.dim(` (${filteredCount} already installed)`) : "")
|
|
5961
5925
|
);
|
|
5962
5926
|
let results;
|
|
5963
5927
|
const config = loadConfig();
|
|
@@ -5991,7 +5955,7 @@ async function searchAndInstallSkills() {
|
|
|
5991
5955
|
}
|
|
5992
5956
|
const unavailableCount = results.length - available.length;
|
|
5993
5957
|
fetchSpinner.succeed(
|
|
5994
|
-
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ?
|
|
5958
|
+
`${available.length} installable skill${available.length > 1 ? "s" : ""}` + (unavailableCount > 0 ? chalk8.dim(` (${unavailableCount} unavailable)`) : "")
|
|
5995
5959
|
);
|
|
5996
5960
|
const selected = await interactiveSelect(available);
|
|
5997
5961
|
if (selected?.length) {
|
|
@@ -6014,30 +5978,30 @@ async function interactiveSelect(recs) {
|
|
|
6014
5978
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
6015
5979
|
const prefixWidth = 8;
|
|
6016
5980
|
const scoreWidth = 6;
|
|
6017
|
-
lines.push(
|
|
5981
|
+
lines.push(chalk8.bold(" Skills"));
|
|
6018
5982
|
lines.push("");
|
|
6019
5983
|
if (hasScores) {
|
|
6020
|
-
const header = " ".repeat(prefixWidth) +
|
|
5984
|
+
const header = " ".repeat(prefixWidth) + chalk8.dim("Score".padEnd(scoreWidth)) + chalk8.dim("Name".padEnd(nameWidth)) + chalk8.dim("Why");
|
|
6021
5985
|
lines.push(header);
|
|
6022
5986
|
} else {
|
|
6023
|
-
const header = " ".repeat(prefixWidth) +
|
|
5987
|
+
const header = " ".repeat(prefixWidth) + chalk8.dim("Name".padEnd(nameWidth)) + chalk8.dim("Technology".padEnd(18)) + chalk8.dim("Source");
|
|
6024
5988
|
lines.push(header);
|
|
6025
5989
|
}
|
|
6026
|
-
lines.push(
|
|
5990
|
+
lines.push(chalk8.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
6027
5991
|
for (let i = 0; i < recs.length; i++) {
|
|
6028
5992
|
const rec = recs[i];
|
|
6029
|
-
const check = selected.has(i) ?
|
|
6030
|
-
const ptr = i === cursor ?
|
|
5993
|
+
const check = selected.has(i) ? chalk8.green("[x]") : "[ ]";
|
|
5994
|
+
const ptr = i === cursor ? chalk8.cyan(">") : " ";
|
|
6031
5995
|
if (hasScores) {
|
|
6032
|
-
const scoreColor = rec.score >= 90 ?
|
|
5996
|
+
const scoreColor = rec.score >= 90 ? chalk8.green : rec.score >= 70 ? chalk8.yellow : chalk8.dim;
|
|
6033
5997
|
const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
|
|
6034
|
-
lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${
|
|
5998
|
+
lines.push(` ${ptr} ${check} ${scoreColor(String(rec.score).padStart(3))} ${rec.name.padEnd(nameWidth)}${chalk8.dim(rec.reason.slice(0, reasonMax))}`);
|
|
6035
5999
|
} else {
|
|
6036
|
-
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
6000
|
+
lines.push(` ${ptr} ${check} ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`);
|
|
6037
6001
|
}
|
|
6038
6002
|
}
|
|
6039
6003
|
lines.push("");
|
|
6040
|
-
lines.push(
|
|
6004
|
+
lines.push(chalk8.dim(" \u2191\u2193 navigate \u23B5 toggle a all n none \u23CE install q cancel"));
|
|
6041
6005
|
return lines.join("\n");
|
|
6042
6006
|
}
|
|
6043
6007
|
function draw(initial) {
|
|
@@ -6086,7 +6050,7 @@ async function interactiveSelect(recs) {
|
|
|
6086
6050
|
case "\n":
|
|
6087
6051
|
cleanup();
|
|
6088
6052
|
if (selected.size === 0) {
|
|
6089
|
-
console.log(
|
|
6053
|
+
console.log(chalk8.dim("\n No skills selected.\n"));
|
|
6090
6054
|
resolve2(null);
|
|
6091
6055
|
} else {
|
|
6092
6056
|
resolve2(Array.from(selected).sort().map((i) => recs[i]));
|
|
@@ -6096,7 +6060,7 @@ async function interactiveSelect(recs) {
|
|
|
6096
6060
|
case "\x1B":
|
|
6097
6061
|
case "":
|
|
6098
6062
|
cleanup();
|
|
6099
|
-
console.log(
|
|
6063
|
+
console.log(chalk8.dim("\n Cancelled.\n"));
|
|
6100
6064
|
resolve2(null);
|
|
6101
6065
|
break;
|
|
6102
6066
|
}
|
|
@@ -6160,7 +6124,7 @@ async function installSkills(recs, platforms, contentMap) {
|
|
|
6160
6124
|
trackSkillsInstalled(installed.length);
|
|
6161
6125
|
spinner.succeed(`Installed ${installed.length} file${installed.length > 1 ? "s" : ""}`);
|
|
6162
6126
|
for (const p of installed) {
|
|
6163
|
-
console.log(
|
|
6127
|
+
console.log(chalk8.green(` \u2713 ${p}`));
|
|
6164
6128
|
}
|
|
6165
6129
|
} else {
|
|
6166
6130
|
spinner.fail("No skills were installed");
|
|
@@ -6173,19 +6137,19 @@ function printSkills(recs) {
|
|
|
6173
6137
|
const nameWidth = Math.max(...recs.map((r) => r.name.length), 4) + 2;
|
|
6174
6138
|
const scoreWidth = 6;
|
|
6175
6139
|
const prefixWidth = 2;
|
|
6176
|
-
console.log(
|
|
6140
|
+
console.log(chalk8.bold("\n Skills\n"));
|
|
6177
6141
|
if (hasScores) {
|
|
6178
|
-
console.log(" ".repeat(prefixWidth) +
|
|
6142
|
+
console.log(" ".repeat(prefixWidth) + chalk8.dim("Score".padEnd(scoreWidth)) + chalk8.dim("Name".padEnd(nameWidth)) + chalk8.dim("Why"));
|
|
6179
6143
|
} else {
|
|
6180
|
-
console.log(" ".repeat(prefixWidth) +
|
|
6144
|
+
console.log(" ".repeat(prefixWidth) + chalk8.dim("Name".padEnd(nameWidth)) + chalk8.dim("Technology".padEnd(18)) + chalk8.dim("Source"));
|
|
6181
6145
|
}
|
|
6182
|
-
console.log(
|
|
6146
|
+
console.log(chalk8.dim(" " + "\u2500".repeat(Math.min(cols - 4, 90))));
|
|
6183
6147
|
for (const rec of recs) {
|
|
6184
6148
|
if (hasScores) {
|
|
6185
6149
|
const reasonMax = Math.max(cols - prefixWidth - scoreWidth - nameWidth - 2, 20);
|
|
6186
|
-
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${
|
|
6150
|
+
console.log(` ${String(rec.score).padStart(3)} ${rec.name.padEnd(nameWidth)}${chalk8.dim(rec.reason.slice(0, reasonMax))}`);
|
|
6187
6151
|
} else {
|
|
6188
|
-
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${
|
|
6152
|
+
console.log(` ${rec.name.padEnd(nameWidth)}${rec.detected_technology.padEnd(16)} ${chalk8.dim(rec.source_url || "")}`);
|
|
6189
6153
|
}
|
|
6190
6154
|
}
|
|
6191
6155
|
console.log("");
|
|
@@ -6280,11 +6244,11 @@ function formatMs(ms) {
|
|
|
6280
6244
|
|
|
6281
6245
|
// src/commands/init.ts
|
|
6282
6246
|
function log(verbose, ...args) {
|
|
6283
|
-
if (verbose) console.log(
|
|
6247
|
+
if (verbose) console.log(chalk9.dim(` [verbose] ${args.map(String).join(" ")}`));
|
|
6284
6248
|
}
|
|
6285
6249
|
async function initCommand(options) {
|
|
6286
|
-
const brand =
|
|
6287
|
-
const title =
|
|
6250
|
+
const brand = chalk9.hex("#EB9D83");
|
|
6251
|
+
const title = chalk9.hex("#83D1EB");
|
|
6288
6252
|
console.log(brand.bold(`
|
|
6289
6253
|
\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557
|
|
6290
6254
|
\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557
|
|
@@ -6293,41 +6257,34 @@ async function initCommand(options) {
|
|
|
6293
6257
|
\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u2588\u2588\u2551
|
|
6294
6258
|
\u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D
|
|
6295
6259
|
`));
|
|
6296
|
-
console.log(
|
|
6297
|
-
console.log(
|
|
6298
|
-
console.log(chalk8.dim(" Caliber analyzes your codebase and creates tailored config files"));
|
|
6299
|
-
console.log(chalk8.dim(" so your AI coding agents understand your project from day one.\n"));
|
|
6260
|
+
console.log(chalk9.dim(" Scan your project and generate tailored config files for"));
|
|
6261
|
+
console.log(chalk9.dim(" Claude Code, Cursor, and Codex.\n"));
|
|
6300
6262
|
const report = options.debugReport ? new DebugReport() : null;
|
|
6301
6263
|
console.log(title.bold(" How it works:\n"));
|
|
6302
|
-
console.log(
|
|
6303
|
-
console.log(
|
|
6304
|
-
console.log(
|
|
6305
|
-
console.log(
|
|
6306
|
-
console.log(
|
|
6307
|
-
console.log(title.bold(" Step 1/5 \u2014 Connect
|
|
6264
|
+
console.log(chalk9.dim(" 1. Connect Choose your LLM provider"));
|
|
6265
|
+
console.log(chalk9.dim(" 2. Discover Scan code, dependencies, and existing configs"));
|
|
6266
|
+
console.log(chalk9.dim(" 3. Generate Build CLAUDE.md, rules, and skills for your codebase"));
|
|
6267
|
+
console.log(chalk9.dim(" 4. Review See a diff \u2014 accept, refine via chat, or decline"));
|
|
6268
|
+
console.log(chalk9.dim(" 5. Skills Search community registries and install skills\n"));
|
|
6269
|
+
console.log(title.bold(" Step 1/5 \u2014 Connect\n"));
|
|
6308
6270
|
let config = loadConfig();
|
|
6309
6271
|
if (!config) {
|
|
6310
|
-
console.log(
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
|
|
6314
|
-
});
|
|
6315
|
-
} catch (err) {
|
|
6316
|
-
if (err.message === "__exit__") throw err;
|
|
6317
|
-
throw err;
|
|
6318
|
-
}
|
|
6272
|
+
console.log(chalk9.dim(" No LLM provider set yet. Choose how to run Caliber:\n"));
|
|
6273
|
+
await runInteractiveProviderSetup({
|
|
6274
|
+
selectMessage: "How do you want to use Caliber? (choose LLM provider)"
|
|
6275
|
+
});
|
|
6319
6276
|
config = loadConfig();
|
|
6320
6277
|
if (!config) {
|
|
6321
|
-
console.log(
|
|
6278
|
+
console.log(chalk9.red(" Setup was cancelled or failed.\n"));
|
|
6322
6279
|
throw new Error("__exit__");
|
|
6323
6280
|
}
|
|
6324
|
-
console.log(
|
|
6281
|
+
console.log(chalk9.green(" \u2713 Provider saved. Let's continue.\n"));
|
|
6325
6282
|
}
|
|
6326
6283
|
trackInitProviderSelected(config.provider, config.model);
|
|
6327
|
-
const displayModel = config
|
|
6284
|
+
const displayModel = getDisplayModel(config);
|
|
6328
6285
|
const fastModel = getFastModel();
|
|
6329
6286
|
const modelLine = fastModel ? ` Provider: ${config.provider} | Model: ${displayModel} | Scan: ${fastModel}` : ` Provider: ${config.provider} | Model: ${displayModel}`;
|
|
6330
|
-
console.log(
|
|
6287
|
+
console.log(chalk9.dim(modelLine + "\n"));
|
|
6331
6288
|
if (report) {
|
|
6332
6289
|
report.markStep("Provider setup");
|
|
6333
6290
|
report.addSection("LLM Provider", `- **Provider**: ${config.provider}
|
|
@@ -6335,18 +6292,19 @@ async function initCommand(options) {
|
|
|
6335
6292
|
- **Fast model**: ${fastModel || "none"}`);
|
|
6336
6293
|
}
|
|
6337
6294
|
await validateModel({ fast: true });
|
|
6338
|
-
console.log(title.bold(" Step 2/5 \u2014 Discover
|
|
6339
|
-
|
|
6340
|
-
const spinner = ora2("Analyzing project...").start();
|
|
6295
|
+
console.log(title.bold(" Step 2/5 \u2014 Discover\n"));
|
|
6296
|
+
const spinner = ora2("Scanning code, dependencies, and existing configs...").start();
|
|
6341
6297
|
const fingerprint = await collectFingerprint(process.cwd());
|
|
6342
|
-
spinner.succeed("Project
|
|
6298
|
+
spinner.succeed("Project scanned");
|
|
6343
6299
|
log(options.verbose, `Fingerprint: ${fingerprint.languages.length} languages, ${fingerprint.frameworks.length} frameworks, ${fingerprint.fileTree.length} files`);
|
|
6344
6300
|
if (options.verbose && fingerprint.codeAnalysis) {
|
|
6345
6301
|
log(options.verbose, `Code analysis: ${fingerprint.codeAnalysis.filesIncluded}/${fingerprint.codeAnalysis.filesAnalyzed} files, ~${fingerprint.codeAnalysis.includedTokens.toLocaleString()} tokens, ${fingerprint.codeAnalysis.duplicateGroups} dedup groups`);
|
|
6346
6302
|
}
|
|
6347
6303
|
trackInitProjectDiscovered(fingerprint.languages.length, fingerprint.frameworks.length, fingerprint.fileTree.length);
|
|
6348
|
-
|
|
6349
|
-
|
|
6304
|
+
const langDisplay = fingerprint.languages.join(", ") || "none detected";
|
|
6305
|
+
const frameworkDisplay = fingerprint.frameworks.length > 0 ? ` (${fingerprint.frameworks.join(", ")})` : "";
|
|
6306
|
+
console.log(chalk9.dim(` Languages: ${langDisplay}${frameworkDisplay}`));
|
|
6307
|
+
console.log(chalk9.dim(` Files: ${fingerprint.fileTree.length} found
|
|
6350
6308
|
`));
|
|
6351
6309
|
if (report) {
|
|
6352
6310
|
report.markStep("Fingerprint");
|
|
@@ -6367,6 +6325,8 @@ async function initCommand(options) {
|
|
|
6367
6325
|
} else {
|
|
6368
6326
|
targetAgent = await promptAgent();
|
|
6369
6327
|
}
|
|
6328
|
+
console.log(chalk9.dim(` Target: ${targetAgent.join(", ")}
|
|
6329
|
+
`));
|
|
6370
6330
|
trackInitAgentSelected(targetAgent);
|
|
6371
6331
|
const preScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6372
6332
|
const failingForDismissal = preScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
@@ -6380,6 +6340,7 @@ async function initCommand(options) {
|
|
|
6380
6340
|
}
|
|
6381
6341
|
}
|
|
6382
6342
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6343
|
+
console.log(chalk9.dim(" Current setup score:"));
|
|
6383
6344
|
displayScoreSummary(baselineScore);
|
|
6384
6345
|
if (options.verbose) {
|
|
6385
6346
|
for (const c of baselineScore.checks) {
|
|
@@ -6408,29 +6369,29 @@ async function initCommand(options) {
|
|
|
6408
6369
|
]);
|
|
6409
6370
|
if (hasExistingConfig && baselineScore.score === 100) {
|
|
6410
6371
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, true);
|
|
6411
|
-
console.log(
|
|
6412
|
-
console.log(
|
|
6372
|
+
console.log(chalk9.bold.green(" Your setup is already optimal \u2014 nothing to change.\n"));
|
|
6373
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to regenerate anyway.\n"));
|
|
6413
6374
|
if (!options.force) return;
|
|
6414
6375
|
}
|
|
6415
6376
|
const allFailingChecks = baselineScore.checks.filter((c) => !c.passed && c.maxPoints > 0);
|
|
6416
6377
|
const llmFixableChecks = allFailingChecks.filter((c) => !NON_LLM_CHECKS.has(c.id));
|
|
6417
6378
|
trackInitScoreComputed(baselineScore.score, passingCount, failingCount, false);
|
|
6418
6379
|
if (hasExistingConfig && llmFixableChecks.length === 0 && allFailingChecks.length > 0 && !options.force) {
|
|
6419
|
-
console.log(
|
|
6420
|
-
console.log(
|
|
6380
|
+
console.log(chalk9.bold.green("\n Your config is fully optimized for LLM generation.\n"));
|
|
6381
|
+
console.log(chalk9.dim(" Remaining items need CLI actions:\n"));
|
|
6421
6382
|
for (const check of allFailingChecks) {
|
|
6422
|
-
console.log(
|
|
6383
|
+
console.log(chalk9.dim(` \u2022 ${check.name}`));
|
|
6423
6384
|
if (check.suggestion) {
|
|
6424
|
-
console.log(` ${
|
|
6385
|
+
console.log(` ${chalk9.hex("#83D1EB")(check.suggestion)}`);
|
|
6425
6386
|
}
|
|
6426
6387
|
}
|
|
6427
6388
|
console.log("");
|
|
6428
|
-
console.log(
|
|
6389
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to regenerate anyway.\n"));
|
|
6429
6390
|
return;
|
|
6430
6391
|
}
|
|
6431
6392
|
const isEmpty = fingerprint.fileTree.length < 3;
|
|
6432
6393
|
if (isEmpty) {
|
|
6433
|
-
fingerprint.description = await
|
|
6394
|
+
fingerprint.description = await promptInput("What will you build in this project?");
|
|
6434
6395
|
}
|
|
6435
6396
|
let failingChecks;
|
|
6436
6397
|
let passingChecks;
|
|
@@ -6440,23 +6401,24 @@ async function initCommand(options) {
|
|
|
6440
6401
|
passingChecks = baselineScore.checks.filter((c) => c.passed).map((c) => ({ name: c.name }));
|
|
6441
6402
|
currentScore = baselineScore.score;
|
|
6442
6403
|
if (failingChecks.length > 0) {
|
|
6443
|
-
console.log(title.bold(" Step 3/5 \u2014
|
|
6444
|
-
console.log(
|
|
6404
|
+
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6405
|
+
console.log(chalk9.dim(` Score is ${baselineScore.score}/100 \u2014 fine-tuning ${failingChecks.length} remaining issue${failingChecks.length === 1 ? "" : "s"}:
|
|
6445
6406
|
`));
|
|
6446
6407
|
for (const check of failingChecks) {
|
|
6447
|
-
console.log(
|
|
6408
|
+
console.log(chalk9.dim(` \u2022 ${check.name}`));
|
|
6448
6409
|
}
|
|
6449
6410
|
console.log("");
|
|
6450
6411
|
}
|
|
6451
6412
|
} else if (hasExistingConfig) {
|
|
6452
|
-
console.log(title.bold(" Step 3/5 \u2014
|
|
6453
|
-
console.log(
|
|
6454
|
-
console.log(chalk8.dim(" and preparing improvements.\n"));
|
|
6413
|
+
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6414
|
+
console.log(chalk9.dim(" Auditing your existing configs against your codebase and improving them.\n"));
|
|
6455
6415
|
} else {
|
|
6456
|
-
console.log(title.bold(" Step 3/5 \u2014
|
|
6457
|
-
console.log(
|
|
6416
|
+
console.log(title.bold(" Step 3/5 \u2014 Generate\n"));
|
|
6417
|
+
console.log(chalk9.dim(" Building CLAUDE.md, rules, and skills tailored to your project.\n"));
|
|
6458
6418
|
}
|
|
6459
|
-
|
|
6419
|
+
const genModelInfo = fastModel ? ` Using ${displayModel} for docs, ${fastModel} for skills` : ` Using ${displayModel}`;
|
|
6420
|
+
console.log(chalk9.dim(genModelInfo));
|
|
6421
|
+
console.log(chalk9.dim(" This can take a couple of minutes depending on your model and provider.\n"));
|
|
6460
6422
|
if (report) {
|
|
6461
6423
|
report.markStep("Generation");
|
|
6462
6424
|
const fullPrompt = buildGeneratePrompt(fingerprint, targetAgent, fingerprint.description, failingChecks, currentScore, passingChecks);
|
|
@@ -6508,8 +6470,8 @@ async function initCommand(options) {
|
|
|
6508
6470
|
genSpinner.fail("Failed to generate setup.");
|
|
6509
6471
|
writeErrorLog(config, rawOutput, void 0, genStopReason);
|
|
6510
6472
|
if (rawOutput) {
|
|
6511
|
-
console.log(
|
|
6512
|
-
console.log(
|
|
6473
|
+
console.log(chalk9.dim("\nRaw LLM output (JSON parse failed):"));
|
|
6474
|
+
console.log(chalk9.dim(rawOutput.slice(0, 500)));
|
|
6513
6475
|
}
|
|
6514
6476
|
throw new Error("__exit__");
|
|
6515
6477
|
}
|
|
@@ -6522,7 +6484,7 @@ async function initCommand(options) {
|
|
|
6522
6484
|
const mins = Math.floor(elapsedMs / 6e4);
|
|
6523
6485
|
const secs = Math.floor(elapsedMs % 6e4 / 1e3);
|
|
6524
6486
|
const timeStr = mins > 0 ? `${mins}m ${secs}s` : `${secs}s`;
|
|
6525
|
-
genSpinner.succeed(`Setup generated ${
|
|
6487
|
+
genSpinner.succeed(`Setup generated ${chalk9.dim(`in ${timeStr}`)}`);
|
|
6526
6488
|
log(options.verbose, `Generation completed: ${elapsedMs}ms, stopReason: ${genStopReason || "end_turn"}`);
|
|
6527
6489
|
printSetupSummary(generatedSetup);
|
|
6528
6490
|
const sessionHistory = [];
|
|
@@ -6530,15 +6492,15 @@ async function initCommand(options) {
|
|
|
6530
6492
|
role: "assistant",
|
|
6531
6493
|
content: summarizeSetup("Initial generation", generatedSetup)
|
|
6532
6494
|
});
|
|
6533
|
-
console.log(title.bold(" Step 4/5 \u2014 Review
|
|
6534
|
-
const setupFiles = collectSetupFiles(generatedSetup);
|
|
6495
|
+
console.log(title.bold(" Step 4/5 \u2014 Review\n"));
|
|
6496
|
+
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
6535
6497
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
6536
6498
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
6537
|
-
console.log(
|
|
6499
|
+
console.log(chalk9.dim(` ${chalk9.green(`${staged.newFiles} new`)} / ${chalk9.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
6538
6500
|
`));
|
|
6539
6501
|
let action;
|
|
6540
6502
|
if (totalChanges === 0) {
|
|
6541
|
-
console.log(
|
|
6503
|
+
console.log(chalk9.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
6542
6504
|
cleanupStaging();
|
|
6543
6505
|
action = "accept";
|
|
6544
6506
|
} else if (options.autoApprove) {
|
|
@@ -6561,12 +6523,12 @@ async function initCommand(options) {
|
|
|
6561
6523
|
trackInitRefinementRound(refinementRound, !!generatedSetup);
|
|
6562
6524
|
if (!generatedSetup) {
|
|
6563
6525
|
cleanupStaging();
|
|
6564
|
-
console.log(
|
|
6526
|
+
console.log(chalk9.dim("Refinement cancelled. No files were modified."));
|
|
6565
6527
|
return;
|
|
6566
6528
|
}
|
|
6567
|
-
const updatedFiles = collectSetupFiles(generatedSetup);
|
|
6529
|
+
const updatedFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
6568
6530
|
const restaged = stageFiles(updatedFiles, process.cwd());
|
|
6569
|
-
console.log(
|
|
6531
|
+
console.log(chalk9.dim(` ${chalk9.green(`${restaged.newFiles} new`)} / ${chalk9.yellow(`${restaged.modifiedFiles} modified`)} file${restaged.newFiles + restaged.modifiedFiles !== 1 ? "s" : ""}
|
|
6570
6532
|
`));
|
|
6571
6533
|
printSetupSummary(generatedSetup);
|
|
6572
6534
|
await openReview("terminal", restaged.stagedFiles);
|
|
@@ -6575,28 +6537,30 @@ async function initCommand(options) {
|
|
|
6575
6537
|
}
|
|
6576
6538
|
cleanupStaging();
|
|
6577
6539
|
if (action === "decline") {
|
|
6578
|
-
console.log(
|
|
6540
|
+
console.log(chalk9.dim("Setup declined. No files were modified."));
|
|
6579
6541
|
return;
|
|
6580
6542
|
}
|
|
6581
6543
|
if (options.dryRun) {
|
|
6582
|
-
console.log(
|
|
6544
|
+
console.log(chalk9.yellow("\n[Dry run] Would write the following files:"));
|
|
6583
6545
|
console.log(JSON.stringify(generatedSetup, null, 2));
|
|
6584
6546
|
return;
|
|
6585
6547
|
}
|
|
6586
6548
|
const writeSpinner = ora2("Writing config files...").start();
|
|
6587
6549
|
try {
|
|
6588
|
-
if (!fs24.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
6589
|
-
const
|
|
6590
|
-
const
|
|
6591
|
-
|
|
6592
|
-
|
|
6593
|
-
|
|
6594
|
-
|
|
6595
|
-
|
|
6596
|
-
|
|
6597
|
-
|
|
6598
|
-
|
|
6599
|
-
|
|
6550
|
+
if (targetAgent.includes("codex") && !fs24.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
6551
|
+
const claude = generatedSetup.claude;
|
|
6552
|
+
const cursor = generatedSetup.cursor;
|
|
6553
|
+
const agentRefs = [];
|
|
6554
|
+
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
6555
|
+
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
6556
|
+
if (agentRefs.length === 0) agentRefs.push("See CLAUDE.md and .cursor/rules/ for agent configurations.");
|
|
6557
|
+
const stubContent = `# AGENTS.md
|
|
6558
|
+
|
|
6559
|
+
This project uses AI coding agents configured by [Caliber](https://github.com/rely-ai-org/caliber).
|
|
6560
|
+
|
|
6561
|
+
${agentRefs.join(" ")}
|
|
6562
|
+
`;
|
|
6563
|
+
generatedSetup.codex = { agentsMd: stubContent };
|
|
6600
6564
|
}
|
|
6601
6565
|
const result = writeSetup(generatedSetup);
|
|
6602
6566
|
writeSpinner.succeed("Config files written");
|
|
@@ -6606,26 +6570,26 @@ async function initCommand(options) {
|
|
|
6606
6570
|
0,
|
|
6607
6571
|
result.deleted.length
|
|
6608
6572
|
);
|
|
6609
|
-
console.log(
|
|
6573
|
+
console.log(chalk9.bold("\nFiles created/updated:"));
|
|
6610
6574
|
for (const file of result.written) {
|
|
6611
|
-
console.log(` ${
|
|
6575
|
+
console.log(` ${chalk9.green("\u2713")} ${file}`);
|
|
6612
6576
|
}
|
|
6613
6577
|
if (result.deleted.length > 0) {
|
|
6614
|
-
console.log(
|
|
6578
|
+
console.log(chalk9.bold("\nFiles removed:"));
|
|
6615
6579
|
for (const file of result.deleted) {
|
|
6616
|
-
console.log(` ${
|
|
6580
|
+
console.log(` ${chalk9.red("\u2717")} ${file}`);
|
|
6617
6581
|
}
|
|
6618
6582
|
}
|
|
6619
6583
|
if (result.backupDir) {
|
|
6620
|
-
console.log(
|
|
6584
|
+
console.log(chalk9.dim(`
|
|
6621
6585
|
Backups saved to ${result.backupDir}`));
|
|
6622
6586
|
}
|
|
6623
6587
|
} catch (err) {
|
|
6624
6588
|
writeSpinner.fail("Failed to write files");
|
|
6625
|
-
console.error(
|
|
6589
|
+
console.error(chalk9.red(err instanceof Error ? err.message : "Unknown error"));
|
|
6626
6590
|
throw new Error("__exit__");
|
|
6627
6591
|
}
|
|
6628
|
-
ensurePermissions();
|
|
6592
|
+
ensurePermissions(fingerprint);
|
|
6629
6593
|
const sha = getCurrentHeadSha();
|
|
6630
6594
|
writeState({
|
|
6631
6595
|
lastRefreshSha: sha ?? "",
|
|
@@ -6633,8 +6597,7 @@ async function initCommand(options) {
|
|
|
6633
6597
|
targetAgent
|
|
6634
6598
|
});
|
|
6635
6599
|
console.log("");
|
|
6636
|
-
console.log(
|
|
6637
|
-
console.log(chalk8.dim(" Caliber can automatically update your agent configs when your code changes.\n"));
|
|
6600
|
+
console.log(chalk9.dim(" Auto-refresh: keep your configs in sync as your code changes.\n"));
|
|
6638
6601
|
let hookChoice;
|
|
6639
6602
|
if (options.autoApprove) {
|
|
6640
6603
|
hookChoice = "skip";
|
|
@@ -6646,46 +6609,46 @@ async function initCommand(options) {
|
|
|
6646
6609
|
if (hookChoice === "claude" || hookChoice === "both") {
|
|
6647
6610
|
const hookResult = installHook();
|
|
6648
6611
|
if (hookResult.installed) {
|
|
6649
|
-
console.log(` ${
|
|
6650
|
-
console.log(
|
|
6612
|
+
console.log(` ${chalk9.green("\u2713")} Claude Code hook installed \u2014 docs update on session end`);
|
|
6613
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
|
|
6651
6614
|
} else if (hookResult.alreadyInstalled) {
|
|
6652
|
-
console.log(
|
|
6615
|
+
console.log(chalk9.dim(" Claude Code hook already installed"));
|
|
6653
6616
|
}
|
|
6654
6617
|
const learnResult = installLearningHooks();
|
|
6655
6618
|
if (learnResult.installed) {
|
|
6656
|
-
console.log(` ${
|
|
6657
|
-
console.log(
|
|
6619
|
+
console.log(` ${chalk9.green("\u2713")} Learning hooks installed \u2014 session insights captured automatically`);
|
|
6620
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber learn remove") + chalk9.dim(" to disable"));
|
|
6658
6621
|
} else if (learnResult.alreadyInstalled) {
|
|
6659
|
-
console.log(
|
|
6622
|
+
console.log(chalk9.dim(" Learning hooks already installed"));
|
|
6660
6623
|
}
|
|
6661
6624
|
}
|
|
6662
6625
|
if (hookChoice === "precommit" || hookChoice === "both") {
|
|
6663
6626
|
const precommitResult = installPreCommitHook();
|
|
6664
6627
|
if (precommitResult.installed) {
|
|
6665
|
-
console.log(` ${
|
|
6666
|
-
console.log(
|
|
6628
|
+
console.log(` ${chalk9.green("\u2713")} Pre-commit hook installed \u2014 docs refresh before each commit`);
|
|
6629
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber hooks --remove") + chalk9.dim(" to disable"));
|
|
6667
6630
|
} else if (precommitResult.alreadyInstalled) {
|
|
6668
|
-
console.log(
|
|
6631
|
+
console.log(chalk9.dim(" Pre-commit hook already installed"));
|
|
6669
6632
|
} else {
|
|
6670
|
-
console.log(
|
|
6633
|
+
console.log(chalk9.yellow(" Could not install pre-commit hook (not a git repository?)"));
|
|
6671
6634
|
}
|
|
6672
6635
|
}
|
|
6673
6636
|
if (hookChoice === "skip") {
|
|
6674
|
-
console.log(
|
|
6637
|
+
console.log(chalk9.dim(" Skipped auto-refresh hooks. Run ") + chalk9.hex("#83D1EB")("caliber hooks --install") + chalk9.dim(" later to enable."));
|
|
6675
6638
|
}
|
|
6676
6639
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
6677
6640
|
if (afterScore.score < baselineScore.score) {
|
|
6678
6641
|
trackInitScoreRegression(baselineScore.score, afterScore.score);
|
|
6679
6642
|
console.log("");
|
|
6680
|
-
console.log(
|
|
6643
|
+
console.log(chalk9.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
6681
6644
|
try {
|
|
6682
6645
|
const { restored, removed } = undoSetup();
|
|
6683
6646
|
if (restored.length > 0 || removed.length > 0) {
|
|
6684
|
-
console.log(
|
|
6647
|
+
console.log(chalk9.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
6685
6648
|
}
|
|
6686
6649
|
} catch {
|
|
6687
6650
|
}
|
|
6688
|
-
console.log(
|
|
6651
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber init --force") + chalk9.dim(" to override.\n"));
|
|
6689
6652
|
return;
|
|
6690
6653
|
}
|
|
6691
6654
|
if (report) {
|
|
@@ -6703,8 +6666,8 @@ async function initCommand(options) {
|
|
|
6703
6666
|
log(options.verbose, ` Still failing: ${c.name} (${c.earnedPoints}/${c.maxPoints})${c.suggestion ? ` \u2014 ${c.suggestion}` : ""}`);
|
|
6704
6667
|
}
|
|
6705
6668
|
}
|
|
6706
|
-
console.log(title.bold("\n Step 5/5 \u2014
|
|
6707
|
-
console.log(
|
|
6669
|
+
console.log(title.bold("\n Step 5/5 \u2014 Skills\n"));
|
|
6670
|
+
console.log(chalk9.dim(" Search community registries for skills that match your tech stack.\n"));
|
|
6708
6671
|
let wantsSkills;
|
|
6709
6672
|
if (options.autoApprove) {
|
|
6710
6673
|
wantsSkills = false;
|
|
@@ -6724,19 +6687,22 @@ async function initCommand(options) {
|
|
|
6724
6687
|
await searchAndInstallSkills();
|
|
6725
6688
|
} catch (err) {
|
|
6726
6689
|
if (err.message !== "__exit__") {
|
|
6727
|
-
console.log(
|
|
6690
|
+
console.log(chalk9.dim(" Skills search failed: " + (err.message || "unknown error")));
|
|
6728
6691
|
}
|
|
6729
|
-
console.log(
|
|
6692
|
+
console.log(chalk9.dim(" Run ") + chalk9.hex("#83D1EB")("caliber skills") + chalk9.dim(" later to try again.\n"));
|
|
6730
6693
|
}
|
|
6731
6694
|
} else {
|
|
6732
6695
|
trackInitSkillsSearch(false, 0);
|
|
6733
|
-
console.log(
|
|
6696
|
+
console.log(chalk9.dim(" Skipped. Run ") + chalk9.hex("#83D1EB")("caliber skills") + chalk9.dim(" later to browse.\n"));
|
|
6734
6697
|
}
|
|
6735
|
-
console.log(
|
|
6736
|
-
console.log(
|
|
6737
|
-
console.log(
|
|
6698
|
+
console.log(chalk9.bold.green(" Setup complete!"));
|
|
6699
|
+
console.log(chalk9.dim(" Your AI agents now understand your project's architecture, build commands,"));
|
|
6700
|
+
console.log(chalk9.dim(" testing patterns, and conventions. All changes are backed up automatically.\n"));
|
|
6701
|
+
console.log(chalk9.bold(" Next steps:\n"));
|
|
6738
6702
|
console.log(` ${title("caliber score")} See your full config breakdown`);
|
|
6739
|
-
console.log(` ${title("caliber
|
|
6703
|
+
console.log(` ${title("caliber refresh")} Update docs after code changes`);
|
|
6704
|
+
console.log(` ${title("caliber hooks")} Toggle auto-refresh hooks`);
|
|
6705
|
+
console.log(` ${title("caliber skills")} Discover community skills for your stack`);
|
|
6740
6706
|
console.log(` ${title("caliber undo")} Revert all changes from this run`);
|
|
6741
6707
|
console.log("");
|
|
6742
6708
|
if (options.showTokens) {
|
|
@@ -6746,13 +6712,13 @@ async function initCommand(options) {
|
|
|
6746
6712
|
report.markStep("Finished");
|
|
6747
6713
|
const reportPath = path19.join(process.cwd(), ".caliber", "debug-report.md");
|
|
6748
6714
|
report.write(reportPath);
|
|
6749
|
-
console.log(
|
|
6715
|
+
console.log(chalk9.dim(` Debug report written to ${path19.relative(process.cwd(), reportPath)}
|
|
6750
6716
|
`));
|
|
6751
6717
|
}
|
|
6752
6718
|
}
|
|
6753
6719
|
async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
6754
6720
|
while (true) {
|
|
6755
|
-
const message = await
|
|
6721
|
+
const message = await promptInput("\nWhat would you like to change?");
|
|
6756
6722
|
if (!message || message.toLowerCase() === "done" || message.toLowerCase() === "accept") {
|
|
6757
6723
|
return currentSetup;
|
|
6758
6724
|
}
|
|
@@ -6761,9 +6727,9 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
6761
6727
|
}
|
|
6762
6728
|
const isValid = await classifyRefineIntent(message);
|
|
6763
6729
|
if (!isValid) {
|
|
6764
|
-
console.log(
|
|
6765
|
-
console.log(
|
|
6766
|
-
console.log(
|
|
6730
|
+
console.log(chalk9.dim(" This doesn't look like a config change request."));
|
|
6731
|
+
console.log(chalk9.dim(" Describe what to add, remove, or modify in your configs."));
|
|
6732
|
+
console.log(chalk9.dim(' Type "done" to accept the current setup.\n'));
|
|
6767
6733
|
continue;
|
|
6768
6734
|
}
|
|
6769
6735
|
const refineSpinner = ora2("Refining setup...").start();
|
|
@@ -6784,10 +6750,10 @@ async function refineLoop(currentSetup, _targetAgent, sessionHistory) {
|
|
|
6784
6750
|
});
|
|
6785
6751
|
refineSpinner.succeed("Setup updated");
|
|
6786
6752
|
printSetupSummary(refined);
|
|
6787
|
-
console.log(
|
|
6753
|
+
console.log(chalk9.dim('Type "done" to accept, or describe more changes.'));
|
|
6788
6754
|
} else {
|
|
6789
6755
|
refineSpinner.fail("Refinement failed \u2014 could not parse AI response.");
|
|
6790
|
-
console.log(
|
|
6756
|
+
console.log(chalk9.dim('Try rephrasing your request, or type "done" to keep the current setup.'));
|
|
6791
6757
|
}
|
|
6792
6758
|
}
|
|
6793
6759
|
}
|
|
@@ -6855,15 +6821,6 @@ ${JSON.stringify(checkList, null, 2)}`,
|
|
|
6855
6821
|
return [];
|
|
6856
6822
|
}
|
|
6857
6823
|
}
|
|
6858
|
-
function promptInput2(question) {
|
|
6859
|
-
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
6860
|
-
return new Promise((resolve2) => {
|
|
6861
|
-
rl.question(chalk8.cyan(`${question} `), (answer) => {
|
|
6862
|
-
rl.close();
|
|
6863
|
-
resolve2(answer.trim());
|
|
6864
|
-
});
|
|
6865
|
-
});
|
|
6866
|
-
}
|
|
6867
6824
|
async function promptAgent() {
|
|
6868
6825
|
const selected = await checkbox({
|
|
6869
6826
|
message: "Which coding agents do you use? (toggle with space)",
|
|
@@ -6911,26 +6868,26 @@ function printSetupSummary(setup) {
|
|
|
6911
6868
|
const fileDescriptions = setup.fileDescriptions;
|
|
6912
6869
|
const deletions = setup.deletions;
|
|
6913
6870
|
console.log("");
|
|
6914
|
-
console.log(
|
|
6871
|
+
console.log(chalk9.bold(" Proposed changes:\n"));
|
|
6915
6872
|
const getDescription = (filePath) => {
|
|
6916
6873
|
return fileDescriptions?.[filePath];
|
|
6917
6874
|
};
|
|
6918
6875
|
if (claude) {
|
|
6919
6876
|
if (claude.claudeMd) {
|
|
6920
|
-
const icon = fs24.existsSync("CLAUDE.md") ?
|
|
6877
|
+
const icon = fs24.existsSync("CLAUDE.md") ? chalk9.yellow("~") : chalk9.green("+");
|
|
6921
6878
|
const desc = getDescription("CLAUDE.md");
|
|
6922
|
-
console.log(` ${icon} ${
|
|
6923
|
-
if (desc) console.log(
|
|
6879
|
+
console.log(` ${icon} ${chalk9.bold("CLAUDE.md")}`);
|
|
6880
|
+
if (desc) console.log(chalk9.dim(` ${desc}`));
|
|
6924
6881
|
console.log("");
|
|
6925
6882
|
}
|
|
6926
6883
|
const skills = claude.skills;
|
|
6927
6884
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
6928
6885
|
for (const skill of skills) {
|
|
6929
6886
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
6930
|
-
const icon = fs24.existsSync(skillPath) ?
|
|
6887
|
+
const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
|
|
6931
6888
|
const desc = getDescription(skillPath);
|
|
6932
|
-
console.log(` ${icon} ${
|
|
6933
|
-
console.log(
|
|
6889
|
+
console.log(` ${icon} ${chalk9.bold(skillPath)}`);
|
|
6890
|
+
console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
|
|
6934
6891
|
console.log("");
|
|
6935
6892
|
}
|
|
6936
6893
|
}
|
|
@@ -6938,40 +6895,40 @@ function printSetupSummary(setup) {
|
|
|
6938
6895
|
const codex = setup.codex;
|
|
6939
6896
|
if (codex) {
|
|
6940
6897
|
if (codex.agentsMd) {
|
|
6941
|
-
const icon = fs24.existsSync("AGENTS.md") ?
|
|
6898
|
+
const icon = fs24.existsSync("AGENTS.md") ? chalk9.yellow("~") : chalk9.green("+");
|
|
6942
6899
|
const desc = getDescription("AGENTS.md");
|
|
6943
|
-
console.log(` ${icon} ${
|
|
6944
|
-
if (desc) console.log(
|
|
6900
|
+
console.log(` ${icon} ${chalk9.bold("AGENTS.md")}`);
|
|
6901
|
+
if (desc) console.log(chalk9.dim(` ${desc}`));
|
|
6945
6902
|
console.log("");
|
|
6946
6903
|
}
|
|
6947
6904
|
const codexSkills = codex.skills;
|
|
6948
6905
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
6949
6906
|
for (const skill of codexSkills) {
|
|
6950
6907
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
6951
|
-
const icon = fs24.existsSync(skillPath) ?
|
|
6908
|
+
const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
|
|
6952
6909
|
const desc = getDescription(skillPath);
|
|
6953
|
-
console.log(` ${icon} ${
|
|
6954
|
-
console.log(
|
|
6910
|
+
console.log(` ${icon} ${chalk9.bold(skillPath)}`);
|
|
6911
|
+
console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
|
|
6955
6912
|
console.log("");
|
|
6956
6913
|
}
|
|
6957
6914
|
}
|
|
6958
6915
|
}
|
|
6959
6916
|
if (cursor) {
|
|
6960
6917
|
if (cursor.cursorrules) {
|
|
6961
|
-
const icon = fs24.existsSync(".cursorrules") ?
|
|
6918
|
+
const icon = fs24.existsSync(".cursorrules") ? chalk9.yellow("~") : chalk9.green("+");
|
|
6962
6919
|
const desc = getDescription(".cursorrules");
|
|
6963
|
-
console.log(` ${icon} ${
|
|
6964
|
-
if (desc) console.log(
|
|
6920
|
+
console.log(` ${icon} ${chalk9.bold(".cursorrules")}`);
|
|
6921
|
+
if (desc) console.log(chalk9.dim(` ${desc}`));
|
|
6965
6922
|
console.log("");
|
|
6966
6923
|
}
|
|
6967
6924
|
const cursorSkills = cursor.skills;
|
|
6968
6925
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
6969
6926
|
for (const skill of cursorSkills) {
|
|
6970
6927
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
6971
|
-
const icon = fs24.existsSync(skillPath) ?
|
|
6928
|
+
const icon = fs24.existsSync(skillPath) ? chalk9.yellow("~") : chalk9.green("+");
|
|
6972
6929
|
const desc = getDescription(skillPath);
|
|
6973
|
-
console.log(` ${icon} ${
|
|
6974
|
-
console.log(
|
|
6930
|
+
console.log(` ${icon} ${chalk9.bold(skillPath)}`);
|
|
6931
|
+
console.log(chalk9.dim(` ${desc || skill.description || skill.name}`));
|
|
6975
6932
|
console.log("");
|
|
6976
6933
|
}
|
|
6977
6934
|
}
|
|
@@ -6979,35 +6936,67 @@ function printSetupSummary(setup) {
|
|
|
6979
6936
|
if (Array.isArray(rules) && rules.length > 0) {
|
|
6980
6937
|
for (const rule of rules) {
|
|
6981
6938
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
6982
|
-
const icon = fs24.existsSync(rulePath) ?
|
|
6939
|
+
const icon = fs24.existsSync(rulePath) ? chalk9.yellow("~") : chalk9.green("+");
|
|
6983
6940
|
const desc = getDescription(rulePath);
|
|
6984
|
-
console.log(` ${icon} ${
|
|
6941
|
+
console.log(` ${icon} ${chalk9.bold(rulePath)}`);
|
|
6985
6942
|
if (desc) {
|
|
6986
|
-
console.log(
|
|
6943
|
+
console.log(chalk9.dim(` ${desc}`));
|
|
6987
6944
|
} else {
|
|
6988
6945
|
const firstLine = rule.content.split("\n").filter((l) => l.trim() && !l.trim().startsWith("#"))[0];
|
|
6989
|
-
if (firstLine) console.log(
|
|
6946
|
+
if (firstLine) console.log(chalk9.dim(` ${firstLine.trim().slice(0, 80)}`));
|
|
6990
6947
|
}
|
|
6991
6948
|
console.log("");
|
|
6992
6949
|
}
|
|
6993
6950
|
}
|
|
6994
6951
|
}
|
|
6995
|
-
if (!codex && !fs24.existsSync("AGENTS.md")) {
|
|
6996
|
-
console.log(` ${chalk8.green("+")} ${chalk8.bold("AGENTS.md")}`);
|
|
6997
|
-
console.log(chalk8.dim(" Cross-agent coordination file"));
|
|
6998
|
-
console.log("");
|
|
6999
|
-
}
|
|
7000
6952
|
if (Array.isArray(deletions) && deletions.length > 0) {
|
|
7001
6953
|
for (const del of deletions) {
|
|
7002
|
-
console.log(` ${
|
|
7003
|
-
console.log(
|
|
6954
|
+
console.log(` ${chalk9.red("-")} ${chalk9.bold(del.filePath)}`);
|
|
6955
|
+
console.log(chalk9.dim(` ${del.reason}`));
|
|
7004
6956
|
console.log("");
|
|
7005
6957
|
}
|
|
7006
6958
|
}
|
|
7007
|
-
console.log(` ${
|
|
6959
|
+
console.log(` ${chalk9.green("+")} ${chalk9.dim("new")} ${chalk9.yellow("~")} ${chalk9.dim("modified")} ${chalk9.red("-")} ${chalk9.dim("removed")}`);
|
|
7008
6960
|
console.log("");
|
|
7009
6961
|
}
|
|
7010
|
-
function
|
|
6962
|
+
function derivePermissions(fingerprint) {
|
|
6963
|
+
const perms = ["Bash(git *)"];
|
|
6964
|
+
const langs = new Set(fingerprint.languages.map((l) => l.toLowerCase()));
|
|
6965
|
+
const tools = new Set(fingerprint.tools.map((t) => t.toLowerCase()));
|
|
6966
|
+
const hasFile = (name) => fingerprint.fileTree.some((f) => f === name || f === `./${name}`);
|
|
6967
|
+
if (langs.has("typescript") || langs.has("javascript") || hasFile("package.json")) {
|
|
6968
|
+
perms.push("Bash(npm run *)", "Bash(npx *)");
|
|
6969
|
+
}
|
|
6970
|
+
if (langs.has("python") || hasFile("pyproject.toml") || hasFile("requirements.txt")) {
|
|
6971
|
+
perms.push("Bash(python *)", "Bash(pip *)", "Bash(pytest *)");
|
|
6972
|
+
}
|
|
6973
|
+
if (langs.has("go") || hasFile("go.mod")) {
|
|
6974
|
+
perms.push("Bash(go *)");
|
|
6975
|
+
}
|
|
6976
|
+
if (langs.has("rust") || hasFile("Cargo.toml")) {
|
|
6977
|
+
perms.push("Bash(cargo *)");
|
|
6978
|
+
}
|
|
6979
|
+
if (langs.has("java") || langs.has("kotlin")) {
|
|
6980
|
+
if (hasFile("gradlew")) perms.push("Bash(./gradlew *)");
|
|
6981
|
+
if (hasFile("mvnw")) perms.push("Bash(./mvnw *)");
|
|
6982
|
+
if (hasFile("pom.xml")) perms.push("Bash(mvn *)");
|
|
6983
|
+
if (hasFile("build.gradle") || hasFile("build.gradle.kts")) perms.push("Bash(gradle *)");
|
|
6984
|
+
}
|
|
6985
|
+
if (langs.has("ruby") || hasFile("Gemfile")) {
|
|
6986
|
+
perms.push("Bash(bundle *)", "Bash(rake *)");
|
|
6987
|
+
}
|
|
6988
|
+
if (tools.has("terraform") || hasFile("main.tf")) {
|
|
6989
|
+
perms.push("Bash(terraform *)");
|
|
6990
|
+
}
|
|
6991
|
+
if (tools.has("docker") || hasFile("Dockerfile") || hasFile("docker-compose.yml")) {
|
|
6992
|
+
perms.push("Bash(docker *)");
|
|
6993
|
+
}
|
|
6994
|
+
if (hasFile("Makefile")) {
|
|
6995
|
+
perms.push("Bash(make *)");
|
|
6996
|
+
}
|
|
6997
|
+
return [...new Set(perms)];
|
|
6998
|
+
}
|
|
6999
|
+
function ensurePermissions(fingerprint) {
|
|
7011
7000
|
const settingsPath = ".claude/settings.json";
|
|
7012
7001
|
let settings = {};
|
|
7013
7002
|
try {
|
|
@@ -7019,12 +7008,7 @@ function ensurePermissions() {
|
|
|
7019
7008
|
const permissions = settings.permissions ?? {};
|
|
7020
7009
|
const allow = permissions.allow;
|
|
7021
7010
|
if (Array.isArray(allow) && allow.length > 0) return;
|
|
7022
|
-
permissions.allow =
|
|
7023
|
-
"Bash(npm run *)",
|
|
7024
|
-
"Bash(npx vitest *)",
|
|
7025
|
-
"Bash(npx tsc *)",
|
|
7026
|
-
"Bash(git *)"
|
|
7027
|
-
];
|
|
7011
|
+
permissions.allow = derivePermissions(fingerprint);
|
|
7028
7012
|
settings.permissions = permissions;
|
|
7029
7013
|
if (!fs24.existsSync(".claude")) fs24.mkdirSync(".claude", { recursive: true });
|
|
7030
7014
|
fs24.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
@@ -7032,20 +7016,20 @@ function ensurePermissions() {
|
|
|
7032
7016
|
function displayTokenUsage() {
|
|
7033
7017
|
const summary = getUsageSummary();
|
|
7034
7018
|
if (summary.length === 0) {
|
|
7035
|
-
console.log(
|
|
7019
|
+
console.log(chalk9.dim(" Token tracking not available for this provider.\n"));
|
|
7036
7020
|
return;
|
|
7037
7021
|
}
|
|
7038
|
-
console.log(
|
|
7022
|
+
console.log(chalk9.bold(" Token usage:\n"));
|
|
7039
7023
|
let totalIn = 0;
|
|
7040
7024
|
let totalOut = 0;
|
|
7041
7025
|
for (const m of summary) {
|
|
7042
7026
|
totalIn += m.inputTokens;
|
|
7043
7027
|
totalOut += m.outputTokens;
|
|
7044
|
-
const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ?
|
|
7045
|
-
console.log(` ${
|
|
7028
|
+
const cacheInfo = m.cacheReadTokens > 0 || m.cacheWriteTokens > 0 ? chalk9.dim(` (cache: ${m.cacheReadTokens.toLocaleString()} read, ${m.cacheWriteTokens.toLocaleString()} write)`) : "";
|
|
7029
|
+
console.log(` ${chalk9.dim(m.model)}: ${m.inputTokens.toLocaleString()} in / ${m.outputTokens.toLocaleString()} out (${m.calls} call${m.calls === 1 ? "" : "s"})${cacheInfo}`);
|
|
7046
7030
|
}
|
|
7047
7031
|
if (summary.length > 1) {
|
|
7048
|
-
console.log(` ${
|
|
7032
|
+
console.log(` ${chalk9.dim("Total")}: ${totalIn.toLocaleString()} in / ${totalOut.toLocaleString()} out`);
|
|
7049
7033
|
}
|
|
7050
7034
|
console.log("");
|
|
7051
7035
|
}
|
|
@@ -7066,14 +7050,14 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
|
7066
7050
|
lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
|
|
7067
7051
|
fs24.mkdirSync(path19.join(process.cwd(), ".caliber"), { recursive: true });
|
|
7068
7052
|
fs24.writeFileSync(logPath, lines.join("\n"));
|
|
7069
|
-
console.log(
|
|
7053
|
+
console.log(chalk9.dim(`
|
|
7070
7054
|
Error log written to .caliber/error-log.md`));
|
|
7071
7055
|
} catch {
|
|
7072
7056
|
}
|
|
7073
7057
|
}
|
|
7074
7058
|
|
|
7075
7059
|
// src/commands/undo.ts
|
|
7076
|
-
import
|
|
7060
|
+
import chalk10 from "chalk";
|
|
7077
7061
|
import ora3 from "ora";
|
|
7078
7062
|
function undoCommand() {
|
|
7079
7063
|
const spinner = ora3("Reverting setup...").start();
|
|
@@ -7086,26 +7070,26 @@ function undoCommand() {
|
|
|
7086
7070
|
trackUndoExecuted();
|
|
7087
7071
|
spinner.succeed("Setup reverted successfully.\n");
|
|
7088
7072
|
if (restored.length > 0) {
|
|
7089
|
-
console.log(
|
|
7073
|
+
console.log(chalk10.cyan(" Restored from backup:"));
|
|
7090
7074
|
for (const file of restored) {
|
|
7091
|
-
console.log(` ${
|
|
7075
|
+
console.log(` ${chalk10.green("\u21A9")} ${file}`);
|
|
7092
7076
|
}
|
|
7093
7077
|
}
|
|
7094
7078
|
if (removed.length > 0) {
|
|
7095
|
-
console.log(
|
|
7079
|
+
console.log(chalk10.cyan(" Removed:"));
|
|
7096
7080
|
for (const file of removed) {
|
|
7097
|
-
console.log(` ${
|
|
7081
|
+
console.log(` ${chalk10.red("\u2717")} ${file}`);
|
|
7098
7082
|
}
|
|
7099
7083
|
}
|
|
7100
7084
|
console.log("");
|
|
7101
7085
|
} catch (err) {
|
|
7102
|
-
spinner.fail(
|
|
7086
|
+
spinner.fail(chalk10.red(err instanceof Error ? err.message : "Undo failed"));
|
|
7103
7087
|
throw new Error("__exit__");
|
|
7104
7088
|
}
|
|
7105
7089
|
}
|
|
7106
7090
|
|
|
7107
7091
|
// src/commands/status.ts
|
|
7108
|
-
import
|
|
7092
|
+
import chalk11 from "chalk";
|
|
7109
7093
|
import fs25 from "fs";
|
|
7110
7094
|
init_config();
|
|
7111
7095
|
async function statusCommand(options) {
|
|
@@ -7120,40 +7104,40 @@ async function statusCommand(options) {
|
|
|
7120
7104
|
}, null, 2));
|
|
7121
7105
|
return;
|
|
7122
7106
|
}
|
|
7123
|
-
console.log(
|
|
7107
|
+
console.log(chalk11.bold("\nCaliber Status\n"));
|
|
7124
7108
|
if (config) {
|
|
7125
|
-
console.log(` LLM: ${
|
|
7109
|
+
console.log(` LLM: ${chalk11.green(config.provider)} (${config.model})`);
|
|
7126
7110
|
} else {
|
|
7127
|
-
console.log(` LLM: ${
|
|
7111
|
+
console.log(` LLM: ${chalk11.yellow("Not configured")} \u2014 run ${chalk11.hex("#83D1EB")("caliber config")}`);
|
|
7128
7112
|
}
|
|
7129
7113
|
if (!manifest) {
|
|
7130
|
-
console.log(` Setup: ${
|
|
7131
|
-
console.log(
|
|
7114
|
+
console.log(` Setup: ${chalk11.dim("No setup applied")}`);
|
|
7115
|
+
console.log(chalk11.dim("\n Run ") + chalk11.hex("#83D1EB")("caliber init") + chalk11.dim(" to get started.\n"));
|
|
7132
7116
|
return;
|
|
7133
7117
|
}
|
|
7134
|
-
console.log(` Files managed: ${
|
|
7118
|
+
console.log(` Files managed: ${chalk11.cyan(manifest.entries.length.toString())}`);
|
|
7135
7119
|
for (const entry of manifest.entries) {
|
|
7136
7120
|
const exists = fs25.existsSync(entry.path);
|
|
7137
|
-
const icon = exists ?
|
|
7121
|
+
const icon = exists ? chalk11.green("\u2713") : chalk11.red("\u2717");
|
|
7138
7122
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
7139
7123
|
}
|
|
7140
7124
|
console.log("");
|
|
7141
7125
|
}
|
|
7142
7126
|
|
|
7143
7127
|
// src/commands/regenerate.ts
|
|
7144
|
-
import
|
|
7128
|
+
import chalk12 from "chalk";
|
|
7145
7129
|
import ora4 from "ora";
|
|
7146
7130
|
import select6 from "@inquirer/select";
|
|
7147
7131
|
init_config();
|
|
7148
7132
|
async function regenerateCommand(options) {
|
|
7149
7133
|
const config = loadConfig();
|
|
7150
7134
|
if (!config) {
|
|
7151
|
-
console.log(
|
|
7135
|
+
console.log(chalk12.red("No LLM provider configured. Run ") + chalk12.hex("#83D1EB")("caliber config") + chalk12.red(" first."));
|
|
7152
7136
|
throw new Error("__exit__");
|
|
7153
7137
|
}
|
|
7154
7138
|
const manifest = readManifest();
|
|
7155
7139
|
if (!manifest) {
|
|
7156
|
-
console.log(
|
|
7140
|
+
console.log(chalk12.yellow("No existing setup found. Run ") + chalk12.hex("#83D1EB")("caliber init") + chalk12.yellow(" first."));
|
|
7157
7141
|
throw new Error("__exit__");
|
|
7158
7142
|
}
|
|
7159
7143
|
const targetAgent = readState()?.targetAgent ?? ["claude", "cursor"];
|
|
@@ -7164,7 +7148,7 @@ async function regenerateCommand(options) {
|
|
|
7164
7148
|
const baselineScore = computeLocalScore(process.cwd(), targetAgent);
|
|
7165
7149
|
displayScoreSummary(baselineScore);
|
|
7166
7150
|
if (baselineScore.score === 100) {
|
|
7167
|
-
console.log(
|
|
7151
|
+
console.log(chalk12.green(" Your setup is already at 100/100 \u2014 nothing to regenerate.\n"));
|
|
7168
7152
|
return;
|
|
7169
7153
|
}
|
|
7170
7154
|
const genSpinner = ora4("Regenerating setup...").start();
|
|
@@ -7202,21 +7186,21 @@ async function regenerateCommand(options) {
|
|
|
7202
7186
|
throw new Error("__exit__");
|
|
7203
7187
|
}
|
|
7204
7188
|
genSpinner.succeed("Setup regenerated");
|
|
7205
|
-
const setupFiles = collectSetupFiles(generatedSetup);
|
|
7189
|
+
const setupFiles = collectSetupFiles(generatedSetup, targetAgent);
|
|
7206
7190
|
const staged = stageFiles(setupFiles, process.cwd());
|
|
7207
7191
|
const totalChanges = staged.newFiles + staged.modifiedFiles;
|
|
7208
|
-
console.log(
|
|
7209
|
-
${
|
|
7192
|
+
console.log(chalk12.dim(`
|
|
7193
|
+
${chalk12.green(`${staged.newFiles} new`)} / ${chalk12.yellow(`${staged.modifiedFiles} modified`)} file${totalChanges !== 1 ? "s" : ""}
|
|
7210
7194
|
`));
|
|
7211
7195
|
if (totalChanges === 0) {
|
|
7212
|
-
console.log(
|
|
7196
|
+
console.log(chalk12.dim(" No changes needed \u2014 your configs are already up to date.\n"));
|
|
7213
7197
|
cleanupStaging();
|
|
7214
7198
|
return;
|
|
7215
7199
|
}
|
|
7216
7200
|
if (options.dryRun) {
|
|
7217
|
-
console.log(
|
|
7201
|
+
console.log(chalk12.yellow("[Dry run] Would write:"));
|
|
7218
7202
|
for (const f of staged.stagedFiles) {
|
|
7219
|
-
console.log(` ${f.isNew ?
|
|
7203
|
+
console.log(` ${f.isNew ? chalk12.green("+") : chalk12.yellow("~")} ${f.relativePath}`);
|
|
7220
7204
|
}
|
|
7221
7205
|
cleanupStaging();
|
|
7222
7206
|
return;
|
|
@@ -7235,7 +7219,7 @@ async function regenerateCommand(options) {
|
|
|
7235
7219
|
});
|
|
7236
7220
|
cleanupStaging();
|
|
7237
7221
|
if (action === "decline") {
|
|
7238
|
-
console.log(
|
|
7222
|
+
console.log(chalk12.dim("Regeneration cancelled. No files were modified."));
|
|
7239
7223
|
return;
|
|
7240
7224
|
}
|
|
7241
7225
|
const writeSpinner = ora4("Writing config files...").start();
|
|
@@ -7243,20 +7227,20 @@ async function regenerateCommand(options) {
|
|
|
7243
7227
|
const result = writeSetup(generatedSetup);
|
|
7244
7228
|
writeSpinner.succeed("Config files written");
|
|
7245
7229
|
for (const file of result.written) {
|
|
7246
|
-
console.log(` ${
|
|
7230
|
+
console.log(` ${chalk12.green("\u2713")} ${file}`);
|
|
7247
7231
|
}
|
|
7248
7232
|
if (result.deleted.length > 0) {
|
|
7249
7233
|
for (const file of result.deleted) {
|
|
7250
|
-
console.log(` ${
|
|
7234
|
+
console.log(` ${chalk12.red("\u2717")} ${file}`);
|
|
7251
7235
|
}
|
|
7252
7236
|
}
|
|
7253
7237
|
if (result.backupDir) {
|
|
7254
|
-
console.log(
|
|
7238
|
+
console.log(chalk12.dim(`
|
|
7255
7239
|
Backups saved to ${result.backupDir}`));
|
|
7256
7240
|
}
|
|
7257
7241
|
} catch (err) {
|
|
7258
7242
|
writeSpinner.fail("Failed to write files");
|
|
7259
|
-
console.error(
|
|
7243
|
+
console.error(chalk12.red(err instanceof Error ? err.message : "Unknown error"));
|
|
7260
7244
|
throw new Error("__exit__");
|
|
7261
7245
|
}
|
|
7262
7246
|
const sha = getCurrentHeadSha();
|
|
@@ -7268,25 +7252,25 @@ async function regenerateCommand(options) {
|
|
|
7268
7252
|
const afterScore = computeLocalScore(process.cwd(), targetAgent);
|
|
7269
7253
|
if (afterScore.score < baselineScore.score) {
|
|
7270
7254
|
console.log("");
|
|
7271
|
-
console.log(
|
|
7255
|
+
console.log(chalk12.yellow(` Score would drop from ${baselineScore.score} to ${afterScore.score} \u2014 reverting changes.`));
|
|
7272
7256
|
try {
|
|
7273
7257
|
const { restored, removed } = undoSetup();
|
|
7274
7258
|
if (restored.length > 0 || removed.length > 0) {
|
|
7275
|
-
console.log(
|
|
7259
|
+
console.log(chalk12.dim(` Reverted ${restored.length + removed.length} file${restored.length + removed.length === 1 ? "" : "s"} from backup.`));
|
|
7276
7260
|
}
|
|
7277
7261
|
} catch {
|
|
7278
7262
|
}
|
|
7279
|
-
console.log(
|
|
7263
|
+
console.log(chalk12.dim(" Run ") + chalk12.hex("#83D1EB")("caliber init --force") + chalk12.dim(" to override.\n"));
|
|
7280
7264
|
return;
|
|
7281
7265
|
}
|
|
7282
7266
|
displayScoreDelta(baselineScore, afterScore);
|
|
7283
7267
|
trackRegenerateCompleted(action, Date.now());
|
|
7284
|
-
console.log(
|
|
7285
|
-
console.log(
|
|
7268
|
+
console.log(chalk12.bold.green(" Regeneration complete!"));
|
|
7269
|
+
console.log(chalk12.dim(" Run ") + chalk12.hex("#83D1EB")("caliber undo") + chalk12.dim(" to revert changes.\n"));
|
|
7286
7270
|
}
|
|
7287
7271
|
|
|
7288
7272
|
// src/commands/score.ts
|
|
7289
|
-
import
|
|
7273
|
+
import chalk13 from "chalk";
|
|
7290
7274
|
async function scoreCommand(options) {
|
|
7291
7275
|
const dir = process.cwd();
|
|
7292
7276
|
const target = options.agent ?? readState()?.targetAgent;
|
|
@@ -7301,14 +7285,14 @@ async function scoreCommand(options) {
|
|
|
7301
7285
|
return;
|
|
7302
7286
|
}
|
|
7303
7287
|
displayScore(result);
|
|
7304
|
-
const separator =
|
|
7288
|
+
const separator = chalk13.gray(" " + "\u2500".repeat(53));
|
|
7305
7289
|
console.log(separator);
|
|
7306
7290
|
if (result.score < 40) {
|
|
7307
|
-
console.log(
|
|
7291
|
+
console.log(chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.gray(" to generate a complete, optimized setup."));
|
|
7308
7292
|
} else if (result.score < 70) {
|
|
7309
|
-
console.log(
|
|
7293
|
+
console.log(chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber init") + chalk13.gray(" to improve your setup."));
|
|
7310
7294
|
} else {
|
|
7311
|
-
console.log(
|
|
7295
|
+
console.log(chalk13.green(" Looking good!") + chalk13.gray(" Run ") + chalk13.hex("#83D1EB")("caliber regenerate") + chalk13.gray(" to rebuild from scratch."));
|
|
7312
7296
|
}
|
|
7313
7297
|
console.log("");
|
|
7314
7298
|
}
|
|
@@ -7316,7 +7300,7 @@ async function scoreCommand(options) {
|
|
|
7316
7300
|
// src/commands/refresh.ts
|
|
7317
7301
|
import fs28 from "fs";
|
|
7318
7302
|
import path22 from "path";
|
|
7319
|
-
import
|
|
7303
|
+
import chalk14 from "chalk";
|
|
7320
7304
|
import ora5 from "ora";
|
|
7321
7305
|
|
|
7322
7306
|
// src/lib/git-diff.ts
|
|
@@ -7515,7 +7499,7 @@ function discoverGitRepos(parentDir) {
|
|
|
7515
7499
|
}
|
|
7516
7500
|
async function refreshSingleRepo(repoDir, options) {
|
|
7517
7501
|
const quiet = !!options.quiet;
|
|
7518
|
-
const prefix = options.label ? `${
|
|
7502
|
+
const prefix = options.label ? `${chalk14.bold(options.label)} ` : "";
|
|
7519
7503
|
const state = readState();
|
|
7520
7504
|
const lastSha = state?.lastRefreshSha ?? null;
|
|
7521
7505
|
const diff = collectDiff(lastSha);
|
|
@@ -7524,7 +7508,7 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7524
7508
|
if (currentSha) {
|
|
7525
7509
|
writeState({ lastRefreshSha: currentSha, lastRefreshTimestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
7526
7510
|
}
|
|
7527
|
-
log2(quiet,
|
|
7511
|
+
log2(quiet, chalk14.dim(`${prefix}No changes since last refresh.`));
|
|
7528
7512
|
return;
|
|
7529
7513
|
}
|
|
7530
7514
|
const spinner = quiet ? null : ora5(`${prefix}Analyzing changes...`).start();
|
|
@@ -7556,10 +7540,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7556
7540
|
if (options.dryRun) {
|
|
7557
7541
|
spinner?.info(`${prefix}Dry run \u2014 would update:`);
|
|
7558
7542
|
for (const doc of response.docsUpdated) {
|
|
7559
|
-
console.log(` ${
|
|
7543
|
+
console.log(` ${chalk14.yellow("~")} ${doc}`);
|
|
7560
7544
|
}
|
|
7561
7545
|
if (response.changesSummary) {
|
|
7562
|
-
console.log(
|
|
7546
|
+
console.log(chalk14.dim(`
|
|
7563
7547
|
${response.changesSummary}`));
|
|
7564
7548
|
}
|
|
7565
7549
|
return;
|
|
@@ -7568,10 +7552,10 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
7568
7552
|
trackRefreshCompleted(written.length, Date.now());
|
|
7569
7553
|
spinner?.succeed(`${prefix}Updated ${written.length} doc${written.length === 1 ? "" : "s"}`);
|
|
7570
7554
|
for (const file of written) {
|
|
7571
|
-
log2(quiet, ` ${
|
|
7555
|
+
log2(quiet, ` ${chalk14.green("\u2713")} ${file}`);
|
|
7572
7556
|
}
|
|
7573
7557
|
if (response.changesSummary) {
|
|
7574
|
-
log2(quiet,
|
|
7558
|
+
log2(quiet, chalk14.dim(`
|
|
7575
7559
|
${response.changesSummary}`));
|
|
7576
7560
|
}
|
|
7577
7561
|
if (currentSha) {
|
|
@@ -7588,7 +7572,7 @@ async function refreshCommand(options) {
|
|
|
7588
7572
|
const config = loadConfig();
|
|
7589
7573
|
if (!config) {
|
|
7590
7574
|
if (quiet) return;
|
|
7591
|
-
console.log(
|
|
7575
|
+
console.log(chalk14.red("No LLM provider configured. Run ") + chalk14.hex("#83D1EB")("caliber config") + chalk14.red(" (e.g. choose Cursor) or set an API key."));
|
|
7592
7576
|
throw new Error("__exit__");
|
|
7593
7577
|
}
|
|
7594
7578
|
await validateModel({ fast: true });
|
|
@@ -7599,10 +7583,10 @@ async function refreshCommand(options) {
|
|
|
7599
7583
|
const repos = discoverGitRepos(process.cwd());
|
|
7600
7584
|
if (repos.length === 0) {
|
|
7601
7585
|
if (quiet) return;
|
|
7602
|
-
console.log(
|
|
7586
|
+
console.log(chalk14.red("Not inside a git repository and no git repos found in child directories."));
|
|
7603
7587
|
throw new Error("__exit__");
|
|
7604
7588
|
}
|
|
7605
|
-
log2(quiet,
|
|
7589
|
+
log2(quiet, chalk14.dim(`Found ${repos.length} git repo${repos.length === 1 ? "" : "s"}
|
|
7606
7590
|
`));
|
|
7607
7591
|
const originalDir = process.cwd();
|
|
7608
7592
|
for (const repo of repos) {
|
|
@@ -7612,7 +7596,7 @@ async function refreshCommand(options) {
|
|
|
7612
7596
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
7613
7597
|
} catch (err) {
|
|
7614
7598
|
if (err instanceof Error && err.message === "__exit__") continue;
|
|
7615
|
-
log2(quiet,
|
|
7599
|
+
log2(quiet, chalk14.yellow(`${repoName}: refresh failed \u2014 ${err instanceof Error ? err.message : "unknown error"}`));
|
|
7616
7600
|
}
|
|
7617
7601
|
}
|
|
7618
7602
|
process.chdir(originalDir);
|
|
@@ -7620,13 +7604,13 @@ async function refreshCommand(options) {
|
|
|
7620
7604
|
if (err instanceof Error && err.message === "__exit__") throw err;
|
|
7621
7605
|
if (quiet) return;
|
|
7622
7606
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
7623
|
-
console.log(
|
|
7607
|
+
console.log(chalk14.red(`Refresh failed: ${msg}`));
|
|
7624
7608
|
throw new Error("__exit__");
|
|
7625
7609
|
}
|
|
7626
7610
|
}
|
|
7627
7611
|
|
|
7628
7612
|
// src/commands/hooks.ts
|
|
7629
|
-
import
|
|
7613
|
+
import chalk15 from "chalk";
|
|
7630
7614
|
var HOOKS = [
|
|
7631
7615
|
{
|
|
7632
7616
|
id: "session-end",
|
|
@@ -7646,13 +7630,13 @@ var HOOKS = [
|
|
|
7646
7630
|
}
|
|
7647
7631
|
];
|
|
7648
7632
|
function printStatus() {
|
|
7649
|
-
console.log(
|
|
7633
|
+
console.log(chalk15.bold("\n Hooks\n"));
|
|
7650
7634
|
for (const hook of HOOKS) {
|
|
7651
7635
|
const installed = hook.isInstalled();
|
|
7652
|
-
const icon = installed ?
|
|
7653
|
-
const state = installed ?
|
|
7636
|
+
const icon = installed ? chalk15.green("\u2713") : chalk15.dim("\u2717");
|
|
7637
|
+
const state = installed ? chalk15.green("enabled") : chalk15.dim("disabled");
|
|
7654
7638
|
console.log(` ${icon} ${hook.label.padEnd(26)} ${state}`);
|
|
7655
|
-
console.log(
|
|
7639
|
+
console.log(chalk15.dim(` ${hook.description}`));
|
|
7656
7640
|
}
|
|
7657
7641
|
console.log("");
|
|
7658
7642
|
}
|
|
@@ -7661,9 +7645,9 @@ async function hooksCommand(options) {
|
|
|
7661
7645
|
for (const hook of HOOKS) {
|
|
7662
7646
|
const result = hook.install();
|
|
7663
7647
|
if (result.alreadyInstalled) {
|
|
7664
|
-
console.log(
|
|
7648
|
+
console.log(chalk15.dim(` ${hook.label} already enabled.`));
|
|
7665
7649
|
} else {
|
|
7666
|
-
console.log(
|
|
7650
|
+
console.log(chalk15.green(" \u2713") + ` ${hook.label} enabled`);
|
|
7667
7651
|
}
|
|
7668
7652
|
}
|
|
7669
7653
|
return;
|
|
@@ -7672,9 +7656,9 @@ async function hooksCommand(options) {
|
|
|
7672
7656
|
for (const hook of HOOKS) {
|
|
7673
7657
|
const result = hook.remove();
|
|
7674
7658
|
if (result.notFound) {
|
|
7675
|
-
console.log(
|
|
7659
|
+
console.log(chalk15.dim(` ${hook.label} already disabled.`));
|
|
7676
7660
|
} else {
|
|
7677
|
-
console.log(
|
|
7661
|
+
console.log(chalk15.green(" \u2713") + ` ${hook.label} removed`);
|
|
7678
7662
|
}
|
|
7679
7663
|
}
|
|
7680
7664
|
return;
|
|
@@ -7689,18 +7673,18 @@ async function hooksCommand(options) {
|
|
|
7689
7673
|
const states = HOOKS.map((h) => h.isInstalled());
|
|
7690
7674
|
function render() {
|
|
7691
7675
|
const lines = [];
|
|
7692
|
-
lines.push(
|
|
7676
|
+
lines.push(chalk15.bold(" Hooks"));
|
|
7693
7677
|
lines.push("");
|
|
7694
7678
|
for (let i = 0; i < HOOKS.length; i++) {
|
|
7695
7679
|
const hook = HOOKS[i];
|
|
7696
7680
|
const enabled = states[i];
|
|
7697
|
-
const toggle = enabled ?
|
|
7698
|
-
const ptr = i === cursor ?
|
|
7681
|
+
const toggle = enabled ? chalk15.green("[on] ") : chalk15.dim("[off]");
|
|
7682
|
+
const ptr = i === cursor ? chalk15.cyan(">") : " ";
|
|
7699
7683
|
lines.push(` ${ptr} ${toggle} ${hook.label}`);
|
|
7700
|
-
lines.push(
|
|
7684
|
+
lines.push(chalk15.dim(` ${hook.description}`));
|
|
7701
7685
|
}
|
|
7702
7686
|
lines.push("");
|
|
7703
|
-
lines.push(
|
|
7687
|
+
lines.push(chalk15.dim(" \u2191\u2193 navigate \u23B5 toggle a all on n all off \u23CE apply q cancel"));
|
|
7704
7688
|
return lines.join("\n");
|
|
7705
7689
|
}
|
|
7706
7690
|
function draw(initial) {
|
|
@@ -7731,16 +7715,16 @@ async function hooksCommand(options) {
|
|
|
7731
7715
|
const wantEnabled = states[i];
|
|
7732
7716
|
if (wantEnabled && !wasInstalled) {
|
|
7733
7717
|
hook.install();
|
|
7734
|
-
console.log(
|
|
7718
|
+
console.log(chalk15.green(" \u2713") + ` ${hook.label} enabled`);
|
|
7735
7719
|
changed++;
|
|
7736
7720
|
} else if (!wantEnabled && wasInstalled) {
|
|
7737
7721
|
hook.remove();
|
|
7738
|
-
console.log(
|
|
7722
|
+
console.log(chalk15.green(" \u2713") + ` ${hook.label} disabled`);
|
|
7739
7723
|
changed++;
|
|
7740
7724
|
}
|
|
7741
7725
|
}
|
|
7742
7726
|
if (changed === 0) {
|
|
7743
|
-
console.log(
|
|
7727
|
+
console.log(chalk15.dim(" No changes."));
|
|
7744
7728
|
}
|
|
7745
7729
|
console.log("");
|
|
7746
7730
|
}
|
|
@@ -7776,7 +7760,7 @@ async function hooksCommand(options) {
|
|
|
7776
7760
|
case "\x1B":
|
|
7777
7761
|
case "":
|
|
7778
7762
|
cleanup();
|
|
7779
|
-
console.log(
|
|
7763
|
+
console.log(chalk15.dim("\n Cancelled.\n"));
|
|
7780
7764
|
resolve2();
|
|
7781
7765
|
break;
|
|
7782
7766
|
}
|
|
@@ -7787,50 +7771,50 @@ async function hooksCommand(options) {
|
|
|
7787
7771
|
|
|
7788
7772
|
// src/commands/config.ts
|
|
7789
7773
|
init_config();
|
|
7790
|
-
import
|
|
7774
|
+
import chalk16 from "chalk";
|
|
7791
7775
|
async function configCommand() {
|
|
7792
7776
|
const existing = loadConfig();
|
|
7793
7777
|
if (existing) {
|
|
7794
|
-
const displayModel = existing
|
|
7778
|
+
const displayModel = getDisplayModel(existing);
|
|
7795
7779
|
const fastModel = getFastModel();
|
|
7796
|
-
console.log(
|
|
7797
|
-
console.log(` Provider: ${
|
|
7798
|
-
console.log(` Model: ${
|
|
7780
|
+
console.log(chalk16.bold("\nCurrent Configuration\n"));
|
|
7781
|
+
console.log(` Provider: ${chalk16.cyan(existing.provider)}`);
|
|
7782
|
+
console.log(` Model: ${chalk16.cyan(displayModel)}`);
|
|
7799
7783
|
if (fastModel) {
|
|
7800
|
-
console.log(` Scan: ${
|
|
7784
|
+
console.log(` Scan: ${chalk16.cyan(fastModel)}`);
|
|
7801
7785
|
}
|
|
7802
7786
|
if (existing.apiKey) {
|
|
7803
7787
|
const masked = existing.apiKey.slice(0, 8) + "..." + existing.apiKey.slice(-4);
|
|
7804
|
-
console.log(` API Key: ${
|
|
7788
|
+
console.log(` API Key: ${chalk16.dim(masked)}`);
|
|
7805
7789
|
}
|
|
7806
7790
|
if (existing.provider === "cursor") {
|
|
7807
|
-
console.log(` Seat: ${
|
|
7791
|
+
console.log(` Seat: ${chalk16.dim("Cursor (agent acp)")}`);
|
|
7808
7792
|
}
|
|
7809
7793
|
if (existing.provider === "claude-cli") {
|
|
7810
|
-
console.log(` Seat: ${
|
|
7794
|
+
console.log(` Seat: ${chalk16.dim("Claude Code (claude -p)")}`);
|
|
7811
7795
|
}
|
|
7812
7796
|
if (existing.baseUrl) {
|
|
7813
|
-
console.log(` Base URL: ${
|
|
7797
|
+
console.log(` Base URL: ${chalk16.dim(existing.baseUrl)}`);
|
|
7814
7798
|
}
|
|
7815
7799
|
if (existing.vertexProjectId) {
|
|
7816
|
-
console.log(` Vertex Project: ${
|
|
7817
|
-
console.log(` Vertex Region: ${
|
|
7800
|
+
console.log(` Vertex Project: ${chalk16.dim(existing.vertexProjectId)}`);
|
|
7801
|
+
console.log(` Vertex Region: ${chalk16.dim(existing.vertexRegion || "us-east5")}`);
|
|
7818
7802
|
}
|
|
7819
|
-
console.log(` Source: ${
|
|
7803
|
+
console.log(` Source: ${chalk16.dim(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY || process.env.VERTEX_PROJECT_ID || process.env.CALIBER_USE_CURSOR_SEAT || process.env.CALIBER_USE_CLAUDE_CLI ? "environment variables" : getConfigFilePath())}`);
|
|
7820
7804
|
console.log("");
|
|
7821
7805
|
}
|
|
7822
7806
|
await runInteractiveProviderSetup();
|
|
7823
7807
|
const updated = loadConfig();
|
|
7824
7808
|
if (updated) trackConfigProviderSet(updated.provider);
|
|
7825
|
-
console.log(
|
|
7826
|
-
console.log(
|
|
7809
|
+
console.log(chalk16.green("\n\u2713 Configuration saved"));
|
|
7810
|
+
console.log(chalk16.dim(` ${getConfigFilePath()}
|
|
7827
7811
|
`));
|
|
7828
|
-
console.log(
|
|
7829
|
-
console.log(
|
|
7812
|
+
console.log(chalk16.dim(" You can also set environment variables instead:"));
|
|
7813
|
+
console.log(chalk16.dim(" ANTHROPIC_API_KEY, OPENAI_API_KEY, VERTEX_PROJECT_ID, CALIBER_USE_CURSOR_SEAT=1, or CALIBER_USE_CLAUDE_CLI=1\n"));
|
|
7830
7814
|
}
|
|
7831
7815
|
|
|
7832
7816
|
// src/commands/learn.ts
|
|
7833
|
-
import
|
|
7817
|
+
import chalk17 from "chalk";
|
|
7834
7818
|
|
|
7835
7819
|
// src/learner/stdin.ts
|
|
7836
7820
|
var STDIN_TIMEOUT_MS = 5e3;
|
|
@@ -8138,46 +8122,46 @@ async function learnFinalizeCommand() {
|
|
|
8138
8122
|
async function learnInstallCommand() {
|
|
8139
8123
|
const result = installLearningHooks();
|
|
8140
8124
|
if (result.alreadyInstalled) {
|
|
8141
|
-
console.log(
|
|
8125
|
+
console.log(chalk17.dim("Learning hooks already installed."));
|
|
8142
8126
|
return;
|
|
8143
8127
|
}
|
|
8144
|
-
console.log(
|
|
8145
|
-
console.log(
|
|
8146
|
-
console.log(
|
|
8128
|
+
console.log(chalk17.green("\u2713") + " Learning hooks installed in .claude/settings.json");
|
|
8129
|
+
console.log(chalk17.dim(" PostToolUse, PostToolUseFailure, and SessionEnd hooks active."));
|
|
8130
|
+
console.log(chalk17.dim(" Session learnings will be written to CLAUDE.md and skills."));
|
|
8147
8131
|
}
|
|
8148
8132
|
async function learnRemoveCommand() {
|
|
8149
8133
|
const result = removeLearningHooks();
|
|
8150
8134
|
if (result.notFound) {
|
|
8151
|
-
console.log(
|
|
8135
|
+
console.log(chalk17.dim("Learning hooks not found."));
|
|
8152
8136
|
return;
|
|
8153
8137
|
}
|
|
8154
|
-
console.log(
|
|
8138
|
+
console.log(chalk17.green("\u2713") + " Learning hooks removed from .claude/settings.json");
|
|
8155
8139
|
}
|
|
8156
8140
|
async function learnStatusCommand() {
|
|
8157
8141
|
const installed = areLearningHooksInstalled();
|
|
8158
8142
|
const state = readState2();
|
|
8159
8143
|
const eventCount = getEventCount();
|
|
8160
|
-
console.log(
|
|
8144
|
+
console.log(chalk17.bold("Session Learning Status"));
|
|
8161
8145
|
console.log();
|
|
8162
8146
|
if (installed) {
|
|
8163
|
-
console.log(
|
|
8147
|
+
console.log(chalk17.green("\u2713") + " Learning hooks are " + chalk17.green("installed"));
|
|
8164
8148
|
} else {
|
|
8165
|
-
console.log(
|
|
8166
|
-
console.log(
|
|
8149
|
+
console.log(chalk17.dim("\u2717") + " Learning hooks are " + chalk17.yellow("not installed"));
|
|
8150
|
+
console.log(chalk17.dim(" Run `caliber learn install` to enable session learning."));
|
|
8167
8151
|
}
|
|
8168
8152
|
console.log();
|
|
8169
|
-
console.log(`Events recorded: ${
|
|
8170
|
-
console.log(`Total this session: ${
|
|
8153
|
+
console.log(`Events recorded: ${chalk17.cyan(String(eventCount))}`);
|
|
8154
|
+
console.log(`Total this session: ${chalk17.cyan(String(state.eventCount))}`);
|
|
8171
8155
|
if (state.lastAnalysisTimestamp) {
|
|
8172
|
-
console.log(`Last analysis: ${
|
|
8156
|
+
console.log(`Last analysis: ${chalk17.cyan(state.lastAnalysisTimestamp)}`);
|
|
8173
8157
|
} else {
|
|
8174
|
-
console.log(`Last analysis: ${
|
|
8158
|
+
console.log(`Last analysis: ${chalk17.dim("none")}`);
|
|
8175
8159
|
}
|
|
8176
8160
|
const learnedSection = readLearnedSection();
|
|
8177
8161
|
if (learnedSection) {
|
|
8178
8162
|
const lineCount = learnedSection.split("\n").filter(Boolean).length;
|
|
8179
8163
|
console.log(`
|
|
8180
|
-
Learned items in CLAUDE.md: ${
|
|
8164
|
+
Learned items in CLAUDE.md: ${chalk17.cyan(String(lineCount))}`);
|
|
8181
8165
|
}
|
|
8182
8166
|
}
|
|
8183
8167
|
|
|
@@ -8262,7 +8246,7 @@ import fs32 from "fs";
|
|
|
8262
8246
|
import path26 from "path";
|
|
8263
8247
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8264
8248
|
import { execSync as execSync14 } from "child_process";
|
|
8265
|
-
import
|
|
8249
|
+
import chalk18 from "chalk";
|
|
8266
8250
|
import ora6 from "ora";
|
|
8267
8251
|
import confirm2 from "@inquirer/confirm";
|
|
8268
8252
|
var __dirname_vc = path26.dirname(fileURLToPath2(import.meta.url));
|
|
@@ -8296,17 +8280,17 @@ async function checkForUpdates() {
|
|
|
8296
8280
|
const isInteractive = process.stdin.isTTY === true;
|
|
8297
8281
|
if (!isInteractive) {
|
|
8298
8282
|
console.log(
|
|
8299
|
-
|
|
8283
|
+
chalk18.yellow(
|
|
8300
8284
|
`
|
|
8301
8285
|
Update available: ${current} -> ${latest}
|
|
8302
|
-
Run ${
|
|
8286
|
+
Run ${chalk18.bold("npm install -g @rely-ai/caliber")} to upgrade.
|
|
8303
8287
|
`
|
|
8304
8288
|
)
|
|
8305
8289
|
);
|
|
8306
8290
|
return;
|
|
8307
8291
|
}
|
|
8308
8292
|
console.log(
|
|
8309
|
-
|
|
8293
|
+
chalk18.yellow(`
|
|
8310
8294
|
Update available: ${current} -> ${latest}`)
|
|
8311
8295
|
);
|
|
8312
8296
|
const shouldUpdate = await confirm2({ message: "Would you like to update now? (Y/n)", default: true });
|
|
@@ -8324,13 +8308,13 @@ Update available: ${current} -> ${latest}`)
|
|
|
8324
8308
|
const installed = getInstalledVersion();
|
|
8325
8309
|
if (installed !== latest) {
|
|
8326
8310
|
spinner.fail(`Update incomplete \u2014 got ${installed ?? "unknown"}, expected ${latest}`);
|
|
8327
|
-
console.log(
|
|
8311
|
+
console.log(chalk18.yellow(`Run ${chalk18.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually.
|
|
8328
8312
|
`));
|
|
8329
8313
|
return;
|
|
8330
8314
|
}
|
|
8331
|
-
spinner.succeed(
|
|
8315
|
+
spinner.succeed(chalk18.green(`Updated to ${latest}`));
|
|
8332
8316
|
const args = process.argv.slice(2);
|
|
8333
|
-
console.log(
|
|
8317
|
+
console.log(chalk18.dim(`
|
|
8334
8318
|
Restarting: caliber ${args.join(" ")}
|
|
8335
8319
|
`));
|
|
8336
8320
|
execSync14(`caliber ${args.map((a) => JSON.stringify(a)).join(" ")}`, {
|
|
@@ -8343,11 +8327,11 @@ Restarting: caliber ${args.join(" ")}
|
|
|
8343
8327
|
if (err instanceof Error) {
|
|
8344
8328
|
const stderr = err.stderr;
|
|
8345
8329
|
const errMsg = stderr ? String(stderr).trim().split("\n").pop() : err.message.split("\n")[0];
|
|
8346
|
-
if (errMsg && !errMsg.includes("SIGTERM")) console.log(
|
|
8330
|
+
if (errMsg && !errMsg.includes("SIGTERM")) console.log(chalk18.dim(` ${errMsg}`));
|
|
8347
8331
|
}
|
|
8348
8332
|
console.log(
|
|
8349
|
-
|
|
8350
|
-
`Run ${
|
|
8333
|
+
chalk18.yellow(
|
|
8334
|
+
`Run ${chalk18.bold(`npm install -g @rely-ai/caliber@${latest}`)} manually to upgrade.
|
|
8351
8335
|
`
|
|
8352
8336
|
)
|
|
8353
8337
|
);
|