instar 1.2.81 → 1.2.83
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/commands/server.d.ts.map +1 -1
- package/dist/commands/server.js +110 -11
- package/dist/commands/server.js.map +1 -1
- package/dist/config/ConfigDefaults.d.ts.map +1 -1
- package/dist/config/ConfigDefaults.js +23 -0
- package/dist/config/ConfigDefaults.js.map +1 -1
- package/dist/core/PostUpdateMigrator.d.ts +7 -0
- package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
- package/dist/core/PostUpdateMigrator.js +59 -75
- package/dist/core/PostUpdateMigrator.js.map +1 -1
- package/dist/core/SessionManager.d.ts +43 -0
- package/dist/core/SessionManager.d.ts.map +1 -1
- package/dist/core/SessionManager.js +123 -24
- package/dist/core/SessionManager.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/monitoring/SessionReaper.d.ts +153 -0
- package/dist/monitoring/SessionReaper.d.ts.map +1 -0
- package/dist/monitoring/SessionReaper.js +376 -0
- package/dist/monitoring/SessionReaper.js.map +1 -0
- package/dist/monitoring/TokenLedger.d.ts +12 -0
- package/dist/monitoring/TokenLedger.d.ts.map +1 -1
- package/dist/monitoring/TokenLedger.js +22 -0
- package/dist/monitoring/TokenLedger.js.map +1 -1
- package/dist/monitoring/transcriptProber.d.ts +44 -0
- package/dist/monitoring/transcriptProber.d.ts.map +1 -0
- package/dist/monitoring/transcriptProber.js +57 -0
- package/dist/monitoring/transcriptProber.js.map +1 -0
- package/dist/scaffold/templates.d.ts.map +1 -1
- package/dist/scaffold/templates.js +21 -0
- package/dist/scaffold/templates.js.map +1 -1
- package/dist/server/AgentServer.d.ts +3 -0
- package/dist/server/AgentServer.d.ts.map +1 -1
- package/dist/server/AgentServer.js +1 -0
- package/dist/server/AgentServer.js.map +1 -1
- package/dist/server/routes.d.ts +3 -0
- package/dist/server/routes.d.ts.map +1 -1
- package/dist/server/routes.js +108 -0
- package/dist/server/routes.js.map +1 -1
- package/dist/threadline/CollaborationSurfacer.d.ts +67 -18
- package/dist/threadline/CollaborationSurfacer.d.ts.map +1 -1
- package/dist/threadline/CollaborationSurfacer.js +132 -37
- package/dist/threadline/CollaborationSurfacer.js.map +1 -1
- package/package.json +1 -1
- package/src/data/builtin-manifest.json +63 -63
- package/src/scaffold/templates.ts +21 -0
- package/upgrades/1.2.81.md +13 -0
- package/upgrades/1.2.82.md +26 -0
- package/upgrades/1.2.83.md +26 -0
- package/upgrades/side-effects/1.2.81.md +127 -0
- package/upgrades/side-effects/session-reaper.md +42 -0
- package/upgrades/side-effects/threadline-notification-routing.md +46 -0
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CollaborationSurfacer —
|
|
3
|
-
* the operator (CMT-509 §2
|
|
2
|
+
* CollaborationSurfacer — the single funnel for making Threadline activity
|
|
3
|
+
* visible to the operator WITHOUT spawning a topic per event (CMT-509 §2 +
|
|
4
|
+
* CMT-519 notification routing).
|
|
4
5
|
*
|
|
5
|
-
* Routing spine (operator
|
|
6
|
-
* - A conversation WITH a parent topic
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* topic.
|
|
6
|
+
* Routing spine (operator directives 2026-05-25):
|
|
7
|
+
* - A conversation WITH a parent topic surfaces THERE via TopicLinkageHandler —
|
|
8
|
+
* this surfacer does NOT touch its *content* (real replies).
|
|
9
|
+
* - A PARENTLESS conversation (a peer reached out cold) surfaces to a SINGLE
|
|
10
|
+
* dedicated "Threadline" Telegram topic — created on demand once and reused,
|
|
11
|
+
* NEVER the generic attention list, NEVER a per-thread/per-event topic.
|
|
12
|
+
* - STATUS / housekeeping notices (loop-gate wind-down, etc. — `notify()`) go to
|
|
13
|
+
* that SAME silent hub, NEVER the parent topic the operator is working in (D1).
|
|
13
14
|
*
|
|
14
|
-
* Near-silent by design:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Near-silent by design (D2): the hub is SILENT — agent-to-agent activity does
|
|
16
|
+
* not buzz the operator and is never framed as "waiting for you" (it isn't the
|
|
17
|
+
* operator's job by default). The hub is a calm, browsable record; the operator
|
|
18
|
+
* engages it on their own schedule ("open this" / "tie this to <topic>"). The
|
|
19
|
+
* only thing that breaks silence is a genuine user-facing escalation, which
|
|
20
|
+
* surfaces normally via its parent topic — not through this surfacer.
|
|
21
|
+
*
|
|
22
|
+
* One post per parentless conversation (`surface()` dedupes per thread). Never
|
|
23
|
+
* emits raw envelope/JSON.
|
|
17
24
|
*/
|
|
18
25
|
export interface SurfacerTelegram {
|
|
19
26
|
findOrCreateForumTopic(name: string, iconColor?: number): Promise<{
|
|
@@ -51,6 +58,21 @@ export interface SurfaceResult {
|
|
|
51
58
|
reason: string;
|
|
52
59
|
topicId?: number;
|
|
53
60
|
}
|
|
61
|
+
/** A STATUS / housekeeping notice (loop-gate, etc.) — hub-only, never parent. */
|
|
62
|
+
export interface NotifyInput {
|
|
63
|
+
threadId: string;
|
|
64
|
+
title: string;
|
|
65
|
+
body: string;
|
|
66
|
+
peerName?: string;
|
|
67
|
+
}
|
|
68
|
+
/** Per-conversation record in the hub (replaces the legacy string[] of threadIds). */
|
|
69
|
+
export interface SurfacedThreadRecord {
|
|
70
|
+
threadId: string;
|
|
71
|
+
peerName: string;
|
|
72
|
+
subject?: string;
|
|
73
|
+
surfacedAt: string;
|
|
74
|
+
bound: boolean;
|
|
75
|
+
}
|
|
54
76
|
export declare class CollaborationSurfacer {
|
|
55
77
|
private telegram;
|
|
56
78
|
private filePath;
|
|
@@ -58,15 +80,42 @@ export declare class CollaborationSurfacer {
|
|
|
58
80
|
private log;
|
|
59
81
|
constructor(config: CollaborationSurfacerConfig);
|
|
60
82
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* inbound path) — returns a structured result.
|
|
83
|
+
* Surface a PARENTLESS first-contact conversation to the silent hub. Idempotent
|
|
84
|
+
* per thread. Never throws (best-effort; must not break the inbound path).
|
|
64
85
|
*/
|
|
65
86
|
surface(input: SurfaceInput): Promise<SurfaceResult>;
|
|
66
|
-
/**
|
|
87
|
+
/**
|
|
88
|
+
* Post a STATUS / housekeeping notice to the SILENT hub. Used by threadline
|
|
89
|
+
* subsystems (loop-gate wind-down, etc.) INSTEAD of `createAttentionItem` —
|
|
90
|
+
* so they never spawn a per-event topic and never clutter the parent topic
|
|
91
|
+
* the operator is working in (D1). Silent (D2). Never throws.
|
|
92
|
+
*/
|
|
93
|
+
notify(input: NotifyInput): Promise<SurfaceResult>;
|
|
94
|
+
/** The dedicated hub topic id, if one has been created. */
|
|
95
|
+
getHubTopicId(): number | undefined;
|
|
96
|
+
/**
|
|
97
|
+
* The most-recently-surfaced conversation not yet bound to its own topic —
|
|
98
|
+
* the default target for a bare "open this" in the hub. Returns null when the
|
|
99
|
+
* choice is ambiguous (>1 unbound) so the caller can ask the operator which.
|
|
100
|
+
*/
|
|
101
|
+
mostRecentUnbound(): {
|
|
102
|
+
record: SurfacedThreadRecord | null;
|
|
103
|
+
ambiguous: boolean;
|
|
104
|
+
};
|
|
105
|
+
/** Mark a surfaced conversation as bound (after "open this" / "tie this to X"). */
|
|
106
|
+
markBound(threadId: string): void;
|
|
107
|
+
/** Post a one-line note into the hub (e.g. "Opened → topic <name>"). */
|
|
108
|
+
noteInHub(text: string): Promise<void>;
|
|
109
|
+
private ensureHubTopic;
|
|
110
|
+
/** A readable, capped gist — NEVER raw envelope/JSON. */
|
|
67
111
|
private readableGist;
|
|
68
112
|
private readablePeer;
|
|
113
|
+
/**
|
|
114
|
+
* Load state with a READ-TIME MIGRATION from the legacy `surfacedThreads:
|
|
115
|
+
* string[]` shape to the `surfaced: SurfacedThreadRecord[]` shape. A legacy
|
|
116
|
+
* file's threadIds become bound:false records with an unknown peer.
|
|
117
|
+
*/
|
|
69
118
|
private load;
|
|
70
|
-
private
|
|
119
|
+
private trimAndSave;
|
|
71
120
|
}
|
|
72
121
|
//# sourceMappingURL=CollaborationSurfacer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollaborationSurfacer.d.ts","sourceRoot":"","sources":["../../src/threadline/CollaborationSurfacer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CollaborationSurfacer.d.ts","sourceRoot":"","sources":["../../src/threadline/CollaborationSurfacer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,MAAM,WAAW,gBAAgB;IAC/B,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,cAAc,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxH;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oCAAoC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE;QAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAA;KAAE,CAAC;CACrC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,cAAc,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,sFAAsF;AACtF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;CAChB;AAUD,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,GAAG,CAAgC;gBAE/B,MAAM,EAAE,2BAA2B;IAS/C;;;OAGG;IACG,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IA+B1D;;;;;OAKG;IACG,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC;IAkBxD,2DAA2D;IAC3D,aAAa,IAAI,MAAM,GAAG,SAAS;IAInC;;;;OAIG;IACH,iBAAiB,IAAI;QAAE,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,OAAO,CAAA;KAAE;IAOhF,mFAAmF;IACnF,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IASjC,wEAAwE;IAClE,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAa9B,cAAc;IAO5B,yDAAyD;IACzD,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,YAAY;IAOpB;;;;OAIG;IACH,OAAO,CAAC,IAAI;IA2BZ,OAAO,CAAC,WAAW;CAYpB"}
|
|
@@ -1,24 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CollaborationSurfacer —
|
|
3
|
-
* the operator (CMT-509 §2
|
|
2
|
+
* CollaborationSurfacer — the single funnel for making Threadline activity
|
|
3
|
+
* visible to the operator WITHOUT spawning a topic per event (CMT-509 §2 +
|
|
4
|
+
* CMT-519 notification routing).
|
|
4
5
|
*
|
|
5
|
-
* Routing spine (operator
|
|
6
|
-
* - A conversation WITH a parent topic
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* topic.
|
|
6
|
+
* Routing spine (operator directives 2026-05-25):
|
|
7
|
+
* - A conversation WITH a parent topic surfaces THERE via TopicLinkageHandler —
|
|
8
|
+
* this surfacer does NOT touch its *content* (real replies).
|
|
9
|
+
* - A PARENTLESS conversation (a peer reached out cold) surfaces to a SINGLE
|
|
10
|
+
* dedicated "Threadline" Telegram topic — created on demand once and reused,
|
|
11
|
+
* NEVER the generic attention list, NEVER a per-thread/per-event topic.
|
|
12
|
+
* - STATUS / housekeeping notices (loop-gate wind-down, etc. — `notify()`) go to
|
|
13
|
+
* that SAME silent hub, NEVER the parent topic the operator is working in (D1).
|
|
13
14
|
*
|
|
14
|
-
* Near-silent by design:
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Near-silent by design (D2): the hub is SILENT — agent-to-agent activity does
|
|
16
|
+
* not buzz the operator and is never framed as "waiting for you" (it isn't the
|
|
17
|
+
* operator's job by default). The hub is a calm, browsable record; the operator
|
|
18
|
+
* engages it on their own schedule ("open this" / "tie this to <topic>"). The
|
|
19
|
+
* only thing that breaks silence is a genuine user-facing escalation, which
|
|
20
|
+
* surfaces normally via its parent topic — not through this surfacer.
|
|
21
|
+
*
|
|
22
|
+
* One post per parentless conversation (`surface()` dedupes per thread). Never
|
|
23
|
+
* emits raw envelope/JSON.
|
|
17
24
|
*/
|
|
18
25
|
import fs from 'node:fs';
|
|
19
26
|
import path from 'node:path';
|
|
20
27
|
const MAX_GIST_LEN = 240;
|
|
21
|
-
const
|
|
28
|
+
const MAX_SURFACED = 500; // bound the record list
|
|
22
29
|
export class CollaborationSurfacer {
|
|
23
30
|
telegram;
|
|
24
31
|
filePath;
|
|
@@ -33,9 +40,8 @@ export class CollaborationSurfacer {
|
|
|
33
40
|
this.log = config.log ?? console;
|
|
34
41
|
}
|
|
35
42
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* inbound path) — returns a structured result.
|
|
43
|
+
* Surface a PARENTLESS first-contact conversation to the silent hub. Idempotent
|
|
44
|
+
* per thread. Never throws (best-effort; must not break the inbound path).
|
|
39
45
|
*/
|
|
40
46
|
async surface(input) {
|
|
41
47
|
try {
|
|
@@ -44,24 +50,22 @@ export class CollaborationSurfacer {
|
|
|
44
50
|
if (!input.warrants)
|
|
45
51
|
return { surfaced: false, reason: 'not-warranted' };
|
|
46
52
|
const state = this.load();
|
|
47
|
-
if (state.
|
|
53
|
+
if (state.surfaced.some(r => r.threadId === input.threadId)) {
|
|
48
54
|
return { surfaced: false, reason: 'already-surfaced' };
|
|
49
55
|
}
|
|
50
|
-
|
|
51
|
-
if (typeof topicId !== 'number') {
|
|
52
|
-
const t = await this.telegram.findOrCreateForumTopic(this.topicName);
|
|
53
|
-
topicId = t.topicId;
|
|
54
|
-
state.dedicatedTopicId = topicId;
|
|
55
|
-
}
|
|
56
|
+
const topicId = await this.ensureHubTopic(state);
|
|
56
57
|
const gist = this.readableGist(input.text);
|
|
57
58
|
const peer = this.readablePeer(input.senderName);
|
|
58
|
-
const body = `🧵 ${peer} started a Threadline conversation:\n${gist}\n\n(reply in-thread, or say "open this" to
|
|
59
|
+
const body = `🧵 ${peer} started a Threadline conversation:\n${gist}\n\n(reply in-thread, or say "open this" to give it its own topic)`;
|
|
59
60
|
await this.telegram.sendToTopic(topicId, body, { silent: true });
|
|
60
|
-
state.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
state.surfaced.push({
|
|
62
|
+
threadId: input.threadId,
|
|
63
|
+
peerName: peer,
|
|
64
|
+
subject: gist.slice(0, 80),
|
|
65
|
+
surfacedAt: new Date().toISOString(),
|
|
66
|
+
bound: false,
|
|
67
|
+
});
|
|
68
|
+
this.trimAndSave(state);
|
|
65
69
|
return { surfaced: true, reason: 'posted', topicId };
|
|
66
70
|
}
|
|
67
71
|
catch (err) {
|
|
@@ -69,10 +73,78 @@ export class CollaborationSurfacer {
|
|
|
69
73
|
return { surfaced: false, reason: 'error' };
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
|
-
/**
|
|
76
|
+
/**
|
|
77
|
+
* Post a STATUS / housekeeping notice to the SILENT hub. Used by threadline
|
|
78
|
+
* subsystems (loop-gate wind-down, etc.) INSTEAD of `createAttentionItem` —
|
|
79
|
+
* so they never spawn a per-event topic and never clutter the parent topic
|
|
80
|
+
* the operator is working in (D1). Silent (D2). Never throws.
|
|
81
|
+
*/
|
|
82
|
+
async notify(input) {
|
|
83
|
+
try {
|
|
84
|
+
const state = this.load();
|
|
85
|
+
const topicId = await this.ensureHubTopic(state);
|
|
86
|
+
const peer = input.peerName ? this.readablePeer(input.peerName) : undefined;
|
|
87
|
+
const head = peer ? `🧵 ${input.title} — ${peer}` : `🧵 ${input.title}`;
|
|
88
|
+
const body = `${head}\n${this.readableGist(input.body)}`;
|
|
89
|
+
await this.telegram.sendToTopic(topicId, body, { silent: true });
|
|
90
|
+
// Persist the hub-topic id if we just created it; status notices are not
|
|
91
|
+
// per-thread-deduped (a status can legitimately recur).
|
|
92
|
+
this.trimAndSave(state);
|
|
93
|
+
return { surfaced: true, reason: 'notified', topicId };
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
this.log.warn(`[CollaborationSurfacer] notify failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
97
|
+
return { surfaced: false, reason: 'error' };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/** The dedicated hub topic id, if one has been created. */
|
|
101
|
+
getHubTopicId() {
|
|
102
|
+
return this.load().dedicatedTopicId;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* The most-recently-surfaced conversation not yet bound to its own topic —
|
|
106
|
+
* the default target for a bare "open this" in the hub. Returns null when the
|
|
107
|
+
* choice is ambiguous (>1 unbound) so the caller can ask the operator which.
|
|
108
|
+
*/
|
|
109
|
+
mostRecentUnbound() {
|
|
110
|
+
const unbound = this.load().surfaced.filter(r => !r.bound);
|
|
111
|
+
if (unbound.length === 0)
|
|
112
|
+
return { record: null, ambiguous: false };
|
|
113
|
+
const sorted = [...unbound].sort((a, b) => b.surfacedAt.localeCompare(a.surfacedAt));
|
|
114
|
+
return { record: sorted[0], ambiguous: unbound.length > 1 };
|
|
115
|
+
}
|
|
116
|
+
/** Mark a surfaced conversation as bound (after "open this" / "tie this to X"). */
|
|
117
|
+
markBound(threadId) {
|
|
118
|
+
const state = this.load();
|
|
119
|
+
const rec = state.surfaced.find(r => r.threadId === threadId);
|
|
120
|
+
if (rec && !rec.bound) {
|
|
121
|
+
rec.bound = true;
|
|
122
|
+
this.trimAndSave(state);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
/** Post a one-line note into the hub (e.g. "Opened → topic <name>"). */
|
|
126
|
+
async noteInHub(text) {
|
|
127
|
+
try {
|
|
128
|
+
const state = this.load();
|
|
129
|
+
const topicId = await this.ensureHubTopic(state);
|
|
130
|
+
await this.telegram.sendToTopic(topicId, text, { silent: true });
|
|
131
|
+
this.trimAndSave(state);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
this.log.warn(`[CollaborationSurfacer] noteInHub failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// ── internals ──────────────────────────────────────────────────
|
|
138
|
+
async ensureHubTopic(state) {
|
|
139
|
+
if (typeof state.dedicatedTopicId === 'number')
|
|
140
|
+
return state.dedicatedTopicId;
|
|
141
|
+
const t = await this.telegram.findOrCreateForumTopic(this.topicName);
|
|
142
|
+
state.dedicatedTopicId = t.topicId;
|
|
143
|
+
return t.topicId;
|
|
144
|
+
}
|
|
145
|
+
/** A readable, capped gist — NEVER raw envelope/JSON. */
|
|
73
146
|
readableGist(text) {
|
|
74
147
|
let t = (text ?? '').trim();
|
|
75
|
-
// Defend against the funnel's JSON.stringify(content) path reaching the user.
|
|
76
148
|
if ((t.startsWith('{') && t.endsWith('}')) || (t.startsWith('[') && t.endsWith(']'))) {
|
|
77
149
|
try {
|
|
78
150
|
const parsed = JSON.parse(t);
|
|
@@ -92,23 +164,46 @@ export class CollaborationSurfacer {
|
|
|
92
164
|
const n = (name ?? '').trim();
|
|
93
165
|
if (!n)
|
|
94
166
|
return 'An agent';
|
|
95
|
-
// Fingerprint-looking → shorten.
|
|
96
167
|
if (/^[a-f0-9]{16,}$/i.test(n))
|
|
97
168
|
return n.slice(0, 8);
|
|
98
169
|
return n;
|
|
99
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* Load state with a READ-TIME MIGRATION from the legacy `surfacedThreads:
|
|
173
|
+
* string[]` shape to the `surfaced: SurfacedThreadRecord[]` shape. A legacy
|
|
174
|
+
* file's threadIds become bound:false records with an unknown peer.
|
|
175
|
+
*/
|
|
100
176
|
load() {
|
|
101
177
|
try {
|
|
102
178
|
if (fs.existsSync(this.filePath)) {
|
|
103
179
|
const data = JSON.parse(fs.readFileSync(this.filePath, 'utf-8'));
|
|
104
|
-
if (data &&
|
|
105
|
-
|
|
180
|
+
if (data && typeof data === 'object') {
|
|
181
|
+
if (Array.isArray(data.surfaced)) {
|
|
182
|
+
return { dedicatedTopicId: data.dedicatedTopicId, surfaced: data.surfaced };
|
|
183
|
+
}
|
|
184
|
+
if (Array.isArray(data.surfacedThreads)) {
|
|
185
|
+
// Legacy → records.
|
|
186
|
+
const surfaced = data.surfacedThreads.map(threadId => ({
|
|
187
|
+
threadId,
|
|
188
|
+
peerName: 'An agent',
|
|
189
|
+
surfacedAt: new Date(0).toISOString(),
|
|
190
|
+
bound: false,
|
|
191
|
+
}));
|
|
192
|
+
return { dedicatedTopicId: data.dedicatedTopicId, surfaced };
|
|
193
|
+
}
|
|
194
|
+
if (typeof data.dedicatedTopicId === 'number') {
|
|
195
|
+
return { dedicatedTopicId: data.dedicatedTopicId, surfaced: [] };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
106
198
|
}
|
|
107
199
|
}
|
|
108
200
|
catch { /* corrupt — start fresh */ }
|
|
109
|
-
return {
|
|
201
|
+
return { surfaced: [] };
|
|
110
202
|
}
|
|
111
|
-
|
|
203
|
+
trimAndSave(state) {
|
|
204
|
+
if (state.surfaced.length > MAX_SURFACED) {
|
|
205
|
+
state.surfaced = state.surfaced.slice(-MAX_SURFACED);
|
|
206
|
+
}
|
|
112
207
|
try {
|
|
113
208
|
const tmp = `${this.filePath}.${process.pid}.tmp`;
|
|
114
209
|
fs.writeFileSync(tmp, JSON.stringify(state, null, 2) + '\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollaborationSurfacer.js","sourceRoot":"","sources":["../../src/threadline/CollaborationSurfacer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"CollaborationSurfacer.js","sourceRoot":"","sources":["../../src/threadline/CollaborationSurfacer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED