@gowelle/stint-agent 1.2.41 → 1.2.43
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/{StatusDashboard-VKR5SXS4.js → StatusDashboard-QOFG2BEM.js} +2 -2
- package/dist/api-7EO4NO7A.js +7 -0
- package/dist/{chunk-IJAVMAOZ.js → chunk-H7MANPCF.js} +1 -1
- package/dist/{chunk-YLZKGUKM.js → chunk-IYPRVBYG.js} +1 -1
- package/dist/{chunk-NTG3X2HK.js → chunk-KGDXQOLB.js} +40 -10
- package/dist/{chunk-H4PLSM7I.js → chunk-XWCVS4R6.js} +2 -2
- package/dist/daemon/runner.js +149 -5
- package/dist/index.js +6 -6
- package/package.json +1 -1
- package/dist/api-QDJ4MDEI.js +0 -7
|
@@ -2,10 +2,10 @@ import {
|
|
|
2
2
|
gitService,
|
|
3
3
|
projectService,
|
|
4
4
|
validatePidFile
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-IYPRVBYG.js";
|
|
6
6
|
import {
|
|
7
7
|
authService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-H7MANPCF.js";
|
|
9
9
|
|
|
10
10
|
// src/components/StatusDashboard.tsx
|
|
11
11
|
import { useState, useEffect } from "react";
|
|
@@ -346,7 +346,7 @@ var AuthServiceImpl = class {
|
|
|
346
346
|
return null;
|
|
347
347
|
}
|
|
348
348
|
try {
|
|
349
|
-
const { apiService } = await import("./api-
|
|
349
|
+
const { apiService } = await import("./api-7EO4NO7A.js");
|
|
350
350
|
const user = await apiService.getCurrentUser();
|
|
351
351
|
logger.info("auth", `Token validated for user: ${user.email}`);
|
|
352
352
|
return user;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
apiService
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XWCVS4R6.js";
|
|
4
4
|
import {
|
|
5
5
|
gitService,
|
|
6
6
|
projectService
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IYPRVBYG.js";
|
|
8
8
|
import {
|
|
9
9
|
authService,
|
|
10
10
|
config,
|
|
11
11
|
logger
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-H7MANPCF.js";
|
|
13
13
|
|
|
14
14
|
// src/utils/notify.ts
|
|
15
15
|
import notifier from "node-notifier";
|
|
@@ -344,7 +344,14 @@ var CommitQueueProcessor = class {
|
|
|
344
344
|
if (!isRepo) {
|
|
345
345
|
throw new Error(`Directory ${projectPath} is not a git repository`);
|
|
346
346
|
}
|
|
347
|
+
let hookModifiedFiles = [];
|
|
347
348
|
if (project.commitSettings?.hooks?.length) {
|
|
349
|
+
const statusBeforeHooks = await gitService.getStatus(projectPath);
|
|
350
|
+
const filesBeforeHooks = /* @__PURE__ */ new Set([
|
|
351
|
+
...statusBeforeHooks.staged,
|
|
352
|
+
...statusBeforeHooks.unstaged,
|
|
353
|
+
...statusBeforeHooks.untracked
|
|
354
|
+
]);
|
|
348
355
|
onProgress?.("Running pre-commit hooks...");
|
|
349
356
|
logger.info("queue", "Executing pre-commit hooks...");
|
|
350
357
|
streamer.append("\n> Executing pre-commit hooks...\n");
|
|
@@ -384,6 +391,22 @@ ${failedBlockingHook.output}`);
|
|
|
384
391
|
streamer.append(
|
|
385
392
|
`
|
|
386
393
|
Warning: ${failedNonBlockingHooks.length} non-blocking hooks failed.
|
|
394
|
+
`
|
|
395
|
+
);
|
|
396
|
+
}
|
|
397
|
+
const statusAfterHooks = await gitService.getStatus(projectPath);
|
|
398
|
+
hookModifiedFiles = [
|
|
399
|
+
...statusAfterHooks.unstaged,
|
|
400
|
+
...statusAfterHooks.untracked
|
|
401
|
+
].filter((f) => !filesBeforeHooks.has(f));
|
|
402
|
+
if (hookModifiedFiles.length > 0) {
|
|
403
|
+
logger.info(
|
|
404
|
+
"queue",
|
|
405
|
+
`Hooks modified ${hookModifiedFiles.length} additional files: ${hookModifiedFiles.join(", ")}`
|
|
406
|
+
);
|
|
407
|
+
streamer.append(
|
|
408
|
+
`
|
|
409
|
+
> Hooks modified ${hookModifiedFiles.length} additional files: ${hookModifiedFiles.join(", ")}
|
|
387
410
|
`
|
|
388
411
|
);
|
|
389
412
|
}
|
|
@@ -391,13 +414,20 @@ Warning: ${failedNonBlockingHooks.length} non-blocking hooks failed.
|
|
|
391
414
|
onProgress?.("Checking repository status...");
|
|
392
415
|
let status = await gitService.getStatus(projectPath);
|
|
393
416
|
if (commit.files && commit.files.length > 0) {
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
417
|
+
const filesToStage = [
|
|
418
|
+
.../* @__PURE__ */ new Set([...commit.files, ...hookModifiedFiles])
|
|
419
|
+
];
|
|
420
|
+
const extraFiles = filesToStage.length - commit.files.length;
|
|
421
|
+
const extraMsg = extraFiles > 0 ? ` (+${extraFiles} from hooks)` : "";
|
|
422
|
+
onProgress?.(`Staging ${filesToStage.length} files${extraMsg}...`);
|
|
423
|
+
streamer.append(
|
|
424
|
+
`
|
|
425
|
+
> Staging ${filesToStage.length} files${extraMsg}...
|
|
426
|
+
`
|
|
427
|
+
);
|
|
428
|
+
await gitService.stageFiles(projectPath, filesToStage, streamOutput);
|
|
399
429
|
status = await gitService.getStatus(projectPath);
|
|
400
|
-
logger.info("queue", `Auto-staged files: ${
|
|
430
|
+
logger.info("queue", `Auto-staged files: ${filesToStage.join(", ")}`);
|
|
401
431
|
} else if (status.staged.length === 0) {
|
|
402
432
|
const hasChanges = status.unstaged.length > 0 || status.untracked.length > 0;
|
|
403
433
|
if (hasChanges) {
|
|
@@ -911,7 +941,7 @@ var WebSocketServiceImpl = class {
|
|
|
911
941
|
"websocket",
|
|
912
942
|
`Commit ${commit.id} marked as large, fetching full details...`
|
|
913
943
|
);
|
|
914
|
-
const { apiService: apiService2 } = await import("./api-
|
|
944
|
+
const { apiService: apiService2 } = await import("./api-7EO4NO7A.js");
|
|
915
945
|
const fullCommit = await apiService2.getCommit(commit.id);
|
|
916
946
|
commit = {
|
|
917
947
|
...commit,
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
authService,
|
|
3
3
|
config,
|
|
4
4
|
logger
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-H7MANPCF.js";
|
|
6
6
|
|
|
7
7
|
// src/utils/circuit-breaker.ts
|
|
8
8
|
var CircuitBreaker = class {
|
|
@@ -100,7 +100,7 @@ var CircuitBreaker = class {
|
|
|
100
100
|
};
|
|
101
101
|
|
|
102
102
|
// src/services/api.ts
|
|
103
|
-
var AGENT_VERSION = "1.2.
|
|
103
|
+
var AGENT_VERSION = "1.2.43";
|
|
104
104
|
var ApiServiceImpl = class {
|
|
105
105
|
sessionId = null;
|
|
106
106
|
circuitBreaker = new CircuitBreaker({
|
package/dist/daemon/runner.js
CHANGED
|
@@ -3,20 +3,20 @@ import {
|
|
|
3
3
|
commitQueue,
|
|
4
4
|
notify,
|
|
5
5
|
websocketService
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-KGDXQOLB.js";
|
|
7
7
|
import {
|
|
8
8
|
apiService
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-XWCVS4R6.js";
|
|
10
10
|
import {
|
|
11
11
|
gitService,
|
|
12
12
|
projectService,
|
|
13
13
|
removePidFile,
|
|
14
14
|
writePidFile
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-IYPRVBYG.js";
|
|
16
16
|
import {
|
|
17
17
|
authService,
|
|
18
18
|
logger
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-H7MANPCF.js";
|
|
20
20
|
|
|
21
21
|
// src/daemon/runner.ts
|
|
22
22
|
import "dotenv/config";
|
|
@@ -484,6 +484,135 @@ var HealthMonitor = class {
|
|
|
484
484
|
};
|
|
485
485
|
var healthMonitor = new HealthMonitor();
|
|
486
486
|
|
|
487
|
+
// src/daemon/memory-trend.ts
|
|
488
|
+
var MAX_SAMPLES = 120;
|
|
489
|
+
var MIN_SAMPLES_FOR_ANALYSIS = 10;
|
|
490
|
+
var RSS_SLOPE_CAUTION_THRESHOLD = 20;
|
|
491
|
+
var RSS_SLOPE_WARNING_THRESHOLD = 50;
|
|
492
|
+
var R2_CONFIDENCE_THRESHOLD = 0.7;
|
|
493
|
+
var MemoryTrendTracker = class {
|
|
494
|
+
samples = [];
|
|
495
|
+
baselineRss = 0;
|
|
496
|
+
/**
|
|
497
|
+
* Add a new memory sample
|
|
498
|
+
*/
|
|
499
|
+
addSample(memoryUsage, uptime) {
|
|
500
|
+
const sample = {
|
|
501
|
+
timestamp: Date.now(),
|
|
502
|
+
rss: Math.round(memoryUsage.rss / 1024 / 1024),
|
|
503
|
+
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024),
|
|
504
|
+
uptime
|
|
505
|
+
};
|
|
506
|
+
if (this.samples.length === 0) {
|
|
507
|
+
this.baselineRss = sample.rss;
|
|
508
|
+
}
|
|
509
|
+
this.samples.push(sample);
|
|
510
|
+
if (this.samples.length > MAX_SAMPLES) {
|
|
511
|
+
this.samples.shift();
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Calculate linear regression for a dataset
|
|
516
|
+
* Returns { slope, intercept, r2 }
|
|
517
|
+
*/
|
|
518
|
+
linearRegression(points) {
|
|
519
|
+
const n = points.length;
|
|
520
|
+
if (n < 2) return { slope: 0, intercept: 0, r2: 0 };
|
|
521
|
+
let sumX = 0;
|
|
522
|
+
let sumY = 0;
|
|
523
|
+
let sumXY = 0;
|
|
524
|
+
let sumXX = 0;
|
|
525
|
+
for (const { x, y } of points) {
|
|
526
|
+
sumX += x;
|
|
527
|
+
sumY += y;
|
|
528
|
+
sumXY += x * y;
|
|
529
|
+
sumXX += x * x;
|
|
530
|
+
}
|
|
531
|
+
const denominator = n * sumXX - sumX * sumX;
|
|
532
|
+
if (denominator === 0) return { slope: 0, intercept: 0, r2: 0 };
|
|
533
|
+
const slope = (n * sumXY - sumX * sumY) / denominator;
|
|
534
|
+
const intercept = (sumY - slope * sumX) / n;
|
|
535
|
+
const yMean = sumY / n;
|
|
536
|
+
let ssTotal = 0;
|
|
537
|
+
let ssResidual = 0;
|
|
538
|
+
for (const { x, y } of points) {
|
|
539
|
+
const yPredicted = slope * x + intercept;
|
|
540
|
+
ssTotal += (y - yMean) ** 2;
|
|
541
|
+
ssResidual += (y - yPredicted) ** 2;
|
|
542
|
+
}
|
|
543
|
+
const r2 = ssTotal === 0 ? 0 : 1 - ssResidual / ssTotal;
|
|
544
|
+
return { slope, intercept, r2 };
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Get current memory trend analysis
|
|
548
|
+
*/
|
|
549
|
+
getTrend() {
|
|
550
|
+
if (this.samples.length < MIN_SAMPLES_FOR_ANALYSIS) {
|
|
551
|
+
return {
|
|
552
|
+
rssSlope: 0,
|
|
553
|
+
heapSlope: 0,
|
|
554
|
+
rssR2: 0,
|
|
555
|
+
heapR2: 0,
|
|
556
|
+
sampleCount: this.samples.length,
|
|
557
|
+
timeSpanMinutes: 0,
|
|
558
|
+
status: "unknown",
|
|
559
|
+
message: `Collecting data... (${this.samples.length}/${MIN_SAMPLES_FOR_ANALYSIS} samples)`,
|
|
560
|
+
baselineRss: this.baselineRss,
|
|
561
|
+
currentRss: this.samples.length > 0 ? this.samples[this.samples.length - 1].rss : 0
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
const firstTimestamp = this.samples[0].timestamp;
|
|
565
|
+
const rssPoints = this.samples.map((s) => ({
|
|
566
|
+
x: (s.timestamp - firstTimestamp) / 1e3 / 3600,
|
|
567
|
+
// hours
|
|
568
|
+
y: s.rss
|
|
569
|
+
}));
|
|
570
|
+
const heapPoints = this.samples.map((s) => ({
|
|
571
|
+
x: (s.timestamp - firstTimestamp) / 1e3 / 3600,
|
|
572
|
+
y: s.heapUsed
|
|
573
|
+
}));
|
|
574
|
+
const rssRegression = this.linearRegression(rssPoints);
|
|
575
|
+
const heapRegression = this.linearRegression(heapPoints);
|
|
576
|
+
const lastTimestamp = this.samples[this.samples.length - 1].timestamp;
|
|
577
|
+
const timeSpanMinutes = (lastTimestamp - firstTimestamp) / 1e3 / 60;
|
|
578
|
+
const currentRss = this.samples[this.samples.length - 1].rss;
|
|
579
|
+
let status = "healthy";
|
|
580
|
+
let message = "Memory usage is stable";
|
|
581
|
+
const isConfidentTrend = rssRegression.r2 >= R2_CONFIDENCE_THRESHOLD;
|
|
582
|
+
if (isConfidentTrend && rssRegression.slope >= RSS_SLOPE_WARNING_THRESHOLD) {
|
|
583
|
+
status = "warning";
|
|
584
|
+
message = `Memory leak detected: +${rssRegression.slope.toFixed(1)} MB/hr (R\xB2=${rssRegression.r2.toFixed(2)})`;
|
|
585
|
+
} else if (isConfidentTrend && rssRegression.slope >= RSS_SLOPE_CAUTION_THRESHOLD) {
|
|
586
|
+
status = "caution";
|
|
587
|
+
message = `Memory trending up: +${rssRegression.slope.toFixed(1)} MB/hr`;
|
|
588
|
+
} else if (rssRegression.slope < 0 && rssRegression.r2 >= 0.5) {
|
|
589
|
+
message = `Memory stable/decreasing: ${rssRegression.slope.toFixed(1)} MB/hr`;
|
|
590
|
+
} else if (!isConfidentTrend && Math.abs(rssRegression.slope) > 10) {
|
|
591
|
+
message = `Memory fluctuating (low confidence: R\xB2=${rssRegression.r2.toFixed(2)})`;
|
|
592
|
+
}
|
|
593
|
+
return {
|
|
594
|
+
rssSlope: rssRegression.slope,
|
|
595
|
+
heapSlope: heapRegression.slope,
|
|
596
|
+
rssR2: rssRegression.r2,
|
|
597
|
+
heapR2: heapRegression.r2,
|
|
598
|
+
sampleCount: this.samples.length,
|
|
599
|
+
timeSpanMinutes,
|
|
600
|
+
status,
|
|
601
|
+
message,
|
|
602
|
+
baselineRss: this.baselineRss,
|
|
603
|
+
currentRss
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
/**
|
|
607
|
+
* Reset all samples (e.g., after restart)
|
|
608
|
+
*/
|
|
609
|
+
reset() {
|
|
610
|
+
this.samples = [];
|
|
611
|
+
this.baselineRss = 0;
|
|
612
|
+
}
|
|
613
|
+
};
|
|
614
|
+
var memoryTrendTracker = new MemoryTrendTracker();
|
|
615
|
+
|
|
487
616
|
// src/daemon/index.ts
|
|
488
617
|
var heartbeatInterval = null;
|
|
489
618
|
var isShuttingDown = false;
|
|
@@ -645,6 +774,9 @@ function startHeartbeat() {
|
|
|
645
774
|
if (isShuttingDown) return;
|
|
646
775
|
try {
|
|
647
776
|
const memoryUsage = process.memoryUsage();
|
|
777
|
+
const uptime = Math.floor(process.uptime());
|
|
778
|
+
memoryTrendTracker.addSample(memoryUsage, uptime);
|
|
779
|
+
const memoryTrend = memoryTrendTracker.getTrend();
|
|
648
780
|
await apiService.heartbeat({
|
|
649
781
|
websocket_connected: websocketService.isConnected(),
|
|
650
782
|
queue_size: commitQueue.getQueueLength(),
|
|
@@ -656,7 +788,19 @@ function startHeartbeat() {
|
|
|
656
788
|
heapUsed: Math.round(memoryUsage.heapUsed / 1024 / 1024),
|
|
657
789
|
external: Math.round(memoryUsage.external / 1024 / 1024)
|
|
658
790
|
},
|
|
659
|
-
|
|
791
|
+
memory_trend: {
|
|
792
|
+
rss_slope: memoryTrend.rssSlope,
|
|
793
|
+
heap_slope: memoryTrend.heapSlope,
|
|
794
|
+
rss_r2: memoryTrend.rssR2,
|
|
795
|
+
heap_r2: memoryTrend.heapR2,
|
|
796
|
+
sample_count: memoryTrend.sampleCount,
|
|
797
|
+
time_span_minutes: memoryTrend.timeSpanMinutes,
|
|
798
|
+
status: memoryTrend.status,
|
|
799
|
+
message: memoryTrend.message,
|
|
800
|
+
baseline_rss: memoryTrend.baselineRss,
|
|
801
|
+
current_rss: memoryTrend.currentRss
|
|
802
|
+
},
|
|
803
|
+
uptime
|
|
660
804
|
});
|
|
661
805
|
healthMonitor.recordHeartbeat();
|
|
662
806
|
logger.debug("daemon", "Heartbeat sent successfully");
|
package/dist/index.js
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
commitQueue,
|
|
4
4
|
websocketService
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KGDXQOLB.js";
|
|
6
6
|
import {
|
|
7
7
|
apiService
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XWCVS4R6.js";
|
|
9
9
|
import {
|
|
10
10
|
getPidFilePath,
|
|
11
11
|
gitService,
|
|
@@ -14,14 +14,14 @@ import {
|
|
|
14
14
|
projectService,
|
|
15
15
|
spawnDetached,
|
|
16
16
|
validatePidFile
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-IYPRVBYG.js";
|
|
18
18
|
import {
|
|
19
19
|
__commonJS,
|
|
20
20
|
__toESM,
|
|
21
21
|
authService,
|
|
22
22
|
config,
|
|
23
23
|
logger
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-H7MANPCF.js";
|
|
25
25
|
|
|
26
26
|
// node_modules/semver/internal/constants.js
|
|
27
27
|
var require_constants = __commonJS({
|
|
@@ -2657,7 +2657,7 @@ function registerStatusCommand(program2) {
|
|
|
2657
2657
|
try {
|
|
2658
2658
|
const { render } = await import("ink");
|
|
2659
2659
|
const { createElement } = await import("react");
|
|
2660
|
-
const { StatusDashboard } = await import("./StatusDashboard-
|
|
2660
|
+
const { StatusDashboard } = await import("./StatusDashboard-QOFG2BEM.js");
|
|
2661
2661
|
render(createElement(StatusDashboard, { cwd }));
|
|
2662
2662
|
return;
|
|
2663
2663
|
} catch (error) {
|
|
@@ -4928,7 +4928,7 @@ Tasks for project ${chalk15.cyan(linkedProject.projectId)}`
|
|
|
4928
4928
|
});
|
|
4929
4929
|
|
|
4930
4930
|
// src/index.ts
|
|
4931
|
-
var AGENT_VERSION = "1.2.
|
|
4931
|
+
var AGENT_VERSION = "1.2.43";
|
|
4932
4932
|
var program = new Command2();
|
|
4933
4933
|
program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-v, --version", "output the current version").addHelpText(
|
|
4934
4934
|
"after",
|
package/package.json
CHANGED