@kenkaiiii/ggcoder 5.6.2 → 5.7.0

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.
Files changed (50) hide show
  1. package/dist/app-sidecar.js +124 -2
  2. package/dist/app-sidecar.js.map +1 -1
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +26 -13
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/progress/engine.d.ts +23 -0
  7. package/dist/core/progress/engine.d.ts.map +1 -0
  8. package/dist/core/progress/engine.js +131 -0
  9. package/dist/core/progress/engine.js.map +1 -0
  10. package/dist/core/progress/engine.test.d.ts +2 -0
  11. package/dist/core/progress/engine.test.d.ts.map +1 -0
  12. package/dist/core/progress/engine.test.js +136 -0
  13. package/dist/core/progress/engine.test.js.map +1 -0
  14. package/dist/core/progress/git-xp.d.ts +16 -0
  15. package/dist/core/progress/git-xp.d.ts.map +1 -0
  16. package/dist/core/progress/git-xp.js +106 -0
  17. package/dist/core/progress/git-xp.js.map +1 -0
  18. package/dist/core/progress/git-xp.test.d.ts +2 -0
  19. package/dist/core/progress/git-xp.test.d.ts.map +1 -0
  20. package/dist/core/progress/git-xp.test.js +88 -0
  21. package/dist/core/progress/git-xp.test.js.map +1 -0
  22. package/dist/core/progress/ranks.d.ts +21 -0
  23. package/dist/core/progress/ranks.d.ts.map +1 -0
  24. package/dist/core/progress/ranks.js +141 -0
  25. package/dist/core/progress/ranks.js.map +1 -0
  26. package/dist/core/progress/ranks.test.d.ts +2 -0
  27. package/dist/core/progress/ranks.test.d.ts.map +1 -0
  28. package/dist/core/progress/ranks.test.js +59 -0
  29. package/dist/core/progress/ranks.test.js.map +1 -0
  30. package/dist/core/progress/rebuild.d.ts +7 -0
  31. package/dist/core/progress/rebuild.d.ts.map +1 -0
  32. package/dist/core/progress/rebuild.js +106 -0
  33. package/dist/core/progress/rebuild.js.map +1 -0
  34. package/dist/core/progress/rebuild.test.d.ts +2 -0
  35. package/dist/core/progress/rebuild.test.d.ts.map +1 -0
  36. package/dist/core/progress/rebuild.test.js +72 -0
  37. package/dist/core/progress/rebuild.test.js.map +1 -0
  38. package/dist/core/progress/store.d.ts +35 -0
  39. package/dist/core/progress/store.d.ts.map +1 -0
  40. package/dist/core/progress/store.js +200 -0
  41. package/dist/core/progress/store.js.map +1 -0
  42. package/dist/core/progress/store.test.d.ts +2 -0
  43. package/dist/core/progress/store.test.d.ts.map +1 -0
  44. package/dist/core/progress/store.test.js +108 -0
  45. package/dist/core/progress/store.test.js.map +1 -0
  46. package/dist/core/progress/types.d.ts +108 -0
  47. package/dist/core/progress/types.d.ts.map +1 -0
  48. package/dist/core/progress/types.js +3 -0
  49. package/dist/core/progress/types.js.map +1 -0
  50. package/package.json +4 -4
