@fonz/tgcc 0.6.14 → 0.6.15

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.
@@ -0,0 +1,176 @@
1
+ /**
2
+ * ProcessRegistry — Global singleton for shared CC process management.
3
+ *
4
+ * Keys processes by `repo:sessionId` instead of per-agent userId,
5
+ * allowing multiple agents/users to subscribe to a single CC process.
6
+ */
7
+ // ── Helpers ──
8
+ function processKey(repo, sessionId) {
9
+ return `${repo}:${sessionId}`;
10
+ }
11
+ function clientKey(ref) {
12
+ return `${ref.agentId}:${ref.userId}:${ref.chatId}`;
13
+ }
14
+ // ── Registry ──
15
+ export class ProcessRegistry {
16
+ entries = new Map();
17
+ // Reverse index: clientKey → processKey (for fast lookup by client)
18
+ clientIndex = new Map();
19
+ /** Get existing process entry for a repo+session, or null. */
20
+ get(repo, sessionId) {
21
+ return this.entries.get(processKey(repo, sessionId)) ?? null;
22
+ }
23
+ /** Register a new process and subscribe the owner. */
24
+ register(repo, sessionId, model, proc, owner) {
25
+ const pKey = processKey(repo, sessionId);
26
+ const cKey = clientKey(owner);
27
+ const entry = {
28
+ ccProcess: proc,
29
+ repo,
30
+ sessionId,
31
+ model,
32
+ owner,
33
+ subscribers: new Map(),
34
+ };
35
+ // Owner is always the first subscriber
36
+ entry.subscribers.set(cKey, {
37
+ client: owner,
38
+ accumulator: null,
39
+ tracker: null,
40
+ });
41
+ this.entries.set(pKey, entry);
42
+ this.clientIndex.set(cKey, pKey);
43
+ return entry;
44
+ }
45
+ /** Subscribe an additional client to an existing process. Returns the entry, or null if not found. */
46
+ subscribe(repo, sessionId, client) {
47
+ const pKey = processKey(repo, sessionId);
48
+ const entry = this.entries.get(pKey);
49
+ if (!entry)
50
+ return null;
51
+ const cKey = clientKey(client);
52
+ // Already subscribed? Just return.
53
+ if (!entry.subscribers.has(cKey)) {
54
+ entry.subscribers.set(cKey, {
55
+ client,
56
+ accumulator: null,
57
+ tracker: null,
58
+ });
59
+ }
60
+ this.clientIndex.set(cKey, pKey);
61
+ return entry;
62
+ }
63
+ /** Unsubscribe a client. Returns true if the process was destroyed (no subscribers left). */
64
+ unsubscribe(client) {
65
+ const cKey = clientKey(client);
66
+ const pKey = this.clientIndex.get(cKey);
67
+ if (!pKey)
68
+ return false;
69
+ const entry = this.entries.get(pKey);
70
+ if (!entry) {
71
+ this.clientIndex.delete(cKey);
72
+ return false;
73
+ }
74
+ // Clean up subscriber's accumulator/tracker
75
+ const sub = entry.subscribers.get(cKey);
76
+ if (sub) {
77
+ if (sub.accumulator)
78
+ sub.accumulator.finalize();
79
+ if (sub.tracker)
80
+ sub.tracker.reset();
81
+ }
82
+ entry.subscribers.delete(cKey);
83
+ this.clientIndex.delete(cKey);
84
+ // If no subscribers remain, destroy the process
85
+ if (entry.subscribers.size === 0) {
86
+ entry.ccProcess.destroy();
87
+ this.entries.delete(pKey);
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+ /** Find entry by client ref. */
93
+ findByClient(client) {
94
+ const cKey = clientKey(client);
95
+ const pKey = this.clientIndex.get(cKey);
96
+ if (!pKey)
97
+ return null;
98
+ return this.entries.get(pKey) ?? null;
99
+ }
100
+ /** Find entry that owns a given CCProcess instance. */
101
+ findByProcess(proc) {
102
+ for (const entry of this.entries.values()) {
103
+ if (entry.ccProcess === proc)
104
+ return entry;
105
+ }
106
+ return null;
107
+ }
108
+ /** Get subscriber for a specific client within an entry. */
109
+ getSubscriber(entry, client) {
110
+ return entry.subscribers.get(clientKey(client)) ?? null;
111
+ }
112
+ /** Set accumulator for a subscriber. */
113
+ setSubscriberAccumulator(entry, client, acc) {
114
+ const sub = entry.subscribers.get(clientKey(client));
115
+ if (sub)
116
+ sub.accumulator = acc;
117
+ }
118
+ /** Set tracker for a subscriber. */
119
+ setSubscriberTracker(entry, client, tracker) {
120
+ const sub = entry.subscribers.get(clientKey(client));
121
+ if (sub)
122
+ sub.tracker = tracker;
123
+ }
124
+ /** Remove and destroy a process entry, cleaning up all subscribers. */
125
+ destroy(repo, sessionId) {
126
+ const pKey = processKey(repo, sessionId);
127
+ const entry = this.entries.get(pKey);
128
+ if (!entry)
129
+ return;
130
+ // Clean up all subscribers
131
+ for (const [cKey, sub] of entry.subscribers) {
132
+ if (sub.accumulator)
133
+ sub.accumulator.finalize();
134
+ if (sub.tracker)
135
+ sub.tracker.reset();
136
+ this.clientIndex.delete(cKey);
137
+ }
138
+ entry.ccProcess.destroy();
139
+ this.entries.delete(pKey);
140
+ }
141
+ /** Remove entry without destroying the process (caller manages destruction). */
142
+ remove(repo, sessionId) {
143
+ const pKey = processKey(repo, sessionId);
144
+ const entry = this.entries.get(pKey);
145
+ if (!entry)
146
+ return;
147
+ for (const [cKey, sub] of entry.subscribers) {
148
+ if (sub.accumulator)
149
+ sub.accumulator.finalize();
150
+ if (sub.tracker)
151
+ sub.tracker.reset();
152
+ this.clientIndex.delete(cKey);
153
+ }
154
+ this.entries.delete(pKey);
155
+ }
156
+ /** Iterate all subscribers of an entry. */
157
+ *subscribers(entry) {
158
+ for (const sub of entry.subscribers.values()) {
159
+ yield sub;
160
+ }
161
+ }
162
+ /** Check if a client is subscribed anywhere. */
163
+ hasClient(client) {
164
+ return this.clientIndex.has(clientKey(client));
165
+ }
166
+ /** Get all entries (for shutdown). */
167
+ allEntries() {
168
+ return [...this.entries.values()];
169
+ }
170
+ /** Clear everything. */
171
+ clear() {
172
+ this.entries.clear();
173
+ this.clientIndex.clear();
174
+ }
175
+ }
176
+ //# sourceMappingURL=process-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-registry.js","sourceRoot":"","sources":["../src/process-registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,gBAAgB;AAEhB,SAAS,UAAU,CAAC,IAAY,EAAE,SAAiB;IACjD,OAAO,GAAG,IAAI,IAAI,SAAS,EAAE,CAAC;AAChC,CAAC;AAED,SAAS,SAAS,CAAC,GAAc;IAC/B,OAAO,GAAG,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,iBAAiB;AAEjB,MAAM,OAAO,eAAe;IAClB,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;IAClD,oEAAoE;IAC5D,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEhD,8DAA8D;IAC9D,GAAG,CAAC,IAAY,EAAE,SAAiB;QACjC,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,IAAI,CAAC;IAC/D,CAAC;IAED,sDAAsD;IACtD,QAAQ,CAAC,IAAY,EAAE,SAAiB,EAAE,KAAa,EAAE,IAAe,EAAE,KAAgB;QACxF,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAE9B,MAAM,KAAK,GAAiB;YAC1B,SAAS,EAAE,IAAI;YACf,IAAI;YACJ,SAAS;YACT,KAAK;YACL,KAAK;YACL,WAAW,EAAE,IAAI,GAAG,EAAE;SACvB,CAAC;QAEF,uCAAuC;QACvC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE;YAC1B,MAAM,EAAE,KAAK;YACb,WAAW,EAAE,IAAI;YACjB,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QAEH,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAEjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,sGAAsG;IACtG,SAAS,CAAC,IAAY,EAAE,SAAiB,EAAE,MAAiB;QAC1D,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QAExB,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAE/B,mCAAmC;QACnC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE;gBAC1B,MAAM;gBACN,WAAW,EAAE,IAAI;gBACjB,OAAO,EAAE,IAAI;aACd,CAAC,CAAC;QACL,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,6FAA6F;IAC7F,WAAW,CAAC,MAAiB;QAC3B,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,KAAK,CAAC;QAExB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC9B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,4CAA4C;QAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,GAAG,EAAE,CAAC;YACR,IAAI,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAChD,IAAI,GAAG,CAAC,OAAO;gBAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACvC,CAAC;QAED,KAAK,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAE9B,gDAAgD;QAChD,IAAI,KAAK,CAAC,WAAW,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACjC,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;IAED,gCAAgC;IAChC,YAAY,CAAC,MAAiB;QAC5B,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACxC,CAAC;IAED,uDAAuD;IACvD,aAAa,CAAC,IAAe;QAC3B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC1C,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;QAC7C,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,4DAA4D;IAC5D,aAAa,CAAC,KAAmB,EAAE,MAAiB;QAClD,OAAO,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,IAAI,CAAC;IAC1D,CAAC;IAED,wCAAwC;IACxC,wBAAwB,CAAC,KAAmB,EAAE,MAAiB,EAAE,GAAsB;QACrF,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACrD,IAAI,GAAG;YAAE,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC;IACjC,CAAC;IAED,oCAAoC;IACpC,oBAAoB,CAAC,KAAmB,EAAE,MAAiB,EAAE,OAAwB;QACnF,MAAM,GAAG,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QACrD,IAAI,GAAG;YAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAC;IACjC,CAAC;IAED,uEAAuE;IACvE,OAAO,CAAC,IAAY,EAAE,SAAiB;QACrC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,2BAA2B;QAC3B,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAChD,IAAI,GAAG,CAAC,OAAO;gBAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAED,KAAK,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,gFAAgF;IAChF,MAAM,CAAC,IAAY,EAAE,SAAiB;QACpC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACzC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK;YAAE,OAAO;QAEnB,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5C,IAAI,GAAG,CAAC,WAAW;gBAAE,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAChD,IAAI,GAAG,CAAC,OAAO;gBAAE,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACrC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,2CAA2C;IAC3C,CAAC,WAAW,CAAC,KAAmB;QAC9B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,gDAAgD;IAChD,SAAS,CAAC,MAAiB;QACzB,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,sCAAsC;IACtC,UAAU;QACR,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IAED,wBAAwB;IACxB,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QACrB,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;CACF"}
package/dist/session.d.ts CHANGED
@@ -1,25 +1,10 @@
1
1
  import type pino from 'pino';
2
- export interface SessionInfo {
3
- id: string;
4
- title?: string;
5
- startedAt: string;
6
- lastActivity: string;
7
- messageCount: number;
8
- totalCostUsd: number;
9
- }
10
- export interface JsonlTracking {
11
- size: number;
12
- mtimeMs: number;
13
- }
14
2
  export interface UserState {
15
3
  currentSessionId: string | null;
16
4
  lastActivity: string;
17
5
  model: string;
18
6
  repo: string;
19
7
  permissionMode: string;
20
- sessions: SessionInfo[];
21
- knownSessionIds: string[];
22
- jsonlTracking?: JsonlTracking;
23
8
  }
24
9
  export interface AgentState {
25
10
  users: Record<string, UserState>;
@@ -37,17 +22,10 @@ export declare class SessionStore {
37
22
  private ensureUser;
38
23
  getUser(agentId: string, userId: string): UserState;
39
24
  setCurrentSession(agentId: string, userId: string, sessionId: string): void;
40
- updateSessionActivity(agentId: string, userId: string, cost?: number): void;
41
25
  setModel(agentId: string, userId: string, model: string): void;
42
26
  setRepo(agentId: string, userId: string, repo: string): void;
43
27
  setPermissionMode(agentId: string, userId: string, mode: string): void;
44
- setSessionTitle(agentId: string, userId: string, sessionId: string, title: string): void;
45
- updateJsonlTracking(agentId: string, userId: string, size: number, mtimeMs: number): void;
46
- getJsonlTracking(agentId: string, userId: string): JsonlTracking | undefined;
47
- clearJsonlTracking(agentId: string, userId: string): void;
48
28
  clearSession(agentId: string, userId: string): void;
49
- deleteSession(agentId: string, userId: string, sessionId: string): boolean;
50
- getRecentSessions(agentId: string, userId: string, limit?: number): SessionInfo[];
51
29
  getFullState(): StateStore;
52
30
  }
53
31
  /**
@@ -55,17 +33,17 @@ export declare class SessionStore {
55
33
  * CC stores sessions at ~/.claude/projects/<repo-slug>/<sessionId>.jsonl
56
34
  */
57
35
  export declare function getSessionJsonlPath(sessionId: string, repo: string): string;
58
- /**
59
- * Read new JSONL entries from a byte offset and summarize the turns.
60
- * Returns a formatted catch-up message or null if nothing meaningful was found.
61
- */
62
- export declare function summarizeJsonlDelta(jsonlPath: string, fromByteOffset: number, maxChars?: number): string | null;
63
- export interface MissedSession {
36
+ export declare function computeProjectSlug(repoPath: string): string;
37
+ export interface DiscoveredSession {
64
38
  id: string;
39
+ title: string;
40
+ model: string | null;
65
41
  mtime: Date;
66
- files: string[];
42
+ lineCount: number;
43
+ contextPct: number | null;
67
44
  }
68
- export declare function computeProjectSlug(repoPath: string): string;
69
- export declare function findMissedSessions(repo: string, knownSessionIds: string[], lastActivity: Date): MissedSession[];
70
- export declare function parseSessionSummary(sessionDir: string): string;
71
- export declare function formatCatchupMessage(repo: string, missed: MissedSession[]): string;
45
+ /**
46
+ * Discover CC sessions from ~/.claude/projects/<slug>/*.jsonl
47
+ * Returns the most recent sessions sorted by modification time.
48
+ */
49
+ export declare function discoverCCSessions(repo: string, limit?: number): DiscoveredSession[];