devark-cli 0.1.0 → 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/checksums.sha256 +2 -2
- package/dist/index.js +153 -30
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/checksums.sha256
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
4e5508903ce1d478e710b2b659be710be26dd3e4233ac1fde8fce9b6a81cb37a index.js
|
|
2
|
+
1af5bc655dd375bcbda2a0274b9441baeebdf921d615302c3c224706f34675cf index.js.map
|
|
3
3
|
137b0f6da8ab3a82dd96e536c9de1c0162f51d5450895af16e935906975671a8 report-template.html
|
package/dist/index.js
CHANGED
|
@@ -2481,7 +2481,7 @@ var require_package = __commonJS({
|
|
|
2481
2481
|
"package.json"(exports2, module2) {
|
|
2482
2482
|
module2.exports = {
|
|
2483
2483
|
name: "devark-cli",
|
|
2484
|
-
version: "0.1.
|
|
2484
|
+
version: "0.1.3",
|
|
2485
2485
|
description: "DevArk - Developer Productivity CLI",
|
|
2486
2486
|
bin: {
|
|
2487
2487
|
devark: "./bin/devark.js"
|
|
@@ -2668,7 +2668,7 @@ async function gatherCLIConfiguration() {
|
|
|
2668
2668
|
return null;
|
|
2669
2669
|
}
|
|
2670
2670
|
}
|
|
2671
|
-
var import_axios, import_crypto2, SecureApiClient, apiClient;
|
|
2671
|
+
var import_axios, import_crypto2, TARGET_BATCH_SIZE_BYTES, BUFFER_PERCENT, SecureApiClient, apiClient;
|
|
2672
2672
|
var init_api_client = __esm({
|
|
2673
2673
|
"src/lib/api-client.ts"() {
|
|
2674
2674
|
"use strict";
|
|
@@ -2681,6 +2681,8 @@ var init_api_client = __esm({
|
|
|
2681
2681
|
init_network_errors();
|
|
2682
2682
|
init_claude_settings_manager();
|
|
2683
2683
|
import_crypto2 = __toESM(require("crypto"));
|
|
2684
|
+
TARGET_BATCH_SIZE_BYTES = 500 * 1024;
|
|
2685
|
+
BUFFER_PERCENT = 0.2;
|
|
2684
2686
|
SecureApiClient = class {
|
|
2685
2687
|
client;
|
|
2686
2688
|
requestCount = 0;
|
|
@@ -2894,20 +2896,45 @@ var init_api_client = __esm({
|
|
|
2894
2896
|
return { valid: false };
|
|
2895
2897
|
}
|
|
2896
2898
|
}
|
|
2899
|
+
estimateSessionSize(session) {
|
|
2900
|
+
return Buffer.byteLength(JSON.stringify(session));
|
|
2901
|
+
}
|
|
2902
|
+
createSizeBatches(sessions, targetSizeBytes = TARGET_BATCH_SIZE_BYTES, bufferPercent = BUFFER_PERCENT) {
|
|
2903
|
+
const effectiveTarget = targetSizeBytes * (1 - bufferPercent);
|
|
2904
|
+
const batches = [];
|
|
2905
|
+
let currentBatch = [];
|
|
2906
|
+
let currentSize = 0;
|
|
2907
|
+
for (const session of sessions) {
|
|
2908
|
+
const sessionSize = this.estimateSessionSize(session);
|
|
2909
|
+
if (currentBatch.length > 0 && currentSize + sessionSize > effectiveTarget) {
|
|
2910
|
+
batches.push(currentBatch);
|
|
2911
|
+
currentBatch = [session];
|
|
2912
|
+
currentSize = sessionSize;
|
|
2913
|
+
} else {
|
|
2914
|
+
currentBatch.push(session);
|
|
2915
|
+
currentSize += sessionSize;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
if (currentBatch.length > 0) {
|
|
2919
|
+
batches.push(currentBatch);
|
|
2920
|
+
}
|
|
2921
|
+
return batches;
|
|
2922
|
+
}
|
|
2897
2923
|
async uploadSessions(sessions, onProgress) {
|
|
2898
2924
|
const cliConfig = await gatherCLIConfiguration();
|
|
2899
2925
|
const sanitizedSessions = sessions.map((session) => this.sanitizeSession(session));
|
|
2900
|
-
const
|
|
2901
|
-
const chunks = [];
|
|
2902
|
-
for (let i = 0; i < sanitizedSessions.length; i += CHUNK_SIZE) {
|
|
2903
|
-
chunks.push(sanitizedSessions.slice(i, i + CHUNK_SIZE));
|
|
2904
|
-
}
|
|
2926
|
+
const chunks = this.createSizeBatches(sanitizedSessions);
|
|
2905
2927
|
const results = [];
|
|
2906
2928
|
let uploadedCount = 0;
|
|
2907
2929
|
let uploadedSizeKB = 0;
|
|
2908
2930
|
const totalSize = Buffer.byteLength(JSON.stringify(sanitizedSessions)) / 1024;
|
|
2909
2931
|
if (process.env.DEVARK_DEBUG === "true") {
|
|
2910
|
-
console.log(
|
|
2932
|
+
console.log(
|
|
2933
|
+
"[DEBUG] Uploading in",
|
|
2934
|
+
chunks.length,
|
|
2935
|
+
"size-based batches",
|
|
2936
|
+
`(Total: ${totalSize.toFixed(2)} KB, Target: ~${TARGET_BATCH_SIZE_BYTES / 1024}KB per batch)`
|
|
2937
|
+
);
|
|
2911
2938
|
}
|
|
2912
2939
|
for (let i = 0; i < chunks.length; i++) {
|
|
2913
2940
|
const chunk = chunks[i];
|
|
@@ -3060,6 +3087,25 @@ var init_api_client = __esm({
|
|
|
3060
3087
|
}
|
|
3061
3088
|
return response.data;
|
|
3062
3089
|
}
|
|
3090
|
+
/**
|
|
3091
|
+
* Get the timestamp of the user's most recent session for incremental sync.
|
|
3092
|
+
* @returns Last session timestamp (ISO string) and ID, or null if no sessions exist
|
|
3093
|
+
*/
|
|
3094
|
+
async getLastSessionDate() {
|
|
3095
|
+
var _a;
|
|
3096
|
+
try {
|
|
3097
|
+
const response = await this.client.get("/api/sessions/last");
|
|
3098
|
+
return {
|
|
3099
|
+
lastSessionTimestamp: response.data.lastSessionTimestamp || null,
|
|
3100
|
+
lastSessionId: response.data.lastSessionId || null
|
|
3101
|
+
};
|
|
3102
|
+
} catch (error) {
|
|
3103
|
+
if (((_a = error.response) == null ? void 0 : _a.status) === 404) {
|
|
3104
|
+
return { lastSessionTimestamp: null, lastSessionId: null };
|
|
3105
|
+
}
|
|
3106
|
+
throw error;
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3063
3109
|
getBaseUrl() {
|
|
3064
3110
|
return this.client.defaults.baseURL || "http://localhost:3000";
|
|
3065
3111
|
}
|
|
@@ -4010,10 +4056,14 @@ var init_send_orchestrator = __esm({
|
|
|
4010
4056
|
return this.readSelectedSessions(options.selectedSessions);
|
|
4011
4057
|
}
|
|
4012
4058
|
if (options.all) {
|
|
4013
|
-
const
|
|
4059
|
+
const serverSince = await this.getServerLastSessionDate();
|
|
4060
|
+
if (serverSince) {
|
|
4061
|
+
logger.debug(`Using server timestamp for incremental sync: ${serverSince.toISOString()}`);
|
|
4062
|
+
}
|
|
4063
|
+
const sessions2 = await readClaudeSessions({ since: serverSince });
|
|
4014
4064
|
return sessions2;
|
|
4015
4065
|
}
|
|
4016
|
-
const sinceDate = this.
|
|
4066
|
+
const sinceDate = await this.determineSinceDateWithServerFallback(options);
|
|
4017
4067
|
if (options.claudeProjectDir && options.claudeProjectDir.trim() !== "") {
|
|
4018
4068
|
return this.loadProjectSessions(options.claudeProjectDir, sinceDate);
|
|
4019
4069
|
}
|
|
@@ -4036,6 +4086,34 @@ var init_send_orchestrator = __esm({
|
|
|
4036
4086
|
}
|
|
4037
4087
|
return void 0;
|
|
4038
4088
|
}
|
|
4089
|
+
/**
|
|
4090
|
+
* Get the server's last session timestamp for incremental sync.
|
|
4091
|
+
* Returns undefined on error to allow fallback to local sync state.
|
|
4092
|
+
*/
|
|
4093
|
+
async getServerLastSessionDate() {
|
|
4094
|
+
try {
|
|
4095
|
+
const result = await apiClient.getLastSessionDate();
|
|
4096
|
+
if (result.lastSessionTimestamp) {
|
|
4097
|
+
return new Date(result.lastSessionTimestamp);
|
|
4098
|
+
}
|
|
4099
|
+
return void 0;
|
|
4100
|
+
} catch (error) {
|
|
4101
|
+
logger.warn(`Failed to get server last session date, falling back to local sync: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4102
|
+
return void 0;
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
/**
|
|
4106
|
+
* Determine since date with server-side incremental sync fallback.
|
|
4107
|
+
* First tries server timestamp, then falls back to local sync state.
|
|
4108
|
+
*/
|
|
4109
|
+
async determineSinceDateWithServerFallback(options) {
|
|
4110
|
+
const serverSince = await this.getServerLastSessionDate();
|
|
4111
|
+
if (serverSince) {
|
|
4112
|
+
logger.debug(`Using server timestamp for incremental sync: ${serverSince.toISOString()}`);
|
|
4113
|
+
return serverSince;
|
|
4114
|
+
}
|
|
4115
|
+
return this.determineSinceDate(options);
|
|
4116
|
+
}
|
|
4039
4117
|
async loadProjectSessions(claudeProjectDir, sinceDate) {
|
|
4040
4118
|
const dirName = parseProjectName(claudeProjectDir);
|
|
4041
4119
|
const project = await analyzeProject(claudeProjectDir, dirName);
|
|
@@ -11422,6 +11500,20 @@ var manual_sync_menu_exports = {};
|
|
|
11422
11500
|
__export(manual_sync_menu_exports, {
|
|
11423
11501
|
showManualSyncMenu: () => showManualSyncMenu
|
|
11424
11502
|
});
|
|
11503
|
+
async function getServerLastSessionDate() {
|
|
11504
|
+
try {
|
|
11505
|
+
if (!await isAuthenticated()) {
|
|
11506
|
+
return void 0;
|
|
11507
|
+
}
|
|
11508
|
+
const result = await apiClient.getLastSessionDate();
|
|
11509
|
+
if (result.lastSessionTimestamp) {
|
|
11510
|
+
return new Date(result.lastSessionTimestamp);
|
|
11511
|
+
}
|
|
11512
|
+
return void 0;
|
|
11513
|
+
} catch {
|
|
11514
|
+
return void 0;
|
|
11515
|
+
}
|
|
11516
|
+
}
|
|
11425
11517
|
async function showManualSyncMenu() {
|
|
11426
11518
|
console.log("");
|
|
11427
11519
|
console.log(colors.primary("Manual sync to cloud"));
|
|
@@ -11562,22 +11654,39 @@ async function showManualSyncMenu() {
|
|
|
11562
11654
|
}
|
|
11563
11655
|
}
|
|
11564
11656
|
case "all": {
|
|
11565
|
-
const
|
|
11566
|
-
|
|
11567
|
-
|
|
11568
|
-
|
|
11569
|
-
|
|
11570
|
-
{
|
|
11571
|
-
|
|
11572
|
-
|
|
11573
|
-
|
|
11574
|
-
|
|
11657
|
+
const spinner = createSpinner("Calculating sessions to sync...").start();
|
|
11658
|
+
try {
|
|
11659
|
+
const serverSince = await getServerLastSessionDate();
|
|
11660
|
+
const sessions = await readClaudeSessions({ since: serverSince });
|
|
11661
|
+
const validSessions = sessions.filter((s) => s.duration >= 240);
|
|
11662
|
+
const projectPaths = new Set(validSessions.map((s) => {
|
|
11663
|
+
var _a;
|
|
11664
|
+
return (_a = s.sourceFile) == null ? void 0 : _a.claudeProjectPath;
|
|
11665
|
+
}).filter(Boolean));
|
|
11666
|
+
spinner.stop();
|
|
11667
|
+
console.log("");
|
|
11668
|
+
if (serverSince) {
|
|
11669
|
+
console.log(colors.info(`This will sync ${validSessions.length} new sessions from ${projectPaths.size} projects`));
|
|
11670
|
+
console.log(colors.subdued(`(Sessions since ${serverSince.toLocaleDateString()})`));
|
|
11671
|
+
} else {
|
|
11672
|
+
console.log(colors.info(`This will sync ${validSessions.length} sessions from ${projectPaths.size} projects.`));
|
|
11575
11673
|
}
|
|
11576
|
-
|
|
11577
|
-
|
|
11674
|
+
const { confirm } = await import_inquirer14.default.prompt([
|
|
11675
|
+
{
|
|
11676
|
+
type: "confirm",
|
|
11677
|
+
name: "confirm",
|
|
11678
|
+
message: `Continue with syncing ${validSessions.length} sessions?`,
|
|
11679
|
+
default: true
|
|
11680
|
+
}
|
|
11681
|
+
]);
|
|
11682
|
+
if (!confirm) {
|
|
11683
|
+
return { type: "cancel" };
|
|
11684
|
+
}
|
|
11685
|
+
return { type: "all" };
|
|
11686
|
+
} catch (error) {
|
|
11687
|
+
spinner.fail(colors.error("Failed to calculate sessions"));
|
|
11578
11688
|
return { type: "cancel" };
|
|
11579
11689
|
}
|
|
11580
|
-
return { type: "all" };
|
|
11581
11690
|
}
|
|
11582
11691
|
default:
|
|
11583
11692
|
return { type: "cancel" };
|
|
@@ -11595,6 +11704,8 @@ var init_manual_sync_menu = __esm({
|
|
|
11595
11704
|
init_claude();
|
|
11596
11705
|
init_project_display();
|
|
11597
11706
|
init_ui();
|
|
11707
|
+
init_api_client();
|
|
11708
|
+
init_token();
|
|
11598
11709
|
}
|
|
11599
11710
|
});
|
|
11600
11711
|
|
|
@@ -15608,7 +15719,7 @@ function createSection(title, content, options) {
|
|
|
15608
15719
|
lines.push(color(chars.bl + chars.h.repeat(width - 2) + chars.br));
|
|
15609
15720
|
return lines.join("\n");
|
|
15610
15721
|
}
|
|
15611
|
-
function createCloudStatusSection(status2) {
|
|
15722
|
+
function createCloudStatusSection(status2, serverLastSessionDate) {
|
|
15612
15723
|
const content = [];
|
|
15613
15724
|
const connectionIcon = status2.connected ? icons.success : icons.error;
|
|
15614
15725
|
const connectionColor = status2.connected ? colors.success : colors.error;
|
|
@@ -15636,12 +15747,13 @@ function createCloudStatusSection(status2) {
|
|
|
15636
15747
|
let syncColor = colors.primary;
|
|
15637
15748
|
let syncText = "Never synced";
|
|
15638
15749
|
let syncProject = "";
|
|
15639
|
-
|
|
15640
|
-
|
|
15750
|
+
const lastSyncDate = serverLastSessionDate || status2.lastSync;
|
|
15751
|
+
if (lastSyncDate) {
|
|
15752
|
+
const timeSince = (/* @__PURE__ */ new Date()).getTime() - lastSyncDate.getTime();
|
|
15641
15753
|
const minutes = Math.floor(timeSince / 6e4);
|
|
15642
15754
|
const hours = Math.floor(minutes / 60);
|
|
15643
15755
|
const days = Math.floor(hours / 24);
|
|
15644
|
-
if (status2.lastSyncProject) {
|
|
15756
|
+
if (!serverLastSessionDate && status2.lastSyncProject) {
|
|
15645
15757
|
syncProject = `${status2.lastSyncProject} `;
|
|
15646
15758
|
}
|
|
15647
15759
|
if (days > 0) {
|
|
@@ -15722,9 +15834,9 @@ function createLocalEngineSection(engine) {
|
|
|
15722
15834
|
color: sectionColor
|
|
15723
15835
|
});
|
|
15724
15836
|
}
|
|
15725
|
-
async function createStatusDashboard(cloud, local) {
|
|
15837
|
+
async function createStatusDashboard(cloud, local, serverLastSessionDate) {
|
|
15726
15838
|
const sections = [];
|
|
15727
|
-
sections.push(createCloudStatusSection(cloud));
|
|
15839
|
+
sections.push(createCloudStatusSection(cloud, serverLastSessionDate));
|
|
15728
15840
|
sections.push("");
|
|
15729
15841
|
sections.push(createLocalEngineSection(local));
|
|
15730
15842
|
return sections.join("\n");
|
|
@@ -16135,7 +16247,18 @@ async function showMainMenu(state, packageUpdateInfo2) {
|
|
|
16135
16247
|
statusLineStatus: state.statusLineStatus,
|
|
16136
16248
|
configPath: "~/.claude/config"
|
|
16137
16249
|
};
|
|
16138
|
-
|
|
16250
|
+
let serverLastSessionDate;
|
|
16251
|
+
if (state.hasAuth) {
|
|
16252
|
+
try {
|
|
16253
|
+
const { apiClient: apiClient2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
|
|
16254
|
+
const result = await apiClient2.getLastSessionDate();
|
|
16255
|
+
if (result.lastSessionTimestamp) {
|
|
16256
|
+
serverLastSessionDate = new Date(result.lastSessionTimestamp);
|
|
16257
|
+
}
|
|
16258
|
+
} catch {
|
|
16259
|
+
}
|
|
16260
|
+
}
|
|
16261
|
+
console.log(await createStatusDashboard(cloudStatus, localEngine, serverLastSessionDate));
|
|
16139
16262
|
console.log("");
|
|
16140
16263
|
const context = {
|
|
16141
16264
|
state: state.state,
|