@@ -0,0 +1,106 @@
1
+ // Detect and score new commits made during an agent run. All failures are silent —
2
+ // progress must never break a run.
3
+ import { execFile } from "node:child_process";
4
+ import crypto from "node:crypto";
5
+ const GIT_TIMEOUT_MS = 5_000;
6
+ const MAX_COMMITS_PER_DETECT = 50;
7
+ /** Commits authored earlier than runStart - 5min are treated as imports (pull), not work. */
8
+ const AUTHOR_WINDOW_SLACK_MS = 5 * 60 * 1000;
9
+ function git(cwd, args, input) {
10
+ return new Promise((resolve, reject) => {
11
+ const opts = { cwd, timeout: GIT_TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 };
12
+ const child = execFile("git", args, opts, (err, stdout) => {
13
+ if (err)
14
+ reject(err);
15
+ else
16
+ resolve(String(stdout));
17
+ });
18
+ if (input !== undefined && child.stdin) {
19
+ child.stdin.write(input);
20
+ child.stdin.end();
21
+ }
22
+ });
23
+ }
24
+ /** Stable key for a repo root, used in ProgressFile.repos. */
25
+ export function repoKey(repoRoot) {
26
+ return crypto.createHash("sha256").update(repoRoot).digest("hex").slice(0, 16);
27
+ }
28
+ /**
29
+ * Detect new, scoreable commits since `lastHead`.
30
+ * - `lastHead` undefined (first time seeing this repo) → record HEAD, score nothing.
31
+ * - Merge commits excluded; commits authored before the run window excluded.
32
+ * - Any git failure → null (silent).
33
+ */
34
+ export async function detectNewCommits(cwd, lastHead, runStartedAt) {
35
+ try {
36
+ const repoRoot = (await git(cwd, ["rev-parse", "--show-toplevel"])).trim();
37
+ const head = (await git(cwd, ["rev-parse", "HEAD"])).trim();
38
+ if (!repoRoot || !head)
39
+ return null;
40
+ if (!lastHead || lastHead === head) {
41
+ return { repoRoot, head, commits: [] };
42
+ }
43
+ const sinceIso = new Date(runStartedAt - AUTHOR_WINDOW_SLACK_MS).toISOString();
44
+ let shas;
45
+ try {
46
+ const out = await git(cwd, [
47
+ "rev-list",
48
+ `${lastHead}..HEAD`,
49
+ "--no-merges",
50
+ `--since=${sinceIso}`,
51
+ `--max-count=${MAX_COMMITS_PER_DETECT}`,
52
+ ]);
53
+ shas = out
54
+ .split("\n")
55
+ .map((s) => s.trim())
56
+ .filter(Boolean);
57
+ }
58
+ catch {
59
+ // lastHead may be gone (rebase/gc) — reset the baseline without scoring.
60
+ return { repoRoot, head, commits: [] };
61
+ }
62
+ const commits = [];
63
+ for (const sha of shas.reverse()) {
64
+ const scored = await scoreCommit(cwd, sha);
65
+ if (scored)
66
+ commits.push(scored);
67
+ }
68
+ return { repoRoot, head, commits };
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
74
+ async function scoreCommit(cwd, sha) {
75
+ try {
76
+ // Lines changed: numstat sums added+deleted; binary files show "-" and count 0.
77
+ const numstat = await git(cwd, ["show", "--numstat", "--format=", sha]);
78
+ let linesChanged = 0;
79
+ for (const line of numstat.split("\n")) {
80
+ const parts = line.split("\t");
81
+ if (parts.length < 3)
82
+ continue;
83
+ const added = parseInt(parts[0], 10);
84
+ const deleted = parseInt(parts[1], 10);
85
+ if (Number.isFinite(added))
86
+ linesChanged += added;
87
+ if (Number.isFinite(deleted))
88
+ linesChanged += deleted;
89
+ }
90
+ // Patch-id dedupe: revert/recommit of the same diff scores 0.
91
+ let patchId = "";
92
+ try {
93
+ const diff = await git(cwd, ["show", sha]);
94
+ const out = await git(cwd, ["patch-id", "--stable"], diff);
95
+ patchId = out.trim().split(" ")[0] ?? "";
96
+ }
97
+ catch {
98
+ patchId = "";
99
+ }
100
+ return { sha, patchId, linesChanged };
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ //# sourceMappingURL=git-xp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-xp.js","sourceRoot":"","sources":["../../../src/core/progress/git-xp.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,mCAAmC;AAEnC,OAAO,EAAE,QAAQ,EAAwB,MAAM,oBAAoB,CAAC;AACpE,OAAO,MAAM,MAAM,aAAa,CAAC;AAGjC,MAAM,cAAc,GAAG,KAAK,CAAC;AAC7B,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAClC,6FAA6F;AAC7F,MAAM,sBAAsB,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AAE7C,SAAS,GAAG,CAAC,GAAW,EAAE,IAAc,EAAE,KAAc;IACtD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAoB,EAAE,GAAG,EAAE,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,CAAC;QAC5F,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YACxD,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;gBAChB,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/B,CAAC,CAAC,CAAC;QACH,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YACvC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;YACzB,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACpB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,8DAA8D;AAC9D,MAAM,UAAU,OAAO,CAAC,QAAgB;IACtC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACjF,CAAC;AAQD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAW,EACX,QAA4B,EAC5B,YAAoB;IAEpB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3E,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QAEpC,IAAI,CAAC,QAAQ,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACnC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,YAAY,GAAG,sBAAsB,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/E,IAAI,IAAc,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE;gBACzB,UAAU;gBACV,GAAG,QAAQ,QAAQ;gBACnB,aAAa;gBACb,WAAW,QAAQ,EAAE;gBACrB,eAAe,sBAAsB,EAAE;aACxC,CAAC,CAAC;YACH,IAAI,GAAG,GAAG;iBACP,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;iBACpB,MAAM,CAAC,OAAO,CAAC,CAAC;QACrB,CAAC;QAAC,MAAM,CAAC;YACP,yEAAyE;YACzE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;QACzC,CAAC;QAED,MAAM,OAAO,GAAmB,EAAE,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC3C,IAAI,MAAM;gBAAE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IACjD,IAAI,CAAC;QACH,gFAAgF;QAChF,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC;QACxE,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,YAAY,IAAI,KAAK,CAAC;YAClD,IAAI,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC;gBAAE,YAAY,IAAI,OAAO,CAAC;QACxD,CAAC;QAED,8DAA8D;QAC9D,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC3C,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,GAAG,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,IAAI,CAAC,CAAC;YAC3D,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,EAAE,CAAC;QACf,CAAC;QAED,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=git-xp.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-xp.test.d.ts","sourceRoot":"","sources":["../../../src/core/progress/git-xp.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import fs from "node:fs/promises";
3
+ import os from "node:os";
4
+ import path from "node:path";
5
+ import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
+ import { detectNewCommits } from "./git-xp.js";
7
+ function hasGit() {
8
+ try {
9
+ execFileSync("git", ["--version"], { stdio: "ignore" });
10
+ return true;
11
+ }
12
+ catch {
13
+ return false;
14
+ }
15
+ }
16
+ const gitAvailable = hasGit();
17
+ const d = gitAvailable ? describe : describe.skip;
18
+ let repo;
19
+ function git(...args) {
20
+ return execFileSync("git", args, {
21
+ cwd: repo,
22
+ encoding: "utf-8",
23
+ env: {
24
+ ...process.env,
25
+ GIT_AUTHOR_NAME: "Test",
26
+ GIT_AUTHOR_EMAIL: "t@t.t",
27
+ GIT_COMMITTER_NAME: "Test",
28
+ GIT_COMMITTER_EMAIL: "t@t.t",
29
+ },
30
+ }).trim();
31
+ }
32
+ async function commitFile(name, lines, message) {
33
+ const content = Array.from({ length: lines }, (_, i) => `line ${i} of ${name}`).join("\n");
34
+ await fs.writeFile(path.join(repo, name), content + "\n");
35
+ git("add", name);
36
+ git("commit", "-m", message);
37
+ return git("rev-parse", "HEAD");
38
+ }
39
+ d("detectNewCommits", () => {
40
+ beforeEach(async () => {
41
+ repo = await fs.mkdtemp(path.join(os.tmpdir(), "gg-gitxp-"));
42
+ git("init", "-q");
43
+ });
44
+ afterEach(async () => {
45
+ await fs.rm(repo, { recursive: true, force: true });
46
+ });
47
+ it("first sight of a repo records HEAD without scoring", async () => {
48
+ await commitFile("a.txt", 10, "initial");
49
+ const result = await detectNewCommits(repo, undefined, Date.now());
50
+ expect(result).not.toBeNull();
51
+ expect(result.commits).toHaveLength(0);
52
+ expect(result.head).toBe(git("rev-parse", "HEAD"));
53
+ });
54
+ it("scores new commits with line counts and patch ids", async () => {
55
+ const base = await commitFile("a.txt", 5, "initial");
56
+ const runStart = Date.now();
57
+ await commitFile("b.txt", 30, "feature");
58
+ const result = await detectNewCommits(repo, base, runStart);
59
+ expect(result.commits).toHaveLength(1);
60
+ expect(result.commits[0].linesChanged).toBe(30);
61
+ expect(result.commits[0].patchId).toMatch(/^[0-9a-f]{40}/);
62
+ });
63
+ it("returns no commits when HEAD is unchanged", async () => {
64
+ const head = await commitFile("a.txt", 5, "initial");
65
+ const result = await detectNewCommits(repo, head, Date.now());
66
+ expect(result.commits).toHaveLength(0);
67
+ });
68
+ it("excludes commits authored before the run window", async () => {
69
+ const base = await commitFile("a.txt", 5, "initial");
70
+ await commitFile("b.txt", 10, "old work");
71
+ // Run "started" an hour from now — the commit above predates the window.
72
+ const result = await detectNewCommits(repo, base, Date.now() + 60 * 60 * 1000);
73
+ expect(result.commits).toHaveLength(0);
74
+ });
75
+ it("resets the baseline silently when lastHead is unknown", async () => {
76
+ await commitFile("a.txt", 5, "initial");
77
+ const result = await detectNewCommits(repo, "0".repeat(40), Date.now());
78
+ expect(result).not.toBeNull();
79
+ expect(result.commits).toHaveLength(0);
80
+ });
81
+ it("returns null for a non-repo directory", async () => {
82
+ const plain = await fs.mkdtemp(path.join(os.tmpdir(), "gg-plain-"));
83
+ const result = await detectNewCommits(plain, undefined, Date.now());
84
+ expect(result).toBeNull();
85
+ await fs.rm(plain, { recursive: true, force: true });
86
+ });
87
+ });
88
+ //# sourceMappingURL=git-xp.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-xp.test.js","sourceRoot":"","sources":["../../../src/core/progress/git-xp.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { ProgressFile, ProgressSnapshot, RankLadderEntry } from "./types.js";
2
+ export declare const MAX_LEVEL = 50;
3
+ /** Cumulative XP required to reach level n (level 1 = 0). */
4
+ export declare function xpForLevel(n: number): number;
5
+ /** Level for a cumulative XP total (1..MAX_LEVEL). */
6
+ export declare function levelForXp(xp: number): number;
7
+ export interface RankInfo {
8
+ level: number;
9
+ name: string;
10
+ tier: number;
11
+ tierName: string;
12
+ tierGlyph: string;
13
+ effectId: string;
14
+ }
15
+ /** Rank metadata for a level (clamped to 1..MAX_LEVEL). */
16
+ export declare function rankForLevel(level: number): RankInfo;
17
+ /** Build the broadcast snapshot the webview renders verbatim. */
18
+ export declare function buildSnapshot(file: ProgressFile): ProgressSnapshot;
19
+ /** Full 50-entry ladder for the scorecard. */
20
+ export declare function rankLadder(): RankLadderEntry[];
21
+ //# sourceMappingURL=ranks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.d.ts","sourceRoot":"","sources":["../../../src/core/progress/ranks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElF,eAAO,MAAM,SAAS,KAAK,CAAC;AAwE5B,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,sDAAsD;AACtD,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAI7C;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,2DAA2D;AAC3D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAYpD;AAED,iEAAiE;AACjE,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,gBAAgB,CA+BlE;AAED,8CAA8C;AAC9C,wBAAgB,UAAU,IAAI,eAAe,EAAE,CAc9C"}
@@ -0,0 +1,141 @@
1
+ // The 50-rank ladder: 10 tiers × 5 levels, with CSS effect ids and tier glyphs.
2
+ export const MAX_LEVEL = 50;
3
+ const TIERS = [
4
+ {
5
+ name: "Boot",
6
+ glyph: "○",
7
+ effectId: "dim",
8
+ ranks: ["Lurker", "Tinkerer", "Prompter", "Looper", "Scripter"],
9
+ },
10
+ {
11
+ name: "Ship",
12
+ glyph: "◇",
13
+ effectId: "plain",
14
+ ranks: ["Patcher", "Forker", "Merger", "Shipper", "Builder"],
15
+ },
16
+ {
17
+ name: "Flow",
18
+ glyph: "◆",
19
+ effectId: "blue",
20
+ ranks: ["Hacker", "Stacker", "Debugger", "Compiler", "Operator"],
21
+ },
22
+ {
23
+ name: "Craft",
24
+ glyph: "⬖",
25
+ effectId: "green",
26
+ ranks: ["Toolsmith", "Machinist", "Optimizer", "Artificer", "Architect"],
27
+ },
28
+ {
29
+ name: "Vibe",
30
+ glyph: "✦",
31
+ effectId: "gradient",
32
+ ranks: ["Vibesmith", "Codeslinger", "Bytebender", "Overclocker", "Netrunner"],
33
+ },
34
+ {
35
+ name: "Deep",
36
+ glyph: "✧",
37
+ effectId: "gradient-glow",
38
+ ranks: ["Cipher", "Daemon", "Phantom", "Glitch", "Specter"],
39
+ },
40
+ {
41
+ name: "Arcane",
42
+ glyph: "❖",
43
+ effectId: "animated",
44
+ ranks: ["Warlock", "Technomancer", "Codeweaver", "Archmage", "Oracle"],
45
+ },
46
+ {
47
+ name: "Root",
48
+ glyph: "⬢",
49
+ effectId: "gold",
50
+ ranks: ["Shellmaster", "Kernelghost", "Gitlord", "Mainframe", "Root"],
51
+ },
52
+ {
53
+ name: "Myth",
54
+ glyph: "★",
55
+ effectId: "gold-shimmer",
56
+ ranks: ["Basilisk", "Ascendant", "Sentinel", "Harbinger", "Titan"],
57
+ },
58
+ {
59
+ name: "Beyond",
60
+ glyph: "✹",
61
+ effectId: "iridescent",
62
+ ranks: ["Anomaly", "Entity", "Overmind", "Deity", "Singularity"],
63
+ },
64
+ ];
65
+ /** Cumulative XP required to reach level n (level 1 = 0). */
66
+ export function xpForLevel(n) {
67
+ if (n <= 1)
68
+ return 0;
69
+ return Math.round(100 * Math.pow(n, 1.6));
70
+ }
71
+ /** Level for a cumulative XP total (1..MAX_LEVEL). */
72
+ export function levelForXp(xp) {
73
+ let level = 1;
74
+ while (level < MAX_LEVEL && xp >= xpForLevel(level + 1))
75
+ level++;
76
+ return level;
77
+ }
78
+ /** Rank metadata for a level (clamped to 1..MAX_LEVEL). */
79
+ export function rankForLevel(level) {
80
+ const l = Math.min(Math.max(1, Math.floor(level)), MAX_LEVEL);
81
+ const tierIndex = Math.floor((l - 1) / 5);
82
+ const tier = TIERS[tierIndex];
83
+ return {
84
+ level: l,
85
+ name: tier.ranks[(l - 1) % 5],
86
+ tier: tierIndex + 1,
87
+ tierName: tier.name,
88
+ tierGlyph: tier.glyph,
89
+ effectId: tier.effectId,
90
+ };
91
+ }
92
+ /** Build the broadcast snapshot the webview renders verbatim. */
93
+ export function buildSnapshot(file) {
94
+ const level = levelForXp(file.xp);
95
+ const rank = rankForLevel(level);
96
+ const floor = xpForLevel(level);
97
+ const ceil = level >= MAX_LEVEL ? floor : xpForLevel(level + 1);
98
+ const span = Math.max(1, ceil - floor);
99
+ const into = Math.max(0, file.xp - floor);
100
+ return {
101
+ level,
102
+ rankName: rank.name,
103
+ tier: rank.tier,
104
+ tierName: rank.tierName,
105
+ tierGlyph: rank.tierGlyph,
106
+ effectId: rank.effectId,
107
+ xp: file.xp,
108
+ xpIntoLevel: into,
109
+ xpForLevel: span,
110
+ percent: level >= MAX_LEVEL ? 100 : Math.min(100, Math.floor((into / span) * 100)),
111
+ streak: { current: file.streak.current, best: file.streak.best },
112
+ totals: {
113
+ prompts: file.totals.prompts,
114
+ commits: file.totals.commits,
115
+ linesShipped: file.totals.linesShipped,
116
+ projects: file.totals.projects.length,
117
+ },
118
+ xpBySource: { ...file.xpBySource },
119
+ memberSince: file.createdAt,
120
+ ladder: rankLadder(),
121
+ levelUp: file.lastEvent?.levelUp ?? null,
122
+ eventNonce: file.lastEvent?.nonce ?? null,
123
+ };
124
+ }
125
+ /** Full 50-entry ladder for the scorecard. */
126
+ export function rankLadder() {
127
+ const ladder = [];
128
+ for (let level = 1; level <= MAX_LEVEL; level++) {
129
+ const rank = rankForLevel(level);
130
+ ladder.push({
131
+ level,
132
+ name: rank.name,
133
+ tier: rank.tier,
134
+ tierName: rank.tierName,
135
+ effectId: rank.effectId,
136
+ xpRequired: xpForLevel(level),
137
+ });
138
+ }
139
+ return ladder;
140
+ }
141
+ //# sourceMappingURL=ranks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.js","sourceRoot":"","sources":["../../../src/core/progress/ranks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ranks.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.test.d.ts","sourceRoot":"","sources":["../../../src/core/progress/ranks.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,59 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { MAX_LEVEL, levelForXp, rankForLevel, rankLadder, xpForLevel } from "./ranks.js";
3
+ describe("xpForLevel", () => {
4
+ it("matches the 100 × N^1.6 curve", () => {
5
+ expect(xpForLevel(1)).toBe(0);
6
+ expect(xpForLevel(2)).toBe(303);
7
+ expect(xpForLevel(10)).toBe(3981);
8
+ expect(xpForLevel(50)).toBe(52282);
9
+ });
10
+ it("is strictly increasing", () => {
11
+ for (let n = 2; n <= MAX_LEVEL; n++) {
12
+ expect(xpForLevel(n)).toBeGreaterThan(xpForLevel(n - 1));
13
+ }
14
+ });
15
+ });
16
+ describe("levelForXp", () => {
17
+ it("returns 1 at 0 XP", () => {
18
+ expect(levelForXp(0)).toBe(1);
19
+ });
20
+ it("crosses level boundaries exactly", () => {
21
+ expect(levelForXp(302)).toBe(1);
22
+ expect(levelForXp(303)).toBe(2);
23
+ expect(levelForXp(3981)).toBe(10);
24
+ });
25
+ it("caps at MAX_LEVEL", () => {
26
+ expect(levelForXp(10_000_000)).toBe(MAX_LEVEL);
27
+ });
28
+ });
29
+ describe("rankForLevel", () => {
30
+ it("names the tier boundaries correctly", () => {
31
+ expect(rankForLevel(1).name).toBe("Lurker");
32
+ expect(rankForLevel(5).name).toBe("Scripter");
33
+ expect(rankForLevel(6).name).toBe("Patcher");
34
+ expect(rankForLevel(20).name).toBe("Architect");
35
+ expect(rankForLevel(25).name).toBe("Netrunner");
36
+ expect(rankForLevel(50).name).toBe("Singularity");
37
+ });
38
+ it("assigns tiers 1–10", () => {
39
+ expect(rankForLevel(1).tier).toBe(1);
40
+ expect(rankForLevel(5).tier).toBe(1);
41
+ expect(rankForLevel(6).tier).toBe(2);
42
+ expect(rankForLevel(50).tier).toBe(10);
43
+ });
44
+ it("clamps out-of-range levels", () => {
45
+ expect(rankForLevel(0).level).toBe(1);
46
+ expect(rankForLevel(99).level).toBe(50);
47
+ });
48
+ });
49
+ describe("rankLadder", () => {
50
+ it("has 50 unique names with increasing xpRequired", () => {
51
+ const ladder = rankLadder();
52
+ expect(ladder).toHaveLength(50);
53
+ expect(new Set(ladder.map((r) => r.name)).size).toBe(50);
54
+ for (let i = 1; i < ladder.length; i++) {
55
+ expect(ladder[i].xpRequired).toBeGreaterThan(ladder[i - 1].xpRequired);
56
+ }
57
+ });
58
+ });
59
+ //# sourceMappingURL=ranks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranks.test.js","sourceRoot":"","sources":["../../../src/core/progress/ranks.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ProgressFile } from "./types.js";
2
+ /**
3
+ * Rebuild a progress file from session history. Returns null when there is no
4
+ * history at all (fresh install → start at Lurker via createEmptyProgress).
5
+ */
6
+ export declare function rebuildFromSessions(sessionsDir?: string): Promise<ProgressFile | null>;
7
+ //# sourceMappingURL=rebuild.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild.d.ts","sourceRoot":"","sources":["../../../src/core/progress/rebuild.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiD/C;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmD5F"}
@@ -0,0 +1,106 @@
1
+ // One-time retroactive seeding from the existing ~/.gg/sessions store. Runs only when
2
+ // both progress.json and its backup are absent — existing users open the update already
3
+ // ranked instead of starting at Lurker.
4
+ import fs from "node:fs/promises";
5
+ import { createReadStream } from "node:fs";
6
+ import { createInterface } from "node:readline";
7
+ import path from "node:path";
8
+ import { getAppPaths } from "@kenkaiiii/gg-core";
9
+ import { xpForLevel } from "./ranks.js";
10
+ import { createEmptyProgress, dayKey } from "./store.js";
11
+ /** Grandfathered XP is capped at the XP needed to reach level 15. */
12
+ const SEED_LEVEL_CAP = 15;
13
+ const XP_PER_HISTORICAL_PROMPT = 10;
14
+ /** Count user prompts + find the session header timestamp in one JSONL pass. */
15
+ function scanSessionFile(file) {
16
+ return new Promise((resolve) => {
17
+ const stream = createReadStream(file, { encoding: "utf-8" });
18
+ const rl = createInterface({ input: stream, crlfDelay: Infinity });
19
+ let userPrompts = 0;
20
+ let oldestTimestamp = null;
21
+ let done = false;
22
+ const finish = () => {
23
+ if (done)
24
+ return;
25
+ done = true;
26
+ resolve({ userPrompts, oldestTimestamp });
27
+ rl.close();
28
+ stream.destroy();
29
+ };
30
+ rl.on("line", (line) => {
31
+ if (done || !line)
32
+ return;
33
+ try {
34
+ const p = JSON.parse(line);
35
+ if (p.type === "session" && p.timestamp && !oldestTimestamp) {
36
+ oldestTimestamp = p.timestamp;
37
+ }
38
+ else if (p.type === "message" && p.message?.role === "user") {
39
+ userPrompts++;
40
+ }
41
+ }
42
+ catch {
43
+ // skip malformed line
44
+ }
45
+ });
46
+ rl.on("close", finish);
47
+ rl.on("error", finish);
48
+ stream.on("error", finish);
49
+ });
50
+ }
51
+ /**
52
+ * Rebuild a progress file from session history. Returns null when there is no
53
+ * history at all (fresh install → start at Lurker via createEmptyProgress).
54
+ */
55
+ export async function rebuildFromSessions(sessionsDir) {
56
+ const dir = sessionsDir ?? getAppPaths().sessionsDir;
57
+ let projectDirs;
58
+ try {
59
+ projectDirs = await fs.readdir(dir);
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ let totalPrompts = 0;
65
+ let projectCount = 0;
66
+ let oldest = null;
67
+ for (const entry of projectDirs) {
68
+ const projectDir = path.join(dir, entry);
69
+ let files;
70
+ try {
71
+ files = (await fs.readdir(projectDir)).filter((f) => f.endsWith(".jsonl"));
72
+ }
73
+ catch {
74
+ continue;
75
+ }
76
+ let projectPrompts = 0;
77
+ for (const f of files) {
78
+ const scan = await scanSessionFile(path.join(projectDir, f));
79
+ projectPrompts += scan.userPrompts;
80
+ if (scan.oldestTimestamp && (!oldest || scan.oldestTimestamp < oldest)) {
81
+ oldest = scan.oldestTimestamp;
82
+ }
83
+ }
84
+ if (projectPrompts > 0) {
85
+ totalPrompts += projectPrompts;
86
+ projectCount++;
87
+ }
88
+ }
89
+ if (totalPrompts === 0)
90
+ return null;
91
+ const now = new Date();
92
+ const file = createEmptyProgress(now);
93
+ const cap = xpForLevel(SEED_LEVEL_CAP);
94
+ const seeded = Math.min(totalPrompts * XP_PER_HISTORICAL_PROMPT, cap);
95
+ file.xp = seeded;
96
+ file.totals.prompts = totalPrompts;
97
+ // Historical projects are counted but their paths aren't rehashed — use opaque markers.
98
+ file.totals.projects = Array.from({ length: projectCount }, (_, i) => `seed-${i}`);
99
+ file.xpBySource.prompts = seeded;
100
+ if (oldest)
101
+ file.createdAt = oldest;
102
+ // Seeding is not "activity today" — leave streak at zero, but keep dayXp clean.
103
+ file.rolling.dayKey = dayKey(now);
104
+ return file;
105
+ }
106
+ //# sourceMappingURL=rebuild.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild.js","sourceRoot":"","sources":["../../../src/core/progress/rebuild.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=rebuild.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rebuild.test.d.ts","sourceRoot":"","sources":["../../../src/core/progress/rebuild.test.ts"],"names":[],"mappings":""}