claudekit-cli 3.42.2-dev.8 → 3.42.2-dev.9
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/cli-manifest.json +2 -2
- package/dist/index.js +537 -248
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6944,7 +6944,7 @@ function resolveModel(sourceModel, targetProvider) {
|
|
|
6944
6944
|
}
|
|
6945
6945
|
return { resolved: providerMap[tier] };
|
|
6946
6946
|
}
|
|
6947
|
-
var
|
|
6947
|
+
var SOURCE_TIER_MAP, DEFAULT_PROVIDER_MODEL_MAP, userOverrides;
|
|
6948
6948
|
var init_model_taxonomy = __esm(() => {
|
|
6949
6949
|
SOURCE_TIER_MAP = {
|
|
6950
6950
|
opus: "heavy",
|
|
@@ -62389,7 +62389,7 @@ var package_default;
|
|
|
62389
62389
|
var init_package = __esm(() => {
|
|
62390
62390
|
package_default = {
|
|
62391
62391
|
name: "claudekit-cli",
|
|
62392
|
-
version: "3.42.2-dev.
|
|
62392
|
+
version: "3.42.2-dev.9",
|
|
62393
62393
|
description: "CLI tool for bootstrapping and updating ClaudeKit projects",
|
|
62394
62394
|
type: "module",
|
|
62395
62395
|
repository: {
|
|
@@ -73556,10 +73556,10 @@ __export(exports_worktree_manager, {
|
|
|
73556
73556
|
cleanupAllWorktrees: () => cleanupAllWorktrees
|
|
73557
73557
|
});
|
|
73558
73558
|
import { existsSync as existsSync69 } from "node:fs";
|
|
73559
|
-
import { readFile as
|
|
73560
|
-
import { join as
|
|
73559
|
+
import { readFile as readFile65, writeFile as writeFile37 } from "node:fs/promises";
|
|
73560
|
+
import { join as join153 } from "node:path";
|
|
73561
73561
|
async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
73562
|
-
const worktreePath =
|
|
73562
|
+
const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
73563
73563
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
73564
73564
|
await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
|
|
73565
73565
|
logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
|
|
@@ -73577,7 +73577,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
|
73577
73577
|
return worktreePath;
|
|
73578
73578
|
}
|
|
73579
73579
|
async function removeWorktree(projectDir, issueNumber) {
|
|
73580
|
-
const worktreePath =
|
|
73580
|
+
const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
73581
73581
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
73582
73582
|
try {
|
|
73583
73583
|
await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
|
|
@@ -73591,7 +73591,7 @@ async function listActiveWorktrees(projectDir) {
|
|
|
73591
73591
|
try {
|
|
73592
73592
|
const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
|
|
73593
73593
|
const issueNumbers = [];
|
|
73594
|
-
const worktreePrefix =
|
|
73594
|
+
const worktreePrefix = join153(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
|
|
73595
73595
|
for (const line of output2.split(`
|
|
73596
73596
|
`)) {
|
|
73597
73597
|
if (line.startsWith("worktree ")) {
|
|
@@ -73619,16 +73619,16 @@ async function cleanupAllWorktrees(projectDir) {
|
|
|
73619
73619
|
await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
|
|
73620
73620
|
}
|
|
73621
73621
|
async function ensureGitignore(projectDir) {
|
|
73622
|
-
const gitignorePath =
|
|
73622
|
+
const gitignorePath = join153(projectDir, ".gitignore");
|
|
73623
73623
|
try {
|
|
73624
|
-
const content = existsSync69(gitignorePath) ? await
|
|
73624
|
+
const content = existsSync69(gitignorePath) ? await readFile65(gitignorePath, "utf-8") : "";
|
|
73625
73625
|
if (!content.includes(".worktrees")) {
|
|
73626
73626
|
const newContent = content.endsWith(`
|
|
73627
73627
|
`) ? `${content}.worktrees/
|
|
73628
73628
|
` : `${content}
|
|
73629
73629
|
.worktrees/
|
|
73630
73630
|
`;
|
|
73631
|
-
await
|
|
73631
|
+
await writeFile37(gitignorePath, newContent, "utf-8");
|
|
73632
73632
|
logger.info("[worktree] Added .worktrees/ to .gitignore");
|
|
73633
73633
|
}
|
|
73634
73634
|
} catch (err) {
|
|
@@ -73657,15 +73657,15 @@ function countTwitterChars(text) {
|
|
|
73657
73657
|
}
|
|
73658
73658
|
return count;
|
|
73659
73659
|
}
|
|
73660
|
-
function validateContent(content,
|
|
73660
|
+
function validateContent(content, platform18) {
|
|
73661
73661
|
const issues = [];
|
|
73662
73662
|
if (!content.text || content.text.trim().length === 0) {
|
|
73663
73663
|
issues.push("Content text is empty");
|
|
73664
73664
|
return { valid: false, issues };
|
|
73665
73665
|
}
|
|
73666
|
-
if (
|
|
73667
|
-
const limit =
|
|
73668
|
-
const charCount =
|
|
73666
|
+
if (platform18 !== "x_thread") {
|
|
73667
|
+
const limit = platform18 === "facebook" ? 500 : 280;
|
|
73668
|
+
const charCount = platform18 === "x" ? countTwitterChars(content.text) : content.text.length;
|
|
73669
73669
|
if (charCount > limit) {
|
|
73670
73670
|
issues.push(`Text exceeds ${limit} char limit (${charCount} weighted chars)`);
|
|
73671
73671
|
}
|
|
@@ -73688,7 +73688,7 @@ function validateContent(content, platform17) {
|
|
|
73688
73688
|
issues.push("Hook (first sentence) is too long (>25 words)");
|
|
73689
73689
|
}
|
|
73690
73690
|
const hashtagCount = content.hashtags?.length ?? 0;
|
|
73691
|
-
if (
|
|
73691
|
+
if (platform18 === "x" && hashtagCount > 5) {
|
|
73692
73692
|
issues.push("Too many hashtags for X (max 5)");
|
|
73693
73693
|
}
|
|
73694
73694
|
return { valid: issues.length === 0, issues };
|
|
@@ -73724,9 +73724,9 @@ var init_content_validator = __esm(() => {
|
|
|
73724
73724
|
// src/commands/content/phases/context-cache-manager.ts
|
|
73725
73725
|
import { createHash as createHash9 } from "node:crypto";
|
|
73726
73726
|
import { existsSync as existsSync75, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync14 } from "node:fs";
|
|
73727
|
-
import { rename as
|
|
73728
|
-
import { homedir as
|
|
73729
|
-
import { basename as basename31, join as
|
|
73727
|
+
import { rename as rename15, writeFile as writeFile39 } from "node:fs/promises";
|
|
73728
|
+
import { homedir as homedir54 } from "node:os";
|
|
73729
|
+
import { basename as basename31, join as join160 } from "node:path";
|
|
73730
73730
|
function getCachedContext(repoPath) {
|
|
73731
73731
|
const cachePath = getCacheFilePath(repoPath);
|
|
73732
73732
|
if (!existsSync75(cachePath))
|
|
@@ -73735,7 +73735,7 @@ function getCachedContext(repoPath) {
|
|
|
73735
73735
|
const raw2 = readFileSync18(cachePath, "utf-8");
|
|
73736
73736
|
const cache5 = JSON.parse(raw2);
|
|
73737
73737
|
const age = Date.now() - new Date(cache5.createdAt).getTime();
|
|
73738
|
-
if (age >=
|
|
73738
|
+
if (age >= CACHE_TTL_MS5)
|
|
73739
73739
|
return null;
|
|
73740
73740
|
const currentHash = computeSourceHash(repoPath);
|
|
73741
73741
|
if (currentHash !== cache5.sourceHash)
|
|
@@ -73751,8 +73751,8 @@ async function saveCachedContext(repoPath, cache5) {
|
|
|
73751
73751
|
}
|
|
73752
73752
|
const cachePath = getCacheFilePath(repoPath);
|
|
73753
73753
|
const tmpPath = `${cachePath}.tmp`;
|
|
73754
|
-
await
|
|
73755
|
-
await
|
|
73754
|
+
await writeFile39(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
|
|
73755
|
+
await rename15(tmpPath, cachePath);
|
|
73756
73756
|
}
|
|
73757
73757
|
function computeSourceHash(repoPath) {
|
|
73758
73758
|
const hash = createHash9("sha256");
|
|
@@ -73769,25 +73769,25 @@ function computeSourceHash(repoPath) {
|
|
|
73769
73769
|
}
|
|
73770
73770
|
function getDocSourcePaths(repoPath) {
|
|
73771
73771
|
const paths = [];
|
|
73772
|
-
const docsDir =
|
|
73772
|
+
const docsDir = join160(repoPath, "docs");
|
|
73773
73773
|
if (existsSync75(docsDir)) {
|
|
73774
73774
|
try {
|
|
73775
73775
|
const files = readdirSync11(docsDir);
|
|
73776
73776
|
for (const f3 of files) {
|
|
73777
73777
|
if (f3.endsWith(".md"))
|
|
73778
|
-
paths.push(
|
|
73778
|
+
paths.push(join160(docsDir, f3));
|
|
73779
73779
|
}
|
|
73780
73780
|
} catch {}
|
|
73781
73781
|
}
|
|
73782
|
-
const readme =
|
|
73782
|
+
const readme = join160(repoPath, "README.md");
|
|
73783
73783
|
if (existsSync75(readme))
|
|
73784
73784
|
paths.push(readme);
|
|
73785
|
-
const stylesDir =
|
|
73785
|
+
const stylesDir = join160(repoPath, "assets", "writing-styles");
|
|
73786
73786
|
if (existsSync75(stylesDir)) {
|
|
73787
73787
|
try {
|
|
73788
73788
|
const files = readdirSync11(stylesDir);
|
|
73789
73789
|
for (const f3 of files) {
|
|
73790
|
-
paths.push(
|
|
73790
|
+
paths.push(join160(stylesDir, f3));
|
|
73791
73791
|
}
|
|
73792
73792
|
} catch {}
|
|
73793
73793
|
}
|
|
@@ -73796,12 +73796,12 @@ function getDocSourcePaths(repoPath) {
|
|
|
73796
73796
|
function getCacheFilePath(repoPath) {
|
|
73797
73797
|
const repoName = basename31(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
73798
73798
|
const pathHash = createHash9("sha256").update(repoPath).digest("hex").slice(0, 8);
|
|
73799
|
-
return
|
|
73799
|
+
return join160(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
|
|
73800
73800
|
}
|
|
73801
|
-
var CACHE_DIR,
|
|
73801
|
+
var CACHE_DIR, CACHE_TTL_MS5;
|
|
73802
73802
|
var init_context_cache_manager = __esm(() => {
|
|
73803
|
-
CACHE_DIR =
|
|
73804
|
-
|
|
73803
|
+
CACHE_DIR = join160(homedir54(), ".claudekit", "cache");
|
|
73804
|
+
CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
|
|
73805
73805
|
});
|
|
73806
73806
|
|
|
73807
73807
|
// src/commands/content/phases/db-queries-git-events.ts
|
|
@@ -73981,7 +73981,7 @@ function extractContentFromResponse(response) {
|
|
|
73981
73981
|
// src/commands/content/phases/docs-summarizer.ts
|
|
73982
73982
|
import { execSync as execSync7 } from "node:child_process";
|
|
73983
73983
|
import { existsSync as existsSync76, readFileSync as readFileSync19, readdirSync as readdirSync12 } from "node:fs";
|
|
73984
|
-
import { join as
|
|
73984
|
+
import { join as join161 } from "node:path";
|
|
73985
73985
|
async function summarizeProjectDocs(repoPath, contentLogger) {
|
|
73986
73986
|
const rawContent = collectRawDocs(repoPath);
|
|
73987
73987
|
if (rawContent.total.length < 200) {
|
|
@@ -74035,12 +74035,12 @@ function collectRawDocs(repoPath) {
|
|
|
74035
74035
|
return capped;
|
|
74036
74036
|
};
|
|
74037
74037
|
const docsContent = [];
|
|
74038
|
-
const docsDir =
|
|
74038
|
+
const docsDir = join161(repoPath, "docs");
|
|
74039
74039
|
if (existsSync76(docsDir)) {
|
|
74040
74040
|
try {
|
|
74041
74041
|
const files = readdirSync12(docsDir).filter((f3) => f3.endsWith(".md")).sort();
|
|
74042
74042
|
for (const f3 of files) {
|
|
74043
|
-
const content = readCapped(
|
|
74043
|
+
const content = readCapped(join161(docsDir, f3), 5000);
|
|
74044
74044
|
if (content) {
|
|
74045
74045
|
docsContent.push(`### ${f3}
|
|
74046
74046
|
${content}`);
|
|
@@ -74054,21 +74054,21 @@ ${content}`);
|
|
|
74054
74054
|
let brand = "";
|
|
74055
74055
|
const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
|
|
74056
74056
|
for (const p of brandCandidates) {
|
|
74057
|
-
brand = readCapped(
|
|
74057
|
+
brand = readCapped(join161(repoPath, p), 3000);
|
|
74058
74058
|
if (brand)
|
|
74059
74059
|
break;
|
|
74060
74060
|
}
|
|
74061
74061
|
let styles3 = "";
|
|
74062
|
-
const stylesDir =
|
|
74062
|
+
const stylesDir = join161(repoPath, "assets", "writing-styles");
|
|
74063
74063
|
if (existsSync76(stylesDir)) {
|
|
74064
74064
|
try {
|
|
74065
74065
|
const files = readdirSync12(stylesDir).slice(0, 3);
|
|
74066
|
-
styles3 = files.map((f3) => readCapped(
|
|
74066
|
+
styles3 = files.map((f3) => readCapped(join161(stylesDir, f3), 1000)).filter(Boolean).join(`
|
|
74067
74067
|
|
|
74068
74068
|
`);
|
|
74069
74069
|
} catch {}
|
|
74070
74070
|
}
|
|
74071
|
-
const readme = readCapped(
|
|
74071
|
+
const readme = readCapped(join161(repoPath, "README.md"), 3000);
|
|
74072
74072
|
const total = [docs, brand, styles3, readme].join(`
|
|
74073
74073
|
`);
|
|
74074
74074
|
return { docs, brand, styles: styles3, readme, total };
|
|
@@ -74102,10 +74102,10 @@ var MAX_RAW_CONTENT_CHARS = 50000;
|
|
|
74102
74102
|
var init_docs_summarizer = () => {};
|
|
74103
74103
|
|
|
74104
74104
|
// src/commands/content/phases/context-builder.ts
|
|
74105
|
-
async function buildContentContext(event, repoPath, config, db,
|
|
74105
|
+
async function buildContentContext(event, repoPath, config, db, platform18, contentLogger) {
|
|
74106
74106
|
const cached = getCachedContext(repoPath);
|
|
74107
74107
|
if (cached) {
|
|
74108
|
-
return buildFromCache(cached, event, db,
|
|
74108
|
+
return buildFromCache(cached, event, db, platform18, config);
|
|
74109
74109
|
}
|
|
74110
74110
|
const noopLogger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} };
|
|
74111
74111
|
const log2 = contentLogger ?? noopLogger;
|
|
@@ -74120,16 +74120,16 @@ async function buildContentContext(event, repoPath, config, db, platform17, cont
|
|
|
74120
74120
|
sourceHash: hash
|
|
74121
74121
|
};
|
|
74122
74122
|
await saveCachedContext(repoPath, newCache);
|
|
74123
|
-
return buildFromCache(newCache, event, db,
|
|
74123
|
+
return buildFromCache(newCache, event, db, platform18, config);
|
|
74124
74124
|
}
|
|
74125
|
-
function buildFromCache(cache5, event, db,
|
|
74125
|
+
function buildFromCache(cache5, event, db, platform18, config) {
|
|
74126
74126
|
return {
|
|
74127
74127
|
brandGuidelines: cache5.brandSummary,
|
|
74128
74128
|
writingStyles: cache5.stylesSummary,
|
|
74129
74129
|
gitEventDetails: formatGitEvent(event),
|
|
74130
74130
|
recentContent: formatRecentContent(db),
|
|
74131
74131
|
topPerformingContent: "",
|
|
74132
|
-
platformRules: getPlatformRules(
|
|
74132
|
+
platformRules: getPlatformRules(platform18, config),
|
|
74133
74133
|
projectReadme: cache5.readmeSummary,
|
|
74134
74134
|
projectDocsSummary: cache5.docsSummary,
|
|
74135
74135
|
currentDateTime: new Date().toISOString()
|
|
@@ -74158,8 +74158,8 @@ function formatRecentContent(db) {
|
|
|
74158
74158
|
return recent.map((c2) => `[${c2.platform}] ${c2.textContent.slice(0, 100)}`).join(`
|
|
74159
74159
|
`);
|
|
74160
74160
|
}
|
|
74161
|
-
function getPlatformRules(
|
|
74162
|
-
switch (
|
|
74161
|
+
function getPlatformRules(platform18, config) {
|
|
74162
|
+
switch (platform18) {
|
|
74163
74163
|
case "x":
|
|
74164
74164
|
return [
|
|
74165
74165
|
"Platform: X (Twitter)",
|
|
@@ -74198,8 +74198,8 @@ var init_context_builder = __esm(() => {
|
|
|
74198
74198
|
});
|
|
74199
74199
|
|
|
74200
74200
|
// src/commands/content/phases/prompt-templates.ts
|
|
74201
|
-
function buildTextPrompt(context,
|
|
74202
|
-
const charLimit =
|
|
74201
|
+
function buildTextPrompt(context, platform18) {
|
|
74202
|
+
const charLimit = platform18 === "x" || platform18 === "x_thread" ? 280 : 500;
|
|
74203
74203
|
return `You are a social media content creator.
|
|
74204
74204
|
|
|
74205
74205
|
## Project Context
|
|
@@ -74214,14 +74214,14 @@ ${context.writingStyles}
|
|
|
74214
74214
|
## Content Source
|
|
74215
74215
|
${context.gitEventDetails}
|
|
74216
74216
|
|
|
74217
|
-
## Platform: ${
|
|
74217
|
+
## Platform: ${platform18}
|
|
74218
74218
|
${context.platformRules}
|
|
74219
74219
|
|
|
74220
74220
|
## Past Content (avoid repetition)
|
|
74221
74221
|
${context.recentContent}
|
|
74222
74222
|
|
|
74223
74223
|
## Instructions
|
|
74224
|
-
1. Create a ${
|
|
74224
|
+
1. Create a ${platform18} post about this development update
|
|
74225
74225
|
2. Start with a compelling hook that creates curiosity
|
|
74226
74226
|
3. Keep it conversational and authentic (avoid AI-sounding language)
|
|
74227
74227
|
4. No generic statements — be specific about what changed and why it matters
|
|
@@ -74231,8 +74231,8 @@ ${context.recentContent}
|
|
|
74231
74231
|
|
|
74232
74232
|
IMPORTANT: Output ONLY the JSON object, nothing else.`;
|
|
74233
74233
|
}
|
|
74234
|
-
function buildPhotoPrompt(context,
|
|
74235
|
-
const dimensions =
|
|
74234
|
+
function buildPhotoPrompt(context, platform18) {
|
|
74235
|
+
const dimensions = platform18 === "facebook" ? "1200x630" : "1200x675";
|
|
74236
74236
|
return `Generate an image for this social media post.
|
|
74237
74237
|
|
|
74238
74238
|
## Brand Guidelines
|
|
@@ -74254,15 +74254,15 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
|
|
|
74254
74254
|
// src/commands/content/phases/photo-generator.ts
|
|
74255
74255
|
import { execSync as execSync8 } from "node:child_process";
|
|
74256
74256
|
import { existsSync as existsSync77, mkdirSync as mkdirSync6, readdirSync as readdirSync13 } from "node:fs";
|
|
74257
|
-
import { homedir as
|
|
74258
|
-
import { join as
|
|
74259
|
-
async function generatePhoto(_content, context, config,
|
|
74260
|
-
const mediaDir =
|
|
74257
|
+
import { homedir as homedir55 } from "node:os";
|
|
74258
|
+
import { join as join162 } from "node:path";
|
|
74259
|
+
async function generatePhoto(_content, context, config, platform18, contentId, contentLogger) {
|
|
74260
|
+
const mediaDir = join162(config.contentDir.replace(/^~/, homedir55()), "media", String(contentId));
|
|
74261
74261
|
if (!existsSync77(mediaDir)) {
|
|
74262
74262
|
mkdirSync6(mediaDir, { recursive: true });
|
|
74263
74263
|
}
|
|
74264
|
-
const prompt = buildPhotoPrompt(context,
|
|
74265
|
-
const dimensions =
|
|
74264
|
+
const prompt = buildPhotoPrompt(context, platform18);
|
|
74265
|
+
const dimensions = platform18 === "facebook" ? { width: 1200, height: 630 } : { width: 1200, height: 675 };
|
|
74266
74266
|
try {
|
|
74267
74267
|
contentLogger.debug(`Generating photo for content ${contentId}...`);
|
|
74268
74268
|
const result = execSync8("claude -p --output-format text --max-turns 40", {
|
|
@@ -74282,7 +74282,7 @@ async function generatePhoto(_content, context, config, platform17, contentId, c
|
|
|
74282
74282
|
const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
|
|
74283
74283
|
if (imageFile) {
|
|
74284
74284
|
const ext2 = imageFile.split(".").pop() ?? "png";
|
|
74285
|
-
return { path:
|
|
74285
|
+
return { path: join162(mediaDir, imageFile), ...dimensions, format: ext2 };
|
|
74286
74286
|
}
|
|
74287
74287
|
contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
|
|
74288
74288
|
return null;
|
|
@@ -74300,14 +74300,14 @@ async function createContent(event, config, db, contentLogger, options2) {
|
|
|
74300
74300
|
const startTime = Date.now();
|
|
74301
74301
|
const items = [];
|
|
74302
74302
|
const platforms = resolveEnabledPlatforms(config);
|
|
74303
|
-
for (const
|
|
74303
|
+
for (const platform18 of platforms) {
|
|
74304
74304
|
try {
|
|
74305
|
-
const item = await createContentForPlatform(event,
|
|
74305
|
+
const item = await createContentForPlatform(event, platform18, config, db, contentLogger, options2);
|
|
74306
74306
|
if (item)
|
|
74307
74307
|
items.push(item);
|
|
74308
74308
|
} catch (err) {
|
|
74309
74309
|
const msg = err instanceof Error ? err.message : String(err);
|
|
74310
|
-
contentLogger.error(`Failed to create ${
|
|
74310
|
+
contentLogger.error(`Failed to create ${platform18} content: ${msg}`);
|
|
74311
74311
|
}
|
|
74312
74312
|
}
|
|
74313
74313
|
insertTaskLog(db, {
|
|
@@ -74326,10 +74326,10 @@ function resolveEnabledPlatforms(config) {
|
|
|
74326
74326
|
platforms.push("facebook");
|
|
74327
74327
|
return platforms;
|
|
74328
74328
|
}
|
|
74329
|
-
async function createContentForPlatform(event,
|
|
74330
|
-
const context = await buildContentContext(event, event.repoPath, config, db,
|
|
74331
|
-
const prompt = buildTextPrompt(context,
|
|
74332
|
-
contentLogger.debug(`Generating ${
|
|
74329
|
+
async function createContentForPlatform(event, platform18, config, db, contentLogger, options2) {
|
|
74330
|
+
const context = await buildContentContext(event, event.repoPath, config, db, platform18, contentLogger);
|
|
74331
|
+
const prompt = buildTextPrompt(context, platform18);
|
|
74332
|
+
contentLogger.debug(`Generating ${platform18} content for event ${event.id}...`);
|
|
74333
74333
|
const stdout2 = execSync9("claude -p --output-format text --max-turns 5", {
|
|
74334
74334
|
input: prompt,
|
|
74335
74335
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -74337,14 +74337,14 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
|
|
|
74337
74337
|
}).toString();
|
|
74338
74338
|
const parsed = parseClaudeJsonOutput(stdout2);
|
|
74339
74339
|
const generated = extractContentFromResponse(parsed);
|
|
74340
|
-
const validation = validateContent(generated,
|
|
74340
|
+
const validation = validateContent(generated, platform18);
|
|
74341
74341
|
if (!validation.valid) {
|
|
74342
|
-
contentLogger.warn(`Content validation failed for ${
|
|
74342
|
+
contentLogger.warn(`Content validation failed for ${platform18}: ${validation.issues.join(", ")}`);
|
|
74343
74343
|
}
|
|
74344
74344
|
const status = validation.valid ? config.reviewMode === "auto" ? "scheduled" : "reviewing" : "draft";
|
|
74345
74345
|
const itemId = insertContentItem(db, {
|
|
74346
74346
|
gitEventId: event.id,
|
|
74347
|
-
platform:
|
|
74347
|
+
platform: platform18,
|
|
74348
74348
|
textContent: generated.text,
|
|
74349
74349
|
hashtags: JSON.stringify(generated.hashtags),
|
|
74350
74350
|
hookLine: generated.hook,
|
|
@@ -74354,12 +74354,12 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
|
|
|
74354
74354
|
scheduledAt: null
|
|
74355
74355
|
});
|
|
74356
74356
|
if (!options2.dryRun && generated.mediaPrompt) {
|
|
74357
|
-
const photo = await generatePhoto(generated, context, config,
|
|
74357
|
+
const photo = await generatePhoto(generated, context, config, platform18, itemId, contentLogger);
|
|
74358
74358
|
if (photo) {
|
|
74359
74359
|
db.prepare("UPDATE content_items SET media_path = ? WHERE id = ?").run(photo.path, itemId);
|
|
74360
74360
|
}
|
|
74361
74361
|
}
|
|
74362
|
-
contentLogger.info(`Created ${
|
|
74362
|
+
contentLogger.info(`Created ${platform18} content (id: ${itemId}, status: ${status})`);
|
|
74363
74363
|
return getContentById(db, itemId);
|
|
74364
74364
|
}
|
|
74365
74365
|
var init_content_creator = __esm(() => {
|
|
@@ -74371,8 +74371,8 @@ var init_content_creator = __esm(() => {
|
|
|
74371
74371
|
|
|
74372
74372
|
// src/commands/content/phases/content-logger.ts
|
|
74373
74373
|
import { createWriteStream as createWriteStream4, existsSync as existsSync78, mkdirSync as mkdirSync7, statSync as statSync15 } from "node:fs";
|
|
74374
|
-
import { homedir as
|
|
74375
|
-
import { join as
|
|
74374
|
+
import { homedir as homedir56 } from "node:os";
|
|
74375
|
+
import { join as join163 } from "node:path";
|
|
74376
74376
|
|
|
74377
74377
|
class ContentLogger {
|
|
74378
74378
|
stream = null;
|
|
@@ -74380,7 +74380,7 @@ class ContentLogger {
|
|
|
74380
74380
|
logDir;
|
|
74381
74381
|
maxBytes;
|
|
74382
74382
|
constructor(maxBytes = 0) {
|
|
74383
|
-
this.logDir =
|
|
74383
|
+
this.logDir = join163(homedir56(), ".claudekit", "logs");
|
|
74384
74384
|
this.maxBytes = maxBytes;
|
|
74385
74385
|
}
|
|
74386
74386
|
init() {
|
|
@@ -74412,7 +74412,7 @@ class ContentLogger {
|
|
|
74412
74412
|
}
|
|
74413
74413
|
}
|
|
74414
74414
|
getLogPath() {
|
|
74415
|
-
return
|
|
74415
|
+
return join163(this.logDir, `content-${this.getDateStr()}.log`);
|
|
74416
74416
|
}
|
|
74417
74417
|
write(level, message) {
|
|
74418
74418
|
this.rotateIfNeeded();
|
|
@@ -74429,19 +74429,19 @@ class ContentLogger {
|
|
|
74429
74429
|
if (dateStr !== this.currentDate) {
|
|
74430
74430
|
this.close();
|
|
74431
74431
|
this.currentDate = dateStr;
|
|
74432
|
-
const logPath =
|
|
74432
|
+
const logPath = join163(this.logDir, `content-${dateStr}.log`);
|
|
74433
74433
|
this.stream = createWriteStream4(logPath, { flags: "a", mode: 384 });
|
|
74434
74434
|
return;
|
|
74435
74435
|
}
|
|
74436
74436
|
if (this.maxBytes > 0 && this.stream) {
|
|
74437
|
-
const logPath =
|
|
74437
|
+
const logPath = join163(this.logDir, `content-${this.currentDate}.log`);
|
|
74438
74438
|
try {
|
|
74439
74439
|
const stat26 = statSync15(logPath);
|
|
74440
74440
|
if (stat26.size >= this.maxBytes) {
|
|
74441
74441
|
this.close();
|
|
74442
74442
|
const suffix = Date.now();
|
|
74443
|
-
const rotatedPath =
|
|
74444
|
-
import("node:fs/promises").then(({ rename:
|
|
74443
|
+
const rotatedPath = join163(this.logDir, `content-${this.currentDate}-${suffix}.log`);
|
|
74444
|
+
import("node:fs/promises").then(({ rename: rename16 }) => rename16(logPath, rotatedPath).catch(() => {}));
|
|
74445
74445
|
this.stream = createWriteStream4(logPath, { flags: "w", mode: 384 });
|
|
74446
74446
|
}
|
|
74447
74447
|
} catch {}
|
|
@@ -74666,7 +74666,7 @@ function isNoiseCommit(title, author) {
|
|
|
74666
74666
|
// src/commands/content/phases/change-detector.ts
|
|
74667
74667
|
import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
|
|
74668
74668
|
import { existsSync as existsSync80, readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as statSync16 } from "node:fs";
|
|
74669
|
-
import { join as
|
|
74669
|
+
import { join as join164 } from "node:path";
|
|
74670
74670
|
function detectCommits(repo, since) {
|
|
74671
74671
|
try {
|
|
74672
74672
|
const fetchUrl = sshToHttps(repo.remoteUrl);
|
|
@@ -74775,7 +74775,7 @@ function detectTags(repo, since) {
|
|
|
74775
74775
|
}
|
|
74776
74776
|
}
|
|
74777
74777
|
function detectCompletedPlans(repo, since) {
|
|
74778
|
-
const plansDir =
|
|
74778
|
+
const plansDir = join164(repo.path, "plans");
|
|
74779
74779
|
if (!existsSync80(plansDir))
|
|
74780
74780
|
return [];
|
|
74781
74781
|
const sinceMs = new Date(since).getTime();
|
|
@@ -74785,7 +74785,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
74785
74785
|
for (const entry of entries) {
|
|
74786
74786
|
if (!entry.isDirectory())
|
|
74787
74787
|
continue;
|
|
74788
|
-
const planFile =
|
|
74788
|
+
const planFile = join164(plansDir, entry.name, "plan.md");
|
|
74789
74789
|
if (!existsSync80(planFile))
|
|
74790
74790
|
continue;
|
|
74791
74791
|
try {
|
|
@@ -74863,7 +74863,7 @@ function classifyCommit(event) {
|
|
|
74863
74863
|
// src/commands/content/phases/repo-discoverer.ts
|
|
74864
74864
|
import { execSync as execSync11 } from "node:child_process";
|
|
74865
74865
|
import { readdirSync as readdirSync15 } from "node:fs";
|
|
74866
|
-
import { join as
|
|
74866
|
+
import { join as join165 } from "node:path";
|
|
74867
74867
|
function discoverRepos2(cwd2) {
|
|
74868
74868
|
const repos = [];
|
|
74869
74869
|
if (isGitRepoRoot(cwd2)) {
|
|
@@ -74876,7 +74876,7 @@ function discoverRepos2(cwd2) {
|
|
|
74876
74876
|
for (const entry of entries) {
|
|
74877
74877
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
74878
74878
|
continue;
|
|
74879
|
-
const dirPath =
|
|
74879
|
+
const dirPath = join165(cwd2, entry.name);
|
|
74880
74880
|
if (isGitRepoRoot(dirPath)) {
|
|
74881
74881
|
const info = getRepoInfo(dirPath);
|
|
74882
74882
|
if (info)
|
|
@@ -75246,15 +75246,15 @@ class RateLimiter {
|
|
|
75246
75246
|
this.state = state;
|
|
75247
75247
|
this.config = config;
|
|
75248
75248
|
}
|
|
75249
|
-
canPost(
|
|
75250
|
-
return this.getTodayCount(
|
|
75249
|
+
canPost(platform18) {
|
|
75250
|
+
return this.getTodayCount(platform18) < this.getMaxPerDay(platform18);
|
|
75251
75251
|
}
|
|
75252
|
-
recordPost(
|
|
75253
|
-
const key = this.dailyKey(
|
|
75252
|
+
recordPost(platform18) {
|
|
75253
|
+
const key = this.dailyKey(platform18);
|
|
75254
75254
|
this.state.dailyPostCounts[key] = (this.state.dailyPostCounts[key] ?? 0) + 1;
|
|
75255
75255
|
}
|
|
75256
|
-
getRemainingToday(
|
|
75257
|
-
return Math.max(0, this.getMaxPerDay(
|
|
75256
|
+
getRemainingToday(platform18) {
|
|
75257
|
+
return Math.max(0, this.getMaxPerDay(platform18) - this.getTodayCount(platform18));
|
|
75258
75258
|
}
|
|
75259
75259
|
isInQuietHours() {
|
|
75260
75260
|
const { timezone, quietHoursStart, quietHoursEnd } = this.config.schedule;
|
|
@@ -75274,19 +75274,19 @@ class RateLimiter {
|
|
|
75274
75274
|
return false;
|
|
75275
75275
|
}
|
|
75276
75276
|
}
|
|
75277
|
-
getMaxPerDay(
|
|
75278
|
-
if (
|
|
75277
|
+
getMaxPerDay(platform18) {
|
|
75278
|
+
if (platform18 === "x" || platform18 === "x_thread") {
|
|
75279
75279
|
return this.config.platforms.x.maxPostsPerDay;
|
|
75280
75280
|
}
|
|
75281
|
-
if (
|
|
75281
|
+
if (platform18 === "facebook") {
|
|
75282
75282
|
return this.config.platforms.facebook.maxPostsPerDay;
|
|
75283
75283
|
}
|
|
75284
75284
|
return this.config.maxContentPerDay;
|
|
75285
75285
|
}
|
|
75286
|
-
getTodayCount(
|
|
75287
|
-
return this.state.dailyPostCounts[this.dailyKey(
|
|
75286
|
+
getTodayCount(platform18) {
|
|
75287
|
+
return this.state.dailyPostCounts[this.dailyKey(platform18)] ?? 0;
|
|
75288
75288
|
}
|
|
75289
|
-
dailyKey(
|
|
75289
|
+
dailyKey(platform18) {
|
|
75290
75290
|
const { timezone } = this.config.schedule;
|
|
75291
75291
|
let dateStr;
|
|
75292
75292
|
try {
|
|
@@ -75300,7 +75300,7 @@ class RateLimiter {
|
|
|
75300
75300
|
} catch {
|
|
75301
75301
|
dateStr = new Date().toISOString().slice(0, 10);
|
|
75302
75302
|
}
|
|
75303
|
-
return `${
|
|
75303
|
+
return `${platform18}-${dateStr}`;
|
|
75304
75304
|
}
|
|
75305
75305
|
}
|
|
75306
75306
|
|
|
@@ -75417,8 +75417,8 @@ function previewContent(content) {
|
|
|
75417
75417
|
console.log(import_picocolors42.default.dim("─".repeat(60)));
|
|
75418
75418
|
console.log();
|
|
75419
75419
|
}
|
|
75420
|
-
function getPlatformBadge(
|
|
75421
|
-
switch (
|
|
75420
|
+
function getPlatformBadge(platform18) {
|
|
75421
|
+
switch (platform18) {
|
|
75422
75422
|
case "x":
|
|
75423
75423
|
return import_picocolors42.default.bgBlue(import_picocolors42.default.white(" X "));
|
|
75424
75424
|
case "x_thread":
|
|
@@ -75426,7 +75426,7 @@ function getPlatformBadge(platform17) {
|
|
|
75426
75426
|
case "facebook":
|
|
75427
75427
|
return import_picocolors42.default.bgCyan(import_picocolors42.default.white(" Facebook "));
|
|
75428
75428
|
default:
|
|
75429
|
-
return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${
|
|
75429
|
+
return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${platform18} `));
|
|
75430
75430
|
}
|
|
75431
75431
|
}
|
|
75432
75432
|
function getStatusColor(status) {
|
|
@@ -75543,12 +75543,12 @@ var init_types6 = __esm(() => {
|
|
|
75543
75543
|
});
|
|
75544
75544
|
|
|
75545
75545
|
// src/commands/content/phases/state-manager.ts
|
|
75546
|
-
import { readFile as
|
|
75547
|
-
import { join as
|
|
75546
|
+
import { readFile as readFile67, rename as rename16, writeFile as writeFile40 } from "node:fs/promises";
|
|
75547
|
+
import { join as join166 } from "node:path";
|
|
75548
75548
|
async function loadContentConfig(projectDir) {
|
|
75549
|
-
const configPath =
|
|
75549
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75550
75550
|
try {
|
|
75551
|
-
const raw2 = await
|
|
75551
|
+
const raw2 = await readFile67(configPath, "utf-8");
|
|
75552
75552
|
const json = JSON.parse(raw2);
|
|
75553
75553
|
return ContentConfigSchema.parse(json.content ?? {});
|
|
75554
75554
|
} catch {
|
|
@@ -75556,15 +75556,15 @@ async function loadContentConfig(projectDir) {
|
|
|
75556
75556
|
}
|
|
75557
75557
|
}
|
|
75558
75558
|
async function saveContentConfig(projectDir, config) {
|
|
75559
|
-
const configPath =
|
|
75559
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75560
75560
|
const json = await readJsonSafe(configPath);
|
|
75561
75561
|
json.content = { ...json.content, ...config };
|
|
75562
75562
|
await atomicWrite2(configPath, json);
|
|
75563
75563
|
}
|
|
75564
75564
|
async function loadContentState(projectDir) {
|
|
75565
|
-
const configPath =
|
|
75565
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75566
75566
|
try {
|
|
75567
|
-
const raw2 = await
|
|
75567
|
+
const raw2 = await readFile67(configPath, "utf-8");
|
|
75568
75568
|
const json = JSON.parse(raw2);
|
|
75569
75569
|
const contentBlock = json.content ?? {};
|
|
75570
75570
|
return ContentStateSchema.parse(contentBlock.state ?? {});
|
|
@@ -75573,7 +75573,7 @@ async function loadContentState(projectDir) {
|
|
|
75573
75573
|
}
|
|
75574
75574
|
}
|
|
75575
75575
|
async function saveContentState(projectDir, state) {
|
|
75576
|
-
const configPath =
|
|
75576
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75577
75577
|
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
75578
75578
|
for (const key of Object.keys(state.dailyPostCounts)) {
|
|
75579
75579
|
const dateStr = key.slice(-10);
|
|
@@ -75591,7 +75591,7 @@ async function saveContentState(projectDir, state) {
|
|
|
75591
75591
|
}
|
|
75592
75592
|
async function readJsonSafe(filePath) {
|
|
75593
75593
|
try {
|
|
75594
|
-
const raw2 = await
|
|
75594
|
+
const raw2 = await readFile67(filePath, "utf-8");
|
|
75595
75595
|
return JSON.parse(raw2);
|
|
75596
75596
|
} catch {
|
|
75597
75597
|
return {};
|
|
@@ -75599,8 +75599,8 @@ async function readJsonSafe(filePath) {
|
|
|
75599
75599
|
}
|
|
75600
75600
|
async function atomicWrite2(filePath, data) {
|
|
75601
75601
|
const tmpPath = `${filePath}.tmp`;
|
|
75602
|
-
await
|
|
75603
|
-
await
|
|
75602
|
+
await writeFile40(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
75603
|
+
await rename16(tmpPath, filePath);
|
|
75604
75604
|
}
|
|
75605
75605
|
var CK_CONFIG_FILE2 = ".ck.json";
|
|
75606
75606
|
var init_state_manager = __esm(() => {
|
|
@@ -75706,15 +75706,15 @@ async function autoInstallFbcli(contentLogger) {
|
|
|
75706
75706
|
contentLogger.warn("go install failed or Go not available");
|
|
75707
75707
|
}
|
|
75708
75708
|
try {
|
|
75709
|
-
const { platform:
|
|
75709
|
+
const { platform: platform18, arch: arch3 } = process;
|
|
75710
75710
|
const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
75711
75711
|
const archMap = { arm64: "arm64", x64: "amd64" };
|
|
75712
|
-
const os7 = osMap[
|
|
75712
|
+
const os7 = osMap[platform18];
|
|
75713
75713
|
const cpu = archMap[arch3];
|
|
75714
75714
|
if (os7 && cpu) {
|
|
75715
|
-
const ext2 =
|
|
75715
|
+
const ext2 = platform18 === "win32" ? ".exe" : "";
|
|
75716
75716
|
const url = `https://github.com/mrgoonie/fbcli/releases/latest/download/fbcli_${os7}_${cpu}${ext2}`;
|
|
75717
|
-
const dest =
|
|
75717
|
+
const dest = platform18 === "win32" ? "fbcli.exe" : "/usr/local/bin/fbcli";
|
|
75718
75718
|
f2.warning(`Will download fbcli binary from: ${url}`);
|
|
75719
75719
|
f2.warning("Note: Binary integrity is not verified. Review the source at https://github.com/mrgoonie/fbcli");
|
|
75720
75720
|
const consent = await se({ message: `Download and install fbcli to ${dest}?` });
|
|
@@ -75798,15 +75798,15 @@ async function autoInstallXurl(contentLogger) {
|
|
|
75798
75798
|
contentLogger.warn("go install failed or Go not available");
|
|
75799
75799
|
}
|
|
75800
75800
|
try {
|
|
75801
|
-
const { platform:
|
|
75801
|
+
const { platform: platform18, arch: arch3 } = process;
|
|
75802
75802
|
const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
75803
75803
|
const archMap = { arm64: "arm64", x64: "amd64" };
|
|
75804
|
-
const os7 = osMap[
|
|
75804
|
+
const os7 = osMap[platform18];
|
|
75805
75805
|
const cpu = archMap[arch3];
|
|
75806
75806
|
if (os7 && cpu) {
|
|
75807
|
-
const ext2 =
|
|
75807
|
+
const ext2 = platform18 === "win32" ? ".exe" : "";
|
|
75808
75808
|
const url = `https://github.com/xdevplatform/xurl/releases/latest/download/xurl_${os7}_${cpu}${ext2}`;
|
|
75809
|
-
const dest =
|
|
75809
|
+
const dest = platform18 === "win32" ? "xurl.exe" : "/usr/local/bin/xurl";
|
|
75810
75810
|
f2.info(`Downloading xurl binary for ${os7}/${cpu}...`);
|
|
75811
75811
|
execSync14(`curl -fsSL "${url}" -o "${dest}" && chmod +x "${dest}"`, {
|
|
75812
75812
|
stdio: "inherit",
|
|
@@ -75855,7 +75855,7 @@ var init_platform_setup_x = __esm(() => {
|
|
|
75855
75855
|
|
|
75856
75856
|
// src/commands/content/phases/setup-wizard.ts
|
|
75857
75857
|
import { existsSync as existsSync81 } from "node:fs";
|
|
75858
|
-
import { join as
|
|
75858
|
+
import { join as join167 } from "node:path";
|
|
75859
75859
|
async function runSetupWizard2(cwd2, contentLogger) {
|
|
75860
75860
|
console.log();
|
|
75861
75861
|
oe(import_picocolors43.default.bgCyan(import_picocolors43.default.white(" CK Content — Multi-Channel Content Engine ")));
|
|
@@ -75923,8 +75923,8 @@ async function showRepoSummary(cwd2) {
|
|
|
75923
75923
|
function detectBrandAssets(cwd2, contentLogger) {
|
|
75924
75924
|
const repos = discoverRepos2(cwd2);
|
|
75925
75925
|
for (const repo of repos) {
|
|
75926
|
-
const hasGuidelines = existsSync81(
|
|
75927
|
-
const hasStyles = existsSync81(
|
|
75926
|
+
const hasGuidelines = existsSync81(join167(repo.path, "docs", "brand-guidelines.md"));
|
|
75927
|
+
const hasStyles = existsSync81(join167(repo.path, "assets", "writing-styles"));
|
|
75928
75928
|
if (!hasGuidelines) {
|
|
75929
75929
|
f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
|
|
75930
75930
|
contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
|
|
@@ -75991,11 +75991,11 @@ var init_setup_wizard = __esm(() => {
|
|
|
75991
75991
|
|
|
75992
75992
|
// src/commands/content/content-review-commands.ts
|
|
75993
75993
|
import { existsSync as existsSync82 } from "node:fs";
|
|
75994
|
-
import { homedir as
|
|
75994
|
+
import { homedir as homedir57 } from "node:os";
|
|
75995
75995
|
async function queueContent() {
|
|
75996
75996
|
const cwd2 = process.cwd();
|
|
75997
75997
|
const config = await loadContentConfig(cwd2);
|
|
75998
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
75998
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
75999
75999
|
if (!existsSync82(dbPath)) {
|
|
76000
76000
|
logger.info("No content database found. Run 'ck content setup' first.");
|
|
76001
76001
|
return;
|
|
@@ -76022,7 +76022,7 @@ async function queueContent() {
|
|
|
76022
76022
|
async function approveContentCmd(id) {
|
|
76023
76023
|
const cwd2 = process.cwd();
|
|
76024
76024
|
const config = await loadContentConfig(cwd2);
|
|
76025
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76025
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
76026
76026
|
const db = initDatabase(dbPath);
|
|
76027
76027
|
try {
|
|
76028
76028
|
approveContent(db, Number.parseInt(id, 10));
|
|
@@ -76034,7 +76034,7 @@ async function approveContentCmd(id) {
|
|
|
76034
76034
|
async function rejectContentCmd(id, reason) {
|
|
76035
76035
|
const cwd2 = process.cwd();
|
|
76036
76036
|
const config = await loadContentConfig(cwd2);
|
|
76037
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76037
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
76038
76038
|
const db = initDatabase(dbPath);
|
|
76039
76039
|
try {
|
|
76040
76040
|
rejectContent(db, Number.parseInt(id, 10), reason);
|
|
@@ -76065,10 +76065,10 @@ __export(exports_content_subcommands, {
|
|
|
76065
76065
|
approveContentCmd: () => approveContentCmd
|
|
76066
76066
|
});
|
|
76067
76067
|
import { existsSync as existsSync83, readFileSync as readFileSync21, unlinkSync as unlinkSync6 } from "node:fs";
|
|
76068
|
-
import { homedir as
|
|
76069
|
-
import { join as
|
|
76068
|
+
import { homedir as homedir58 } from "node:os";
|
|
76069
|
+
import { join as join168 } from "node:path";
|
|
76070
76070
|
function isDaemonRunning() {
|
|
76071
|
-
const lockFile =
|
|
76071
|
+
const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
76072
76072
|
if (!existsSync83(lockFile))
|
|
76073
76073
|
return { running: false, pid: null };
|
|
76074
76074
|
try {
|
|
@@ -76100,7 +76100,7 @@ async function startContent(options2) {
|
|
|
76100
76100
|
await contentCommand(options2);
|
|
76101
76101
|
}
|
|
76102
76102
|
async function stopContent() {
|
|
76103
|
-
const lockFile =
|
|
76103
|
+
const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
76104
76104
|
if (!existsSync83(lockFile)) {
|
|
76105
76105
|
logger.info("Content daemon is not running.");
|
|
76106
76106
|
return;
|
|
@@ -76139,9 +76139,9 @@ async function statusContent() {
|
|
|
76139
76139
|
} catch {}
|
|
76140
76140
|
}
|
|
76141
76141
|
async function logsContent(options2) {
|
|
76142
|
-
const logDir =
|
|
76142
|
+
const logDir = join168(homedir58(), ".claudekit", "logs");
|
|
76143
76143
|
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
76144
|
-
const logPath =
|
|
76144
|
+
const logPath = join168(logDir, `content-${dateStr}.log`);
|
|
76145
76145
|
if (!existsSync83(logPath)) {
|
|
76146
76146
|
logger.info("No content logs found for today.");
|
|
76147
76147
|
return;
|
|
@@ -76173,13 +76173,13 @@ var init_content_subcommands = __esm(() => {
|
|
|
76173
76173
|
init_setup_wizard();
|
|
76174
76174
|
init_state_manager();
|
|
76175
76175
|
init_content_review_commands();
|
|
76176
|
-
LOCK_DIR =
|
|
76176
|
+
LOCK_DIR = join168(homedir58(), ".claudekit", "locks");
|
|
76177
76177
|
});
|
|
76178
76178
|
|
|
76179
76179
|
// src/commands/content/content-command.ts
|
|
76180
76180
|
import { existsSync as existsSync84, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
76181
|
-
import { homedir as
|
|
76182
|
-
import { join as
|
|
76181
|
+
import { homedir as homedir59 } from "node:os";
|
|
76182
|
+
import { join as join169 } from "node:path";
|
|
76183
76183
|
async function contentCommand(options2) {
|
|
76184
76184
|
const cwd2 = process.cwd();
|
|
76185
76185
|
const contentLogger = new ContentLogger;
|
|
@@ -76211,7 +76211,7 @@ async function contentCommand(options2) {
|
|
|
76211
76211
|
if (!existsSync84(LOCK_DIR2))
|
|
76212
76212
|
mkdirSync9(LOCK_DIR2, { recursive: true });
|
|
76213
76213
|
writeFileSync7(LOCK_FILE, String(process.pid), "utf-8");
|
|
76214
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76214
|
+
const dbPath = config.dbPath.replace(/^~/, homedir59());
|
|
76215
76215
|
const db = initDatabase(dbPath);
|
|
76216
76216
|
contentLogger.info(`Database initialised at ${dbPath}`);
|
|
76217
76217
|
const adapters = initializeAdapters(config);
|
|
@@ -76357,8 +76357,8 @@ var init_content_command = __esm(() => {
|
|
|
76357
76357
|
init_publisher();
|
|
76358
76358
|
init_review_manager();
|
|
76359
76359
|
init_state_manager();
|
|
76360
|
-
LOCK_DIR2 =
|
|
76361
|
-
LOCK_FILE =
|
|
76360
|
+
LOCK_DIR2 = join169(homedir59(), ".claudekit", "locks");
|
|
76361
|
+
LOCK_FILE = join169(LOCK_DIR2, "ck-content.lock");
|
|
76362
76362
|
});
|
|
76363
76363
|
|
|
76364
76364
|
// src/commands/content/index.ts
|
|
@@ -107075,9 +107075,9 @@ async function initCommand(options2) {
|
|
|
107075
107075
|
init_dist2();
|
|
107076
107076
|
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
107077
107077
|
import { existsSync as existsSync64 } from "node:fs";
|
|
107078
|
-
import { readFile as
|
|
107079
|
-
import { homedir as
|
|
107080
|
-
import { basename as basename27, join as
|
|
107078
|
+
import { readFile as readFile63, rm as rm16, unlink as unlink13 } from "node:fs/promises";
|
|
107079
|
+
import { homedir as homedir52 } from "node:os";
|
|
107080
|
+
import { basename as basename27, join as join144, resolve as resolve41 } from "node:path";
|
|
107081
107081
|
init_logger();
|
|
107082
107082
|
|
|
107083
107083
|
// src/ui/ck-cli-design/tokens.ts
|
|
@@ -107549,32 +107549,262 @@ init_model_taxonomy();
|
|
|
107549
107549
|
init_logger();
|
|
107550
107550
|
init_dist2();
|
|
107551
107551
|
init_model_taxonomy();
|
|
107552
|
-
import { mkdir as
|
|
107552
|
+
import { mkdir as mkdir37, readFile as readFile62, writeFile as writeFile36 } from "node:fs/promises";
|
|
107553
|
+
import { homedir as homedir51 } from "node:os";
|
|
107554
|
+
import { dirname as dirname41, join as join143 } from "node:path";
|
|
107555
|
+
|
|
107556
|
+
// src/commands/portable/models-dev-cache.ts
|
|
107557
|
+
init_logger();
|
|
107558
|
+
import { mkdir as mkdir36, readFile as readFile60, rename as rename13, writeFile as writeFile35 } from "node:fs/promises";
|
|
107553
107559
|
import { homedir as homedir49 } from "node:os";
|
|
107554
|
-
import {
|
|
107555
|
-
|
|
107556
|
-
|
|
107557
|
-
|
|
107560
|
+
import { join as join141 } from "node:path";
|
|
107561
|
+
|
|
107562
|
+
class ModelsDevUnavailableError extends Error {
|
|
107563
|
+
constructor(message, cause) {
|
|
107564
|
+
super(message, { cause });
|
|
107565
|
+
this.name = "ModelsDevUnavailableError";
|
|
107566
|
+
}
|
|
107567
|
+
}
|
|
107568
|
+
var MODELS_DEV_URL = "https://models.dev/api.json";
|
|
107569
|
+
var CACHE_TTL_MS3 = 24 * 60 * 60 * 1000;
|
|
107570
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
107571
|
+
function defaultCacheDir() {
|
|
107572
|
+
return join141(homedir49(), ".config", "claudekit", "cache");
|
|
107573
|
+
}
|
|
107574
|
+
function cacheFilePath(cacheDir) {
|
|
107575
|
+
return join141(cacheDir, "models-dev.json");
|
|
107576
|
+
}
|
|
107577
|
+
function tmpFilePath(cacheDir) {
|
|
107578
|
+
return join141(cacheDir, "models-dev.json.tmp");
|
|
107579
|
+
}
|
|
107580
|
+
async function readCacheEntry(cacheDir) {
|
|
107581
|
+
const filePath = cacheFilePath(cacheDir);
|
|
107582
|
+
try {
|
|
107583
|
+
const raw2 = await readFile60(filePath, "utf-8");
|
|
107584
|
+
const parsed = JSON.parse(raw2);
|
|
107585
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) && "fetchedAt" in parsed && typeof parsed.fetchedAt === "string" && "payload" in parsed && typeof parsed.payload === "object" && parsed.payload !== null) {
|
|
107586
|
+
return parsed;
|
|
107587
|
+
}
|
|
107588
|
+
return null;
|
|
107589
|
+
} catch {
|
|
107590
|
+
return null;
|
|
107591
|
+
}
|
|
107592
|
+
}
|
|
107593
|
+
function isCacheFresh(entry) {
|
|
107594
|
+
const fetchedAt = new Date(entry.fetchedAt).getTime();
|
|
107595
|
+
return Date.now() - fetchedAt < CACHE_TTL_MS3;
|
|
107596
|
+
}
|
|
107597
|
+
async function writeCacheEntry(cacheDir, entry) {
|
|
107598
|
+
await mkdir36(cacheDir, { recursive: true });
|
|
107599
|
+
const tmp = tmpFilePath(cacheDir);
|
|
107600
|
+
const dest = cacheFilePath(cacheDir);
|
|
107601
|
+
await writeFile35(tmp, JSON.stringify(entry), "utf-8");
|
|
107602
|
+
await rename13(tmp, dest);
|
|
107603
|
+
}
|
|
107604
|
+
async function fetchCatalog(fetcher) {
|
|
107605
|
+
const controller = new AbortController;
|
|
107606
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
107607
|
+
try {
|
|
107608
|
+
const response = await fetcher(MODELS_DEV_URL, { signal: controller.signal });
|
|
107609
|
+
if (!response.ok) {
|
|
107610
|
+
throw new Error(`models.dev returned HTTP ${response.status}`);
|
|
107611
|
+
}
|
|
107612
|
+
const json = await response.json();
|
|
107613
|
+
if (json === null || typeof json !== "object" || Array.isArray(json)) {
|
|
107614
|
+
throw new Error("models.dev response is not an object");
|
|
107615
|
+
}
|
|
107616
|
+
return json;
|
|
107617
|
+
} finally {
|
|
107618
|
+
clearTimeout(timer);
|
|
107619
|
+
}
|
|
107620
|
+
}
|
|
107621
|
+
async function getModelsDevCatalog(opts = {}) {
|
|
107622
|
+
const cacheDir = opts.cacheDir ?? defaultCacheDir();
|
|
107623
|
+
const fetcher = opts.fetcher ?? globalThis.fetch;
|
|
107624
|
+
const cached = await readCacheEntry(cacheDir);
|
|
107625
|
+
if (cached !== null && isCacheFresh(cached)) {
|
|
107626
|
+
return cached.payload;
|
|
107627
|
+
}
|
|
107628
|
+
try {
|
|
107629
|
+
const payload = await fetchCatalog(fetcher);
|
|
107630
|
+
const entry = {
|
|
107631
|
+
fetchedAt: new Date().toISOString(),
|
|
107632
|
+
payload
|
|
107633
|
+
};
|
|
107634
|
+
try {
|
|
107635
|
+
await writeCacheEntry(cacheDir, entry);
|
|
107636
|
+
} catch (writeErr) {
|
|
107637
|
+
logger.verbose(`models-dev-cache: failed to write cache to ${cacheDir}: ${String(writeErr)}`);
|
|
107638
|
+
}
|
|
107639
|
+
return payload;
|
|
107640
|
+
} catch (fetchErr) {
|
|
107641
|
+
if (cached !== null) {
|
|
107642
|
+
logger.warning(`models-dev-cache: fetch failed (${String(fetchErr)}), using stale cache from ${cached.fetchedAt}`);
|
|
107643
|
+
return cached.payload;
|
|
107644
|
+
}
|
|
107645
|
+
throw new ModelsDevUnavailableError(`models.dev catalog unavailable: ${String(fetchErr)}`, fetchErr);
|
|
107558
107646
|
}
|
|
107559
|
-
return join141(options2.cwd ?? process.cwd(), "opencode.json");
|
|
107560
107647
|
}
|
|
107561
|
-
|
|
107562
|
-
|
|
107648
|
+
|
|
107649
|
+
// src/commands/portable/opencode-model-discovery.ts
|
|
107650
|
+
init_logger();
|
|
107651
|
+
import { readFile as readFile61 } from "node:fs/promises";
|
|
107652
|
+
import { homedir as homedir50, platform as platform17 } from "node:os";
|
|
107653
|
+
import { join as join142 } from "node:path";
|
|
107654
|
+
function resolveOpenCodeAuthPath(homeDir) {
|
|
107655
|
+
if (platform17() === "win32") {
|
|
107656
|
+
const dataRoot2 = process.env.LOCALAPPDATA ?? join142(homeDir, "AppData", "Local");
|
|
107657
|
+
return join142(dataRoot2, "opencode", "auth.json");
|
|
107658
|
+
}
|
|
107659
|
+
const dataRoot = process.env.XDG_DATA_HOME ?? join142(homeDir, ".local", "share");
|
|
107660
|
+
return join142(dataRoot, "opencode", "auth.json");
|
|
107661
|
+
}
|
|
107662
|
+
async function readAuthedProviders(homeDir) {
|
|
107663
|
+
const authPath = resolveOpenCodeAuthPath(homeDir);
|
|
107563
107664
|
try {
|
|
107564
|
-
const raw2 = await
|
|
107665
|
+
const raw2 = await readFile61(authPath, "utf-8");
|
|
107565
107666
|
const parsed = JSON.parse(raw2);
|
|
107566
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107667
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107567
107668
|
return Object.keys(parsed);
|
|
107568
107669
|
}
|
|
107569
107670
|
} catch {}
|
|
107570
107671
|
return [];
|
|
107571
107672
|
}
|
|
107572
|
-
|
|
107673
|
+
function releaseDateMs(model) {
|
|
107674
|
+
const d3 = new Date(model.release_date);
|
|
107675
|
+
return Number.isNaN(d3.getTime()) ? 0 : d3.getTime();
|
|
107676
|
+
}
|
|
107677
|
+
function sortByDateDesc(models) {
|
|
107678
|
+
return [...models].sort((a3, b3) => releaseDateMs(b3) - releaseDateMs(a3));
|
|
107679
|
+
}
|
|
107680
|
+
function pickOpenCodeModel(models) {
|
|
107681
|
+
const all = Object.values(models);
|
|
107682
|
+
const freeCallable = all.filter((m2) => m2.tool_call && m2.id.endsWith("-free"));
|
|
107683
|
+
const sortedFree = sortByDateDesc(freeCallable);
|
|
107684
|
+
const topFree = sortedFree[0];
|
|
107685
|
+
if (topFree !== undefined) {
|
|
107686
|
+
return topFree;
|
|
107687
|
+
}
|
|
107688
|
+
const callable = all.filter((m2) => m2.tool_call);
|
|
107689
|
+
const sortedCallable = sortByDateDesc(callable);
|
|
107690
|
+
return sortedCallable[0] ?? null;
|
|
107691
|
+
}
|
|
107692
|
+
function pickGenericModel(models) {
|
|
107693
|
+
const callable = Object.values(models).filter((m2) => m2.tool_call);
|
|
107694
|
+
const sorted = sortByDateDesc(callable);
|
|
107695
|
+
return sorted[0] ?? null;
|
|
107696
|
+
}
|
|
107697
|
+
async function resolveOpenCodeDefaultModel(opts = {}) {
|
|
107698
|
+
const home9 = opts.homeDir ?? homedir50();
|
|
107699
|
+
const authedProviders = await readAuthedProviders(home9);
|
|
107700
|
+
if (authedProviders.length === 0) {
|
|
107701
|
+
return { ok: false, reason: "no-auth", authedProviders: [] };
|
|
107702
|
+
}
|
|
107703
|
+
let catalog;
|
|
107704
|
+
try {
|
|
107705
|
+
catalog = await getModelsDevCatalog({ fetcher: opts.fetcher, cacheDir: opts.cacheDir });
|
|
107706
|
+
} catch (err) {
|
|
107707
|
+
if (err instanceof ModelsDevUnavailableError) {
|
|
107708
|
+
logger.verbose(`opencode-model-discovery: models.dev unavailable, cannot auto-resolve model: ${err.message}`);
|
|
107709
|
+
return { ok: false, reason: "catalog-unavailable", authedProviders };
|
|
107710
|
+
}
|
|
107711
|
+
throw err;
|
|
107712
|
+
}
|
|
107713
|
+
const orderedProviders = [
|
|
107714
|
+
...authedProviders.filter((id) => id === "opencode"),
|
|
107715
|
+
...authedProviders.filter((id) => id !== "opencode")
|
|
107716
|
+
];
|
|
107717
|
+
for (const providerId of orderedProviders) {
|
|
107718
|
+
const providerEntry = catalog[providerId];
|
|
107719
|
+
if (!providerEntry) {
|
|
107720
|
+
continue;
|
|
107721
|
+
}
|
|
107722
|
+
const picked = providerId === "opencode" ? pickOpenCodeModel(providerEntry.models) : pickGenericModel(providerEntry.models);
|
|
107723
|
+
if (!picked) {
|
|
107724
|
+
continue;
|
|
107725
|
+
}
|
|
107726
|
+
const isFree = picked.id.endsWith("-free");
|
|
107727
|
+
const tierLabel = isFree ? "free tier" : "paid";
|
|
107728
|
+
const reason = `auth-detected: ${providerId} (${tierLabel}, released ${picked.release_date})`;
|
|
107729
|
+
return {
|
|
107730
|
+
ok: true,
|
|
107731
|
+
value: {
|
|
107732
|
+
model: `${providerId}/${picked.id}`,
|
|
107733
|
+
reason,
|
|
107734
|
+
authedProviders
|
|
107735
|
+
}
|
|
107736
|
+
};
|
|
107737
|
+
}
|
|
107738
|
+
return { ok: false, reason: "no-usable-model", authedProviders };
|
|
107739
|
+
}
|
|
107740
|
+
|
|
107741
|
+
// src/commands/portable/opencode-config-installer.ts
|
|
107742
|
+
class OpenCodeAuthRequiredError extends Error {
|
|
107743
|
+
reason;
|
|
107744
|
+
constructor(reason = "no-auth") {
|
|
107745
|
+
super(messageForReason(reason));
|
|
107746
|
+
this.name = "OpenCodeAuthRequiredError";
|
|
107747
|
+
this.reason = reason;
|
|
107748
|
+
}
|
|
107749
|
+
}
|
|
107750
|
+
function messageForReason(reason) {
|
|
107751
|
+
switch (reason) {
|
|
107752
|
+
case "no-auth":
|
|
107753
|
+
return "opencode has no authenticated providers. Run `opencode auth login` first, then re-run `ck migrate`.";
|
|
107754
|
+
case "catalog-unavailable":
|
|
107755
|
+
return "Cannot reach models.dev to pick a default model. Check your network, then re-run `ck migrate` — or set `model` in opencode.json manually.";
|
|
107756
|
+
case "no-usable-model":
|
|
107757
|
+
return "None of your authenticated opencode providers have a tool-capable model in the models.dev catalog. Set `model` in opencode.json manually.";
|
|
107758
|
+
}
|
|
107759
|
+
}
|
|
107760
|
+
function getOpenCodeConfigPath(options2) {
|
|
107761
|
+
if (options2.global) {
|
|
107762
|
+
return join143(options2.homeDir ?? homedir51(), ".config", "opencode", "opencode.json");
|
|
107763
|
+
}
|
|
107764
|
+
return join143(options2.cwd ?? process.cwd(), "opencode.json");
|
|
107765
|
+
}
|
|
107766
|
+
function makeCatalogOpts(options2) {
|
|
107767
|
+
return {
|
|
107768
|
+
fetcher: options2.fetcher,
|
|
107769
|
+
cacheDir: options2.cacheDir
|
|
107770
|
+
};
|
|
107771
|
+
}
|
|
107772
|
+
async function validateModelAgainstCatalog(model, options2) {
|
|
107773
|
+
const slashIdx = model.indexOf("/");
|
|
107774
|
+
if (slashIdx <= 0 || slashIdx === model.length - 1) {
|
|
107775
|
+
return false;
|
|
107776
|
+
}
|
|
107777
|
+
const providerId = model.slice(0, slashIdx);
|
|
107778
|
+
const modelId = model.slice(slashIdx + 1);
|
|
107779
|
+
try {
|
|
107780
|
+
const catalog = await getModelsDevCatalog(makeCatalogOpts(options2));
|
|
107781
|
+
const provider = catalog[providerId];
|
|
107782
|
+
if (!provider)
|
|
107783
|
+
return false;
|
|
107784
|
+
return modelId in provider.models;
|
|
107785
|
+
} catch {
|
|
107786
|
+
return true;
|
|
107787
|
+
}
|
|
107788
|
+
}
|
|
107789
|
+
async function suggestModel(options2) {
|
|
107573
107790
|
const override = getOpenCodeDefaultModelOverride();
|
|
107574
107791
|
if (override) {
|
|
107575
|
-
return { model: override, reason: ".ck.json override" };
|
|
107792
|
+
return { ok: true, model: override, reason: ".ck.json override", authedProviders: [] };
|
|
107793
|
+
}
|
|
107794
|
+
const result = await resolveOpenCodeDefaultModel({
|
|
107795
|
+
homeDir: options2.homeDir,
|
|
107796
|
+
fetcher: options2.fetcher,
|
|
107797
|
+
cacheDir: options2.cacheDir
|
|
107798
|
+
});
|
|
107799
|
+
if (result.ok) {
|
|
107800
|
+
return {
|
|
107801
|
+
ok: true,
|
|
107802
|
+
model: result.value.model,
|
|
107803
|
+
reason: result.value.reason,
|
|
107804
|
+
authedProviders: result.value.authedProviders
|
|
107805
|
+
};
|
|
107576
107806
|
}
|
|
107577
|
-
return {
|
|
107807
|
+
return { ok: false, failure: result.reason, authedProviders: result.authedProviders };
|
|
107578
107808
|
}
|
|
107579
107809
|
var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
107580
107810
|
const providersHint = detectedProviders.length > 0 ? `Authenticated providers in opencode: ${detectedProviders.join(", ")}` : "No authenticated providers detected in opencode.";
|
|
@@ -107596,7 +107826,7 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
|
107596
107826
|
if (response === "accept")
|
|
107597
107827
|
return { action: "accept" };
|
|
107598
107828
|
const custom2 = await te({
|
|
107599
|
-
message: "Model (format: provider/model-id, e.g.
|
|
107829
|
+
message: "Model (format: provider/model-id, e.g. opencode/qwen3.5-plus-free)",
|
|
107600
107830
|
placeholder: suggestion,
|
|
107601
107831
|
validate: (value) => {
|
|
107602
107832
|
if (!value || !value.includes("/"))
|
|
@@ -107608,13 +107838,35 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
|
107608
107838
|
return { action: "skip" };
|
|
107609
107839
|
return { action: "custom", value: custom2 };
|
|
107610
107840
|
};
|
|
107841
|
+
var makeInvalidModelPrompter = (existingModel, suggestion, reason) => async ({ detectedProviders }) => {
|
|
107842
|
+
const providersHint = detectedProviders.length > 0 ? `Authenticated providers: ${detectedProviders.join(", ")}` : "No authenticated providers detected.";
|
|
107843
|
+
const response = await ie({
|
|
107844
|
+
message: `Existing model "${existingModel}" is not in the models.dev catalog. ${providersHint}`,
|
|
107845
|
+
options: [
|
|
107846
|
+
{
|
|
107847
|
+
value: "rewrite",
|
|
107848
|
+
label: `Replace with "${suggestion}"`,
|
|
107849
|
+
hint: reason
|
|
107850
|
+
},
|
|
107851
|
+
{
|
|
107852
|
+
value: "keep",
|
|
107853
|
+
label: `Keep "${existingModel}" as-is`,
|
|
107854
|
+
hint: "May cause ProviderModelNotFoundError at runtime"
|
|
107855
|
+
}
|
|
107856
|
+
],
|
|
107857
|
+
initialValue: "rewrite"
|
|
107858
|
+
});
|
|
107859
|
+
if (lD(response) || response === "keep")
|
|
107860
|
+
return { action: "skip" };
|
|
107861
|
+
return { action: "accept" };
|
|
107862
|
+
};
|
|
107611
107863
|
async function ensureOpenCodeModel(options2) {
|
|
107612
107864
|
const configPath = getOpenCodeConfigPath(options2);
|
|
107613
107865
|
let existing = null;
|
|
107614
107866
|
try {
|
|
107615
|
-
const raw2 = await
|
|
107867
|
+
const raw2 = await readFile62(configPath, "utf-8");
|
|
107616
107868
|
const parsed = JSON.parse(raw2);
|
|
107617
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107869
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107618
107870
|
existing = parsed;
|
|
107619
107871
|
} else {
|
|
107620
107872
|
logger.warning(`ensureOpenCodeModel: ${configPath} is valid JSON but not an object; overwriting with default model`);
|
|
@@ -107627,40 +107879,72 @@ async function ensureOpenCodeModel(options2) {
|
|
|
107627
107879
|
logger.verbose(`ensureOpenCodeModel: failed to read ${configPath} (${errno ?? String(err)}); recreating`);
|
|
107628
107880
|
}
|
|
107629
107881
|
}
|
|
107630
|
-
if (existing && typeof existing.model === "string" && existing.model.trim().length > 0) {
|
|
107631
|
-
|
|
107632
|
-
|
|
107633
|
-
|
|
107634
|
-
|
|
107635
|
-
|
|
107636
|
-
|
|
107637
|
-
|
|
107638
|
-
|
|
107639
|
-
|
|
107640
|
-
|
|
107641
|
-
|
|
107882
|
+
if (existing !== null && typeof existing.model === "string" && existing.model.trim().length > 0) {
|
|
107883
|
+
const existingModel = existing.model.trim();
|
|
107884
|
+
const isValid2 = await validateModelAgainstCatalog(existingModel, options2);
|
|
107885
|
+
if (isValid2) {
|
|
107886
|
+
return { path: configPath, action: "existing", model: existingModel };
|
|
107887
|
+
}
|
|
107888
|
+
if (!options2.interactive) {
|
|
107889
|
+
logger.warning(`ensureOpenCodeModel: existing model "${existingModel}" is not found in the models.dev catalog. ` + `Run \`ck migrate --agent opencode\` interactively to update it, or edit ${configPath} manually.`);
|
|
107890
|
+
return { path: configPath, action: "existing", model: existingModel };
|
|
107891
|
+
}
|
|
107892
|
+
const suggestion2 = await suggestModel(options2);
|
|
107893
|
+
if (!suggestion2.ok) {
|
|
107894
|
+
return { path: configPath, action: "existing", model: existingModel };
|
|
107895
|
+
}
|
|
107896
|
+
const invalidPrompter = options2.prompter ?? makeInvalidModelPrompter(existingModel, suggestion2.model, suggestion2.reason);
|
|
107897
|
+
const response2 = await invalidPrompter({
|
|
107898
|
+
suggestion: suggestion2.model,
|
|
107899
|
+
reason: suggestion2.reason,
|
|
107900
|
+
detectedProviders: suggestion2.authedProviders
|
|
107642
107901
|
});
|
|
107643
|
-
if (
|
|
107644
|
-
return {
|
|
107645
|
-
path: configPath,
|
|
107646
|
-
action: "skipped",
|
|
107647
|
-
model: "",
|
|
107648
|
-
reason: "user declined"
|
|
107649
|
-
};
|
|
107902
|
+
if (response2.action === "skip") {
|
|
107903
|
+
return { path: configPath, action: "existing", model: existingModel };
|
|
107650
107904
|
}
|
|
107651
|
-
|
|
107652
|
-
|
|
107905
|
+
const chosenModel2 = response2.action === "custom" ? response2.value : suggestion2.model;
|
|
107906
|
+
const next2 = { ...existing, model: chosenModel2 };
|
|
107907
|
+
await mkdir37(dirname41(configPath), { recursive: true });
|
|
107908
|
+
await writeFile36(configPath, `${JSON.stringify(next2, null, 2)}
|
|
107909
|
+
`, "utf-8");
|
|
107910
|
+
return { path: configPath, action: "added", model: chosenModel2, reason: suggestion2.reason };
|
|
107911
|
+
}
|
|
107912
|
+
const suggestion = await suggestModel(options2);
|
|
107913
|
+
if (!options2.interactive) {
|
|
107914
|
+
if (!suggestion.ok) {
|
|
107915
|
+
throw new OpenCodeAuthRequiredError(suggestion.failure);
|
|
107653
107916
|
}
|
|
107917
|
+
const next2 = { ...existing ?? {}, model: suggestion.model };
|
|
107918
|
+
await mkdir37(dirname41(configPath), { recursive: true });
|
|
107919
|
+
await writeFile36(configPath, `${JSON.stringify(next2, null, 2)}
|
|
107920
|
+
`, "utf-8");
|
|
107921
|
+
return {
|
|
107922
|
+
path: configPath,
|
|
107923
|
+
action: existing ? "added" : "created",
|
|
107924
|
+
model: suggestion.model,
|
|
107925
|
+
reason: suggestion.reason
|
|
107926
|
+
};
|
|
107927
|
+
}
|
|
107928
|
+
const prompter = options2.prompter ?? clackPrompter;
|
|
107929
|
+
const detectedProviders = suggestion.ok ? suggestion.authedProviders : suggestion.authedProviders;
|
|
107930
|
+
const response = await prompter({
|
|
107931
|
+
suggestion: suggestion.ok ? suggestion.model : "",
|
|
107932
|
+
reason: suggestion.ok ? suggestion.reason : messageForReason(suggestion.failure),
|
|
107933
|
+
detectedProviders
|
|
107934
|
+
});
|
|
107935
|
+
if (response.action === "skip") {
|
|
107936
|
+
return { path: configPath, action: "skipped", model: "", reason: "user declined" };
|
|
107654
107937
|
}
|
|
107938
|
+
const chosenModel = response.action === "custom" ? response.value : suggestion.ok ? suggestion.model : "";
|
|
107655
107939
|
const next = { ...existing ?? {}, model: chosenModel };
|
|
107656
|
-
await
|
|
107657
|
-
await
|
|
107940
|
+
await mkdir37(dirname41(configPath), { recursive: true });
|
|
107941
|
+
await writeFile36(configPath, `${JSON.stringify(next, null, 2)}
|
|
107658
107942
|
`, "utf-8");
|
|
107659
107943
|
return {
|
|
107660
107944
|
path: configPath,
|
|
107661
107945
|
action: existing ? "added" : "created",
|
|
107662
107946
|
model: chosenModel,
|
|
107663
|
-
reason: suggestion.reason
|
|
107947
|
+
reason: suggestion.ok ? suggestion.reason : undefined
|
|
107664
107948
|
};
|
|
107665
107949
|
}
|
|
107666
107950
|
|
|
@@ -108435,12 +108719,12 @@ async function executeDeleteAction(action, options2) {
|
|
|
108435
108719
|
async function processMetadataDeletions(skillSourcePath, installGlobally) {
|
|
108436
108720
|
if (!skillSourcePath)
|
|
108437
108721
|
return;
|
|
108438
|
-
const sourceMetadataPath =
|
|
108722
|
+
const sourceMetadataPath = join144(resolve41(skillSourcePath, ".."), "metadata.json");
|
|
108439
108723
|
if (!existsSync64(sourceMetadataPath))
|
|
108440
108724
|
return;
|
|
108441
108725
|
let sourceMetadata;
|
|
108442
108726
|
try {
|
|
108443
|
-
const content = await
|
|
108727
|
+
const content = await readFile63(sourceMetadataPath, "utf-8");
|
|
108444
108728
|
sourceMetadata = JSON.parse(content);
|
|
108445
108729
|
} catch (error) {
|
|
108446
108730
|
logger.debug(`[migrate] Failed to parse source metadata.json: ${error}`);
|
|
@@ -108448,7 +108732,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
|
|
|
108448
108732
|
}
|
|
108449
108733
|
if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
|
|
108450
108734
|
return;
|
|
108451
|
-
const claudeDir3 = installGlobally ?
|
|
108735
|
+
const claudeDir3 = installGlobally ? join144(homedir52(), ".claude") : join144(process.cwd(), ".claude");
|
|
108452
108736
|
if (!existsSync64(claudeDir3))
|
|
108453
108737
|
return;
|
|
108454
108738
|
try {
|
|
@@ -108570,8 +108854,8 @@ async function migrateCommand(options2) {
|
|
|
108570
108854
|
let requestedGlobal = options2.global ?? false;
|
|
108571
108855
|
let installGlobally = requestedGlobal;
|
|
108572
108856
|
if (options2.global === undefined && !options2.yes) {
|
|
108573
|
-
const projectTarget =
|
|
108574
|
-
const globalTarget =
|
|
108857
|
+
const projectTarget = join144(process.cwd(), ".claude");
|
|
108858
|
+
const globalTarget = join144(homedir52(), ".claude");
|
|
108575
108859
|
const scopeChoice = await ie({
|
|
108576
108860
|
message: "Installation scope",
|
|
108577
108861
|
options: [
|
|
@@ -108734,7 +109018,7 @@ async function migrateCommand(options2) {
|
|
|
108734
109018
|
for (const action of conflictActions) {
|
|
108735
109019
|
if (!action.diff && action.targetPath && existsSync64(action.targetPath)) {
|
|
108736
109020
|
try {
|
|
108737
|
-
const targetContent = await
|
|
109021
|
+
const targetContent = await readFile63(action.targetPath, "utf-8");
|
|
108738
109022
|
const sourceItem = effectiveAgents.find((a3) => a3.name === action.item) || effectiveCommands.find((c2) => c2.name === action.item) || (effectiveConfigItem?.name === action.item ? effectiveConfigItem : null) || effectiveRuleItems.find((r2) => r2.name === action.item) || effectiveHookItems.find((h2) => h2.name === action.item);
|
|
108739
109023
|
if (sourceItem) {
|
|
108740
109024
|
const providerConfig = providers[action.provider];
|
|
@@ -108881,7 +109165,12 @@ async function migrateCommand(options2) {
|
|
|
108881
109165
|
f2.warn("Skipped writing default model to opencode.json. Migrated agents may fail with ProviderModelNotFoundError until you set one.");
|
|
108882
109166
|
}
|
|
108883
109167
|
} catch (err) {
|
|
108884
|
-
|
|
109168
|
+
if (err instanceof OpenCodeAuthRequiredError) {
|
|
109169
|
+
f2.warn(err.message);
|
|
109170
|
+
postProgressWarnings.push(`opencode setup is incomplete: ${err.message}`);
|
|
109171
|
+
} else {
|
|
109172
|
+
postProgressWarnings.push(`Could not update opencode.json model (${err instanceof Error ? err.message : String(err)}). Agents may fail with ProviderModelNotFoundError until a model is set.`);
|
|
109173
|
+
}
|
|
108885
109174
|
}
|
|
108886
109175
|
}
|
|
108887
109176
|
if (hooksSource && successfulHookFiles.size > 0) {
|
|
@@ -109146,7 +109435,7 @@ function buildDryRunFallbackResults(skills, selectedProviders, installGlobally,
|
|
|
109146
109435
|
results.push({
|
|
109147
109436
|
itemName: skill.name,
|
|
109148
109437
|
operation: "apply",
|
|
109149
|
-
path:
|
|
109438
|
+
path: join144(basePath, skill.name),
|
|
109150
109439
|
portableType: "skill",
|
|
109151
109440
|
provider,
|
|
109152
109441
|
providerDisplayName: providers[provider].displayName,
|
|
@@ -109306,7 +109595,7 @@ async function handleDirectorySetup(ctx) {
|
|
|
109306
109595
|
// src/commands/new/phases/project-creation.ts
|
|
109307
109596
|
init_config_manager();
|
|
109308
109597
|
init_github_client();
|
|
109309
|
-
import { join as
|
|
109598
|
+
import { join as join145 } from "node:path";
|
|
109310
109599
|
init_logger();
|
|
109311
109600
|
init_output_manager();
|
|
109312
109601
|
init_types3();
|
|
@@ -109432,7 +109721,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
|
|
|
109432
109721
|
output.section("Installing");
|
|
109433
109722
|
logger.verbose("Installation target", { directory: resolvedDir });
|
|
109434
109723
|
const merger = new FileMerger;
|
|
109435
|
-
const claudeDir3 =
|
|
109724
|
+
const claudeDir3 = join145(resolvedDir, ".claude");
|
|
109436
109725
|
merger.setMultiKitContext(claudeDir3, kit);
|
|
109437
109726
|
if (validOptions.exclude && validOptions.exclude.length > 0) {
|
|
109438
109727
|
merger.addIgnorePatterns(validOptions.exclude);
|
|
@@ -109479,7 +109768,7 @@ async function handleProjectCreation(ctx) {
|
|
|
109479
109768
|
}
|
|
109480
109769
|
// src/commands/new/phases/post-setup.ts
|
|
109481
109770
|
init_projects_registry();
|
|
109482
|
-
import { join as
|
|
109771
|
+
import { join as join146 } from "node:path";
|
|
109483
109772
|
init_package_installer();
|
|
109484
109773
|
init_logger();
|
|
109485
109774
|
init_path_resolver();
|
|
@@ -109511,9 +109800,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
|
|
|
109511
109800
|
withSudo: validOptions.withSudo
|
|
109512
109801
|
});
|
|
109513
109802
|
}
|
|
109514
|
-
const claudeDir3 =
|
|
109803
|
+
const claudeDir3 = join146(resolvedDir, ".claude");
|
|
109515
109804
|
await promptSetupWizardIfNeeded({
|
|
109516
|
-
envPath:
|
|
109805
|
+
envPath: join146(claudeDir3, ".env"),
|
|
109517
109806
|
claudeDir: claudeDir3,
|
|
109518
109807
|
isGlobal: false,
|
|
109519
109808
|
isNonInteractive: isNonInteractive2,
|
|
@@ -109583,7 +109872,7 @@ Please use only one download method.`);
|
|
|
109583
109872
|
// src/commands/plan/plan-command.ts
|
|
109584
109873
|
init_output_manager();
|
|
109585
109874
|
import { existsSync as existsSync67, statSync as statSync12 } from "node:fs";
|
|
109586
|
-
import { dirname as dirname46, isAbsolute as isAbsolute11, join as
|
|
109875
|
+
import { dirname as dirname46, isAbsolute as isAbsolute11, join as join149, parse as parse7, resolve as resolve48 } from "node:path";
|
|
109587
109876
|
|
|
109588
109877
|
// src/commands/plan/plan-read-handlers.ts
|
|
109589
109878
|
init_config();
|
|
@@ -109593,14 +109882,14 @@ init_logger();
|
|
|
109593
109882
|
init_output_manager();
|
|
109594
109883
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
109595
109884
|
import { existsSync as existsSync66, statSync as statSync11 } from "node:fs";
|
|
109596
|
-
import { basename as basename28, dirname as dirname44, join as
|
|
109885
|
+
import { basename as basename28, dirname as dirname44, join as join148, relative as relative27, resolve as resolve46 } from "node:path";
|
|
109597
109886
|
|
|
109598
109887
|
// src/commands/plan/plan-dependencies.ts
|
|
109599
109888
|
init_config();
|
|
109600
109889
|
init_plan_parser();
|
|
109601
109890
|
init_plans_registry();
|
|
109602
109891
|
import { existsSync as existsSync65 } from "node:fs";
|
|
109603
|
-
import { dirname as dirname43, join as
|
|
109892
|
+
import { dirname as dirname43, join as join147 } from "node:path";
|
|
109604
109893
|
async function resolvePlanDependencies(references, currentPlanFile, options2 = {}) {
|
|
109605
109894
|
if (references.length === 0)
|
|
109606
109895
|
return [];
|
|
@@ -109620,7 +109909,7 @@ async function resolvePlanDependencies(references, currentPlanFile, options2 = {
|
|
|
109620
109909
|
};
|
|
109621
109910
|
}
|
|
109622
109911
|
const scopeRoot = resolvePlanDirForScope(scope, projectRoot, config);
|
|
109623
|
-
const planFile =
|
|
109912
|
+
const planFile = join147(scopeRoot, planId, "plan.md");
|
|
109624
109913
|
const isSelfReference = planFile === currentPlanFile;
|
|
109625
109914
|
if (!existsSync65(planFile)) {
|
|
109626
109915
|
return {
|
|
@@ -109762,7 +110051,7 @@ async function handleStatus(target, options2) {
|
|
|
109762
110051
|
}
|
|
109763
110052
|
const effectiveTarget = !resolvedTarget && globalBaseDir ? globalBaseDir : resolvedTarget;
|
|
109764
110053
|
const t = effectiveTarget ? resolve46(effectiveTarget) : null;
|
|
109765
|
-
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(
|
|
110054
|
+
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join148(t, "plan.md")) ? t : null;
|
|
109766
110055
|
if (plansDir) {
|
|
109767
110056
|
const planFiles = scanPlanDir(plansDir);
|
|
109768
110057
|
if (planFiles.length === 0) {
|
|
@@ -110177,7 +110466,7 @@ function resolvePlanFile(target, baseDir) {
|
|
|
110177
110466
|
const stat24 = statSync12(t);
|
|
110178
110467
|
if (stat24.isFile())
|
|
110179
110468
|
return t;
|
|
110180
|
-
const candidate =
|
|
110469
|
+
const candidate = join149(t, "plan.md");
|
|
110181
110470
|
if (existsSync67(candidate))
|
|
110182
110471
|
return candidate;
|
|
110183
110472
|
}
|
|
@@ -110185,7 +110474,7 @@ function resolvePlanFile(target, baseDir) {
|
|
|
110185
110474
|
let dir = process.cwd();
|
|
110186
110475
|
const root = parse7(dir).root;
|
|
110187
110476
|
while (dir !== root) {
|
|
110188
|
-
const candidate =
|
|
110477
|
+
const candidate = join149(dir, "plan.md");
|
|
110189
110478
|
if (existsSync67(candidate))
|
|
110190
110479
|
return candidate;
|
|
110191
110480
|
dir = dirname46(dir);
|
|
@@ -110707,8 +110996,8 @@ init_skills_registry();
|
|
|
110707
110996
|
init_skills_uninstaller();
|
|
110708
110997
|
var import_gray_matter11 = __toESM(require_gray_matter(), 1);
|
|
110709
110998
|
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
110710
|
-
import { readFile as
|
|
110711
|
-
import { join as
|
|
110999
|
+
import { readFile as readFile64 } from "node:fs/promises";
|
|
111000
|
+
import { join as join150 } from "node:path";
|
|
110712
111001
|
|
|
110713
111002
|
// src/commands/skills/types.ts
|
|
110714
111003
|
init_zod();
|
|
@@ -110830,9 +111119,9 @@ async function handleValidate2(sourcePath) {
|
|
|
110830
111119
|
spinner.stop(`Checked ${skills.length} skill(s)`);
|
|
110831
111120
|
let hasIssues = false;
|
|
110832
111121
|
for (const skill of skills) {
|
|
110833
|
-
const skillMdPath =
|
|
111122
|
+
const skillMdPath = join150(skill.path, "SKILL.md");
|
|
110834
111123
|
try {
|
|
110835
|
-
const content = await
|
|
111124
|
+
const content = await readFile64(skillMdPath, "utf-8");
|
|
110836
111125
|
const { data } = import_gray_matter11.default(content, {
|
|
110837
111126
|
engines: { javascript: { parse: () => ({}) } }
|
|
110838
111127
|
});
|
|
@@ -111388,7 +111677,7 @@ async function detectInstallations() {
|
|
|
111388
111677
|
|
|
111389
111678
|
// src/commands/uninstall/removal-handler.ts
|
|
111390
111679
|
import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
|
|
111391
|
-
import { basename as basename30, join as
|
|
111680
|
+
import { basename as basename30, join as join152, resolve as resolve50, sep as sep12 } from "node:path";
|
|
111392
111681
|
init_logger();
|
|
111393
111682
|
init_safe_prompts();
|
|
111394
111683
|
init_safe_spinner();
|
|
@@ -111397,7 +111686,7 @@ var import_fs_extra44 = __toESM(require_lib3(), 1);
|
|
|
111397
111686
|
// src/commands/uninstall/analysis-handler.ts
|
|
111398
111687
|
init_metadata_migration();
|
|
111399
111688
|
import { readdirSync as readdirSync9, rmSync as rmSync4 } from "node:fs";
|
|
111400
|
-
import { dirname as dirname47, join as
|
|
111689
|
+
import { dirname as dirname47, join as join151 } from "node:path";
|
|
111401
111690
|
init_logger();
|
|
111402
111691
|
init_safe_prompts();
|
|
111403
111692
|
var import_fs_extra43 = __toESM(require_lib3(), 1);
|
|
@@ -111454,7 +111743,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111454
111743
|
const remainingFiles = metadata.kits?.[remainingKit]?.files || [];
|
|
111455
111744
|
for (const file of remainingFiles) {
|
|
111456
111745
|
const relativePath = normalizeTrackedPath(file.path);
|
|
111457
|
-
if (await import_fs_extra43.pathExists(
|
|
111746
|
+
if (await import_fs_extra43.pathExists(join151(installation.path, relativePath))) {
|
|
111458
111747
|
result.retainedManifestPaths.push(relativePath);
|
|
111459
111748
|
}
|
|
111460
111749
|
}
|
|
@@ -111462,7 +111751,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111462
111751
|
const kitFiles = metadata.kits[kit].files || [];
|
|
111463
111752
|
for (const trackedFile of kitFiles) {
|
|
111464
111753
|
const relativePath = normalizeTrackedPath(trackedFile.path);
|
|
111465
|
-
const filePath =
|
|
111754
|
+
const filePath = join151(installation.path, relativePath);
|
|
111466
111755
|
if (preservedPaths.has(relativePath)) {
|
|
111467
111756
|
result.toPreserve.push({ path: relativePath, reason: "shared with other kit" });
|
|
111468
111757
|
continue;
|
|
@@ -111495,7 +111784,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111495
111784
|
}
|
|
111496
111785
|
for (const trackedFile of allTrackedFiles) {
|
|
111497
111786
|
const relativePath = normalizeTrackedPath(trackedFile.path);
|
|
111498
|
-
const filePath =
|
|
111787
|
+
const filePath = join151(installation.path, relativePath);
|
|
111499
111788
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
111500
111789
|
if (!ownershipResult.exists)
|
|
111501
111790
|
continue;
|
|
@@ -111638,7 +111927,7 @@ async function removeInstallations(installations, options2) {
|
|
|
111638
111927
|
let removedCount = 0;
|
|
111639
111928
|
let cleanedDirs = 0;
|
|
111640
111929
|
for (const item of analysis.toDelete) {
|
|
111641
|
-
const filePath =
|
|
111930
|
+
const filePath = join152(installation.path, item.path);
|
|
111642
111931
|
if (!await import_fs_extra44.pathExists(filePath))
|
|
111643
111932
|
continue;
|
|
111644
111933
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
@@ -111972,7 +112261,7 @@ ${import_picocolors40.default.bold(import_picocolors40.default.cyan(result.kitCo
|
|
|
111972
112261
|
init_logger();
|
|
111973
112262
|
import { existsSync as existsSync74 } from "node:fs";
|
|
111974
112263
|
import { rm as rm17 } from "node:fs/promises";
|
|
111975
|
-
import { join as
|
|
112264
|
+
import { join as join159 } from "node:path";
|
|
111976
112265
|
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
111977
112266
|
|
|
111978
112267
|
// src/commands/watch/phases/implementation-runner.ts
|
|
@@ -112490,8 +112779,8 @@ function spawnAndCollect3(command, args) {
|
|
|
112490
112779
|
}
|
|
112491
112780
|
|
|
112492
112781
|
// src/commands/watch/phases/issue-processor.ts
|
|
112493
|
-
import { mkdir as
|
|
112494
|
-
import { join as
|
|
112782
|
+
import { mkdir as mkdir38, writeFile as writeFile38 } from "node:fs/promises";
|
|
112783
|
+
import { join as join155 } from "node:path";
|
|
112495
112784
|
|
|
112496
112785
|
// src/commands/watch/phases/approval-detector.ts
|
|
112497
112786
|
init_logger();
|
|
@@ -112869,9 +113158,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
|
|
|
112869
113158
|
|
|
112870
113159
|
// src/commands/watch/phases/plan-dir-finder.ts
|
|
112871
113160
|
import { readdir as readdir44, stat as stat24 } from "node:fs/promises";
|
|
112872
|
-
import { join as
|
|
113161
|
+
import { join as join154 } from "node:path";
|
|
112873
113162
|
async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
112874
|
-
const plansRoot =
|
|
113163
|
+
const plansRoot = join154(cwd2, "plans");
|
|
112875
113164
|
try {
|
|
112876
113165
|
const entries = await readdir44(plansRoot);
|
|
112877
113166
|
const tenMinAgo = Date.now() - 10 * 60 * 1000;
|
|
@@ -112880,14 +113169,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
|
112880
113169
|
for (const entry of entries) {
|
|
112881
113170
|
if (entry === "watch" || entry === "reports" || entry === "visuals")
|
|
112882
113171
|
continue;
|
|
112883
|
-
const dirPath =
|
|
113172
|
+
const dirPath = join154(plansRoot, entry);
|
|
112884
113173
|
const dirStat = await stat24(dirPath);
|
|
112885
113174
|
if (!dirStat.isDirectory())
|
|
112886
113175
|
continue;
|
|
112887
113176
|
if (dirStat.mtimeMs < tenMinAgo)
|
|
112888
113177
|
continue;
|
|
112889
113178
|
try {
|
|
112890
|
-
await stat24(
|
|
113179
|
+
await stat24(join154(dirPath, "plan.md"));
|
|
112891
113180
|
} catch {
|
|
112892
113181
|
continue;
|
|
112893
113182
|
}
|
|
@@ -113118,14 +113407,14 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
|
|
|
113118
113407
|
stats.plansCreated++;
|
|
113119
113408
|
const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
|
|
113120
113409
|
if (detectedPlanDir) {
|
|
113121
|
-
state.activeIssues[numStr].planPath =
|
|
113410
|
+
state.activeIssues[numStr].planPath = join155(detectedPlanDir, "plan.md");
|
|
113122
113411
|
watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
|
|
113123
113412
|
} else {
|
|
113124
113413
|
try {
|
|
113125
|
-
const planDir =
|
|
113126
|
-
await
|
|
113127
|
-
const planFilePath =
|
|
113128
|
-
await
|
|
113414
|
+
const planDir = join155(projectDir, "plans", "watch");
|
|
113415
|
+
await mkdir38(planDir, { recursive: true });
|
|
113416
|
+
const planFilePath = join155(planDir, `issue-${issue.number}-plan.md`);
|
|
113417
|
+
await writeFile38(planFilePath, planResult.planText, "utf-8");
|
|
113129
113418
|
state.activeIssues[numStr].planPath = planFilePath;
|
|
113130
113419
|
watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
|
|
113131
113420
|
} catch (err) {
|
|
@@ -113202,7 +113491,7 @@ async function checkActiveIssues(state, config, setup, options2, watchLog, stats
|
|
|
113202
113491
|
// src/commands/watch/phases/maintainer-resolver.ts
|
|
113203
113492
|
init_logger();
|
|
113204
113493
|
init_implementation_git_helpers();
|
|
113205
|
-
var
|
|
113494
|
+
var CACHE_TTL_MS4 = 3600000;
|
|
113206
113495
|
var cache4 = new Map;
|
|
113207
113496
|
async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
|
|
113208
113497
|
const normalizedExclude = excludeAuthors.map((s) => s.toLowerCase());
|
|
@@ -113211,7 +113500,7 @@ async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
|
|
|
113211
113500
|
}
|
|
113212
113501
|
const cacheKey = `${owner}/${repo}`;
|
|
113213
113502
|
const cached = cache4.get(cacheKey);
|
|
113214
|
-
if (cached && Date.now() - cached.fetchedAt >=
|
|
113503
|
+
if (cached && Date.now() - cached.fetchedAt >= CACHE_TTL_MS4) {
|
|
113215
113504
|
cache4.delete(cacheKey);
|
|
113216
113505
|
} else if (cached) {
|
|
113217
113506
|
const merged = Array.from(new Set([...cached.users, ...normalizedExclude]));
|
|
@@ -113270,7 +113559,7 @@ init_ck_config_manager();
|
|
|
113270
113559
|
init_file_io();
|
|
113271
113560
|
init_logger();
|
|
113272
113561
|
import { existsSync as existsSync70 } from "node:fs";
|
|
113273
|
-
import { mkdir as
|
|
113562
|
+
import { mkdir as mkdir39, readFile as readFile66 } from "node:fs/promises";
|
|
113274
113563
|
import { dirname as dirname48 } from "node:path";
|
|
113275
113564
|
var PROCESSED_ISSUES_CAP = 500;
|
|
113276
113565
|
async function readCkJson(projectDir) {
|
|
@@ -113278,7 +113567,7 @@ async function readCkJson(projectDir) {
|
|
|
113278
113567
|
try {
|
|
113279
113568
|
if (!existsSync70(configPath))
|
|
113280
113569
|
return {};
|
|
113281
|
-
const content = await
|
|
113570
|
+
const content = await readFile66(configPath, "utf-8");
|
|
113282
113571
|
return JSON.parse(content);
|
|
113283
113572
|
} catch (error) {
|
|
113284
113573
|
logger.warning(`Failed to parse .ck.json: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -113303,7 +113592,7 @@ async function saveWatchState(projectDir, state) {
|
|
|
113303
113592
|
const configPath = CkConfigManager.getProjectConfigPath(projectDir);
|
|
113304
113593
|
const configDir = dirname48(configPath);
|
|
113305
113594
|
if (!existsSync70(configDir)) {
|
|
113306
|
-
await
|
|
113595
|
+
await mkdir39(configDir, { recursive: true });
|
|
113307
113596
|
}
|
|
113308
113597
|
const raw2 = await readCkJson(projectDir);
|
|
113309
113598
|
const watchRaw = raw2.watch ?? {};
|
|
@@ -113431,18 +113720,18 @@ init_logger();
|
|
|
113431
113720
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
113432
113721
|
import { existsSync as existsSync71 } from "node:fs";
|
|
113433
113722
|
import { readdir as readdir45, stat as stat25 } from "node:fs/promises";
|
|
113434
|
-
import { join as
|
|
113723
|
+
import { join as join156 } from "node:path";
|
|
113435
113724
|
async function scanForRepos(parentDir) {
|
|
113436
113725
|
const repos = [];
|
|
113437
113726
|
const entries = await readdir45(parentDir);
|
|
113438
113727
|
for (const entry of entries) {
|
|
113439
113728
|
if (entry.startsWith("."))
|
|
113440
113729
|
continue;
|
|
113441
|
-
const fullPath =
|
|
113730
|
+
const fullPath = join156(parentDir, entry);
|
|
113442
113731
|
const entryStat = await stat25(fullPath);
|
|
113443
113732
|
if (!entryStat.isDirectory())
|
|
113444
113733
|
continue;
|
|
113445
|
-
const gitDir =
|
|
113734
|
+
const gitDir = join156(fullPath, ".git");
|
|
113446
113735
|
if (!existsSync71(gitDir))
|
|
113447
113736
|
continue;
|
|
113448
113737
|
const result = spawnSync7("gh", ["repo", "view", "--json", "owner,name"], {
|
|
@@ -113468,8 +113757,8 @@ async function scanForRepos(parentDir) {
|
|
|
113468
113757
|
init_logger();
|
|
113469
113758
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
113470
113759
|
import { existsSync as existsSync72 } from "node:fs";
|
|
113471
|
-
import { homedir as
|
|
113472
|
-
import { join as
|
|
113760
|
+
import { homedir as homedir53 } from "node:os";
|
|
113761
|
+
import { join as join157 } from "node:path";
|
|
113473
113762
|
async function validateSetup(cwd2) {
|
|
113474
113763
|
const workDir = cwd2 ?? process.cwd();
|
|
113475
113764
|
const ghVersion = spawnSync8("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
|
|
@@ -113500,7 +113789,7 @@ Run this command from a directory with a GitHub remote.`);
|
|
|
113500
113789
|
} catch {
|
|
113501
113790
|
throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
|
|
113502
113791
|
}
|
|
113503
|
-
const skillsPath =
|
|
113792
|
+
const skillsPath = join157(homedir53(), ".claude", "skills");
|
|
113504
113793
|
const skillsAvailable = existsSync72(skillsPath);
|
|
113505
113794
|
if (!skillsAvailable) {
|
|
113506
113795
|
logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
|
|
@@ -113518,8 +113807,8 @@ init_logger();
|
|
|
113518
113807
|
init_path_resolver();
|
|
113519
113808
|
import { createWriteStream as createWriteStream3, statSync as statSync13 } from "node:fs";
|
|
113520
113809
|
import { existsSync as existsSync73 } from "node:fs";
|
|
113521
|
-
import { mkdir as
|
|
113522
|
-
import { join as
|
|
113810
|
+
import { mkdir as mkdir40, rename as rename14 } from "node:fs/promises";
|
|
113811
|
+
import { join as join158 } from "node:path";
|
|
113523
113812
|
|
|
113524
113813
|
class WatchLogger {
|
|
113525
113814
|
logStream = null;
|
|
@@ -113527,16 +113816,16 @@ class WatchLogger {
|
|
|
113527
113816
|
logPath = null;
|
|
113528
113817
|
maxBytes;
|
|
113529
113818
|
constructor(logDir, maxBytes = 0) {
|
|
113530
|
-
this.logDir = logDir ??
|
|
113819
|
+
this.logDir = logDir ?? join158(PathResolver.getClaudeKitDir(), "logs");
|
|
113531
113820
|
this.maxBytes = maxBytes;
|
|
113532
113821
|
}
|
|
113533
113822
|
async init() {
|
|
113534
113823
|
try {
|
|
113535
113824
|
if (!existsSync73(this.logDir)) {
|
|
113536
|
-
await
|
|
113825
|
+
await mkdir40(this.logDir, { recursive: true });
|
|
113537
113826
|
}
|
|
113538
113827
|
const dateStr = formatDate(new Date);
|
|
113539
|
-
this.logPath =
|
|
113828
|
+
this.logPath = join158(this.logDir, `watch-${dateStr}.log`);
|
|
113540
113829
|
this.logStream = createWriteStream3(this.logPath, { flags: "a", mode: 384 });
|
|
113541
113830
|
} catch (error) {
|
|
113542
113831
|
logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -113601,7 +113890,7 @@ class WatchLogger {
|
|
|
113601
113890
|
try {
|
|
113602
113891
|
this.logStream.end();
|
|
113603
113892
|
const rotatedPath = `${this.logPath}.1`;
|
|
113604
|
-
|
|
113893
|
+
rename14(this.logPath, rotatedPath).catch(() => {});
|
|
113605
113894
|
this.logStream = createWriteStream3(this.logPath, { flags: "w", mode: 384 });
|
|
113606
113895
|
} catch {}
|
|
113607
113896
|
}
|
|
@@ -113718,7 +114007,7 @@ async function watchCommand(options2) {
|
|
|
113718
114007
|
}
|
|
113719
114008
|
async function discoverRepos(options2, watchLog) {
|
|
113720
114009
|
const cwd2 = process.cwd();
|
|
113721
|
-
const isGitRepo = existsSync74(
|
|
114010
|
+
const isGitRepo = existsSync74(join159(cwd2, ".git"));
|
|
113722
114011
|
if (options2.force) {
|
|
113723
114012
|
await forceRemoveLock(watchLog);
|
|
113724
114013
|
}
|
|
@@ -113977,7 +114266,7 @@ function registerCommands(cli) {
|
|
|
113977
114266
|
init_package();
|
|
113978
114267
|
init_config_version_checker();
|
|
113979
114268
|
import { existsSync as existsSync86, readFileSync as readFileSync22 } from "node:fs";
|
|
113980
|
-
import { join as
|
|
114269
|
+
import { join as join171 } from "node:path";
|
|
113981
114270
|
|
|
113982
114271
|
// src/domains/versioning/version-checker.ts
|
|
113983
114272
|
init_version_utils();
|
|
@@ -113991,15 +114280,15 @@ init_types3();
|
|
|
113991
114280
|
init_logger();
|
|
113992
114281
|
init_path_resolver();
|
|
113993
114282
|
import { existsSync as existsSync85 } from "node:fs";
|
|
113994
|
-
import { mkdir as
|
|
113995
|
-
import { join as
|
|
114283
|
+
import { mkdir as mkdir41, readFile as readFile68, writeFile as writeFile41 } from "node:fs/promises";
|
|
114284
|
+
import { join as join170 } from "node:path";
|
|
113996
114285
|
|
|
113997
114286
|
class VersionCacheManager {
|
|
113998
114287
|
static CACHE_FILENAME = "version-check.json";
|
|
113999
114288
|
static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
114000
114289
|
static getCacheFile() {
|
|
114001
114290
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
114002
|
-
return
|
|
114291
|
+
return join170(cacheDir, VersionCacheManager.CACHE_FILENAME);
|
|
114003
114292
|
}
|
|
114004
114293
|
static async load() {
|
|
114005
114294
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
@@ -114008,7 +114297,7 @@ class VersionCacheManager {
|
|
|
114008
114297
|
logger.debug("Version check cache not found");
|
|
114009
114298
|
return null;
|
|
114010
114299
|
}
|
|
114011
|
-
const content = await
|
|
114300
|
+
const content = await readFile68(cacheFile, "utf-8");
|
|
114012
114301
|
const cache5 = JSON.parse(content);
|
|
114013
114302
|
if (!cache5.lastCheck || !cache5.currentVersion || !cache5.latestVersion) {
|
|
114014
114303
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -114026,9 +114315,9 @@ class VersionCacheManager {
|
|
|
114026
114315
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
114027
114316
|
try {
|
|
114028
114317
|
if (!existsSync85(cacheDir)) {
|
|
114029
|
-
await
|
|
114318
|
+
await mkdir41(cacheDir, { recursive: true, mode: 448 });
|
|
114030
114319
|
}
|
|
114031
|
-
await
|
|
114320
|
+
await writeFile41(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
|
|
114032
114321
|
logger.debug(`Version check cache saved to ${cacheFile}`);
|
|
114033
114322
|
} catch (error) {
|
|
114034
114323
|
logger.debug(`Failed to save version check cache: ${error}`);
|
|
@@ -114310,9 +114599,9 @@ async function displayVersion() {
|
|
|
114310
114599
|
let localInstalledKits = [];
|
|
114311
114600
|
let globalInstalledKits = [];
|
|
114312
114601
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
114313
|
-
const globalMetadataPath =
|
|
114602
|
+
const globalMetadataPath = join171(globalKitDir, "metadata.json");
|
|
114314
114603
|
const prefix = PathResolver.getPathPrefix(false);
|
|
114315
|
-
const localMetadataPath = prefix ?
|
|
114604
|
+
const localMetadataPath = prefix ? join171(process.cwd(), prefix, "metadata.json") : join171(process.cwd(), "metadata.json");
|
|
114316
114605
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
114317
114606
|
if (!isLocalSameAsGlobal && existsSync86(localMetadataPath)) {
|
|
114318
114607
|
try {
|