@ulpi/cli 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth-KQCJ43U2.js +118 -0
- package/dist/{chunk-UA6EFK64.js → chunk-2VYFVYJL.js} +63 -16
- package/dist/{chunk-VGZLMUNO.js → chunk-5J6NLQUN.js} +1 -1
- package/dist/{chunk-S253WCQJ.js → chunk-F7OXF7Z3.js} +1 -1
- package/dist/chunk-G6SVZ4Q5.js +122 -0
- package/dist/{chunk-NNUWU6CV.js → chunk-JGBXM5NC.js} +42 -0
- package/dist/{chunk-FNPD3V2X.js → chunk-PDR55ZNW.js} +57 -6
- package/dist/ci-QM57ZCBW.js +367 -0
- package/dist/{codemap-3BVYMMVM.js → codemap-RKSD4MIE.js} +13 -13
- package/dist/{dist-MFFX7TZW.js → dist-CB5D5LMO.js} +2 -2
- package/dist/{dist-3SNTTNM3.js → dist-CS2VKNYS.js} +3 -3
- package/dist/{dist-57UMTPGR.js → dist-GJYT2OQV.js} +9 -3
- package/dist/{dist-RJGCUS3L.js → dist-QAU3LGJN.js} +3 -1
- package/dist/{dist-QYFQYSXP.js → dist-UKMCJBB2.js} +2 -2
- package/dist/{history-UG65BCO6.js → history-NFNA4HE5.js} +9 -6
- package/dist/index.js +34 -17
- package/dist/{init-22PO3EQB.js → init-6CH4HV5T.js} +2 -2
- package/dist/{memory-IT4H3WRD.js → memory-Y6OZTXJ2.js} +153 -34
- package/dist/{server-KYER5KX3-43RQQ4MY.js → server-USLHY6GH-AEOJC5ST.js} +2 -2
- package/dist/{ui-3EFREFSY.js → ui-OWXZ3YSR.js} +3 -3
- package/dist/ui.html +87 -87
- package/dist/{update-364RHTAO.js → update-WUITQX4Z.js} +1 -1
- package/dist/{version-checker-DTAS4ZYK.js → version-checker-SMAYSN7Y.js} +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import {
|
|
2
|
+
extractCredentials,
|
|
3
|
+
getCredentialExpiry,
|
|
4
|
+
validateCredentials
|
|
5
|
+
} from "./chunk-G6SVZ4Q5.js";
|
|
6
|
+
import "./chunk-4VNS5WPM.js";
|
|
7
|
+
|
|
8
|
+
// src/commands/auth.ts
|
|
9
|
+
import * as fs from "fs";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
async function runAuth(args) {
|
|
12
|
+
const subcommand = args[0];
|
|
13
|
+
switch (subcommand) {
|
|
14
|
+
case "setup":
|
|
15
|
+
return authSetup();
|
|
16
|
+
case "check":
|
|
17
|
+
return authCheck(args.slice(1));
|
|
18
|
+
case "refresh":
|
|
19
|
+
return authSetup();
|
|
20
|
+
// Same flow as setup
|
|
21
|
+
default:
|
|
22
|
+
console.log(`
|
|
23
|
+
${chalk.bold("ulpi auth")} \u2014 Manage Claude Code credentials for CI workers
|
|
24
|
+
|
|
25
|
+
Usage: ulpi auth <command>
|
|
26
|
+
|
|
27
|
+
Commands:
|
|
28
|
+
setup Extract Claude Code credentials for CI use (interactive)
|
|
29
|
+
check Validate stored credentials
|
|
30
|
+
refresh Re-authenticate and output new credentials
|
|
31
|
+
|
|
32
|
+
How it works:
|
|
33
|
+
1. Run 'ulpi auth setup' on a machine with a browser
|
|
34
|
+
2. It extracts your Claude Code session credentials
|
|
35
|
+
3. Outputs a base64 blob you can store as a Docker secret
|
|
36
|
+
4. Set ULPI_CLAUDE_CREDENTIALS in your orchestrator config
|
|
37
|
+
`.trim());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function authSetup() {
|
|
41
|
+
console.log(chalk.blue("Extracting Claude Code credentials..."));
|
|
42
|
+
console.log();
|
|
43
|
+
const claudeDir = process.env.CLAUDE_CONFIG_DIR ?? `${process.env.HOME}/.claude`;
|
|
44
|
+
if (!fs.existsSync(claudeDir)) {
|
|
45
|
+
console.log(chalk.yellow("No Claude Code configuration found."));
|
|
46
|
+
console.log();
|
|
47
|
+
console.log("Please run 'claude login' first to authenticate with Anthropic.");
|
|
48
|
+
console.log("Then run 'ulpi auth setup' again.");
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const blob = extractCredentials(claudeDir);
|
|
53
|
+
const expiry = getCredentialExpiry(blob);
|
|
54
|
+
console.log(chalk.green("Credentials extracted successfully."));
|
|
55
|
+
console.log();
|
|
56
|
+
if (expiry) {
|
|
57
|
+
console.log(` Expires: ${expiry}`);
|
|
58
|
+
console.log();
|
|
59
|
+
}
|
|
60
|
+
console.log(chalk.bold("Your credentials blob:"));
|
|
61
|
+
console.log();
|
|
62
|
+
console.log(blob);
|
|
63
|
+
console.log();
|
|
64
|
+
console.log(chalk.bold("To use in your orchestrator:"));
|
|
65
|
+
console.log();
|
|
66
|
+
console.log(" 1. Set as environment variable:");
|
|
67
|
+
console.log(chalk.cyan(` export ULPI_CLAUDE_CREDENTIALS="${blob.slice(0, 20)}..."`));
|
|
68
|
+
console.log();
|
|
69
|
+
console.log(" 2. Or add to docker-compose.yml:");
|
|
70
|
+
console.log(chalk.cyan(" environment:"));
|
|
71
|
+
console.log(chalk.cyan(" - ULPI_CLAUDE_CREDENTIALS=${ULPI_CLAUDE_CREDENTIALS}"));
|
|
72
|
+
console.log();
|
|
73
|
+
console.log(" 3. Or store as a Docker secret:");
|
|
74
|
+
console.log(chalk.cyan(` echo "${blob.slice(0, 20)}..." | docker secret create ulpi-claude-creds -`));
|
|
75
|
+
console.log();
|
|
76
|
+
console.log(chalk.yellow("Keep this blob safe \u2014 it contains your Claude Code session credentials."));
|
|
77
|
+
} catch (err) {
|
|
78
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
79
|
+
console.error(chalk.red(`Error: ${message}`));
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function authCheck(args) {
|
|
84
|
+
const blob = args[0] ?? process.env.ULPI_CLAUDE_CREDENTIALS;
|
|
85
|
+
if (!blob) {
|
|
86
|
+
console.error(chalk.red("Error: No credentials provided."));
|
|
87
|
+
console.log(" Provide as argument: ulpi auth check <blob>");
|
|
88
|
+
console.log(" Or set ULPI_CLAUDE_CREDENTIALS env var");
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
console.log(chalk.blue("Validating credentials..."));
|
|
92
|
+
const valid = validateCredentials(blob);
|
|
93
|
+
const expiry = getCredentialExpiry(blob);
|
|
94
|
+
if (valid) {
|
|
95
|
+
console.log(chalk.green("Credentials are valid."));
|
|
96
|
+
if (expiry) {
|
|
97
|
+
const expiryDate = new Date(expiry);
|
|
98
|
+
const now = /* @__PURE__ */ new Date();
|
|
99
|
+
const hoursLeft = (expiryDate.getTime() - now.getTime()) / (60 * 60 * 1e3);
|
|
100
|
+
if (hoursLeft < 0) {
|
|
101
|
+
console.log(chalk.red(` Expired: ${expiry}`));
|
|
102
|
+
console.log(chalk.yellow(" Run 'ulpi auth refresh' to re-authenticate."));
|
|
103
|
+
} else if (hoursLeft < 24) {
|
|
104
|
+
console.log(chalk.yellow(` Expires soon: ${expiry} (${Math.floor(hoursLeft)}h remaining)`));
|
|
105
|
+
console.log(chalk.yellow(" Consider running 'ulpi auth refresh' soon."));
|
|
106
|
+
} else {
|
|
107
|
+
console.log(chalk.green(` Expires: ${expiry}`));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
} else {
|
|
111
|
+
console.log(chalk.red("Credentials are invalid or corrupted."));
|
|
112
|
+
console.log("Run 'ulpi auth setup' to generate new credentials.");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export {
|
|
117
|
+
runAuth
|
|
118
|
+
};
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
updateEntryEnrichment,
|
|
50
50
|
withWorktree,
|
|
51
51
|
writeAndStage
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-JGBXM5NC.js";
|
|
53
53
|
import {
|
|
54
54
|
JsonSessionStore,
|
|
55
55
|
readEvents
|
|
@@ -74,7 +74,7 @@ import {
|
|
|
74
74
|
saveUlpiSettings
|
|
75
75
|
} from "./chunk-7LXY5UVC.js";
|
|
76
76
|
|
|
77
|
-
// ../api/dist/chunk-
|
|
77
|
+
// ../api/dist/chunk-P4BERD2G.js
|
|
78
78
|
import * as http from "http";
|
|
79
79
|
import * as fs12 from "fs";
|
|
80
80
|
import * as path9 from "path";
|
|
@@ -394,33 +394,51 @@ async function putUsernameSettings(ctx) {
|
|
|
394
394
|
resolvedHistoryBranch: getHistoryBranch()
|
|
395
395
|
}, 200, ctx.req);
|
|
396
396
|
}
|
|
397
|
+
function yamlEscapeString(s) {
|
|
398
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
399
|
+
}
|
|
397
400
|
function writeYamlFields(obj, lines, indent) {
|
|
398
401
|
const pad = " ".repeat(indent);
|
|
399
402
|
for (const [k, v] of Object.entries(obj)) {
|
|
400
403
|
if (k === "id" || k === "type" || k === "source") continue;
|
|
401
404
|
if (typeof v === "string") {
|
|
402
|
-
lines.push(`${pad}${k}: "${v}"`);
|
|
405
|
+
lines.push(`${pad}${k}: "${yamlEscapeString(v)}"`);
|
|
403
406
|
} else if (typeof v === "boolean" || typeof v === "number") {
|
|
404
407
|
lines.push(`${pad}${k}: ${v}`);
|
|
405
408
|
} else if (Array.isArray(v)) {
|
|
406
409
|
lines.push(`${pad}${k}:`);
|
|
407
410
|
for (const item of v) {
|
|
408
411
|
if (typeof item === "string") {
|
|
409
|
-
lines.push(`${pad} - "${item}"`);
|
|
412
|
+
lines.push(`${pad} - "${yamlEscapeString(item)}"`);
|
|
413
|
+
} else if (item && typeof item === "object") {
|
|
414
|
+
const entries = Object.entries(item);
|
|
415
|
+
if (entries.length > 0) {
|
|
416
|
+
const [firstKey, firstVal] = entries[0];
|
|
417
|
+
lines.push(`${pad} - ${firstKey}: ${formatScalar(firstVal)}`);
|
|
418
|
+
for (let i = 1; i < entries.length; i++) {
|
|
419
|
+
const [ek, ev] = entries[i];
|
|
420
|
+
lines.push(`${pad} ${ek}: ${formatScalar(ev)}`);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
410
423
|
}
|
|
411
424
|
}
|
|
412
425
|
}
|
|
413
426
|
}
|
|
414
427
|
}
|
|
428
|
+
function formatScalar(v) {
|
|
429
|
+
if (typeof v === "string") return `"${yamlEscapeString(v)}"`;
|
|
430
|
+
if (typeof v === "boolean" || typeof v === "number") return String(v);
|
|
431
|
+
return `"${String(v)}"`;
|
|
432
|
+
}
|
|
415
433
|
function writeRulesConfig(rulesPath, config) {
|
|
416
434
|
const lines = [
|
|
417
435
|
"# ULPI \u2014 Rules Configuration",
|
|
418
436
|
"# Generated via Web UI",
|
|
419
437
|
"",
|
|
420
438
|
"project:",
|
|
421
|
-
` name: "${config.project.name}"`,
|
|
422
|
-
` runtime: "${config.project.runtime}"`,
|
|
423
|
-
` package_manager: "${config.project.package_manager}"`,
|
|
439
|
+
` name: "${yamlEscapeString(config.project.name)}"`,
|
|
440
|
+
` runtime: "${yamlEscapeString(config.project.runtime)}"`,
|
|
441
|
+
` package_manager: "${yamlEscapeString(config.project.package_manager)}"`,
|
|
424
442
|
""
|
|
425
443
|
];
|
|
426
444
|
const sections = [
|
|
@@ -2245,7 +2263,7 @@ async function exportObsidian(ctx) {
|
|
|
2245
2263
|
jsonResponse(ctx.res, { format: "obsidian", content: md }, 200, ctx.req);
|
|
2246
2264
|
}
|
|
2247
2265
|
async function getEngine() {
|
|
2248
|
-
return await import("./dist-
|
|
2266
|
+
return await import("./dist-CB5D5LMO.js");
|
|
2249
2267
|
}
|
|
2250
2268
|
var runningPipelines = /* @__PURE__ */ new Map();
|
|
2251
2269
|
var activeWatchers = /* @__PURE__ */ new Map();
|
|
@@ -2551,7 +2569,7 @@ async function codemapActionHandler(ctx) {
|
|
|
2551
2569
|
}
|
|
2552
2570
|
}
|
|
2553
2571
|
async function getEngine2() {
|
|
2554
|
-
return await import("./dist-
|
|
2572
|
+
return await import("./dist-GJYT2OQV.js");
|
|
2555
2573
|
}
|
|
2556
2574
|
async function memoryStatusHandler(ctx) {
|
|
2557
2575
|
try {
|
|
@@ -2559,7 +2577,8 @@ async function memoryStatusHandler(ctx) {
|
|
|
2559
2577
|
const stats = await engine.getMemoryStats(ctx.projectDir);
|
|
2560
2578
|
const config = engine.loadMemoryConfig(ctx.projectDir);
|
|
2561
2579
|
const initialized = engine.isMemoryInitialized(ctx.projectDir);
|
|
2562
|
-
|
|
2580
|
+
const classifyProgress = engine.readClassifyBatchProgress(ctx.projectDir);
|
|
2581
|
+
jsonResponse(ctx.res, { stats, config, initialized, classifyProgress }, 200, ctx.req);
|
|
2563
2582
|
} catch (err) {
|
|
2564
2583
|
const message = err instanceof Error ? err.message : "Failed to get memory status";
|
|
2565
2584
|
jsonResponse(ctx.res, { error: message }, 500, ctx.req);
|
|
@@ -2739,7 +2758,7 @@ async function memoryActionHandler(ctx) {
|
|
|
2739
2758
|
return;
|
|
2740
2759
|
}
|
|
2741
2760
|
const action = data.action;
|
|
2742
|
-
const validActions = ["init", "export", "import", "enable", "disable", "classify", "reindex"];
|
|
2761
|
+
const validActions = ["init", "export", "import", "enable", "disable", "classify", "classify-all", "classify-clear", "reindex"];
|
|
2743
2762
|
if (!validActions.includes(action)) {
|
|
2744
2763
|
jsonResponse(
|
|
2745
2764
|
ctx.res,
|
|
@@ -2796,6 +2815,32 @@ async function memoryActionHandler(ctx) {
|
|
|
2796
2815
|
jsonResponse(ctx.res, { ok: true, action, ...result }, 200, ctx.req);
|
|
2797
2816
|
return;
|
|
2798
2817
|
}
|
|
2818
|
+
case "classify-all": {
|
|
2819
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
2820
|
+
const ulpiBin = process.argv[1];
|
|
2821
|
+
const args = ["memory", "classify", "-p", ctx.projectDir];
|
|
2822
|
+
if (typeof data.branch === "string" && data.branch) {
|
|
2823
|
+
args.push("--branch", data.branch);
|
|
2824
|
+
}
|
|
2825
|
+
if (data.export) args.push("--export");
|
|
2826
|
+
const child = spawn4(process.execPath, [ulpiBin, ...args], {
|
|
2827
|
+
detached: true,
|
|
2828
|
+
stdio: "ignore",
|
|
2829
|
+
env: { ...process.env, ULPI_BG_CLASSIFY: "1" }
|
|
2830
|
+
});
|
|
2831
|
+
child.unref();
|
|
2832
|
+
jsonResponse(ctx.res, {
|
|
2833
|
+
ok: true,
|
|
2834
|
+
action,
|
|
2835
|
+
message: "Classification started"
|
|
2836
|
+
}, 200, ctx.req);
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
case "classify-clear": {
|
|
2840
|
+
engine.clearClassifyBatchProgress(ctx.projectDir);
|
|
2841
|
+
jsonResponse(ctx.res, { ok: true, action, message: "Classification progress cleared" }, 200, ctx.req);
|
|
2842
|
+
return;
|
|
2843
|
+
}
|
|
2799
2844
|
case "reindex": {
|
|
2800
2845
|
const result = await engine.reindexMemories(ctx.projectDir);
|
|
2801
2846
|
jsonResponse(ctx.res, { ok: true, action, ...result }, 200, ctx.req);
|
|
@@ -3457,7 +3502,7 @@ async function historyInitHandler(ctx) {
|
|
|
3457
3502
|
}
|
|
3458
3503
|
let gitHooksResult = { installed: [], skipped: [] };
|
|
3459
3504
|
try {
|
|
3460
|
-
const { installGitHooks } = await import("./dist-
|
|
3505
|
+
const { installGitHooks } = await import("./dist-QAU3LGJN.js");
|
|
3461
3506
|
const binaryPath = getBinaryPath();
|
|
3462
3507
|
gitHooksResult = installGitHooks(projectDir, binaryPath);
|
|
3463
3508
|
} catch {
|
|
@@ -3495,8 +3540,10 @@ async function historyBackfillHandler(ctx) {
|
|
|
3495
3540
|
} catch {
|
|
3496
3541
|
}
|
|
3497
3542
|
const limit = Math.min(options.limit ?? 20, 100);
|
|
3543
|
+
const branchOnly = options.branchOnly ?? false;
|
|
3498
3544
|
const {
|
|
3499
3545
|
listRecentCommits,
|
|
3546
|
+
listBranchOnlyCommits,
|
|
3500
3547
|
getCommitMetadata,
|
|
3501
3548
|
getCommitDiffStats,
|
|
3502
3549
|
getCommitRawDiff,
|
|
@@ -3506,8 +3553,8 @@ async function historyBackfillHandler(ctx) {
|
|
|
3506
3553
|
entryExists,
|
|
3507
3554
|
writeHistoryEntry,
|
|
3508
3555
|
DEFAULT_HISTORY_CONFIG
|
|
3509
|
-
} = await import("./dist-
|
|
3510
|
-
const commits = listRecentCommits(projectDir, limit);
|
|
3556
|
+
} = await import("./dist-QAU3LGJN.js");
|
|
3557
|
+
const commits = branchOnly ? listBranchOnlyCommits(projectDir, limit) : listRecentCommits(projectDir, limit);
|
|
3511
3558
|
if (commits.length === 0) {
|
|
3512
3559
|
jsonResponse(res, { captured: 0, skipped: 0, total: 0 }, 200, req);
|
|
3513
3560
|
return;
|
|
@@ -3830,7 +3877,7 @@ async function historyEntryTagsHandler(ctx) {
|
|
|
3830
3877
|
return;
|
|
3831
3878
|
}
|
|
3832
3879
|
try {
|
|
3833
|
-
const { updateEntryTags } = await import("./dist-
|
|
3880
|
+
const { updateEntryTags } = await import("./dist-QAU3LGJN.js");
|
|
3834
3881
|
await updateEntryTags(projectDir, sha, payload.tags);
|
|
3835
3882
|
jsonResponse(res, { success: true, sha, tags: payload.tags }, 200, req);
|
|
3836
3883
|
} catch (err) {
|
|
@@ -3846,7 +3893,7 @@ async function historyEntryTranscriptHandler(ctx) {
|
|
|
3846
3893
|
jsonResponse(res, { error: "History branch not initialized" }, 400, req);
|
|
3847
3894
|
return;
|
|
3848
3895
|
}
|
|
3849
|
-
const { readEntryTranscript } = await import("./dist-
|
|
3896
|
+
const { readEntryTranscript } = await import("./dist-QAU3LGJN.js");
|
|
3850
3897
|
const transcript = readEntryTranscript(projectDir, sha);
|
|
3851
3898
|
if (!transcript) {
|
|
3852
3899
|
jsonResponse(res, { error: "No transcript for this entry" }, 404, req);
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// ../../packages/ci-engine/dist/index.js
|
|
2
|
+
import * as fs4 from "fs";
|
|
3
|
+
import * as path3 from "path";
|
|
4
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
5
|
+
function buildPrompt(config, context) {
|
|
6
|
+
const sections = [];
|
|
7
|
+
sections.push("# Task");
|
|
8
|
+
sections.push("");
|
|
9
|
+
sections.push(config.instruction);
|
|
10
|
+
sections.push("");
|
|
11
|
+
if (context.prTitle || context.prBody) {
|
|
12
|
+
sections.push("# Pull Request Context");
|
|
13
|
+
sections.push("");
|
|
14
|
+
if (context.prTitle) sections.push(`**Title:** ${context.prTitle}`);
|
|
15
|
+
if (context.prBody) {
|
|
16
|
+
sections.push("");
|
|
17
|
+
sections.push(context.prBody);
|
|
18
|
+
}
|
|
19
|
+
sections.push("");
|
|
20
|
+
}
|
|
21
|
+
sections.push("# Branch Info");
|
|
22
|
+
sections.push("");
|
|
23
|
+
sections.push(`- **Working branch:** ${config.ref}`);
|
|
24
|
+
sections.push(`- **Base branch:** ${config.baseBranch}`);
|
|
25
|
+
sections.push(`- **Repository:** ${config.repoFullName}`);
|
|
26
|
+
sections.push("");
|
|
27
|
+
if (config.jiraContext || context.jiraContext) {
|
|
28
|
+
sections.push("# Jira Context");
|
|
29
|
+
sections.push("");
|
|
30
|
+
sections.push(config.jiraContext ?? context.jiraContext ?? "");
|
|
31
|
+
sections.push("");
|
|
32
|
+
}
|
|
33
|
+
sections.push("# Important Instructions");
|
|
34
|
+
sections.push("");
|
|
35
|
+
sections.push(
|
|
36
|
+
"- You are running in CI mode inside a worker container."
|
|
37
|
+
);
|
|
38
|
+
sections.push(
|
|
39
|
+
"- Work on the existing branch \u2014 do NOT create new branches."
|
|
40
|
+
);
|
|
41
|
+
sections.push(
|
|
42
|
+
"- Commit your changes with clear, descriptive commit messages."
|
|
43
|
+
);
|
|
44
|
+
sections.push("- Run tests if a test runner is configured.");
|
|
45
|
+
sections.push(
|
|
46
|
+
"- Do NOT push to the remote \u2014 the orchestrator will handle pushing."
|
|
47
|
+
);
|
|
48
|
+
sections.push("");
|
|
49
|
+
return sections.join("\n");
|
|
50
|
+
}
|
|
51
|
+
function extractCredentials(claudeConfigDir) {
|
|
52
|
+
const configDir = claudeConfigDir ?? path3.join(process.env.HOME ?? "", ".claude");
|
|
53
|
+
if (!fs4.existsSync(configDir)) {
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Claude config directory not found: ${configDir}`
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const tarOutput = execFileSync2(
|
|
59
|
+
"tar",
|
|
60
|
+
["-czf", "-", "-C", configDir, "."],
|
|
61
|
+
{
|
|
62
|
+
encoding: "buffer",
|
|
63
|
+
timeout: 3e4,
|
|
64
|
+
maxBuffer: 50 * 1024 * 1024
|
|
65
|
+
// 50MB limit
|
|
66
|
+
}
|
|
67
|
+
);
|
|
68
|
+
return tarOutput.toString("base64");
|
|
69
|
+
}
|
|
70
|
+
function writeCredentials(blob, targetDir) {
|
|
71
|
+
fs4.mkdirSync(targetDir, { recursive: true });
|
|
72
|
+
const tarBuffer = Buffer.from(blob, "base64");
|
|
73
|
+
execFileSync2("tar", ["-xzf", "-", "-C", targetDir], {
|
|
74
|
+
input: tarBuffer,
|
|
75
|
+
timeout: 3e4
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function validateCredentials(blob) {
|
|
79
|
+
const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-check-");
|
|
80
|
+
try {
|
|
81
|
+
writeCredentials(blob, tmpDir);
|
|
82
|
+
const files = fs4.readdirSync(tmpDir);
|
|
83
|
+
return files.length > 0;
|
|
84
|
+
} catch {
|
|
85
|
+
return false;
|
|
86
|
+
} finally {
|
|
87
|
+
try {
|
|
88
|
+
fs4.rmSync(tmpDir, { recursive: true, force: true });
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function getCredentialExpiry(blob) {
|
|
94
|
+
const tmpDir = fs4.mkdtempSync("/tmp/ulpi-claude-expiry-");
|
|
95
|
+
try {
|
|
96
|
+
writeCredentials(blob, tmpDir);
|
|
97
|
+
const authFile = path3.join(tmpDir, ".credentials.json");
|
|
98
|
+
if (fs4.existsSync(authFile)) {
|
|
99
|
+
try {
|
|
100
|
+
const data = JSON.parse(
|
|
101
|
+
fs4.readFileSync(authFile, "utf-8")
|
|
102
|
+
);
|
|
103
|
+
if (data.expiresAt) return data.expiresAt;
|
|
104
|
+
if (data.expires_at) return data.expires_at;
|
|
105
|
+
} catch {
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return void 0;
|
|
109
|
+
} finally {
|
|
110
|
+
try {
|
|
111
|
+
fs4.rmSync(tmpDir, { recursive: true, force: true });
|
|
112
|
+
} catch {
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export {
|
|
118
|
+
buildPrompt,
|
|
119
|
+
extractCredentials,
|
|
120
|
+
validateCredentials,
|
|
121
|
+
getCredentialExpiry
|
|
122
|
+
};
|
|
@@ -345,6 +345,47 @@ function listRecentCommits(projectDir, maxCount = 20) {
|
|
|
345
345
|
return [];
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
|
+
function listBranchOnlyCommits(projectDir, maxCount = 50) {
|
|
349
|
+
try {
|
|
350
|
+
let currentBranch;
|
|
351
|
+
try {
|
|
352
|
+
currentBranch = gitExec(projectDir, ["rev-parse", "--abbrev-ref", "HEAD"]);
|
|
353
|
+
} catch {
|
|
354
|
+
return listRecentCommits(projectDir, maxCount);
|
|
355
|
+
}
|
|
356
|
+
let defaultBranch = "main";
|
|
357
|
+
try {
|
|
358
|
+
const ref = gitExec(projectDir, ["symbolic-ref", "refs/remotes/origin/HEAD"]);
|
|
359
|
+
defaultBranch = ref.replace("refs/remotes/origin/", "");
|
|
360
|
+
} catch {
|
|
361
|
+
try {
|
|
362
|
+
gitExec(projectDir, ["rev-parse", "--verify", "refs/heads/main"]);
|
|
363
|
+
defaultBranch = "main";
|
|
364
|
+
} catch {
|
|
365
|
+
try {
|
|
366
|
+
gitExec(projectDir, ["rev-parse", "--verify", "refs/heads/master"]);
|
|
367
|
+
defaultBranch = "master";
|
|
368
|
+
} catch {
|
|
369
|
+
return listRecentCommits(projectDir, maxCount);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (currentBranch === defaultBranch) {
|
|
374
|
+
return listRecentCommits(projectDir, maxCount);
|
|
375
|
+
}
|
|
376
|
+
const raw = gitExec(projectDir, [
|
|
377
|
+
"rev-list",
|
|
378
|
+
"--reverse",
|
|
379
|
+
`--max-count=${maxCount}`,
|
|
380
|
+
"HEAD",
|
|
381
|
+
"--not",
|
|
382
|
+
defaultBranch
|
|
383
|
+
]);
|
|
384
|
+
return raw ? raw.split("\n").filter(Boolean) : [];
|
|
385
|
+
} catch {
|
|
386
|
+
return listRecentCommits(projectDir, maxCount);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
348
389
|
function readFromBranch(projectDir, filePath, branchName) {
|
|
349
390
|
branchName ??= getHistoryBranch();
|
|
350
391
|
validateBranchPath(filePath);
|
|
@@ -1575,6 +1616,7 @@ export {
|
|
|
1575
1616
|
getCurrentHead,
|
|
1576
1617
|
listCommitsBetween,
|
|
1577
1618
|
listRecentCommits,
|
|
1619
|
+
listBranchOnlyCommits,
|
|
1578
1620
|
readFromBranch,
|
|
1579
1621
|
listBranchDir,
|
|
1580
1622
|
getWorktreeId,
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
|
-
createEmbedder
|
|
3
|
-
|
|
2
|
+
createEmbedder,
|
|
3
|
+
loadCodemapIgnore,
|
|
4
|
+
matchesDenyPattern
|
|
5
|
+
} from "./chunk-5J6NLQUN.js";
|
|
4
6
|
import {
|
|
5
7
|
commitInWorktree,
|
|
6
8
|
copyAndStage,
|
|
7
9
|
historyBranchExists,
|
|
8
10
|
withWorktree,
|
|
9
11
|
writeAndStage
|
|
10
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JGBXM5NC.js";
|
|
11
13
|
import {
|
|
12
14
|
readEvents
|
|
13
15
|
} from "./chunk-YM2HV4IA.js";
|
|
@@ -53,6 +55,8 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
53
55
|
import * as fs9 from "fs";
|
|
54
56
|
import * as os3 from "os";
|
|
55
57
|
import * as path9 from "path";
|
|
58
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync8, unlinkSync as unlinkSync3, existsSync as existsSync10 } from "fs";
|
|
59
|
+
import { join as join8 } from "path";
|
|
56
60
|
var DEFAULT_MEMORY_CONFIG = MemoryConfigSchema.parse({});
|
|
57
61
|
function loadMemoryConfig(projectDir) {
|
|
58
62
|
const configPath = memoryConfigFile(projectDir);
|
|
@@ -411,11 +415,16 @@ var TRIVIAL_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
411
415
|
"date",
|
|
412
416
|
"wc"
|
|
413
417
|
]);
|
|
414
|
-
function filterSignificantEvents(events) {
|
|
418
|
+
function filterSignificantEvents(events, projectDir) {
|
|
419
|
+
const ignorePatterns = projectDir ? loadCodemapIgnore(projectDir) : [];
|
|
415
420
|
return events.filter((ev) => {
|
|
416
421
|
if (ev.event === "tool_blocked" || ev.event === "permission_denied" || ev.event === "postcondition_failed") {
|
|
417
422
|
return true;
|
|
418
423
|
}
|
|
424
|
+
if (ev.filePath && ignorePatterns.length > 0 && projectDir) {
|
|
425
|
+
const rel = ev.filePath.startsWith(projectDir) ? ev.filePath.slice(projectDir.length + 1) : ev.filePath;
|
|
426
|
+
if (matchesDenyPattern(rel, ignorePatterns)) return false;
|
|
427
|
+
}
|
|
419
428
|
if (ev.event === "tool_used" && ev.toolName === "Read") {
|
|
420
429
|
return false;
|
|
421
430
|
}
|
|
@@ -1031,7 +1040,7 @@ async function classifySession(projectDir, sessionId, onProgress) {
|
|
|
1031
1040
|
};
|
|
1032
1041
|
}
|
|
1033
1042
|
const unprocessedEvents = allEvents.slice(startIdx);
|
|
1034
|
-
const filteredEvents = config.classifier.filterNoiseEvents ? filterSignificantEvents(unprocessedEvents) : unprocessedEvents;
|
|
1043
|
+
const filteredEvents = config.classifier.filterNoiseEvents ? filterSignificantEvents(unprocessedEvents, projectDir) : unprocessedEvents;
|
|
1035
1044
|
const meta = loadSessionMeta(projectDir, sessionId);
|
|
1036
1045
|
if (!isSessionSignificant(meta, filteredEvents, config.classifier.minSignificantEvents)) {
|
|
1037
1046
|
saveWatermark(projectDir, {
|
|
@@ -1578,6 +1587,45 @@ function copyDirRecursiveImport(srcDir, destDir) {
|
|
|
1578
1587
|
}
|
|
1579
1588
|
return { fileCount, totalBytes };
|
|
1580
1589
|
}
|
|
1590
|
+
function progressFile(projectDir) {
|
|
1591
|
+
return join8(projectMemoryDir(projectDir), "classify-progress.json");
|
|
1592
|
+
}
|
|
1593
|
+
var STALE_THRESHOLD_MS = 2 * 60 * 1e3;
|
|
1594
|
+
function writeClassifyBatchProgress(projectDir, progress) {
|
|
1595
|
+
try {
|
|
1596
|
+
const p = { ...progress, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
1597
|
+
writeFileSync8(progressFile(projectDir), JSON.stringify(p, null, 2));
|
|
1598
|
+
} catch {
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
function readClassifyBatchProgress(projectDir) {
|
|
1602
|
+
const file = progressFile(projectDir);
|
|
1603
|
+
if (!existsSync10(file)) return null;
|
|
1604
|
+
try {
|
|
1605
|
+
const raw = readFileSync8(file, "utf-8");
|
|
1606
|
+
const data = JSON.parse(raw);
|
|
1607
|
+
if (data.status === "classifying" && data.updatedAt) {
|
|
1608
|
+
const age = Date.now() - new Date(data.updatedAt).getTime();
|
|
1609
|
+
if (age > STALE_THRESHOLD_MS) {
|
|
1610
|
+
return {
|
|
1611
|
+
...data,
|
|
1612
|
+
status: "error",
|
|
1613
|
+
error: "Classification process appears to have stopped unexpectedly."
|
|
1614
|
+
};
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
return data;
|
|
1618
|
+
} catch {
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
function clearClassifyBatchProgress(projectDir) {
|
|
1623
|
+
try {
|
|
1624
|
+
const file = progressFile(projectDir);
|
|
1625
|
+
if (existsSync10(file)) unlinkSync3(file);
|
|
1626
|
+
} catch {
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1581
1629
|
|
|
1582
1630
|
export {
|
|
1583
1631
|
DEFAULT_MEMORY_CONFIG,
|
|
@@ -1626,5 +1674,8 @@ export {
|
|
|
1626
1674
|
memoryBranchExists,
|
|
1627
1675
|
initMemoryBranch,
|
|
1628
1676
|
exportMemories,
|
|
1629
|
-
importMemories
|
|
1677
|
+
importMemories,
|
|
1678
|
+
writeClassifyBatchProgress,
|
|
1679
|
+
readClassifyBatchProgress,
|
|
1680
|
+
clearClassifyBatchProgress
|
|
1630
1681
|
};
|