claudekit-cli 3.42.2-dev.7 → 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 +909 -291
- 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: {
|
|
@@ -63356,6 +63356,9 @@ async function invalidateAuth() {
|
|
|
63356
63356
|
cachedOctokit = null;
|
|
63357
63357
|
logger.debug("Invalidated cached authentication due to 401 error");
|
|
63358
63358
|
}
|
|
63359
|
+
function resetClient() {
|
|
63360
|
+
cachedOctokit = null;
|
|
63361
|
+
}
|
|
63359
63362
|
var cachedOctokit = null;
|
|
63360
63363
|
var init_auth_api = __esm(() => {
|
|
63361
63364
|
init_claudekit_constants();
|
|
@@ -64268,6 +64271,16 @@ var init_asset_utils = __esm(() => {
|
|
|
64268
64271
|
});
|
|
64269
64272
|
|
|
64270
64273
|
// src/domains/github/client/index.ts
|
|
64274
|
+
var exports_client = {};
|
|
64275
|
+
__export(exports_client, {
|
|
64276
|
+
resetClient: () => resetClient,
|
|
64277
|
+
invalidateAuth: () => invalidateAuth,
|
|
64278
|
+
handleHttpError: () => handleHttpError,
|
|
64279
|
+
getDownloadableAsset: () => getDownloadableAsset,
|
|
64280
|
+
getAuthenticatedClient: () => getAuthenticatedClient,
|
|
64281
|
+
RepoApi: () => RepoApi,
|
|
64282
|
+
ReleasesApi: () => ReleasesApi
|
|
64283
|
+
});
|
|
64271
64284
|
var init_client = __esm(() => {
|
|
64272
64285
|
init_auth_api();
|
|
64273
64286
|
init_error_handler2();
|
|
@@ -73512,7 +73525,7 @@ async function restoreOriginalBranch(branchName, cwd2, issueNumber) {
|
|
|
73512
73525
|
}
|
|
73513
73526
|
}
|
|
73514
73527
|
function spawnAndCollect(command, args, cwd2) {
|
|
73515
|
-
return new Promise((
|
|
73528
|
+
return new Promise((resolve44, reject) => {
|
|
73516
73529
|
const child = spawn6(command, args, { ...cwd2 && { cwd: cwd2 }, stdio: ["ignore", "pipe", "pipe"] });
|
|
73517
73530
|
const chunks = [];
|
|
73518
73531
|
const stderrChunks = [];
|
|
@@ -73525,7 +73538,7 @@ function spawnAndCollect(command, args, cwd2) {
|
|
|
73525
73538
|
reject(new Error(`${command} ${args[0] ?? ""} exited with code ${code2}: ${stderr}`));
|
|
73526
73539
|
return;
|
|
73527
73540
|
}
|
|
73528
|
-
|
|
73541
|
+
resolve44(Buffer.concat(chunks).toString("utf-8"));
|
|
73529
73542
|
});
|
|
73530
73543
|
});
|
|
73531
73544
|
}
|
|
@@ -73543,10 +73556,10 @@ __export(exports_worktree_manager, {
|
|
|
73543
73556
|
cleanupAllWorktrees: () => cleanupAllWorktrees
|
|
73544
73557
|
});
|
|
73545
73558
|
import { existsSync as existsSync69 } from "node:fs";
|
|
73546
|
-
import { readFile as
|
|
73547
|
-
import { join as
|
|
73559
|
+
import { readFile as readFile65, writeFile as writeFile37 } from "node:fs/promises";
|
|
73560
|
+
import { join as join153 } from "node:path";
|
|
73548
73561
|
async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
73549
|
-
const worktreePath =
|
|
73562
|
+
const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
73550
73563
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
73551
73564
|
await spawnAndCollect("git", ["fetch", "origin", baseBranch], projectDir).catch(() => {
|
|
73552
73565
|
logger.warning(`[worktree] Could not fetch origin/${baseBranch}, using local`);
|
|
@@ -73564,7 +73577,7 @@ async function createWorktree(projectDir, issueNumber, baseBranch) {
|
|
|
73564
73577
|
return worktreePath;
|
|
73565
73578
|
}
|
|
73566
73579
|
async function removeWorktree(projectDir, issueNumber) {
|
|
73567
|
-
const worktreePath =
|
|
73580
|
+
const worktreePath = join153(projectDir, WORKTREE_DIR, `issue-${issueNumber}`);
|
|
73568
73581
|
const branchName = `ck-watch/issue-${issueNumber}`;
|
|
73569
73582
|
try {
|
|
73570
73583
|
await spawnAndCollect("git", ["worktree", "remove", worktreePath, "--force"], projectDir);
|
|
@@ -73578,7 +73591,7 @@ async function listActiveWorktrees(projectDir) {
|
|
|
73578
73591
|
try {
|
|
73579
73592
|
const output2 = await spawnAndCollect("git", ["worktree", "list", "--porcelain"], projectDir);
|
|
73580
73593
|
const issueNumbers = [];
|
|
73581
|
-
const worktreePrefix =
|
|
73594
|
+
const worktreePrefix = join153(projectDir, WORKTREE_DIR, "issue-").replace(/\\/g, "/");
|
|
73582
73595
|
for (const line of output2.split(`
|
|
73583
73596
|
`)) {
|
|
73584
73597
|
if (line.startsWith("worktree ")) {
|
|
@@ -73606,16 +73619,16 @@ async function cleanupAllWorktrees(projectDir) {
|
|
|
73606
73619
|
await spawnAndCollect("git", ["worktree", "prune"], projectDir).catch(() => {});
|
|
73607
73620
|
}
|
|
73608
73621
|
async function ensureGitignore(projectDir) {
|
|
73609
|
-
const gitignorePath =
|
|
73622
|
+
const gitignorePath = join153(projectDir, ".gitignore");
|
|
73610
73623
|
try {
|
|
73611
|
-
const content = existsSync69(gitignorePath) ? await
|
|
73624
|
+
const content = existsSync69(gitignorePath) ? await readFile65(gitignorePath, "utf-8") : "";
|
|
73612
73625
|
if (!content.includes(".worktrees")) {
|
|
73613
73626
|
const newContent = content.endsWith(`
|
|
73614
73627
|
`) ? `${content}.worktrees/
|
|
73615
73628
|
` : `${content}
|
|
73616
73629
|
.worktrees/
|
|
73617
73630
|
`;
|
|
73618
|
-
await
|
|
73631
|
+
await writeFile37(gitignorePath, newContent, "utf-8");
|
|
73619
73632
|
logger.info("[worktree] Added .worktrees/ to .gitignore");
|
|
73620
73633
|
}
|
|
73621
73634
|
} catch (err) {
|
|
@@ -73644,15 +73657,15 @@ function countTwitterChars(text) {
|
|
|
73644
73657
|
}
|
|
73645
73658
|
return count;
|
|
73646
73659
|
}
|
|
73647
|
-
function validateContent(content,
|
|
73660
|
+
function validateContent(content, platform18) {
|
|
73648
73661
|
const issues = [];
|
|
73649
73662
|
if (!content.text || content.text.trim().length === 0) {
|
|
73650
73663
|
issues.push("Content text is empty");
|
|
73651
73664
|
return { valid: false, issues };
|
|
73652
73665
|
}
|
|
73653
|
-
if (
|
|
73654
|
-
const limit =
|
|
73655
|
-
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;
|
|
73656
73669
|
if (charCount > limit) {
|
|
73657
73670
|
issues.push(`Text exceeds ${limit} char limit (${charCount} weighted chars)`);
|
|
73658
73671
|
}
|
|
@@ -73675,7 +73688,7 @@ function validateContent(content, platform17) {
|
|
|
73675
73688
|
issues.push("Hook (first sentence) is too long (>25 words)");
|
|
73676
73689
|
}
|
|
73677
73690
|
const hashtagCount = content.hashtags?.length ?? 0;
|
|
73678
|
-
if (
|
|
73691
|
+
if (platform18 === "x" && hashtagCount > 5) {
|
|
73679
73692
|
issues.push("Too many hashtags for X (max 5)");
|
|
73680
73693
|
}
|
|
73681
73694
|
return { valid: issues.length === 0, issues };
|
|
@@ -73711,9 +73724,9 @@ var init_content_validator = __esm(() => {
|
|
|
73711
73724
|
// src/commands/content/phases/context-cache-manager.ts
|
|
73712
73725
|
import { createHash as createHash9 } from "node:crypto";
|
|
73713
73726
|
import { existsSync as existsSync75, mkdirSync as mkdirSync5, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync14 } from "node:fs";
|
|
73714
|
-
import { rename as
|
|
73715
|
-
import { homedir as
|
|
73716
|
-
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";
|
|
73717
73730
|
function getCachedContext(repoPath) {
|
|
73718
73731
|
const cachePath = getCacheFilePath(repoPath);
|
|
73719
73732
|
if (!existsSync75(cachePath))
|
|
@@ -73722,7 +73735,7 @@ function getCachedContext(repoPath) {
|
|
|
73722
73735
|
const raw2 = readFileSync18(cachePath, "utf-8");
|
|
73723
73736
|
const cache5 = JSON.parse(raw2);
|
|
73724
73737
|
const age = Date.now() - new Date(cache5.createdAt).getTime();
|
|
73725
|
-
if (age >=
|
|
73738
|
+
if (age >= CACHE_TTL_MS5)
|
|
73726
73739
|
return null;
|
|
73727
73740
|
const currentHash = computeSourceHash(repoPath);
|
|
73728
73741
|
if (currentHash !== cache5.sourceHash)
|
|
@@ -73738,8 +73751,8 @@ async function saveCachedContext(repoPath, cache5) {
|
|
|
73738
73751
|
}
|
|
73739
73752
|
const cachePath = getCacheFilePath(repoPath);
|
|
73740
73753
|
const tmpPath = `${cachePath}.tmp`;
|
|
73741
|
-
await
|
|
73742
|
-
await
|
|
73754
|
+
await writeFile39(tmpPath, JSON.stringify(cache5, null, 2), "utf-8");
|
|
73755
|
+
await rename15(tmpPath, cachePath);
|
|
73743
73756
|
}
|
|
73744
73757
|
function computeSourceHash(repoPath) {
|
|
73745
73758
|
const hash = createHash9("sha256");
|
|
@@ -73756,25 +73769,25 @@ function computeSourceHash(repoPath) {
|
|
|
73756
73769
|
}
|
|
73757
73770
|
function getDocSourcePaths(repoPath) {
|
|
73758
73771
|
const paths = [];
|
|
73759
|
-
const docsDir =
|
|
73772
|
+
const docsDir = join160(repoPath, "docs");
|
|
73760
73773
|
if (existsSync75(docsDir)) {
|
|
73761
73774
|
try {
|
|
73762
73775
|
const files = readdirSync11(docsDir);
|
|
73763
73776
|
for (const f3 of files) {
|
|
73764
73777
|
if (f3.endsWith(".md"))
|
|
73765
|
-
paths.push(
|
|
73778
|
+
paths.push(join160(docsDir, f3));
|
|
73766
73779
|
}
|
|
73767
73780
|
} catch {}
|
|
73768
73781
|
}
|
|
73769
|
-
const readme =
|
|
73782
|
+
const readme = join160(repoPath, "README.md");
|
|
73770
73783
|
if (existsSync75(readme))
|
|
73771
73784
|
paths.push(readme);
|
|
73772
|
-
const stylesDir =
|
|
73785
|
+
const stylesDir = join160(repoPath, "assets", "writing-styles");
|
|
73773
73786
|
if (existsSync75(stylesDir)) {
|
|
73774
73787
|
try {
|
|
73775
73788
|
const files = readdirSync11(stylesDir);
|
|
73776
73789
|
for (const f3 of files) {
|
|
73777
|
-
paths.push(
|
|
73790
|
+
paths.push(join160(stylesDir, f3));
|
|
73778
73791
|
}
|
|
73779
73792
|
} catch {}
|
|
73780
73793
|
}
|
|
@@ -73783,12 +73796,12 @@ function getDocSourcePaths(repoPath) {
|
|
|
73783
73796
|
function getCacheFilePath(repoPath) {
|
|
73784
73797
|
const repoName = basename31(repoPath).replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
73785
73798
|
const pathHash = createHash9("sha256").update(repoPath).digest("hex").slice(0, 8);
|
|
73786
|
-
return
|
|
73799
|
+
return join160(CACHE_DIR, `${repoName}-${pathHash}-context-cache.json`);
|
|
73787
73800
|
}
|
|
73788
|
-
var CACHE_DIR,
|
|
73801
|
+
var CACHE_DIR, CACHE_TTL_MS5;
|
|
73789
73802
|
var init_context_cache_manager = __esm(() => {
|
|
73790
|
-
CACHE_DIR =
|
|
73791
|
-
|
|
73803
|
+
CACHE_DIR = join160(homedir54(), ".claudekit", "cache");
|
|
73804
|
+
CACHE_TTL_MS5 = 24 * 60 * 60 * 1000;
|
|
73792
73805
|
});
|
|
73793
73806
|
|
|
73794
73807
|
// src/commands/content/phases/db-queries-git-events.ts
|
|
@@ -73968,7 +73981,7 @@ function extractContentFromResponse(response) {
|
|
|
73968
73981
|
// src/commands/content/phases/docs-summarizer.ts
|
|
73969
73982
|
import { execSync as execSync7 } from "node:child_process";
|
|
73970
73983
|
import { existsSync as existsSync76, readFileSync as readFileSync19, readdirSync as readdirSync12 } from "node:fs";
|
|
73971
|
-
import { join as
|
|
73984
|
+
import { join as join161 } from "node:path";
|
|
73972
73985
|
async function summarizeProjectDocs(repoPath, contentLogger) {
|
|
73973
73986
|
const rawContent = collectRawDocs(repoPath);
|
|
73974
73987
|
if (rawContent.total.length < 200) {
|
|
@@ -74022,12 +74035,12 @@ function collectRawDocs(repoPath) {
|
|
|
74022
74035
|
return capped;
|
|
74023
74036
|
};
|
|
74024
74037
|
const docsContent = [];
|
|
74025
|
-
const docsDir =
|
|
74038
|
+
const docsDir = join161(repoPath, "docs");
|
|
74026
74039
|
if (existsSync76(docsDir)) {
|
|
74027
74040
|
try {
|
|
74028
74041
|
const files = readdirSync12(docsDir).filter((f3) => f3.endsWith(".md")).sort();
|
|
74029
74042
|
for (const f3 of files) {
|
|
74030
|
-
const content = readCapped(
|
|
74043
|
+
const content = readCapped(join161(docsDir, f3), 5000);
|
|
74031
74044
|
if (content) {
|
|
74032
74045
|
docsContent.push(`### ${f3}
|
|
74033
74046
|
${content}`);
|
|
@@ -74041,21 +74054,21 @@ ${content}`);
|
|
|
74041
74054
|
let brand = "";
|
|
74042
74055
|
const brandCandidates = ["docs/brand-guidelines.md", "docs/design-guidelines.md"];
|
|
74043
74056
|
for (const p of brandCandidates) {
|
|
74044
|
-
brand = readCapped(
|
|
74057
|
+
brand = readCapped(join161(repoPath, p), 3000);
|
|
74045
74058
|
if (brand)
|
|
74046
74059
|
break;
|
|
74047
74060
|
}
|
|
74048
74061
|
let styles3 = "";
|
|
74049
|
-
const stylesDir =
|
|
74062
|
+
const stylesDir = join161(repoPath, "assets", "writing-styles");
|
|
74050
74063
|
if (existsSync76(stylesDir)) {
|
|
74051
74064
|
try {
|
|
74052
74065
|
const files = readdirSync12(stylesDir).slice(0, 3);
|
|
74053
|
-
styles3 = files.map((f3) => readCapped(
|
|
74066
|
+
styles3 = files.map((f3) => readCapped(join161(stylesDir, f3), 1000)).filter(Boolean).join(`
|
|
74054
74067
|
|
|
74055
74068
|
`);
|
|
74056
74069
|
} catch {}
|
|
74057
74070
|
}
|
|
74058
|
-
const readme = readCapped(
|
|
74071
|
+
const readme = readCapped(join161(repoPath, "README.md"), 3000);
|
|
74059
74072
|
const total = [docs, brand, styles3, readme].join(`
|
|
74060
74073
|
`);
|
|
74061
74074
|
return { docs, brand, styles: styles3, readme, total };
|
|
@@ -74089,10 +74102,10 @@ var MAX_RAW_CONTENT_CHARS = 50000;
|
|
|
74089
74102
|
var init_docs_summarizer = () => {};
|
|
74090
74103
|
|
|
74091
74104
|
// src/commands/content/phases/context-builder.ts
|
|
74092
|
-
async function buildContentContext(event, repoPath, config, db,
|
|
74105
|
+
async function buildContentContext(event, repoPath, config, db, platform18, contentLogger) {
|
|
74093
74106
|
const cached = getCachedContext(repoPath);
|
|
74094
74107
|
if (cached) {
|
|
74095
|
-
return buildFromCache(cached, event, db,
|
|
74108
|
+
return buildFromCache(cached, event, db, platform18, config);
|
|
74096
74109
|
}
|
|
74097
74110
|
const noopLogger = { debug: () => {}, info: () => {}, warn: () => {}, error: () => {} };
|
|
74098
74111
|
const log2 = contentLogger ?? noopLogger;
|
|
@@ -74107,16 +74120,16 @@ async function buildContentContext(event, repoPath, config, db, platform17, cont
|
|
|
74107
74120
|
sourceHash: hash
|
|
74108
74121
|
};
|
|
74109
74122
|
await saveCachedContext(repoPath, newCache);
|
|
74110
|
-
return buildFromCache(newCache, event, db,
|
|
74123
|
+
return buildFromCache(newCache, event, db, platform18, config);
|
|
74111
74124
|
}
|
|
74112
|
-
function buildFromCache(cache5, event, db,
|
|
74125
|
+
function buildFromCache(cache5, event, db, platform18, config) {
|
|
74113
74126
|
return {
|
|
74114
74127
|
brandGuidelines: cache5.brandSummary,
|
|
74115
74128
|
writingStyles: cache5.stylesSummary,
|
|
74116
74129
|
gitEventDetails: formatGitEvent(event),
|
|
74117
74130
|
recentContent: formatRecentContent(db),
|
|
74118
74131
|
topPerformingContent: "",
|
|
74119
|
-
platformRules: getPlatformRules(
|
|
74132
|
+
platformRules: getPlatformRules(platform18, config),
|
|
74120
74133
|
projectReadme: cache5.readmeSummary,
|
|
74121
74134
|
projectDocsSummary: cache5.docsSummary,
|
|
74122
74135
|
currentDateTime: new Date().toISOString()
|
|
@@ -74145,8 +74158,8 @@ function formatRecentContent(db) {
|
|
|
74145
74158
|
return recent.map((c2) => `[${c2.platform}] ${c2.textContent.slice(0, 100)}`).join(`
|
|
74146
74159
|
`);
|
|
74147
74160
|
}
|
|
74148
|
-
function getPlatformRules(
|
|
74149
|
-
switch (
|
|
74161
|
+
function getPlatformRules(platform18, config) {
|
|
74162
|
+
switch (platform18) {
|
|
74150
74163
|
case "x":
|
|
74151
74164
|
return [
|
|
74152
74165
|
"Platform: X (Twitter)",
|
|
@@ -74185,8 +74198,8 @@ var init_context_builder = __esm(() => {
|
|
|
74185
74198
|
});
|
|
74186
74199
|
|
|
74187
74200
|
// src/commands/content/phases/prompt-templates.ts
|
|
74188
|
-
function buildTextPrompt(context,
|
|
74189
|
-
const charLimit =
|
|
74201
|
+
function buildTextPrompt(context, platform18) {
|
|
74202
|
+
const charLimit = platform18 === "x" || platform18 === "x_thread" ? 280 : 500;
|
|
74190
74203
|
return `You are a social media content creator.
|
|
74191
74204
|
|
|
74192
74205
|
## Project Context
|
|
@@ -74201,14 +74214,14 @@ ${context.writingStyles}
|
|
|
74201
74214
|
## Content Source
|
|
74202
74215
|
${context.gitEventDetails}
|
|
74203
74216
|
|
|
74204
|
-
## Platform: ${
|
|
74217
|
+
## Platform: ${platform18}
|
|
74205
74218
|
${context.platformRules}
|
|
74206
74219
|
|
|
74207
74220
|
## Past Content (avoid repetition)
|
|
74208
74221
|
${context.recentContent}
|
|
74209
74222
|
|
|
74210
74223
|
## Instructions
|
|
74211
|
-
1. Create a ${
|
|
74224
|
+
1. Create a ${platform18} post about this development update
|
|
74212
74225
|
2. Start with a compelling hook that creates curiosity
|
|
74213
74226
|
3. Keep it conversational and authentic (avoid AI-sounding language)
|
|
74214
74227
|
4. No generic statements — be specific about what changed and why it matters
|
|
@@ -74218,8 +74231,8 @@ ${context.recentContent}
|
|
|
74218
74231
|
|
|
74219
74232
|
IMPORTANT: Output ONLY the JSON object, nothing else.`;
|
|
74220
74233
|
}
|
|
74221
|
-
function buildPhotoPrompt(context,
|
|
74222
|
-
const dimensions =
|
|
74234
|
+
function buildPhotoPrompt(context, platform18) {
|
|
74235
|
+
const dimensions = platform18 === "facebook" ? "1200x630" : "1200x675";
|
|
74223
74236
|
return `Generate an image for this social media post.
|
|
74224
74237
|
|
|
74225
74238
|
## Brand Guidelines
|
|
@@ -74241,15 +74254,15 @@ IMPORTANT: Generate the image and output the path as JSON: {"imagePath": "/path/
|
|
|
74241
74254
|
// src/commands/content/phases/photo-generator.ts
|
|
74242
74255
|
import { execSync as execSync8 } from "node:child_process";
|
|
74243
74256
|
import { existsSync as existsSync77, mkdirSync as mkdirSync6, readdirSync as readdirSync13 } from "node:fs";
|
|
74244
|
-
import { homedir as
|
|
74245
|
-
import { join as
|
|
74246
|
-
async function generatePhoto(_content, context, config,
|
|
74247
|
-
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));
|
|
74248
74261
|
if (!existsSync77(mediaDir)) {
|
|
74249
74262
|
mkdirSync6(mediaDir, { recursive: true });
|
|
74250
74263
|
}
|
|
74251
|
-
const prompt = buildPhotoPrompt(context,
|
|
74252
|
-
const dimensions =
|
|
74264
|
+
const prompt = buildPhotoPrompt(context, platform18);
|
|
74265
|
+
const dimensions = platform18 === "facebook" ? { width: 1200, height: 630 } : { width: 1200, height: 675 };
|
|
74253
74266
|
try {
|
|
74254
74267
|
contentLogger.debug(`Generating photo for content ${contentId}...`);
|
|
74255
74268
|
const result = execSync8("claude -p --output-format text --max-turns 40", {
|
|
@@ -74269,7 +74282,7 @@ async function generatePhoto(_content, context, config, platform17, contentId, c
|
|
|
74269
74282
|
const imageFile = files.find((f3) => /\.(png|jpg|jpeg|webp)$/i.test(f3));
|
|
74270
74283
|
if (imageFile) {
|
|
74271
74284
|
const ext2 = imageFile.split(".").pop() ?? "png";
|
|
74272
|
-
return { path:
|
|
74285
|
+
return { path: join162(mediaDir, imageFile), ...dimensions, format: ext2 };
|
|
74273
74286
|
}
|
|
74274
74287
|
contentLogger.warn(`Photo generation produced no image for content ${contentId}`);
|
|
74275
74288
|
return null;
|
|
@@ -74287,14 +74300,14 @@ async function createContent(event, config, db, contentLogger, options2) {
|
|
|
74287
74300
|
const startTime = Date.now();
|
|
74288
74301
|
const items = [];
|
|
74289
74302
|
const platforms = resolveEnabledPlatforms(config);
|
|
74290
|
-
for (const
|
|
74303
|
+
for (const platform18 of platforms) {
|
|
74291
74304
|
try {
|
|
74292
|
-
const item = await createContentForPlatform(event,
|
|
74305
|
+
const item = await createContentForPlatform(event, platform18, config, db, contentLogger, options2);
|
|
74293
74306
|
if (item)
|
|
74294
74307
|
items.push(item);
|
|
74295
74308
|
} catch (err) {
|
|
74296
74309
|
const msg = err instanceof Error ? err.message : String(err);
|
|
74297
|
-
contentLogger.error(`Failed to create ${
|
|
74310
|
+
contentLogger.error(`Failed to create ${platform18} content: ${msg}`);
|
|
74298
74311
|
}
|
|
74299
74312
|
}
|
|
74300
74313
|
insertTaskLog(db, {
|
|
@@ -74313,10 +74326,10 @@ function resolveEnabledPlatforms(config) {
|
|
|
74313
74326
|
platforms.push("facebook");
|
|
74314
74327
|
return platforms;
|
|
74315
74328
|
}
|
|
74316
|
-
async function createContentForPlatform(event,
|
|
74317
|
-
const context = await buildContentContext(event, event.repoPath, config, db,
|
|
74318
|
-
const prompt = buildTextPrompt(context,
|
|
74319
|
-
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}...`);
|
|
74320
74333
|
const stdout2 = execSync9("claude -p --output-format text --max-turns 5", {
|
|
74321
74334
|
input: prompt,
|
|
74322
74335
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -74324,14 +74337,14 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
|
|
|
74324
74337
|
}).toString();
|
|
74325
74338
|
const parsed = parseClaudeJsonOutput(stdout2);
|
|
74326
74339
|
const generated = extractContentFromResponse(parsed);
|
|
74327
|
-
const validation = validateContent(generated,
|
|
74340
|
+
const validation = validateContent(generated, platform18);
|
|
74328
74341
|
if (!validation.valid) {
|
|
74329
|
-
contentLogger.warn(`Content validation failed for ${
|
|
74342
|
+
contentLogger.warn(`Content validation failed for ${platform18}: ${validation.issues.join(", ")}`);
|
|
74330
74343
|
}
|
|
74331
74344
|
const status = validation.valid ? config.reviewMode === "auto" ? "scheduled" : "reviewing" : "draft";
|
|
74332
74345
|
const itemId = insertContentItem(db, {
|
|
74333
74346
|
gitEventId: event.id,
|
|
74334
|
-
platform:
|
|
74347
|
+
platform: platform18,
|
|
74335
74348
|
textContent: generated.text,
|
|
74336
74349
|
hashtags: JSON.stringify(generated.hashtags),
|
|
74337
74350
|
hookLine: generated.hook,
|
|
@@ -74341,12 +74354,12 @@ async function createContentForPlatform(event, platform17, config, db, contentLo
|
|
|
74341
74354
|
scheduledAt: null
|
|
74342
74355
|
});
|
|
74343
74356
|
if (!options2.dryRun && generated.mediaPrompt) {
|
|
74344
|
-
const photo = await generatePhoto(generated, context, config,
|
|
74357
|
+
const photo = await generatePhoto(generated, context, config, platform18, itemId, contentLogger);
|
|
74345
74358
|
if (photo) {
|
|
74346
74359
|
db.prepare("UPDATE content_items SET media_path = ? WHERE id = ?").run(photo.path, itemId);
|
|
74347
74360
|
}
|
|
74348
74361
|
}
|
|
74349
|
-
contentLogger.info(`Created ${
|
|
74362
|
+
contentLogger.info(`Created ${platform18} content (id: ${itemId}, status: ${status})`);
|
|
74350
74363
|
return getContentById(db, itemId);
|
|
74351
74364
|
}
|
|
74352
74365
|
var init_content_creator = __esm(() => {
|
|
@@ -74358,8 +74371,8 @@ var init_content_creator = __esm(() => {
|
|
|
74358
74371
|
|
|
74359
74372
|
// src/commands/content/phases/content-logger.ts
|
|
74360
74373
|
import { createWriteStream as createWriteStream4, existsSync as existsSync78, mkdirSync as mkdirSync7, statSync as statSync15 } from "node:fs";
|
|
74361
|
-
import { homedir as
|
|
74362
|
-
import { join as
|
|
74374
|
+
import { homedir as homedir56 } from "node:os";
|
|
74375
|
+
import { join as join163 } from "node:path";
|
|
74363
74376
|
|
|
74364
74377
|
class ContentLogger {
|
|
74365
74378
|
stream = null;
|
|
@@ -74367,7 +74380,7 @@ class ContentLogger {
|
|
|
74367
74380
|
logDir;
|
|
74368
74381
|
maxBytes;
|
|
74369
74382
|
constructor(maxBytes = 0) {
|
|
74370
|
-
this.logDir =
|
|
74383
|
+
this.logDir = join163(homedir56(), ".claudekit", "logs");
|
|
74371
74384
|
this.maxBytes = maxBytes;
|
|
74372
74385
|
}
|
|
74373
74386
|
init() {
|
|
@@ -74399,7 +74412,7 @@ class ContentLogger {
|
|
|
74399
74412
|
}
|
|
74400
74413
|
}
|
|
74401
74414
|
getLogPath() {
|
|
74402
|
-
return
|
|
74415
|
+
return join163(this.logDir, `content-${this.getDateStr()}.log`);
|
|
74403
74416
|
}
|
|
74404
74417
|
write(level, message) {
|
|
74405
74418
|
this.rotateIfNeeded();
|
|
@@ -74416,19 +74429,19 @@ class ContentLogger {
|
|
|
74416
74429
|
if (dateStr !== this.currentDate) {
|
|
74417
74430
|
this.close();
|
|
74418
74431
|
this.currentDate = dateStr;
|
|
74419
|
-
const logPath =
|
|
74432
|
+
const logPath = join163(this.logDir, `content-${dateStr}.log`);
|
|
74420
74433
|
this.stream = createWriteStream4(logPath, { flags: "a", mode: 384 });
|
|
74421
74434
|
return;
|
|
74422
74435
|
}
|
|
74423
74436
|
if (this.maxBytes > 0 && this.stream) {
|
|
74424
|
-
const logPath =
|
|
74437
|
+
const logPath = join163(this.logDir, `content-${this.currentDate}.log`);
|
|
74425
74438
|
try {
|
|
74426
74439
|
const stat26 = statSync15(logPath);
|
|
74427
74440
|
if (stat26.size >= this.maxBytes) {
|
|
74428
74441
|
this.close();
|
|
74429
74442
|
const suffix = Date.now();
|
|
74430
|
-
const rotatedPath =
|
|
74431
|
-
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(() => {}));
|
|
74432
74445
|
this.stream = createWriteStream4(logPath, { flags: "w", mode: 384 });
|
|
74433
74446
|
}
|
|
74434
74447
|
} catch {}
|
|
@@ -74653,7 +74666,7 @@ function isNoiseCommit(title, author) {
|
|
|
74653
74666
|
// src/commands/content/phases/change-detector.ts
|
|
74654
74667
|
import { execSync as execSync10, spawnSync as spawnSync9 } from "node:child_process";
|
|
74655
74668
|
import { existsSync as existsSync80, readFileSync as readFileSync20, readdirSync as readdirSync14, statSync as statSync16 } from "node:fs";
|
|
74656
|
-
import { join as
|
|
74669
|
+
import { join as join164 } from "node:path";
|
|
74657
74670
|
function detectCommits(repo, since) {
|
|
74658
74671
|
try {
|
|
74659
74672
|
const fetchUrl = sshToHttps(repo.remoteUrl);
|
|
@@ -74762,7 +74775,7 @@ function detectTags(repo, since) {
|
|
|
74762
74775
|
}
|
|
74763
74776
|
}
|
|
74764
74777
|
function detectCompletedPlans(repo, since) {
|
|
74765
|
-
const plansDir =
|
|
74778
|
+
const plansDir = join164(repo.path, "plans");
|
|
74766
74779
|
if (!existsSync80(plansDir))
|
|
74767
74780
|
return [];
|
|
74768
74781
|
const sinceMs = new Date(since).getTime();
|
|
@@ -74772,7 +74785,7 @@ function detectCompletedPlans(repo, since) {
|
|
|
74772
74785
|
for (const entry of entries) {
|
|
74773
74786
|
if (!entry.isDirectory())
|
|
74774
74787
|
continue;
|
|
74775
|
-
const planFile =
|
|
74788
|
+
const planFile = join164(plansDir, entry.name, "plan.md");
|
|
74776
74789
|
if (!existsSync80(planFile))
|
|
74777
74790
|
continue;
|
|
74778
74791
|
try {
|
|
@@ -74850,7 +74863,7 @@ function classifyCommit(event) {
|
|
|
74850
74863
|
// src/commands/content/phases/repo-discoverer.ts
|
|
74851
74864
|
import { execSync as execSync11 } from "node:child_process";
|
|
74852
74865
|
import { readdirSync as readdirSync15 } from "node:fs";
|
|
74853
|
-
import { join as
|
|
74866
|
+
import { join as join165 } from "node:path";
|
|
74854
74867
|
function discoverRepos2(cwd2) {
|
|
74855
74868
|
const repos = [];
|
|
74856
74869
|
if (isGitRepoRoot(cwd2)) {
|
|
@@ -74863,7 +74876,7 @@ function discoverRepos2(cwd2) {
|
|
|
74863
74876
|
for (const entry of entries) {
|
|
74864
74877
|
if (!entry.isDirectory() || entry.name.startsWith("."))
|
|
74865
74878
|
continue;
|
|
74866
|
-
const dirPath =
|
|
74879
|
+
const dirPath = join165(cwd2, entry.name);
|
|
74867
74880
|
if (isGitRepoRoot(dirPath)) {
|
|
74868
74881
|
const info = getRepoInfo(dirPath);
|
|
74869
74882
|
if (info)
|
|
@@ -75233,15 +75246,15 @@ class RateLimiter {
|
|
|
75233
75246
|
this.state = state;
|
|
75234
75247
|
this.config = config;
|
|
75235
75248
|
}
|
|
75236
|
-
canPost(
|
|
75237
|
-
return this.getTodayCount(
|
|
75249
|
+
canPost(platform18) {
|
|
75250
|
+
return this.getTodayCount(platform18) < this.getMaxPerDay(platform18);
|
|
75238
75251
|
}
|
|
75239
|
-
recordPost(
|
|
75240
|
-
const key = this.dailyKey(
|
|
75252
|
+
recordPost(platform18) {
|
|
75253
|
+
const key = this.dailyKey(platform18);
|
|
75241
75254
|
this.state.dailyPostCounts[key] = (this.state.dailyPostCounts[key] ?? 0) + 1;
|
|
75242
75255
|
}
|
|
75243
|
-
getRemainingToday(
|
|
75244
|
-
return Math.max(0, this.getMaxPerDay(
|
|
75256
|
+
getRemainingToday(platform18) {
|
|
75257
|
+
return Math.max(0, this.getMaxPerDay(platform18) - this.getTodayCount(platform18));
|
|
75245
75258
|
}
|
|
75246
75259
|
isInQuietHours() {
|
|
75247
75260
|
const { timezone, quietHoursStart, quietHoursEnd } = this.config.schedule;
|
|
@@ -75261,19 +75274,19 @@ class RateLimiter {
|
|
|
75261
75274
|
return false;
|
|
75262
75275
|
}
|
|
75263
75276
|
}
|
|
75264
|
-
getMaxPerDay(
|
|
75265
|
-
if (
|
|
75277
|
+
getMaxPerDay(platform18) {
|
|
75278
|
+
if (platform18 === "x" || platform18 === "x_thread") {
|
|
75266
75279
|
return this.config.platforms.x.maxPostsPerDay;
|
|
75267
75280
|
}
|
|
75268
|
-
if (
|
|
75281
|
+
if (platform18 === "facebook") {
|
|
75269
75282
|
return this.config.platforms.facebook.maxPostsPerDay;
|
|
75270
75283
|
}
|
|
75271
75284
|
return this.config.maxContentPerDay;
|
|
75272
75285
|
}
|
|
75273
|
-
getTodayCount(
|
|
75274
|
-
return this.state.dailyPostCounts[this.dailyKey(
|
|
75286
|
+
getTodayCount(platform18) {
|
|
75287
|
+
return this.state.dailyPostCounts[this.dailyKey(platform18)] ?? 0;
|
|
75275
75288
|
}
|
|
75276
|
-
dailyKey(
|
|
75289
|
+
dailyKey(platform18) {
|
|
75277
75290
|
const { timezone } = this.config.schedule;
|
|
75278
75291
|
let dateStr;
|
|
75279
75292
|
try {
|
|
@@ -75287,7 +75300,7 @@ class RateLimiter {
|
|
|
75287
75300
|
} catch {
|
|
75288
75301
|
dateStr = new Date().toISOString().slice(0, 10);
|
|
75289
75302
|
}
|
|
75290
|
-
return `${
|
|
75303
|
+
return `${platform18}-${dateStr}`;
|
|
75291
75304
|
}
|
|
75292
75305
|
}
|
|
75293
75306
|
|
|
@@ -75404,8 +75417,8 @@ function previewContent(content) {
|
|
|
75404
75417
|
console.log(import_picocolors42.default.dim("─".repeat(60)));
|
|
75405
75418
|
console.log();
|
|
75406
75419
|
}
|
|
75407
|
-
function getPlatformBadge(
|
|
75408
|
-
switch (
|
|
75420
|
+
function getPlatformBadge(platform18) {
|
|
75421
|
+
switch (platform18) {
|
|
75409
75422
|
case "x":
|
|
75410
75423
|
return import_picocolors42.default.bgBlue(import_picocolors42.default.white(" X "));
|
|
75411
75424
|
case "x_thread":
|
|
@@ -75413,7 +75426,7 @@ function getPlatformBadge(platform17) {
|
|
|
75413
75426
|
case "facebook":
|
|
75414
75427
|
return import_picocolors42.default.bgCyan(import_picocolors42.default.white(" Facebook "));
|
|
75415
75428
|
default:
|
|
75416
|
-
return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${
|
|
75429
|
+
return import_picocolors42.default.bgBlack(import_picocolors42.default.white(` ${platform18} `));
|
|
75417
75430
|
}
|
|
75418
75431
|
}
|
|
75419
75432
|
function getStatusColor(status) {
|
|
@@ -75530,12 +75543,12 @@ var init_types6 = __esm(() => {
|
|
|
75530
75543
|
});
|
|
75531
75544
|
|
|
75532
75545
|
// src/commands/content/phases/state-manager.ts
|
|
75533
|
-
import { readFile as
|
|
75534
|
-
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";
|
|
75535
75548
|
async function loadContentConfig(projectDir) {
|
|
75536
|
-
const configPath =
|
|
75549
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75537
75550
|
try {
|
|
75538
|
-
const raw2 = await
|
|
75551
|
+
const raw2 = await readFile67(configPath, "utf-8");
|
|
75539
75552
|
const json = JSON.parse(raw2);
|
|
75540
75553
|
return ContentConfigSchema.parse(json.content ?? {});
|
|
75541
75554
|
} catch {
|
|
@@ -75543,15 +75556,15 @@ async function loadContentConfig(projectDir) {
|
|
|
75543
75556
|
}
|
|
75544
75557
|
}
|
|
75545
75558
|
async function saveContentConfig(projectDir, config) {
|
|
75546
|
-
const configPath =
|
|
75559
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75547
75560
|
const json = await readJsonSafe(configPath);
|
|
75548
75561
|
json.content = { ...json.content, ...config };
|
|
75549
75562
|
await atomicWrite2(configPath, json);
|
|
75550
75563
|
}
|
|
75551
75564
|
async function loadContentState(projectDir) {
|
|
75552
|
-
const configPath =
|
|
75565
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75553
75566
|
try {
|
|
75554
|
-
const raw2 = await
|
|
75567
|
+
const raw2 = await readFile67(configPath, "utf-8");
|
|
75555
75568
|
const json = JSON.parse(raw2);
|
|
75556
75569
|
const contentBlock = json.content ?? {};
|
|
75557
75570
|
return ContentStateSchema.parse(contentBlock.state ?? {});
|
|
@@ -75560,7 +75573,7 @@ async function loadContentState(projectDir) {
|
|
|
75560
75573
|
}
|
|
75561
75574
|
}
|
|
75562
75575
|
async function saveContentState(projectDir, state) {
|
|
75563
|
-
const configPath =
|
|
75576
|
+
const configPath = join166(projectDir, CK_CONFIG_FILE2);
|
|
75564
75577
|
const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
|
|
75565
75578
|
for (const key of Object.keys(state.dailyPostCounts)) {
|
|
75566
75579
|
const dateStr = key.slice(-10);
|
|
@@ -75578,7 +75591,7 @@ async function saveContentState(projectDir, state) {
|
|
|
75578
75591
|
}
|
|
75579
75592
|
async function readJsonSafe(filePath) {
|
|
75580
75593
|
try {
|
|
75581
|
-
const raw2 = await
|
|
75594
|
+
const raw2 = await readFile67(filePath, "utf-8");
|
|
75582
75595
|
return JSON.parse(raw2);
|
|
75583
75596
|
} catch {
|
|
75584
75597
|
return {};
|
|
@@ -75586,8 +75599,8 @@ async function readJsonSafe(filePath) {
|
|
|
75586
75599
|
}
|
|
75587
75600
|
async function atomicWrite2(filePath, data) {
|
|
75588
75601
|
const tmpPath = `${filePath}.tmp`;
|
|
75589
|
-
await
|
|
75590
|
-
await
|
|
75602
|
+
await writeFile40(tmpPath, JSON.stringify(data, null, 2), "utf-8");
|
|
75603
|
+
await rename16(tmpPath, filePath);
|
|
75591
75604
|
}
|
|
75592
75605
|
var CK_CONFIG_FILE2 = ".ck.json";
|
|
75593
75606
|
var init_state_manager = __esm(() => {
|
|
@@ -75693,15 +75706,15 @@ async function autoInstallFbcli(contentLogger) {
|
|
|
75693
75706
|
contentLogger.warn("go install failed or Go not available");
|
|
75694
75707
|
}
|
|
75695
75708
|
try {
|
|
75696
|
-
const { platform:
|
|
75709
|
+
const { platform: platform18, arch: arch3 } = process;
|
|
75697
75710
|
const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
75698
75711
|
const archMap = { arm64: "arm64", x64: "amd64" };
|
|
75699
|
-
const os7 = osMap[
|
|
75712
|
+
const os7 = osMap[platform18];
|
|
75700
75713
|
const cpu = archMap[arch3];
|
|
75701
75714
|
if (os7 && cpu) {
|
|
75702
|
-
const ext2 =
|
|
75715
|
+
const ext2 = platform18 === "win32" ? ".exe" : "";
|
|
75703
75716
|
const url = `https://github.com/mrgoonie/fbcli/releases/latest/download/fbcli_${os7}_${cpu}${ext2}`;
|
|
75704
|
-
const dest =
|
|
75717
|
+
const dest = platform18 === "win32" ? "fbcli.exe" : "/usr/local/bin/fbcli";
|
|
75705
75718
|
f2.warning(`Will download fbcli binary from: ${url}`);
|
|
75706
75719
|
f2.warning("Note: Binary integrity is not verified. Review the source at https://github.com/mrgoonie/fbcli");
|
|
75707
75720
|
const consent = await se({ message: `Download and install fbcli to ${dest}?` });
|
|
@@ -75785,15 +75798,15 @@ async function autoInstallXurl(contentLogger) {
|
|
|
75785
75798
|
contentLogger.warn("go install failed or Go not available");
|
|
75786
75799
|
}
|
|
75787
75800
|
try {
|
|
75788
|
-
const { platform:
|
|
75801
|
+
const { platform: platform18, arch: arch3 } = process;
|
|
75789
75802
|
const osMap = { darwin: "darwin", linux: "linux", win32: "windows" };
|
|
75790
75803
|
const archMap = { arm64: "arm64", x64: "amd64" };
|
|
75791
|
-
const os7 = osMap[
|
|
75804
|
+
const os7 = osMap[platform18];
|
|
75792
75805
|
const cpu = archMap[arch3];
|
|
75793
75806
|
if (os7 && cpu) {
|
|
75794
|
-
const ext2 =
|
|
75807
|
+
const ext2 = platform18 === "win32" ? ".exe" : "";
|
|
75795
75808
|
const url = `https://github.com/xdevplatform/xurl/releases/latest/download/xurl_${os7}_${cpu}${ext2}`;
|
|
75796
|
-
const dest =
|
|
75809
|
+
const dest = platform18 === "win32" ? "xurl.exe" : "/usr/local/bin/xurl";
|
|
75797
75810
|
f2.info(`Downloading xurl binary for ${os7}/${cpu}...`);
|
|
75798
75811
|
execSync14(`curl -fsSL "${url}" -o "${dest}" && chmod +x "${dest}"`, {
|
|
75799
75812
|
stdio: "inherit",
|
|
@@ -75842,7 +75855,7 @@ var init_platform_setup_x = __esm(() => {
|
|
|
75842
75855
|
|
|
75843
75856
|
// src/commands/content/phases/setup-wizard.ts
|
|
75844
75857
|
import { existsSync as existsSync81 } from "node:fs";
|
|
75845
|
-
import { join as
|
|
75858
|
+
import { join as join167 } from "node:path";
|
|
75846
75859
|
async function runSetupWizard2(cwd2, contentLogger) {
|
|
75847
75860
|
console.log();
|
|
75848
75861
|
oe(import_picocolors43.default.bgCyan(import_picocolors43.default.white(" CK Content — Multi-Channel Content Engine ")));
|
|
@@ -75910,8 +75923,8 @@ async function showRepoSummary(cwd2) {
|
|
|
75910
75923
|
function detectBrandAssets(cwd2, contentLogger) {
|
|
75911
75924
|
const repos = discoverRepos2(cwd2);
|
|
75912
75925
|
for (const repo of repos) {
|
|
75913
|
-
const hasGuidelines = existsSync81(
|
|
75914
|
-
const hasStyles = existsSync81(
|
|
75926
|
+
const hasGuidelines = existsSync81(join167(repo.path, "docs", "brand-guidelines.md"));
|
|
75927
|
+
const hasStyles = existsSync81(join167(repo.path, "assets", "writing-styles"));
|
|
75915
75928
|
if (!hasGuidelines) {
|
|
75916
75929
|
f2.warning(`${repo.name}: No docs/brand-guidelines.md — content will use generic tone.`);
|
|
75917
75930
|
contentLogger.warn(`${repo.name}: missing docs/brand-guidelines.md`);
|
|
@@ -75978,11 +75991,11 @@ var init_setup_wizard = __esm(() => {
|
|
|
75978
75991
|
|
|
75979
75992
|
// src/commands/content/content-review-commands.ts
|
|
75980
75993
|
import { existsSync as existsSync82 } from "node:fs";
|
|
75981
|
-
import { homedir as
|
|
75994
|
+
import { homedir as homedir57 } from "node:os";
|
|
75982
75995
|
async function queueContent() {
|
|
75983
75996
|
const cwd2 = process.cwd();
|
|
75984
75997
|
const config = await loadContentConfig(cwd2);
|
|
75985
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
75998
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
75986
75999
|
if (!existsSync82(dbPath)) {
|
|
75987
76000
|
logger.info("No content database found. Run 'ck content setup' first.");
|
|
75988
76001
|
return;
|
|
@@ -76009,7 +76022,7 @@ async function queueContent() {
|
|
|
76009
76022
|
async function approveContentCmd(id) {
|
|
76010
76023
|
const cwd2 = process.cwd();
|
|
76011
76024
|
const config = await loadContentConfig(cwd2);
|
|
76012
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76025
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
76013
76026
|
const db = initDatabase(dbPath);
|
|
76014
76027
|
try {
|
|
76015
76028
|
approveContent(db, Number.parseInt(id, 10));
|
|
@@ -76021,7 +76034,7 @@ async function approveContentCmd(id) {
|
|
|
76021
76034
|
async function rejectContentCmd(id, reason) {
|
|
76022
76035
|
const cwd2 = process.cwd();
|
|
76023
76036
|
const config = await loadContentConfig(cwd2);
|
|
76024
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76037
|
+
const dbPath = config.dbPath.replace(/^~/, homedir57());
|
|
76025
76038
|
const db = initDatabase(dbPath);
|
|
76026
76039
|
try {
|
|
76027
76040
|
rejectContent(db, Number.parseInt(id, 10), reason);
|
|
@@ -76052,10 +76065,10 @@ __export(exports_content_subcommands, {
|
|
|
76052
76065
|
approveContentCmd: () => approveContentCmd
|
|
76053
76066
|
});
|
|
76054
76067
|
import { existsSync as existsSync83, readFileSync as readFileSync21, unlinkSync as unlinkSync6 } from "node:fs";
|
|
76055
|
-
import { homedir as
|
|
76056
|
-
import { join as
|
|
76068
|
+
import { homedir as homedir58 } from "node:os";
|
|
76069
|
+
import { join as join168 } from "node:path";
|
|
76057
76070
|
function isDaemonRunning() {
|
|
76058
|
-
const lockFile =
|
|
76071
|
+
const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
76059
76072
|
if (!existsSync83(lockFile))
|
|
76060
76073
|
return { running: false, pid: null };
|
|
76061
76074
|
try {
|
|
@@ -76087,7 +76100,7 @@ async function startContent(options2) {
|
|
|
76087
76100
|
await contentCommand(options2);
|
|
76088
76101
|
}
|
|
76089
76102
|
async function stopContent() {
|
|
76090
|
-
const lockFile =
|
|
76103
|
+
const lockFile = join168(LOCK_DIR, `${LOCK_NAME2}.lock`);
|
|
76091
76104
|
if (!existsSync83(lockFile)) {
|
|
76092
76105
|
logger.info("Content daemon is not running.");
|
|
76093
76106
|
return;
|
|
@@ -76126,9 +76139,9 @@ async function statusContent() {
|
|
|
76126
76139
|
} catch {}
|
|
76127
76140
|
}
|
|
76128
76141
|
async function logsContent(options2) {
|
|
76129
|
-
const logDir =
|
|
76142
|
+
const logDir = join168(homedir58(), ".claudekit", "logs");
|
|
76130
76143
|
const dateStr = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
|
76131
|
-
const logPath =
|
|
76144
|
+
const logPath = join168(logDir, `content-${dateStr}.log`);
|
|
76132
76145
|
if (!existsSync83(logPath)) {
|
|
76133
76146
|
logger.info("No content logs found for today.");
|
|
76134
76147
|
return;
|
|
@@ -76160,13 +76173,13 @@ var init_content_subcommands = __esm(() => {
|
|
|
76160
76173
|
init_setup_wizard();
|
|
76161
76174
|
init_state_manager();
|
|
76162
76175
|
init_content_review_commands();
|
|
76163
|
-
LOCK_DIR =
|
|
76176
|
+
LOCK_DIR = join168(homedir58(), ".claudekit", "locks");
|
|
76164
76177
|
});
|
|
76165
76178
|
|
|
76166
76179
|
// src/commands/content/content-command.ts
|
|
76167
76180
|
import { existsSync as existsSync84, mkdirSync as mkdirSync9, unlinkSync as unlinkSync7, writeFileSync as writeFileSync7 } from "node:fs";
|
|
76168
|
-
import { homedir as
|
|
76169
|
-
import { join as
|
|
76181
|
+
import { homedir as homedir59 } from "node:os";
|
|
76182
|
+
import { join as join169 } from "node:path";
|
|
76170
76183
|
async function contentCommand(options2) {
|
|
76171
76184
|
const cwd2 = process.cwd();
|
|
76172
76185
|
const contentLogger = new ContentLogger;
|
|
@@ -76198,7 +76211,7 @@ async function contentCommand(options2) {
|
|
|
76198
76211
|
if (!existsSync84(LOCK_DIR2))
|
|
76199
76212
|
mkdirSync9(LOCK_DIR2, { recursive: true });
|
|
76200
76213
|
writeFileSync7(LOCK_FILE, String(process.pid), "utf-8");
|
|
76201
|
-
const dbPath = config.dbPath.replace(/^~/,
|
|
76214
|
+
const dbPath = config.dbPath.replace(/^~/, homedir59());
|
|
76202
76215
|
const db = initDatabase(dbPath);
|
|
76203
76216
|
contentLogger.info(`Database initialised at ${dbPath}`);
|
|
76204
76217
|
const adapters = initializeAdapters(config);
|
|
@@ -76327,8 +76340,8 @@ function shouldRunCleanup(lastAt) {
|
|
|
76327
76340
|
return Date.now() - new Date(lastAt).getTime() >= 86400000;
|
|
76328
76341
|
}
|
|
76329
76342
|
function sleep2(ms) {
|
|
76330
|
-
return new Promise((
|
|
76331
|
-
setTimeout(
|
|
76343
|
+
return new Promise((resolve44) => {
|
|
76344
|
+
setTimeout(resolve44, ms);
|
|
76332
76345
|
});
|
|
76333
76346
|
}
|
|
76334
76347
|
var LOCK_DIR2, LOCK_FILE, MAX_CREATION_RETRIES = 3, MAX_PUBLISH_RETRIES_PER_CYCLE = 3, PUBLISH_RETRY_WINDOW_HOURS = 24;
|
|
@@ -76344,8 +76357,8 @@ var init_content_command = __esm(() => {
|
|
|
76344
76357
|
init_publisher();
|
|
76345
76358
|
init_review_manager();
|
|
76346
76359
|
init_state_manager();
|
|
76347
|
-
LOCK_DIR2 =
|
|
76348
|
-
LOCK_FILE =
|
|
76360
|
+
LOCK_DIR2 = join169(homedir59(), ".claudekit", "locks");
|
|
76361
|
+
LOCK_FILE = join169(LOCK_DIR2, "ck-content.lock");
|
|
76349
76362
|
});
|
|
76350
76363
|
|
|
76351
76364
|
// src/commands/content/index.ts
|
|
@@ -78611,7 +78624,7 @@ function getPagerArgs(pagerCmd) {
|
|
|
78611
78624
|
return [];
|
|
78612
78625
|
}
|
|
78613
78626
|
async function trySystemPager(content) {
|
|
78614
|
-
return new Promise((
|
|
78627
|
+
return new Promise((resolve44) => {
|
|
78615
78628
|
const pagerCmd = process.env.PAGER || "less";
|
|
78616
78629
|
const pagerArgs = getPagerArgs(pagerCmd);
|
|
78617
78630
|
try {
|
|
@@ -78621,20 +78634,20 @@ async function trySystemPager(content) {
|
|
|
78621
78634
|
});
|
|
78622
78635
|
const timeout2 = setTimeout(() => {
|
|
78623
78636
|
pager.kill();
|
|
78624
|
-
|
|
78637
|
+
resolve44(false);
|
|
78625
78638
|
}, 30000);
|
|
78626
78639
|
pager.stdin.write(content);
|
|
78627
78640
|
pager.stdin.end();
|
|
78628
78641
|
pager.on("close", (code2) => {
|
|
78629
78642
|
clearTimeout(timeout2);
|
|
78630
|
-
|
|
78643
|
+
resolve44(code2 === 0);
|
|
78631
78644
|
});
|
|
78632
78645
|
pager.on("error", () => {
|
|
78633
78646
|
clearTimeout(timeout2);
|
|
78634
|
-
|
|
78647
|
+
resolve44(false);
|
|
78635
78648
|
});
|
|
78636
78649
|
} catch {
|
|
78637
|
-
|
|
78650
|
+
resolve44(false);
|
|
78638
78651
|
}
|
|
78639
78652
|
});
|
|
78640
78653
|
}
|
|
@@ -78661,16 +78674,16 @@ async function basicPager(content) {
|
|
|
78661
78674
|
break;
|
|
78662
78675
|
}
|
|
78663
78676
|
const remaining = lines.length - currentLine;
|
|
78664
|
-
await new Promise((
|
|
78677
|
+
await new Promise((resolve44) => {
|
|
78665
78678
|
rl.question(`-- More (${remaining} lines) [Enter/q] --`, (answer) => {
|
|
78666
78679
|
if (answer.toLowerCase() === "q") {
|
|
78667
78680
|
rl.close();
|
|
78668
78681
|
process.exitCode = 0;
|
|
78669
|
-
|
|
78682
|
+
resolve44();
|
|
78670
78683
|
return;
|
|
78671
78684
|
}
|
|
78672
78685
|
process.stdout.write("\x1B[1A\x1B[2K");
|
|
78673
|
-
|
|
78686
|
+
resolve44();
|
|
78674
78687
|
});
|
|
78675
78688
|
});
|
|
78676
78689
|
}
|
|
@@ -88254,6 +88267,313 @@ class NetworkChecker {
|
|
|
88254
88267
|
}
|
|
88255
88268
|
}
|
|
88256
88269
|
}
|
|
88270
|
+
// src/domains/health-checks/checkers/github-reachability-checker.ts
|
|
88271
|
+
init_environment();
|
|
88272
|
+
init_logger();
|
|
88273
|
+
init_types3();
|
|
88274
|
+
import * as dnsPromises from "node:dns/promises";
|
|
88275
|
+
import * as https from "node:https";
|
|
88276
|
+
import * as net2 from "node:net";
|
|
88277
|
+
var DNS_TIMEOUT_MS = (() => {
|
|
88278
|
+
const envVal = Number.parseInt(process.env.CLAUDEKIT_DNS_TIMEOUT ?? "", 10);
|
|
88279
|
+
return Number.isFinite(envVal) && envVal > 0 ? envVal : 500;
|
|
88280
|
+
})();
|
|
88281
|
+
var TCP_TIMEOUT_MS = 1000;
|
|
88282
|
+
var TLS_TIMEOUT_MS = 3000;
|
|
88283
|
+
var AUTH_TIMEOUT_MS = 5000;
|
|
88284
|
+
var API_HOST = "api.github.com";
|
|
88285
|
+
var ZEN_URL = `https://${API_HOST}/zen`;
|
|
88286
|
+
var PROBE_KIT = "engineer";
|
|
88287
|
+
function createDefaultDeps() {
|
|
88288
|
+
return {
|
|
88289
|
+
dns: createDefaultDns(),
|
|
88290
|
+
tcp: createDefaultTcp(),
|
|
88291
|
+
tls: createDefaultTls(),
|
|
88292
|
+
auth: createDefaultAuth()
|
|
88293
|
+
};
|
|
88294
|
+
}
|
|
88295
|
+
function createDefaultDns() {
|
|
88296
|
+
return {
|
|
88297
|
+
resolve4: (host) => dnsPromises.resolve4(host),
|
|
88298
|
+
resolve6: (host) => dnsPromises.resolve6(host)
|
|
88299
|
+
};
|
|
88300
|
+
}
|
|
88301
|
+
function createDefaultTcp() {
|
|
88302
|
+
return {
|
|
88303
|
+
connect: ({ host, port, timeoutMs }) => new Promise((resolve32) => {
|
|
88304
|
+
const start = Date.now();
|
|
88305
|
+
const socket = net2.createConnection({ host, port });
|
|
88306
|
+
const timer = setTimeout(() => {
|
|
88307
|
+
socket.destroy();
|
|
88308
|
+
resolve32({ ok: false, layer: "tcp", detail: "timeout", latencyMs: Date.now() - start });
|
|
88309
|
+
}, timeoutMs);
|
|
88310
|
+
socket.on("connect", () => {
|
|
88311
|
+
clearTimeout(timer);
|
|
88312
|
+
socket.destroy();
|
|
88313
|
+
resolve32({
|
|
88314
|
+
ok: true,
|
|
88315
|
+
layer: "tcp",
|
|
88316
|
+
detail: "connected",
|
|
88317
|
+
latencyMs: Date.now() - start
|
|
88318
|
+
});
|
|
88319
|
+
});
|
|
88320
|
+
socket.on("error", (err) => {
|
|
88321
|
+
clearTimeout(timer);
|
|
88322
|
+
resolve32({
|
|
88323
|
+
ok: false,
|
|
88324
|
+
layer: "tcp",
|
|
88325
|
+
detail: err.message,
|
|
88326
|
+
latencyMs: Date.now() - start
|
|
88327
|
+
});
|
|
88328
|
+
});
|
|
88329
|
+
})
|
|
88330
|
+
};
|
|
88331
|
+
}
|
|
88332
|
+
function createDefaultTls() {
|
|
88333
|
+
return {
|
|
88334
|
+
get: (url, timeoutMs) => new Promise((resolve32) => {
|
|
88335
|
+
const start = Date.now();
|
|
88336
|
+
const timer = setTimeout(() => {
|
|
88337
|
+
req.destroy();
|
|
88338
|
+
resolve32({ ok: false, layer: "tls", detail: "timeout", latencyMs: Date.now() - start });
|
|
88339
|
+
}, timeoutMs);
|
|
88340
|
+
const req = https.get(url, {
|
|
88341
|
+
headers: {
|
|
88342
|
+
"User-Agent": "claudekit-cli-doctor/1.0"
|
|
88343
|
+
}
|
|
88344
|
+
}, (res) => {
|
|
88345
|
+
res.resume();
|
|
88346
|
+
clearTimeout(timer);
|
|
88347
|
+
const status = res.statusCode ?? 0;
|
|
88348
|
+
const latencyMs = Date.now() - start;
|
|
88349
|
+
if (status === 200) {
|
|
88350
|
+
resolve32({ ok: true, layer: "tls", detail: `HTTP ${status}`, latencyMs });
|
|
88351
|
+
} else {
|
|
88352
|
+
resolve32({ ok: false, layer: "tls", detail: `HTTP ${status}`, latencyMs });
|
|
88353
|
+
}
|
|
88354
|
+
});
|
|
88355
|
+
req.on("error", (err) => {
|
|
88356
|
+
clearTimeout(timer);
|
|
88357
|
+
resolve32({
|
|
88358
|
+
ok: false,
|
|
88359
|
+
layer: "tls",
|
|
88360
|
+
detail: err.message,
|
|
88361
|
+
latencyMs: Date.now() - start
|
|
88362
|
+
});
|
|
88363
|
+
});
|
|
88364
|
+
})
|
|
88365
|
+
};
|
|
88366
|
+
}
|
|
88367
|
+
function createDefaultAuth() {
|
|
88368
|
+
return {
|
|
88369
|
+
checkKitAccess: async () => {
|
|
88370
|
+
const start = Date.now();
|
|
88371
|
+
const { getAuthenticatedClient: getAuthenticatedClient2 } = await Promise.resolve().then(() => (init_client(), exports_client));
|
|
88372
|
+
const kit = AVAILABLE_KITS[PROBE_KIT];
|
|
88373
|
+
try {
|
|
88374
|
+
const client = await getAuthenticatedClient2();
|
|
88375
|
+
await client.repos.get({ owner: kit.owner, repo: kit.repo });
|
|
88376
|
+
return {
|
|
88377
|
+
ok: true,
|
|
88378
|
+
layer: "auth",
|
|
88379
|
+
detail: "200 OK",
|
|
88380
|
+
latencyMs: Date.now() - start,
|
|
88381
|
+
statusCode: 200
|
|
88382
|
+
};
|
|
88383
|
+
} catch (err) {
|
|
88384
|
+
const latencyMs = Date.now() - start;
|
|
88385
|
+
const status = err?.status ?? err?.statusCode;
|
|
88386
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
88387
|
+
if (status === 401) {
|
|
88388
|
+
return {
|
|
88389
|
+
ok: false,
|
|
88390
|
+
layer: "auth",
|
|
88391
|
+
detail: `401 Unauthorized — token invalid or missing. ${message}`,
|
|
88392
|
+
latencyMs,
|
|
88393
|
+
statusCode: 401
|
|
88394
|
+
};
|
|
88395
|
+
}
|
|
88396
|
+
if (status === 404) {
|
|
88397
|
+
return {
|
|
88398
|
+
ok: false,
|
|
88399
|
+
layer: "auth",
|
|
88400
|
+
detail: `404 — no repository access (invitation pending). ${message}`,
|
|
88401
|
+
latencyMs,
|
|
88402
|
+
statusCode: 404
|
|
88403
|
+
};
|
|
88404
|
+
}
|
|
88405
|
+
return {
|
|
88406
|
+
ok: false,
|
|
88407
|
+
layer: "auth",
|
|
88408
|
+
detail: `${status ?? "?"} — ${message}`,
|
|
88409
|
+
latencyMs,
|
|
88410
|
+
statusCode: status
|
|
88411
|
+
};
|
|
88412
|
+
}
|
|
88413
|
+
}
|
|
88414
|
+
};
|
|
88415
|
+
}
|
|
88416
|
+
async function checkGitHubReachability(deps) {
|
|
88417
|
+
const dnsStart = Date.now();
|
|
88418
|
+
let dnsResult;
|
|
88419
|
+
try {
|
|
88420
|
+
const [r4, r6] = await Promise.allSettled([
|
|
88421
|
+
raceTimeout(deps.dns.resolve4(API_HOST), DNS_TIMEOUT_MS),
|
|
88422
|
+
raceTimeout(deps.dns.resolve6(API_HOST), DNS_TIMEOUT_MS)
|
|
88423
|
+
]);
|
|
88424
|
+
const ok = r4.status === "fulfilled" || r6.status === "fulfilled";
|
|
88425
|
+
let detail;
|
|
88426
|
+
if (ok) {
|
|
88427
|
+
if (r4.status === "fulfilled") {
|
|
88428
|
+
detail = `resolved: ${r4.value[0]}`;
|
|
88429
|
+
} else {
|
|
88430
|
+
const r6Value = r6.value;
|
|
88431
|
+
detail = `resolved (IPv6): ${r6Value[0]}`;
|
|
88432
|
+
}
|
|
88433
|
+
} else {
|
|
88434
|
+
detail = "NXDOMAIN / timeout";
|
|
88435
|
+
}
|
|
88436
|
+
dnsResult = { ok, layer: "dns", detail, latencyMs: Date.now() - dnsStart };
|
|
88437
|
+
} catch {
|
|
88438
|
+
dnsResult = {
|
|
88439
|
+
ok: false,
|
|
88440
|
+
layer: "dns",
|
|
88441
|
+
detail: "DNS resolution failed",
|
|
88442
|
+
latencyMs: Date.now() - dnsStart
|
|
88443
|
+
};
|
|
88444
|
+
}
|
|
88445
|
+
if (!dnsResult.ok) {
|
|
88446
|
+
return { ok: false, failedLayer: "dns", layers: { dns: dnsResult } };
|
|
88447
|
+
}
|
|
88448
|
+
const tcpResult = await deps.tcp.connect({
|
|
88449
|
+
host: API_HOST,
|
|
88450
|
+
port: 443,
|
|
88451
|
+
timeoutMs: TCP_TIMEOUT_MS
|
|
88452
|
+
});
|
|
88453
|
+
if (!tcpResult.ok) {
|
|
88454
|
+
return { ok: false, failedLayer: "tcp", layers: { dns: dnsResult, tcp: tcpResult } };
|
|
88455
|
+
}
|
|
88456
|
+
const tlsResult = await deps.tls.get(ZEN_URL, TLS_TIMEOUT_MS);
|
|
88457
|
+
if (!tlsResult.ok) {
|
|
88458
|
+
return {
|
|
88459
|
+
ok: false,
|
|
88460
|
+
failedLayer: "tls",
|
|
88461
|
+
layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult }
|
|
88462
|
+
};
|
|
88463
|
+
}
|
|
88464
|
+
const authResult = await deps.auth.checkKitAccess();
|
|
88465
|
+
if (!authResult.ok) {
|
|
88466
|
+
return {
|
|
88467
|
+
ok: false,
|
|
88468
|
+
failedLayer: "auth",
|
|
88469
|
+
layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult, auth: authResult }
|
|
88470
|
+
};
|
|
88471
|
+
}
|
|
88472
|
+
return {
|
|
88473
|
+
ok: true,
|
|
88474
|
+
layers: { dns: dnsResult, tcp: tcpResult, tls: tlsResult, auth: authResult }
|
|
88475
|
+
};
|
|
88476
|
+
}
|
|
88477
|
+
function raceTimeout(promise, ms) {
|
|
88478
|
+
return new Promise((resolve32, reject) => {
|
|
88479
|
+
const timer = setTimeout(() => reject(new Error(`timeout after ${ms}ms`)), ms);
|
|
88480
|
+
promise.then((v2) => {
|
|
88481
|
+
clearTimeout(timer);
|
|
88482
|
+
resolve32(v2);
|
|
88483
|
+
}, (e2) => {
|
|
88484
|
+
clearTimeout(timer);
|
|
88485
|
+
reject(e2);
|
|
88486
|
+
});
|
|
88487
|
+
});
|
|
88488
|
+
}
|
|
88489
|
+
|
|
88490
|
+
class GitHubReachabilityChecker {
|
|
88491
|
+
group = "network";
|
|
88492
|
+
deps;
|
|
88493
|
+
usingRealDeps;
|
|
88494
|
+
constructor(options2 = {}) {
|
|
88495
|
+
this.usingRealDeps = options2.deps === undefined;
|
|
88496
|
+
this.deps = options2.deps ?? createDefaultDeps();
|
|
88497
|
+
}
|
|
88498
|
+
async run() {
|
|
88499
|
+
if (this.usingRealDeps && (isCIEnvironment() || isTestEnvironment())) {
|
|
88500
|
+
return [
|
|
88501
|
+
{
|
|
88502
|
+
id: "github-reachability",
|
|
88503
|
+
name: "GitHub Reachability",
|
|
88504
|
+
group: "network",
|
|
88505
|
+
priority: "standard",
|
|
88506
|
+
status: "info",
|
|
88507
|
+
message: "Skipped in CI/test environment",
|
|
88508
|
+
autoFixable: false
|
|
88509
|
+
}
|
|
88510
|
+
];
|
|
88511
|
+
}
|
|
88512
|
+
logger.verbose("GitHubReachabilityChecker: running layered probe");
|
|
88513
|
+
let result;
|
|
88514
|
+
try {
|
|
88515
|
+
result = await raceTimeout(checkGitHubReachability(this.deps), AUTH_TIMEOUT_MS + TLS_TIMEOUT_MS + TCP_TIMEOUT_MS + DNS_TIMEOUT_MS + 500);
|
|
88516
|
+
} catch (err) {
|
|
88517
|
+
return [
|
|
88518
|
+
{
|
|
88519
|
+
id: "github-reachability",
|
|
88520
|
+
name: "GitHub Reachability",
|
|
88521
|
+
group: "network",
|
|
88522
|
+
priority: "standard",
|
|
88523
|
+
status: "fail",
|
|
88524
|
+
message: "Probe timed out",
|
|
88525
|
+
details: err instanceof Error ? err.message : String(err),
|
|
88526
|
+
suggestion: "Check internet connection and proxy settings",
|
|
88527
|
+
autoFixable: false
|
|
88528
|
+
}
|
|
88529
|
+
];
|
|
88530
|
+
}
|
|
88531
|
+
logger.verbose("GitHubReachabilityChecker: probe complete", { result });
|
|
88532
|
+
return [buildCheckResult(result)];
|
|
88533
|
+
}
|
|
88534
|
+
}
|
|
88535
|
+
function buildCheckResult(result) {
|
|
88536
|
+
if (result.ok) {
|
|
88537
|
+
const { dns, tcp, tls, auth } = result.layers;
|
|
88538
|
+
const details = [
|
|
88539
|
+
`DNS: ${dns.latencyMs}ms`,
|
|
88540
|
+
tcp ? `TCP: ${tcp.latencyMs}ms` : null,
|
|
88541
|
+
tls ? `TLS/GET: ${tls.latencyMs}ms` : null,
|
|
88542
|
+
auth ? `Auth: ${auth.latencyMs}ms` : null
|
|
88543
|
+
].filter(Boolean).join(", ");
|
|
88544
|
+
return {
|
|
88545
|
+
id: "github-reachability",
|
|
88546
|
+
name: "GitHub Reachability",
|
|
88547
|
+
group: "network",
|
|
88548
|
+
priority: "standard",
|
|
88549
|
+
status: "pass",
|
|
88550
|
+
message: "All layers reachable",
|
|
88551
|
+
details,
|
|
88552
|
+
autoFixable: false
|
|
88553
|
+
};
|
|
88554
|
+
}
|
|
88555
|
+
const { failedLayer, layers } = result;
|
|
88556
|
+
const failedProbe = layers[failedLayer];
|
|
88557
|
+
const detail = failedProbe?.detail ?? "unknown";
|
|
88558
|
+
const authSuggestion = failedProbe?.statusCode === 401 ? "GitHub token invalid or missing — run: gh auth login" : "No repository access — check GitHub invitation email or purchase at https://claudekit.cc";
|
|
88559
|
+
const suggestions = {
|
|
88560
|
+
dns: "DNS resolution failed — check /etc/resolv.conf or system DNS settings",
|
|
88561
|
+
tcp: "TCP connect to api.github.com:443 failed — check firewall or proxy blocking port 443",
|
|
88562
|
+
tls: "HTTPS GET /zen returned unexpected status — possible TLS interception or GitHub outage. Check https://githubstatus.com",
|
|
88563
|
+
auth: authSuggestion
|
|
88564
|
+
};
|
|
88565
|
+
return {
|
|
88566
|
+
id: "github-reachability",
|
|
88567
|
+
name: "GitHub Reachability",
|
|
88568
|
+
group: "network",
|
|
88569
|
+
priority: "standard",
|
|
88570
|
+
status: "fail",
|
|
88571
|
+
message: `GitHub unreachable at ${failedLayer?.toUpperCase()} layer`,
|
|
88572
|
+
details: detail,
|
|
88573
|
+
suggestion: suggestions[failedLayer ?? ""] ?? "Run: ck doctor for full diagnostics",
|
|
88574
|
+
autoFixable: false
|
|
88575
|
+
};
|
|
88576
|
+
}
|
|
88257
88577
|
// src/domains/health-checks/auto-healer.ts
|
|
88258
88578
|
class AutoHealer {
|
|
88259
88579
|
timeout;
|
|
@@ -88680,6 +89000,7 @@ async function doctorCommand(options2 = {}) {
|
|
|
88680
89000
|
runner.registerChecker(new AuthChecker);
|
|
88681
89001
|
runner.registerChecker(new PlatformChecker);
|
|
88682
89002
|
runner.registerChecker(new NetworkChecker);
|
|
89003
|
+
runner.registerChecker(new GitHubReachabilityChecker);
|
|
88683
89004
|
const summary = await runner.run();
|
|
88684
89005
|
if (json) {
|
|
88685
89006
|
const generator = new ReportGenerator;
|
|
@@ -105382,7 +105703,15 @@ async function handleSelection(ctx) {
|
|
|
105382
105703
|
logger.info("Full diagnostics: ck doctor");
|
|
105383
105704
|
return { ...ctx, cancelled: true };
|
|
105384
105705
|
}
|
|
105385
|
-
|
|
105706
|
+
try {
|
|
105707
|
+
accessibleKits = await detectAccessibleKits();
|
|
105708
|
+
} catch (err) {
|
|
105709
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
105710
|
+
logger.error(`Failed to check repository access: ${message}`);
|
|
105711
|
+
logger.info("");
|
|
105712
|
+
logger.info("Run: ck doctor");
|
|
105713
|
+
return { ...ctx, cancelled: true };
|
|
105714
|
+
}
|
|
105386
105715
|
if (accessibleKits.length === 0) {
|
|
105387
105716
|
logger.error("No ClaudeKit repository access found.");
|
|
105388
105717
|
logger.info("Check email for GitHub invitation, or purchase at https://claudekit.cc");
|
|
@@ -106746,9 +107075,9 @@ async function initCommand(options2) {
|
|
|
106746
107075
|
init_dist2();
|
|
106747
107076
|
var import_picocolors30 = __toESM(require_picocolors(), 1);
|
|
106748
107077
|
import { existsSync as existsSync64 } from "node:fs";
|
|
106749
|
-
import { readFile as
|
|
106750
|
-
import { homedir as
|
|
106751
|
-
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";
|
|
106752
107081
|
init_logger();
|
|
106753
107082
|
|
|
106754
107083
|
// src/ui/ck-cli-design/tokens.ts
|
|
@@ -107220,32 +107549,262 @@ init_model_taxonomy();
|
|
|
107220
107549
|
init_logger();
|
|
107221
107550
|
init_dist2();
|
|
107222
107551
|
init_model_taxonomy();
|
|
107223
|
-
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";
|
|
107224
107559
|
import { homedir as homedir49 } from "node:os";
|
|
107225
|
-
import {
|
|
107226
|
-
|
|
107227
|
-
|
|
107228
|
-
|
|
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);
|
|
107229
107646
|
}
|
|
107230
|
-
return join141(options2.cwd ?? process.cwd(), "opencode.json");
|
|
107231
107647
|
}
|
|
107232
|
-
|
|
107233
|
-
|
|
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);
|
|
107234
107664
|
try {
|
|
107235
|
-
const raw2 = await
|
|
107665
|
+
const raw2 = await readFile61(authPath, "utf-8");
|
|
107236
107666
|
const parsed = JSON.parse(raw2);
|
|
107237
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107667
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107238
107668
|
return Object.keys(parsed);
|
|
107239
107669
|
}
|
|
107240
107670
|
} catch {}
|
|
107241
107671
|
return [];
|
|
107242
107672
|
}
|
|
107243
|
-
|
|
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) {
|
|
107244
107790
|
const override = getOpenCodeDefaultModelOverride();
|
|
107245
107791
|
if (override) {
|
|
107246
|
-
return { model: override, reason: ".ck.json override" };
|
|
107792
|
+
return { ok: true, model: override, reason: ".ck.json override", authedProviders: [] };
|
|
107247
107793
|
}
|
|
107248
|
-
|
|
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
|
+
};
|
|
107806
|
+
}
|
|
107807
|
+
return { ok: false, failure: result.reason, authedProviders: result.authedProviders };
|
|
107249
107808
|
}
|
|
107250
107809
|
var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
107251
107810
|
const providersHint = detectedProviders.length > 0 ? `Authenticated providers in opencode: ${detectedProviders.join(", ")}` : "No authenticated providers detected in opencode.";
|
|
@@ -107267,7 +107826,7 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
|
107267
107826
|
if (response === "accept")
|
|
107268
107827
|
return { action: "accept" };
|
|
107269
107828
|
const custom2 = await te({
|
|
107270
|
-
message: "Model (format: provider/model-id, e.g.
|
|
107829
|
+
message: "Model (format: provider/model-id, e.g. opencode/qwen3.5-plus-free)",
|
|
107271
107830
|
placeholder: suggestion,
|
|
107272
107831
|
validate: (value) => {
|
|
107273
107832
|
if (!value || !value.includes("/"))
|
|
@@ -107279,13 +107838,35 @@ var clackPrompter = async ({ suggestion, reason, detectedProviders }) => {
|
|
|
107279
107838
|
return { action: "skip" };
|
|
107280
107839
|
return { action: "custom", value: custom2 };
|
|
107281
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
|
+
};
|
|
107282
107863
|
async function ensureOpenCodeModel(options2) {
|
|
107283
107864
|
const configPath = getOpenCodeConfigPath(options2);
|
|
107284
107865
|
let existing = null;
|
|
107285
107866
|
try {
|
|
107286
|
-
const raw2 = await
|
|
107867
|
+
const raw2 = await readFile62(configPath, "utf-8");
|
|
107287
107868
|
const parsed = JSON.parse(raw2);
|
|
107288
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107869
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
107289
107870
|
existing = parsed;
|
|
107290
107871
|
} else {
|
|
107291
107872
|
logger.warning(`ensureOpenCodeModel: ${configPath} is valid JSON but not an object; overwriting with default model`);
|
|
@@ -107298,40 +107879,72 @@ async function ensureOpenCodeModel(options2) {
|
|
|
107298
107879
|
logger.verbose(`ensureOpenCodeModel: failed to read ${configPath} (${errno ?? String(err)}); recreating`);
|
|
107299
107880
|
}
|
|
107300
107881
|
}
|
|
107301
|
-
if (existing && typeof existing.model === "string" && existing.model.trim().length > 0) {
|
|
107302
|
-
|
|
107303
|
-
|
|
107304
|
-
|
|
107305
|
-
|
|
107306
|
-
|
|
107307
|
-
|
|
107308
|
-
|
|
107309
|
-
|
|
107310
|
-
|
|
107311
|
-
|
|
107312
|
-
|
|
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
|
|
107313
107901
|
});
|
|
107314
|
-
if (
|
|
107315
|
-
return {
|
|
107316
|
-
path: configPath,
|
|
107317
|
-
action: "skipped",
|
|
107318
|
-
model: "",
|
|
107319
|
-
reason: "user declined"
|
|
107320
|
-
};
|
|
107902
|
+
if (response2.action === "skip") {
|
|
107903
|
+
return { path: configPath, action: "existing", model: existingModel };
|
|
107321
107904
|
}
|
|
107322
|
-
|
|
107323
|
-
|
|
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);
|
|
107324
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" };
|
|
107325
107937
|
}
|
|
107938
|
+
const chosenModel = response.action === "custom" ? response.value : suggestion.ok ? suggestion.model : "";
|
|
107326
107939
|
const next = { ...existing ?? {}, model: chosenModel };
|
|
107327
|
-
await
|
|
107328
|
-
await
|
|
107940
|
+
await mkdir37(dirname41(configPath), { recursive: true });
|
|
107941
|
+
await writeFile36(configPath, `${JSON.stringify(next, null, 2)}
|
|
107329
107942
|
`, "utf-8");
|
|
107330
107943
|
return {
|
|
107331
107944
|
path: configPath,
|
|
107332
107945
|
action: existing ? "added" : "created",
|
|
107333
107946
|
model: chosenModel,
|
|
107334
|
-
reason: suggestion.reason
|
|
107947
|
+
reason: suggestion.ok ? suggestion.reason : undefined
|
|
107335
107948
|
};
|
|
107336
107949
|
}
|
|
107337
107950
|
|
|
@@ -108106,12 +108719,12 @@ async function executeDeleteAction(action, options2) {
|
|
|
108106
108719
|
async function processMetadataDeletions(skillSourcePath, installGlobally) {
|
|
108107
108720
|
if (!skillSourcePath)
|
|
108108
108721
|
return;
|
|
108109
|
-
const sourceMetadataPath =
|
|
108722
|
+
const sourceMetadataPath = join144(resolve41(skillSourcePath, ".."), "metadata.json");
|
|
108110
108723
|
if (!existsSync64(sourceMetadataPath))
|
|
108111
108724
|
return;
|
|
108112
108725
|
let sourceMetadata;
|
|
108113
108726
|
try {
|
|
108114
|
-
const content = await
|
|
108727
|
+
const content = await readFile63(sourceMetadataPath, "utf-8");
|
|
108115
108728
|
sourceMetadata = JSON.parse(content);
|
|
108116
108729
|
} catch (error) {
|
|
108117
108730
|
logger.debug(`[migrate] Failed to parse source metadata.json: ${error}`);
|
|
@@ -108119,7 +108732,7 @@ async function processMetadataDeletions(skillSourcePath, installGlobally) {
|
|
|
108119
108732
|
}
|
|
108120
108733
|
if (!sourceMetadata.deletions || sourceMetadata.deletions.length === 0)
|
|
108121
108734
|
return;
|
|
108122
|
-
const claudeDir3 = installGlobally ?
|
|
108735
|
+
const claudeDir3 = installGlobally ? join144(homedir52(), ".claude") : join144(process.cwd(), ".claude");
|
|
108123
108736
|
if (!existsSync64(claudeDir3))
|
|
108124
108737
|
return;
|
|
108125
108738
|
try {
|
|
@@ -108241,8 +108854,8 @@ async function migrateCommand(options2) {
|
|
|
108241
108854
|
let requestedGlobal = options2.global ?? false;
|
|
108242
108855
|
let installGlobally = requestedGlobal;
|
|
108243
108856
|
if (options2.global === undefined && !options2.yes) {
|
|
108244
|
-
const projectTarget =
|
|
108245
|
-
const globalTarget =
|
|
108857
|
+
const projectTarget = join144(process.cwd(), ".claude");
|
|
108858
|
+
const globalTarget = join144(homedir52(), ".claude");
|
|
108246
108859
|
const scopeChoice = await ie({
|
|
108247
108860
|
message: "Installation scope",
|
|
108248
108861
|
options: [
|
|
@@ -108405,7 +109018,7 @@ async function migrateCommand(options2) {
|
|
|
108405
109018
|
for (const action of conflictActions) {
|
|
108406
109019
|
if (!action.diff && action.targetPath && existsSync64(action.targetPath)) {
|
|
108407
109020
|
try {
|
|
108408
|
-
const targetContent = await
|
|
109021
|
+
const targetContent = await readFile63(action.targetPath, "utf-8");
|
|
108409
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);
|
|
108410
109023
|
if (sourceItem) {
|
|
108411
109024
|
const providerConfig = providers[action.provider];
|
|
@@ -108552,7 +109165,12 @@ async function migrateCommand(options2) {
|
|
|
108552
109165
|
f2.warn("Skipped writing default model to opencode.json. Migrated agents may fail with ProviderModelNotFoundError until you set one.");
|
|
108553
109166
|
}
|
|
108554
109167
|
} catch (err) {
|
|
108555
|
-
|
|
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
|
+
}
|
|
108556
109174
|
}
|
|
108557
109175
|
}
|
|
108558
109176
|
if (hooksSource && successfulHookFiles.size > 0) {
|
|
@@ -108817,7 +109435,7 @@ function buildDryRunFallbackResults(skills, selectedProviders, installGlobally,
|
|
|
108817
109435
|
results.push({
|
|
108818
109436
|
itemName: skill.name,
|
|
108819
109437
|
operation: "apply",
|
|
108820
|
-
path:
|
|
109438
|
+
path: join144(basePath, skill.name),
|
|
108821
109439
|
portableType: "skill",
|
|
108822
109440
|
provider,
|
|
108823
109441
|
providerDisplayName: providers[provider].displayName,
|
|
@@ -108835,7 +109453,7 @@ var import_picocolors31 = __toESM(require_picocolors(), 1);
|
|
|
108835
109453
|
|
|
108836
109454
|
// src/commands/new/phases/directory-setup.ts
|
|
108837
109455
|
init_config_manager();
|
|
108838
|
-
import { resolve as
|
|
109456
|
+
import { resolve as resolve43 } from "node:path";
|
|
108839
109457
|
init_logger();
|
|
108840
109458
|
init_path_resolver();
|
|
108841
109459
|
init_types3();
|
|
@@ -108920,7 +109538,7 @@ async function directorySetup(validOptions, prompts) {
|
|
|
108920
109538
|
targetDir = await prompts.getDirectory(targetDir);
|
|
108921
109539
|
}
|
|
108922
109540
|
}
|
|
108923
|
-
const resolvedDir =
|
|
109541
|
+
const resolvedDir = resolve43(targetDir);
|
|
108924
109542
|
logger.info(`Target directory: ${resolvedDir}`);
|
|
108925
109543
|
if (PathResolver.isLocalSameAsGlobal(resolvedDir)) {
|
|
108926
109544
|
logger.warning("You're creating a project at HOME directory.");
|
|
@@ -108977,7 +109595,7 @@ async function handleDirectorySetup(ctx) {
|
|
|
108977
109595
|
// src/commands/new/phases/project-creation.ts
|
|
108978
109596
|
init_config_manager();
|
|
108979
109597
|
init_github_client();
|
|
108980
|
-
import { join as
|
|
109598
|
+
import { join as join145 } from "node:path";
|
|
108981
109599
|
init_logger();
|
|
108982
109600
|
init_output_manager();
|
|
108983
109601
|
init_types3();
|
|
@@ -109103,7 +109721,7 @@ async function projectCreation(kit, resolvedDir, validOptions, isNonInteractive2
|
|
|
109103
109721
|
output.section("Installing");
|
|
109104
109722
|
logger.verbose("Installation target", { directory: resolvedDir });
|
|
109105
109723
|
const merger = new FileMerger;
|
|
109106
|
-
const claudeDir3 =
|
|
109724
|
+
const claudeDir3 = join145(resolvedDir, ".claude");
|
|
109107
109725
|
merger.setMultiKitContext(claudeDir3, kit);
|
|
109108
109726
|
if (validOptions.exclude && validOptions.exclude.length > 0) {
|
|
109109
109727
|
merger.addIgnorePatterns(validOptions.exclude);
|
|
@@ -109150,7 +109768,7 @@ async function handleProjectCreation(ctx) {
|
|
|
109150
109768
|
}
|
|
109151
109769
|
// src/commands/new/phases/post-setup.ts
|
|
109152
109770
|
init_projects_registry();
|
|
109153
|
-
import { join as
|
|
109771
|
+
import { join as join146 } from "node:path";
|
|
109154
109772
|
init_package_installer();
|
|
109155
109773
|
init_logger();
|
|
109156
109774
|
init_path_resolver();
|
|
@@ -109182,9 +109800,9 @@ async function postSetup(resolvedDir, validOptions, isNonInteractive2, prompts)
|
|
|
109182
109800
|
withSudo: validOptions.withSudo
|
|
109183
109801
|
});
|
|
109184
109802
|
}
|
|
109185
|
-
const claudeDir3 =
|
|
109803
|
+
const claudeDir3 = join146(resolvedDir, ".claude");
|
|
109186
109804
|
await promptSetupWizardIfNeeded({
|
|
109187
|
-
envPath:
|
|
109805
|
+
envPath: join146(claudeDir3, ".env"),
|
|
109188
109806
|
claudeDir: claudeDir3,
|
|
109189
109807
|
isGlobal: false,
|
|
109190
109808
|
isNonInteractive: isNonInteractive2,
|
|
@@ -109254,7 +109872,7 @@ Please use only one download method.`);
|
|
|
109254
109872
|
// src/commands/plan/plan-command.ts
|
|
109255
109873
|
init_output_manager();
|
|
109256
109874
|
import { existsSync as existsSync67, statSync as statSync12 } from "node:fs";
|
|
109257
|
-
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";
|
|
109258
109876
|
|
|
109259
109877
|
// src/commands/plan/plan-read-handlers.ts
|
|
109260
109878
|
init_config();
|
|
@@ -109264,14 +109882,14 @@ init_logger();
|
|
|
109264
109882
|
init_output_manager();
|
|
109265
109883
|
var import_picocolors32 = __toESM(require_picocolors(), 1);
|
|
109266
109884
|
import { existsSync as existsSync66, statSync as statSync11 } from "node:fs";
|
|
109267
|
-
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";
|
|
109268
109886
|
|
|
109269
109887
|
// src/commands/plan/plan-dependencies.ts
|
|
109270
109888
|
init_config();
|
|
109271
109889
|
init_plan_parser();
|
|
109272
109890
|
init_plans_registry();
|
|
109273
109891
|
import { existsSync as existsSync65 } from "node:fs";
|
|
109274
|
-
import { dirname as dirname43, join as
|
|
109892
|
+
import { dirname as dirname43, join as join147 } from "node:path";
|
|
109275
109893
|
async function resolvePlanDependencies(references, currentPlanFile, options2 = {}) {
|
|
109276
109894
|
if (references.length === 0)
|
|
109277
109895
|
return [];
|
|
@@ -109291,7 +109909,7 @@ async function resolvePlanDependencies(references, currentPlanFile, options2 = {
|
|
|
109291
109909
|
};
|
|
109292
109910
|
}
|
|
109293
109911
|
const scopeRoot = resolvePlanDirForScope(scope, projectRoot, config);
|
|
109294
|
-
const planFile =
|
|
109912
|
+
const planFile = join147(scopeRoot, planId, "plan.md");
|
|
109295
109913
|
const isSelfReference = planFile === currentPlanFile;
|
|
109296
109914
|
if (!existsSync65(planFile)) {
|
|
109297
109915
|
return {
|
|
@@ -109322,14 +109940,14 @@ init_config();
|
|
|
109322
109940
|
init_plan_parser();
|
|
109323
109941
|
init_plan_scope();
|
|
109324
109942
|
init_plans_registry();
|
|
109325
|
-
import { isAbsolute as isAbsolute10, resolve as
|
|
109943
|
+
import { isAbsolute as isAbsolute10, resolve as resolve45 } from "node:path";
|
|
109326
109944
|
async function getGlobalPlansDirFromCwd() {
|
|
109327
109945
|
const projectRoot = findProjectRoot(process.cwd());
|
|
109328
109946
|
const { config } = await CkConfigManager.loadFull(projectRoot);
|
|
109329
109947
|
return resolveGlobalPlansDir(config);
|
|
109330
109948
|
}
|
|
109331
109949
|
function resolveTargetFromBase(target, baseDir) {
|
|
109332
|
-
const resolvedTarget = isAbsolute10(target) ?
|
|
109950
|
+
const resolvedTarget = isAbsolute10(target) ? resolve45(target) : resolve45(baseDir, target);
|
|
109333
109951
|
return isWithinDir(resolvedTarget, baseDir) ? resolvedTarget : null;
|
|
109334
109952
|
}
|
|
109335
109953
|
|
|
@@ -109432,8 +110050,8 @@ async function handleStatus(target, options2) {
|
|
|
109432
110050
|
return;
|
|
109433
110051
|
}
|
|
109434
110052
|
const effectiveTarget = !resolvedTarget && globalBaseDir ? globalBaseDir : resolvedTarget;
|
|
109435
|
-
const t = effectiveTarget ?
|
|
109436
|
-
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(
|
|
110053
|
+
const t = effectiveTarget ? resolve46(effectiveTarget) : null;
|
|
110054
|
+
const plansDir = t && existsSync66(t) && statSync11(t).isDirectory() && !existsSync66(join148(t, "plan.md")) ? t : null;
|
|
109437
110055
|
if (plansDir) {
|
|
109438
110056
|
const planFiles = scanPlanDir(plansDir);
|
|
109439
110057
|
if (planFiles.length === 0) {
|
|
@@ -109617,7 +110235,7 @@ init_plan_parser();
|
|
|
109617
110235
|
init_plans_registry();
|
|
109618
110236
|
init_output_manager();
|
|
109619
110237
|
var import_picocolors33 = __toESM(require_picocolors(), 1);
|
|
109620
|
-
import { basename as basename29, dirname as dirname45, relative as relative28, resolve as
|
|
110238
|
+
import { basename as basename29, dirname as dirname45, relative as relative28, resolve as resolve47 } from "node:path";
|
|
109621
110239
|
async function handleCreate(target, options2) {
|
|
109622
110240
|
if (!options2.title) {
|
|
109623
110241
|
output.error("[X] --title is required for create");
|
|
@@ -109649,13 +110267,13 @@ async function handleCreate(target, options2) {
|
|
|
109649
110267
|
return;
|
|
109650
110268
|
}
|
|
109651
110269
|
const globalBaseDir = options2.global ? await getGlobalPlansDirFromCwd() : undefined;
|
|
109652
|
-
const resolvedDir = globalBaseDir ? resolveTargetFromBase(dir, globalBaseDir) :
|
|
110270
|
+
const resolvedDir = globalBaseDir ? resolveTargetFromBase(dir, globalBaseDir) : resolve47(dir);
|
|
109653
110271
|
if (globalBaseDir && !resolvedDir) {
|
|
109654
110272
|
output.error("[X] Target directory must stay within the configured global plans root");
|
|
109655
110273
|
process.exitCode = 1;
|
|
109656
110274
|
return;
|
|
109657
110275
|
}
|
|
109658
|
-
const safeResolvedDir = resolvedDir ??
|
|
110276
|
+
const safeResolvedDir = resolvedDir ?? resolve47(dir);
|
|
109659
110277
|
const result = scaffoldPlan({
|
|
109660
110278
|
title: options2.title,
|
|
109661
110279
|
phases: phaseNames.map((name2) => ({ name: name2 })),
|
|
@@ -109831,24 +110449,24 @@ async function handleAddPhase(target, options2) {
|
|
|
109831
110449
|
// src/commands/plan/plan-command.ts
|
|
109832
110450
|
function resolveTargetPath(target, baseDir) {
|
|
109833
110451
|
if (!baseDir) {
|
|
109834
|
-
return
|
|
110452
|
+
return resolve48(target);
|
|
109835
110453
|
}
|
|
109836
110454
|
if (isAbsolute11(target)) {
|
|
109837
|
-
return
|
|
110455
|
+
return resolve48(target);
|
|
109838
110456
|
}
|
|
109839
|
-
const cwdCandidate =
|
|
110457
|
+
const cwdCandidate = resolve48(target);
|
|
109840
110458
|
if (existsSync67(cwdCandidate)) {
|
|
109841
110459
|
return cwdCandidate;
|
|
109842
110460
|
}
|
|
109843
|
-
return
|
|
110461
|
+
return resolve48(baseDir, target);
|
|
109844
110462
|
}
|
|
109845
110463
|
function resolvePlanFile(target, baseDir) {
|
|
109846
|
-
const t = target ? resolveTargetPath(target, baseDir) : baseDir ?
|
|
110464
|
+
const t = target ? resolveTargetPath(target, baseDir) : baseDir ? resolve48(baseDir) : process.cwd();
|
|
109847
110465
|
if (existsSync67(t)) {
|
|
109848
110466
|
const stat24 = statSync12(t);
|
|
109849
110467
|
if (stat24.isFile())
|
|
109850
110468
|
return t;
|
|
109851
|
-
const candidate =
|
|
110469
|
+
const candidate = join149(t, "plan.md");
|
|
109852
110470
|
if (existsSync67(candidate))
|
|
109853
110471
|
return candidate;
|
|
109854
110472
|
}
|
|
@@ -109856,7 +110474,7 @@ function resolvePlanFile(target, baseDir) {
|
|
|
109856
110474
|
let dir = process.cwd();
|
|
109857
110475
|
const root = parse7(dir).root;
|
|
109858
110476
|
while (dir !== root) {
|
|
109859
|
-
const candidate =
|
|
110477
|
+
const candidate = join149(dir, "plan.md");
|
|
109860
110478
|
if (existsSync67(candidate))
|
|
109861
110479
|
return candidate;
|
|
109862
110480
|
dir = dirname46(dir);
|
|
@@ -109907,7 +110525,7 @@ async function planCommand(action, target, options2) {
|
|
|
109907
110525
|
let resolvedTarget = target;
|
|
109908
110526
|
if (resolvedAction && !knownActions.has(resolvedAction)) {
|
|
109909
110527
|
const looksLikePath = resolvedAction.includes("/") || resolvedAction.includes("\\") || resolvedAction.endsWith(".md") || resolvedAction === "." || resolvedAction === "..";
|
|
109910
|
-
const existsOnDisk = !looksLikePath && existsSync67(
|
|
110528
|
+
const existsOnDisk = !looksLikePath && existsSync67(resolve48(resolvedAction));
|
|
109911
110529
|
if (looksLikePath || existsOnDisk) {
|
|
109912
110530
|
resolvedTarget = resolvedAction;
|
|
109913
110531
|
resolvedAction = undefined;
|
|
@@ -109950,11 +110568,11 @@ init_logger();
|
|
|
109950
110568
|
init_safe_prompts();
|
|
109951
110569
|
var import_picocolors34 = __toESM(require_picocolors(), 1);
|
|
109952
110570
|
import { existsSync as existsSync68 } from "node:fs";
|
|
109953
|
-
import { resolve as
|
|
110571
|
+
import { resolve as resolve49 } from "node:path";
|
|
109954
110572
|
async function handleAdd(projectPath, options2) {
|
|
109955
110573
|
logger.debug(`Adding project: ${projectPath}, options: ${JSON.stringify(options2)}`);
|
|
109956
110574
|
intro("Add Project");
|
|
109957
|
-
const absolutePath =
|
|
110575
|
+
const absolutePath = resolve49(projectPath);
|
|
109958
110576
|
if (!existsSync68(absolutePath)) {
|
|
109959
110577
|
log.error(`Path does not exist: ${absolutePath}`);
|
|
109960
110578
|
process.exitCode = 1;
|
|
@@ -110378,8 +110996,8 @@ init_skills_registry();
|
|
|
110378
110996
|
init_skills_uninstaller();
|
|
110379
110997
|
var import_gray_matter11 = __toESM(require_gray_matter(), 1);
|
|
110380
110998
|
var import_picocolors37 = __toESM(require_picocolors(), 1);
|
|
110381
|
-
import { readFile as
|
|
110382
|
-
import { join as
|
|
110999
|
+
import { readFile as readFile64 } from "node:fs/promises";
|
|
111000
|
+
import { join as join150 } from "node:path";
|
|
110383
111001
|
|
|
110384
111002
|
// src/commands/skills/types.ts
|
|
110385
111003
|
init_zod();
|
|
@@ -110501,9 +111119,9 @@ async function handleValidate2(sourcePath) {
|
|
|
110501
111119
|
spinner.stop(`Checked ${skills.length} skill(s)`);
|
|
110502
111120
|
let hasIssues = false;
|
|
110503
111121
|
for (const skill of skills) {
|
|
110504
|
-
const skillMdPath =
|
|
111122
|
+
const skillMdPath = join150(skill.path, "SKILL.md");
|
|
110505
111123
|
try {
|
|
110506
|
-
const content = await
|
|
111124
|
+
const content = await readFile64(skillMdPath, "utf-8");
|
|
110507
111125
|
const { data } = import_gray_matter11.default(content, {
|
|
110508
111126
|
engines: { javascript: { parse: () => ({}) } }
|
|
110509
111127
|
});
|
|
@@ -111059,7 +111677,7 @@ async function detectInstallations() {
|
|
|
111059
111677
|
|
|
111060
111678
|
// src/commands/uninstall/removal-handler.ts
|
|
111061
111679
|
import { readdirSync as readdirSync10, rmSync as rmSync5 } from "node:fs";
|
|
111062
|
-
import { basename as basename30, join as
|
|
111680
|
+
import { basename as basename30, join as join152, resolve as resolve50, sep as sep12 } from "node:path";
|
|
111063
111681
|
init_logger();
|
|
111064
111682
|
init_safe_prompts();
|
|
111065
111683
|
init_safe_spinner();
|
|
@@ -111068,7 +111686,7 @@ var import_fs_extra44 = __toESM(require_lib3(), 1);
|
|
|
111068
111686
|
// src/commands/uninstall/analysis-handler.ts
|
|
111069
111687
|
init_metadata_migration();
|
|
111070
111688
|
import { readdirSync as readdirSync9, rmSync as rmSync4 } from "node:fs";
|
|
111071
|
-
import { dirname as dirname47, join as
|
|
111689
|
+
import { dirname as dirname47, join as join151 } from "node:path";
|
|
111072
111690
|
init_logger();
|
|
111073
111691
|
init_safe_prompts();
|
|
111074
111692
|
var import_fs_extra43 = __toESM(require_lib3(), 1);
|
|
@@ -111125,7 +111743,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111125
111743
|
const remainingFiles = metadata.kits?.[remainingKit]?.files || [];
|
|
111126
111744
|
for (const file of remainingFiles) {
|
|
111127
111745
|
const relativePath = normalizeTrackedPath(file.path);
|
|
111128
|
-
if (await import_fs_extra43.pathExists(
|
|
111746
|
+
if (await import_fs_extra43.pathExists(join151(installation.path, relativePath))) {
|
|
111129
111747
|
result.retainedManifestPaths.push(relativePath);
|
|
111130
111748
|
}
|
|
111131
111749
|
}
|
|
@@ -111133,7 +111751,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111133
111751
|
const kitFiles = metadata.kits[kit].files || [];
|
|
111134
111752
|
for (const trackedFile of kitFiles) {
|
|
111135
111753
|
const relativePath = normalizeTrackedPath(trackedFile.path);
|
|
111136
|
-
const filePath =
|
|
111754
|
+
const filePath = join151(installation.path, relativePath);
|
|
111137
111755
|
if (preservedPaths.has(relativePath)) {
|
|
111138
111756
|
result.toPreserve.push({ path: relativePath, reason: "shared with other kit" });
|
|
111139
111757
|
continue;
|
|
@@ -111166,7 +111784,7 @@ async function analyzeInstallation(installation, forceOverwrite, kit) {
|
|
|
111166
111784
|
}
|
|
111167
111785
|
for (const trackedFile of allTrackedFiles) {
|
|
111168
111786
|
const relativePath = normalizeTrackedPath(trackedFile.path);
|
|
111169
|
-
const filePath =
|
|
111787
|
+
const filePath = join151(installation.path, relativePath);
|
|
111170
111788
|
const ownershipResult = await OwnershipChecker.checkOwnership(filePath, metadata, installation.path);
|
|
111171
111789
|
if (!ownershipResult.exists)
|
|
111172
111790
|
continue;
|
|
@@ -111240,8 +111858,8 @@ async function restoreUninstallBackup(backup) {
|
|
|
111240
111858
|
}
|
|
111241
111859
|
async function isPathSafeToRemove(filePath, baseDir) {
|
|
111242
111860
|
try {
|
|
111243
|
-
const resolvedPath =
|
|
111244
|
-
const resolvedBase =
|
|
111861
|
+
const resolvedPath = resolve50(filePath);
|
|
111862
|
+
const resolvedBase = resolve50(baseDir);
|
|
111245
111863
|
if (!resolvedPath.startsWith(resolvedBase + sep12) && resolvedPath !== resolvedBase) {
|
|
111246
111864
|
logger.debug(`Path outside installation directory: ${filePath}`);
|
|
111247
111865
|
return false;
|
|
@@ -111249,7 +111867,7 @@ async function isPathSafeToRemove(filePath, baseDir) {
|
|
|
111249
111867
|
const stats = await import_fs_extra44.lstat(filePath);
|
|
111250
111868
|
if (stats.isSymbolicLink()) {
|
|
111251
111869
|
const realPath = await import_fs_extra44.realpath(filePath);
|
|
111252
|
-
const resolvedReal =
|
|
111870
|
+
const resolvedReal = resolve50(realPath);
|
|
111253
111871
|
if (!resolvedReal.startsWith(resolvedBase + sep12) && resolvedReal !== resolvedBase) {
|
|
111254
111872
|
logger.debug(`Symlink points outside installation directory: ${filePath} -> ${realPath}`);
|
|
111255
111873
|
return false;
|
|
@@ -111309,7 +111927,7 @@ async function removeInstallations(installations, options2) {
|
|
|
111309
111927
|
let removedCount = 0;
|
|
111310
111928
|
let cleanedDirs = 0;
|
|
111311
111929
|
for (const item of analysis.toDelete) {
|
|
111312
|
-
const filePath =
|
|
111930
|
+
const filePath = join152(installation.path, item.path);
|
|
111313
111931
|
if (!await import_fs_extra44.pathExists(filePath))
|
|
111314
111932
|
continue;
|
|
111315
111933
|
if (!await isPathSafeToRemove(filePath, installation.path)) {
|
|
@@ -111643,7 +112261,7 @@ ${import_picocolors40.default.bold(import_picocolors40.default.cyan(result.kitCo
|
|
|
111643
112261
|
init_logger();
|
|
111644
112262
|
import { existsSync as existsSync74 } from "node:fs";
|
|
111645
112263
|
import { rm as rm17 } from "node:fs/promises";
|
|
111646
|
-
import { join as
|
|
112264
|
+
import { join as join159 } from "node:path";
|
|
111647
112265
|
var import_picocolors41 = __toESM(require_picocolors(), 1);
|
|
111648
112266
|
|
|
111649
112267
|
// src/commands/watch/phases/implementation-runner.ts
|
|
@@ -111712,7 +112330,7 @@ function getDisclaimerMarker() {
|
|
|
111712
112330
|
return AI_DISCLAIMER;
|
|
111713
112331
|
}
|
|
111714
112332
|
function spawnAndCollect2(command, args) {
|
|
111715
|
-
return new Promise((
|
|
112333
|
+
return new Promise((resolve44, reject) => {
|
|
111716
112334
|
const child = spawn7(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
111717
112335
|
const chunks = [];
|
|
111718
112336
|
const stderrChunks = [];
|
|
@@ -111725,7 +112343,7 @@ function spawnAndCollect2(command, args) {
|
|
|
111725
112343
|
reject(new Error(`${command} exited with code ${code2}: ${stderr}`));
|
|
111726
112344
|
return;
|
|
111727
112345
|
}
|
|
111728
|
-
|
|
112346
|
+
resolve44(Buffer.concat(chunks).toString("utf-8"));
|
|
111729
112347
|
});
|
|
111730
112348
|
});
|
|
111731
112349
|
}
|
|
@@ -111833,7 +112451,7 @@ function formatResponse(content, showBranding) {
|
|
|
111833
112451
|
return disclaimer + formatted + branding;
|
|
111834
112452
|
}
|
|
111835
112453
|
async function postViaGh(owner, repo, issueNumber, body) {
|
|
111836
|
-
return new Promise((
|
|
112454
|
+
return new Promise((resolve44, reject) => {
|
|
111837
112455
|
const args = [
|
|
111838
112456
|
"issue",
|
|
111839
112457
|
"comment",
|
|
@@ -111855,7 +112473,7 @@ async function postViaGh(owner, repo, issueNumber, body) {
|
|
|
111855
112473
|
reject(new Error(`gh exited with code ${code2}: ${stderr}`));
|
|
111856
112474
|
return;
|
|
111857
112475
|
}
|
|
111858
|
-
|
|
112476
|
+
resolve44();
|
|
111859
112477
|
});
|
|
111860
112478
|
});
|
|
111861
112479
|
}
|
|
@@ -111973,7 +112591,7 @@ After completing the implementation:
|
|
|
111973
112591
|
"--allowedTools",
|
|
111974
112592
|
tools
|
|
111975
112593
|
];
|
|
111976
|
-
await new Promise((
|
|
112594
|
+
await new Promise((resolve44, reject) => {
|
|
111977
112595
|
const child = spawn9("claude", args, { cwd: cwd2, stdio: ["pipe", "pipe", "pipe"], detached: false });
|
|
111978
112596
|
child.stdin.write(prompt);
|
|
111979
112597
|
child.stdin.end();
|
|
@@ -111998,7 +112616,7 @@ After completing the implementation:
|
|
|
111998
112616
|
reject(new Error(`Claude exited ${code2}: ${stderr.slice(0, 500)}`));
|
|
111999
112617
|
return;
|
|
112000
112618
|
}
|
|
112001
|
-
|
|
112619
|
+
resolve44();
|
|
112002
112620
|
});
|
|
112003
112621
|
});
|
|
112004
112622
|
}
|
|
@@ -112142,7 +112760,7 @@ function checkRateLimit2(processedThisHour, maxPerHour) {
|
|
|
112142
112760
|
return processedThisHour < maxPerHour;
|
|
112143
112761
|
}
|
|
112144
112762
|
function spawnAndCollect3(command, args) {
|
|
112145
|
-
return new Promise((
|
|
112763
|
+
return new Promise((resolve44, reject) => {
|
|
112146
112764
|
const child = spawn10(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
112147
112765
|
const chunks = [];
|
|
112148
112766
|
const stderrChunks = [];
|
|
@@ -112155,14 +112773,14 @@ function spawnAndCollect3(command, args) {
|
|
|
112155
112773
|
reject(new Error(`${command} exited with code ${code2}: ${stderr}`));
|
|
112156
112774
|
return;
|
|
112157
112775
|
}
|
|
112158
|
-
|
|
112776
|
+
resolve44(Buffer.concat(chunks).toString("utf-8"));
|
|
112159
112777
|
});
|
|
112160
112778
|
});
|
|
112161
112779
|
}
|
|
112162
112780
|
|
|
112163
112781
|
// src/commands/watch/phases/issue-processor.ts
|
|
112164
|
-
import { mkdir as
|
|
112165
|
-
import { join as
|
|
112782
|
+
import { mkdir as mkdir38, writeFile as writeFile38 } from "node:fs/promises";
|
|
112783
|
+
import { join as join155 } from "node:path";
|
|
112166
112784
|
|
|
112167
112785
|
// src/commands/watch/phases/approval-detector.ts
|
|
112168
112786
|
init_logger();
|
|
@@ -112207,7 +112825,7 @@ async function invokeClaude(options2) {
|
|
|
112207
112825
|
return collectClaudeOutput(child, options2.timeoutSec, verbose);
|
|
112208
112826
|
}
|
|
112209
112827
|
function collectClaudeOutput(child, timeoutSec, verbose = false) {
|
|
112210
|
-
return new Promise((
|
|
112828
|
+
return new Promise((resolve44, reject) => {
|
|
112211
112829
|
const chunks = [];
|
|
112212
112830
|
const stderrChunks = [];
|
|
112213
112831
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -112237,7 +112855,7 @@ function collectClaudeOutput(child, timeoutSec, verbose = false) {
|
|
|
112237
112855
|
reject(new Error(`Claude exited with code ${code2}: ${stderr}`));
|
|
112238
112856
|
return;
|
|
112239
112857
|
}
|
|
112240
|
-
|
|
112858
|
+
resolve44(verbose ? parseStreamJsonOutput(stdout2) : parseClaudeOutput(stdout2));
|
|
112241
112859
|
});
|
|
112242
112860
|
});
|
|
112243
112861
|
}
|
|
@@ -112540,9 +113158,9 @@ async function checkAwaitingApproval(state, setup, options2, watchLog, projectDi
|
|
|
112540
113158
|
|
|
112541
113159
|
// src/commands/watch/phases/plan-dir-finder.ts
|
|
112542
113160
|
import { readdir as readdir44, stat as stat24 } from "node:fs/promises";
|
|
112543
|
-
import { join as
|
|
113161
|
+
import { join as join154 } from "node:path";
|
|
112544
113162
|
async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
112545
|
-
const plansRoot =
|
|
113163
|
+
const plansRoot = join154(cwd2, "plans");
|
|
112546
113164
|
try {
|
|
112547
113165
|
const entries = await readdir44(plansRoot);
|
|
112548
113166
|
const tenMinAgo = Date.now() - 10 * 60 * 1000;
|
|
@@ -112551,14 +113169,14 @@ async function findRecentPlanDir(cwd2, issueNumber, watchLog) {
|
|
|
112551
113169
|
for (const entry of entries) {
|
|
112552
113170
|
if (entry === "watch" || entry === "reports" || entry === "visuals")
|
|
112553
113171
|
continue;
|
|
112554
|
-
const dirPath =
|
|
113172
|
+
const dirPath = join154(plansRoot, entry);
|
|
112555
113173
|
const dirStat = await stat24(dirPath);
|
|
112556
113174
|
if (!dirStat.isDirectory())
|
|
112557
113175
|
continue;
|
|
112558
113176
|
if (dirStat.mtimeMs < tenMinAgo)
|
|
112559
113177
|
continue;
|
|
112560
113178
|
try {
|
|
112561
|
-
await stat24(
|
|
113179
|
+
await stat24(join154(dirPath, "plan.md"));
|
|
112562
113180
|
} catch {
|
|
112563
113181
|
continue;
|
|
112564
113182
|
}
|
|
@@ -112789,14 +113407,14 @@ async function handlePlanGeneration(issue, state, config, setup, options2, watch
|
|
|
112789
113407
|
stats.plansCreated++;
|
|
112790
113408
|
const detectedPlanDir = await findRecentPlanDir(projectDir, issue.number, watchLog);
|
|
112791
113409
|
if (detectedPlanDir) {
|
|
112792
|
-
state.activeIssues[numStr].planPath =
|
|
113410
|
+
state.activeIssues[numStr].planPath = join155(detectedPlanDir, "plan.md");
|
|
112793
113411
|
watchLog.info(`Plan directory detected: ${detectedPlanDir}`);
|
|
112794
113412
|
} else {
|
|
112795
113413
|
try {
|
|
112796
|
-
const planDir =
|
|
112797
|
-
await
|
|
112798
|
-
const planFilePath =
|
|
112799
|
-
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");
|
|
112800
113418
|
state.activeIssues[numStr].planPath = planFilePath;
|
|
112801
113419
|
watchLog.info(`Plan saved (fallback) to ${planFilePath}`);
|
|
112802
113420
|
} catch (err) {
|
|
@@ -112873,7 +113491,7 @@ async function checkActiveIssues(state, config, setup, options2, watchLog, stats
|
|
|
112873
113491
|
// src/commands/watch/phases/maintainer-resolver.ts
|
|
112874
113492
|
init_logger();
|
|
112875
113493
|
init_implementation_git_helpers();
|
|
112876
|
-
var
|
|
113494
|
+
var CACHE_TTL_MS4 = 3600000;
|
|
112877
113495
|
var cache4 = new Map;
|
|
112878
113496
|
async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
|
|
112879
113497
|
const normalizedExclude = excludeAuthors.map((s) => s.toLowerCase());
|
|
@@ -112882,7 +113500,7 @@ async function resolveMaintainers(owner, repo, excludeAuthors, autoDetect) {
|
|
|
112882
113500
|
}
|
|
112883
113501
|
const cacheKey = `${owner}/${repo}`;
|
|
112884
113502
|
const cached = cache4.get(cacheKey);
|
|
112885
|
-
if (cached && Date.now() - cached.fetchedAt >=
|
|
113503
|
+
if (cached && Date.now() - cached.fetchedAt >= CACHE_TTL_MS4) {
|
|
112886
113504
|
cache4.delete(cacheKey);
|
|
112887
113505
|
} else if (cached) {
|
|
112888
113506
|
const merged = Array.from(new Set([...cached.users, ...normalizedExclude]));
|
|
@@ -112941,7 +113559,7 @@ init_ck_config_manager();
|
|
|
112941
113559
|
init_file_io();
|
|
112942
113560
|
init_logger();
|
|
112943
113561
|
import { existsSync as existsSync70 } from "node:fs";
|
|
112944
|
-
import { mkdir as
|
|
113562
|
+
import { mkdir as mkdir39, readFile as readFile66 } from "node:fs/promises";
|
|
112945
113563
|
import { dirname as dirname48 } from "node:path";
|
|
112946
113564
|
var PROCESSED_ISSUES_CAP = 500;
|
|
112947
113565
|
async function readCkJson(projectDir) {
|
|
@@ -112949,7 +113567,7 @@ async function readCkJson(projectDir) {
|
|
|
112949
113567
|
try {
|
|
112950
113568
|
if (!existsSync70(configPath))
|
|
112951
113569
|
return {};
|
|
112952
|
-
const content = await
|
|
113570
|
+
const content = await readFile66(configPath, "utf-8");
|
|
112953
113571
|
return JSON.parse(content);
|
|
112954
113572
|
} catch (error) {
|
|
112955
113573
|
logger.warning(`Failed to parse .ck.json: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -112974,7 +113592,7 @@ async function saveWatchState(projectDir, state) {
|
|
|
112974
113592
|
const configPath = CkConfigManager.getProjectConfigPath(projectDir);
|
|
112975
113593
|
const configDir = dirname48(configPath);
|
|
112976
113594
|
if (!existsSync70(configDir)) {
|
|
112977
|
-
await
|
|
113595
|
+
await mkdir39(configDir, { recursive: true });
|
|
112978
113596
|
}
|
|
112979
113597
|
const raw2 = await readCkJson(projectDir);
|
|
112980
113598
|
const watchRaw = raw2.watch ?? {};
|
|
@@ -113102,18 +113720,18 @@ init_logger();
|
|
|
113102
113720
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
113103
113721
|
import { existsSync as existsSync71 } from "node:fs";
|
|
113104
113722
|
import { readdir as readdir45, stat as stat25 } from "node:fs/promises";
|
|
113105
|
-
import { join as
|
|
113723
|
+
import { join as join156 } from "node:path";
|
|
113106
113724
|
async function scanForRepos(parentDir) {
|
|
113107
113725
|
const repos = [];
|
|
113108
113726
|
const entries = await readdir45(parentDir);
|
|
113109
113727
|
for (const entry of entries) {
|
|
113110
113728
|
if (entry.startsWith("."))
|
|
113111
113729
|
continue;
|
|
113112
|
-
const fullPath =
|
|
113730
|
+
const fullPath = join156(parentDir, entry);
|
|
113113
113731
|
const entryStat = await stat25(fullPath);
|
|
113114
113732
|
if (!entryStat.isDirectory())
|
|
113115
113733
|
continue;
|
|
113116
|
-
const gitDir =
|
|
113734
|
+
const gitDir = join156(fullPath, ".git");
|
|
113117
113735
|
if (!existsSync71(gitDir))
|
|
113118
113736
|
continue;
|
|
113119
113737
|
const result = spawnSync7("gh", ["repo", "view", "--json", "owner,name"], {
|
|
@@ -113139,8 +113757,8 @@ async function scanForRepos(parentDir) {
|
|
|
113139
113757
|
init_logger();
|
|
113140
113758
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
113141
113759
|
import { existsSync as existsSync72 } from "node:fs";
|
|
113142
|
-
import { homedir as
|
|
113143
|
-
import { join as
|
|
113760
|
+
import { homedir as homedir53 } from "node:os";
|
|
113761
|
+
import { join as join157 } from "node:path";
|
|
113144
113762
|
async function validateSetup(cwd2) {
|
|
113145
113763
|
const workDir = cwd2 ?? process.cwd();
|
|
113146
113764
|
const ghVersion = spawnSync8("gh", ["--version"], { encoding: "utf-8", timeout: 1e4 });
|
|
@@ -113171,7 +113789,7 @@ Run this command from a directory with a GitHub remote.`);
|
|
|
113171
113789
|
} catch {
|
|
113172
113790
|
throw new Error(`Failed to parse repository info: ${ghRepo.stdout}`);
|
|
113173
113791
|
}
|
|
113174
|
-
const skillsPath =
|
|
113792
|
+
const skillsPath = join157(homedir53(), ".claude", "skills");
|
|
113175
113793
|
const skillsAvailable = existsSync72(skillsPath);
|
|
113176
113794
|
if (!skillsAvailable) {
|
|
113177
113795
|
logger.warning(`ClaudeKit Engineer skills not found at ${skillsPath}`);
|
|
@@ -113189,8 +113807,8 @@ init_logger();
|
|
|
113189
113807
|
init_path_resolver();
|
|
113190
113808
|
import { createWriteStream as createWriteStream3, statSync as statSync13 } from "node:fs";
|
|
113191
113809
|
import { existsSync as existsSync73 } from "node:fs";
|
|
113192
|
-
import { mkdir as
|
|
113193
|
-
import { join as
|
|
113810
|
+
import { mkdir as mkdir40, rename as rename14 } from "node:fs/promises";
|
|
113811
|
+
import { join as join158 } from "node:path";
|
|
113194
113812
|
|
|
113195
113813
|
class WatchLogger {
|
|
113196
113814
|
logStream = null;
|
|
@@ -113198,16 +113816,16 @@ class WatchLogger {
|
|
|
113198
113816
|
logPath = null;
|
|
113199
113817
|
maxBytes;
|
|
113200
113818
|
constructor(logDir, maxBytes = 0) {
|
|
113201
|
-
this.logDir = logDir ??
|
|
113819
|
+
this.logDir = logDir ?? join158(PathResolver.getClaudeKitDir(), "logs");
|
|
113202
113820
|
this.maxBytes = maxBytes;
|
|
113203
113821
|
}
|
|
113204
113822
|
async init() {
|
|
113205
113823
|
try {
|
|
113206
113824
|
if (!existsSync73(this.logDir)) {
|
|
113207
|
-
await
|
|
113825
|
+
await mkdir40(this.logDir, { recursive: true });
|
|
113208
113826
|
}
|
|
113209
113827
|
const dateStr = formatDate(new Date);
|
|
113210
|
-
this.logPath =
|
|
113828
|
+
this.logPath = join158(this.logDir, `watch-${dateStr}.log`);
|
|
113211
113829
|
this.logStream = createWriteStream3(this.logPath, { flags: "a", mode: 384 });
|
|
113212
113830
|
} catch (error) {
|
|
113213
113831
|
logger.warning(`Cannot create watch log file: ${error instanceof Error ? error.message : "Unknown"}`);
|
|
@@ -113272,7 +113890,7 @@ class WatchLogger {
|
|
|
113272
113890
|
try {
|
|
113273
113891
|
this.logStream.end();
|
|
113274
113892
|
const rotatedPath = `${this.logPath}.1`;
|
|
113275
|
-
|
|
113893
|
+
rename14(this.logPath, rotatedPath).catch(() => {});
|
|
113276
113894
|
this.logStream = createWriteStream3(this.logPath, { flags: "w", mode: 384 });
|
|
113277
113895
|
} catch {}
|
|
113278
113896
|
}
|
|
@@ -113389,7 +114007,7 @@ async function watchCommand(options2) {
|
|
|
113389
114007
|
}
|
|
113390
114008
|
async function discoverRepos(options2, watchLog) {
|
|
113391
114009
|
const cwd2 = process.cwd();
|
|
113392
|
-
const isGitRepo = existsSync74(
|
|
114010
|
+
const isGitRepo = existsSync74(join159(cwd2, ".git"));
|
|
113393
114011
|
if (options2.force) {
|
|
113394
114012
|
await forceRemoveLock(watchLog);
|
|
113395
114013
|
}
|
|
@@ -113501,7 +114119,7 @@ function formatQueueInfo(state) {
|
|
|
113501
114119
|
return "idle";
|
|
113502
114120
|
}
|
|
113503
114121
|
function sleep(ms) {
|
|
113504
|
-
return new Promise((
|
|
114122
|
+
return new Promise((resolve44) => setTimeout(resolve44, ms));
|
|
113505
114123
|
}
|
|
113506
114124
|
// src/cli/command-registry.ts
|
|
113507
114125
|
init_logger();
|
|
@@ -113648,7 +114266,7 @@ function registerCommands(cli) {
|
|
|
113648
114266
|
init_package();
|
|
113649
114267
|
init_config_version_checker();
|
|
113650
114268
|
import { existsSync as existsSync86, readFileSync as readFileSync22 } from "node:fs";
|
|
113651
|
-
import { join as
|
|
114269
|
+
import { join as join171 } from "node:path";
|
|
113652
114270
|
|
|
113653
114271
|
// src/domains/versioning/version-checker.ts
|
|
113654
114272
|
init_version_utils();
|
|
@@ -113662,15 +114280,15 @@ init_types3();
|
|
|
113662
114280
|
init_logger();
|
|
113663
114281
|
init_path_resolver();
|
|
113664
114282
|
import { existsSync as existsSync85 } from "node:fs";
|
|
113665
|
-
import { mkdir as
|
|
113666
|
-
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";
|
|
113667
114285
|
|
|
113668
114286
|
class VersionCacheManager {
|
|
113669
114287
|
static CACHE_FILENAME = "version-check.json";
|
|
113670
114288
|
static CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
113671
114289
|
static getCacheFile() {
|
|
113672
114290
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
113673
|
-
return
|
|
114291
|
+
return join170(cacheDir, VersionCacheManager.CACHE_FILENAME);
|
|
113674
114292
|
}
|
|
113675
114293
|
static async load() {
|
|
113676
114294
|
const cacheFile = VersionCacheManager.getCacheFile();
|
|
@@ -113679,7 +114297,7 @@ class VersionCacheManager {
|
|
|
113679
114297
|
logger.debug("Version check cache not found");
|
|
113680
114298
|
return null;
|
|
113681
114299
|
}
|
|
113682
|
-
const content = await
|
|
114300
|
+
const content = await readFile68(cacheFile, "utf-8");
|
|
113683
114301
|
const cache5 = JSON.parse(content);
|
|
113684
114302
|
if (!cache5.lastCheck || !cache5.currentVersion || !cache5.latestVersion) {
|
|
113685
114303
|
logger.debug("Invalid cache structure, ignoring");
|
|
@@ -113697,9 +114315,9 @@ class VersionCacheManager {
|
|
|
113697
114315
|
const cacheDir = PathResolver.getCacheDir(false);
|
|
113698
114316
|
try {
|
|
113699
114317
|
if (!existsSync85(cacheDir)) {
|
|
113700
|
-
await
|
|
114318
|
+
await mkdir41(cacheDir, { recursive: true, mode: 448 });
|
|
113701
114319
|
}
|
|
113702
|
-
await
|
|
114320
|
+
await writeFile41(cacheFile, JSON.stringify(cache5, null, 2), "utf-8");
|
|
113703
114321
|
logger.debug(`Version check cache saved to ${cacheFile}`);
|
|
113704
114322
|
} catch (error) {
|
|
113705
114323
|
logger.debug(`Failed to save version check cache: ${error}`);
|
|
@@ -113981,9 +114599,9 @@ async function displayVersion() {
|
|
|
113981
114599
|
let localInstalledKits = [];
|
|
113982
114600
|
let globalInstalledKits = [];
|
|
113983
114601
|
const globalKitDir = PathResolver.getGlobalKitDir();
|
|
113984
|
-
const globalMetadataPath =
|
|
114602
|
+
const globalMetadataPath = join171(globalKitDir, "metadata.json");
|
|
113985
114603
|
const prefix = PathResolver.getPathPrefix(false);
|
|
113986
|
-
const localMetadataPath = prefix ?
|
|
114604
|
+
const localMetadataPath = prefix ? join171(process.cwd(), prefix, "metadata.json") : join171(process.cwd(), "metadata.json");
|
|
113987
114605
|
const isLocalSameAsGlobal = localMetadataPath === globalMetadataPath;
|
|
113988
114606
|
if (!isLocalSameAsGlobal && existsSync86(localMetadataPath)) {
|
|
113989
114607
|
try {
|