@rely-ai/caliber 1.34.0-dev.1774825768 → 1.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +532 -398
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -443,8 +443,8 @@ __export(builtin_skills_exports, {
|
|
|
443
443
|
buildSkillContent: () => buildSkillContent,
|
|
444
444
|
ensureBuiltinSkills: () => ensureBuiltinSkills
|
|
445
445
|
});
|
|
446
|
-
import
|
|
447
|
-
import
|
|
446
|
+
import fs16 from "fs";
|
|
447
|
+
import path16 from "path";
|
|
448
448
|
function buildSkillContent(skill) {
|
|
449
449
|
const frontmatter = `---
|
|
450
450
|
name: ${skill.name}
|
|
@@ -777,11 +777,11 @@ From now on, every commit keeps all your agent configs in sync automatically.
|
|
|
777
777
|
function ensureBuiltinSkills() {
|
|
778
778
|
const written = [];
|
|
779
779
|
for (const { platformDir, skillsDir } of PLATFORM_CONFIGS) {
|
|
780
|
-
if (!
|
|
780
|
+
if (!fs16.existsSync(platformDir)) continue;
|
|
781
781
|
for (const skill of BUILTIN_SKILLS) {
|
|
782
|
-
const skillPath =
|
|
783
|
-
|
|
784
|
-
|
|
782
|
+
const skillPath = path16.join(skillsDir, skill.name, "SKILL.md");
|
|
783
|
+
fs16.mkdirSync(path16.dirname(skillPath), { recursive: true });
|
|
784
|
+
fs16.writeFileSync(skillPath, buildSkillContent(skill));
|
|
785
785
|
written.push(skillPath);
|
|
786
786
|
}
|
|
787
787
|
}
|
|
@@ -815,9 +815,10 @@ var init_builtin_skills = __esm({
|
|
|
815
815
|
};
|
|
816
816
|
BUILTIN_SKILLS = [FIND_SKILLS_SKILL, SAVE_LEARNING_SKILL, SETUP_CALIBER_SKILL];
|
|
817
817
|
PLATFORM_CONFIGS = [
|
|
818
|
-
{ platformDir: ".claude", skillsDir:
|
|
819
|
-
{ platformDir: ".cursor", skillsDir:
|
|
820
|
-
{ platformDir: ".agents", skillsDir:
|
|
818
|
+
{ platformDir: ".claude", skillsDir: path16.join(".claude", "skills") },
|
|
819
|
+
{ platformDir: ".cursor", skillsDir: path16.join(".cursor", "skills") },
|
|
820
|
+
{ platformDir: ".agents", skillsDir: path16.join(".agents", "skills") },
|
|
821
|
+
{ platformDir: ".opencode", skillsDir: path16.join(".opencode", "skills") }
|
|
821
822
|
];
|
|
822
823
|
BUILTIN_SKILL_NAMES = new Set(BUILTIN_SKILLS.map((s) => s.name));
|
|
823
824
|
}
|
|
@@ -825,13 +826,13 @@ var init_builtin_skills = __esm({
|
|
|
825
826
|
|
|
826
827
|
// src/utils/editor.ts
|
|
827
828
|
import { execSync as execSync14, spawn as spawn3 } from "child_process";
|
|
828
|
-
import
|
|
829
|
-
import
|
|
829
|
+
import fs28 from "fs";
|
|
830
|
+
import path25 from "path";
|
|
830
831
|
import os6 from "os";
|
|
831
832
|
function getEmptyFilePath(proposedPath) {
|
|
832
|
-
|
|
833
|
-
const tempPath =
|
|
834
|
-
|
|
833
|
+
fs28.mkdirSync(DIFF_TEMP_DIR, { recursive: true });
|
|
834
|
+
const tempPath = path25.join(DIFF_TEMP_DIR, path25.basename(proposedPath));
|
|
835
|
+
fs28.writeFileSync(tempPath, "");
|
|
835
836
|
return tempPath;
|
|
836
837
|
}
|
|
837
838
|
function commandExists(cmd) {
|
|
@@ -871,7 +872,7 @@ var init_editor = __esm({
|
|
|
871
872
|
"src/utils/editor.ts"() {
|
|
872
873
|
"use strict";
|
|
873
874
|
IS_WINDOWS3 = process.platform === "win32";
|
|
874
|
-
DIFF_TEMP_DIR =
|
|
875
|
+
DIFF_TEMP_DIR = path25.join(os6.tmpdir(), "caliber-diff");
|
|
875
876
|
}
|
|
876
877
|
});
|
|
877
878
|
|
|
@@ -883,7 +884,7 @@ __export(review_exports, {
|
|
|
883
884
|
promptWantsReview: () => promptWantsReview
|
|
884
885
|
});
|
|
885
886
|
import chalk10 from "chalk";
|
|
886
|
-
import
|
|
887
|
+
import fs29 from "fs";
|
|
887
888
|
import select4 from "@inquirer/select";
|
|
888
889
|
import { createTwoFilesPatch } from "diff";
|
|
889
890
|
async function promptWantsReview() {
|
|
@@ -920,8 +921,8 @@ async function openReview(method, stagedFiles) {
|
|
|
920
921
|
return;
|
|
921
922
|
}
|
|
922
923
|
const fileInfos = stagedFiles.map((file) => {
|
|
923
|
-
const proposed =
|
|
924
|
-
const current = file.currentPath ?
|
|
924
|
+
const proposed = fs29.readFileSync(file.proposedPath, "utf-8");
|
|
925
|
+
const current = file.currentPath ? fs29.readFileSync(file.currentPath, "utf-8") : "";
|
|
925
926
|
const patch = createTwoFilesPatch(
|
|
926
927
|
file.isNew ? "/dev/null" : file.relativePath,
|
|
927
928
|
file.relativePath,
|
|
@@ -1096,13 +1097,13 @@ __export(lock_exports, {
|
|
|
1096
1097
|
isCaliberRunning: () => isCaliberRunning,
|
|
1097
1098
|
releaseLock: () => releaseLock
|
|
1098
1099
|
});
|
|
1099
|
-
import
|
|
1100
|
-
import
|
|
1100
|
+
import fs39 from "fs";
|
|
1101
|
+
import path32 from "path";
|
|
1101
1102
|
import os8 from "os";
|
|
1102
1103
|
function isCaliberRunning() {
|
|
1103
1104
|
try {
|
|
1104
|
-
if (!
|
|
1105
|
-
const raw =
|
|
1105
|
+
if (!fs39.existsSync(LOCK_FILE)) return false;
|
|
1106
|
+
const raw = fs39.readFileSync(LOCK_FILE, "utf-8").trim();
|
|
1106
1107
|
const { pid, ts } = JSON.parse(raw);
|
|
1107
1108
|
if (Date.now() - ts > STALE_MS) return false;
|
|
1108
1109
|
try {
|
|
@@ -1117,13 +1118,13 @@ function isCaliberRunning() {
|
|
|
1117
1118
|
}
|
|
1118
1119
|
function acquireLock() {
|
|
1119
1120
|
try {
|
|
1120
|
-
|
|
1121
|
+
fs39.writeFileSync(LOCK_FILE, JSON.stringify({ pid: process.pid, ts: Date.now() }));
|
|
1121
1122
|
} catch {
|
|
1122
1123
|
}
|
|
1123
1124
|
}
|
|
1124
1125
|
function releaseLock() {
|
|
1125
1126
|
try {
|
|
1126
|
-
if (
|
|
1127
|
+
if (fs39.existsSync(LOCK_FILE)) fs39.unlinkSync(LOCK_FILE);
|
|
1127
1128
|
} catch {
|
|
1128
1129
|
}
|
|
1129
1130
|
}
|
|
@@ -1131,21 +1132,21 @@ var LOCK_FILE, STALE_MS;
|
|
|
1131
1132
|
var init_lock = __esm({
|
|
1132
1133
|
"src/lib/lock.ts"() {
|
|
1133
1134
|
"use strict";
|
|
1134
|
-
LOCK_FILE =
|
|
1135
|
+
LOCK_FILE = path32.join(os8.tmpdir(), ".caliber.lock");
|
|
1135
1136
|
STALE_MS = 10 * 60 * 1e3;
|
|
1136
1137
|
}
|
|
1137
1138
|
});
|
|
1138
1139
|
|
|
1139
1140
|
// src/cli.ts
|
|
1140
1141
|
import { Command } from "commander";
|
|
1141
|
-
import
|
|
1142
|
-
import
|
|
1142
|
+
import fs50 from "fs";
|
|
1143
|
+
import path41 from "path";
|
|
1143
1144
|
import { fileURLToPath } from "url";
|
|
1144
1145
|
|
|
1145
1146
|
// src/commands/init.ts
|
|
1146
|
-
import
|
|
1147
|
+
import path28 from "path";
|
|
1147
1148
|
import chalk14 from "chalk";
|
|
1148
|
-
import
|
|
1149
|
+
import fs34 from "fs";
|
|
1149
1150
|
|
|
1150
1151
|
// src/fingerprint/index.ts
|
|
1151
1152
|
import fs8 from "fs";
|
|
@@ -3007,7 +3008,7 @@ async function validateModel(options) {
|
|
|
3007
3008
|
init_config();
|
|
3008
3009
|
|
|
3009
3010
|
// src/ai/prompts.ts
|
|
3010
|
-
var ROLE_AND_CONTEXT = `You are an expert auditor for coding agent configurations (Claude Code, Cursor, Codex, and GitHub Copilot).
|
|
3011
|
+
var ROLE_AND_CONTEXT = `You are an expert auditor for coding agent configurations (Claude Code, Cursor, Codex, OpenCode, and GitHub Copilot).
|
|
3011
3012
|
|
|
3012
3013
|
Your job depends on context:
|
|
3013
3014
|
- If no existing configs exist \u2192 generate an initial configuration from scratch.
|
|
@@ -3017,6 +3018,7 @@ var CONFIG_FILE_TYPES = `You understand these config files:
|
|
|
3017
3018
|
- 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.
|
|
3018
3019
|
- .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.
|
|
3019
3020
|
- .agents/skills/{name}/SKILL.md: Same OpenSkills format for Codex skills (Codex scans .agents/skills/ for skills).
|
|
3021
|
+
- .opencode/skills/{name}/SKILL.md: Same OpenSkills format for OpenCode skills (OpenCode scans .opencode/skills/ for skills).
|
|
3020
3022
|
- .cursor/skills/{name}/SKILL.md: Same OpenSkills format for Cursor skills.
|
|
3021
3023
|
- .cursorrules: Coding rules for Cursor (deprecated legacy format \u2014 do NOT generate this).
|
|
3022
3024
|
- .cursor/rules/*.mdc: Modern Cursor rules with frontmatter (description, globs, alwaysApply).
|
|
@@ -3044,7 +3046,7 @@ EXPLAIN:
|
|
|
3044
3046
|
Omit empty categories. Keep each reason punchy and specific. End with a blank line.
|
|
3045
3047
|
|
|
3046
3048
|
3. The JSON object starting with {.`;
|
|
3047
|
-
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.
|
|
3049
|
+
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", ".opencode/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.
|
|
3048
3050
|
|
|
3049
3051
|
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.`;
|
|
3050
3052
|
var SKILL_FORMAT_RULES = `All skills follow the OpenSkills standard (agentskills.io). Anthropic's official skill guide defines three levels of progressive disclosure:
|
|
@@ -3068,7 +3070,7 @@ var SCORING_CRITERIA = `SCORING CRITERIA \u2014 your output is scored determinis
|
|
|
3068
3070
|
|
|
3069
3071
|
Existence (25 pts):
|
|
3070
3072
|
- CLAUDE.md exists (6 pts) \u2014 always generate for claude targets
|
|
3071
|
-
- AGENTS.md exists (6 pts) \u2014 always generate for codex
|
|
3073
|
+
- AGENTS.md exists (6 pts) \u2014 always generate for codex or opencode targets
|
|
3072
3074
|
- copilot-instructions.md exists (6 pts) \u2014 always generate for github-copilot target
|
|
3073
3075
|
- Skills configured (8 pts) \u2014 generate 3+ skills for full points
|
|
3074
3076
|
- MCP servers referenced (3 pts) \u2014 mention detected MCP integrations in your config text
|
|
@@ -3119,7 +3121,7 @@ ${OUTPUT_FORMAT}
|
|
|
3119
3121
|
|
|
3120
3122
|
AgentSetup schema:
|
|
3121
3123
|
{
|
|
3122
|
-
"targetAgent": ["claude", "cursor", "codex", "github-copilot"] (array of selected agents),
|
|
3124
|
+
"targetAgent": ["claude", "cursor", "codex", "opencode", "github-copilot"] (array of selected agents),
|
|
3123
3125
|
"fileDescriptions": {
|
|
3124
3126
|
"<file-path>": "reason for this change (max 80 chars)"
|
|
3125
3127
|
},
|
|
@@ -3134,6 +3136,10 @@ AgentSetup schema:
|
|
|
3134
3136
|
"agentsMd": "string (markdown content for AGENTS.md \u2014 the primary Codex instructions file, same quality/structure as CLAUDE.md)",
|
|
3135
3137
|
"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)" }]
|
|
3136
3138
|
},
|
|
3139
|
+
"opencode": {
|
|
3140
|
+
"agentsMd": "string (markdown content for AGENTS.md \u2014 reuse codex.agentsMd if codex is also targeted, otherwise generate fresh)",
|
|
3141
|
+
"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)" }]
|
|
3142
|
+
},
|
|
3137
3143
|
"cursor": {
|
|
3138
3144
|
"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)" }],
|
|
3139
3145
|
"rules": [{ "filename": "string.mdc", "content": "string (with frontmatter)" }]
|
|
@@ -3144,6 +3150,8 @@ AgentSetup schema:
|
|
|
3144
3150
|
}
|
|
3145
3151
|
}
|
|
3146
3152
|
|
|
3153
|
+
NOTE: If both "codex" and "opencode" are targeted, set opencode.agentsMd to the SAME content as codex.agentsMd \u2014 both agents read the same AGENTS.md file.
|
|
3154
|
+
|
|
3147
3155
|
${SKILL_FORMAT_RULES}
|
|
3148
3156
|
|
|
3149
3157
|
${FILE_DESCRIPTIONS_RULES}
|
|
@@ -3164,7 +3172,7 @@ ${OUTPUT_FORMAT}
|
|
|
3164
3172
|
|
|
3165
3173
|
CoreSetup schema:
|
|
3166
3174
|
{
|
|
3167
|
-
"targetAgent": ["claude", "cursor", "codex", "github-copilot"] (array of selected agents),
|
|
3175
|
+
"targetAgent": ["claude", "cursor", "codex", "opencode", "github-copilot"] (array of selected agents),
|
|
3168
3176
|
"fileDescriptions": {
|
|
3169
3177
|
"<file-path>": "reason for this change (max 80 chars)"
|
|
3170
3178
|
},
|
|
@@ -3179,6 +3187,10 @@ CoreSetup schema:
|
|
|
3179
3187
|
"agentsMd": "string (markdown content for AGENTS.md)",
|
|
3180
3188
|
"skillTopics": [{ "name": "string (kebab-case)", "description": "string (what this skill does and WHEN to use it \u2014 include trigger phrases)" }]
|
|
3181
3189
|
},
|
|
3190
|
+
"opencode": {
|
|
3191
|
+
"agentsMd": "string (reuse codex.agentsMd if codex also targeted)",
|
|
3192
|
+
"skillTopics": [{ "name": "string (kebab-case)", "description": "string (what this skill does and WHEN to use it \u2014 include trigger phrases)" }]
|
|
3193
|
+
},
|
|
3182
3194
|
"cursor": {
|
|
3183
3195
|
"skillTopics": [{ "name": "string (kebab-case)", "description": "string (what this skill does and WHEN to use it \u2014 include trigger phrases)" }],
|
|
3184
3196
|
"rules": [{ "filename": "string.mdc", "content": "string (with frontmatter)" }]
|
|
@@ -3208,7 +3220,7 @@ ${SCORING_CRITERIA}
|
|
|
3208
3220
|
|
|
3209
3221
|
${OUTPUT_SIZE_CONSTRAINTS}
|
|
3210
3222
|
- Skill topics: 3-6 per platform based on project complexity (name + description only, no content).`;
|
|
3211
|
-
var SKILL_GENERATION_PROMPT = `You generate a single skill file for a coding agent (Claude Code, Cursor, or
|
|
3223
|
+
var SKILL_GENERATION_PROMPT = `You generate a single skill file for a coding agent (Claude Code, Cursor, Codex, or OpenCode).
|
|
3212
3224
|
|
|
3213
3225
|
Given project context and a skill topic, produce a focused SKILL.md body.
|
|
3214
3226
|
|
|
@@ -3238,7 +3250,7 @@ Description field formula: [What it does] + [When to use it with trigger phrases
|
|
|
3238
3250
|
|
|
3239
3251
|
Return ONLY a JSON object:
|
|
3240
3252
|
{"name": "string (kebab-case)", "description": "string (what + when + capabilities + negative triggers)", "content": "string (markdown body)"}`;
|
|
3241
|
-
var REFINE_SYSTEM_PROMPT = `You are an expert at modifying coding agent configurations (Claude Code, Cursor, Codex, and GitHub Copilot).
|
|
3253
|
+
var REFINE_SYSTEM_PROMPT = `You are an expert at modifying coding agent configurations (Claude Code, Cursor, Codex, OpenCode, and GitHub Copilot).
|
|
3242
3254
|
|
|
3243
3255
|
You will receive the current AgentSetup JSON and a user request describing what to change.
|
|
3244
3256
|
|
|
@@ -3246,7 +3258,7 @@ Apply the requested changes to the setup and return the complete updated AgentSe
|
|
|
3246
3258
|
|
|
3247
3259
|
AgentSetup schema:
|
|
3248
3260
|
{
|
|
3249
|
-
"targetAgent": ["claude", "cursor", "codex", "github-copilot"] (array of selected agents),
|
|
3261
|
+
"targetAgent": ["claude", "cursor", "codex", "opencode", "github-copilot"] (array of selected agents),
|
|
3250
3262
|
"fileDescriptions": {
|
|
3251
3263
|
"<file-path>": "reason for this change (max 80 chars)"
|
|
3252
3264
|
},
|
|
@@ -3261,6 +3273,10 @@ AgentSetup schema:
|
|
|
3261
3273
|
"agentsMd": "string (markdown content for AGENTS.md)",
|
|
3262
3274
|
"skills": [{ "name": "string (kebab-case)", "description": "string", "content": "string (markdown body, no frontmatter)" }]
|
|
3263
3275
|
},
|
|
3276
|
+
"opencode": {
|
|
3277
|
+
"agentsMd": "string (reuse codex.agentsMd if codex also targeted)",
|
|
3278
|
+
"skills": [{ "name": "string (kebab-case)", "description": "string", "content": "string (markdown body, no frontmatter)" }]
|
|
3279
|
+
},
|
|
3264
3280
|
"cursor": {
|
|
3265
3281
|
"skills": [{ "name": "string (kebab-case)", "description": "string", "content": "string (markdown body, no frontmatter)" }],
|
|
3266
3282
|
"rules": [{ "filename": "string.mdc", "content": "string (with frontmatter)" }]
|
|
@@ -3317,6 +3333,7 @@ Managed content:
|
|
|
3317
3333
|
Return a JSON object with this exact shape:
|
|
3318
3334
|
{
|
|
3319
3335
|
"updatedDocs": {
|
|
3336
|
+
"agentsMd": "<updated content or null>",
|
|
3320
3337
|
"claudeMd": "<updated content or null>",
|
|
3321
3338
|
"readmeMd": "<updated content or null>",
|
|
3322
3339
|
"cursorrules": "<updated content or null>",
|
|
@@ -3659,7 +3676,8 @@ function detectPlatforms() {
|
|
|
3659
3676
|
return {
|
|
3660
3677
|
claude: fs9.existsSync(path9.join(home, ".claude")),
|
|
3661
3678
|
cursor: fs9.existsSync(getCursorConfigDir()),
|
|
3662
|
-
codex: fs9.existsSync(path9.join(home, ".codex"))
|
|
3679
|
+
codex: fs9.existsSync(path9.join(home, ".codex")),
|
|
3680
|
+
opencode: fs9.existsSync(path9.join(home, ".config", "opencode"))
|
|
3663
3681
|
};
|
|
3664
3682
|
}
|
|
3665
3683
|
function scanLocalState(dir) {
|
|
@@ -3735,6 +3753,25 @@ function scanLocalState(dir) {
|
|
|
3735
3753
|
warnScanSkip(".agents/skills", error);
|
|
3736
3754
|
}
|
|
3737
3755
|
}
|
|
3756
|
+
const opencodeSkillsDir = path9.join(dir, ".opencode", "skills");
|
|
3757
|
+
if (fs9.existsSync(opencodeSkillsDir)) {
|
|
3758
|
+
try {
|
|
3759
|
+
for (const name of fs9.readdirSync(opencodeSkillsDir)) {
|
|
3760
|
+
const skillFile = path9.join(opencodeSkillsDir, name, "SKILL.md");
|
|
3761
|
+
if (fs9.existsSync(skillFile)) {
|
|
3762
|
+
items.push({
|
|
3763
|
+
type: "skill",
|
|
3764
|
+
platform: "opencode",
|
|
3765
|
+
name: `${name}/SKILL.md`,
|
|
3766
|
+
contentHash: hashFile(skillFile),
|
|
3767
|
+
path: skillFile
|
|
3768
|
+
});
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
} catch (error) {
|
|
3772
|
+
warnScanSkip(".opencode/skills", error);
|
|
3773
|
+
}
|
|
3774
|
+
}
|
|
3738
3775
|
const cursorrulesPath = path9.join(dir, ".cursorrules");
|
|
3739
3776
|
if (fs9.existsSync(cursorrulesPath)) {
|
|
3740
3777
|
items.push({
|
|
@@ -4553,15 +4590,15 @@ init_config();
|
|
|
4553
4590
|
// src/utils/dependencies.ts
|
|
4554
4591
|
import { readFileSync as readFileSync2 } from "fs";
|
|
4555
4592
|
import { join as join2 } from "path";
|
|
4556
|
-
function readFileOrNull2(
|
|
4593
|
+
function readFileOrNull2(path43) {
|
|
4557
4594
|
try {
|
|
4558
|
-
return readFileSync2(
|
|
4595
|
+
return readFileSync2(path43, "utf-8");
|
|
4559
4596
|
} catch {
|
|
4560
4597
|
return null;
|
|
4561
4598
|
}
|
|
4562
4599
|
}
|
|
4563
|
-
function readJsonOrNull(
|
|
4564
|
-
const content = readFileOrNull2(
|
|
4600
|
+
function readJsonOrNull(path43) {
|
|
4601
|
+
const content = readFileOrNull2(path43);
|
|
4565
4602
|
if (!content) return null;
|
|
4566
4603
|
try {
|
|
4567
4604
|
return JSON.parse(content);
|
|
@@ -4700,7 +4737,7 @@ function mergeSkillResults(results, setup) {
|
|
|
4700
4737
|
skills.push(skill);
|
|
4701
4738
|
platformObj.skills = skills;
|
|
4702
4739
|
setup[platform] = platformObj;
|
|
4703
|
-
const skillPath = platform === "codex" ? `.agents/skills/${skill.name}/SKILL.md` : `.${platform}/skills/${skill.name}/SKILL.md`;
|
|
4740
|
+
const skillPath = platform === "codex" ? `.agents/skills/${skill.name}/SKILL.md` : platform === "opencode" ? `.opencode/skills/${skill.name}/SKILL.md` : `.${platform}/skills/${skill.name}/SKILL.md`;
|
|
4704
4741
|
const descriptions = setup.fileDescriptions ?? {};
|
|
4705
4742
|
descriptions[skillPath] = skill.description.slice(0, 80);
|
|
4706
4743
|
setup.fileDescriptions = descriptions;
|
|
@@ -4713,7 +4750,7 @@ function mergeSkillResults(results, setup) {
|
|
|
4713
4750
|
}
|
|
4714
4751
|
function collectSkillTopics(setup, targetAgent, fingerprint) {
|
|
4715
4752
|
const topics = [];
|
|
4716
|
-
for (const platform of ["claude", "codex", "cursor"]) {
|
|
4753
|
+
for (const platform of ["claude", "codex", "opencode", "cursor"]) {
|
|
4717
4754
|
if (!targetAgent.includes(platform)) continue;
|
|
4718
4755
|
const platformObj = setup[platform];
|
|
4719
4756
|
const skillTopics = platformObj?.skillTopics;
|
|
@@ -5154,7 +5191,7 @@ ${f.content}
|
|
|
5154
5191
|
}
|
|
5155
5192
|
|
|
5156
5193
|
// src/writers/index.ts
|
|
5157
|
-
import
|
|
5194
|
+
import fs20 from "fs";
|
|
5158
5195
|
|
|
5159
5196
|
// src/writers/claude/index.ts
|
|
5160
5197
|
init_pre_commit_block();
|
|
@@ -5300,31 +5337,54 @@ function writeGithubCopilotConfig(config) {
|
|
|
5300
5337
|
return written;
|
|
5301
5338
|
}
|
|
5302
5339
|
|
|
5340
|
+
// src/writers/opencode/index.ts
|
|
5341
|
+
init_pre_commit_block();
|
|
5342
|
+
init_builtin_skills();
|
|
5343
|
+
import fs17 from "fs";
|
|
5344
|
+
import path17 from "path";
|
|
5345
|
+
function writeOpencodeConfig(config, agentsMdAlreadyWritten = false) {
|
|
5346
|
+
const written = [];
|
|
5347
|
+
if (!agentsMdAlreadyWritten) {
|
|
5348
|
+
fs17.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(config.agentsMd)));
|
|
5349
|
+
written.push("AGENTS.md");
|
|
5350
|
+
}
|
|
5351
|
+
if (config.skills?.length) {
|
|
5352
|
+
for (const skill of config.skills) {
|
|
5353
|
+
const skillDir = path17.join(".opencode", "skills", skill.name);
|
|
5354
|
+
if (!fs17.existsSync(skillDir)) fs17.mkdirSync(skillDir, { recursive: true });
|
|
5355
|
+
const skillPath = path17.join(skillDir, "SKILL.md");
|
|
5356
|
+
fs17.writeFileSync(skillPath, buildSkillContent(skill));
|
|
5357
|
+
written.push(skillPath);
|
|
5358
|
+
}
|
|
5359
|
+
}
|
|
5360
|
+
return written;
|
|
5361
|
+
}
|
|
5362
|
+
|
|
5303
5363
|
// src/writers/backup.ts
|
|
5304
|
-
import
|
|
5305
|
-
import
|
|
5364
|
+
import fs18 from "fs";
|
|
5365
|
+
import path18 from "path";
|
|
5306
5366
|
function createBackup(files) {
|
|
5307
5367
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5308
|
-
const backupDir =
|
|
5368
|
+
const backupDir = path18.join(BACKUPS_DIR, timestamp);
|
|
5309
5369
|
for (const file of files) {
|
|
5310
|
-
if (!
|
|
5311
|
-
const dest =
|
|
5312
|
-
const destDir =
|
|
5313
|
-
if (!
|
|
5314
|
-
|
|
5370
|
+
if (!fs18.existsSync(file)) continue;
|
|
5371
|
+
const dest = path18.join(backupDir, file);
|
|
5372
|
+
const destDir = path18.dirname(dest);
|
|
5373
|
+
if (!fs18.existsSync(destDir)) {
|
|
5374
|
+
fs18.mkdirSync(destDir, { recursive: true });
|
|
5315
5375
|
}
|
|
5316
|
-
|
|
5376
|
+
fs18.copyFileSync(file, dest);
|
|
5317
5377
|
}
|
|
5318
5378
|
return backupDir;
|
|
5319
5379
|
}
|
|
5320
5380
|
function restoreBackup(backupDir, file) {
|
|
5321
|
-
const backupFile =
|
|
5322
|
-
if (!
|
|
5323
|
-
const destDir =
|
|
5324
|
-
if (!
|
|
5325
|
-
|
|
5381
|
+
const backupFile = path18.join(backupDir, file);
|
|
5382
|
+
if (!fs18.existsSync(backupFile)) return false;
|
|
5383
|
+
const destDir = path18.dirname(file);
|
|
5384
|
+
if (!fs18.existsSync(destDir)) {
|
|
5385
|
+
fs18.mkdirSync(destDir, { recursive: true });
|
|
5326
5386
|
}
|
|
5327
|
-
|
|
5387
|
+
fs18.copyFileSync(backupFile, file);
|
|
5328
5388
|
return true;
|
|
5329
5389
|
}
|
|
5330
5390
|
|
|
@@ -5332,32 +5392,32 @@ function restoreBackup(backupDir, file) {
|
|
|
5332
5392
|
init_builtin_skills();
|
|
5333
5393
|
|
|
5334
5394
|
// src/writers/manifest.ts
|
|
5335
|
-
import
|
|
5395
|
+
import fs19 from "fs";
|
|
5336
5396
|
import crypto3 from "crypto";
|
|
5337
5397
|
function readManifest() {
|
|
5338
5398
|
try {
|
|
5339
|
-
if (!
|
|
5340
|
-
return JSON.parse(
|
|
5399
|
+
if (!fs19.existsSync(MANIFEST_FILE)) return null;
|
|
5400
|
+
return JSON.parse(fs19.readFileSync(MANIFEST_FILE, "utf-8"));
|
|
5341
5401
|
} catch {
|
|
5342
5402
|
return null;
|
|
5343
5403
|
}
|
|
5344
5404
|
}
|
|
5345
5405
|
function writeManifest(manifest) {
|
|
5346
|
-
if (!
|
|
5347
|
-
|
|
5406
|
+
if (!fs19.existsSync(CALIBER_DIR)) {
|
|
5407
|
+
fs19.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
5348
5408
|
}
|
|
5349
|
-
|
|
5409
|
+
fs19.writeFileSync(MANIFEST_FILE, JSON.stringify(manifest, null, 2));
|
|
5350
5410
|
}
|
|
5351
5411
|
function fileChecksum(filePath) {
|
|
5352
|
-
const content =
|
|
5412
|
+
const content = fs19.readFileSync(filePath);
|
|
5353
5413
|
return crypto3.createHash("sha256").update(content).digest("hex");
|
|
5354
5414
|
}
|
|
5355
5415
|
|
|
5356
5416
|
// src/writers/index.ts
|
|
5357
5417
|
function writeSetup(setup) {
|
|
5358
5418
|
const filesToWrite = getFilesToWrite(setup);
|
|
5359
|
-
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) =>
|
|
5360
|
-
const existingFiles = [...filesToWrite.filter((f) =>
|
|
5419
|
+
const filesToDelete = (setup.deletions || []).map((d) => d.filePath).filter((f) => fs20.existsSync(f));
|
|
5420
|
+
const existingFiles = [...filesToWrite.filter((f) => fs20.existsSync(f)), ...filesToDelete];
|
|
5361
5421
|
const backupDir = existingFiles.length > 0 ? createBackup(existingFiles) : void 0;
|
|
5362
5422
|
const written = [];
|
|
5363
5423
|
if (setup.targetAgent.includes("claude") && setup.claude) {
|
|
@@ -5369,12 +5429,16 @@ function writeSetup(setup) {
|
|
|
5369
5429
|
if (setup.targetAgent.includes("codex") && setup.codex) {
|
|
5370
5430
|
written.push(...writeCodexConfig(setup.codex));
|
|
5371
5431
|
}
|
|
5432
|
+
if (setup.targetAgent.includes("opencode") && setup.opencode) {
|
|
5433
|
+
const agentsMdAlreadyWritten = written.includes("AGENTS.md");
|
|
5434
|
+
written.push(...writeOpencodeConfig(setup.opencode, agentsMdAlreadyWritten));
|
|
5435
|
+
}
|
|
5372
5436
|
if (setup.targetAgent.includes("github-copilot") && setup.copilot) {
|
|
5373
5437
|
written.push(...writeGithubCopilotConfig(setup.copilot));
|
|
5374
5438
|
}
|
|
5375
5439
|
const deleted = [];
|
|
5376
5440
|
for (const filePath of filesToDelete) {
|
|
5377
|
-
|
|
5441
|
+
fs20.unlinkSync(filePath);
|
|
5378
5442
|
deleted.push(filePath);
|
|
5379
5443
|
}
|
|
5380
5444
|
written.push(...ensureBuiltinSkills());
|
|
@@ -5405,8 +5469,8 @@ function undoSetup() {
|
|
|
5405
5469
|
const removed = [];
|
|
5406
5470
|
for (const entry of manifest.entries) {
|
|
5407
5471
|
if (entry.action === "created") {
|
|
5408
|
-
if (
|
|
5409
|
-
|
|
5472
|
+
if (fs20.existsSync(entry.path)) {
|
|
5473
|
+
fs20.unlinkSync(entry.path);
|
|
5410
5474
|
removed.push(entry.path);
|
|
5411
5475
|
}
|
|
5412
5476
|
} else if ((entry.action === "modified" || entry.action === "deleted") && manifest.backupDir) {
|
|
@@ -5415,8 +5479,8 @@ function undoSetup() {
|
|
|
5415
5479
|
}
|
|
5416
5480
|
}
|
|
5417
5481
|
}
|
|
5418
|
-
if (
|
|
5419
|
-
|
|
5482
|
+
if (fs20.existsSync(MANIFEST_FILE)) {
|
|
5483
|
+
fs20.unlinkSync(MANIFEST_FILE);
|
|
5420
5484
|
}
|
|
5421
5485
|
return { restored, removed };
|
|
5422
5486
|
}
|
|
@@ -5447,6 +5511,14 @@ function getFilesToWrite(setup) {
|
|
|
5447
5511
|
for (const s of setup.codex.skills) files.push(`.agents/skills/${s.name}/SKILL.md`);
|
|
5448
5512
|
}
|
|
5449
5513
|
}
|
|
5514
|
+
if (setup.targetAgent.includes("opencode") && setup.opencode) {
|
|
5515
|
+
if (!setup.targetAgent.includes("codex")) {
|
|
5516
|
+
files.push("AGENTS.md");
|
|
5517
|
+
}
|
|
5518
|
+
if (setup.opencode.skills) {
|
|
5519
|
+
for (const s of setup.opencode.skills) files.push(`.opencode/skills/${s.name}/SKILL.md`);
|
|
5520
|
+
}
|
|
5521
|
+
}
|
|
5450
5522
|
if (setup.targetAgent.includes("github-copilot") && setup.copilot) {
|
|
5451
5523
|
if (setup.copilot.instructions) files.push(".github/copilot-instructions.md");
|
|
5452
5524
|
if (setup.copilot.instructionFiles) {
|
|
@@ -5458,22 +5530,22 @@ function getFilesToWrite(setup) {
|
|
|
5458
5530
|
}
|
|
5459
5531
|
function ensureGitignore() {
|
|
5460
5532
|
const gitignorePath = ".gitignore";
|
|
5461
|
-
if (
|
|
5462
|
-
const content =
|
|
5533
|
+
if (fs20.existsSync(gitignorePath)) {
|
|
5534
|
+
const content = fs20.readFileSync(gitignorePath, "utf-8");
|
|
5463
5535
|
if (!content.includes(".caliber/")) {
|
|
5464
|
-
|
|
5536
|
+
fs20.appendFileSync(gitignorePath, "\n# Caliber local state\n.caliber/\n");
|
|
5465
5537
|
}
|
|
5466
5538
|
} else {
|
|
5467
|
-
|
|
5539
|
+
fs20.writeFileSync(gitignorePath, "# Caliber local state\n.caliber/\n");
|
|
5468
5540
|
}
|
|
5469
5541
|
}
|
|
5470
5542
|
|
|
5471
5543
|
// src/writers/staging.ts
|
|
5472
|
-
import
|
|
5473
|
-
import
|
|
5474
|
-
var STAGED_DIR =
|
|
5475
|
-
var PROPOSED_DIR =
|
|
5476
|
-
var CURRENT_DIR =
|
|
5544
|
+
import fs21 from "fs";
|
|
5545
|
+
import path19 from "path";
|
|
5546
|
+
var STAGED_DIR = path19.join(CALIBER_DIR, "staged");
|
|
5547
|
+
var PROPOSED_DIR = path19.join(STAGED_DIR, "proposed");
|
|
5548
|
+
var CURRENT_DIR = path19.join(STAGED_DIR, "current");
|
|
5477
5549
|
function normalizeContent(content) {
|
|
5478
5550
|
return content.split("\n").map((line) => line.trimEnd()).join("\n").replace(/\n{3,}/g, "\n\n").trim();
|
|
5479
5551
|
}
|
|
@@ -5484,20 +5556,20 @@ function stageFiles(files, projectDir) {
|
|
|
5484
5556
|
const stagedFiles = [];
|
|
5485
5557
|
for (const file of files) {
|
|
5486
5558
|
assertPathWithinDir(file.path, projectDir);
|
|
5487
|
-
const originalPath =
|
|
5488
|
-
if (
|
|
5489
|
-
const existing =
|
|
5559
|
+
const originalPath = path19.join(projectDir, file.path);
|
|
5560
|
+
if (fs21.existsSync(originalPath)) {
|
|
5561
|
+
const existing = fs21.readFileSync(originalPath, "utf-8");
|
|
5490
5562
|
if (normalizeContent(existing) === normalizeContent(file.content)) {
|
|
5491
5563
|
continue;
|
|
5492
5564
|
}
|
|
5493
5565
|
}
|
|
5494
|
-
const proposedPath =
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
if (
|
|
5498
|
-
const currentPath =
|
|
5499
|
-
|
|
5500
|
-
|
|
5566
|
+
const proposedPath = path19.join(PROPOSED_DIR, file.path);
|
|
5567
|
+
fs21.mkdirSync(path19.dirname(proposedPath), { recursive: true });
|
|
5568
|
+
fs21.writeFileSync(proposedPath, file.content);
|
|
5569
|
+
if (fs21.existsSync(originalPath)) {
|
|
5570
|
+
const currentPath = path19.join(CURRENT_DIR, file.path);
|
|
5571
|
+
fs21.mkdirSync(path19.dirname(currentPath), { recursive: true });
|
|
5572
|
+
fs21.copyFileSync(originalPath, currentPath);
|
|
5501
5573
|
modifiedFiles++;
|
|
5502
5574
|
stagedFiles.push({
|
|
5503
5575
|
relativePath: file.path,
|
|
@@ -5514,14 +5586,14 @@ function stageFiles(files, projectDir) {
|
|
|
5514
5586
|
return { newFiles, modifiedFiles, stagedFiles };
|
|
5515
5587
|
}
|
|
5516
5588
|
function cleanupStaging() {
|
|
5517
|
-
if (
|
|
5518
|
-
|
|
5589
|
+
if (fs21.existsSync(STAGED_DIR)) {
|
|
5590
|
+
fs21.rmSync(STAGED_DIR, { recursive: true, force: true });
|
|
5519
5591
|
}
|
|
5520
5592
|
}
|
|
5521
5593
|
|
|
5522
5594
|
// src/commands/setup-files.ts
|
|
5523
5595
|
init_builtin_skills();
|
|
5524
|
-
import
|
|
5596
|
+
import fs22 from "fs";
|
|
5525
5597
|
function collectSetupFiles(setup, targetAgent) {
|
|
5526
5598
|
const files = [];
|
|
5527
5599
|
const claude = setup.claude;
|
|
@@ -5588,6 +5660,27 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
5588
5660
|
}
|
|
5589
5661
|
}
|
|
5590
5662
|
}
|
|
5663
|
+
const opencode = setup.opencode;
|
|
5664
|
+
if (opencode) {
|
|
5665
|
+
if (opencode.agentsMd && !files.some((f) => f.path === "AGENTS.md")) {
|
|
5666
|
+
files.push({ path: "AGENTS.md", content: opencode.agentsMd });
|
|
5667
|
+
}
|
|
5668
|
+
const opencodeSkills = opencode.skills;
|
|
5669
|
+
if (Array.isArray(opencodeSkills)) {
|
|
5670
|
+
for (const skill of opencodeSkills) {
|
|
5671
|
+
files.push({
|
|
5672
|
+
path: `.opencode/skills/${sanitizePath(skill.name)}/SKILL.md`,
|
|
5673
|
+
content: buildSkillContent(skill)
|
|
5674
|
+
});
|
|
5675
|
+
}
|
|
5676
|
+
}
|
|
5677
|
+
for (const builtin of BUILTIN_SKILLS) {
|
|
5678
|
+
files.push({
|
|
5679
|
+
path: `.opencode/skills/${builtin.name}/SKILL.md`,
|
|
5680
|
+
content: buildSkillContent(builtin)
|
|
5681
|
+
});
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5591
5684
|
const copilot = setup.copilot;
|
|
5592
5685
|
if (copilot) {
|
|
5593
5686
|
if (copilot.instructions)
|
|
@@ -5606,7 +5699,8 @@ function collectSetupFiles(setup, targetAgent) {
|
|
|
5606
5699
|
}
|
|
5607
5700
|
}
|
|
5608
5701
|
const codexTargeted = targetAgent ? targetAgent.includes("codex") : false;
|
|
5609
|
-
|
|
5702
|
+
const opencodeTargeted = targetAgent ? targetAgent.includes("opencode") : false;
|
|
5703
|
+
if ((codexTargeted || opencodeTargeted) && !fs22.existsSync("AGENTS.md") && !(codex && codex.agentsMd) && !(opencode && opencode.agentsMd)) {
|
|
5610
5704
|
const agentRefs = [];
|
|
5611
5705
|
if (claude) agentRefs.push("See `CLAUDE.md` for Claude Code configuration.");
|
|
5612
5706
|
if (cursor) agentRefs.push("See `.cursor/rules/` for Cursor rules.");
|
|
@@ -5625,9 +5719,9 @@ ${agentRefs.join(" ")}
|
|
|
5625
5719
|
|
|
5626
5720
|
// src/lib/learning-hooks.ts
|
|
5627
5721
|
init_resolve_caliber();
|
|
5628
|
-
import
|
|
5629
|
-
import
|
|
5630
|
-
var SETTINGS_PATH2 =
|
|
5722
|
+
import fs23 from "fs";
|
|
5723
|
+
import path20 from "path";
|
|
5724
|
+
var SETTINGS_PATH2 = path20.join(".claude", "settings.json");
|
|
5631
5725
|
var HOOK_TAILS = [
|
|
5632
5726
|
{ event: "PostToolUse", tail: "learn observe", description: "Caliber: recording tool usage for session learning" },
|
|
5633
5727
|
{ event: "PostToolUseFailure", tail: "learn observe --failure", description: "Caliber: recording tool failure for session learning" },
|
|
@@ -5644,17 +5738,17 @@ function getHookConfigs() {
|
|
|
5644
5738
|
}));
|
|
5645
5739
|
}
|
|
5646
5740
|
function readSettings2() {
|
|
5647
|
-
if (!
|
|
5741
|
+
if (!fs23.existsSync(SETTINGS_PATH2)) return {};
|
|
5648
5742
|
try {
|
|
5649
|
-
return JSON.parse(
|
|
5743
|
+
return JSON.parse(fs23.readFileSync(SETTINGS_PATH2, "utf-8"));
|
|
5650
5744
|
} catch {
|
|
5651
5745
|
return {};
|
|
5652
5746
|
}
|
|
5653
5747
|
}
|
|
5654
5748
|
function writeSettings2(settings) {
|
|
5655
|
-
const dir =
|
|
5656
|
-
if (!
|
|
5657
|
-
|
|
5749
|
+
const dir = path20.dirname(SETTINGS_PATH2);
|
|
5750
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
5751
|
+
fs23.writeFileSync(SETTINGS_PATH2, JSON.stringify(settings, null, 2));
|
|
5658
5752
|
}
|
|
5659
5753
|
function hasLearningHook(matchers, tail) {
|
|
5660
5754
|
return matchers.some((entry) => entry.hooks?.some((h) => isCaliberCommand(h.command, tail)));
|
|
@@ -5688,7 +5782,7 @@ function installLearningHooks() {
|
|
|
5688
5782
|
writeSettings2(settings);
|
|
5689
5783
|
return { installed: true, alreadyInstalled: false };
|
|
5690
5784
|
}
|
|
5691
|
-
var CURSOR_HOOKS_PATH =
|
|
5785
|
+
var CURSOR_HOOKS_PATH = path20.join(".cursor", "hooks.json");
|
|
5692
5786
|
var CURSOR_HOOK_EVENTS = [
|
|
5693
5787
|
{ event: "postToolUse", tail: "learn observe" },
|
|
5694
5788
|
{ event: "postToolUseFailure", tail: "learn observe --failure" },
|
|
@@ -5696,17 +5790,17 @@ var CURSOR_HOOK_EVENTS = [
|
|
|
5696
5790
|
{ event: "sessionEnd", tail: "learn finalize --auto" }
|
|
5697
5791
|
];
|
|
5698
5792
|
function readCursorHooks() {
|
|
5699
|
-
if (!
|
|
5793
|
+
if (!fs23.existsSync(CURSOR_HOOKS_PATH)) return { version: 1, hooks: {} };
|
|
5700
5794
|
try {
|
|
5701
|
-
return JSON.parse(
|
|
5795
|
+
return JSON.parse(fs23.readFileSync(CURSOR_HOOKS_PATH, "utf-8"));
|
|
5702
5796
|
} catch {
|
|
5703
5797
|
return { version: 1, hooks: {} };
|
|
5704
5798
|
}
|
|
5705
5799
|
}
|
|
5706
5800
|
function writeCursorHooks(config) {
|
|
5707
|
-
const dir =
|
|
5708
|
-
if (!
|
|
5709
|
-
|
|
5801
|
+
const dir = path20.dirname(CURSOR_HOOKS_PATH);
|
|
5802
|
+
if (!fs23.existsSync(dir)) fs23.mkdirSync(dir, { recursive: true });
|
|
5803
|
+
fs23.writeFileSync(CURSOR_HOOKS_PATH, JSON.stringify(config, null, 2));
|
|
5710
5804
|
}
|
|
5711
5805
|
function hasCursorHook(entries, tail) {
|
|
5712
5806
|
return entries.some((e) => isCaliberCommand(e.command, tail));
|
|
@@ -5778,22 +5872,22 @@ function removeLearningHooks() {
|
|
|
5778
5872
|
init_resolve_caliber();
|
|
5779
5873
|
|
|
5780
5874
|
// src/lib/state.ts
|
|
5781
|
-
import
|
|
5782
|
-
import
|
|
5875
|
+
import fs24 from "fs";
|
|
5876
|
+
import path21 from "path";
|
|
5783
5877
|
import { execSync as execSync9 } from "child_process";
|
|
5784
|
-
var STATE_FILE =
|
|
5878
|
+
var STATE_FILE = path21.join(CALIBER_DIR, ".caliber-state.json");
|
|
5785
5879
|
function normalizeTargetAgent(value) {
|
|
5786
5880
|
if (Array.isArray(value)) return value;
|
|
5787
5881
|
if (typeof value === "string") {
|
|
5788
5882
|
if (value === "both") return ["claude", "cursor"];
|
|
5789
|
-
if (["claude", "cursor", "codex", "github-copilot"].includes(value)) return [value];
|
|
5883
|
+
if (["claude", "cursor", "codex", "opencode", "github-copilot"].includes(value)) return [value];
|
|
5790
5884
|
}
|
|
5791
5885
|
return void 0;
|
|
5792
5886
|
}
|
|
5793
5887
|
function readState() {
|
|
5794
5888
|
try {
|
|
5795
|
-
if (!
|
|
5796
|
-
const raw = JSON.parse(
|
|
5889
|
+
if (!fs24.existsSync(STATE_FILE)) return null;
|
|
5890
|
+
const raw = JSON.parse(fs24.readFileSync(STATE_FILE, "utf-8"));
|
|
5797
5891
|
if (raw.targetAgent) raw.targetAgent = normalizeTargetAgent(raw.targetAgent);
|
|
5798
5892
|
return raw;
|
|
5799
5893
|
} catch {
|
|
@@ -5801,10 +5895,10 @@ function readState() {
|
|
|
5801
5895
|
}
|
|
5802
5896
|
}
|
|
5803
5897
|
function writeState(state) {
|
|
5804
|
-
if (!
|
|
5805
|
-
|
|
5898
|
+
if (!fs24.existsSync(CALIBER_DIR)) {
|
|
5899
|
+
fs24.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
5806
5900
|
}
|
|
5807
|
-
|
|
5901
|
+
fs24.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
5808
5902
|
}
|
|
5809
5903
|
function getCurrentHeadSha() {
|
|
5810
5904
|
try {
|
|
@@ -6127,7 +6221,8 @@ function checkExistence(dir) {
|
|
|
6127
6221
|
});
|
|
6128
6222
|
const claudeSkills = countFiles(join3(dir, ".claude", "skills"), /\.(md|SKILL\.md)$/);
|
|
6129
6223
|
const codexSkills = countFiles(join3(dir, ".agents", "skills"), /SKILL\.md$/);
|
|
6130
|
-
const
|
|
6224
|
+
const opencodeSkills = countFiles(join3(dir, ".opencode", "skills"), /SKILL\.md$/);
|
|
6225
|
+
const skillCount = claudeSkills.length + codexSkills.length + opencodeSkills.length;
|
|
6131
6226
|
const skillBase = skillCount >= 1 ? POINTS_SKILLS_EXIST : 0;
|
|
6132
6227
|
const skillBonus = Math.min((skillCount - 1) * POINTS_SKILLS_BONUS_PER_EXTRA, POINTS_SKILLS_BONUS_CAP);
|
|
6133
6228
|
const skillPoints = skillCount >= 1 ? skillBase + Math.max(0, skillBonus) : 0;
|
|
@@ -6861,25 +6956,29 @@ function checkSources(dir) {
|
|
|
6861
6956
|
}
|
|
6862
6957
|
|
|
6863
6958
|
// src/scoring/dismissed.ts
|
|
6864
|
-
import
|
|
6865
|
-
import
|
|
6866
|
-
var DISMISSED_FILE =
|
|
6867
|
-
function
|
|
6959
|
+
import fs25 from "fs";
|
|
6960
|
+
import path22 from "path";
|
|
6961
|
+
var DISMISSED_FILE = path22.join(CALIBER_DIR, "dismissed-checks.json");
|
|
6962
|
+
function dismissedFilePath(dir) {
|
|
6963
|
+
return dir ? path22.join(dir, CALIBER_DIR, "dismissed-checks.json") : DISMISSED_FILE;
|
|
6964
|
+
}
|
|
6965
|
+
function readDismissedChecks(dir) {
|
|
6868
6966
|
try {
|
|
6869
|
-
|
|
6870
|
-
|
|
6967
|
+
const filePath = dismissedFilePath(dir);
|
|
6968
|
+
if (!fs25.existsSync(filePath)) return [];
|
|
6969
|
+
return JSON.parse(fs25.readFileSync(filePath, "utf-8"));
|
|
6871
6970
|
} catch {
|
|
6872
6971
|
return [];
|
|
6873
6972
|
}
|
|
6874
6973
|
}
|
|
6875
6974
|
function writeDismissedChecks(checks) {
|
|
6876
|
-
if (!
|
|
6877
|
-
|
|
6975
|
+
if (!fs25.existsSync(CALIBER_DIR)) {
|
|
6976
|
+
fs25.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
6878
6977
|
}
|
|
6879
|
-
|
|
6978
|
+
fs25.writeFileSync(DISMISSED_FILE, JSON.stringify(checks, null, 2) + "\n");
|
|
6880
6979
|
}
|
|
6881
|
-
function getDismissedIds() {
|
|
6882
|
-
return new Set(readDismissedChecks().map((c) => c.id));
|
|
6980
|
+
function getDismissedIds(dir) {
|
|
6981
|
+
return new Set(readDismissedChecks(dir).map((c) => c.id));
|
|
6883
6982
|
}
|
|
6884
6983
|
|
|
6885
6984
|
// src/scoring/index.ts
|
|
@@ -6894,11 +6993,11 @@ function filterChecksForTarget(checks, target) {
|
|
|
6894
6993
|
return checks.filter((c) => {
|
|
6895
6994
|
if (CLAUDE_ONLY_CHECKS.has(c.id)) return target.includes("claude");
|
|
6896
6995
|
if (CURSOR_ONLY_CHECKS.has(c.id)) return target.includes("cursor");
|
|
6897
|
-
if (CODEX_ONLY_CHECKS.has(c.id)) return target.includes("codex");
|
|
6996
|
+
if (CODEX_ONLY_CHECKS.has(c.id)) return target.includes("codex") || target.includes("opencode");
|
|
6898
6997
|
if (COPILOT_ONLY_CHECKS.has(c.id)) return target.includes("github-copilot");
|
|
6899
6998
|
if (BOTH_ONLY_CHECKS.has(c.id)) return target.includes("claude") && target.includes("cursor");
|
|
6900
|
-
if (NON_CODEX_CHECKS.has(c.id)) return !target.includes("codex");
|
|
6901
|
-
if (CLAUDE_OR_CODEX_CHECKS.has(c.id)) return target.includes("claude") || target.includes("codex");
|
|
6999
|
+
if (NON_CODEX_CHECKS.has(c.id)) return !target.includes("codex") && !target.includes("opencode");
|
|
7000
|
+
if (CLAUDE_OR_CODEX_CHECKS.has(c.id)) return target.includes("claude") || target.includes("codex") || target.includes("opencode");
|
|
6902
7001
|
return true;
|
|
6903
7002
|
});
|
|
6904
7003
|
}
|
|
@@ -6907,6 +7006,7 @@ function detectTargetAgent(dir) {
|
|
|
6907
7006
|
if (existsSync7(join9(dir, "CLAUDE.md")) || existsSync7(join9(dir, ".claude", "skills"))) agents.push("claude");
|
|
6908
7007
|
if (existsSync7(join9(dir, ".cursorrules")) || existsSync7(join9(dir, ".cursor", "rules"))) agents.push("cursor");
|
|
6909
7008
|
if (existsSync7(join9(dir, ".codex")) || existsSync7(join9(dir, ".agents", "skills")) || existsSync7(join9(dir, "AGENTS.md"))) agents.push("codex");
|
|
7009
|
+
if (existsSync7(join9(dir, ".opencode"))) agents.push("opencode");
|
|
6910
7010
|
if (existsSync7(join9(dir, ".github", "copilot-instructions.md")) || existsSync7(join9(dir, ".github", "instructions"))) agents.push("github-copilot");
|
|
6911
7011
|
return agents.length > 0 ? agents : ["claude"];
|
|
6912
7012
|
}
|
|
@@ -6921,7 +7021,7 @@ function computeLocalScore(dir, targetAgent) {
|
|
|
6921
7021
|
...checkBonus(dir),
|
|
6922
7022
|
...checkSources(dir)
|
|
6923
7023
|
];
|
|
6924
|
-
const dismissed = getDismissedIds();
|
|
7024
|
+
const dismissed = getDismissedIds(dir);
|
|
6925
7025
|
const checks = filterChecksForTarget(allChecks, target).filter((c) => !dismissed.has(c.id));
|
|
6926
7026
|
const maxPossible = checks.reduce((s, c) => s + c.maxPoints, 0);
|
|
6927
7027
|
const earned = checks.reduce((s, c) => s + c.earnedPoints, 0);
|
|
@@ -7131,27 +7231,27 @@ import { PostHog } from "posthog-node";
|
|
|
7131
7231
|
import chalk5 from "chalk";
|
|
7132
7232
|
|
|
7133
7233
|
// src/telemetry/config.ts
|
|
7134
|
-
import
|
|
7135
|
-
import
|
|
7234
|
+
import fs26 from "fs";
|
|
7235
|
+
import path23 from "path";
|
|
7136
7236
|
import os5 from "os";
|
|
7137
7237
|
import crypto4 from "crypto";
|
|
7138
7238
|
import { execSync as execSync13 } from "child_process";
|
|
7139
|
-
var CONFIG_DIR2 =
|
|
7140
|
-
var CONFIG_FILE2 =
|
|
7239
|
+
var CONFIG_DIR2 = path23.join(os5.homedir(), ".caliber");
|
|
7240
|
+
var CONFIG_FILE2 = path23.join(CONFIG_DIR2, "config.json");
|
|
7141
7241
|
var runtimeDisabled = false;
|
|
7142
7242
|
function readConfig() {
|
|
7143
7243
|
try {
|
|
7144
|
-
if (!
|
|
7145
|
-
return JSON.parse(
|
|
7244
|
+
if (!fs26.existsSync(CONFIG_FILE2)) return {};
|
|
7245
|
+
return JSON.parse(fs26.readFileSync(CONFIG_FILE2, "utf-8"));
|
|
7146
7246
|
} catch {
|
|
7147
7247
|
return {};
|
|
7148
7248
|
}
|
|
7149
7249
|
}
|
|
7150
7250
|
function writeConfig(config) {
|
|
7151
|
-
if (!
|
|
7152
|
-
|
|
7251
|
+
if (!fs26.existsSync(CONFIG_DIR2)) {
|
|
7252
|
+
fs26.mkdirSync(CONFIG_DIR2, { recursive: true });
|
|
7153
7253
|
}
|
|
7154
|
-
|
|
7254
|
+
fs26.writeFileSync(CONFIG_FILE2, JSON.stringify(config, null, 2) + "\n", { mode: 384 });
|
|
7155
7255
|
}
|
|
7156
7256
|
function getMachineId() {
|
|
7157
7257
|
const config = readConfig();
|
|
@@ -7320,8 +7420,8 @@ function trackInitSkillsSearch(searched, installedCount) {
|
|
|
7320
7420
|
function trackInitScoreRegression(oldScore, newScore) {
|
|
7321
7421
|
trackEvent("init_score_regression", { old_score: oldScore, new_score: newScore });
|
|
7322
7422
|
}
|
|
7323
|
-
function trackInitCompleted(
|
|
7324
|
-
trackEvent("init_completed", { path:
|
|
7423
|
+
function trackInitCompleted(path43, score) {
|
|
7424
|
+
trackEvent("init_completed", { path: path43, score });
|
|
7325
7425
|
}
|
|
7326
7426
|
function trackRegenerateCompleted(action, durationMs) {
|
|
7327
7427
|
trackEvent("regenerate_completed", { action, duration_ms: durationMs });
|
|
@@ -7400,7 +7500,7 @@ function sanitizeSlug(slug) {
|
|
|
7400
7500
|
function getSkillPath(platform, slug) {
|
|
7401
7501
|
const safe = sanitizeSlug(slug);
|
|
7402
7502
|
if (!safe) throw new Error(`Invalid skill slug: "${slug}"`);
|
|
7403
|
-
const baseDir = platform === "cursor" ? join10(".cursor", "skills") : platform === "codex" ? join10(".agents", "skills") : join10(".claude", "skills");
|
|
7503
|
+
const baseDir = platform === "cursor" ? join10(".cursor", "skills") : platform === "codex" ? join10(".agents", "skills") : platform === "opencode" ? join10(".opencode", "skills") : join10(".claude", "skills");
|
|
7404
7504
|
const cwd = process.cwd();
|
|
7405
7505
|
const fullPath = resolve2(cwd, baseDir, safe, "SKILL.md");
|
|
7406
7506
|
if (!fullPath.startsWith(resolve2(cwd, baseDir) + "/")) {
|
|
@@ -7411,6 +7511,7 @@ function getSkillPath(platform, slug) {
|
|
|
7411
7511
|
function getSkillDir(platform) {
|
|
7412
7512
|
if (platform === "cursor") return join10(process.cwd(), ".cursor", "skills");
|
|
7413
7513
|
if (platform === "codex") return join10(process.cwd(), ".agents", "skills");
|
|
7514
|
+
if (platform === "opencode") return join10(process.cwd(), ".opencode", "skills");
|
|
7414
7515
|
return join10(process.cwd(), ".claude", "skills");
|
|
7415
7516
|
}
|
|
7416
7517
|
function getInstalledSkills(platforms) {
|
|
@@ -8315,11 +8416,11 @@ function countIssuePoints(issues) {
|
|
|
8315
8416
|
}
|
|
8316
8417
|
async function scoreAndRefine(setup, dir, sessionHistory, callbacks) {
|
|
8317
8418
|
const existsCache = /* @__PURE__ */ new Map();
|
|
8318
|
-
const cachedExists = (
|
|
8319
|
-
const cached = existsCache.get(
|
|
8419
|
+
const cachedExists = (path43) => {
|
|
8420
|
+
const cached = existsCache.get(path43);
|
|
8320
8421
|
if (cached !== void 0) return cached;
|
|
8321
|
-
const result = existsSync9(
|
|
8322
|
-
existsCache.set(
|
|
8422
|
+
const result = existsSync9(path43);
|
|
8423
|
+
existsCache.set(path43, result);
|
|
8323
8424
|
return result;
|
|
8324
8425
|
};
|
|
8325
8426
|
const projectStructure = collectProjectStructure(dir);
|
|
@@ -8458,8 +8559,8 @@ async function runScoreRefineWithSpinner(setup, dir, sessionHistory) {
|
|
|
8458
8559
|
}
|
|
8459
8560
|
|
|
8460
8561
|
// src/lib/debug-report.ts
|
|
8461
|
-
import
|
|
8462
|
-
import
|
|
8562
|
+
import fs27 from "fs";
|
|
8563
|
+
import path24 from "path";
|
|
8463
8564
|
var DebugReport = class {
|
|
8464
8565
|
sections = [];
|
|
8465
8566
|
startTime;
|
|
@@ -8528,11 +8629,11 @@ var DebugReport = class {
|
|
|
8528
8629
|
lines.push(`| **Total** | **${formatMs(totalMs)}** |`);
|
|
8529
8630
|
lines.push("");
|
|
8530
8631
|
}
|
|
8531
|
-
const dir =
|
|
8532
|
-
if (!
|
|
8533
|
-
|
|
8632
|
+
const dir = path24.dirname(outputPath);
|
|
8633
|
+
if (!fs27.existsSync(dir)) {
|
|
8634
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
8534
8635
|
}
|
|
8535
|
-
|
|
8636
|
+
fs27.writeFileSync(outputPath, lines.join("\n"));
|
|
8536
8637
|
}
|
|
8537
8638
|
};
|
|
8538
8639
|
function formatMs(ms) {
|
|
@@ -8933,7 +9034,7 @@ import chalk11 from "chalk";
|
|
|
8933
9034
|
import ora3 from "ora";
|
|
8934
9035
|
import select5 from "@inquirer/select";
|
|
8935
9036
|
import checkbox from "@inquirer/checkbox";
|
|
8936
|
-
import
|
|
9037
|
+
import fs30 from "fs";
|
|
8937
9038
|
|
|
8938
9039
|
// src/ai/refine.ts
|
|
8939
9040
|
async function refineSetup(currentSetup, message, conversationHistory, callbacks) {
|
|
@@ -9074,10 +9175,11 @@ init_config();
|
|
|
9074
9175
|
init_review();
|
|
9075
9176
|
function detectAgents(dir) {
|
|
9076
9177
|
const agents = [];
|
|
9077
|
-
if (
|
|
9078
|
-
if (
|
|
9079
|
-
if (
|
|
9080
|
-
if (
|
|
9178
|
+
if (fs30.existsSync(`${dir}/.claude`)) agents.push("claude");
|
|
9179
|
+
if (fs30.existsSync(`${dir}/.cursor`)) agents.push("cursor");
|
|
9180
|
+
if (fs30.existsSync(`${dir}/.agents`) || fs30.existsSync(`${dir}/AGENTS.md`)) agents.push("codex");
|
|
9181
|
+
if (fs30.existsSync(`${dir}/.opencode`)) agents.push("opencode");
|
|
9182
|
+
if (fs30.existsSync(`${dir}/.github/copilot-instructions.md`)) agents.push("github-copilot");
|
|
9081
9183
|
return agents;
|
|
9082
9184
|
}
|
|
9083
9185
|
async function promptAgent(detected) {
|
|
@@ -9085,6 +9187,7 @@ async function promptAgent(detected) {
|
|
|
9085
9187
|
{ name: "Claude Code", value: "claude", checked: detected?.includes("claude") ?? false },
|
|
9086
9188
|
{ name: "Cursor", value: "cursor", checked: detected?.includes("cursor") ?? false },
|
|
9087
9189
|
{ name: "Codex (OpenAI)", value: "codex", checked: detected?.includes("codex") ?? false },
|
|
9190
|
+
{ name: "OpenCode", value: "opencode", checked: detected?.includes("opencode") ?? false },
|
|
9088
9191
|
{ name: "GitHub Copilot", value: "github-copilot", checked: detected?.includes("github-copilot") ?? false }
|
|
9089
9192
|
];
|
|
9090
9193
|
const hasDefaults = detected && detected.length > 0;
|
|
@@ -9180,24 +9283,26 @@ async function refineLoop(currentSetup, sessionHistory, summarizeSetup2, printSu
|
|
|
9180
9283
|
|
|
9181
9284
|
// src/commands/init-display.ts
|
|
9182
9285
|
import chalk12 from "chalk";
|
|
9183
|
-
import
|
|
9286
|
+
import fs31 from "fs";
|
|
9184
9287
|
function formatWhatChanged(setup) {
|
|
9185
9288
|
const lines = [];
|
|
9186
9289
|
const claude = setup.claude;
|
|
9187
9290
|
const codex = setup.codex;
|
|
9188
9291
|
const cursor = setup.cursor;
|
|
9189
9292
|
if (claude?.claudeMd) {
|
|
9190
|
-
const action =
|
|
9293
|
+
const action = fs31.existsSync("CLAUDE.md") ? "Updated" : "Created";
|
|
9191
9294
|
lines.push(`${action} CLAUDE.md`);
|
|
9192
9295
|
}
|
|
9193
|
-
|
|
9194
|
-
|
|
9296
|
+
const opencode = setup.opencode;
|
|
9297
|
+
if (codex?.agentsMd || opencode?.agentsMd) {
|
|
9298
|
+
const action = fs31.existsSync("AGENTS.md") ? "Updated" : "Created";
|
|
9195
9299
|
lines.push(`${action} AGENTS.md`);
|
|
9196
9300
|
}
|
|
9197
9301
|
const allSkills = [];
|
|
9198
9302
|
for (const [_platform, obj] of [
|
|
9199
9303
|
["claude", claude],
|
|
9200
9304
|
["codex", codex],
|
|
9305
|
+
["opencode", opencode],
|
|
9201
9306
|
["cursor", cursor]
|
|
9202
9307
|
]) {
|
|
9203
9308
|
const skills = obj?.skills;
|
|
@@ -9234,7 +9339,7 @@ function printSetupSummary(setup) {
|
|
|
9234
9339
|
};
|
|
9235
9340
|
if (claude) {
|
|
9236
9341
|
if (claude.claudeMd) {
|
|
9237
|
-
const icon =
|
|
9342
|
+
const icon = fs31.existsSync("CLAUDE.md") ? chalk12.yellow("~") : chalk12.green("+");
|
|
9238
9343
|
const desc = getDescription("CLAUDE.md");
|
|
9239
9344
|
console.log(` ${icon} ${chalk12.bold("CLAUDE.md")}`);
|
|
9240
9345
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -9244,7 +9349,7 @@ function printSetupSummary(setup) {
|
|
|
9244
9349
|
if (Array.isArray(skills) && skills.length > 0) {
|
|
9245
9350
|
for (const skill of skills) {
|
|
9246
9351
|
const skillPath = `.claude/skills/${skill.name}/SKILL.md`;
|
|
9247
|
-
const icon =
|
|
9352
|
+
const icon = fs31.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
9248
9353
|
const desc = getDescription(skillPath);
|
|
9249
9354
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
9250
9355
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -9255,7 +9360,7 @@ function printSetupSummary(setup) {
|
|
|
9255
9360
|
const codex = setup.codex;
|
|
9256
9361
|
if (codex) {
|
|
9257
9362
|
if (codex.agentsMd) {
|
|
9258
|
-
const icon =
|
|
9363
|
+
const icon = fs31.existsSync("AGENTS.md") ? chalk12.yellow("~") : chalk12.green("+");
|
|
9259
9364
|
const desc = getDescription("AGENTS.md");
|
|
9260
9365
|
console.log(` ${icon} ${chalk12.bold("AGENTS.md")}`);
|
|
9261
9366
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -9265,7 +9370,28 @@ function printSetupSummary(setup) {
|
|
|
9265
9370
|
if (Array.isArray(codexSkills) && codexSkills.length > 0) {
|
|
9266
9371
|
for (const skill of codexSkills) {
|
|
9267
9372
|
const skillPath = `.agents/skills/${skill.name}/SKILL.md`;
|
|
9268
|
-
const icon =
|
|
9373
|
+
const icon = fs31.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
9374
|
+
const desc = getDescription(skillPath);
|
|
9375
|
+
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
9376
|
+
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
9377
|
+
console.log("");
|
|
9378
|
+
}
|
|
9379
|
+
}
|
|
9380
|
+
}
|
|
9381
|
+
const opencode = setup.opencode;
|
|
9382
|
+
if (opencode) {
|
|
9383
|
+
if (opencode.agentsMd && !codex?.agentsMd) {
|
|
9384
|
+
const icon = fs31.existsSync("AGENTS.md") ? chalk12.yellow("~") : chalk12.green("+");
|
|
9385
|
+
const desc = getDescription("AGENTS.md");
|
|
9386
|
+
console.log(` ${icon} ${chalk12.bold("AGENTS.md")} ${chalk12.dim("(OpenCode)")}`);
|
|
9387
|
+
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
9388
|
+
console.log("");
|
|
9389
|
+
}
|
|
9390
|
+
const opencodeSkills = opencode.skills;
|
|
9391
|
+
if (Array.isArray(opencodeSkills) && opencodeSkills.length > 0) {
|
|
9392
|
+
for (const skill of opencodeSkills) {
|
|
9393
|
+
const skillPath = `.opencode/skills/${skill.name}/SKILL.md`;
|
|
9394
|
+
const icon = fs31.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
9269
9395
|
const desc = getDescription(skillPath);
|
|
9270
9396
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
9271
9397
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -9275,7 +9401,7 @@ function printSetupSummary(setup) {
|
|
|
9275
9401
|
}
|
|
9276
9402
|
if (cursor) {
|
|
9277
9403
|
if (cursor.cursorrules) {
|
|
9278
|
-
const icon =
|
|
9404
|
+
const icon = fs31.existsSync(".cursorrules") ? chalk12.yellow("~") : chalk12.green("+");
|
|
9279
9405
|
const desc = getDescription(".cursorrules");
|
|
9280
9406
|
console.log(` ${icon} ${chalk12.bold(".cursorrules")}`);
|
|
9281
9407
|
if (desc) console.log(chalk12.dim(` ${desc}`));
|
|
@@ -9285,7 +9411,7 @@ function printSetupSummary(setup) {
|
|
|
9285
9411
|
if (Array.isArray(cursorSkills) && cursorSkills.length > 0) {
|
|
9286
9412
|
for (const skill of cursorSkills) {
|
|
9287
9413
|
const skillPath = `.cursor/skills/${skill.name}/SKILL.md`;
|
|
9288
|
-
const icon =
|
|
9414
|
+
const icon = fs31.existsSync(skillPath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
9289
9415
|
const desc = getDescription(skillPath);
|
|
9290
9416
|
console.log(` ${icon} ${chalk12.bold(skillPath)}`);
|
|
9291
9417
|
console.log(chalk12.dim(` ${desc || skill.description || skill.name}`));
|
|
@@ -9296,7 +9422,7 @@ function printSetupSummary(setup) {
|
|
|
9296
9422
|
if (Array.isArray(rulesArr) && rulesArr.length > 0) {
|
|
9297
9423
|
for (const rule of rulesArr) {
|
|
9298
9424
|
const rulePath = `.cursor/rules/${rule.filename}`;
|
|
9299
|
-
const icon =
|
|
9425
|
+
const icon = fs31.existsSync(rulePath) ? chalk12.yellow("~") : chalk12.green("+");
|
|
9300
9426
|
const desc = getDescription(rulePath);
|
|
9301
9427
|
console.log(` ${icon} ${chalk12.bold(rulePath)}`);
|
|
9302
9428
|
if (desc) {
|
|
@@ -9351,12 +9477,12 @@ function displayTokenUsage() {
|
|
|
9351
9477
|
// src/commands/init-helpers.ts
|
|
9352
9478
|
init_config();
|
|
9353
9479
|
import chalk13 from "chalk";
|
|
9354
|
-
import
|
|
9355
|
-
import
|
|
9480
|
+
import fs32 from "fs";
|
|
9481
|
+
import path26 from "path";
|
|
9356
9482
|
function isFirstRun(dir) {
|
|
9357
|
-
const caliberDir =
|
|
9483
|
+
const caliberDir = path26.join(dir, ".caliber");
|
|
9358
9484
|
try {
|
|
9359
|
-
const stat =
|
|
9485
|
+
const stat = fs32.statSync(caliberDir);
|
|
9360
9486
|
return !stat.isDirectory();
|
|
9361
9487
|
} catch {
|
|
9362
9488
|
return true;
|
|
@@ -9409,8 +9535,8 @@ function ensurePermissions(fingerprint) {
|
|
|
9409
9535
|
const settingsPath = ".claude/settings.json";
|
|
9410
9536
|
let settings = {};
|
|
9411
9537
|
try {
|
|
9412
|
-
if (
|
|
9413
|
-
settings = JSON.parse(
|
|
9538
|
+
if (fs32.existsSync(settingsPath)) {
|
|
9539
|
+
settings = JSON.parse(fs32.readFileSync(settingsPath, "utf-8"));
|
|
9414
9540
|
}
|
|
9415
9541
|
} catch {
|
|
9416
9542
|
}
|
|
@@ -9419,12 +9545,12 @@ function ensurePermissions(fingerprint) {
|
|
|
9419
9545
|
if (Array.isArray(allow) && allow.length > 0) return;
|
|
9420
9546
|
permissions.allow = derivePermissions(fingerprint);
|
|
9421
9547
|
settings.permissions = permissions;
|
|
9422
|
-
if (!
|
|
9423
|
-
|
|
9548
|
+
if (!fs32.existsSync(".claude")) fs32.mkdirSync(".claude", { recursive: true });
|
|
9549
|
+
fs32.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
9424
9550
|
}
|
|
9425
9551
|
function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
9426
9552
|
try {
|
|
9427
|
-
const logPath =
|
|
9553
|
+
const logPath = path26.join(process.cwd(), ".caliber", "error-log.md");
|
|
9428
9554
|
const lines = [
|
|
9429
9555
|
`# Generation Error \u2014 ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
9430
9556
|
"",
|
|
@@ -9437,8 +9563,8 @@ function writeErrorLog(config, rawOutput, error, stopReason) {
|
|
|
9437
9563
|
lines.push("## Error", "```", error, "```", "");
|
|
9438
9564
|
}
|
|
9439
9565
|
lines.push("## Raw LLM Output", "```", rawOutput || "(empty)", "```");
|
|
9440
|
-
|
|
9441
|
-
|
|
9566
|
+
fs32.mkdirSync(path26.join(process.cwd(), ".caliber"), { recursive: true });
|
|
9567
|
+
fs32.writeFileSync(logPath, lines.join("\n"));
|
|
9442
9568
|
console.log(chalk13.dim(`
|
|
9443
9569
|
Error log written to .caliber/error-log.md`));
|
|
9444
9570
|
} catch {
|
|
@@ -9489,13 +9615,13 @@ ${JSON.stringify(checkList, null, 2)}`,
|
|
|
9489
9615
|
}
|
|
9490
9616
|
|
|
9491
9617
|
// src/scoring/history.ts
|
|
9492
|
-
import
|
|
9493
|
-
import
|
|
9618
|
+
import fs33 from "fs";
|
|
9619
|
+
import path27 from "path";
|
|
9494
9620
|
var HISTORY_FILE = "score-history.jsonl";
|
|
9495
9621
|
var MAX_ENTRIES = 500;
|
|
9496
9622
|
var TRIM_THRESHOLD = MAX_ENTRIES + 50;
|
|
9497
9623
|
function historyFilePath() {
|
|
9498
|
-
return
|
|
9624
|
+
return path27.join(CALIBER_DIR, HISTORY_FILE);
|
|
9499
9625
|
}
|
|
9500
9626
|
function recordScore(result, trigger) {
|
|
9501
9627
|
const entry = {
|
|
@@ -9506,14 +9632,14 @@ function recordScore(result, trigger) {
|
|
|
9506
9632
|
trigger
|
|
9507
9633
|
};
|
|
9508
9634
|
try {
|
|
9509
|
-
|
|
9635
|
+
fs33.mkdirSync(CALIBER_DIR, { recursive: true });
|
|
9510
9636
|
const filePath = historyFilePath();
|
|
9511
|
-
|
|
9512
|
-
const stat =
|
|
9637
|
+
fs33.appendFileSync(filePath, JSON.stringify(entry) + "\n");
|
|
9638
|
+
const stat = fs33.statSync(filePath);
|
|
9513
9639
|
if (stat.size > TRIM_THRESHOLD * 120) {
|
|
9514
|
-
const lines =
|
|
9640
|
+
const lines = fs33.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
9515
9641
|
if (lines.length > MAX_ENTRIES) {
|
|
9516
|
-
|
|
9642
|
+
fs33.writeFileSync(filePath, lines.slice(-MAX_ENTRIES).join("\n") + "\n");
|
|
9517
9643
|
}
|
|
9518
9644
|
}
|
|
9519
9645
|
} catch {
|
|
@@ -9522,7 +9648,7 @@ function recordScore(result, trigger) {
|
|
|
9522
9648
|
function readScoreHistory() {
|
|
9523
9649
|
const filePath = historyFilePath();
|
|
9524
9650
|
try {
|
|
9525
|
-
const content =
|
|
9651
|
+
const content = fs33.readFileSync(filePath, "utf-8");
|
|
9526
9652
|
const entries = [];
|
|
9527
9653
|
for (const line of content.split("\n")) {
|
|
9528
9654
|
if (!line) continue;
|
|
@@ -9578,8 +9704,8 @@ async function initCommand(options) {
|
|
|
9578
9704
|
console.log(brand.bold("\n CALIBER") + chalk14.dim(" \u2014 setting up continuous sync\n"));
|
|
9579
9705
|
}
|
|
9580
9706
|
const platforms = detectPlatforms();
|
|
9581
|
-
if (!platforms.claude && !platforms.cursor && !platforms.codex) {
|
|
9582
|
-
console.log(chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex)."));
|
|
9707
|
+
if (!platforms.claude && !platforms.cursor && !platforms.codex && !platforms.opencode) {
|
|
9708
|
+
console.log(chalk14.yellow(" \u26A0 No supported AI platforms detected (Claude, Cursor, Codex, OpenCode)."));
|
|
9583
9709
|
console.log(chalk14.yellow(" Caliber will still generate config files, but they won't be auto-installed.\n"));
|
|
9584
9710
|
}
|
|
9585
9711
|
const report = options.debugReport ? new DebugReport() : null;
|
|
@@ -9673,9 +9799,9 @@ async function initCommand(options) {
|
|
|
9673
9799
|
console.log(` ${chalk14.green("\u2713")} Onboarding hook \u2014 nudges new team members to set up`);
|
|
9674
9800
|
const { ensureBuiltinSkills: ensureBuiltinSkills2 } = await Promise.resolve().then(() => (init_builtin_skills(), builtin_skills_exports));
|
|
9675
9801
|
for (const agent of targetAgent) {
|
|
9676
|
-
if (agent === "claude" && !
|
|
9677
|
-
if (agent === "cursor" && !
|
|
9678
|
-
if (agent === "codex" && !
|
|
9802
|
+
if (agent === "claude" && !fs34.existsSync(".claude")) fs34.mkdirSync(".claude", { recursive: true });
|
|
9803
|
+
if (agent === "cursor" && !fs34.existsSync(".cursor")) fs34.mkdirSync(".cursor", { recursive: true });
|
|
9804
|
+
if (agent === "codex" && !fs34.existsSync(".agents")) fs34.mkdirSync(".agents", { recursive: true });
|
|
9679
9805
|
}
|
|
9680
9806
|
const skillsWritten = ensureBuiltinSkills2();
|
|
9681
9807
|
if (skillsWritten.length > 0) {
|
|
@@ -9732,41 +9858,41 @@ async function initCommand(options) {
|
|
|
9732
9858
|
const claudeMdPath = "CLAUDE.md";
|
|
9733
9859
|
let claudeContent = "";
|
|
9734
9860
|
try {
|
|
9735
|
-
claudeContent =
|
|
9861
|
+
claudeContent = fs34.readFileSync(claudeMdPath, "utf-8");
|
|
9736
9862
|
} catch {
|
|
9737
9863
|
}
|
|
9738
9864
|
if (!claudeContent) {
|
|
9739
|
-
claudeContent = `# ${
|
|
9865
|
+
claudeContent = `# ${path28.basename(process.cwd())}
|
|
9740
9866
|
`;
|
|
9741
9867
|
}
|
|
9742
9868
|
const updatedClaude = appendManagedBlocks2(claudeContent, "claude");
|
|
9743
|
-
if (updatedClaude !== claudeContent || !
|
|
9744
|
-
|
|
9869
|
+
if (updatedClaude !== claudeContent || !fs34.existsSync(claudeMdPath)) {
|
|
9870
|
+
fs34.writeFileSync(claudeMdPath, updatedClaude);
|
|
9745
9871
|
console.log(` ${chalk14.green("\u2713")} CLAUDE.md \u2014 added Caliber sync instructions`);
|
|
9746
9872
|
}
|
|
9747
9873
|
if (targetAgent.includes("cursor")) {
|
|
9748
|
-
const rulesDir =
|
|
9749
|
-
if (!
|
|
9874
|
+
const rulesDir = path28.join(".cursor", "rules");
|
|
9875
|
+
if (!fs34.existsSync(rulesDir)) fs34.mkdirSync(rulesDir, { recursive: true });
|
|
9750
9876
|
for (const rule of [getCursorPreCommitRule2(), getCursorLearningsRule2(), getCursorSyncRule2(), getCursorSetupRule2()]) {
|
|
9751
|
-
|
|
9877
|
+
fs34.writeFileSync(path28.join(rulesDir, rule.filename), rule.content);
|
|
9752
9878
|
}
|
|
9753
9879
|
console.log(` ${chalk14.green("\u2713")} Cursor rules \u2014 added Caliber sync rules`);
|
|
9754
9880
|
}
|
|
9755
9881
|
if (targetAgent.includes("github-copilot")) {
|
|
9756
|
-
const copilotPath =
|
|
9882
|
+
const copilotPath = path28.join(".github", "copilot-instructions.md");
|
|
9757
9883
|
let copilotContent = "";
|
|
9758
9884
|
try {
|
|
9759
|
-
copilotContent =
|
|
9885
|
+
copilotContent = fs34.readFileSync(copilotPath, "utf-8");
|
|
9760
9886
|
} catch {
|
|
9761
9887
|
}
|
|
9762
9888
|
if (!copilotContent) {
|
|
9763
|
-
|
|
9764
|
-
copilotContent = `# ${
|
|
9889
|
+
fs34.mkdirSync(".github", { recursive: true });
|
|
9890
|
+
copilotContent = `# ${path28.basename(process.cwd())}
|
|
9765
9891
|
`;
|
|
9766
9892
|
}
|
|
9767
9893
|
const updatedCopilot = appendManagedBlocks2(copilotContent, "copilot");
|
|
9768
9894
|
if (updatedCopilot !== copilotContent) {
|
|
9769
|
-
|
|
9895
|
+
fs34.writeFileSync(copilotPath, updatedCopilot);
|
|
9770
9896
|
console.log(` ${chalk14.green("\u2713")} Copilot instructions \u2014 added Caliber sync instructions`);
|
|
9771
9897
|
}
|
|
9772
9898
|
}
|
|
@@ -10051,7 +10177,7 @@ async function initCommand(options) {
|
|
|
10051
10177
|
const { default: ora9 } = await import("ora");
|
|
10052
10178
|
const writeSpinner = ora9("Writing config files...").start();
|
|
10053
10179
|
try {
|
|
10054
|
-
if (targetAgent.includes("codex") && !
|
|
10180
|
+
if (targetAgent.includes("codex") && !fs34.existsSync("AGENTS.md") && !generatedSetup.codex) {
|
|
10055
10181
|
const claude = generatedSetup.claude;
|
|
10056
10182
|
const cursor = generatedSetup.cursor;
|
|
10057
10183
|
const agentRefs = [];
|
|
@@ -10168,9 +10294,9 @@ ${agentRefs.join(" ")}
|
|
|
10168
10294
|
}
|
|
10169
10295
|
if (report) {
|
|
10170
10296
|
report.markStep("Finished");
|
|
10171
|
-
const reportPath =
|
|
10297
|
+
const reportPath = path28.join(process.cwd(), ".caliber", "debug-report.md");
|
|
10172
10298
|
report.write(reportPath);
|
|
10173
|
-
console.log(chalk14.dim(` Debug report written to ${
|
|
10299
|
+
console.log(chalk14.dim(` Debug report written to ${path28.relative(process.cwd(), reportPath)}
|
|
10174
10300
|
`));
|
|
10175
10301
|
}
|
|
10176
10302
|
}
|
|
@@ -10209,7 +10335,7 @@ function undoCommand() {
|
|
|
10209
10335
|
|
|
10210
10336
|
// src/commands/status.ts
|
|
10211
10337
|
import chalk16 from "chalk";
|
|
10212
|
-
import
|
|
10338
|
+
import fs35 from "fs";
|
|
10213
10339
|
init_config();
|
|
10214
10340
|
init_resolve_caliber();
|
|
10215
10341
|
async function statusCommand(options) {
|
|
@@ -10238,7 +10364,7 @@ async function statusCommand(options) {
|
|
|
10238
10364
|
}
|
|
10239
10365
|
console.log(` Files managed: ${chalk16.cyan(manifest.entries.length.toString())}`);
|
|
10240
10366
|
for (const entry of manifest.entries) {
|
|
10241
|
-
const exists =
|
|
10367
|
+
const exists = fs35.existsSync(entry.path);
|
|
10242
10368
|
const icon = exists ? chalk16.green("\u2713") : chalk16.red("\u2717");
|
|
10243
10369
|
console.log(` ${icon} ${entry.path} (${entry.action})`);
|
|
10244
10370
|
}
|
|
@@ -10395,9 +10521,9 @@ async function regenerateCommand(options) {
|
|
|
10395
10521
|
}
|
|
10396
10522
|
|
|
10397
10523
|
// src/commands/score.ts
|
|
10398
|
-
import
|
|
10524
|
+
import fs36 from "fs";
|
|
10399
10525
|
import os7 from "os";
|
|
10400
|
-
import
|
|
10526
|
+
import path29 from "path";
|
|
10401
10527
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
10402
10528
|
import chalk18 from "chalk";
|
|
10403
10529
|
init_resolve_caliber();
|
|
@@ -10405,7 +10531,7 @@ var CONFIG_FILES = ["CLAUDE.md", "AGENTS.md", ".cursorrules", "CALIBER_LEARNINGS
|
|
|
10405
10531
|
var CONFIG_DIRS = [".claude", ".cursor"];
|
|
10406
10532
|
function scoreBaseRef(ref, target) {
|
|
10407
10533
|
if (!/^[\w.\-/~^@{}]+$/.test(ref)) return null;
|
|
10408
|
-
const tmpDir =
|
|
10534
|
+
const tmpDir = fs36.mkdtempSync(path29.join(os7.tmpdir(), "caliber-compare-"));
|
|
10409
10535
|
try {
|
|
10410
10536
|
for (const file of CONFIG_FILES) {
|
|
10411
10537
|
try {
|
|
@@ -10413,7 +10539,7 @@ function scoreBaseRef(ref, target) {
|
|
|
10413
10539
|
encoding: "utf-8",
|
|
10414
10540
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10415
10541
|
});
|
|
10416
|
-
|
|
10542
|
+
fs36.writeFileSync(path29.join(tmpDir, file), content);
|
|
10417
10543
|
} catch {
|
|
10418
10544
|
}
|
|
10419
10545
|
}
|
|
@@ -10424,13 +10550,13 @@ function scoreBaseRef(ref, target) {
|
|
|
10424
10550
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10425
10551
|
}).trim().split("\n").filter(Boolean);
|
|
10426
10552
|
for (const file of files) {
|
|
10427
|
-
const filePath =
|
|
10428
|
-
|
|
10553
|
+
const filePath = path29.join(tmpDir, file);
|
|
10554
|
+
fs36.mkdirSync(path29.dirname(filePath), { recursive: true });
|
|
10429
10555
|
const content = execFileSync2("git", ["show", `${ref}:${file}`], {
|
|
10430
10556
|
encoding: "utf-8",
|
|
10431
10557
|
stdio: ["pipe", "pipe", "pipe"]
|
|
10432
10558
|
});
|
|
10433
|
-
|
|
10559
|
+
fs36.writeFileSync(filePath, content);
|
|
10434
10560
|
}
|
|
10435
10561
|
} catch {
|
|
10436
10562
|
}
|
|
@@ -10440,7 +10566,7 @@ function scoreBaseRef(ref, target) {
|
|
|
10440
10566
|
} catch {
|
|
10441
10567
|
return null;
|
|
10442
10568
|
} finally {
|
|
10443
|
-
|
|
10569
|
+
fs36.rmSync(tmpDir, { recursive: true, force: true });
|
|
10444
10570
|
}
|
|
10445
10571
|
}
|
|
10446
10572
|
async function scoreCommand(options) {
|
|
@@ -10524,8 +10650,8 @@ async function scoreCommand(options) {
|
|
|
10524
10650
|
}
|
|
10525
10651
|
|
|
10526
10652
|
// src/commands/refresh.ts
|
|
10527
|
-
import
|
|
10528
|
-
import
|
|
10653
|
+
import fs40 from "fs";
|
|
10654
|
+
import path33 from "path";
|
|
10529
10655
|
import chalk19 from "chalk";
|
|
10530
10656
|
import ora6 from "ora";
|
|
10531
10657
|
|
|
@@ -10604,48 +10730,52 @@ function collectDiff(lastSha) {
|
|
|
10604
10730
|
|
|
10605
10731
|
// src/writers/refresh.ts
|
|
10606
10732
|
init_pre_commit_block();
|
|
10607
|
-
import
|
|
10608
|
-
import
|
|
10733
|
+
import fs37 from "fs";
|
|
10734
|
+
import path30 from "path";
|
|
10609
10735
|
function writeRefreshDocs(docs) {
|
|
10610
10736
|
const written = [];
|
|
10737
|
+
if (docs.agentsMd) {
|
|
10738
|
+
fs37.writeFileSync("AGENTS.md", appendLearningsBlock(appendPreCommitBlock(docs.agentsMd)));
|
|
10739
|
+
written.push("AGENTS.md");
|
|
10740
|
+
}
|
|
10611
10741
|
if (docs.claudeMd) {
|
|
10612
|
-
|
|
10742
|
+
fs37.writeFileSync("CLAUDE.md", appendLearningsBlock(appendPreCommitBlock(docs.claudeMd)));
|
|
10613
10743
|
written.push("CLAUDE.md");
|
|
10614
10744
|
}
|
|
10615
10745
|
if (docs.readmeMd) {
|
|
10616
|
-
|
|
10746
|
+
fs37.writeFileSync("README.md", docs.readmeMd);
|
|
10617
10747
|
written.push("README.md");
|
|
10618
10748
|
}
|
|
10619
10749
|
if (docs.cursorrules) {
|
|
10620
|
-
|
|
10750
|
+
fs37.writeFileSync(".cursorrules", docs.cursorrules);
|
|
10621
10751
|
written.push(".cursorrules");
|
|
10622
10752
|
}
|
|
10623
10753
|
if (docs.cursorRules) {
|
|
10624
|
-
const rulesDir =
|
|
10625
|
-
if (!
|
|
10754
|
+
const rulesDir = path30.join(".cursor", "rules");
|
|
10755
|
+
if (!fs37.existsSync(rulesDir)) fs37.mkdirSync(rulesDir, { recursive: true });
|
|
10626
10756
|
for (const rule of docs.cursorRules) {
|
|
10627
|
-
|
|
10757
|
+
fs37.writeFileSync(path30.join(rulesDir, rule.filename), rule.content);
|
|
10628
10758
|
written.push(`.cursor/rules/${rule.filename}`);
|
|
10629
10759
|
}
|
|
10630
10760
|
}
|
|
10631
10761
|
if (docs.claudeSkills) {
|
|
10632
|
-
const skillsDir =
|
|
10633
|
-
if (!
|
|
10762
|
+
const skillsDir = path30.join(".claude", "skills");
|
|
10763
|
+
if (!fs37.existsSync(skillsDir)) fs37.mkdirSync(skillsDir, { recursive: true });
|
|
10634
10764
|
for (const skill of docs.claudeSkills) {
|
|
10635
|
-
|
|
10765
|
+
fs37.writeFileSync(path30.join(skillsDir, skill.filename), skill.content);
|
|
10636
10766
|
written.push(`.claude/skills/${skill.filename}`);
|
|
10637
10767
|
}
|
|
10638
10768
|
}
|
|
10639
10769
|
if (docs.copilotInstructions) {
|
|
10640
|
-
|
|
10641
|
-
|
|
10770
|
+
fs37.mkdirSync(".github", { recursive: true });
|
|
10771
|
+
fs37.writeFileSync(path30.join(".github", "copilot-instructions.md"), appendLearningsBlock(appendPreCommitBlock(docs.copilotInstructions)));
|
|
10642
10772
|
written.push(".github/copilot-instructions.md");
|
|
10643
10773
|
}
|
|
10644
10774
|
if (docs.copilotInstructionFiles) {
|
|
10645
|
-
const instructionsDir =
|
|
10646
|
-
|
|
10775
|
+
const instructionsDir = path30.join(".github", "instructions");
|
|
10776
|
+
fs37.mkdirSync(instructionsDir, { recursive: true });
|
|
10647
10777
|
for (const file of docs.copilotInstructionFiles) {
|
|
10648
|
-
|
|
10778
|
+
fs37.writeFileSync(path30.join(instructionsDir, file.filename), file.content);
|
|
10649
10779
|
written.push(`.github/instructions/${file.filename}`);
|
|
10650
10780
|
}
|
|
10651
10781
|
}
|
|
@@ -10693,6 +10823,10 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
10693
10823
|
parts.push(diff.unstaged);
|
|
10694
10824
|
}
|
|
10695
10825
|
parts.push("\n--- Current Documentation ---");
|
|
10826
|
+
if (existingDocs.agentsMd) {
|
|
10827
|
+
parts.push("\n[AGENTS.md]");
|
|
10828
|
+
parts.push(existingDocs.agentsMd);
|
|
10829
|
+
}
|
|
10696
10830
|
if (existingDocs.claudeMd) {
|
|
10697
10831
|
parts.push("\n[CLAUDE.md]");
|
|
10698
10832
|
parts.push(existingDocs.claudeMd);
|
|
@@ -10731,8 +10865,8 @@ Changed files: ${diff.changedFiles.join(", ")}`);
|
|
|
10731
10865
|
}
|
|
10732
10866
|
|
|
10733
10867
|
// src/learner/writer.ts
|
|
10734
|
-
import
|
|
10735
|
-
import
|
|
10868
|
+
import fs38 from "fs";
|
|
10869
|
+
import path31 from "path";
|
|
10736
10870
|
|
|
10737
10871
|
// src/learner/utils.ts
|
|
10738
10872
|
var TYPE_PREFIX_RE = /^\*\*\[[^\]]+\]\*\*\s*/;
|
|
@@ -10849,20 +10983,20 @@ function deduplicateLearnedItems(existing, incoming) {
|
|
|
10849
10983
|
}
|
|
10850
10984
|
function writeLearnedSectionTo(filePath, header, existing, incoming, mode) {
|
|
10851
10985
|
const { merged, newCount, newItems } = deduplicateLearnedItems(existing, incoming);
|
|
10852
|
-
|
|
10853
|
-
if (mode)
|
|
10986
|
+
fs38.writeFileSync(filePath, header + merged + "\n");
|
|
10987
|
+
if (mode) fs38.chmodSync(filePath, mode);
|
|
10854
10988
|
return { newCount, newItems };
|
|
10855
10989
|
}
|
|
10856
10990
|
function writeLearnedSection(content) {
|
|
10857
10991
|
return writeLearnedSectionTo(LEARNINGS_FILE, LEARNINGS_HEADER, readLearnedSection(), content);
|
|
10858
10992
|
}
|
|
10859
10993
|
function writeLearnedSkill(skill) {
|
|
10860
|
-
const skillDir =
|
|
10861
|
-
if (!
|
|
10862
|
-
const skillPath =
|
|
10863
|
-
if (!skill.isNew &&
|
|
10864
|
-
const existing =
|
|
10865
|
-
|
|
10994
|
+
const skillDir = path31.join(".claude", "skills", skill.name);
|
|
10995
|
+
if (!fs38.existsSync(skillDir)) fs38.mkdirSync(skillDir, { recursive: true });
|
|
10996
|
+
const skillPath = path31.join(skillDir, "SKILL.md");
|
|
10997
|
+
if (!skill.isNew && fs38.existsSync(skillPath)) {
|
|
10998
|
+
const existing = fs38.readFileSync(skillPath, "utf-8");
|
|
10999
|
+
fs38.writeFileSync(skillPath, existing.trimEnd() + "\n\n" + skill.content);
|
|
10866
11000
|
} else {
|
|
10867
11001
|
const frontmatter = [
|
|
10868
11002
|
"---",
|
|
@@ -10871,12 +11005,12 @@ function writeLearnedSkill(skill) {
|
|
|
10871
11005
|
"---",
|
|
10872
11006
|
""
|
|
10873
11007
|
].join("\n");
|
|
10874
|
-
|
|
11008
|
+
fs38.writeFileSync(skillPath, frontmatter + skill.content);
|
|
10875
11009
|
}
|
|
10876
11010
|
return skillPath;
|
|
10877
11011
|
}
|
|
10878
11012
|
function writePersonalLearnedSection(content) {
|
|
10879
|
-
if (!
|
|
11013
|
+
if (!fs38.existsSync(AUTH_DIR)) fs38.mkdirSync(AUTH_DIR, { recursive: true });
|
|
10880
11014
|
return writeLearnedSectionTo(PERSONAL_LEARNINGS_FILE, PERSONAL_LEARNINGS_HEADER, readPersonalLearnings(), content, 384);
|
|
10881
11015
|
}
|
|
10882
11016
|
function addLearning(bullet, scope = "project") {
|
|
@@ -10889,38 +11023,38 @@ function addLearning(bullet, scope = "project") {
|
|
|
10889
11023
|
return { file: LEARNINGS_FILE, added: result.newCount > 0 };
|
|
10890
11024
|
}
|
|
10891
11025
|
function readPersonalLearnings() {
|
|
10892
|
-
if (!
|
|
10893
|
-
const content =
|
|
11026
|
+
if (!fs38.existsSync(PERSONAL_LEARNINGS_FILE)) return null;
|
|
11027
|
+
const content = fs38.readFileSync(PERSONAL_LEARNINGS_FILE, "utf-8");
|
|
10894
11028
|
const bullets = content.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
10895
11029
|
return bullets || null;
|
|
10896
11030
|
}
|
|
10897
11031
|
function readLearnedSection() {
|
|
10898
|
-
if (
|
|
10899
|
-
const content2 =
|
|
11032
|
+
if (fs38.existsSync(LEARNINGS_FILE)) {
|
|
11033
|
+
const content2 = fs38.readFileSync(LEARNINGS_FILE, "utf-8");
|
|
10900
11034
|
const bullets = content2.split("\n").filter((l) => l.startsWith("- ")).join("\n");
|
|
10901
11035
|
return bullets || null;
|
|
10902
11036
|
}
|
|
10903
11037
|
const claudeMdPath = "CLAUDE.md";
|
|
10904
|
-
if (!
|
|
10905
|
-
const content =
|
|
11038
|
+
if (!fs38.existsSync(claudeMdPath)) return null;
|
|
11039
|
+
const content = fs38.readFileSync(claudeMdPath, "utf-8");
|
|
10906
11040
|
const startIdx = content.indexOf(LEARNED_START);
|
|
10907
11041
|
const endIdx = content.indexOf(LEARNED_END);
|
|
10908
11042
|
if (startIdx === -1 || endIdx === -1) return null;
|
|
10909
11043
|
return content.slice(startIdx + LEARNED_START.length, endIdx).trim() || null;
|
|
10910
11044
|
}
|
|
10911
11045
|
function migrateInlineLearnings() {
|
|
10912
|
-
if (
|
|
11046
|
+
if (fs38.existsSync(LEARNINGS_FILE)) return false;
|
|
10913
11047
|
const claudeMdPath = "CLAUDE.md";
|
|
10914
|
-
if (!
|
|
10915
|
-
const content =
|
|
11048
|
+
if (!fs38.existsSync(claudeMdPath)) return false;
|
|
11049
|
+
const content = fs38.readFileSync(claudeMdPath, "utf-8");
|
|
10916
11050
|
const startIdx = content.indexOf(LEARNED_START);
|
|
10917
11051
|
const endIdx = content.indexOf(LEARNED_END);
|
|
10918
11052
|
if (startIdx === -1 || endIdx === -1) return false;
|
|
10919
11053
|
const section = content.slice(startIdx + LEARNED_START.length, endIdx).trim();
|
|
10920
11054
|
if (!section) return false;
|
|
10921
|
-
|
|
11055
|
+
fs38.writeFileSync(LEARNINGS_FILE, LEARNINGS_HEADER + section + "\n");
|
|
10922
11056
|
const cleaned = content.slice(0, startIdx) + content.slice(endIdx + LEARNED_END.length);
|
|
10923
|
-
|
|
11057
|
+
fs38.writeFileSync(claudeMdPath, cleaned.replace(/\n{3,}/g, "\n\n").trim() + "\n");
|
|
10924
11058
|
return true;
|
|
10925
11059
|
}
|
|
10926
11060
|
|
|
@@ -10934,11 +11068,11 @@ function log2(quiet, ...args) {
|
|
|
10934
11068
|
function discoverGitRepos(parentDir) {
|
|
10935
11069
|
const repos = [];
|
|
10936
11070
|
try {
|
|
10937
|
-
const entries =
|
|
11071
|
+
const entries = fs40.readdirSync(parentDir, { withFileTypes: true });
|
|
10938
11072
|
for (const entry of entries) {
|
|
10939
11073
|
if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
|
|
10940
|
-
const childPath =
|
|
10941
|
-
if (
|
|
11074
|
+
const childPath = path33.join(parentDir, entry.name);
|
|
11075
|
+
if (fs40.existsSync(path33.join(childPath, ".git"))) {
|
|
10942
11076
|
repos.push(childPath);
|
|
10943
11077
|
}
|
|
10944
11078
|
}
|
|
@@ -11024,9 +11158,9 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
11024
11158
|
const filesToWrite = response.docsUpdated || [];
|
|
11025
11159
|
const preRefreshContents = /* @__PURE__ */ new Map();
|
|
11026
11160
|
for (const filePath of filesToWrite) {
|
|
11027
|
-
const fullPath =
|
|
11161
|
+
const fullPath = path33.resolve(repoDir, filePath);
|
|
11028
11162
|
try {
|
|
11029
|
-
preRefreshContents.set(filePath,
|
|
11163
|
+
preRefreshContents.set(filePath, fs40.readFileSync(fullPath, "utf-8"));
|
|
11030
11164
|
} catch {
|
|
11031
11165
|
preRefreshContents.set(filePath, null);
|
|
11032
11166
|
}
|
|
@@ -11037,14 +11171,14 @@ async function refreshSingleRepo(repoDir, options) {
|
|
|
11037
11171
|
const postScore = computeLocalScore(repoDir, targetAgent);
|
|
11038
11172
|
if (postScore.score < preScore.score) {
|
|
11039
11173
|
for (const [filePath, content] of preRefreshContents) {
|
|
11040
|
-
const fullPath =
|
|
11174
|
+
const fullPath = path33.resolve(repoDir, filePath);
|
|
11041
11175
|
if (content === null) {
|
|
11042
11176
|
try {
|
|
11043
|
-
|
|
11177
|
+
fs40.unlinkSync(fullPath);
|
|
11044
11178
|
} catch {
|
|
11045
11179
|
}
|
|
11046
11180
|
} else {
|
|
11047
|
-
|
|
11181
|
+
fs40.writeFileSync(fullPath, content);
|
|
11048
11182
|
}
|
|
11049
11183
|
}
|
|
11050
11184
|
spinner?.warn(`${prefix}Refresh reverted \u2014 score would drop from ${preScore.score} to ${postScore.score}`);
|
|
@@ -11099,7 +11233,7 @@ async function refreshCommand(options) {
|
|
|
11099
11233
|
`));
|
|
11100
11234
|
const originalDir = process.cwd();
|
|
11101
11235
|
for (const repo of repos) {
|
|
11102
|
-
const repoName =
|
|
11236
|
+
const repoName = path33.basename(repo);
|
|
11103
11237
|
try {
|
|
11104
11238
|
process.chdir(repo);
|
|
11105
11239
|
await refreshSingleRepo(repo, { ...options, label: repoName });
|
|
@@ -11120,7 +11254,7 @@ async function refreshCommand(options) {
|
|
|
11120
11254
|
|
|
11121
11255
|
// src/commands/hooks.ts
|
|
11122
11256
|
import chalk20 from "chalk";
|
|
11123
|
-
import
|
|
11257
|
+
import fs41 from "fs";
|
|
11124
11258
|
var HOOKS = [
|
|
11125
11259
|
{
|
|
11126
11260
|
id: "session-end",
|
|
@@ -11164,11 +11298,11 @@ async function hooksCommand(options) {
|
|
|
11164
11298
|
console.log(chalk20.green(" \u2713") + ` ${hook.label} enabled`);
|
|
11165
11299
|
}
|
|
11166
11300
|
}
|
|
11167
|
-
if (
|
|
11301
|
+
if (fs41.existsSync(".claude")) {
|
|
11168
11302
|
const r = installLearningHooks();
|
|
11169
11303
|
if (r.installed) console.log(chalk20.green(" \u2713") + " Claude Code learning hooks enabled");
|
|
11170
11304
|
}
|
|
11171
|
-
if (
|
|
11305
|
+
if (fs41.existsSync(".cursor")) {
|
|
11172
11306
|
const r = installCursorLearningHooks();
|
|
11173
11307
|
if (r.installed) console.log(chalk20.green(" \u2713") + " Cursor learning hooks enabled");
|
|
11174
11308
|
}
|
|
@@ -11336,8 +11470,8 @@ async function configCommand() {
|
|
|
11336
11470
|
}
|
|
11337
11471
|
|
|
11338
11472
|
// src/commands/learn.ts
|
|
11339
|
-
import
|
|
11340
|
-
import
|
|
11473
|
+
import fs45 from "fs";
|
|
11474
|
+
import path37 from "path";
|
|
11341
11475
|
import chalk23 from "chalk";
|
|
11342
11476
|
|
|
11343
11477
|
// src/learner/stdin.ts
|
|
@@ -11368,8 +11502,8 @@ function readStdin() {
|
|
|
11368
11502
|
}
|
|
11369
11503
|
|
|
11370
11504
|
// src/learner/storage.ts
|
|
11371
|
-
import
|
|
11372
|
-
import
|
|
11505
|
+
import fs42 from "fs";
|
|
11506
|
+
import path34 from "path";
|
|
11373
11507
|
var MAX_RESPONSE_LENGTH = 2e3;
|
|
11374
11508
|
var DEFAULT_STATE = {
|
|
11375
11509
|
sessionId: null,
|
|
@@ -11378,15 +11512,15 @@ var DEFAULT_STATE = {
|
|
|
11378
11512
|
lastAnalysisEventCount: 0
|
|
11379
11513
|
};
|
|
11380
11514
|
function ensureLearningDir() {
|
|
11381
|
-
if (!
|
|
11382
|
-
|
|
11515
|
+
if (!fs42.existsSync(getLearningDir())) {
|
|
11516
|
+
fs42.mkdirSync(getLearningDir(), { recursive: true });
|
|
11383
11517
|
}
|
|
11384
11518
|
}
|
|
11385
11519
|
function sessionFilePath() {
|
|
11386
|
-
return
|
|
11520
|
+
return path34.join(getLearningDir(), LEARNING_SESSION_FILE);
|
|
11387
11521
|
}
|
|
11388
11522
|
function stateFilePath() {
|
|
11389
|
-
return
|
|
11523
|
+
return path34.join(getLearningDir(), LEARNING_STATE_FILE);
|
|
11390
11524
|
}
|
|
11391
11525
|
function truncateResponse(response) {
|
|
11392
11526
|
const str = JSON.stringify(response);
|
|
@@ -11396,10 +11530,10 @@ function truncateResponse(response) {
|
|
|
11396
11530
|
function trimSessionFileIfNeeded(filePath) {
|
|
11397
11531
|
const state = readState2();
|
|
11398
11532
|
if (state.eventCount + 1 > LEARNING_MAX_EVENTS) {
|
|
11399
|
-
const lines =
|
|
11533
|
+
const lines = fs42.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
11400
11534
|
if (lines.length > LEARNING_MAX_EVENTS) {
|
|
11401
11535
|
const kept = lines.slice(lines.length - LEARNING_MAX_EVENTS);
|
|
11402
|
-
|
|
11536
|
+
fs42.writeFileSync(filePath, kept.join("\n") + "\n");
|
|
11403
11537
|
}
|
|
11404
11538
|
}
|
|
11405
11539
|
}
|
|
@@ -11407,19 +11541,19 @@ function appendEvent(event) {
|
|
|
11407
11541
|
ensureLearningDir();
|
|
11408
11542
|
const truncated = { ...event, tool_response: truncateResponse(event.tool_response) };
|
|
11409
11543
|
const filePath = sessionFilePath();
|
|
11410
|
-
|
|
11544
|
+
fs42.appendFileSync(filePath, JSON.stringify(truncated) + "\n");
|
|
11411
11545
|
trimSessionFileIfNeeded(filePath);
|
|
11412
11546
|
}
|
|
11413
11547
|
function appendPromptEvent(event) {
|
|
11414
11548
|
ensureLearningDir();
|
|
11415
11549
|
const filePath = sessionFilePath();
|
|
11416
|
-
|
|
11550
|
+
fs42.appendFileSync(filePath, JSON.stringify(event) + "\n");
|
|
11417
11551
|
trimSessionFileIfNeeded(filePath);
|
|
11418
11552
|
}
|
|
11419
11553
|
function readAllEvents() {
|
|
11420
11554
|
const filePath = sessionFilePath();
|
|
11421
|
-
if (!
|
|
11422
|
-
const lines =
|
|
11555
|
+
if (!fs42.existsSync(filePath)) return [];
|
|
11556
|
+
const lines = fs42.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
11423
11557
|
const events = [];
|
|
11424
11558
|
for (const line of lines) {
|
|
11425
11559
|
try {
|
|
@@ -11431,26 +11565,26 @@ function readAllEvents() {
|
|
|
11431
11565
|
}
|
|
11432
11566
|
function getEventCount() {
|
|
11433
11567
|
const filePath = sessionFilePath();
|
|
11434
|
-
if (!
|
|
11435
|
-
const content =
|
|
11568
|
+
if (!fs42.existsSync(filePath)) return 0;
|
|
11569
|
+
const content = fs42.readFileSync(filePath, "utf-8");
|
|
11436
11570
|
return content.split("\n").filter(Boolean).length;
|
|
11437
11571
|
}
|
|
11438
11572
|
function clearSession() {
|
|
11439
11573
|
const filePath = sessionFilePath();
|
|
11440
|
-
if (
|
|
11574
|
+
if (fs42.existsSync(filePath)) fs42.unlinkSync(filePath);
|
|
11441
11575
|
}
|
|
11442
11576
|
function readState2() {
|
|
11443
11577
|
const filePath = stateFilePath();
|
|
11444
|
-
if (!
|
|
11578
|
+
if (!fs42.existsSync(filePath)) return { ...DEFAULT_STATE };
|
|
11445
11579
|
try {
|
|
11446
|
-
return JSON.parse(
|
|
11580
|
+
return JSON.parse(fs42.readFileSync(filePath, "utf-8"));
|
|
11447
11581
|
} catch {
|
|
11448
11582
|
return { ...DEFAULT_STATE };
|
|
11449
11583
|
}
|
|
11450
11584
|
}
|
|
11451
11585
|
function writeState2(state) {
|
|
11452
11586
|
ensureLearningDir();
|
|
11453
|
-
|
|
11587
|
+
fs42.writeFileSync(stateFilePath(), JSON.stringify(state, null, 2));
|
|
11454
11588
|
}
|
|
11455
11589
|
function resetState() {
|
|
11456
11590
|
writeState2({ ...DEFAULT_STATE });
|
|
@@ -11458,16 +11592,16 @@ function resetState() {
|
|
|
11458
11592
|
var LOCK_FILE2 = "finalize.lock";
|
|
11459
11593
|
var LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
11460
11594
|
function lockFilePath() {
|
|
11461
|
-
return
|
|
11595
|
+
return path34.join(getLearningDir(), LOCK_FILE2);
|
|
11462
11596
|
}
|
|
11463
11597
|
function acquireFinalizeLock() {
|
|
11464
11598
|
ensureLearningDir();
|
|
11465
11599
|
const lockPath = lockFilePath();
|
|
11466
|
-
if (
|
|
11600
|
+
if (fs42.existsSync(lockPath)) {
|
|
11467
11601
|
try {
|
|
11468
|
-
const stat =
|
|
11602
|
+
const stat = fs42.statSync(lockPath);
|
|
11469
11603
|
if (Date.now() - stat.mtimeMs < LOCK_STALE_MS) {
|
|
11470
|
-
const pid = parseInt(
|
|
11604
|
+
const pid = parseInt(fs42.readFileSync(lockPath, "utf-8").trim(), 10);
|
|
11471
11605
|
if (!isNaN(pid) && isProcessAlive(pid)) {
|
|
11472
11606
|
return false;
|
|
11473
11607
|
}
|
|
@@ -11475,12 +11609,12 @@ function acquireFinalizeLock() {
|
|
|
11475
11609
|
} catch {
|
|
11476
11610
|
}
|
|
11477
11611
|
try {
|
|
11478
|
-
|
|
11612
|
+
fs42.unlinkSync(lockPath);
|
|
11479
11613
|
} catch {
|
|
11480
11614
|
}
|
|
11481
11615
|
}
|
|
11482
11616
|
try {
|
|
11483
|
-
|
|
11617
|
+
fs42.writeFileSync(lockPath, String(process.pid), { flag: "wx" });
|
|
11484
11618
|
return true;
|
|
11485
11619
|
} catch {
|
|
11486
11620
|
return false;
|
|
@@ -11497,30 +11631,30 @@ function isProcessAlive(pid) {
|
|
|
11497
11631
|
function releaseFinalizeLock() {
|
|
11498
11632
|
const lockPath = lockFilePath();
|
|
11499
11633
|
try {
|
|
11500
|
-
if (
|
|
11634
|
+
if (fs42.existsSync(lockPath)) fs42.unlinkSync(lockPath);
|
|
11501
11635
|
} catch {
|
|
11502
11636
|
}
|
|
11503
11637
|
}
|
|
11504
11638
|
|
|
11505
11639
|
// src/lib/notifications.ts
|
|
11506
|
-
import
|
|
11507
|
-
import
|
|
11640
|
+
import fs43 from "fs";
|
|
11641
|
+
import path35 from "path";
|
|
11508
11642
|
import chalk22 from "chalk";
|
|
11509
11643
|
function notificationFilePath() {
|
|
11510
|
-
return
|
|
11644
|
+
return path35.join(getLearningDir(), "last-finalize-summary.json");
|
|
11511
11645
|
}
|
|
11512
11646
|
function writeFinalizeSummary(summary) {
|
|
11513
11647
|
try {
|
|
11514
11648
|
ensureLearningDir();
|
|
11515
|
-
|
|
11649
|
+
fs43.writeFileSync(notificationFilePath(), JSON.stringify(summary, null, 2));
|
|
11516
11650
|
} catch {
|
|
11517
11651
|
}
|
|
11518
11652
|
}
|
|
11519
11653
|
function checkPendingNotifications() {
|
|
11520
11654
|
try {
|
|
11521
|
-
if (!
|
|
11522
|
-
const raw =
|
|
11523
|
-
|
|
11655
|
+
if (!fs43.existsSync(notificationFilePath())) return;
|
|
11656
|
+
const raw = fs43.readFileSync(notificationFilePath(), "utf-8");
|
|
11657
|
+
fs43.unlinkSync(notificationFilePath());
|
|
11524
11658
|
const summary = JSON.parse(raw);
|
|
11525
11659
|
if (!summary.newItemCount || summary.newItemCount === 0) return;
|
|
11526
11660
|
const wasteLabel = summary.wasteTokens > 0 ? ` (~${summary.wasteTokens.toLocaleString()} wasted tokens captured)` : "";
|
|
@@ -11536,7 +11670,7 @@ function checkPendingNotifications() {
|
|
|
11536
11670
|
console.log("");
|
|
11537
11671
|
} catch {
|
|
11538
11672
|
try {
|
|
11539
|
-
|
|
11673
|
+
fs43.unlinkSync(notificationFilePath());
|
|
11540
11674
|
} catch {
|
|
11541
11675
|
}
|
|
11542
11676
|
}
|
|
@@ -11688,8 +11822,8 @@ function calculateSessionWaste(events) {
|
|
|
11688
11822
|
init_config();
|
|
11689
11823
|
|
|
11690
11824
|
// src/learner/roi.ts
|
|
11691
|
-
import
|
|
11692
|
-
import
|
|
11825
|
+
import fs44 from "fs";
|
|
11826
|
+
import path36 from "path";
|
|
11693
11827
|
var DEFAULT_TOTALS = {
|
|
11694
11828
|
totalWasteTokens: 0,
|
|
11695
11829
|
totalWasteSeconds: 0,
|
|
@@ -11703,19 +11837,19 @@ var DEFAULT_TOTALS = {
|
|
|
11703
11837
|
lastSessionTimestamp: ""
|
|
11704
11838
|
};
|
|
11705
11839
|
function roiFilePath() {
|
|
11706
|
-
return
|
|
11840
|
+
return path36.join(getLearningDir(), LEARNING_ROI_FILE);
|
|
11707
11841
|
}
|
|
11708
11842
|
function readROIStats() {
|
|
11709
11843
|
const filePath = roiFilePath();
|
|
11710
|
-
if (!
|
|
11844
|
+
if (!fs44.existsSync(filePath)) {
|
|
11711
11845
|
return { learnings: [], sessions: [], totals: { ...DEFAULT_TOTALS } };
|
|
11712
11846
|
}
|
|
11713
11847
|
try {
|
|
11714
|
-
return JSON.parse(
|
|
11848
|
+
return JSON.parse(fs44.readFileSync(filePath, "utf-8"));
|
|
11715
11849
|
} catch {
|
|
11716
11850
|
try {
|
|
11717
11851
|
const corruptPath = filePath + ".corrupt";
|
|
11718
|
-
|
|
11852
|
+
fs44.renameSync(filePath, corruptPath);
|
|
11719
11853
|
console.error(`caliber: roi-stats.json was corrupt \u2014 renamed to ${corruptPath}`);
|
|
11720
11854
|
} catch {
|
|
11721
11855
|
}
|
|
@@ -11724,7 +11858,7 @@ function readROIStats() {
|
|
|
11724
11858
|
}
|
|
11725
11859
|
function writeROIStats(stats) {
|
|
11726
11860
|
ensureLearningDir();
|
|
11727
|
-
|
|
11861
|
+
fs44.writeFileSync(roiFilePath(), JSON.stringify(stats, null, 2));
|
|
11728
11862
|
}
|
|
11729
11863
|
function recalculateTotals(stats) {
|
|
11730
11864
|
const totals = stats.totals;
|
|
@@ -11933,9 +12067,9 @@ var AUTO_SETTLE_MS = 200;
|
|
|
11933
12067
|
var INCREMENTAL_INTERVAL = 50;
|
|
11934
12068
|
function writeFinalizeError(message) {
|
|
11935
12069
|
try {
|
|
11936
|
-
const errorPath =
|
|
11937
|
-
if (!
|
|
11938
|
-
|
|
12070
|
+
const errorPath = path37.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
|
|
12071
|
+
if (!fs45.existsSync(getLearningDir())) fs45.mkdirSync(getLearningDir(), { recursive: true });
|
|
12072
|
+
fs45.writeFileSync(errorPath, JSON.stringify({
|
|
11939
12073
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11940
12074
|
error: message,
|
|
11941
12075
|
pid: process.pid
|
|
@@ -11945,9 +12079,9 @@ function writeFinalizeError(message) {
|
|
|
11945
12079
|
}
|
|
11946
12080
|
function readFinalizeError() {
|
|
11947
12081
|
try {
|
|
11948
|
-
const errorPath =
|
|
11949
|
-
if (!
|
|
11950
|
-
return JSON.parse(
|
|
12082
|
+
const errorPath = path37.join(getLearningDir(), LEARNING_LAST_ERROR_FILE);
|
|
12083
|
+
if (!fs45.existsSync(errorPath)) return null;
|
|
12084
|
+
return JSON.parse(fs45.readFileSync(errorPath, "utf-8"));
|
|
11951
12085
|
} catch {
|
|
11952
12086
|
return null;
|
|
11953
12087
|
}
|
|
@@ -11994,14 +12128,14 @@ async function learnObserveCommand(options) {
|
|
|
11994
12128
|
const { resolveCaliber: resolveCaliber2 } = await Promise.resolve().then(() => (init_resolve_caliber(), resolve_caliber_exports));
|
|
11995
12129
|
const bin = resolveCaliber2();
|
|
11996
12130
|
const { spawn: spawn4 } = await import("child_process");
|
|
11997
|
-
const logPath =
|
|
11998
|
-
if (!
|
|
11999
|
-
const logFd =
|
|
12131
|
+
const logPath = path37.join(getLearningDir(), LEARNING_FINALIZE_LOG);
|
|
12132
|
+
if (!fs45.existsSync(getLearningDir())) fs45.mkdirSync(getLearningDir(), { recursive: true });
|
|
12133
|
+
const logFd = fs45.openSync(logPath, "a");
|
|
12000
12134
|
spawn4(bin, ["learn", "finalize", "--auto", "--incremental"], {
|
|
12001
12135
|
detached: true,
|
|
12002
12136
|
stdio: ["ignore", logFd, logFd]
|
|
12003
12137
|
}).unref();
|
|
12004
|
-
|
|
12138
|
+
fs45.closeSync(logFd);
|
|
12005
12139
|
} catch {
|
|
12006
12140
|
}
|
|
12007
12141
|
}
|
|
@@ -12208,7 +12342,7 @@ async function learnFinalizeCommand(options) {
|
|
|
12208
12342
|
}
|
|
12209
12343
|
async function learnInstallCommand() {
|
|
12210
12344
|
let anyInstalled = false;
|
|
12211
|
-
if (
|
|
12345
|
+
if (fs45.existsSync(".claude")) {
|
|
12212
12346
|
const r = installLearningHooks();
|
|
12213
12347
|
if (r.installed) {
|
|
12214
12348
|
console.log(chalk23.green("\u2713") + " Claude Code learning hooks installed");
|
|
@@ -12217,7 +12351,7 @@ async function learnInstallCommand() {
|
|
|
12217
12351
|
console.log(chalk23.dim(" Claude Code hooks already installed"));
|
|
12218
12352
|
}
|
|
12219
12353
|
}
|
|
12220
|
-
if (
|
|
12354
|
+
if (fs45.existsSync(".cursor")) {
|
|
12221
12355
|
const r = installCursorLearningHooks();
|
|
12222
12356
|
if (r.installed) {
|
|
12223
12357
|
console.log(chalk23.green("\u2713") + " Cursor learning hooks installed");
|
|
@@ -12226,7 +12360,7 @@ async function learnInstallCommand() {
|
|
|
12226
12360
|
console.log(chalk23.dim(" Cursor hooks already installed"));
|
|
12227
12361
|
}
|
|
12228
12362
|
}
|
|
12229
|
-
if (!
|
|
12363
|
+
if (!fs45.existsSync(".claude") && !fs45.existsSync(".cursor")) {
|
|
12230
12364
|
console.log(chalk23.yellow("No .claude/ or .cursor/ directory found."));
|
|
12231
12365
|
console.log(chalk23.dim(` Run \`${resolveCaliber()} init\` first, or create the directory manually.`));
|
|
12232
12366
|
return;
|
|
@@ -12284,8 +12418,8 @@ async function learnStatusCommand() {
|
|
|
12284
12418
|
if (lastError) {
|
|
12285
12419
|
console.log(`Last error: ${chalk23.red(lastError.error)}`);
|
|
12286
12420
|
console.log(chalk23.dim(` at ${lastError.timestamp}`));
|
|
12287
|
-
const logPath =
|
|
12288
|
-
if (
|
|
12421
|
+
const logPath = path37.join(getLearningDir(), LEARNING_FINALIZE_LOG);
|
|
12422
|
+
if (fs45.existsSync(logPath)) {
|
|
12289
12423
|
console.log(chalk23.dim(` Full log: ${logPath}`));
|
|
12290
12424
|
}
|
|
12291
12425
|
}
|
|
@@ -12365,11 +12499,11 @@ async function learnDeleteCommand(indexStr) {
|
|
|
12365
12499
|
}
|
|
12366
12500
|
const item = items[targetIdx];
|
|
12367
12501
|
const filePath = item.source === "personal" ? PERSONAL_LEARNINGS_FILE : "CALIBER_LEARNINGS.md";
|
|
12368
|
-
if (!
|
|
12502
|
+
if (!fs45.existsSync(filePath)) {
|
|
12369
12503
|
console.log(chalk23.red("Learnings file not found."));
|
|
12370
12504
|
return;
|
|
12371
12505
|
}
|
|
12372
|
-
const content =
|
|
12506
|
+
const content = fs45.readFileSync(filePath, "utf-8");
|
|
12373
12507
|
const lines = content.split("\n");
|
|
12374
12508
|
const bulletsOfSource = items.filter((i) => i.source === item.source);
|
|
12375
12509
|
const posInFile = bulletsOfSource.indexOf(item);
|
|
@@ -12390,9 +12524,9 @@ async function learnDeleteCommand(indexStr) {
|
|
|
12390
12524
|
}
|
|
12391
12525
|
const bulletToRemove = lines[lineToRemove];
|
|
12392
12526
|
const newLines = lines.filter((_, i) => i !== lineToRemove);
|
|
12393
|
-
|
|
12527
|
+
fs45.writeFileSync(filePath, newLines.join("\n"));
|
|
12394
12528
|
if (item.source === "personal") {
|
|
12395
|
-
|
|
12529
|
+
fs45.chmodSync(filePath, 384);
|
|
12396
12530
|
}
|
|
12397
12531
|
const roiStats = readROIStats();
|
|
12398
12532
|
const cleanText = bulletToRemove.replace(/^- /, "").replace(/^\*\*\[[^\]]+\]\*\*\s*/, "").trim();
|
|
@@ -12565,8 +12699,8 @@ async function insightsCommand(options) {
|
|
|
12565
12699
|
}
|
|
12566
12700
|
|
|
12567
12701
|
// src/commands/sources.ts
|
|
12568
|
-
import
|
|
12569
|
-
import
|
|
12702
|
+
import fs46 from "fs";
|
|
12703
|
+
import path38 from "path";
|
|
12570
12704
|
import chalk25 from "chalk";
|
|
12571
12705
|
init_resolve_caliber();
|
|
12572
12706
|
async function sourcesListCommand() {
|
|
@@ -12583,9 +12717,9 @@ async function sourcesListCommand() {
|
|
|
12583
12717
|
if (configSources.length > 0) {
|
|
12584
12718
|
for (const source of configSources) {
|
|
12585
12719
|
const sourcePath = source.path || source.url || "";
|
|
12586
|
-
const exists = source.path ?
|
|
12720
|
+
const exists = source.path ? fs46.existsSync(path38.resolve(dir, source.path)) : false;
|
|
12587
12721
|
const status = exists ? chalk25.green("reachable") : chalk25.red("not found");
|
|
12588
|
-
const hasSummary = source.path &&
|
|
12722
|
+
const hasSummary = source.path && fs46.existsSync(path38.join(path38.resolve(dir, source.path), ".caliber", "summary.json"));
|
|
12589
12723
|
console.log(` ${chalk25.bold(source.role || source.type)} ${chalk25.dim(sourcePath)}`);
|
|
12590
12724
|
console.log(` Type: ${source.type} Status: ${status}${hasSummary ? " " + chalk25.cyan("has summary.json") : ""}`);
|
|
12591
12725
|
if (source.description) console.log(` ${chalk25.dim(source.description)}`);
|
|
@@ -12595,7 +12729,7 @@ async function sourcesListCommand() {
|
|
|
12595
12729
|
if (workspaces.length > 0) {
|
|
12596
12730
|
console.log(chalk25.dim(" Auto-detected workspaces:"));
|
|
12597
12731
|
for (const ws of workspaces) {
|
|
12598
|
-
const exists =
|
|
12732
|
+
const exists = fs46.existsSync(path38.resolve(dir, ws));
|
|
12599
12733
|
console.log(` ${exists ? chalk25.green("\u25CF") : chalk25.red("\u25CF")} ${ws}`);
|
|
12600
12734
|
}
|
|
12601
12735
|
console.log("");
|
|
@@ -12603,8 +12737,8 @@ async function sourcesListCommand() {
|
|
|
12603
12737
|
}
|
|
12604
12738
|
async function sourcesAddCommand(sourcePath) {
|
|
12605
12739
|
const dir = process.cwd();
|
|
12606
|
-
const absPath =
|
|
12607
|
-
if (!
|
|
12740
|
+
const absPath = path38.resolve(dir, sourcePath);
|
|
12741
|
+
if (!fs46.existsSync(absPath)) {
|
|
12608
12742
|
console.log(chalk25.red(`
|
|
12609
12743
|
Path not found: ${sourcePath}
|
|
12610
12744
|
`));
|
|
@@ -12619,7 +12753,7 @@ async function sourcesAddCommand(sourcePath) {
|
|
|
12619
12753
|
}
|
|
12620
12754
|
const existing = loadSourcesConfig(dir);
|
|
12621
12755
|
const alreadyConfigured = existing.some(
|
|
12622
|
-
(s) => s.path &&
|
|
12756
|
+
(s) => s.path && path38.resolve(dir, s.path) === absPath
|
|
12623
12757
|
);
|
|
12624
12758
|
if (alreadyConfigured) {
|
|
12625
12759
|
console.log(chalk25.yellow(`
|
|
@@ -12667,8 +12801,8 @@ async function sourcesRemoveCommand(name) {
|
|
|
12667
12801
|
}
|
|
12668
12802
|
|
|
12669
12803
|
// src/commands/publish.ts
|
|
12670
|
-
import
|
|
12671
|
-
import
|
|
12804
|
+
import fs47 from "fs";
|
|
12805
|
+
import path39 from "path";
|
|
12672
12806
|
import chalk26 from "chalk";
|
|
12673
12807
|
import ora7 from "ora";
|
|
12674
12808
|
init_config();
|
|
@@ -12683,10 +12817,10 @@ async function publishCommand() {
|
|
|
12683
12817
|
const spinner = ora7("Generating project summary...").start();
|
|
12684
12818
|
try {
|
|
12685
12819
|
const fingerprint = await collectFingerprint(dir);
|
|
12686
|
-
const claudeMd = readFileOrNull(
|
|
12820
|
+
const claudeMd = readFileOrNull(path39.join(dir, "CLAUDE.md"));
|
|
12687
12821
|
const topLevelDirs = fingerprint.fileTree.filter((f) => f.endsWith("/") && !f.includes("/")).map((f) => f.replace(/\/$/, ""));
|
|
12688
12822
|
const summary = {
|
|
12689
|
-
name: fingerprint.packageName ||
|
|
12823
|
+
name: fingerprint.packageName || path39.basename(dir),
|
|
12690
12824
|
version: "1.0.0",
|
|
12691
12825
|
description: fingerprint.description || "",
|
|
12692
12826
|
languages: fingerprint.languages,
|
|
@@ -12698,7 +12832,7 @@ async function publishCommand() {
|
|
|
12698
12832
|
summary.conventions = claudeMd.slice(0, 2e3);
|
|
12699
12833
|
}
|
|
12700
12834
|
try {
|
|
12701
|
-
const pkgContent = readFileOrNull(
|
|
12835
|
+
const pkgContent = readFileOrNull(path39.join(dir, "package.json"));
|
|
12702
12836
|
if (pkgContent) {
|
|
12703
12837
|
const pkg3 = JSON.parse(pkgContent);
|
|
12704
12838
|
if (pkg3.scripts) {
|
|
@@ -12711,14 +12845,14 @@ async function publishCommand() {
|
|
|
12711
12845
|
}
|
|
12712
12846
|
} catch {
|
|
12713
12847
|
}
|
|
12714
|
-
const outputDir =
|
|
12715
|
-
if (!
|
|
12716
|
-
|
|
12848
|
+
const outputDir = path39.join(dir, ".caliber");
|
|
12849
|
+
if (!fs47.existsSync(outputDir)) {
|
|
12850
|
+
fs47.mkdirSync(outputDir, { recursive: true });
|
|
12717
12851
|
}
|
|
12718
|
-
const outputPath =
|
|
12719
|
-
|
|
12852
|
+
const outputPath = path39.join(outputDir, "summary.json");
|
|
12853
|
+
fs47.writeFileSync(outputPath, JSON.stringify(summary, null, 2) + "\n", "utf-8");
|
|
12720
12854
|
spinner.succeed("Project summary published");
|
|
12721
|
-
console.log(` ${chalk26.green("\u2713")} ${
|
|
12855
|
+
console.log(` ${chalk26.green("\u2713")} ${path39.relative(dir, outputPath)}`);
|
|
12722
12856
|
console.log(chalk26.dim("\n Other projects can now reference this repo as a source."));
|
|
12723
12857
|
console.log(chalk26.dim(" When they run `caliber init`, they'll read this summary automatically.\n"));
|
|
12724
12858
|
} catch (err) {
|
|
@@ -12731,7 +12865,7 @@ async function publishCommand() {
|
|
|
12731
12865
|
|
|
12732
12866
|
// src/commands/bootstrap.ts
|
|
12733
12867
|
init_builtin_skills();
|
|
12734
|
-
import
|
|
12868
|
+
import fs48 from "fs";
|
|
12735
12869
|
import chalk27 from "chalk";
|
|
12736
12870
|
var PLATFORM_SKILL_DIRS = {
|
|
12737
12871
|
claude: ".claude/skills",
|
|
@@ -12752,8 +12886,8 @@ async function bootstrapCommand() {
|
|
|
12752
12886
|
for (const skill of BUILTIN_SKILLS) {
|
|
12753
12887
|
const skillDir = `${skillsDir}/${skill.name}`;
|
|
12754
12888
|
const skillPath = `${skillDir}/SKILL.md`;
|
|
12755
|
-
|
|
12756
|
-
|
|
12889
|
+
fs48.mkdirSync(skillDir, { recursive: true });
|
|
12890
|
+
fs48.writeFileSync(skillPath, buildSkillContent(skill));
|
|
12757
12891
|
written.push(skillPath);
|
|
12758
12892
|
}
|
|
12759
12893
|
}
|
|
@@ -12770,8 +12904,8 @@ async function bootstrapCommand() {
|
|
|
12770
12904
|
}
|
|
12771
12905
|
|
|
12772
12906
|
// src/commands/uninstall.ts
|
|
12773
|
-
import
|
|
12774
|
-
import
|
|
12907
|
+
import fs49 from "fs";
|
|
12908
|
+
import path40 from "path";
|
|
12775
12909
|
import chalk28 from "chalk";
|
|
12776
12910
|
import confirm3 from "@inquirer/confirm";
|
|
12777
12911
|
init_pre_commit_block();
|
|
@@ -12779,18 +12913,18 @@ init_builtin_skills();
|
|
|
12779
12913
|
init_config();
|
|
12780
12914
|
var MANAGED_DOC_FILES = [
|
|
12781
12915
|
"CLAUDE.md",
|
|
12782
|
-
|
|
12916
|
+
path40.join(".github", "copilot-instructions.md"),
|
|
12783
12917
|
"AGENTS.md"
|
|
12784
12918
|
];
|
|
12785
12919
|
var SKILL_DIRS = PLATFORM_CONFIGS.map((c) => c.skillsDir);
|
|
12786
|
-
var CURSOR_RULES_DIR =
|
|
12920
|
+
var CURSOR_RULES_DIR = path40.join(".cursor", "rules");
|
|
12787
12921
|
function removeCaliberCursorRules() {
|
|
12788
12922
|
const removed = [];
|
|
12789
|
-
if (!
|
|
12790
|
-
for (const file of
|
|
12923
|
+
if (!fs49.existsSync(CURSOR_RULES_DIR)) return removed;
|
|
12924
|
+
for (const file of fs49.readdirSync(CURSOR_RULES_DIR)) {
|
|
12791
12925
|
if (file.startsWith("caliber-") && file.endsWith(".mdc")) {
|
|
12792
|
-
const fullPath =
|
|
12793
|
-
|
|
12926
|
+
const fullPath = path40.join(CURSOR_RULES_DIR, file);
|
|
12927
|
+
fs49.unlinkSync(fullPath);
|
|
12794
12928
|
removed.push(fullPath);
|
|
12795
12929
|
}
|
|
12796
12930
|
}
|
|
@@ -12799,11 +12933,11 @@ function removeCaliberCursorRules() {
|
|
|
12799
12933
|
function removeBuiltinSkills() {
|
|
12800
12934
|
const removed = [];
|
|
12801
12935
|
for (const skillsDir of SKILL_DIRS) {
|
|
12802
|
-
if (!
|
|
12936
|
+
if (!fs49.existsSync(skillsDir)) continue;
|
|
12803
12937
|
for (const name of BUILTIN_SKILL_NAMES) {
|
|
12804
|
-
const skillDir =
|
|
12805
|
-
if (
|
|
12806
|
-
|
|
12938
|
+
const skillDir = path40.join(skillsDir, name);
|
|
12939
|
+
if (fs49.existsSync(skillDir)) {
|
|
12940
|
+
fs49.rmSync(skillDir, { recursive: true });
|
|
12807
12941
|
removed.push(skillDir);
|
|
12808
12942
|
}
|
|
12809
12943
|
}
|
|
@@ -12813,15 +12947,15 @@ function removeBuiltinSkills() {
|
|
|
12813
12947
|
function stripManagedBlocksFromFiles() {
|
|
12814
12948
|
const modified = [];
|
|
12815
12949
|
for (const filePath of MANAGED_DOC_FILES) {
|
|
12816
|
-
if (!
|
|
12817
|
-
const original =
|
|
12950
|
+
if (!fs49.existsSync(filePath)) continue;
|
|
12951
|
+
const original = fs49.readFileSync(filePath, "utf-8");
|
|
12818
12952
|
const stripped = stripManagedBlocks(original);
|
|
12819
12953
|
if (stripped !== original) {
|
|
12820
12954
|
const trimmed = stripped.trim();
|
|
12821
12955
|
if (!trimmed || /^#\s*\S*$/.test(trimmed)) {
|
|
12822
|
-
|
|
12956
|
+
fs49.unlinkSync(filePath);
|
|
12823
12957
|
} else {
|
|
12824
|
-
|
|
12958
|
+
fs49.writeFileSync(filePath, stripped);
|
|
12825
12959
|
}
|
|
12826
12960
|
modified.push(filePath);
|
|
12827
12961
|
}
|
|
@@ -12829,8 +12963,8 @@ function stripManagedBlocksFromFiles() {
|
|
|
12829
12963
|
return modified;
|
|
12830
12964
|
}
|
|
12831
12965
|
function removeDirectory(dir) {
|
|
12832
|
-
if (!
|
|
12833
|
-
|
|
12966
|
+
if (!fs49.existsSync(dir)) return false;
|
|
12967
|
+
fs49.rmSync(dir, { recursive: true });
|
|
12834
12968
|
return true;
|
|
12835
12969
|
}
|
|
12836
12970
|
async function uninstallCommand(options) {
|
|
@@ -12887,8 +13021,8 @@ async function uninstallCommand(options) {
|
|
|
12887
13021
|
console.log(` ${chalk28.red("\u2717")} ${skill}/`);
|
|
12888
13022
|
}
|
|
12889
13023
|
if (removedSkills.length > 0) actions.push("builtin skills");
|
|
12890
|
-
if (
|
|
12891
|
-
|
|
13024
|
+
if (fs49.existsSync("CALIBER_LEARNINGS.md")) {
|
|
13025
|
+
fs49.unlinkSync("CALIBER_LEARNINGS.md");
|
|
12892
13026
|
console.log(` ${chalk28.red("\u2717")} CALIBER_LEARNINGS.md`);
|
|
12893
13027
|
actions.push("learnings file");
|
|
12894
13028
|
}
|
|
@@ -12902,18 +13036,18 @@ async function uninstallCommand(options) {
|
|
|
12902
13036
|
}
|
|
12903
13037
|
trackUninstallExecuted();
|
|
12904
13038
|
const configPath = getConfigFilePath();
|
|
12905
|
-
if (
|
|
13039
|
+
if (fs49.existsSync(configPath)) {
|
|
12906
13040
|
console.log("");
|
|
12907
13041
|
const removeConfig = options.force || await confirm3({
|
|
12908
13042
|
message: `Remove global config (~/.caliber/config.json)? This affects all projects.`
|
|
12909
13043
|
});
|
|
12910
13044
|
if (removeConfig) {
|
|
12911
|
-
|
|
13045
|
+
fs49.unlinkSync(configPath);
|
|
12912
13046
|
console.log(` ${chalk28.red("\u2717")} ${configPath}`);
|
|
12913
|
-
const configDir =
|
|
13047
|
+
const configDir = path40.dirname(configPath);
|
|
12914
13048
|
try {
|
|
12915
|
-
const remaining =
|
|
12916
|
-
if (remaining.length === 0)
|
|
13049
|
+
const remaining = fs49.readdirSync(configDir);
|
|
13050
|
+
if (remaining.length === 0) fs49.rmdirSync(configDir);
|
|
12917
13051
|
} catch {
|
|
12918
13052
|
}
|
|
12919
13053
|
}
|
|
@@ -12924,9 +13058,9 @@ async function uninstallCommand(options) {
|
|
|
12924
13058
|
}
|
|
12925
13059
|
|
|
12926
13060
|
// src/cli.ts
|
|
12927
|
-
var __dirname =
|
|
13061
|
+
var __dirname = path41.dirname(fileURLToPath(import.meta.url));
|
|
12928
13062
|
var pkg = JSON.parse(
|
|
12929
|
-
|
|
13063
|
+
fs50.readFileSync(path41.resolve(__dirname, "..", "package.json"), "utf-8")
|
|
12930
13064
|
);
|
|
12931
13065
|
var program = new Command();
|
|
12932
13066
|
var displayVersion = process.env.CALIBER_LOCAL ? `${pkg.version}-local` : pkg.version;
|
|
@@ -12980,16 +13114,16 @@ program.hook("preAction", (thisCommand) => {
|
|
|
12980
13114
|
});
|
|
12981
13115
|
function parseAgentOption(value) {
|
|
12982
13116
|
if (value === "both") return ["claude", "cursor"];
|
|
12983
|
-
if (value === "all") return ["claude", "cursor", "codex", "github-copilot"];
|
|
12984
|
-
const valid = ["claude", "cursor", "codex", "github-copilot"];
|
|
13117
|
+
if (value === "all") return ["claude", "cursor", "codex", "opencode", "github-copilot"];
|
|
13118
|
+
const valid = ["claude", "cursor", "codex", "opencode", "github-copilot"];
|
|
12985
13119
|
const agents = [...new Set(value.split(",").map((s) => s.trim().toLowerCase()).filter((a) => valid.includes(a)))];
|
|
12986
13120
|
if (agents.length === 0) {
|
|
12987
|
-
console.error(`Invalid agent "${value}". Choose from: claude, cursor, codex, github-copilot (comma-separated for multiple)`);
|
|
13121
|
+
console.error(`Invalid agent "${value}". Choose from: claude, cursor, codex, opencode, github-copilot (comma-separated for multiple)`);
|
|
12988
13122
|
process.exit(1);
|
|
12989
13123
|
}
|
|
12990
13124
|
return agents;
|
|
12991
13125
|
}
|
|
12992
|
-
program.command("init").description("Initialize your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, github-copilot", parseAgentOption).option("--source <paths...>", "Related source paths to include as context").option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing config without prompting").option("--debug-report", void 0, false).option("--show-tokens", "Show token usage summary at the end").option("--auto-approve", "Run without interactive prompts (auto-accept all)").option("--verbose", "Show detailed logs of each step").action(tracked("init", initCommand));
|
|
13126
|
+
program.command("init").description("Initialize your project for AI-assisted development").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, opencode, github-copilot", parseAgentOption).option("--source <paths...>", "Related source paths to include as context").option("--dry-run", "Preview changes without writing files").option("--force", "Overwrite existing config without prompting").option("--debug-report", void 0, false).option("--show-tokens", "Show token usage summary at the end").option("--auto-approve", "Run without interactive prompts (auto-accept all)").option("--verbose", "Show detailed logs of each step").action(tracked("init", initCommand));
|
|
12993
13127
|
program.command("bootstrap").description("Install agent skills (/setup-caliber, /find-skills, /save-learning) without running init").action(tracked("bootstrap", bootstrapCommand));
|
|
12994
13128
|
program.command("undo").description("Revert all config changes made by Caliber").action(tracked("undo", undoCommand));
|
|
12995
13129
|
program.command("uninstall").description("Remove all Caliber resources from this project").option("--force", "Skip confirmation prompt").action(tracked("uninstall", (options) => uninstallCommand(options)));
|
|
@@ -12997,7 +13131,7 @@ program.command("status").description("Show current Caliber config status").opti
|
|
|
12997
13131
|
program.command("regenerate").alias("regen").alias("re").description("Re-analyze project and regenerate config").option("--dry-run", "Preview changes without writing files").action(tracked("regenerate", regenerateCommand));
|
|
12998
13132
|
program.command("config").description("Configure LLM provider, API key, and model").action(tracked("config", configCommand));
|
|
12999
13133
|
program.command("skills").description("Discover and install community skills for your project").option("--query <terms>", 'Search for skills by topic (e.g. "react frontend")').option("--install <slugs>", "Install specific skills by slug (comma-separated)").action(tracked("skills", recommendCommand));
|
|
13000
|
-
program.command("score").description("Score your AI context configuration (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, github-copilot", parseAgentOption).option("--compare <ref>", "Compare score against a git ref (branch, tag, or SHA)").action(tracked("score", scoreCommand));
|
|
13134
|
+
program.command("score").description("Score your AI context configuration (deterministic, no network)").option("--json", "Output as JSON").option("--quiet", "One-line output for scripts/hooks").option("--agent <type>", "Target agents (comma-separated): claude, cursor, codex, opencode, github-copilot", parseAgentOption).option("--compare <ref>", "Compare score against a git ref (branch, tag, or SHA)").action(tracked("score", scoreCommand));
|
|
13001
13135
|
program.command("refresh").description("Update docs based on recent code changes").option("--quiet", "Suppress output (for use in hooks)").option("--dry-run", "Preview changes without writing files").action(tracked("refresh", refreshCommand));
|
|
13002
13136
|
program.command("hooks").description("Manage auto-refresh hooks (toggle interactively)").option("--install", "Enable all hooks non-interactively").option("--remove", "Disable all hooks non-interactively").action(tracked("hooks", hooksCommand));
|
|
13003
13137
|
program.command("insights").description("Show agent performance insights and learning impact").option("--json", "Output as JSON").action(tracked("insights", insightsCommand));
|
|
@@ -13017,15 +13151,15 @@ learn.command("delete <index>").description("Delete a learning by its index numb
|
|
|
13017
13151
|
learn.command("add <content>").description("Add a learning directly (used by agent skills)").option("--personal", "Save as a personal learning instead of project-level").action(tracked("learn:add", learnAddCommand));
|
|
13018
13152
|
|
|
13019
13153
|
// src/utils/version-check.ts
|
|
13020
|
-
import
|
|
13021
|
-
import
|
|
13154
|
+
import fs51 from "fs";
|
|
13155
|
+
import path42 from "path";
|
|
13022
13156
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13023
13157
|
import { execSync as execSync16, execFileSync as execFileSync3 } from "child_process";
|
|
13024
13158
|
import chalk29 from "chalk";
|
|
13025
13159
|
import ora8 from "ora";
|
|
13026
13160
|
import confirm4 from "@inquirer/confirm";
|
|
13027
|
-
var __dirname_vc =
|
|
13028
|
-
var pkg2 = JSON.parse(
|
|
13161
|
+
var __dirname_vc = path42.dirname(fileURLToPath2(import.meta.url));
|
|
13162
|
+
var pkg2 = JSON.parse(fs51.readFileSync(path42.resolve(__dirname_vc, "..", "package.json"), "utf-8"));
|
|
13029
13163
|
function getChannel(version) {
|
|
13030
13164
|
const match = version.match(/-(dev|next)\./);
|
|
13031
13165
|
return match ? match[1] : "latest";
|
|
@@ -13052,8 +13186,8 @@ function getInstalledVersion() {
|
|
|
13052
13186
|
encoding: "utf-8",
|
|
13053
13187
|
stdio: ["pipe", "pipe", "pipe"]
|
|
13054
13188
|
}).trim();
|
|
13055
|
-
const pkgPath =
|
|
13056
|
-
return JSON.parse(
|
|
13189
|
+
const pkgPath = path42.join(globalRoot, "@rely-ai", "caliber", "package.json");
|
|
13190
|
+
return JSON.parse(fs51.readFileSync(pkgPath, "utf-8")).version;
|
|
13057
13191
|
} catch {
|
|
13058
13192
|
return null;
|
|
13059
13193
|
}
|