chainlesschain 0.132.0 → 0.145.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/package.json +1 -1
- package/src/commands/a2a.js +230 -0
- package/src/commands/activitypub.js +191 -0
- package/src/commands/agent.js +601 -0
- package/src/commands/audit.js +206 -0
- package/src/commands/bi.js +186 -0
- package/src/commands/bm25.js +162 -0
- package/src/commands/browse.js +225 -0
- package/src/commands/ccron.js +178 -0
- package/src/commands/chat.js +207 -0
- package/src/commands/compliance.js +420 -0
- package/src/commands/compt.js +176 -0
- package/src/commands/consol.js +237 -0
- package/src/commands/cowork.js +588 -0
- package/src/commands/crosschain.js +216 -0
- package/src/commands/dao.js +216 -0
- package/src/commands/dlp.js +206 -0
- package/src/commands/economy.js +211 -0
- package/src/commands/evolution.js +209 -0
- package/src/commands/evomap.js +216 -0
- package/src/commands/fflag.js +230 -0
- package/src/commands/git.js +185 -0
- package/src/commands/hardening.js +209 -0
- package/src/commands/hmemory.js +210 -0
- package/src/commands/incentive.js +209 -0
- package/src/commands/inference.js +178 -0
- package/src/commands/itbudget.js +161 -0
- package/src/commands/kg.js +206 -0
- package/src/commands/lowcode.js +201 -0
- package/src/commands/marketplace.js +206 -0
- package/src/commands/matrix.js +214 -0
- package/src/commands/mcpscaf.js +153 -0
- package/src/commands/meminj.js +153 -0
- package/src/commands/nostr.js +213 -0
- package/src/commands/orchestrate.js +217 -0
- package/src/commands/orchgov.js +156 -0
- package/src/commands/pdfp.js +160 -0
- package/src/commands/perf.js +176 -0
- package/src/commands/perm.js +156 -0
- package/src/commands/pipeline.js +211 -0
- package/src/commands/planmode.js +154 -0
- package/src/commands/privacy.js +203 -0
- package/src/commands/promcomp.js +166 -0
- package/src/commands/recommend.js +185 -0
- package/src/commands/reputation.js +208 -0
- package/src/commands/sandbox.js +206 -0
- package/src/commands/seshhook.js +153 -0
- package/src/commands/seshsearch.js +149 -0
- package/src/commands/seshtail.js +152 -0
- package/src/commands/seshu.js +160 -0
- package/src/commands/sganal.js +172 -0
- package/src/commands/siem.js +207 -0
- package/src/commands/sla.js +212 -0
- package/src/commands/slotfill.js +154 -0
- package/src/commands/social.js +159 -0
- package/src/commands/stress.js +206 -0
- package/src/commands/svccont.js +157 -0
- package/src/commands/terraform.js +206 -0
- package/src/commands/tms.js +183 -0
- package/src/commands/topiccls.js +158 -0
- package/src/commands/uprof.js +154 -0
- package/src/commands/vcheck.js +172 -0
- package/src/commands/webfetch.js +150 -0
- package/src/commands/zkp.js +218 -0
- package/src/harness/prompt-compressor.js +331 -0
- package/src/index.js +101 -1
- package/src/lib/a2a-protocol.js +373 -0
- package/src/lib/activitypub-bridge.js +343 -0
- package/src/lib/agent-economy.js +358 -0
- package/src/lib/app-builder.js +338 -0
- package/src/lib/audit-logger.js +321 -0
- package/src/lib/autonomous-agent.js +341 -0
- package/src/lib/bi-engine.js +339 -0
- package/src/lib/bm25-search.js +333 -0
- package/src/lib/browser-automation.js +352 -0
- package/src/lib/chat-core.js +336 -0
- package/src/lib/claude-code-bridge.js +341 -0
- package/src/lib/compliance-framework-reporter.js +359 -0
- package/src/lib/compliance-manager.js +330 -0
- package/src/lib/compression-telemetry.js +333 -0
- package/src/lib/content-recommender.js +370 -0
- package/src/lib/cowork-cron.js +330 -0
- package/src/lib/cowork-learning.js +333 -0
- package/src/lib/cowork-task-runner.js +362 -0
- package/src/lib/cowork-workflow.js +327 -0
- package/src/lib/cross-chain.js +365 -0
- package/src/lib/dao-governance.js +339 -0
- package/src/lib/dlp-engine.js +343 -0
- package/src/lib/evolution-system.js +336 -0
- package/src/lib/evomap-manager.js +339 -0
- package/src/lib/execution-backend.js +351 -0
- package/src/lib/feature-flags.js +330 -0
- package/src/lib/git-integration.js +343 -0
- package/src/lib/hardening-manager.js +341 -0
- package/src/lib/hierarchical-memory.js +341 -0
- package/src/lib/inference-network.js +362 -0
- package/src/lib/iteration-budget.js +357 -0
- package/src/lib/knowledge-graph.js +333 -0
- package/src/lib/matrix-bridge.js +339 -0
- package/src/lib/mcp-scaffold.js +345 -0
- package/src/lib/memory-injection.js +320 -0
- package/src/lib/nostr-bridge.js +342 -0
- package/src/lib/orchestrator.js +350 -0
- package/src/lib/pdf-parser.js +330 -0
- package/src/lib/perf-tuning.js +364 -0
- package/src/lib/permission-engine.js +319 -0
- package/src/lib/pipeline-orchestrator.js +345 -0
- package/src/lib/plan-mode.js +328 -0
- package/src/lib/privacy-computing.js +335 -0
- package/src/lib/prompt-compressor.js +1 -10
- package/src/lib/reputation-optimizer.js +340 -0
- package/src/lib/sandbox-v2.js +327 -0
- package/src/lib/service-container.js +342 -0
- package/src/lib/session-consolidator.js +352 -0
- package/src/lib/session-hooks.js +340 -0
- package/src/lib/session-search.js +334 -0
- package/src/lib/session-tail.js +320 -0
- package/src/lib/session-usage.js +329 -0
- package/src/lib/siem-exporter.js +352 -0
- package/src/lib/skill-marketplace.js +345 -0
- package/src/lib/sla-manager.js +341 -0
- package/src/lib/slot-filler.js +333 -0
- package/src/lib/social-graph-analytics.js +327 -0
- package/src/lib/social-graph.js +304 -0
- package/src/lib/stress-tester.js +342 -0
- package/src/lib/sub-agent-registry.js +359 -0
- package/src/lib/task-model-selector.js +333 -0
- package/src/lib/terraform-manager.js +333 -0
- package/src/lib/todo-manager.js +339 -0
- package/src/lib/token-incentive.js +341 -0
- package/src/lib/topic-classifier.js +353 -0
- package/src/lib/user-profile.js +325 -0
- package/src/lib/version-checker.js +335 -0
- package/src/lib/web-fetch.js +322 -0
- package/src/lib/zkp-engine.js +342 -0
|
@@ -3,3 +3,336 @@ export {
|
|
|
3
3
|
getCompressionTelemetrySummary,
|
|
4
4
|
resetCompressionTelemetry,
|
|
5
5
|
} from "../harness/compression-telemetry.js";
|
|
6
|
+
|
|
7
|
+
// =====================================================================
|
|
8
|
+
// Compression Telemetry V2 governance overlay
|
|
9
|
+
// =====================================================================
|
|
10
|
+
export const COMPT_PROFILE_MATURITY_V2 = Object.freeze({
|
|
11
|
+
PENDING: "pending",
|
|
12
|
+
ACTIVE: "active",
|
|
13
|
+
STALE: "stale",
|
|
14
|
+
ARCHIVED: "archived",
|
|
15
|
+
});
|
|
16
|
+
export const COMPT_SAMPLE_LIFECYCLE_V2 = Object.freeze({
|
|
17
|
+
QUEUED: "queued",
|
|
18
|
+
RECORDING: "recording",
|
|
19
|
+
RECORDED: "recorded",
|
|
20
|
+
FAILED: "failed",
|
|
21
|
+
CANCELLED: "cancelled",
|
|
22
|
+
});
|
|
23
|
+
const _comptPTrans = new Map([
|
|
24
|
+
[
|
|
25
|
+
COMPT_PROFILE_MATURITY_V2.PENDING,
|
|
26
|
+
new Set([
|
|
27
|
+
COMPT_PROFILE_MATURITY_V2.ACTIVE,
|
|
28
|
+
COMPT_PROFILE_MATURITY_V2.ARCHIVED,
|
|
29
|
+
]),
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
COMPT_PROFILE_MATURITY_V2.ACTIVE,
|
|
33
|
+
new Set([
|
|
34
|
+
COMPT_PROFILE_MATURITY_V2.STALE,
|
|
35
|
+
COMPT_PROFILE_MATURITY_V2.ARCHIVED,
|
|
36
|
+
]),
|
|
37
|
+
],
|
|
38
|
+
[
|
|
39
|
+
COMPT_PROFILE_MATURITY_V2.STALE,
|
|
40
|
+
new Set([
|
|
41
|
+
COMPT_PROFILE_MATURITY_V2.ACTIVE,
|
|
42
|
+
COMPT_PROFILE_MATURITY_V2.ARCHIVED,
|
|
43
|
+
]),
|
|
44
|
+
],
|
|
45
|
+
[COMPT_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
|
|
46
|
+
]);
|
|
47
|
+
const _comptPTerminal = new Set([COMPT_PROFILE_MATURITY_V2.ARCHIVED]);
|
|
48
|
+
const _comptJTrans = new Map([
|
|
49
|
+
[
|
|
50
|
+
COMPT_SAMPLE_LIFECYCLE_V2.QUEUED,
|
|
51
|
+
new Set([
|
|
52
|
+
COMPT_SAMPLE_LIFECYCLE_V2.RECORDING,
|
|
53
|
+
COMPT_SAMPLE_LIFECYCLE_V2.CANCELLED,
|
|
54
|
+
]),
|
|
55
|
+
],
|
|
56
|
+
[
|
|
57
|
+
COMPT_SAMPLE_LIFECYCLE_V2.RECORDING,
|
|
58
|
+
new Set([
|
|
59
|
+
COMPT_SAMPLE_LIFECYCLE_V2.RECORDED,
|
|
60
|
+
COMPT_SAMPLE_LIFECYCLE_V2.FAILED,
|
|
61
|
+
COMPT_SAMPLE_LIFECYCLE_V2.CANCELLED,
|
|
62
|
+
]),
|
|
63
|
+
],
|
|
64
|
+
[COMPT_SAMPLE_LIFECYCLE_V2.RECORDED, new Set()],
|
|
65
|
+
[COMPT_SAMPLE_LIFECYCLE_V2.FAILED, new Set()],
|
|
66
|
+
[COMPT_SAMPLE_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
67
|
+
]);
|
|
68
|
+
const _comptPsV2 = new Map();
|
|
69
|
+
const _comptJsV2 = new Map();
|
|
70
|
+
let _comptMaxActive = 10,
|
|
71
|
+
_comptMaxPending = 30,
|
|
72
|
+
_comptIdleMs = 30 * 24 * 60 * 60 * 1000,
|
|
73
|
+
_comptStuckMs = 30 * 1000;
|
|
74
|
+
function _comptPos(n, label) {
|
|
75
|
+
const v = Math.floor(Number(n));
|
|
76
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
77
|
+
throw new Error(`${label} must be positive integer`);
|
|
78
|
+
return v;
|
|
79
|
+
}
|
|
80
|
+
function _comptCheckP(from, to) {
|
|
81
|
+
const a = _comptPTrans.get(from);
|
|
82
|
+
if (!a || !a.has(to))
|
|
83
|
+
throw new Error(`invalid compt profile transition ${from} → ${to}`);
|
|
84
|
+
}
|
|
85
|
+
function _comptCheckJ(from, to) {
|
|
86
|
+
const a = _comptJTrans.get(from);
|
|
87
|
+
if (!a || !a.has(to))
|
|
88
|
+
throw new Error(`invalid compt sample transition ${from} → ${to}`);
|
|
89
|
+
}
|
|
90
|
+
function _comptCountActive(owner) {
|
|
91
|
+
let c = 0;
|
|
92
|
+
for (const p of _comptPsV2.values())
|
|
93
|
+
if (p.owner === owner && p.status === COMPT_PROFILE_MATURITY_V2.ACTIVE) c++;
|
|
94
|
+
return c;
|
|
95
|
+
}
|
|
96
|
+
function _comptCountPending(profileId) {
|
|
97
|
+
let c = 0;
|
|
98
|
+
for (const j of _comptJsV2.values())
|
|
99
|
+
if (
|
|
100
|
+
j.profileId === profileId &&
|
|
101
|
+
(j.status === COMPT_SAMPLE_LIFECYCLE_V2.QUEUED ||
|
|
102
|
+
j.status === COMPT_SAMPLE_LIFECYCLE_V2.RECORDING)
|
|
103
|
+
)
|
|
104
|
+
c++;
|
|
105
|
+
return c;
|
|
106
|
+
}
|
|
107
|
+
export function setMaxActiveComptProfilesPerOwnerV2(n) {
|
|
108
|
+
_comptMaxActive = _comptPos(n, "maxActiveComptProfilesPerOwner");
|
|
109
|
+
}
|
|
110
|
+
export function getMaxActiveComptProfilesPerOwnerV2() {
|
|
111
|
+
return _comptMaxActive;
|
|
112
|
+
}
|
|
113
|
+
export function setMaxPendingComptSamplesPerProfileV2(n) {
|
|
114
|
+
_comptMaxPending = _comptPos(n, "maxPendingComptSamplesPerProfile");
|
|
115
|
+
}
|
|
116
|
+
export function getMaxPendingComptSamplesPerProfileV2() {
|
|
117
|
+
return _comptMaxPending;
|
|
118
|
+
}
|
|
119
|
+
export function setComptProfileIdleMsV2(n) {
|
|
120
|
+
_comptIdleMs = _comptPos(n, "comptProfileIdleMs");
|
|
121
|
+
}
|
|
122
|
+
export function getComptProfileIdleMsV2() {
|
|
123
|
+
return _comptIdleMs;
|
|
124
|
+
}
|
|
125
|
+
export function setComptSampleStuckMsV2(n) {
|
|
126
|
+
_comptStuckMs = _comptPos(n, "comptSampleStuckMs");
|
|
127
|
+
}
|
|
128
|
+
export function getComptSampleStuckMsV2() {
|
|
129
|
+
return _comptStuckMs;
|
|
130
|
+
}
|
|
131
|
+
export function _resetStateCompressionTelemetryV2() {
|
|
132
|
+
_comptPsV2.clear();
|
|
133
|
+
_comptJsV2.clear();
|
|
134
|
+
_comptMaxActive = 10;
|
|
135
|
+
_comptMaxPending = 30;
|
|
136
|
+
_comptIdleMs = 30 * 24 * 60 * 60 * 1000;
|
|
137
|
+
_comptStuckMs = 30 * 1000;
|
|
138
|
+
}
|
|
139
|
+
export function registerComptProfileV2({ id, owner, kind, metadata } = {}) {
|
|
140
|
+
if (!id || !owner) throw new Error("id and owner required");
|
|
141
|
+
if (_comptPsV2.has(id)) throw new Error(`compt profile ${id} already exists`);
|
|
142
|
+
const now = Date.now();
|
|
143
|
+
const p = {
|
|
144
|
+
id,
|
|
145
|
+
owner,
|
|
146
|
+
kind: kind || "default",
|
|
147
|
+
status: COMPT_PROFILE_MATURITY_V2.PENDING,
|
|
148
|
+
createdAt: now,
|
|
149
|
+
updatedAt: now,
|
|
150
|
+
lastTouchedAt: now,
|
|
151
|
+
activatedAt: null,
|
|
152
|
+
archivedAt: null,
|
|
153
|
+
metadata: { ...(metadata || {}) },
|
|
154
|
+
};
|
|
155
|
+
_comptPsV2.set(id, p);
|
|
156
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
157
|
+
}
|
|
158
|
+
export function activateComptProfileV2(id) {
|
|
159
|
+
const p = _comptPsV2.get(id);
|
|
160
|
+
if (!p) throw new Error(`compt profile ${id} not found`);
|
|
161
|
+
const isInitial = p.status === COMPT_PROFILE_MATURITY_V2.PENDING;
|
|
162
|
+
_comptCheckP(p.status, COMPT_PROFILE_MATURITY_V2.ACTIVE);
|
|
163
|
+
if (isInitial && _comptCountActive(p.owner) >= _comptMaxActive)
|
|
164
|
+
throw new Error(`max active compt profiles for owner ${p.owner} reached`);
|
|
165
|
+
const now = Date.now();
|
|
166
|
+
p.status = COMPT_PROFILE_MATURITY_V2.ACTIVE;
|
|
167
|
+
p.updatedAt = now;
|
|
168
|
+
p.lastTouchedAt = now;
|
|
169
|
+
if (!p.activatedAt) p.activatedAt = now;
|
|
170
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
171
|
+
}
|
|
172
|
+
export function staleComptProfileV2(id) {
|
|
173
|
+
const p = _comptPsV2.get(id);
|
|
174
|
+
if (!p) throw new Error(`compt profile ${id} not found`);
|
|
175
|
+
_comptCheckP(p.status, COMPT_PROFILE_MATURITY_V2.STALE);
|
|
176
|
+
p.status = COMPT_PROFILE_MATURITY_V2.STALE;
|
|
177
|
+
p.updatedAt = Date.now();
|
|
178
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
179
|
+
}
|
|
180
|
+
export function archiveComptProfileV2(id) {
|
|
181
|
+
const p = _comptPsV2.get(id);
|
|
182
|
+
if (!p) throw new Error(`compt profile ${id} not found`);
|
|
183
|
+
_comptCheckP(p.status, COMPT_PROFILE_MATURITY_V2.ARCHIVED);
|
|
184
|
+
const now = Date.now();
|
|
185
|
+
p.status = COMPT_PROFILE_MATURITY_V2.ARCHIVED;
|
|
186
|
+
p.updatedAt = now;
|
|
187
|
+
if (!p.archivedAt) p.archivedAt = now;
|
|
188
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
189
|
+
}
|
|
190
|
+
export function touchComptProfileV2(id) {
|
|
191
|
+
const p = _comptPsV2.get(id);
|
|
192
|
+
if (!p) throw new Error(`compt profile ${id} not found`);
|
|
193
|
+
if (_comptPTerminal.has(p.status))
|
|
194
|
+
throw new Error(`cannot touch terminal compt profile ${id}`);
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
p.lastTouchedAt = now;
|
|
197
|
+
p.updatedAt = now;
|
|
198
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
199
|
+
}
|
|
200
|
+
export function getComptProfileV2(id) {
|
|
201
|
+
const p = _comptPsV2.get(id);
|
|
202
|
+
if (!p) return null;
|
|
203
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
204
|
+
}
|
|
205
|
+
export function listComptProfilesV2() {
|
|
206
|
+
return [..._comptPsV2.values()].map((p) => ({
|
|
207
|
+
...p,
|
|
208
|
+
metadata: { ...p.metadata },
|
|
209
|
+
}));
|
|
210
|
+
}
|
|
211
|
+
export function createComptSampleV2({ id, profileId, metric, metadata } = {}) {
|
|
212
|
+
if (!id || !profileId) throw new Error("id and profileId required");
|
|
213
|
+
if (_comptJsV2.has(id)) throw new Error(`compt sample ${id} already exists`);
|
|
214
|
+
if (!_comptPsV2.has(profileId))
|
|
215
|
+
throw new Error(`compt profile ${profileId} not found`);
|
|
216
|
+
if (_comptCountPending(profileId) >= _comptMaxPending)
|
|
217
|
+
throw new Error(
|
|
218
|
+
`max pending compt samples for profile ${profileId} reached`,
|
|
219
|
+
);
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
const j = {
|
|
222
|
+
id,
|
|
223
|
+
profileId,
|
|
224
|
+
metric: metric || "",
|
|
225
|
+
status: COMPT_SAMPLE_LIFECYCLE_V2.QUEUED,
|
|
226
|
+
createdAt: now,
|
|
227
|
+
updatedAt: now,
|
|
228
|
+
startedAt: null,
|
|
229
|
+
settledAt: null,
|
|
230
|
+
metadata: { ...(metadata || {}) },
|
|
231
|
+
};
|
|
232
|
+
_comptJsV2.set(id, j);
|
|
233
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
234
|
+
}
|
|
235
|
+
export function recordingComptSampleV2(id) {
|
|
236
|
+
const j = _comptJsV2.get(id);
|
|
237
|
+
if (!j) throw new Error(`compt sample ${id} not found`);
|
|
238
|
+
_comptCheckJ(j.status, COMPT_SAMPLE_LIFECYCLE_V2.RECORDING);
|
|
239
|
+
const now = Date.now();
|
|
240
|
+
j.status = COMPT_SAMPLE_LIFECYCLE_V2.RECORDING;
|
|
241
|
+
j.updatedAt = now;
|
|
242
|
+
if (!j.startedAt) j.startedAt = now;
|
|
243
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
244
|
+
}
|
|
245
|
+
export function recordComptSampleV2(id) {
|
|
246
|
+
const j = _comptJsV2.get(id);
|
|
247
|
+
if (!j) throw new Error(`compt sample ${id} not found`);
|
|
248
|
+
_comptCheckJ(j.status, COMPT_SAMPLE_LIFECYCLE_V2.RECORDED);
|
|
249
|
+
const now = Date.now();
|
|
250
|
+
j.status = COMPT_SAMPLE_LIFECYCLE_V2.RECORDED;
|
|
251
|
+
j.updatedAt = now;
|
|
252
|
+
if (!j.settledAt) j.settledAt = now;
|
|
253
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
254
|
+
}
|
|
255
|
+
export function failComptSampleV2(id, reason) {
|
|
256
|
+
const j = _comptJsV2.get(id);
|
|
257
|
+
if (!j) throw new Error(`compt sample ${id} not found`);
|
|
258
|
+
_comptCheckJ(j.status, COMPT_SAMPLE_LIFECYCLE_V2.FAILED);
|
|
259
|
+
const now = Date.now();
|
|
260
|
+
j.status = COMPT_SAMPLE_LIFECYCLE_V2.FAILED;
|
|
261
|
+
j.updatedAt = now;
|
|
262
|
+
if (!j.settledAt) j.settledAt = now;
|
|
263
|
+
if (reason) j.metadata.failReason = String(reason);
|
|
264
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
265
|
+
}
|
|
266
|
+
export function cancelComptSampleV2(id, reason) {
|
|
267
|
+
const j = _comptJsV2.get(id);
|
|
268
|
+
if (!j) throw new Error(`compt sample ${id} not found`);
|
|
269
|
+
_comptCheckJ(j.status, COMPT_SAMPLE_LIFECYCLE_V2.CANCELLED);
|
|
270
|
+
const now = Date.now();
|
|
271
|
+
j.status = COMPT_SAMPLE_LIFECYCLE_V2.CANCELLED;
|
|
272
|
+
j.updatedAt = now;
|
|
273
|
+
if (!j.settledAt) j.settledAt = now;
|
|
274
|
+
if (reason) j.metadata.cancelReason = String(reason);
|
|
275
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
276
|
+
}
|
|
277
|
+
export function getComptSampleV2(id) {
|
|
278
|
+
const j = _comptJsV2.get(id);
|
|
279
|
+
if (!j) return null;
|
|
280
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
281
|
+
}
|
|
282
|
+
export function listComptSamplesV2() {
|
|
283
|
+
return [..._comptJsV2.values()].map((j) => ({
|
|
284
|
+
...j,
|
|
285
|
+
metadata: { ...j.metadata },
|
|
286
|
+
}));
|
|
287
|
+
}
|
|
288
|
+
export function autoStaleIdleComptProfilesV2({ now } = {}) {
|
|
289
|
+
const t = now ?? Date.now();
|
|
290
|
+
const flipped = [];
|
|
291
|
+
for (const p of _comptPsV2.values())
|
|
292
|
+
if (
|
|
293
|
+
p.status === COMPT_PROFILE_MATURITY_V2.ACTIVE &&
|
|
294
|
+
t - p.lastTouchedAt >= _comptIdleMs
|
|
295
|
+
) {
|
|
296
|
+
p.status = COMPT_PROFILE_MATURITY_V2.STALE;
|
|
297
|
+
p.updatedAt = t;
|
|
298
|
+
flipped.push(p.id);
|
|
299
|
+
}
|
|
300
|
+
return { flipped, count: flipped.length };
|
|
301
|
+
}
|
|
302
|
+
export function autoFailStuckComptSamplesV2({ now } = {}) {
|
|
303
|
+
const t = now ?? Date.now();
|
|
304
|
+
const flipped = [];
|
|
305
|
+
for (const j of _comptJsV2.values())
|
|
306
|
+
if (
|
|
307
|
+
j.status === COMPT_SAMPLE_LIFECYCLE_V2.RECORDING &&
|
|
308
|
+
j.startedAt != null &&
|
|
309
|
+
t - j.startedAt >= _comptStuckMs
|
|
310
|
+
) {
|
|
311
|
+
j.status = COMPT_SAMPLE_LIFECYCLE_V2.FAILED;
|
|
312
|
+
j.updatedAt = t;
|
|
313
|
+
if (!j.settledAt) j.settledAt = t;
|
|
314
|
+
j.metadata.failReason = "auto-fail-stuck";
|
|
315
|
+
flipped.push(j.id);
|
|
316
|
+
}
|
|
317
|
+
return { flipped, count: flipped.length };
|
|
318
|
+
}
|
|
319
|
+
export function getCompressionTelemetryGovStatsV2() {
|
|
320
|
+
const profilesByStatus = {};
|
|
321
|
+
for (const v of Object.values(COMPT_PROFILE_MATURITY_V2))
|
|
322
|
+
profilesByStatus[v] = 0;
|
|
323
|
+
for (const p of _comptPsV2.values()) profilesByStatus[p.status]++;
|
|
324
|
+
const samplesByStatus = {};
|
|
325
|
+
for (const v of Object.values(COMPT_SAMPLE_LIFECYCLE_V2))
|
|
326
|
+
samplesByStatus[v] = 0;
|
|
327
|
+
for (const j of _comptJsV2.values()) samplesByStatus[j.status]++;
|
|
328
|
+
return {
|
|
329
|
+
totalComptProfilesV2: _comptPsV2.size,
|
|
330
|
+
totalComptSamplesV2: _comptJsV2.size,
|
|
331
|
+
maxActiveComptProfilesPerOwner: _comptMaxActive,
|
|
332
|
+
maxPendingComptSamplesPerProfile: _comptMaxPending,
|
|
333
|
+
comptProfileIdleMs: _comptIdleMs,
|
|
334
|
+
comptSampleStuckMs: _comptStuckMs,
|
|
335
|
+
profilesByStatus,
|
|
336
|
+
samplesByStatus,
|
|
337
|
+
};
|
|
338
|
+
}
|
|
@@ -203,3 +203,373 @@ export class CLIContentRecommender {
|
|
|
203
203
|
return matrix;
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
|
+
|
|
207
|
+
// ===== V2 Surface: Content Recommender governance overlay (CLI v0.139.0) =====
|
|
208
|
+
export const RECOMMENDER_PROFILE_MATURITY_V2 = Object.freeze({
|
|
209
|
+
PENDING: "pending",
|
|
210
|
+
ACTIVE: "active",
|
|
211
|
+
STALE: "stale",
|
|
212
|
+
ARCHIVED: "archived",
|
|
213
|
+
});
|
|
214
|
+
export const RECOMMENDATION_JOB_LIFECYCLE_V2 = Object.freeze({
|
|
215
|
+
QUEUED: "queued",
|
|
216
|
+
RUNNING: "running",
|
|
217
|
+
COMPLETED: "completed",
|
|
218
|
+
FAILED: "failed",
|
|
219
|
+
CANCELLED: "cancelled",
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
const _crpTrans = new Map([
|
|
223
|
+
[
|
|
224
|
+
RECOMMENDER_PROFILE_MATURITY_V2.PENDING,
|
|
225
|
+
new Set([
|
|
226
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE,
|
|
227
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED,
|
|
228
|
+
]),
|
|
229
|
+
],
|
|
230
|
+
[
|
|
231
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE,
|
|
232
|
+
new Set([
|
|
233
|
+
RECOMMENDER_PROFILE_MATURITY_V2.STALE,
|
|
234
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED,
|
|
235
|
+
]),
|
|
236
|
+
],
|
|
237
|
+
[
|
|
238
|
+
RECOMMENDER_PROFILE_MATURITY_V2.STALE,
|
|
239
|
+
new Set([
|
|
240
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE,
|
|
241
|
+
RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED,
|
|
242
|
+
]),
|
|
243
|
+
],
|
|
244
|
+
[RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED, new Set()],
|
|
245
|
+
]);
|
|
246
|
+
const _crpTerminal = new Set([RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED]);
|
|
247
|
+
const _crjTrans = new Map([
|
|
248
|
+
[
|
|
249
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.QUEUED,
|
|
250
|
+
new Set([
|
|
251
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING,
|
|
252
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.CANCELLED,
|
|
253
|
+
]),
|
|
254
|
+
],
|
|
255
|
+
[
|
|
256
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING,
|
|
257
|
+
new Set([
|
|
258
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.COMPLETED,
|
|
259
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.FAILED,
|
|
260
|
+
RECOMMENDATION_JOB_LIFECYCLE_V2.CANCELLED,
|
|
261
|
+
]),
|
|
262
|
+
],
|
|
263
|
+
[RECOMMENDATION_JOB_LIFECYCLE_V2.COMPLETED, new Set()],
|
|
264
|
+
[RECOMMENDATION_JOB_LIFECYCLE_V2.FAILED, new Set()],
|
|
265
|
+
[RECOMMENDATION_JOB_LIFECYCLE_V2.CANCELLED, new Set()],
|
|
266
|
+
]);
|
|
267
|
+
|
|
268
|
+
const _crpsV2 = new Map();
|
|
269
|
+
const _crjsV2 = new Map();
|
|
270
|
+
let _crpMaxActivePerOwner = 8;
|
|
271
|
+
let _crpMaxPendingJobsPerProfile = 10;
|
|
272
|
+
let _crpIdleMs = 7 * 24 * 60 * 60 * 1000;
|
|
273
|
+
let _crjStuckMs = 5 * 60 * 1000;
|
|
274
|
+
|
|
275
|
+
function _crpPos(n, lbl) {
|
|
276
|
+
const v = Math.floor(Number(n));
|
|
277
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
278
|
+
throw new Error(`${lbl} must be positive integer`);
|
|
279
|
+
return v;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export function setMaxActiveRecommenderProfilesPerOwnerV2(n) {
|
|
283
|
+
_crpMaxActivePerOwner = _crpPos(n, "maxActiveRecommenderProfilesPerOwner");
|
|
284
|
+
}
|
|
285
|
+
export function getMaxActiveRecommenderProfilesPerOwnerV2() {
|
|
286
|
+
return _crpMaxActivePerOwner;
|
|
287
|
+
}
|
|
288
|
+
export function setMaxPendingRecommendationJobsPerProfileV2(n) {
|
|
289
|
+
_crpMaxPendingJobsPerProfile = _crpPos(
|
|
290
|
+
n,
|
|
291
|
+
"maxPendingRecommendationJobsPerProfile",
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
export function getMaxPendingRecommendationJobsPerProfileV2() {
|
|
295
|
+
return _crpMaxPendingJobsPerProfile;
|
|
296
|
+
}
|
|
297
|
+
export function setRecommenderProfileIdleMsV2(n) {
|
|
298
|
+
_crpIdleMs = _crpPos(n, "recommenderProfileIdleMs");
|
|
299
|
+
}
|
|
300
|
+
export function getRecommenderProfileIdleMsV2() {
|
|
301
|
+
return _crpIdleMs;
|
|
302
|
+
}
|
|
303
|
+
export function setRecommendationJobStuckMsV2(n) {
|
|
304
|
+
_crjStuckMs = _crpPos(n, "recommendationJobStuckMs");
|
|
305
|
+
}
|
|
306
|
+
export function getRecommendationJobStuckMsV2() {
|
|
307
|
+
return _crjStuckMs;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function _resetStateContentRecommenderV2() {
|
|
311
|
+
_crpsV2.clear();
|
|
312
|
+
_crjsV2.clear();
|
|
313
|
+
_crpMaxActivePerOwner = 8;
|
|
314
|
+
_crpMaxPendingJobsPerProfile = 10;
|
|
315
|
+
_crpIdleMs = 7 * 24 * 60 * 60 * 1000;
|
|
316
|
+
_crjStuckMs = 5 * 60 * 1000;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
export function registerRecommenderProfileV2({
|
|
320
|
+
id,
|
|
321
|
+
owner,
|
|
322
|
+
strategy,
|
|
323
|
+
metadata,
|
|
324
|
+
} = {}) {
|
|
325
|
+
if (!id || typeof id !== "string") throw new Error("id is required");
|
|
326
|
+
if (!owner || typeof owner !== "string") throw new Error("owner is required");
|
|
327
|
+
if (_crpsV2.has(id))
|
|
328
|
+
throw new Error(`recommender profile ${id} already registered`);
|
|
329
|
+
const now = Date.now();
|
|
330
|
+
const p = {
|
|
331
|
+
id,
|
|
332
|
+
owner,
|
|
333
|
+
strategy: strategy || "tfidf",
|
|
334
|
+
status: RECOMMENDER_PROFILE_MATURITY_V2.PENDING,
|
|
335
|
+
createdAt: now,
|
|
336
|
+
updatedAt: now,
|
|
337
|
+
activatedAt: null,
|
|
338
|
+
archivedAt: null,
|
|
339
|
+
lastTouchedAt: now,
|
|
340
|
+
metadata: { ...(metadata || {}) },
|
|
341
|
+
};
|
|
342
|
+
_crpsV2.set(id, p);
|
|
343
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
344
|
+
}
|
|
345
|
+
function _crpCheckP(from, to) {
|
|
346
|
+
const a = _crpTrans.get(from);
|
|
347
|
+
if (!a || !a.has(to))
|
|
348
|
+
throw new Error(`invalid recommender profile transition ${from} → ${to}`);
|
|
349
|
+
}
|
|
350
|
+
function _crpCountActive(owner) {
|
|
351
|
+
let n = 0;
|
|
352
|
+
for (const p of _crpsV2.values())
|
|
353
|
+
if (
|
|
354
|
+
p.owner === owner &&
|
|
355
|
+
p.status === RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE
|
|
356
|
+
)
|
|
357
|
+
n++;
|
|
358
|
+
return n;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function activateRecommenderProfileV2(id) {
|
|
362
|
+
const p = _crpsV2.get(id);
|
|
363
|
+
if (!p) throw new Error(`recommender profile ${id} not found`);
|
|
364
|
+
_crpCheckP(p.status, RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE);
|
|
365
|
+
const recovery = p.status === RECOMMENDER_PROFILE_MATURITY_V2.STALE;
|
|
366
|
+
if (!recovery) {
|
|
367
|
+
const c = _crpCountActive(p.owner);
|
|
368
|
+
if (c >= _crpMaxActivePerOwner)
|
|
369
|
+
throw new Error(
|
|
370
|
+
`max active recommender profiles per owner (${_crpMaxActivePerOwner}) reached for ${p.owner}`,
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
const now = Date.now();
|
|
374
|
+
p.status = RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE;
|
|
375
|
+
p.updatedAt = now;
|
|
376
|
+
p.lastTouchedAt = now;
|
|
377
|
+
if (!p.activatedAt) p.activatedAt = now;
|
|
378
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
379
|
+
}
|
|
380
|
+
export function staleRecommenderProfileV2(id) {
|
|
381
|
+
const p = _crpsV2.get(id);
|
|
382
|
+
if (!p) throw new Error(`recommender profile ${id} not found`);
|
|
383
|
+
_crpCheckP(p.status, RECOMMENDER_PROFILE_MATURITY_V2.STALE);
|
|
384
|
+
p.status = RECOMMENDER_PROFILE_MATURITY_V2.STALE;
|
|
385
|
+
p.updatedAt = Date.now();
|
|
386
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
387
|
+
}
|
|
388
|
+
export function archiveRecommenderProfileV2(id) {
|
|
389
|
+
const p = _crpsV2.get(id);
|
|
390
|
+
if (!p) throw new Error(`recommender profile ${id} not found`);
|
|
391
|
+
_crpCheckP(p.status, RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED);
|
|
392
|
+
const now = Date.now();
|
|
393
|
+
p.status = RECOMMENDER_PROFILE_MATURITY_V2.ARCHIVED;
|
|
394
|
+
p.updatedAt = now;
|
|
395
|
+
if (!p.archivedAt) p.archivedAt = now;
|
|
396
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
397
|
+
}
|
|
398
|
+
export function touchRecommenderProfileV2(id) {
|
|
399
|
+
const p = _crpsV2.get(id);
|
|
400
|
+
if (!p) throw new Error(`recommender profile ${id} not found`);
|
|
401
|
+
if (_crpTerminal.has(p.status))
|
|
402
|
+
throw new Error(`cannot touch terminal recommender profile ${id}`);
|
|
403
|
+
const now = Date.now();
|
|
404
|
+
p.lastTouchedAt = now;
|
|
405
|
+
p.updatedAt = now;
|
|
406
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
407
|
+
}
|
|
408
|
+
export function getRecommenderProfileV2(id) {
|
|
409
|
+
const p = _crpsV2.get(id);
|
|
410
|
+
if (!p) return null;
|
|
411
|
+
return { ...p, metadata: { ...p.metadata } };
|
|
412
|
+
}
|
|
413
|
+
export function listRecommenderProfilesV2() {
|
|
414
|
+
return [..._crpsV2.values()].map((p) => ({
|
|
415
|
+
...p,
|
|
416
|
+
metadata: { ...p.metadata },
|
|
417
|
+
}));
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function _crjCountPending(profileId) {
|
|
421
|
+
let n = 0;
|
|
422
|
+
for (const j of _crjsV2.values())
|
|
423
|
+
if (
|
|
424
|
+
j.profileId === profileId &&
|
|
425
|
+
(j.status === RECOMMENDATION_JOB_LIFECYCLE_V2.QUEUED ||
|
|
426
|
+
j.status === RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING)
|
|
427
|
+
)
|
|
428
|
+
n++;
|
|
429
|
+
return n;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export function createRecommendationJobV2({
|
|
433
|
+
id,
|
|
434
|
+
profileId,
|
|
435
|
+
query,
|
|
436
|
+
metadata,
|
|
437
|
+
} = {}) {
|
|
438
|
+
if (!id || typeof id !== "string") throw new Error("id is required");
|
|
439
|
+
if (!profileId || typeof profileId !== "string")
|
|
440
|
+
throw new Error("profileId is required");
|
|
441
|
+
if (_crjsV2.has(id))
|
|
442
|
+
throw new Error(`recommendation job ${id} already exists`);
|
|
443
|
+
if (!_crpsV2.has(profileId))
|
|
444
|
+
throw new Error(`recommender profile ${profileId} not found`);
|
|
445
|
+
const pending = _crjCountPending(profileId);
|
|
446
|
+
if (pending >= _crpMaxPendingJobsPerProfile)
|
|
447
|
+
throw new Error(
|
|
448
|
+
`max pending recommendation jobs per profile (${_crpMaxPendingJobsPerProfile}) reached for ${profileId}`,
|
|
449
|
+
);
|
|
450
|
+
const now = Date.now();
|
|
451
|
+
const j = {
|
|
452
|
+
id,
|
|
453
|
+
profileId,
|
|
454
|
+
query: query || "",
|
|
455
|
+
status: RECOMMENDATION_JOB_LIFECYCLE_V2.QUEUED,
|
|
456
|
+
createdAt: now,
|
|
457
|
+
updatedAt: now,
|
|
458
|
+
startedAt: null,
|
|
459
|
+
settledAt: null,
|
|
460
|
+
metadata: { ...(metadata || {}) },
|
|
461
|
+
};
|
|
462
|
+
_crjsV2.set(id, j);
|
|
463
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
464
|
+
}
|
|
465
|
+
function _crjCheckJ(from, to) {
|
|
466
|
+
const a = _crjTrans.get(from);
|
|
467
|
+
if (!a || !a.has(to))
|
|
468
|
+
throw new Error(`invalid recommendation job transition ${from} → ${to}`);
|
|
469
|
+
}
|
|
470
|
+
export function startRecommendationJobV2(id) {
|
|
471
|
+
const j = _crjsV2.get(id);
|
|
472
|
+
if (!j) throw new Error(`recommendation job ${id} not found`);
|
|
473
|
+
_crjCheckJ(j.status, RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING);
|
|
474
|
+
const now = Date.now();
|
|
475
|
+
j.status = RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING;
|
|
476
|
+
j.updatedAt = now;
|
|
477
|
+
if (!j.startedAt) j.startedAt = now;
|
|
478
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
479
|
+
}
|
|
480
|
+
export function completeRecommendationJobV2(id) {
|
|
481
|
+
const j = _crjsV2.get(id);
|
|
482
|
+
if (!j) throw new Error(`recommendation job ${id} not found`);
|
|
483
|
+
_crjCheckJ(j.status, RECOMMENDATION_JOB_LIFECYCLE_V2.COMPLETED);
|
|
484
|
+
const now = Date.now();
|
|
485
|
+
j.status = RECOMMENDATION_JOB_LIFECYCLE_V2.COMPLETED;
|
|
486
|
+
j.updatedAt = now;
|
|
487
|
+
if (!j.settledAt) j.settledAt = now;
|
|
488
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
489
|
+
}
|
|
490
|
+
export function failRecommendationJobV2(id, reason) {
|
|
491
|
+
const j = _crjsV2.get(id);
|
|
492
|
+
if (!j) throw new Error(`recommendation job ${id} not found`);
|
|
493
|
+
_crjCheckJ(j.status, RECOMMENDATION_JOB_LIFECYCLE_V2.FAILED);
|
|
494
|
+
const now = Date.now();
|
|
495
|
+
j.status = RECOMMENDATION_JOB_LIFECYCLE_V2.FAILED;
|
|
496
|
+
j.updatedAt = now;
|
|
497
|
+
if (!j.settledAt) j.settledAt = now;
|
|
498
|
+
if (reason) j.metadata.failReason = String(reason);
|
|
499
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
500
|
+
}
|
|
501
|
+
export function cancelRecommendationJobV2(id, reason) {
|
|
502
|
+
const j = _crjsV2.get(id);
|
|
503
|
+
if (!j) throw new Error(`recommendation job ${id} not found`);
|
|
504
|
+
_crjCheckJ(j.status, RECOMMENDATION_JOB_LIFECYCLE_V2.CANCELLED);
|
|
505
|
+
const now = Date.now();
|
|
506
|
+
j.status = RECOMMENDATION_JOB_LIFECYCLE_V2.CANCELLED;
|
|
507
|
+
j.updatedAt = now;
|
|
508
|
+
if (!j.settledAt) j.settledAt = now;
|
|
509
|
+
if (reason) j.metadata.cancelReason = String(reason);
|
|
510
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
511
|
+
}
|
|
512
|
+
export function getRecommendationJobV2(id) {
|
|
513
|
+
const j = _crjsV2.get(id);
|
|
514
|
+
if (!j) return null;
|
|
515
|
+
return { ...j, metadata: { ...j.metadata } };
|
|
516
|
+
}
|
|
517
|
+
export function listRecommendationJobsV2() {
|
|
518
|
+
return [..._crjsV2.values()].map((j) => ({
|
|
519
|
+
...j,
|
|
520
|
+
metadata: { ...j.metadata },
|
|
521
|
+
}));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
export function autoStaleIdleRecommenderProfilesV2({ now } = {}) {
|
|
525
|
+
const t = now ?? Date.now();
|
|
526
|
+
const flipped = [];
|
|
527
|
+
for (const p of _crpsV2.values())
|
|
528
|
+
if (
|
|
529
|
+
p.status === RECOMMENDER_PROFILE_MATURITY_V2.ACTIVE &&
|
|
530
|
+
t - p.lastTouchedAt >= _crpIdleMs
|
|
531
|
+
) {
|
|
532
|
+
p.status = RECOMMENDER_PROFILE_MATURITY_V2.STALE;
|
|
533
|
+
p.updatedAt = t;
|
|
534
|
+
flipped.push(p.id);
|
|
535
|
+
}
|
|
536
|
+
return { flipped, count: flipped.length };
|
|
537
|
+
}
|
|
538
|
+
export function autoFailStuckRecommendationJobsV2({ now } = {}) {
|
|
539
|
+
const t = now ?? Date.now();
|
|
540
|
+
const flipped = [];
|
|
541
|
+
for (const j of _crjsV2.values())
|
|
542
|
+
if (
|
|
543
|
+
j.status === RECOMMENDATION_JOB_LIFECYCLE_V2.RUNNING &&
|
|
544
|
+
j.startedAt != null &&
|
|
545
|
+
t - j.startedAt >= _crjStuckMs
|
|
546
|
+
) {
|
|
547
|
+
j.status = RECOMMENDATION_JOB_LIFECYCLE_V2.FAILED;
|
|
548
|
+
j.updatedAt = t;
|
|
549
|
+
if (!j.settledAt) j.settledAt = t;
|
|
550
|
+
j.metadata.failReason = "auto-fail-stuck";
|
|
551
|
+
flipped.push(j.id);
|
|
552
|
+
}
|
|
553
|
+
return { flipped, count: flipped.length };
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
export function getContentRecommenderGovStatsV2() {
|
|
557
|
+
const profilesByStatus = {};
|
|
558
|
+
for (const s of Object.values(RECOMMENDER_PROFILE_MATURITY_V2))
|
|
559
|
+
profilesByStatus[s] = 0;
|
|
560
|
+
for (const p of _crpsV2.values()) profilesByStatus[p.status]++;
|
|
561
|
+
const jobsByStatus = {};
|
|
562
|
+
for (const s of Object.values(RECOMMENDATION_JOB_LIFECYCLE_V2))
|
|
563
|
+
jobsByStatus[s] = 0;
|
|
564
|
+
for (const j of _crjsV2.values()) jobsByStatus[j.status]++;
|
|
565
|
+
return {
|
|
566
|
+
totalRecommenderProfilesV2: _crpsV2.size,
|
|
567
|
+
totalRecommendationJobsV2: _crjsV2.size,
|
|
568
|
+
maxActiveRecommenderProfilesPerOwner: _crpMaxActivePerOwner,
|
|
569
|
+
maxPendingRecommendationJobsPerProfile: _crpMaxPendingJobsPerProfile,
|
|
570
|
+
recommenderProfileIdleMs: _crpIdleMs,
|
|
571
|
+
recommendationJobStuckMs: _crjStuckMs,
|
|
572
|
+
profilesByStatus,
|
|
573
|
+
jobsByStatus,
|
|
574
|
+
};
|
|
575
|
+
}
|