@triflux/core 10.44.0 → 10.46.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.
- package/hooks/codex-session-hook.mjs +67 -1
- package/hooks/cto-north-star-brief.mjs +3 -16
- package/hooks/error-context.mjs +3 -6
- package/hooks/hook-manager.mjs +1 -1
- package/hooks/hook-registry.json +0 -11
- package/hooks/keyword-rules.json +8 -4
- package/hooks/permission-safe-allow.mjs +36 -2
- package/hooks/session-start-fast.mjs +50 -1
- package/hooks/session-start-lake.mjs +3 -16
- package/hub/bridge.mjs +111 -5
- package/hub/dynamic-routing-engine.mjs +1 -1
- package/hub/gemini-adapter.mjs +29 -11
- package/hub/lib/memory-store.mjs +66 -30
- package/hub/lib/tfx-route-args.mjs +41 -4
- package/hub/reflexion.mjs +0 -57
- package/hub/router.mjs +202 -24
- package/hub/team/claude-daemon-control.mjs +2 -0
- package/hub/team/retry-state-machine.mjs +47 -16
- package/hud/cli-policy.mjs +69 -0
- package/hud/constants.mjs +20 -17
- package/hud/context-monitor.mjs +31 -21
- package/hud/hud-qos-status.mjs +81 -91
- package/hud/providers/claude.mjs +150 -84
- package/hud/providers/codex.mjs +10 -1
- package/hud/renderers.mjs +21 -59
- package/hud/utils.mjs +1 -15
- package/package.json +1 -1
- package/scripts/lib/agent-route-policy.mjs +47 -39
- package/scripts/lib/cli-agy.mjs +24 -4
- package/scripts/lib/codex-profile-config.mjs +45 -13
- package/scripts/lib/gemini-profiles.mjs +113 -29
- package/scripts/lib/keyword-rules.mjs +12 -0
- package/scripts/lib/logger.mjs +60 -43
- package/scripts/lib/machine-profile.mjs +293 -0
- package/scripts/lib/mcp-health.mjs +44 -18
package/hub/gemini-adapter.mjs
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
import { mkdirSync } from "node:fs";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
+
import {
|
|
8
|
+
resolveGeminiModel,
|
|
9
|
+
resolveGeminiProfileForPurpose,
|
|
10
|
+
} from "../scripts/lib/gemini-profiles.mjs";
|
|
7
11
|
import {
|
|
8
12
|
executeWithCircuitBroker,
|
|
9
13
|
normalizePathForShell,
|
|
@@ -61,15 +65,13 @@ async function runPreflight(opts = {}) {
|
|
|
61
65
|
// ── Command building ────────────────────────────────────────────
|
|
62
66
|
|
|
63
67
|
function buildGeminiCommand(prompt, resultFile, opts = {}) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"--dangerously-skip-permissions",
|
|
72
|
-
];
|
|
68
|
+
// agy 의 --print 는 값(프롬프트)을 받는 플래그다. 1.1.27 부터 stdin 프롬프트는
|
|
69
|
+
// "empty prompt" 로 거부되므로 프롬프트를 --print 의 값으로, 맨 끝에 넘긴다.
|
|
70
|
+
const parts = ["agy", "--dangerously-skip-permissions"];
|
|
71
|
+
if (typeof opts.model === "string" && opts.model.trim()) {
|
|
72
|
+
parts.push("--model", shellSingleQuote(opts.model.trim()));
|
|
73
|
+
}
|
|
74
|
+
parts.push("--print", shellSingleQuote(prompt));
|
|
73
75
|
|
|
74
76
|
if (resultFile) {
|
|
75
77
|
return `${parts.join(" ")} > ${shellSingleQuote(normalizePathForShell(resultFile))} 2>${shellSingleQuote(normalizePathForShell(resultFile + ".err"))}`;
|
|
@@ -78,11 +80,27 @@ function buildGeminiCommand(prompt, resultFile, opts = {}) {
|
|
|
78
80
|
return parts.join(" ");
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
function resolveAntigravityModel(opts = {}) {
|
|
84
|
+
// effort 는 역할별 SSOT(scripts/lib/gemini-profiles.mjs). 명시 model 이 우선한다.
|
|
85
|
+
const explicit = typeof opts.model === "string" ? opts.model.trim() : "";
|
|
86
|
+
if (explicit)
|
|
87
|
+
return resolveGeminiModel(explicit, {
|
|
88
|
+
profilesPath: opts.geminiProfilesPath,
|
|
89
|
+
});
|
|
90
|
+
if (!opts.role && !opts.agent) return "";
|
|
91
|
+
return resolveGeminiModel(
|
|
92
|
+
resolveGeminiProfileForPurpose(opts.role || opts.agent),
|
|
93
|
+
{
|
|
94
|
+
profilesPath: opts.geminiProfilesPath,
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
function buildAttempts(opts, preflight) {
|
|
82
100
|
const timeout = Number.isFinite(opts.timeout) ? opts.timeout : 900_000;
|
|
83
101
|
const base = {
|
|
84
102
|
timeout,
|
|
85
|
-
model: opts
|
|
103
|
+
model: resolveAntigravityModel(opts),
|
|
86
104
|
allowedMcpServers: Array.isArray(opts.mcpServers)
|
|
87
105
|
? [...opts.mcpServers]
|
|
88
106
|
: [],
|
|
@@ -98,7 +116,7 @@ function buildAttempts(opts, preflight) {
|
|
|
98
116
|
export function buildExecArgs(opts = {}) {
|
|
99
117
|
const prompt = typeof opts.prompt === "string" ? opts.prompt : "";
|
|
100
118
|
return buildGeminiCommand(prompt, opts.resultFile || null, {
|
|
101
|
-
model: opts
|
|
119
|
+
model: resolveAntigravityModel(opts),
|
|
102
120
|
allowedMcpServers: opts.mcpServers,
|
|
103
121
|
});
|
|
104
122
|
}
|
package/hub/lib/memory-store.mjs
CHANGED
|
@@ -142,6 +142,7 @@ export function createMemoryStore() {
|
|
|
142
142
|
const store = {
|
|
143
143
|
type: "memory",
|
|
144
144
|
db: null,
|
|
145
|
+
fingerprint: "memory:ephemeral",
|
|
145
146
|
uuidv7,
|
|
146
147
|
|
|
147
148
|
close() {},
|
|
@@ -166,6 +167,7 @@ export function createMemoryStore() {
|
|
|
166
167
|
topics: clone(topics),
|
|
167
168
|
last_seen_ms: now,
|
|
168
169
|
lease_expires_ms: now + heartbeat_ttl_ms,
|
|
170
|
+
presence_generation: Number(current.presence_generation || 0) + 1,
|
|
169
171
|
status: "online",
|
|
170
172
|
metadata: clone(metadata),
|
|
171
173
|
};
|
|
@@ -173,6 +175,7 @@ export function createMemoryStore() {
|
|
|
173
175
|
return {
|
|
174
176
|
agent_id,
|
|
175
177
|
lease_id: uuidv7(),
|
|
178
|
+
presence_generation: next.presence_generation,
|
|
176
179
|
lease_expires_ms: next.lease_expires_ms,
|
|
177
180
|
server_time_ms: now,
|
|
178
181
|
effective: {
|
|
@@ -183,6 +186,7 @@ export function createMemoryStore() {
|
|
|
183
186
|
lease_expires_ms: next.lease_expires_ms,
|
|
184
187
|
store_type: "memory",
|
|
185
188
|
db_path: null,
|
|
189
|
+
store_fingerprint: "memory:ephemeral",
|
|
186
190
|
},
|
|
187
191
|
};
|
|
188
192
|
},
|
|
@@ -191,14 +195,23 @@ export function createMemoryStore() {
|
|
|
191
195
|
return clone(agents.get(id) || null);
|
|
192
196
|
},
|
|
193
197
|
|
|
194
|
-
refreshLease(agentId, ttlMs = 30000) {
|
|
198
|
+
refreshLease(agentId, ttlMs = 30000, presenceGeneration) {
|
|
195
199
|
const current = agents.get(agentId);
|
|
196
|
-
if (
|
|
200
|
+
if (
|
|
201
|
+
!current ||
|
|
202
|
+
(presenceGeneration != null &&
|
|
203
|
+
current.presence_generation !== presenceGeneration)
|
|
204
|
+
)
|
|
197
205
|
return {
|
|
198
206
|
agent_id: agentId,
|
|
199
207
|
lease_expires_ms: Date.now() + ttlMs,
|
|
200
208
|
server_time_ms: Date.now(),
|
|
201
|
-
effective: {
|
|
209
|
+
effective: {
|
|
210
|
+
updated: false,
|
|
211
|
+
store_type: "memory",
|
|
212
|
+
db_path: null,
|
|
213
|
+
store_fingerprint: "memory:ephemeral",
|
|
214
|
+
},
|
|
202
215
|
};
|
|
203
216
|
const now = Date.now();
|
|
204
217
|
current.last_seen_ms = now;
|
|
@@ -208,7 +221,12 @@ export function createMemoryStore() {
|
|
|
208
221
|
agent_id: agentId,
|
|
209
222
|
lease_expires_ms: current.lease_expires_ms,
|
|
210
223
|
server_time_ms: now,
|
|
211
|
-
effective: {
|
|
224
|
+
effective: {
|
|
225
|
+
updated: true,
|
|
226
|
+
store_type: "memory",
|
|
227
|
+
db_path: null,
|
|
228
|
+
store_fingerprint: "memory:ephemeral",
|
|
229
|
+
},
|
|
212
230
|
};
|
|
213
231
|
},
|
|
214
232
|
|
|
@@ -243,9 +261,19 @@ export function createMemoryStore() {
|
|
|
243
261
|
|
|
244
262
|
sweepStaleAgents() {
|
|
245
263
|
const now = Date.now();
|
|
264
|
+
const candidates = Array.from(agents.values(), (agent) => ({
|
|
265
|
+
agent_id: agent.agent_id,
|
|
266
|
+
presence_generation: agent.presence_generation,
|
|
267
|
+
}));
|
|
246
268
|
let stale = 0;
|
|
247
269
|
let offline = 0;
|
|
248
|
-
for (const
|
|
270
|
+
for (const candidate of candidates) {
|
|
271
|
+
const agent = agents.get(candidate.agent_id);
|
|
272
|
+
if (
|
|
273
|
+
!agent ||
|
|
274
|
+
agent.presence_generation !== candidate.presence_generation
|
|
275
|
+
)
|
|
276
|
+
continue;
|
|
249
277
|
if (agent.status === "online" && agent.lease_expires_ms < now) {
|
|
250
278
|
agent.status = "stale";
|
|
251
279
|
stale += 1;
|
|
@@ -260,9 +288,14 @@ export function createMemoryStore() {
|
|
|
260
288
|
return { stale, offline };
|
|
261
289
|
},
|
|
262
290
|
|
|
263
|
-
updateAgentStatus(agentId, status) {
|
|
291
|
+
updateAgentStatus(agentId, status, presenceGeneration) {
|
|
264
292
|
const current = agents.get(agentId);
|
|
265
|
-
if (
|
|
293
|
+
if (
|
|
294
|
+
!current ||
|
|
295
|
+
(presenceGeneration != null &&
|
|
296
|
+
current.presence_generation !== presenceGeneration)
|
|
297
|
+
)
|
|
298
|
+
return false;
|
|
266
299
|
current.status = status;
|
|
267
300
|
return true;
|
|
268
301
|
},
|
|
@@ -421,21 +454,11 @@ export function createMemoryStore() {
|
|
|
421
454
|
.map((request) => clone(request));
|
|
422
455
|
},
|
|
423
456
|
|
|
424
|
-
expireHumanRequests() {
|
|
425
|
-
let changed = 0;
|
|
426
|
-
const now = Date.now();
|
|
427
|
-
for (const request of humanRequests.values()) {
|
|
428
|
-
if (request.state === "pending" && request.deadline_ms < now) {
|
|
429
|
-
request.state = "timed_out";
|
|
430
|
-
changed += 1;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return changed;
|
|
434
|
-
},
|
|
435
|
-
|
|
436
457
|
moveToDeadLetter(messageId, reason, lastError = null) {
|
|
437
458
|
const current = messages.get(messageId);
|
|
438
|
-
if (current
|
|
459
|
+
if (!current || current.status === "dead_letter") return false;
|
|
460
|
+
current.status = "dead_letter";
|
|
461
|
+
if (deadLetters.has(messageId)) return true;
|
|
439
462
|
deadLetters.set(messageId, {
|
|
440
463
|
message_id: messageId,
|
|
441
464
|
reason,
|
|
@@ -685,25 +708,38 @@ export function createMemoryStore() {
|
|
|
685
708
|
});
|
|
686
709
|
},
|
|
687
710
|
|
|
688
|
-
sweepExpired() {
|
|
689
|
-
const
|
|
690
|
-
let expiredMessages = 0;
|
|
711
|
+
sweepExpired({ now_ms = Date.now() } = {}) {
|
|
712
|
+
const transitions = [];
|
|
691
713
|
for (const message of messages.values()) {
|
|
692
|
-
if (
|
|
693
|
-
message.status
|
|
714
|
+
if (
|
|
715
|
+
!["queued", "delivered"].includes(message.status) ||
|
|
716
|
+
message.expires_at_ms > now_ms
|
|
717
|
+
)
|
|
718
|
+
continue;
|
|
719
|
+
const snapshot = clone(message);
|
|
720
|
+
const previousStatus = message.status;
|
|
721
|
+
message.status = "dead_letter";
|
|
722
|
+
const dlqInserted = !deadLetters.has(message.id);
|
|
723
|
+
if (dlqInserted) {
|
|
694
724
|
deadLetters.set(message.id, {
|
|
695
725
|
message_id: message.id,
|
|
696
726
|
reason: "ttl_expired",
|
|
697
|
-
failed_at_ms:
|
|
727
|
+
failed_at_ms: now_ms,
|
|
698
728
|
last_error: null,
|
|
699
729
|
});
|
|
700
|
-
expiredMessages += 1;
|
|
701
730
|
}
|
|
731
|
+
transitions.push({
|
|
732
|
+
message: snapshot,
|
|
733
|
+
previous_status: previousStatus,
|
|
734
|
+
reason: "ttl_expired",
|
|
735
|
+
failed_at_ms: now_ms,
|
|
736
|
+
dlq_inserted: dlqInserted,
|
|
737
|
+
});
|
|
702
738
|
}
|
|
703
|
-
const humanRequestsExpired = store.expireHumanRequests();
|
|
704
739
|
return {
|
|
705
|
-
|
|
706
|
-
|
|
740
|
+
now_ms,
|
|
741
|
+
messages: transitions.length,
|
|
742
|
+
transitions,
|
|
707
743
|
};
|
|
708
744
|
},
|
|
709
745
|
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
//
|
|
9
9
|
// 기존 플래그 (Phase 2 v10.9.33+):
|
|
10
10
|
// --cli {auto|codex|antigravity|claude}
|
|
11
|
-
// --mode {quick|deep|consensus}
|
|
11
|
+
// --mode {quick|deep|consensus|live}
|
|
12
12
|
// --parallel {1|N|swarm}
|
|
13
13
|
// --retry {0|1|ralph|auto-escalate} (Phase 3 에서 ralph/auto-escalate 신규)
|
|
14
14
|
// --isolation {none|worktree}
|
|
15
15
|
// --remote {none|<host>}
|
|
16
|
+
// --rounds <N> (--mode live 전용, 기본 4)
|
|
16
17
|
//
|
|
17
18
|
// Phase 3 신규:
|
|
18
19
|
// --lead {claude|codex} (tfx-auto-codex 의미 흡수)
|
|
@@ -31,11 +32,12 @@ export const DEFAULT_OPTIONS = Object.freeze({
|
|
|
31
32
|
lead: "claude",
|
|
32
33
|
noClaudeNative: false,
|
|
33
34
|
maxIterations: 0,
|
|
35
|
+
rounds: 4,
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
const VALID_VALUES = Object.freeze({
|
|
37
39
|
cli: ["auto", "codex", "antigravity", "claude"],
|
|
38
|
-
mode: ["quick", "deep", "consensus"],
|
|
40
|
+
mode: ["quick", "deep", "consensus", "live"],
|
|
39
41
|
retry: ["0", "1", "ralph", "auto-escalate"],
|
|
40
42
|
isolation: ["none", "worktree"],
|
|
41
43
|
lead: ["claude", "codex"],
|
|
@@ -50,6 +52,7 @@ const VALUE_FLAGS = new Set([
|
|
|
50
52
|
"--remote",
|
|
51
53
|
"--lead",
|
|
52
54
|
"--max-iterations",
|
|
55
|
+
"--rounds",
|
|
53
56
|
]);
|
|
54
57
|
|
|
55
58
|
const BOOL_FLAGS = new Set(["--no-claude-native"]);
|
|
@@ -61,12 +64,14 @@ export function parseArgs(input) {
|
|
|
61
64
|
const opts = { ...DEFAULT_OPTIONS };
|
|
62
65
|
const warnings = [];
|
|
63
66
|
const taskTokens = [];
|
|
67
|
+
const providedFlags = new Set();
|
|
64
68
|
|
|
65
69
|
let i = 0;
|
|
66
70
|
while (i < tokens.length) {
|
|
67
71
|
const raw = tokens[i];
|
|
68
72
|
|
|
69
73
|
if (BOOL_FLAGS.has(raw)) {
|
|
74
|
+
providedFlags.add(raw);
|
|
70
75
|
applyBool(opts, raw);
|
|
71
76
|
i += 1;
|
|
72
77
|
continue;
|
|
@@ -82,6 +87,7 @@ export function parseArgs(input) {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
if (VALUE_FLAGS.has(flag)) {
|
|
90
|
+
providedFlags.add(flag);
|
|
85
91
|
if (value === null) {
|
|
86
92
|
const next = tokens[i + 1];
|
|
87
93
|
if (next === undefined || next.startsWith("--")) {
|
|
@@ -108,7 +114,7 @@ export function parseArgs(input) {
|
|
|
108
114
|
i += 1;
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
validate(opts, warnings);
|
|
117
|
+
validate(opts, warnings, providedFlags);
|
|
112
118
|
|
|
113
119
|
return {
|
|
114
120
|
...opts,
|
|
@@ -196,10 +202,19 @@ function applyValue(opts, flag, value, warnings) {
|
|
|
196
202
|
}
|
|
197
203
|
break;
|
|
198
204
|
}
|
|
205
|
+
case "--rounds": {
|
|
206
|
+
const n = Number(value);
|
|
207
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
208
|
+
warnings.push(`invalid --rounds=${value}, expected positive integer`);
|
|
209
|
+
} else {
|
|
210
|
+
opts.rounds = n;
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
199
214
|
}
|
|
200
215
|
}
|
|
201
216
|
|
|
202
|
-
function validate(opts, warnings) {
|
|
217
|
+
function validate(opts, warnings, providedFlags = new Set()) {
|
|
203
218
|
for (const key of Object.keys(VALID_VALUES)) {
|
|
204
219
|
if (!VALID_VALUES[key].includes(opts[key])) {
|
|
205
220
|
warnings.push(
|
|
@@ -214,6 +229,28 @@ function validate(opts, warnings) {
|
|
|
214
229
|
) {
|
|
215
230
|
warnings.push(`invalid --parallel=${opts.parallel}, expected 1|N|swarm`);
|
|
216
231
|
}
|
|
232
|
+
|
|
233
|
+
if (opts.mode === "live") {
|
|
234
|
+
const ignored = [
|
|
235
|
+
["--parallel", "parallel", DEFAULT_OPTIONS.parallel],
|
|
236
|
+
["--isolation", "isolation", DEFAULT_OPTIONS.isolation],
|
|
237
|
+
["--remote", "remote", DEFAULT_OPTIONS.remote],
|
|
238
|
+
];
|
|
239
|
+
for (const [flag, key, fallback] of ignored) {
|
|
240
|
+
if (providedFlags.has(flag)) {
|
|
241
|
+
warnings.push(`${flag} ignored with --mode live`);
|
|
242
|
+
opts[key] = fallback;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (providedFlags.has("--retry") && opts.retry === "ralph") {
|
|
246
|
+
warnings.push("--retry ralph ignored with --mode live");
|
|
247
|
+
opts.retry = DEFAULT_OPTIONS.retry;
|
|
248
|
+
}
|
|
249
|
+
} else if (providedFlags.has("--rounds")) {
|
|
250
|
+
warnings.push("--rounds ignored unless --mode live");
|
|
251
|
+
opts.rounds = DEFAULT_OPTIONS.rounds;
|
|
252
|
+
}
|
|
253
|
+
|
|
217
254
|
const parallelOne = opts.parallel === "1" || opts.parallel === 1;
|
|
218
255
|
if (parallelOne && opts.isolation === "worktree") {
|
|
219
256
|
warnings.push(
|
package/hub/reflexion.mjs
CHANGED
|
@@ -7,8 +7,6 @@ const DEFAULT_CONFIDENCE = 0.5;
|
|
|
7
7
|
const ACTIVE_RULE_CONFIDENCE = 0.5;
|
|
8
8
|
const ADAPTIVE_PROMOTION_STEP = 0.1;
|
|
9
9
|
const ADAPTIVE_DECAY_STEP = 0.1;
|
|
10
|
-
/** @deprecated 세션 기반 decay에서 시간 기반으로 변경됨. 미사용. */
|
|
11
|
-
const _ADAPTIVE_DECAY_WINDOW = 5;
|
|
12
10
|
const ADAPTIVE_DELETE_THRESHOLD = 0.3;
|
|
13
11
|
|
|
14
12
|
function clampConfidence(value) {
|
|
@@ -102,61 +100,6 @@ function buildAdaptiveSolution(errorContext = {}, errorText = "") {
|
|
|
102
100
|
return `${toolName} 재시도 전 실패 원인을 검증하세요: ${summary}`;
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
function normalizeSessionIds(sessionIds) {
|
|
106
|
-
if (!Array.isArray(sessionIds)) return [];
|
|
107
|
-
return [
|
|
108
|
-
...new Set(
|
|
109
|
-
sessionIds.filter((value) => typeof value === "string" && value.trim()),
|
|
110
|
-
),
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** @deprecated reflexion_entries 기반. adaptive_rules에서는 미사용. 세션 인식 복원 시 재활용 예정. */
|
|
115
|
-
function getAdaptiveState(rule = {}) {
|
|
116
|
-
const state = rule.adaptive_state || {};
|
|
117
|
-
const session_ids = normalizeSessionIds(state.session_ids);
|
|
118
|
-
return {
|
|
119
|
-
...state,
|
|
120
|
-
project_slug: pickString(state.project_slug, rule.context?.project_slug),
|
|
121
|
-
session_ids,
|
|
122
|
-
session_occurrences: Math.max(
|
|
123
|
-
state.session_occurrences || 0,
|
|
124
|
-
session_ids.length,
|
|
125
|
-
),
|
|
126
|
-
last_seen_session: pickSessionCount(state.last_seen_session),
|
|
127
|
-
last_decay_session: pickSessionCount(state.last_decay_session),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** @deprecated reflexion_entries 기반. adaptive_rules에서는 미사용. 세션 인식 복원 시 재활용 예정. */
|
|
132
|
-
function _mergeAdaptiveState(rule, errorContext = {}) {
|
|
133
|
-
const current = getAdaptiveState(rule);
|
|
134
|
-
const sessionId = pickSessionId(errorContext);
|
|
135
|
-
const sessionCount = pickSessionCount(
|
|
136
|
-
errorContext.sessionCount,
|
|
137
|
-
errorContext.session_count,
|
|
138
|
-
errorContext.context?.sessionCount,
|
|
139
|
-
errorContext.context?.session_count,
|
|
140
|
-
);
|
|
141
|
-
const session_ids = normalizeSessionIds(
|
|
142
|
-
sessionId ? [...current.session_ids, sessionId] : current.session_ids,
|
|
143
|
-
);
|
|
144
|
-
return {
|
|
145
|
-
...current,
|
|
146
|
-
project_slug: pickString(
|
|
147
|
-
pickProjectSlug(errorContext),
|
|
148
|
-
current.project_slug,
|
|
149
|
-
),
|
|
150
|
-
session_ids,
|
|
151
|
-
session_occurrences: Math.max(
|
|
152
|
-
current.session_occurrences,
|
|
153
|
-
session_ids.length,
|
|
154
|
-
),
|
|
155
|
-
last_seen_session: Math.max(current.last_seen_session, sessionCount),
|
|
156
|
-
last_decay_session: current.last_decay_session || sessionCount,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
103
|
function filterEntriesByType(entries, type) {
|
|
161
104
|
return entries.filter(
|
|
162
105
|
(entry) => (entry.type || DEFAULT_REFLEXION_TYPE) === type,
|