sloppatrol 0.1.0 → 0.1.2
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/README.md +111 -160
- package/dist/census/index.js +4 -2
- package/dist/census/index.js.map +1 -1
- package/dist/census/lib/guardrails.js +38 -9
- package/dist/census/lib/guardrails.js.map +1 -1
- package/dist/census/lib/stack.d.ts +2 -1
- package/dist/census/lib/stack.js +8 -4
- package/dist/census/lib/stack.js.map +1 -1
- package/dist/cli/index.js +20 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/lib/browser.d.ts +2 -0
- package/dist/cli/lib/browser.js +13 -0
- package/dist/cli/lib/browser.js.map +1 -0
- package/dist/cli/lib/usage.d.ts +1 -1
- package/dist/cli/lib/usage.js +4 -3
- package/dist/cli/lib/usage.js.map +1 -1
- package/dist/config/lib/schema.d.ts +30 -0
- package/dist/config/lib/schema.js +16 -0
- package/dist/config/lib/schema.js.map +1 -1
- package/dist/dashboard/index.d.ts +4 -0
- package/dist/dashboard/index.js +6 -2
- package/dist/dashboard/index.js.map +1 -1
- package/dist/dashboard/lib/snapshot.d.ts +168 -30
- package/dist/dashboard/lib/snapshot.js +104 -37
- package/dist/dashboard/lib/snapshot.js.map +1 -1
- package/dist/dashboard/lib/summary.d.ts +230 -0
- package/dist/dashboard/lib/summary.js +398 -0
- package/dist/dashboard/lib/summary.js.map +1 -0
- package/dist/domain/index.d.ts +2 -0
- package/dist/domain/index.js +1 -0
- package/dist/domain/index.js.map +1 -1
- package/dist/domain/lib/cycle.d.ts +17 -0
- package/dist/domain/lib/cycle.js +2 -0
- package/dist/domain/lib/cycle.js.map +1 -0
- package/dist/{patrol → domain}/lib/pick.d.ts +2 -1
- package/dist/{patrol → domain}/lib/pick.js.map +1 -1
- package/dist/domain/lib/refactor.d.ts +2 -0
- package/dist/gate/index.d.ts +7 -0
- package/dist/gate/index.js +15 -0
- package/dist/gate/index.js.map +1 -1
- package/dist/patrol/lib/attempt.js +10 -2
- package/dist/patrol/lib/attempt.js.map +1 -1
- package/dist/patrol/lib/base.d.ts +10 -3
- package/dist/patrol/lib/base.js +14 -8
- package/dist/patrol/lib/base.js.map +1 -1
- package/dist/patrol/lib/cycle.d.ts +1 -1
- package/dist/patrol/lib/cycle.js +32 -1
- package/dist/patrol/lib/cycle.js.map +1 -1
- package/dist/patrol/lib/recover.d.ts +2 -1
- package/dist/patrol/lib/recover.js +16 -1
- package/dist/patrol/lib/recover.js.map +1 -1
- package/dist/patrol/lib/scorecard.js +12 -4
- package/dist/patrol/lib/scorecard.js.map +1 -1
- package/dist/patrol/lib/steps.d.ts +5 -2
- package/dist/patrol/lib/steps.js +9 -6
- package/dist/patrol/lib/steps.js.map +1 -1
- package/dist/playbook/index.js +3 -3
- package/dist/roles/lib/prompts.d.ts +1 -0
- package/dist/roles/lib/prompts.js +6 -0
- package/dist/roles/lib/prompts.js.map +1 -1
- package/dist/roles/lib/refactorer.d.ts +1 -0
- package/dist/roles/lib/refactorer.js +24 -6
- package/dist/roles/lib/refactorer.js.map +1 -1
- package/dist/roles/lib/scorecard-text.js +1 -1
- package/dist/roles/lib/scorecard-text.js.map +1 -1
- package/dist/store/index.d.ts +4 -1
- package/dist/store/index.js +7 -0
- package/dist/store/index.js.map +1 -1
- package/package.json +1 -1
- package/ui/app.js +1236 -324
- package/ui/index.html +35 -13
- package/ui/style.css +1063 -340
- /package/dist/{patrol → domain}/lib/pick.js +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
/** Opens `url` in the default browser. It is a convenience: when it fails, the printed URL still works. */
|
|
3
|
+
export function openInBrowser(url) {
|
|
4
|
+
const [command, args] = process.platform === 'darwin'
|
|
5
|
+
? ['open', [url]]
|
|
6
|
+
: process.platform === 'win32'
|
|
7
|
+
? ['cmd', ['/c', 'start', '""', url]]
|
|
8
|
+
: ['xdg-open', [url]];
|
|
9
|
+
const child = spawn(command, args, { detached: true, stdio: 'ignore' });
|
|
10
|
+
child.on('error', () => { });
|
|
11
|
+
child.unref();
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../src/cli/lib/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,2GAA2G;AAC3G,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,GACnB,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAC3B,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC;QACjB,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;YAC5B,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACrC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxE,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAC5B,KAAK,CAAC,KAAK,EAAE,CAAC;AAChB,CAAC"}
|
package/dist/cli/lib/usage.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const USAGE = "sloppatrol: a team of agents that makes your code cleaner, one verified refactor at a time.\n\nStart\n sloppatrol init Create .sloppatrol/ with a guess at your checks\n sloppatrol doctor Show the config, the agent each role runs on, and what is missing\n\nRun\n sloppatrol Patrol all day: a cycle every patrol.intervalMinutes, with the dashboard\n sloppatrol --once One cycle, then stop\n sloppatrol dashboard Only the dashboard (http://127.0.0.1:4322)\n\nOne step at a time\n sloppatrol check Run your checks on the patrolled commit (the oracle)\n sloppatrol survey Let the surveyor record opportunities now\n sloppatrol refactor [id] Attempt one opportunity now: the best open one, or <id>\n sloppatrol
|
|
1
|
+
export declare const USAGE = "sloppatrol: a team of agents that makes your code cleaner, one verified refactor at a time.\n\nStart\n sloppatrol init Create .sloppatrol/ with a guess at your checks\n sloppatrol doctor Show the config, the agent each role runs on, and what is missing\n\nRun\n sloppatrol Patrol all day: a cycle every patrol.intervalMinutes, with the dashboard\n sloppatrol --once One cycle, then stop\n sloppatrol dashboard Only the dashboard (http://127.0.0.1:4322)\n sloppatrol score Score every file, then open the scorecard, ready to share\n\nOne step at a time\n sloppatrol check Run your checks on the patrolled commit (the oracle)\n sloppatrol survey Let the surveyor record opportunities now\n sloppatrol refactor [id] Attempt one opportunity now: the best open one, or <id>\n sloppatrol publish Open pull requests for verified refactors (--dry-run)\n\nRead\n sloppatrol status The opportunities, the refactors and the agents\n sloppatrol census What the surveyor sees: stack, large files, mocks, churn\n sloppatrol dismiss <id> Never propose this opportunity again (--reason \"...\")\n\nFlags\n --agent <name> init: auto (default), claude, codex or opencode\n --port <n> The dashboard port (default 4322)\n --files <n> score: score at most <n> more files in this run\n --no-dashboard Patrol or score without the dashboard\n --no-open score: do not open the browser\n --cwd <dir> Run as if in <dir>\n -h, --help This help\n -v, --version The version";
|
package/dist/cli/lib/usage.js
CHANGED
|
@@ -8,12 +8,12 @@ Run
|
|
|
8
8
|
sloppatrol Patrol all day: a cycle every patrol.intervalMinutes, with the dashboard
|
|
9
9
|
sloppatrol --once One cycle, then stop
|
|
10
10
|
sloppatrol dashboard Only the dashboard (http://127.0.0.1:4322)
|
|
11
|
+
sloppatrol score Score every file, then open the scorecard, ready to share
|
|
11
12
|
|
|
12
13
|
One step at a time
|
|
13
14
|
sloppatrol check Run your checks on the patrolled commit (the oracle)
|
|
14
15
|
sloppatrol survey Let the surveyor record opportunities now
|
|
15
16
|
sloppatrol refactor [id] Attempt one opportunity now: the best open one, or <id>
|
|
16
|
-
sloppatrol score Score the repo now: up to metrics.panel more files (--files <n>)
|
|
17
17
|
sloppatrol publish Open pull requests for verified refactors (--dry-run)
|
|
18
18
|
|
|
19
19
|
Read
|
|
@@ -24,8 +24,9 @@ Read
|
|
|
24
24
|
Flags
|
|
25
25
|
--agent <name> init: auto (default), claude, codex or opencode
|
|
26
26
|
--port <n> The dashboard port (default 4322)
|
|
27
|
-
--files <n> score:
|
|
28
|
-
--no-dashboard Patrol without the dashboard
|
|
27
|
+
--files <n> score: score at most <n> more files in this run
|
|
28
|
+
--no-dashboard Patrol or score without the dashboard
|
|
29
|
+
--no-open score: do not open the browser
|
|
29
30
|
--cwd <dir> Run as if in <dir>
|
|
30
31
|
-h, --help This help
|
|
31
32
|
-v, --version The version`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/cli/lib/usage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG
|
|
1
|
+
{"version":3,"file":"usage.js","sourceRoot":"","sources":["../../../src/cli/lib/usage.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,KAAK,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA+BW,CAAC"}
|
|
@@ -85,6 +85,14 @@ export declare const configSchema: z.ZodObject<{
|
|
|
85
85
|
}>]>>;
|
|
86
86
|
/** Runs once in each fresh checkout or worktree, before the checks: install, codegen. */
|
|
87
87
|
prepare: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
88
|
+
/**
|
|
89
|
+
* Mechanical tidy-up commands run in the refactorer's worktree after its
|
|
90
|
+
* session and before the gate: remove the imports and helpers an edit left
|
|
91
|
+
* unused, format, sort. They run on every attempt, so residue from a session
|
|
92
|
+
* that ran out of time never reaches a check. A failing command is logged
|
|
93
|
+
* and left to the checks: cleanup never decides the verdict.
|
|
94
|
+
*/
|
|
95
|
+
cleanup: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
88
96
|
/**
|
|
89
97
|
* The oracle. Each check must pass on the patrolled commit before
|
|
90
98
|
* Sloppatrol starts work, and again on every refactor.
|
|
@@ -213,6 +221,14 @@ export declare const configSchema: z.ZodObject<{
|
|
|
213
221
|
maxPerCycle: z.ZodDefault<z.ZodNumber>;
|
|
214
222
|
/** Attempts per opportunity before it is exhausted. */
|
|
215
223
|
maxAttempts: z.ZodDefault<z.ZodNumber>;
|
|
224
|
+
/**
|
|
225
|
+
* A session that stops at its timeout hands its worktree to one
|
|
226
|
+
* bounded completion session, which finishes the change and tidies
|
|
227
|
+
* what it left unused instead of letting the gate reject a
|
|
228
|
+
* half-finished edit. These are that session's limits.
|
|
229
|
+
*/
|
|
230
|
+
cleanupTimeoutMinutes: z.ZodDefault<z.ZodNumber>;
|
|
231
|
+
cleanupMaxSteps: z.ZodDefault<z.ZodNumber>;
|
|
216
232
|
/** Overrides the top-level `agent` for this role. */
|
|
217
233
|
use: z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"auto">, z.ZodEffects<z.ZodEnum<["claude", "codex", "opencode"]>, {
|
|
218
234
|
runtime: "cli";
|
|
@@ -255,6 +271,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
255
271
|
maxSteps: number;
|
|
256
272
|
maxPerCycle: number;
|
|
257
273
|
maxAttempts: number;
|
|
274
|
+
cleanupTimeoutMinutes: number;
|
|
275
|
+
cleanupMaxSteps: number;
|
|
258
276
|
use?: "auto" | {
|
|
259
277
|
runtime: "cli";
|
|
260
278
|
agent: "claude" | "codex" | "opencode";
|
|
@@ -286,6 +304,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
286
304
|
budgetUsd?: number | undefined;
|
|
287
305
|
maxPerCycle?: number | undefined;
|
|
288
306
|
maxAttempts?: number | undefined;
|
|
307
|
+
cleanupTimeoutMinutes?: number | undefined;
|
|
308
|
+
cleanupMaxSteps?: number | undefined;
|
|
289
309
|
}>>;
|
|
290
310
|
/** Scores files against the metrics rubric, for the scorecard and for each refactor's proof. */
|
|
291
311
|
assessor: z.ZodDefault<z.ZodObject<{
|
|
@@ -457,6 +477,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
457
477
|
maxSteps: number;
|
|
458
478
|
maxPerCycle: number;
|
|
459
479
|
maxAttempts: number;
|
|
480
|
+
cleanupTimeoutMinutes: number;
|
|
481
|
+
cleanupMaxSteps: number;
|
|
460
482
|
use?: "auto" | {
|
|
461
483
|
runtime: "cli";
|
|
462
484
|
agent: "claude" | "codex" | "opencode";
|
|
@@ -545,6 +567,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
545
567
|
budgetUsd?: number | undefined;
|
|
546
568
|
maxPerCycle?: number | undefined;
|
|
547
569
|
maxAttempts?: number | undefined;
|
|
570
|
+
cleanupTimeoutMinutes?: number | undefined;
|
|
571
|
+
cleanupMaxSteps?: number | undefined;
|
|
548
572
|
} | undefined;
|
|
549
573
|
assessor?: {
|
|
550
574
|
timeoutMinutes?: number | undefined;
|
|
@@ -653,6 +677,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
653
677
|
source: string;
|
|
654
678
|
};
|
|
655
679
|
prepare: string[];
|
|
680
|
+
cleanup: string[];
|
|
656
681
|
checks: {
|
|
657
682
|
tests: boolean;
|
|
658
683
|
name: string;
|
|
@@ -694,6 +719,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
694
719
|
maxSteps: number;
|
|
695
720
|
maxPerCycle: number;
|
|
696
721
|
maxAttempts: number;
|
|
722
|
+
cleanupTimeoutMinutes: number;
|
|
723
|
+
cleanupMaxSteps: number;
|
|
697
724
|
use?: "auto" | {
|
|
698
725
|
runtime: "cli";
|
|
699
726
|
agent: "claude" | "codex" | "opencode";
|
|
@@ -788,6 +815,7 @@ export declare const configSchema: z.ZodObject<{
|
|
|
788
815
|
source?: string | undefined;
|
|
789
816
|
} | undefined;
|
|
790
817
|
prepare?: string[] | undefined;
|
|
818
|
+
cleanup?: string[] | undefined;
|
|
791
819
|
uncheckedTests?: string[] | undefined;
|
|
792
820
|
focus?: string[] | undefined;
|
|
793
821
|
ignore?: string[] | undefined;
|
|
@@ -831,6 +859,8 @@ export declare const configSchema: z.ZodObject<{
|
|
|
831
859
|
budgetUsd?: number | undefined;
|
|
832
860
|
maxPerCycle?: number | undefined;
|
|
833
861
|
maxAttempts?: number | undefined;
|
|
862
|
+
cleanupTimeoutMinutes?: number | undefined;
|
|
863
|
+
cleanupMaxSteps?: number | undefined;
|
|
834
864
|
} | undefined;
|
|
835
865
|
assessor?: {
|
|
836
866
|
timeoutMinutes?: number | undefined;
|
|
@@ -43,6 +43,14 @@ export const configSchema = z.object({
|
|
|
43
43
|
agent: runtimeSchema.default('auto'),
|
|
44
44
|
/** Runs once in each fresh checkout or worktree, before the checks: install, codegen. */
|
|
45
45
|
prepare: z.array(z.string()).default([]),
|
|
46
|
+
/**
|
|
47
|
+
* Mechanical tidy-up commands run in the refactorer's worktree after its
|
|
48
|
+
* session and before the gate: remove the imports and helpers an edit left
|
|
49
|
+
* unused, format, sort. They run on every attempt, so residue from a session
|
|
50
|
+
* that ran out of time never reaches a check. A failing command is logged
|
|
51
|
+
* and left to the checks: cleanup never decides the verdict.
|
|
52
|
+
*/
|
|
53
|
+
cleanup: z.array(z.string()).default([]),
|
|
46
54
|
/**
|
|
47
55
|
* The oracle. Each check must pass on the patrolled commit before
|
|
48
56
|
* Sloppatrol starts work, and again on every refactor.
|
|
@@ -84,6 +92,14 @@ export const configSchema = z.object({
|
|
|
84
92
|
maxPerCycle: z.number().int().positive().default(1),
|
|
85
93
|
/** Attempts per opportunity before it is exhausted. */
|
|
86
94
|
maxAttempts: z.number().int().positive().default(2),
|
|
95
|
+
/**
|
|
96
|
+
* A session that stops at its timeout hands its worktree to one
|
|
97
|
+
* bounded completion session, which finishes the change and tidies
|
|
98
|
+
* what it left unused instead of letting the gate reject a
|
|
99
|
+
* half-finished edit. These are that session's limits.
|
|
100
|
+
*/
|
|
101
|
+
cleanupTimeoutMinutes: z.number().positive().default(15),
|
|
102
|
+
cleanupMaxSteps: z.number().int().positive().default(30),
|
|
87
103
|
})
|
|
88
104
|
.default({}),
|
|
89
105
|
/** Scores files against the metrics rubric, for the scorecard and for each refactor's proof. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/config/lib/schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/config/lib/schema.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Store } from '../store/index.js';
|
|
2
2
|
export type { DashboardState } from './lib/snapshot.js';
|
|
3
|
+
export type { ProjectSummary } from './lib/summary.js';
|
|
3
4
|
export type Dashboard = {
|
|
4
5
|
url: string;
|
|
5
6
|
close(): Promise<void>;
|
|
@@ -7,9 +8,12 @@ export type Dashboard = {
|
|
|
7
8
|
/**
|
|
8
9
|
* A read-only local page over the store: the agents, the backlog, the
|
|
9
10
|
* refactors and their gate, and every check run, refreshed live.
|
|
11
|
+
* `/api/summary` holds every number the pages show, computed once here.
|
|
10
12
|
*/
|
|
11
13
|
export declare function startDashboard(options: {
|
|
12
14
|
store: Store;
|
|
13
15
|
project: string;
|
|
14
16
|
port?: number;
|
|
17
|
+
/** Whether a process runs, by its id. The tests pass their own. */
|
|
18
|
+
alive?: (pid: number) => boolean;
|
|
15
19
|
}): Promise<Dashboard>;
|
package/dist/dashboard/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import {
|
|
4
|
+
import { snapshots } from './lib/snapshot.js';
|
|
5
5
|
/** Shipped in the npm package next to `dist/`. */
|
|
6
6
|
const UI = fileURLToPath(new URL('../../ui/', import.meta.url));
|
|
7
7
|
const STATIC = {
|
|
@@ -17,9 +17,11 @@ function json(response, status, body) {
|
|
|
17
17
|
/**
|
|
18
18
|
* A read-only local page over the store: the agents, the backlog, the
|
|
19
19
|
* refactors and their gate, and every check run, refreshed live.
|
|
20
|
+
* `/api/summary` holds every number the pages show, computed once here.
|
|
20
21
|
*/
|
|
21
22
|
export async function startDashboard(options) {
|
|
22
23
|
const { store } = options;
|
|
24
|
+
const read = snapshots(store, options.project, options.alive);
|
|
23
25
|
const server = createServer(async (request, response) => {
|
|
24
26
|
try {
|
|
25
27
|
const url = new URL(request.url ?? '/', 'http://localhost');
|
|
@@ -30,7 +32,9 @@ export async function startDashboard(options) {
|
|
|
30
32
|
return;
|
|
31
33
|
}
|
|
32
34
|
if (url.pathname === '/api/state')
|
|
33
|
-
return json(response, 200, await
|
|
35
|
+
return json(response, 200, await read.state());
|
|
36
|
+
if (url.pathname === '/api/summary')
|
|
37
|
+
return json(response, 200, await read.summary());
|
|
34
38
|
const [, api, kind, id] = url.pathname.split('/');
|
|
35
39
|
if (api === 'api' && id && ID.test(id)) {
|
|
36
40
|
if (kind === 'sessions')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAuB,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAuB,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAK9C,kDAAkD;AAClD,MAAM,EAAE,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAChE,MAAM,MAAM,GAAqC;IAC/C,GAAG,EAAE,CAAC,YAAY,EAAE,0BAA0B,CAAC;IAC/C,SAAS,EAAE,CAAC,QAAQ,EAAE,gCAAgC,CAAC;IACvD,YAAY,EAAE,CAAC,WAAW,EAAE,yBAAyB,CAAC;CACvD,CAAC;AACF,MAAM,EAAE,GAAG,iBAAiB,CAAC;AAE7B,SAAS,IAAI,CAAC,QAAwB,EAAE,MAAc,EAAE,IAAa;IACnE,QAAQ,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;IAChG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACrC,CAAC;AAID;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAMpC;IACC,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;IAC1B,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;QACtD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;YAC5D,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClC,IAAI,IAAI,EAAE,CAAC;gBACT,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,UAAU,EAAE,CAAC,CAAC;gBAClF,QAAQ,CAAC,GAAG,CAAC,MAAM,QAAQ,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YACD,IAAI,GAAG,CAAC,QAAQ,KAAK,YAAY;gBAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAClF,IAAI,GAAG,CAAC,QAAQ,KAAK,cAAc;gBAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACtF,MAAM,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAClD,IAAI,GAAG,KAAK,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;gBACvC,IAAI,IAAI,KAAK,UAAU;oBAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC5E,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACtB,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;oBACnE,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;gBACtF,CAAC;YACH,CAAC;YACD,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,QAAQ,EAAE,GAAG,EAAE,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,OAAO,CAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;QACvC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;IAClF,OAAO;QACL,GAAG,EAAE,oBAAoB,IAAI,EAAE;QAC/B,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACnB,MAAM,CAAC,mBAAmB,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAC7B,CAAC,CAAC;KACL,CAAC;AACJ,CAAC"}
|
|
@@ -1,32 +1,170 @@
|
|
|
1
|
-
import type { AgentEvent, CheckRun } from '../../domain/index.js';
|
|
2
1
|
import type { Store } from '../../store/index.js';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
import { type LiveStatus, type ProjectSummary, type SessionRow } from './summary.js';
|
|
3
|
+
export type DashboardState = Awaited<ReturnType<ReturnType<typeof snapshots>['state']>>;
|
|
4
|
+
/**
|
|
5
|
+
* Reads the store for the dashboard. A session that ended never changes, so
|
|
6
|
+
* its row is read once; the counts still cover every session.
|
|
7
|
+
*/
|
|
8
|
+
export declare function snapshots(store: Store, project: string, alive?: (pid: number) => boolean): {
|
|
9
|
+
summary(): Promise<ProjectSummary>;
|
|
10
|
+
/** Everything the dashboard shows, in one read of the store. */
|
|
11
|
+
state(): Promise<{
|
|
12
|
+
project: string;
|
|
13
|
+
now: string;
|
|
14
|
+
summary: {
|
|
15
|
+
checks: {
|
|
16
|
+
caught?: number | undefined;
|
|
17
|
+
planted?: number | undefined;
|
|
18
|
+
runs: number;
|
|
19
|
+
problems: number;
|
|
20
|
+
base: {
|
|
21
|
+
runs: number;
|
|
22
|
+
bad: number;
|
|
23
|
+
problems: number;
|
|
24
|
+
};
|
|
25
|
+
gate: {
|
|
26
|
+
runs: number;
|
|
27
|
+
bad: number;
|
|
28
|
+
problems: number;
|
|
29
|
+
};
|
|
30
|
+
refactorer: {
|
|
31
|
+
runs: number;
|
|
32
|
+
bad: number;
|
|
33
|
+
problems: number;
|
|
34
|
+
};
|
|
35
|
+
mutation: {
|
|
36
|
+
runs: number;
|
|
37
|
+
bad: number;
|
|
38
|
+
problems: number;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
sessions: {
|
|
42
|
+
total: number;
|
|
43
|
+
running: number;
|
|
44
|
+
failed: number;
|
|
45
|
+
failedRecent: number;
|
|
46
|
+
stopped: number;
|
|
47
|
+
costUsd: number;
|
|
48
|
+
costRecentUsd: number;
|
|
49
|
+
byRole: {
|
|
50
|
+
[k: string]: number;
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
attention: {
|
|
54
|
+
tone: import("./summary.js").Tone;
|
|
55
|
+
title: string;
|
|
56
|
+
detail: string;
|
|
57
|
+
command?: string;
|
|
58
|
+
target?: {
|
|
59
|
+
tab: string;
|
|
60
|
+
filter?: string;
|
|
61
|
+
select?: string;
|
|
62
|
+
};
|
|
63
|
+
links?: {
|
|
64
|
+
label: string;
|
|
65
|
+
href: string;
|
|
66
|
+
select?: string;
|
|
67
|
+
}[];
|
|
68
|
+
}[];
|
|
69
|
+
quality?: {
|
|
70
|
+
compared: number;
|
|
71
|
+
trend: number[];
|
|
72
|
+
metrics: {
|
|
73
|
+
trend: number[];
|
|
74
|
+
delta?: number | undefined;
|
|
75
|
+
id: "tests" | "simplicity" | "modularity" | "injection" | "purity" | "clarity" | "guardrails";
|
|
76
|
+
name: string;
|
|
77
|
+
value: number;
|
|
78
|
+
}[];
|
|
79
|
+
coverage: {
|
|
80
|
+
files: number;
|
|
81
|
+
totalFiles: number;
|
|
82
|
+
share: number;
|
|
83
|
+
};
|
|
84
|
+
guardrails: {
|
|
85
|
+
present: number;
|
|
86
|
+
total: number;
|
|
87
|
+
};
|
|
88
|
+
delta?: number | undefined;
|
|
89
|
+
overall?: number | undefined;
|
|
90
|
+
sha: string;
|
|
91
|
+
at: string;
|
|
92
|
+
rubric: string;
|
|
93
|
+
} | undefined;
|
|
94
|
+
cycles: {
|
|
95
|
+
last?: {
|
|
96
|
+
at: string;
|
|
97
|
+
tone: import("./summary.js").Tone;
|
|
98
|
+
text: string;
|
|
99
|
+
sha?: string;
|
|
100
|
+
} | undefined;
|
|
101
|
+
count: number;
|
|
102
|
+
};
|
|
103
|
+
refactors: {
|
|
104
|
+
rejectedBy: {
|
|
105
|
+
step: string;
|
|
106
|
+
label: string;
|
|
107
|
+
count: number;
|
|
108
|
+
}[];
|
|
109
|
+
keptRate?: number | undefined;
|
|
110
|
+
total: number;
|
|
111
|
+
working: number;
|
|
112
|
+
waits: number;
|
|
113
|
+
rejected: number;
|
|
114
|
+
error: number;
|
|
115
|
+
merged: number;
|
|
116
|
+
closed: number;
|
|
117
|
+
judged: number;
|
|
118
|
+
kept: number;
|
|
119
|
+
};
|
|
120
|
+
decisions: {
|
|
121
|
+
toPublish: number;
|
|
122
|
+
toReview: number;
|
|
123
|
+
};
|
|
124
|
+
backlog: {
|
|
125
|
+
total: number;
|
|
126
|
+
open: number;
|
|
127
|
+
ready: string[];
|
|
128
|
+
busy: string[];
|
|
129
|
+
working: string[];
|
|
130
|
+
byStrength: Record<import("../../domain/index.js").Strength, number>;
|
|
131
|
+
verified: number;
|
|
132
|
+
proposed: number;
|
|
133
|
+
done: number;
|
|
134
|
+
exhausted: number;
|
|
135
|
+
dismissed: number;
|
|
136
|
+
};
|
|
137
|
+
main?: {
|
|
138
|
+
failed?: string | undefined;
|
|
139
|
+
sha: string;
|
|
140
|
+
state: "running" | "failed" | "passed";
|
|
141
|
+
runId: string;
|
|
142
|
+
at: string;
|
|
143
|
+
} | undefined;
|
|
144
|
+
project: string;
|
|
145
|
+
verdict: {
|
|
146
|
+
tone: import("./summary.js").Tone;
|
|
147
|
+
text: string;
|
|
148
|
+
detail: string;
|
|
149
|
+
};
|
|
150
|
+
activity: {
|
|
151
|
+
state: "running" | "waiting" | "stopped";
|
|
152
|
+
text: string;
|
|
153
|
+
detail: string;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
patrol: import("../../store/index.js").PatrolState;
|
|
157
|
+
statuses: LiveStatus[];
|
|
158
|
+
opportunities: import("../../domain/index.js").Opportunity[];
|
|
159
|
+
refactors: import("./summary.js").RefactorRow[];
|
|
160
|
+
checkRuns: import("./summary.js").CheckRunRow[];
|
|
161
|
+
sessions: SessionRow[];
|
|
162
|
+
scorecards: import("../../domain/index.js").Scorecard[];
|
|
163
|
+
metrics: {
|
|
164
|
+
id: "tests" | "simplicity" | "modularity" | "injection" | "purity" | "clarity" | "guardrails";
|
|
165
|
+
name: string;
|
|
166
|
+
question: string;
|
|
167
|
+
levels: [string, string, string, string, string];
|
|
168
|
+
}[];
|
|
169
|
+
}>;
|
|
12
170
|
};
|
|
13
|
-
/** Everything the dashboard shows, in one read of the store. */
|
|
14
|
-
export declare function snapshot(store: Store, project: string): Promise<{
|
|
15
|
-
project: string;
|
|
16
|
-
now: string;
|
|
17
|
-
patrol: import("../../store/index.js").PatrolState;
|
|
18
|
-
statuses: import("../../domain/index.js").AgentStatus[];
|
|
19
|
-
opportunities: import("../../domain/index.js").Opportunity[];
|
|
20
|
-
refactors: import("../../domain/index.js").Refactor[];
|
|
21
|
-
checkRuns: CheckRun[];
|
|
22
|
-
sessions: (SessionSummary | undefined)[];
|
|
23
|
-
/** Oldest first, for the trend; the last one is the current scorecard. */
|
|
24
|
-
scorecards: import("../../domain/index.js").Scorecard[];
|
|
25
|
-
metrics: {
|
|
26
|
-
id: "tests" | "simplicity" | "modularity" | "injection" | "purity" | "clarity" | "guardrails";
|
|
27
|
-
name: string;
|
|
28
|
-
question: string;
|
|
29
|
-
levels: [string, string, string, string, string];
|
|
30
|
-
}[];
|
|
31
|
-
}>;
|
|
32
|
-
export type DashboardState = Awaited<ReturnType<typeof snapshot>>;
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { METRICS } from '../../metrics/index.js';
|
|
2
|
-
|
|
3
|
-
const
|
|
2
|
+
import { checkRunRow, projectSummary, refactorRow, } from './summary.js';
|
|
3
|
+
const RECENT_SESSIONS = 60;
|
|
4
|
+
const RECENT_CHECKS = 80;
|
|
4
5
|
const RECENT_SCORECARDS = 30;
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
/** True when a process with this id runs. EPERM: it runs, as another user. */
|
|
7
|
+
function processAlive(pid) {
|
|
8
|
+
try {
|
|
9
|
+
process.kill(pid, 0);
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
return error.code === 'EPERM';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function sessionRow(id, events, active) {
|
|
7
17
|
const first = events[0];
|
|
8
18
|
const last = events.at(-1);
|
|
9
19
|
if (!first || !last)
|
|
@@ -12,10 +22,17 @@ async function summarize(store, id) {
|
|
|
12
22
|
return {
|
|
13
23
|
id,
|
|
14
24
|
role: first.role,
|
|
15
|
-
subject: first.subject,
|
|
25
|
+
...(first.subject ? { subject: first.subject } : {}),
|
|
16
26
|
startedAt: first.at,
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
...(ended ? { endedAt: last.at } : {}),
|
|
28
|
+
// An interrupted session ended because Sloppatrol stopped, not because the agent failed.
|
|
29
|
+
state: !ended || /^Interrupted/.test(last.summary)
|
|
30
|
+
? !ended && active
|
|
31
|
+
? 'running'
|
|
32
|
+
: 'stopped'
|
|
33
|
+
: last.kind === 'error'
|
|
34
|
+
? 'failed'
|
|
35
|
+
: 'done',
|
|
19
36
|
last: last.summary.split('\n')[0].slice(0, 200),
|
|
20
37
|
costUsd: events.reduce((sum, e) => sum + (e.kind === 'finish' || e.kind === 'error' ? (e.costUsd ?? 0) : 0), 0),
|
|
21
38
|
};
|
|
@@ -24,37 +41,87 @@ async function summarize(store, id) {
|
|
|
24
41
|
function light(run) {
|
|
25
42
|
return { ...run, results: run.results.map((r) => ({ ...r, output: r.ok ? '' : r.output.slice(-600) })) };
|
|
26
43
|
}
|
|
27
|
-
/**
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
44
|
+
/**
|
|
45
|
+
* Reads the store for the dashboard. A session that ended never changes, so
|
|
46
|
+
* its row is read once; the counts still cover every session.
|
|
47
|
+
*/
|
|
48
|
+
export function snapshots(store, project, alive = processAlive) {
|
|
49
|
+
const ended = new Map();
|
|
50
|
+
const sessionRows = async (ids, active) => (await Promise.all(ids.map(async (id) => {
|
|
51
|
+
const known = ended.get(id);
|
|
52
|
+
if (known)
|
|
53
|
+
return known;
|
|
54
|
+
const row = sessionRow(id, await store.events(id), active);
|
|
55
|
+
if (row?.endedAt)
|
|
56
|
+
ended.set(id, row);
|
|
57
|
+
return row;
|
|
58
|
+
}))).filter((row) => !!row);
|
|
59
|
+
const read = async () => {
|
|
60
|
+
const [patrol, rawStatuses, opportunities, refactors, checkRuns, sessionIds, scorecards, cycles] = await Promise.all([
|
|
61
|
+
store.patrolState(),
|
|
62
|
+
store.statuses(),
|
|
63
|
+
store.listOpportunities(),
|
|
64
|
+
store.listRefactors(),
|
|
65
|
+
store.listCheckRuns(),
|
|
66
|
+
store.sessions(),
|
|
67
|
+
store.listScorecards(),
|
|
68
|
+
store.listCycles(),
|
|
69
|
+
]);
|
|
70
|
+
const statuses = rawStatuses.map((s) => {
|
|
71
|
+
const running = alive(s.pid);
|
|
72
|
+
return { ...s, alive: running, stale: s.state === 'running' && !running };
|
|
73
|
+
});
|
|
74
|
+
// Work marked as running is real only while a Sloppatrol process runs.
|
|
75
|
+
const active = statuses.some((s) => s.alive);
|
|
76
|
+
const byId = new Map(opportunities.map((o) => [o.id, o]));
|
|
77
|
+
const refactorRows = refactors.map((r) => refactorRow(r, byId.get(r.opportunityId), checkRuns, active));
|
|
78
|
+
const runRows = checkRuns.map((run) => checkRunRow(run, active));
|
|
79
|
+
const sessions = await sessionRows(sessionIds, active);
|
|
80
|
+
const now = new Date();
|
|
81
|
+
const summary = projectSummary({
|
|
82
|
+
project,
|
|
83
|
+
now,
|
|
84
|
+
patrol,
|
|
85
|
+
statuses,
|
|
86
|
+
opportunities,
|
|
87
|
+
refactors: refactorRows,
|
|
88
|
+
checkRuns: runRows,
|
|
89
|
+
scorecards,
|
|
90
|
+
sessions,
|
|
91
|
+
cycles,
|
|
92
|
+
});
|
|
93
|
+
return { now, patrol, statuses, opportunities, refactorRows, runRows, sessions, scorecards, summary };
|
|
94
|
+
};
|
|
42
95
|
return {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
96
|
+
async summary() {
|
|
97
|
+
return (await read()).summary;
|
|
98
|
+
},
|
|
99
|
+
/** Everything the dashboard shows, in one read of the store. */
|
|
100
|
+
async state() {
|
|
101
|
+
const data = await read();
|
|
102
|
+
return {
|
|
103
|
+
project,
|
|
104
|
+
now: data.now.toISOString(),
|
|
105
|
+
summary: data.summary,
|
|
106
|
+
patrol: data.patrol,
|
|
107
|
+
statuses: data.statuses,
|
|
108
|
+
opportunities: data.opportunities.reverse(),
|
|
109
|
+
// The gate's check outputs are one request away, in their check run.
|
|
110
|
+
refactors: data.refactorRows
|
|
111
|
+
.reverse()
|
|
112
|
+
.map((r) => r.verdict
|
|
113
|
+
? { ...r, verdict: { ...r.verdict, checks: r.verdict.checks.map((c) => ({ ...c, output: '' })) } }
|
|
114
|
+
: r),
|
|
115
|
+
checkRuns: data.runRows.slice(-RECENT_CHECKS).reverse().map(light),
|
|
116
|
+
sessions: data.sessions.slice(-RECENT_SESSIONS).reverse(),
|
|
117
|
+
// Every file's scores for the newest scorecard only: older ones feed the
|
|
118
|
+
// trend, which needs their means alone. Oldest first.
|
|
119
|
+
scorecards: data.scorecards
|
|
120
|
+
.slice(-RECENT_SCORECARDS)
|
|
121
|
+
.map((card, i, all) => (i === all.length - 1 ? card : { ...card, units: [] })),
|
|
122
|
+
metrics: METRICS.map((m) => ({ id: m.id, name: m.name, question: m.question, levels: m.levels })),
|
|
123
|
+
};
|
|
124
|
+
},
|
|
58
125
|
};
|
|
59
126
|
}
|
|
60
127
|
//# sourceMappingURL=snapshot.js.map
|