niuma-codex 0.0.1-beta.28 → 0.0.1-beta.29
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/assets/control/app.js +8 -0
- package/dist/assets/control/index.html +4 -0
- package/dist/assets/control/thread-loads.js +175 -0
- package/dist/cli.js +1943 -1421
- package/dist/managed-tauri.js +593 -129
- package/dist/managed.js +564 -123
- package/package.json +1 -1
- package/resources/lite-release.json +7 -7
- package/resources/niuma-daemon-arm64.tgz +0 -0
- package/resources/niuma-lite-arm64.dmg +0 -0
package/dist/managed-tauri.js
CHANGED
|
@@ -6820,6 +6820,45 @@ var init_push_preferences = __esm({
|
|
|
6820
6820
|
}
|
|
6821
6821
|
});
|
|
6822
6822
|
|
|
6823
|
+
// packages/protocol/src/thread-load-trace.ts
|
|
6824
|
+
function object8(value, required, optional = []) {
|
|
6825
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) throw new TypeError("invalid_load_report");
|
|
6826
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
6827
|
+
if (Reflect.ownKeys(value).some((key) => typeof key !== "string" || ![...required, ...optional].includes(key)) || required.some((key) => !Object.hasOwn(descriptors, key)) || Object.values(descriptors).some((d) => !d.enumerable || !("value" in d))) throw new TypeError("invalid_load_report");
|
|
6828
|
+
return value;
|
|
6829
|
+
}
|
|
6830
|
+
function timing(value) {
|
|
6831
|
+
if (!Number.isInteger(value.elapsed_ms) || value.elapsed_ms < 0 || value.elapsed_ms > 9e5 || value.occurred_at_ms !== void 0 && (!Number.isInteger(value.occurred_at_ms) || value.occurred_at_ms < 1 || value.occurred_at_ms > 864e13)) throw new TypeError("invalid_load_timing");
|
|
6832
|
+
}
|
|
6833
|
+
function parseThreadLoadReportV2(value) {
|
|
6834
|
+
const v = object8(value, ["version", "thread_id", "load_id", "client_class", "samples"], ["terminal"]);
|
|
6835
|
+
if (v.version !== 2 || typeof v.thread_id !== "string" || !v.thread_id.length || v.thread_id.length > 256 || typeof v.load_id !== "string" || !/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(v.load_id) || !["web", "ios", "other"].includes(v.client_class) || !Array.isArray(v.samples) || v.samples.length > 6 || !v.samples.length && v.terminal === void 0) throw new TypeError("invalid_load_report");
|
|
6836
|
+
for (const sample of v.samples) {
|
|
6837
|
+
const s = object8(sample, ["phase", "elapsed_ms"], ["occurred_at_ms"]);
|
|
6838
|
+
timing(s);
|
|
6839
|
+
if (!CLIENT_LOAD_PHASES.includes(s.phase)) throw new TypeError("invalid_load_phase");
|
|
6840
|
+
}
|
|
6841
|
+
if (v.terminal !== void 0) {
|
|
6842
|
+
const t = object8(v.terminal, ["kind", "phase", "reason", "elapsed_ms"], ["occurred_at_ms"]);
|
|
6843
|
+
timing(t);
|
|
6844
|
+
const reasons = { failed: ["open_rejected", "history_failed"], cancelled: ["left_view", "user_cancelled"], superseded: ["stream_replaced"] };
|
|
6845
|
+
if (!["request_started", "snapshot_received", "history_ready"].includes(t.phase) || !Object.hasOwn(reasons, t.kind) || !reasons[t.kind]?.includes(t.reason) || v.samples.some((s) => s.phase === "content_presented")) throw new TypeError("invalid_load_terminal");
|
|
6846
|
+
}
|
|
6847
|
+
return v;
|
|
6848
|
+
}
|
|
6849
|
+
function reduceThreadLoadOutcome(current2, event) {
|
|
6850
|
+
if (event === "closed" || event === "expired") return current2.status === "loading" ? { ...current2, status: "incomplete" } : current2;
|
|
6851
|
+
if (current2.status === "loading" || current2.status === "incomplete" && ["cancelled", "superseded"].includes(event)) return { ...current2, status: event };
|
|
6852
|
+
return current2.status === event ? current2 : { ...current2, conflict: true };
|
|
6853
|
+
}
|
|
6854
|
+
var CLIENT_LOAD_PHASES;
|
|
6855
|
+
var init_thread_load_trace = __esm({
|
|
6856
|
+
"packages/protocol/src/thread-load-trace.ts"() {
|
|
6857
|
+
"use strict";
|
|
6858
|
+
CLIENT_LOAD_PHASES = ["selected", "restored", "request_started", "snapshot_received", "history_ready", "content_presented"];
|
|
6859
|
+
}
|
|
6860
|
+
});
|
|
6861
|
+
|
|
6823
6862
|
// packages/protocol/src/index.ts
|
|
6824
6863
|
var init_src2 = __esm({
|
|
6825
6864
|
"packages/protocol/src/index.ts"() {
|
|
@@ -6875,13 +6914,14 @@ var init_src2 = __esm({
|
|
|
6875
6914
|
init_attachment_local_cache_v1();
|
|
6876
6915
|
init_thread_action_state_v1();
|
|
6877
6916
|
init_push_preferences();
|
|
6917
|
+
init_thread_load_trace();
|
|
6878
6918
|
}
|
|
6879
6919
|
});
|
|
6880
6920
|
|
|
6881
6921
|
// apps/desktop/src/release-version.ts
|
|
6882
6922
|
import { readFileSync } from "node:fs";
|
|
6883
6923
|
function desktopReleaseVersion() {
|
|
6884
|
-
return false ? null : "0.0.1-beta.
|
|
6924
|
+
return false ? null : "0.0.1-beta.29";
|
|
6885
6925
|
}
|
|
6886
6926
|
function desktopPresenceVersion() {
|
|
6887
6927
|
return desktopReleaseVersion() ?? sourcePresenceVersion;
|
|
@@ -11337,6 +11377,65 @@ var init_launcher = __esm({
|
|
|
11337
11377
|
}
|
|
11338
11378
|
});
|
|
11339
11379
|
|
|
11380
|
+
// apps/desktop/src/daemon/runtime/ipc-thread-discovery.ts
|
|
11381
|
+
var RuntimeIpcThreadDiscovery;
|
|
11382
|
+
var init_ipc_thread_discovery = __esm({
|
|
11383
|
+
"apps/desktop/src/daemon/runtime/ipc-thread-discovery.ts"() {
|
|
11384
|
+
"use strict";
|
|
11385
|
+
RuntimeIpcThreadDiscovery = class {
|
|
11386
|
+
constructor(ports) {
|
|
11387
|
+
this.ports = ports;
|
|
11388
|
+
}
|
|
11389
|
+
ports;
|
|
11390
|
+
pending = /* @__PURE__ */ new Map();
|
|
11391
|
+
discover(id5) {
|
|
11392
|
+
const started2 = Date.now();
|
|
11393
|
+
const report = (phase) => {
|
|
11394
|
+
try {
|
|
11395
|
+
this.ports.diagnostic(id5, phase, Date.now() - started2);
|
|
11396
|
+
} catch {
|
|
11397
|
+
}
|
|
11398
|
+
};
|
|
11399
|
+
if (!this.ports.eligible(id5)) {
|
|
11400
|
+
report("ignored");
|
|
11401
|
+
return;
|
|
11402
|
+
}
|
|
11403
|
+
if (this.pending.has(id5)) {
|
|
11404
|
+
report("deduplicated");
|
|
11405
|
+
return;
|
|
11406
|
+
}
|
|
11407
|
+
if (this.pending.size >= 66) {
|
|
11408
|
+
report("capacity");
|
|
11409
|
+
return;
|
|
11410
|
+
}
|
|
11411
|
+
const current2 = this.ports.capture();
|
|
11412
|
+
report("received");
|
|
11413
|
+
const task = this.run(id5, current2, report).catch(() => report("failed")).finally(() => {
|
|
11414
|
+
if (this.pending.get(id5) === task) this.pending.delete(id5);
|
|
11415
|
+
});
|
|
11416
|
+
this.pending.set(id5, task);
|
|
11417
|
+
}
|
|
11418
|
+
async run(id5, current2, report) {
|
|
11419
|
+
const result = await this.ports.read(id5);
|
|
11420
|
+
report("read_completed");
|
|
11421
|
+
const valid = () => current2() && this.ports.eligible(id5) && result.kind === "ordinary" && result.summary?.id === id5 && !!result.token && this.ports.current(result.token);
|
|
11422
|
+
if (!valid()) {
|
|
11423
|
+
report("rejected");
|
|
11424
|
+
return;
|
|
11425
|
+
}
|
|
11426
|
+
await this.ports.enqueue(() => {
|
|
11427
|
+
if (!valid()) {
|
|
11428
|
+
report("stale");
|
|
11429
|
+
return;
|
|
11430
|
+
}
|
|
11431
|
+
this.ports.commit(result.summary);
|
|
11432
|
+
report("published");
|
|
11433
|
+
});
|
|
11434
|
+
}
|
|
11435
|
+
};
|
|
11436
|
+
}
|
|
11437
|
+
});
|
|
11438
|
+
|
|
11340
11439
|
// apps/desktop/src/daemon/async-question-response.ts
|
|
11341
11440
|
import { createHash } from "node:crypto";
|
|
11342
11441
|
function submissionId(input) {
|
|
@@ -14316,11 +14415,11 @@ var init_activity_publication = __esm({
|
|
|
14316
14415
|
if (!thread4) {
|
|
14317
14416
|
return null;
|
|
14318
14417
|
}
|
|
14319
|
-
const
|
|
14320
|
-
const timingFields =
|
|
14321
|
-
turnStartedAt:
|
|
14322
|
-
...
|
|
14323
|
-
...
|
|
14418
|
+
const timing2 = this.ports.turnTiming(signal.threadId, signal.turnId);
|
|
14419
|
+
const timingFields = timing2 ? {
|
|
14420
|
+
turnStartedAt: timing2.startedAt,
|
|
14421
|
+
...timing2.endedAt !== void 0 ? { turnEndedAt: timing2.endedAt } : {},
|
|
14422
|
+
...timing2.outcome !== void 0 ? { turnOutcome: timing2.outcome } : {}
|
|
14324
14423
|
} : {};
|
|
14325
14424
|
if (signal.type === "turn_aborted") {
|
|
14326
14425
|
return {
|
|
@@ -20217,7 +20316,7 @@ var init_private_journal = __esm({
|
|
|
20217
20316
|
function fail14(reason) {
|
|
20218
20317
|
throw new MessageSubmissionStoreError(reason);
|
|
20219
20318
|
}
|
|
20220
|
-
function
|
|
20319
|
+
function object9(value, keys3, optional = []) {
|
|
20221
20320
|
if (!value || typeof value !== "object" || Array.isArray(value)) return fail14("invalid");
|
|
20222
20321
|
const record25 = value;
|
|
20223
20322
|
if (Object.keys(record25).some((key) => !keys3.includes(key) && !optional.includes(key)) || !keys3.every((key) => Object.hasOwn(record25, key))) return fail14("invalid");
|
|
@@ -20251,7 +20350,7 @@ function parseReceipt(value, clientMessageId) {
|
|
|
20251
20350
|
return receipt;
|
|
20252
20351
|
}
|
|
20253
20352
|
function parsePost(value, clientMessageId) {
|
|
20254
|
-
const record25 =
|
|
20353
|
+
const record25 = object9(value, ["httpStatus", "code", "message", "data"]);
|
|
20255
20354
|
if (![200, 400, 404, 500].includes(record25.httpStatus) || !Number.isInteger(record25.code) || record25.code !== 0 && (record25.code < 1e5 || record25.code > 999999) || typeof record25.message !== "string" || record25.message.length === 0 || Buffer.byteLength(record25.message) > MAX_MESSAGE_BYTES || byteSize(record25.message) > MAX_MESSAGE_BYTES + 2) fail14("invalid");
|
|
20256
20355
|
if (record25.code === 0) {
|
|
20257
20356
|
if (record25.httpStatus !== 200) fail14("invalid");
|
|
@@ -20264,10 +20363,10 @@ function parsePost(value, clientMessageId) {
|
|
|
20264
20363
|
} else if (record25.data !== null) {
|
|
20265
20364
|
const data = record25.data;
|
|
20266
20365
|
if (data.state === "unknown") {
|
|
20267
|
-
|
|
20366
|
+
object9(data, ["client_message_id", "state"]);
|
|
20268
20367
|
if (data.client_message_id !== clientMessageId) fail14("invalid");
|
|
20269
20368
|
} else {
|
|
20270
|
-
|
|
20369
|
+
object9(data, ["dispatch_state"]);
|
|
20271
20370
|
if (data.dispatch_state !== "not_dispatched") fail14("invalid");
|
|
20272
20371
|
}
|
|
20273
20372
|
}
|
|
@@ -20300,13 +20399,13 @@ function parseDocument(raw, maxEntries) {
|
|
|
20300
20399
|
} catch {
|
|
20301
20400
|
return fail14("invalid");
|
|
20302
20401
|
}
|
|
20303
|
-
const document =
|
|
20402
|
+
const document = object9(value, ["version", "entries"]);
|
|
20304
20403
|
if (document.version !== 1 || !Array.isArray(document.entries)) fail14("invalid");
|
|
20305
20404
|
if (document.entries.length > maxEntries) fail14("capacity");
|
|
20306
20405
|
const entries = /* @__PURE__ */ new Map();
|
|
20307
20406
|
const nativeItems = /* @__PURE__ */ new Set();
|
|
20308
20407
|
for (const value2 of document.entries) {
|
|
20309
|
-
const record25 =
|
|
20408
|
+
const record25 = object9(value2, ["principal", "threadId", "clientMessageId", "fingerprint", "nativeToken", "receipt", "firstResult", "createdAt", "updatedAt"], ["questionId"]);
|
|
20310
20409
|
if (typeof record25.nativeToken !== "boolean" || !Number.isSafeInteger(record25.createdAt) || record25.createdAt < 0 || !Number.isSafeInteger(record25.updatedAt) || record25.updatedAt < 0) fail14("invalid");
|
|
20311
20410
|
const entry = { ...record25, nativeToken: record25.nativeToken ? record25.clientMessageId : null };
|
|
20312
20411
|
validateReservation(entry);
|
|
@@ -20398,7 +20497,7 @@ async function openMessageSubmissionStore(options) {
|
|
|
20398
20497
|
reserve(input) {
|
|
20399
20498
|
const captured = clone(input);
|
|
20400
20499
|
return enqueue(async () => {
|
|
20401
|
-
|
|
20500
|
+
object9(captured, ["principal", "threadId", "clientMessageId", "fingerprint", "nativeToken"], ["questionId"]);
|
|
20402
20501
|
validateReservation(captured);
|
|
20403
20502
|
const existing = entries.get(captured.clientMessageId);
|
|
20404
20503
|
if (existing) {
|
|
@@ -24313,8 +24412,8 @@ var init_transport = __esm({
|
|
|
24313
24412
|
/** 慢响应只保留每分钟首条及抑制数;超时和协议失败仍逐次保留。 */
|
|
24314
24413
|
auditSlowResponse(id5, pending, bytes3, failed) {
|
|
24315
24414
|
if (!Number.isFinite(pending.startedAtMs)) return;
|
|
24316
|
-
const
|
|
24317
|
-
if (
|
|
24415
|
+
const timing2 = this.requestTiming(pending), now = performance.now();
|
|
24416
|
+
if (timing2.elapsedMs < 5e3) return;
|
|
24318
24417
|
if (now - this.lastSlowAuditAtMs < 6e4) {
|
|
24319
24418
|
this.suppressedSlowAudits++;
|
|
24320
24419
|
return;
|
|
@@ -24325,7 +24424,7 @@ var init_transport = __esm({
|
|
|
24325
24424
|
...typeof id5 === "number" ? { requestId: id5 } : {},
|
|
24326
24425
|
...isSafeErrorAuditOperation(pending.method) ? { method: pending.method } : {},
|
|
24327
24426
|
bytes: bytes3,
|
|
24328
|
-
requestTiming:
|
|
24427
|
+
requestTiming: timing2,
|
|
24329
24428
|
responseDisposition: failed ? "error" : "success",
|
|
24330
24429
|
suppressedCount: this.suppressedSlowAudits
|
|
24331
24430
|
});
|
|
@@ -28763,7 +28862,7 @@ import { randomBytes as randomBytes3 } from "node:crypto";
|
|
|
28763
28862
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
28764
28863
|
function logicalDescriptor(descriptor) {
|
|
28765
28864
|
if (descriptor.pathname !== "/api/v1/thread/open") return descriptor;
|
|
28766
|
-
const { load_id: _loadId, range_resume_token: _rangeToken, ...query2 } = descriptor.query;
|
|
28865
|
+
const { load_id: _loadId, load_trace: _loadTrace, range_resume_token: _rangeToken, ...query2 } = descriptor.query;
|
|
28767
28866
|
return { pathname: descriptor.pathname, query: query2 };
|
|
28768
28867
|
}
|
|
28769
28868
|
function fail15(code, message) {
|
|
@@ -31094,8 +31193,7 @@ function invalidPushServerOrigin() {
|
|
|
31094
31193
|
function resolvePushServerOrigin(environment) {
|
|
31095
31194
|
const value = environment.NIUMA_PUSH_SERVER_ORIGIN;
|
|
31096
31195
|
if (value === void 0 || isBlankConfigValue(value)) {
|
|
31097
|
-
|
|
31098
|
-
return release2 ? DEFAULT_PUSH_PUBLIC_URL : resolveLocalServerOrigin(environment);
|
|
31196
|
+
return DEFAULT_PUSH_PUBLIC_URL;
|
|
31099
31197
|
}
|
|
31100
31198
|
if (URL_CONTROL_OR_SPACE_PATTERN.test(value)) {
|
|
31101
31199
|
throw invalidPushServerOrigin();
|
|
@@ -31197,10 +31295,11 @@ var init_server_client = __esm({
|
|
|
31197
31295
|
|
|
31198
31296
|
// apps/desktop/src/daemon/thread-load-trace.ts
|
|
31199
31297
|
import { z as z8 } from "zod";
|
|
31200
|
-
var ClientLoadPhaseSchema, occurredAtSchema, LoadSampleSchema, ThreadLoadReportSchema, LoadingTraceSchema, ThreadLoadReports;
|
|
31201
|
-
var
|
|
31298
|
+
var ClientLoadPhaseSchema, occurredAtSchema, LoadSampleSchema, ThreadLoadReportSchema, ThreadLoadReportV2Schema, LoadingTraceSchema, ThreadLoadReports;
|
|
31299
|
+
var init_thread_load_trace2 = __esm({
|
|
31202
31300
|
"apps/desktop/src/daemon/thread-load-trace.ts"() {
|
|
31203
31301
|
"use strict";
|
|
31302
|
+
init_src2();
|
|
31204
31303
|
ClientLoadPhaseSchema = z8.enum(["selected", "restored", "request_started", "snapshot_received", "history_ready", "content_presented"]);
|
|
31205
31304
|
occurredAtSchema = z8.number().int().min(1).max(864e13).optional();
|
|
31206
31305
|
LoadSampleSchema = z8.object({
|
|
@@ -31213,6 +31312,20 @@ var init_thread_load_trace = __esm({
|
|
|
31213
31312
|
load_id: z8.string().uuid(),
|
|
31214
31313
|
samples: z8.array(LoadSampleSchema).min(1).max(6)
|
|
31215
31314
|
}).strict();
|
|
31315
|
+
ThreadLoadReportV2Schema = z8.object({
|
|
31316
|
+
version: z8.literal(2),
|
|
31317
|
+
thread_id: z8.string().min(1).max(256),
|
|
31318
|
+
load_id: z8.string().uuid(),
|
|
31319
|
+
client_class: z8.enum(["web", "ios", "other"]),
|
|
31320
|
+
samples: z8.array(LoadSampleSchema).max(6),
|
|
31321
|
+
terminal: z8.object({ kind: z8.enum(["failed", "cancelled", "superseded"]), phase: z8.enum(["request_started", "snapshot_received", "history_ready"]), reason: z8.enum(["open_rejected", "history_failed", "left_view", "user_cancelled", "stream_replaced"]), elapsed_ms: z8.number().int().min(0).max(9e5), occurred_at_ms: occurredAtSchema }).strict().optional()
|
|
31322
|
+
}).strict().superRefine((value, context) => {
|
|
31323
|
+
try {
|
|
31324
|
+
parseThreadLoadReportV2(value);
|
|
31325
|
+
} catch {
|
|
31326
|
+
context.addIssue({ code: "custom", message: "\u52A0\u8F7D\u91C7\u6837\u7EC4\u5408\u65E0\u6548" });
|
|
31327
|
+
}
|
|
31328
|
+
});
|
|
31216
31329
|
LoadingTraceSchema = z8.object({
|
|
31217
31330
|
load_id: z8.string().uuid(),
|
|
31218
31331
|
lease_id: z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u),
|
|
@@ -31222,27 +31335,128 @@ var init_thread_load_trace = __esm({
|
|
|
31222
31335
|
occurred_at_ms: occurredAtSchema
|
|
31223
31336
|
}).strict().refine((value) => value.clock === "browser" ? ClientLoadPhaseSchema.safeParse(value.phase).success : ["open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent", "stream_closed"].includes(value.phase));
|
|
31224
31337
|
ThreadLoadReports = class {
|
|
31225
|
-
constructor(now = Date.now) {
|
|
31338
|
+
constructor(now = Date.now, audit = () => void 0) {
|
|
31226
31339
|
this.now = now;
|
|
31340
|
+
this.audit = audit;
|
|
31227
31341
|
}
|
|
31228
31342
|
now;
|
|
31343
|
+
audit;
|
|
31229
31344
|
entries = /* @__PURE__ */ new Map();
|
|
31230
|
-
|
|
31345
|
+
used = /* @__PURE__ */ new Set();
|
|
31346
|
+
clear() {
|
|
31347
|
+
this.entries.clear();
|
|
31348
|
+
}
|
|
31349
|
+
begin(input) {
|
|
31350
|
+
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
31351
|
+
if (!z8.string().uuid().safeParse(input.loadId).success || this.entries.size >= 256 || this.used.size >= 1e4 || this.used.has(input.loadId)) return null;
|
|
31352
|
+
const id5 = input.loadId;
|
|
31353
|
+
const writer = this.audit();
|
|
31354
|
+
if (writer?.reserveLoadId && !writer.reserveLoadId(id5)) {
|
|
31355
|
+
this.used.add(id5);
|
|
31356
|
+
return null;
|
|
31357
|
+
}
|
|
31358
|
+
this.used.add(id5);
|
|
31359
|
+
const epoch = writer?.loadGeneration?.();
|
|
31360
|
+
let outcome = { status: "loading", conflict: false };
|
|
31361
|
+
let lease, trace;
|
|
31362
|
+
const entry = { threadId: input.threadId, owner: input.owner, expires: input.nowMs + 9e5, seen: /* @__PURE__ */ new Set(), record: () => {
|
|
31363
|
+
}, valid: () => this.entries.get(id5) === entry && writer?.loadGeneration?.() === epoch && this.now() <= entry.expires };
|
|
31364
|
+
const write = (record25) => {
|
|
31365
|
+
if (!entry.valid?.()) return;
|
|
31366
|
+
try {
|
|
31367
|
+
writer?.recordLoad?.({ ...record25, load_id: id5, thread_id: input.threadId, occurred_at_ms: this.now(), ...lease ? { lease_id: lease } : {}, ...trace ? { trace_id: trace } : {} });
|
|
31368
|
+
} catch {
|
|
31369
|
+
}
|
|
31370
|
+
};
|
|
31371
|
+
const end = (event) => {
|
|
31372
|
+
outcome = reduceThreadLoadOutcome(outcome, event);
|
|
31373
|
+
entry.expires = Math.min(entry.expires, this.now() + 3e4);
|
|
31374
|
+
};
|
|
31375
|
+
const elapsed = () => Math.max(0, Math.min(9e5, this.now() - input.nowMs));
|
|
31376
|
+
const handle = {
|
|
31377
|
+
markDaemon: (phase, elapsedMs, occurredAtMs = this.now()) => {
|
|
31378
|
+
if (!entry.valid?.() || entry.seen.has("daemon:" + phase)) return;
|
|
31379
|
+
entry.seen.add("daemon:" + phase);
|
|
31380
|
+
write({ record_type: "load_sample", clock: "daemon", phase, elapsed_ms: elapsedMs, event_at_ms: occurredAtMs });
|
|
31381
|
+
},
|
|
31382
|
+
attachLease: (leaseId, traceId) => {
|
|
31383
|
+
lease = leaseId;
|
|
31384
|
+
trace = traceId;
|
|
31385
|
+
},
|
|
31386
|
+
// 每种确定终态只记一次;保留不同证据供 reducer 标示冲突,不延长授权期限。
|
|
31387
|
+
finish: (kind, evidence = {}) => {
|
|
31388
|
+
if (!entry.valid?.() || entry.seen.has("terminal:" + kind)) return;
|
|
31389
|
+
entry.seen.add("terminal:" + kind);
|
|
31390
|
+
write({ record_type: "load_terminal", clock: "daemon", phase: kind, elapsed_ms: elapsed(), ...evidence });
|
|
31391
|
+
end(kind);
|
|
31392
|
+
},
|
|
31393
|
+
close: () => {
|
|
31394
|
+
if (!entry.valid?.() || entry.seen.has("closed")) return;
|
|
31395
|
+
entry.seen.add("closed");
|
|
31396
|
+
write({ record_type: "load_close", clock: "daemon", phase: "closed", elapsed_ms: elapsed() });
|
|
31397
|
+
end("closed");
|
|
31398
|
+
},
|
|
31399
|
+
outcome: () => outcome
|
|
31400
|
+
};
|
|
31401
|
+
entry.handle = handle;
|
|
31402
|
+
entry.accept = (samples, client, terminal) => {
|
|
31403
|
+
for (const sample of samples) if (!entry.seen.has("client:" + sample.phase)) {
|
|
31404
|
+
entry.seen.add("client:" + sample.phase);
|
|
31405
|
+
write({ record_type: "load_sample", clock: "client", phase: sample.phase, elapsed_ms: sample.elapsed_ms, ...sample.occurred_at_ms ? { event_at_ms: sample.occurred_at_ms } : {}, ...client ? { client_class: client } : {} });
|
|
31406
|
+
if (sample.phase === "content_presented") end("presented");
|
|
31407
|
+
try {
|
|
31408
|
+
entry.record(sample);
|
|
31409
|
+
} catch {
|
|
31410
|
+
}
|
|
31411
|
+
}
|
|
31412
|
+
if (terminal && !entry.seen.has("terminal")) {
|
|
31413
|
+
entry.seen.add("terminal");
|
|
31414
|
+
write({ record_type: "load_terminal", clock: "client", phase: terminal.kind, terminal_phase: terminal.phase, reason: terminal.reason, elapsed_ms: terminal.elapsed_ms, ...terminal.occurred_at_ms ? { event_at_ms: terminal.occurred_at_ms } : {}, ...client ? { client_class: client } : {} });
|
|
31415
|
+
end(terminal.kind);
|
|
31416
|
+
}
|
|
31417
|
+
};
|
|
31418
|
+
this.entries.set(id5, entry);
|
|
31419
|
+
write({ record_type: "load_start", clock: "daemon", phase: "open_received", elapsed_ms: 0, source_transport: input.transport });
|
|
31420
|
+
return handle;
|
|
31421
|
+
}
|
|
31422
|
+
register(loadId, threadId2, owner2, record25, attempt) {
|
|
31231
31423
|
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
31232
|
-
|
|
31424
|
+
const existing = this.entries.get(loadId);
|
|
31425
|
+
if (existing?.handle && existing.handle === attempt && existing.threadId === threadId2 && existing.owner === owner2) {
|
|
31426
|
+
existing.record = record25;
|
|
31427
|
+
return () => {
|
|
31428
|
+
};
|
|
31429
|
+
}
|
|
31430
|
+
if (!z8.string().uuid().safeParse(loadId).success || this.entries.size >= 256 || this.used.size >= 1e4 || this.entries.has(loadId) || this.used.has(loadId)) return () => {
|
|
31233
31431
|
};
|
|
31234
|
-
const
|
|
31432
|
+
const writer = this.audit(), epoch = writer?.loadGeneration?.();
|
|
31433
|
+
if (writer?.reserveLoadId && !writer.reserveLoadId(loadId)) {
|
|
31434
|
+
this.used.add(loadId);
|
|
31435
|
+
return () => {
|
|
31436
|
+
};
|
|
31437
|
+
}
|
|
31438
|
+
this.used.add(loadId);
|
|
31439
|
+
const entry = { threadId: threadId2, owner: owner2, expires: this.now() + 9e5, record: record25, seen: /* @__PURE__ */ new Set(), valid: () => this.entries.get(loadId) === entry && writer?.loadGeneration?.() === epoch && this.now() <= entry.expires };
|
|
31235
31440
|
this.entries.set(loadId, entry);
|
|
31236
31441
|
return () => {
|
|
31237
31442
|
if (this.entries.get(loadId) === entry) this.entries.delete(loadId);
|
|
31238
31443
|
};
|
|
31239
31444
|
}
|
|
31240
31445
|
report(input, owner2) {
|
|
31241
|
-
|
|
31446
|
+
let parsed;
|
|
31447
|
+
try {
|
|
31448
|
+
parsed = input?.version === 2 ? { success: true, data: parseThreadLoadReportV2(input) } : ThreadLoadReportSchema.safeParse(input);
|
|
31449
|
+
} catch {
|
|
31450
|
+
parsed = { success: false };
|
|
31451
|
+
}
|
|
31242
31452
|
if (!parsed.success) return { accepted: false };
|
|
31243
31453
|
const { load_id, thread_id, samples } = parsed.data;
|
|
31244
31454
|
const entry = this.entries.get(load_id);
|
|
31245
|
-
if (!entry || entry.threadId !== thread_id || entry.owner !== owner2 || entry.expires < this.now()) return { accepted: false };
|
|
31455
|
+
if (!entry || entry.threadId !== thread_id || entry.owner !== owner2 || entry.expires < this.now() || entry.valid && !entry.valid()) return { accepted: false };
|
|
31456
|
+
if (entry.accept) {
|
|
31457
|
+
entry.accept(samples, parsed.data.client_class, parsed.data.terminal);
|
|
31458
|
+
return { accepted: true };
|
|
31459
|
+
}
|
|
31246
31460
|
for (const sample of samples) if (!entry.seen.has(sample.phase)) {
|
|
31247
31461
|
entry.seen.add(sample.phase);
|
|
31248
31462
|
try {
|
|
@@ -31262,7 +31476,7 @@ var nonEmptyString5, booleanQuery, authorizationMode, canonicalBase64, boundedIn
|
|
|
31262
31476
|
var init_contracts2 = __esm({
|
|
31263
31477
|
"apps/desktop/src/http/contracts.ts"() {
|
|
31264
31478
|
"use strict";
|
|
31265
|
-
|
|
31479
|
+
init_thread_load_trace2();
|
|
31266
31480
|
init_src2();
|
|
31267
31481
|
nonEmptyString5 = z9.string().trim().min(1);
|
|
31268
31482
|
booleanQuery = z9.enum(["true", "false"]).transform((value) => value === "true");
|
|
@@ -31477,6 +31691,8 @@ var init_contracts2 = __esm({
|
|
|
31477
31691
|
range_resume_version: z9.literal("1").transform(() => 1).optional(),
|
|
31478
31692
|
range_resume_token: z9.string().regex(/^[A-Za-z0-9_-]{43}$/).optional(),
|
|
31479
31693
|
load_id: z9.string().uuid().optional(),
|
|
31694
|
+
// 恢复关联仍保留,只有首屏采样可显式关闭。
|
|
31695
|
+
load_trace: z9.literal("false").transform(() => false).optional(),
|
|
31480
31696
|
include_execution: z9.literal("true").transform(() => true).optional(),
|
|
31481
31697
|
include_message_times: z9.literal("true").transform(() => true).optional(),
|
|
31482
31698
|
include_async_questions: z9.literal("true").transform(() => true).optional(),
|
|
@@ -32522,6 +32738,7 @@ function createThreadOpenSseProjection(rawQuery, options = {}) {
|
|
|
32522
32738
|
...query2.range_resume_version ? { rangeResumeVersion: 1 } : {},
|
|
32523
32739
|
...query2.range_resume_token ? { rangeResumeToken: query2.range_resume_token } : {},
|
|
32524
32740
|
...query2.load_id ? { loadId: query2.load_id } : {},
|
|
32741
|
+
...query2.load_trace === false ? { loadTrace: false } : {},
|
|
32525
32742
|
viewVersion: THREAD_VIEW_VERSION,
|
|
32526
32743
|
...query2.include_async_questions ? { includeAsyncQuestions: true } : {},
|
|
32527
32744
|
...query2.include_read_receipts ? { includeReadReceipts: true } : {},
|
|
@@ -33556,7 +33773,7 @@ async function dispatchRestRoute(request2, dependencies) {
|
|
|
33556
33773
|
}
|
|
33557
33774
|
}
|
|
33558
33775
|
if (route === "POST /api/v1/thread/load/report") {
|
|
33559
|
-
const body = ThreadLoadReportSchema.parse(request2.body);
|
|
33776
|
+
const body = request2.body?.version === 2 ? ThreadLoadReportV2Schema.parse(request2.body) : ThreadLoadReportSchema.parse(request2.body);
|
|
33560
33777
|
const result = await daemonClient.request("thread/load/report", body, {
|
|
33561
33778
|
...daemonRequestOptions(5e3, request2.signal),
|
|
33562
33779
|
...request2.authenticatedMessageSubmissionScope !== void 0 ? { authenticatedMessageSubmissionScope: request2.authenticatedMessageSubmissionScope } : {}
|
|
@@ -44262,8 +44479,8 @@ function createRelayAttachmentDataLink(options) {
|
|
|
44262
44479
|
const child = { permit, lease: null, ws: null, receiver: null, closed: false, paired: false, ready: false, opening: null, cleanup: null, unregister: null };
|
|
44263
44480
|
children.set(permit.transfer_id, child);
|
|
44264
44481
|
const registrationStarted = Date.now();
|
|
44265
|
-
const
|
|
44266
|
-
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "started", ...
|
|
44482
|
+
const timing2 = () => ({ attach_remaining_ms: permit.attach_expires_at - Date.now(), transfer_remaining_ms: permit.expires_at - Date.now(), registration_elapsed_ms: Date.now() - registrationStarted });
|
|
44483
|
+
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "started", ...timing2() });
|
|
44267
44484
|
try {
|
|
44268
44485
|
const reply = await options.control.requestFileControl("file.register", {
|
|
44269
44486
|
version: 1,
|
|
@@ -44275,7 +44492,7 @@ function createRelayAttachmentDataLink(options) {
|
|
|
44275
44492
|
max_wire_bytes: attachmentTransferWireBudget(permit.context.byte_size)
|
|
44276
44493
|
});
|
|
44277
44494
|
if (reply.code !== 0) {
|
|
44278
|
-
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...
|
|
44495
|
+
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...timing2() });
|
|
44279
44496
|
const error2 = unavailable7();
|
|
44280
44497
|
error2.cause = { stage: "file.register", relayCode: reply.code };
|
|
44281
44498
|
throw error2;
|
|
@@ -48026,7 +48243,7 @@ var init_desktop_ingress = __esm({
|
|
|
48026
48243
|
resetMethodValidity() {
|
|
48027
48244
|
this.ipcMethodInvalidatedThreads.clear();
|
|
48028
48245
|
}
|
|
48029
|
-
async process(frame, ownClientId = this.ports.ipc()?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.ipcConnectionGeneration(),
|
|
48246
|
+
async process(frame, ownClientId = this.ports.ipc()?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.ipcConnectionGeneration(), timing2, readDiagnostic) {
|
|
48030
48247
|
this.ports.writeDebug({
|
|
48031
48248
|
component: "daemon",
|
|
48032
48249
|
channel: "ipc",
|
|
@@ -48036,7 +48253,7 @@ var init_desktop_ingress = __esm({
|
|
|
48036
48253
|
attributes: {
|
|
48037
48254
|
type: frame.type,
|
|
48038
48255
|
...typeof frame.method === "string" ? { method: frame.method } : {},
|
|
48039
|
-
...
|
|
48256
|
+
...timing2
|
|
48040
48257
|
}
|
|
48041
48258
|
});
|
|
48042
48259
|
this.ports.writeRawDebug({
|
|
@@ -48068,6 +48285,9 @@ var init_desktop_ingress = __esm({
|
|
|
48068
48285
|
}
|
|
48069
48286
|
const status2 = objectRecord(frame.params);
|
|
48070
48287
|
const methodThreadId = extractThreadIdFromIpcFrame(frame);
|
|
48288
|
+
if (!this.ports.stopping() && receivedIpcGeneration === this.ports.ipcConnectionGeneration() && this.ports.desktopIpcState() === "ready" && ownClientId && frame.type === "broadcast" && frame.sourceClientId && frame.sourceClientId !== ownClientId && status2.hostId === "local" && methodThreadId && (frame.method === "thread-stream-following-status-requested" || frame.method === "thread-stream-following-changed" && status2.following === true)) {
|
|
48289
|
+
this.ports.discoverThread(methodThreadId);
|
|
48290
|
+
}
|
|
48071
48291
|
if (frame.method === "thread-stream-state-changed" && methodThreadId && this.ipcMethodInvalidatedThreads.has(methodThreadId) && objectRecord(status2.change).type !== "snapshot") {
|
|
48072
48292
|
if (readDiagnostic) readDiagnostic.reason = "baseline_required";
|
|
48073
48293
|
return;
|
|
@@ -48770,19 +48990,19 @@ var init_socket_client = __esm({
|
|
|
48770
48990
|
this.events.on("requestDiagnostic", listener);
|
|
48771
48991
|
return () => this.events.off("requestDiagnostic", listener);
|
|
48772
48992
|
}
|
|
48773
|
-
emitRequestDiagnostic(
|
|
48993
|
+
emitRequestDiagnostic(timing2, phase, outcome) {
|
|
48774
48994
|
this.events.emit("requestDiagnostic", {
|
|
48775
|
-
requestId:
|
|
48776
|
-
method:
|
|
48777
|
-
threadId:
|
|
48995
|
+
requestId: timing2.requestId,
|
|
48996
|
+
method: timing2.method,
|
|
48997
|
+
threadId: timing2.threadId,
|
|
48778
48998
|
phase,
|
|
48779
48999
|
outcome,
|
|
48780
|
-
durationMs: Math.max(0, Math.floor(performance.now() -
|
|
49000
|
+
durationMs: Math.max(0, Math.floor(performance.now() - timing2.startedAt))
|
|
48781
49001
|
});
|
|
48782
49002
|
}
|
|
48783
49003
|
pruneTimedOutRequests() {
|
|
48784
|
-
for (const [id5,
|
|
48785
|
-
if (performance.now() -
|
|
49004
|
+
for (const [id5, timing2] of this.timedOutRequests) {
|
|
49005
|
+
if (performance.now() - timing2.startedAt > 12e4) this.timedOutRequests.delete(id5);
|
|
48786
49006
|
}
|
|
48787
49007
|
while (this.timedOutRequests.size > 128) this.timedOutRequests.delete(this.timedOutRequests.keys().next().value);
|
|
48788
49008
|
}
|
|
@@ -48919,20 +49139,20 @@ var init_socket_client = __esm({
|
|
|
48919
49139
|
this.pruneTimedOutRequests();
|
|
48920
49140
|
const localParams = params && typeof params === "object" ? params : {};
|
|
48921
49141
|
const threadId2 = typeof localParams.threadId === "string" ? localParams.threadId : typeof localParams.conversationId === "string" ? localParams.conversationId : void 0;
|
|
48922
|
-
const
|
|
49142
|
+
const timing2 = { requestId, method: method2, threadId: threadId2, startedAt: performance.now() };
|
|
48923
49143
|
const responsePromise = new Promise((resolve5, reject3) => {
|
|
48924
49144
|
const timer = setTimeout(() => {
|
|
48925
49145
|
this.pending.delete(requestId);
|
|
48926
|
-
this.timedOutRequests.set(requestId,
|
|
49146
|
+
this.timedOutRequests.set(requestId, timing2);
|
|
48927
49147
|
this.pruneTimedOutRequests();
|
|
48928
|
-
this.emitRequestDiagnostic(
|
|
49148
|
+
this.emitRequestDiagnostic(timing2, "timeout", "unknown");
|
|
48929
49149
|
reject3(new NiumaError("UNKNOWN_RESULT", `IPC \u8BF7\u6C42\u8D85\u65F6: ${method2}`, { method: method2 }));
|
|
48930
49150
|
}, options.timeoutMs ?? this.requestTimeoutMs);
|
|
48931
|
-
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing });
|
|
49151
|
+
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing: timing2 });
|
|
48932
49152
|
});
|
|
48933
49153
|
try {
|
|
48934
49154
|
await this.write(frame);
|
|
48935
|
-
this.emitRequestDiagnostic(
|
|
49155
|
+
this.emitRequestDiagnostic(timing2, "sent", "pending");
|
|
48936
49156
|
} catch (error2) {
|
|
48937
49157
|
this.clearPending(requestId);
|
|
48938
49158
|
throw error2 instanceof Error ? new NiumaError("IPC_NOT_INITIALIZED", error2.message) : new NiumaError("IPC_NOT_INITIALIZED", String(error2));
|
|
@@ -49031,10 +49251,10 @@ var init_socket_client = __esm({
|
|
|
49031
49251
|
this.pruneTimedOutRequests();
|
|
49032
49252
|
const outcome = frame.resultType === "error" ? "error" : "success";
|
|
49033
49253
|
if (!pending) {
|
|
49034
|
-
const
|
|
49035
|
-
if (
|
|
49254
|
+
const timing2 = this.timedOutRequests.get(requestId);
|
|
49255
|
+
if (timing2) {
|
|
49036
49256
|
this.timedOutRequests.delete(requestId);
|
|
49037
|
-
this.emitRequestDiagnostic(
|
|
49257
|
+
this.emitRequestDiagnostic(timing2, "late_response", outcome);
|
|
49038
49258
|
}
|
|
49039
49259
|
return;
|
|
49040
49260
|
}
|
|
@@ -59545,15 +59765,46 @@ function createHistoryHandlers(ports) {
|
|
|
59545
59765
|
if (negotiated && (!handoffScope || !scope || scope.bindingId !== handoffScope.bindingId)) {
|
|
59546
59766
|
throw new HttpApiError(200, 200004, "\u6B63\u6587\u4EA4\u63A5\u9700\u8981\u8BA4\u8BC1\u4F1A\u8BDD");
|
|
59547
59767
|
}
|
|
59768
|
+
const loadStartedAt = performance.now();
|
|
59769
|
+
const loadAttempt = params.loadTrace === false ? null : ports.threadLoadReports().begin?.({ loadId: params.loadId, threadId: threadId2, owner: scope ? `binding:${scope.bindingId.toLowerCase()}` : "local", transport: scope?.transport ?? "local", nowMs: Date.now() });
|
|
59770
|
+
const loadElapsed = () => Math.max(0, Math.min(9e5, Math.round(performance.now() - loadStartedAt)));
|
|
59771
|
+
let loadFailurePhase = "open_received";
|
|
59772
|
+
const failOpen = (error2) => {
|
|
59773
|
+
if (!options.signal?.aborted && normalizeHttpError(error2).httpStatus === 200) loadAttempt?.finish("failed", { terminal_phase: loadFailurePhase, reason: "open_rejected" });
|
|
59774
|
+
};
|
|
59548
59775
|
if (negotiated && typeof params.handoffTicket === "string") {
|
|
59549
|
-
if (options.signal?.aborted || socket.destroyed || socket.writableEnded)
|
|
59550
|
-
|
|
59551
|
-
|
|
59552
|
-
|
|
59553
|
-
|
|
59554
|
-
|
|
59555
|
-
|
|
59556
|
-
|
|
59776
|
+
if (options.signal?.aborted || socket.destroyed || socket.writableEnded) {
|
|
59777
|
+
loadAttempt?.close();
|
|
59778
|
+
return STREAMING_RESPONSE;
|
|
59779
|
+
}
|
|
59780
|
+
let consumer;
|
|
59781
|
+
try {
|
|
59782
|
+
consumer = ports.connectionHandoff().claim(
|
|
59783
|
+
handoffScope,
|
|
59784
|
+
params.handoffDescriptor,
|
|
59785
|
+
params.handoffTicket,
|
|
59786
|
+
{ emit: (frame) => {
|
|
59787
|
+
socket.write(`${JSON.stringify(successEnvelope(frame))}
|
|
59788
|
+
`);
|
|
59789
|
+
if (frame.type === "thread_view_snapshot") {
|
|
59790
|
+
loadFailurePhase = "shell_sent";
|
|
59791
|
+
loadAttempt?.markDaemon("shell_sent", loadElapsed());
|
|
59792
|
+
}
|
|
59793
|
+
const view = frame.data;
|
|
59794
|
+
if (view?.availability?.state === "ready") {
|
|
59795
|
+
loadFailurePhase = "history_sent";
|
|
59796
|
+
loadAttempt?.markDaemon("history_sent", loadElapsed());
|
|
59797
|
+
}
|
|
59798
|
+
}, onClose: () => {
|
|
59799
|
+
loadAttempt?.close();
|
|
59800
|
+
socket.end();
|
|
59801
|
+
} }
|
|
59802
|
+
);
|
|
59803
|
+
} catch (error2) {
|
|
59804
|
+
failOpen(error2);
|
|
59805
|
+
loadAttempt?.close();
|
|
59806
|
+
throw error2;
|
|
59807
|
+
}
|
|
59557
59808
|
let recoveryClosed = false;
|
|
59558
59809
|
let unregisterRecovery2 = () => {
|
|
59559
59810
|
};
|
|
@@ -59566,12 +59817,14 @@ function createHistoryHandlers(ports) {
|
|
|
59566
59817
|
}) : () => {
|
|
59567
59818
|
};
|
|
59568
59819
|
} catch (error2) {
|
|
59820
|
+
loadAttempt?.close();
|
|
59569
59821
|
consumer.close();
|
|
59570
59822
|
throw error2;
|
|
59571
59823
|
}
|
|
59572
59824
|
let unregisterArchive2 = () => {
|
|
59573
59825
|
};
|
|
59574
59826
|
const close2 = () => {
|
|
59827
|
+
loadAttempt?.close();
|
|
59575
59828
|
unregisterArchive2();
|
|
59576
59829
|
recoveryClosed = true;
|
|
59577
59830
|
unregisterRecovery2();
|
|
@@ -59598,7 +59851,6 @@ function createHistoryHandlers(ports) {
|
|
|
59598
59851
|
`);
|
|
59599
59852
|
return STREAMING_RESPONSE;
|
|
59600
59853
|
}
|
|
59601
|
-
const loadStartedAt = performance.now();
|
|
59602
59854
|
let loadTrace = null;
|
|
59603
59855
|
let loadLeaseId = null;
|
|
59604
59856
|
let unregisterLoad = () => {
|
|
@@ -59608,7 +59860,9 @@ function createHistoryHandlers(ports) {
|
|
|
59608
59860
|
const pendingLoad = [];
|
|
59609
59861
|
const loadSeen = /* @__PURE__ */ new Set();
|
|
59610
59862
|
const recordLoad = (phase, clock = "daemon", elapsed = Math.round(performance.now() - loadStartedAt), occurredAt4 = clock === "daemon" ? Date.now() : void 0) => {
|
|
59611
|
-
if (
|
|
59863
|
+
if (clock === "daemon" && ["open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent"].includes(phase)) loadFailurePhase = phase;
|
|
59864
|
+
if (params.loadTrace === false || typeof params.loadId !== "string" || elapsed < 0 || elapsed > 9e5) return;
|
|
59865
|
+
if (clock === "daemon") loadAttempt?.markDaemon(phase, elapsed, occurredAt4);
|
|
59612
59866
|
if (!loadLeaseId) {
|
|
59613
59867
|
if (pendingLoad.length < 8) pendingLoad.push({ phase, elapsed, occurredAt: occurredAt4 });
|
|
59614
59868
|
return;
|
|
@@ -59697,6 +59951,7 @@ function createHistoryHandlers(ports) {
|
|
|
59697
59951
|
readReceiptTimer = null;
|
|
59698
59952
|
}
|
|
59699
59953
|
recordLoad("stream_closed");
|
|
59954
|
+
loadAttempt?.close();
|
|
59700
59955
|
unregisterLoad();
|
|
59701
59956
|
unregisterRecovery();
|
|
59702
59957
|
closed = true;
|
|
@@ -59733,6 +59988,7 @@ function createHistoryHandlers(ports) {
|
|
|
59733
59988
|
const close = () => {
|
|
59734
59989
|
if (physicalClosed) return;
|
|
59735
59990
|
physicalClosed = true;
|
|
59991
|
+
loadAttempt?.close();
|
|
59736
59992
|
unregisterRecovery();
|
|
59737
59993
|
options.signal?.removeEventListener("abort", close);
|
|
59738
59994
|
publisher?.close();
|
|
@@ -59749,7 +60005,14 @@ function createHistoryHandlers(ports) {
|
|
|
59749
60005
|
return STREAMING_RESPONSE;
|
|
59750
60006
|
}
|
|
59751
60007
|
if (!ports.store().getThread(threadId2, { tailCount: 0 })) {
|
|
59752
|
-
|
|
60008
|
+
try {
|
|
60009
|
+
await ports.verifyThreadForOpen(threadId2);
|
|
60010
|
+
} catch (error2) {
|
|
60011
|
+
failOpen(error2);
|
|
60012
|
+
loadAttempt?.close();
|
|
60013
|
+
detachClose();
|
|
60014
|
+
throw error2;
|
|
60015
|
+
}
|
|
59753
60016
|
}
|
|
59754
60017
|
if (closed || socketIsClosed()) {
|
|
59755
60018
|
closed = true;
|
|
@@ -59798,13 +60061,15 @@ function createHistoryHandlers(ports) {
|
|
|
59798
60061
|
}
|
|
59799
60062
|
for (const sample of pendingLoad) recordLoad(sample.phase, "daemon", sample.elapsed, sample.occurredAt);
|
|
59800
60063
|
pendingLoad.length = 0;
|
|
60064
|
+
if (loadLeaseId && loadTrace) loadAttempt?.attachLease(loadLeaseId, loadTrace.traceId);
|
|
59801
60065
|
recordLoad("lease_acquired");
|
|
59802
60066
|
try {
|
|
59803
|
-
if (loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
60067
|
+
if (loadAttempt && loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
59804
60068
|
params.loadId,
|
|
59805
60069
|
threadId2,
|
|
59806
60070
|
scope ? `binding:${scope.bindingId.toLowerCase()}` : "local",
|
|
59807
|
-
(sample) => recordLoad(sample.phase, "browser", sample.elapsed_ms, sample.occurred_at_ms)
|
|
60071
|
+
(sample) => recordLoad(sample.phase, "browser", sample.elapsed_ms, sample.occurred_at_ms),
|
|
60072
|
+
loadAttempt
|
|
59808
60073
|
);
|
|
59809
60074
|
} catch {
|
|
59810
60075
|
}
|
|
@@ -59918,6 +60183,7 @@ function createHistoryHandlers(ports) {
|
|
|
59918
60183
|
ports.requestThreadAuthorityRecovery(threadId2, true);
|
|
59919
60184
|
ports.history().onHistoryLeaseStateChanged(threadId2, ports.activeThreadFollowerCoordinator()?.leaseKindsFor(threadId2) ?? []);
|
|
59920
60185
|
unsubscribeHistoryWindow = historyWindow.subscribe(() => {
|
|
60186
|
+
if (historyWindow?.initialWindowState === "failed") loadAttempt?.finish("failed", { terminal_phase: "shell_sent", reason: "history_failed" });
|
|
59921
60187
|
if (rangeClaim && historyWindow?.initialWindowState === "failed") {
|
|
59922
60188
|
socket.write(`${JSON.stringify(errorEnvelope(new NiumaError("HISTORY_SNAPSHOT_EXPIRED", "\u5386\u53F2\u6062\u590D\u8303\u56F4\u4E0D\u53EF\u7528\u6216\u5DF2\u8FC7\u671F")))}
|
|
59923
60189
|
`);
|
|
@@ -59992,6 +60258,7 @@ function createHistoryHandlers(ports) {
|
|
|
59992
60258
|
`);
|
|
59993
60259
|
}
|
|
59994
60260
|
} catch (error2) {
|
|
60261
|
+
failOpen(error2);
|
|
59995
60262
|
try {
|
|
59996
60263
|
const sites = [
|
|
59997
60264
|
["historySourceAssertion", "Object.sourceCurrent"],
|
|
@@ -60073,20 +60340,20 @@ function text10(value) {
|
|
|
60073
60340
|
return false;
|
|
60074
60341
|
}
|
|
60075
60342
|
}
|
|
60076
|
-
function
|
|
60343
|
+
function object10(value, keys3) {
|
|
60077
60344
|
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return fail16("invalid");
|
|
60078
60345
|
const own = Reflect.ownKeys(value);
|
|
60079
60346
|
if (own.length !== keys3.length || !own.every((key) => typeof key === "string" && keys3.includes(key) && "value" in Object.getOwnPropertyDescriptor(value, key))) return fail16("invalid");
|
|
60080
60347
|
return value;
|
|
60081
60348
|
}
|
|
60082
60349
|
function parseAsyncQuestionBatch(value) {
|
|
60083
|
-
const raw =
|
|
60350
|
+
const raw = object10(value, ["thread_id", "group_id", "revision", "idempotency_key", "question_ids", "answers"]);
|
|
60084
60351
|
if (!id3(raw.thread_id) || !id3(raw.group_id) || !id3(raw.idempotency_key) || !Number.isSafeInteger(raw.revision) || raw.revision < 0 || !Array.isArray(raw.question_ids) || !raw.question_ids.length || raw.question_ids.length > 256 || !Array.isArray(raw.answers) || raw.answers.length > raw.question_ids.length) return fail16("invalid");
|
|
60085
60352
|
const questionIds = Array.from(raw.question_ids);
|
|
60086
60353
|
if (!questionIds.every(id3) || new Set(questionIds).size !== questionIds.length) return fail16("invalid");
|
|
60087
60354
|
const seen = /* @__PURE__ */ new Set();
|
|
60088
60355
|
const answers = Array.from(raw.answers, (value2) => {
|
|
60089
|
-
const answer =
|
|
60356
|
+
const answer = object10(value2, ["question_id", "title", "answer"]);
|
|
60090
60357
|
if (!id3(answer.question_id) || !questionIds.includes(answer.question_id) || seen.has(answer.question_id) || !text10(answer.title) || !text10(answer.answer)) return fail16("invalid");
|
|
60091
60358
|
seen.add(answer.question_id);
|
|
60092
60359
|
return { question_id: answer.question_id, title: answer.title, answer: answer.answer };
|
|
@@ -62997,10 +63264,10 @@ var init_thread_history_window_loader = __esm({
|
|
|
62997
63264
|
sourceRevision: 0
|
|
62998
63265
|
};
|
|
62999
63266
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
63000
|
-
const
|
|
63267
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
63001
63268
|
this.assertSource(epoch);
|
|
63002
63269
|
signal.throwIfAborted();
|
|
63003
|
-
const versionKey = JSON.stringify([epoch, description.contentVersion,
|
|
63270
|
+
const versionKey = JSON.stringify([epoch, description.contentVersion, timing2]);
|
|
63004
63271
|
let cached = this.turns.get(identity6);
|
|
63005
63272
|
if (cached?.current?.version === versionKey) {
|
|
63006
63273
|
if (description.sourceRevision >= cached.sourceRevision && cached.nativeOrder !== description.nativeOrder) {
|
|
@@ -63017,7 +63284,7 @@ var init_thread_history_window_loader = __esm({
|
|
|
63017
63284
|
this.assertSource(epoch);
|
|
63018
63285
|
signal.throwIfAborted();
|
|
63019
63286
|
if (enriched.turnId !== turn.id) throw new RangeError("\u7A97\u53E3\u65F6\u95F4\u8865\u9F50 Turn \u8EAB\u4EFD\u4E0D\u5339\u914D");
|
|
63020
|
-
if (await this.timestampVersion(turn, signal) !==
|
|
63287
|
+
if (await this.timestampVersion(turn, signal) !== timing2) continue;
|
|
63021
63288
|
this.assertSource(epoch);
|
|
63022
63289
|
signal.throwIfAborted();
|
|
63023
63290
|
const freeze = (value) => {
|
|
@@ -63075,11 +63342,11 @@ var init_thread_history_window_loader = __esm({
|
|
|
63075
63342
|
const epoch = this.sourceEpoch;
|
|
63076
63343
|
this.currentProtection.addTurnIds([turn.id]);
|
|
63077
63344
|
const description = this.reader.describeTurn?.(turn) ?? { contentVersion: createHash26("sha256").update(JSON.stringify(turn)).digest("hex") };
|
|
63078
|
-
const
|
|
63345
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
63079
63346
|
this.assertSource(epoch);
|
|
63080
63347
|
signal.throwIfAborted();
|
|
63081
63348
|
const cached = this.turns.get(JSON.stringify([this.currentThreadId, turn.id]));
|
|
63082
|
-
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion,
|
|
63349
|
+
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion, timing2])) {
|
|
63083
63350
|
this.holdVersion(this.currentProtection, cached.current);
|
|
63084
63351
|
return cached.current.projection.displayItemCount;
|
|
63085
63352
|
}
|
|
@@ -64340,17 +64607,17 @@ var init_app_server_thread_view_adapter = __esm({
|
|
|
64340
64607
|
lastError: null
|
|
64341
64608
|
}).status;
|
|
64342
64609
|
const terminalStatus = failed || aborted || status2 === "completed" ? lifecycleStatus : "completed";
|
|
64343
|
-
const
|
|
64610
|
+
const timing2 = context.getTurnLifecycle?.(turnId);
|
|
64344
64611
|
return [{
|
|
64345
64612
|
type: "ThreadStatusChanged",
|
|
64346
64613
|
thread_id: context.threadId,
|
|
64347
64614
|
status: terminalStatus,
|
|
64348
64615
|
turn_id: turnId,
|
|
64349
64616
|
terminal_item_state: terminalStatus === "error" ? "failed" : "completed",
|
|
64350
|
-
...
|
|
64351
|
-
startedAt: lifecycleTime(
|
|
64352
|
-
endedAt: lifecycleTime(
|
|
64353
|
-
outcome:
|
|
64617
|
+
...timing2 ? { process_lifecycle: {
|
|
64618
|
+
startedAt: lifecycleTime(timing2.startedAt),
|
|
64619
|
+
endedAt: lifecycleTime(timing2.endedAt),
|
|
64620
|
+
outcome: timing2.outcome
|
|
64354
64621
|
} } : {},
|
|
64355
64622
|
last_error: terminalStatus === "error" ? {
|
|
64356
64623
|
code: 900001,
|
|
@@ -64621,10 +64888,10 @@ var init_thread_history_window_projection = __esm({
|
|
|
64621
64888
|
const enriched = this.options.enrichTimeline ? await this.options.enrichTimeline(sources.map((source2) => source2.timeline), startedAt) : this.timestamps.enrichTimelineFromReplay(sources.map((source2) => source2.timeline), startedAt, replay);
|
|
64622
64889
|
const timingById = new Map(sources.map((source2, index) => [source2.id, enriched[index]]));
|
|
64623
64890
|
const items = projected.items.map((item) => {
|
|
64624
|
-
const
|
|
64891
|
+
const timing2 = timingById.get(item.id);
|
|
64625
64892
|
const fact = item.process_fact;
|
|
64626
|
-
if (!
|
|
64627
|
-
const merged = mergeThreadHistoryTimelineLifecycle(
|
|
64893
|
+
if (!timing2 || !fact) return item;
|
|
64894
|
+
const merged = mergeThreadHistoryTimelineLifecycle(timing2, {
|
|
64628
64895
|
...fact.startedAt !== null ? { turnStartedAt: fact.startedAt } : {},
|
|
64629
64896
|
...fact.endedAt !== null ? { turnEndedAt: fact.endedAt } : {},
|
|
64630
64897
|
...fact.durationMs != null ? { turnDurationMs: fact.durationMs } : {},
|
|
@@ -65445,7 +65712,7 @@ function readStateDiagnostic(before, after, candidate = after.confirmed) {
|
|
|
65445
65712
|
sameCycle: candidate ? candidate.cycle === after.cycle : null
|
|
65446
65713
|
};
|
|
65447
65714
|
}
|
|
65448
|
-
function
|
|
65715
|
+
function object11(value) {
|
|
65449
65716
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
65450
65717
|
}
|
|
65451
65718
|
function field(value, present, count) {
|
|
@@ -65455,15 +65722,15 @@ function field(value, present, count) {
|
|
|
65455
65722
|
}
|
|
65456
65723
|
function unreadFrameDiagnostic(frame) {
|
|
65457
65724
|
if (frame.method !== "thread-stream-state-changed") return null;
|
|
65458
|
-
const params =
|
|
65725
|
+
const params = object11(frame.params), change = object11(params.change);
|
|
65459
65726
|
const kind = change.type === "snapshot" ? "snapshot" : change.type === "patches" ? "patch" : "invalid";
|
|
65460
|
-
const values = kind === "snapshot" ?
|
|
65727
|
+
const values = kind === "snapshot" ? object11(change.conversationState) : {};
|
|
65461
65728
|
let unread = field(values.hasUnreadTurn, Object.hasOwn(values, "hasUnreadTurn"), false);
|
|
65462
65729
|
let count = field(values.unreadMessageCount, Object.hasOwn(values, "unreadMessageCount"), true);
|
|
65463
65730
|
let countValue = values.unreadMessageCount;
|
|
65464
65731
|
if (kind === "patch") {
|
|
65465
65732
|
for (const value of Array.isArray(change.patches) ? change.patches : []) {
|
|
65466
|
-
const patch =
|
|
65733
|
+
const patch = object11(value), path55 = Array.isArray(patch.path) ? patch.path : [];
|
|
65467
65734
|
const name2 = path55.length === 1 ? path55[0] : path55.length === 2 && path55[0] === "conversationState" ? path55[1] : null;
|
|
65468
65735
|
if (name2 !== "hasUnreadTurn" && name2 !== "unreadMessageCount") continue;
|
|
65469
65736
|
const state = patch.op === "remove" ? "removed" : ["add", "replace"].includes(String(patch.op)) ? field(patch.value, Object.hasOwn(patch, "value"), name2 === "unreadMessageCount") : "invalid";
|
|
@@ -65577,10 +65844,10 @@ var init_ingress_dispatch = __esm({
|
|
|
65577
65844
|
}
|
|
65578
65845
|
ports;
|
|
65579
65846
|
/** 单帧入站与最终结果成对记录;原始字段与业务结果分开,拒绝帧同样留证。 */
|
|
65580
|
-
async handleIpcFrame(frame, ownClientId = this.ports.desktopSession().ipcValue?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.desktopSession().ipcConnectionGenerationValue,
|
|
65847
|
+
async handleIpcFrame(frame, ownClientId = this.ports.desktopSession().ipcValue?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.desktopSession().ipcConnectionGenerationValue, timing2) {
|
|
65581
65848
|
const attributes = this.ports.options().debugLogger ? unreadFrameDiagnostic(frame) : null;
|
|
65582
65849
|
const threadId2 = attributes ? extractThreadIdFromIpcFrame(frame) : null;
|
|
65583
|
-
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
65850
|
+
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2);
|
|
65584
65851
|
const before = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 })?.unread;
|
|
65585
65852
|
const diagnostic = { reason: "processed" };
|
|
65586
65853
|
const metadata = { ...attributes, sequence: this.ports.diagnostics().threadReadDiagnosticSequenceValue++, generation: receivedIpcGeneration, currentGeneration: this.ports.desktopSession().ipcConnectionGenerationValue };
|
|
@@ -65593,7 +65860,7 @@ var init_ingress_dispatch = __esm({
|
|
|
65593
65860
|
}
|
|
65594
65861
|
});
|
|
65595
65862
|
try {
|
|
65596
|
-
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
65863
|
+
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2, diagnostic);
|
|
65597
65864
|
} catch (error2) {
|
|
65598
65865
|
diagnostic.reason = "processing_failed";
|
|
65599
65866
|
throw error2;
|
|
@@ -67405,11 +67672,11 @@ var init_projection_context = __esm({
|
|
|
67405
67672
|
} : null),
|
|
67406
67673
|
enrichTimelineItemTiming: (item) => this.ports.timelinePublication().enrichTimelineItemTiming(item, timelineItems),
|
|
67407
67674
|
getTurnLifecycle: (turnId) => {
|
|
67408
|
-
const
|
|
67409
|
-
return
|
|
67410
|
-
startedAt:
|
|
67411
|
-
endedAt:
|
|
67412
|
-
outcome:
|
|
67675
|
+
const timing2 = this.ports.timelinePublication().turnTiming(threadId2, turnId);
|
|
67676
|
+
return timing2 ? {
|
|
67677
|
+
startedAt: timing2.startedAt,
|
|
67678
|
+
endedAt: timing2.endedAt ?? null,
|
|
67679
|
+
outcome: timing2.outcome ?? null
|
|
67413
67680
|
} : null;
|
|
67414
67681
|
},
|
|
67415
67682
|
resolveKnownLocalImage: (sourcePath, itemId, partIndex) => this.ports.resolveThreadViewImage(threadId2, sourcePath, () => this.ports.isCurrentAppServerAsyncFence(threadId2, fence), itemId, partIndex)
|
|
@@ -68027,7 +68294,7 @@ var init_active_thread_follower_coordinator = __esm({
|
|
|
68027
68294
|
init_errors();
|
|
68028
68295
|
init_session_history_file();
|
|
68029
68296
|
init_error_log();
|
|
68030
|
-
ACTIVE_THREAD_SCAN_INTERVAL_MS =
|
|
68297
|
+
ACTIVE_THREAD_SCAN_INTERVAL_MS = 6e4;
|
|
68031
68298
|
ACTIVE_THREAD_READ_CONCURRENCY = 4;
|
|
68032
68299
|
ACTIVE_FOLLOWER_SNAPSHOT_TIMEOUT_MS = 12e3;
|
|
68033
68300
|
ACTIVE_FOLLOWER_RETRY_DELAYS_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
@@ -75120,7 +75387,7 @@ var init_thread_state_coordination = __esm({
|
|
|
75120
75387
|
return token3;
|
|
75121
75388
|
}
|
|
75122
75389
|
/** 仅供已核验的同轮终态使用;同时收敛列表与详情,不伪造新的完成通知。 */
|
|
75123
|
-
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message,
|
|
75390
|
+
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message, timing2) {
|
|
75124
75391
|
const previous = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 });
|
|
75125
75392
|
const mutation = this.ports.catalog().storeValue.applyActivitySignal({
|
|
75126
75393
|
type: "snapshot",
|
|
@@ -75140,7 +75407,7 @@ var init_thread_state_coordination = __esm({
|
|
|
75140
75407
|
turn_id: turnId,
|
|
75141
75408
|
status: outcome === "aborted" ? "idle" : outcome === "failed" ? "error" : "completed",
|
|
75142
75409
|
terminal_item_state: outcome === "failed" ? "failed" : "completed",
|
|
75143
|
-
process_lifecycle: { startedAt:
|
|
75410
|
+
process_lifecycle: { startedAt: timing2?.startedAt ?? null, endedAt: timing2?.endedAt ?? null, outcome },
|
|
75144
75411
|
last_error: outcome === "failed" && message ? { code: 900001, message, occurred_at: occurredAt4, turn_id: turnId } : null
|
|
75145
75412
|
},
|
|
75146
75413
|
{ type: "ThreadActivityChanged", thread_id: threadId2, turn_id: turnId, activity: null },
|
|
@@ -75400,15 +75667,15 @@ var init_timeline_publication = __esm({
|
|
|
75400
75667
|
if (!item.turnId) {
|
|
75401
75668
|
return item;
|
|
75402
75669
|
}
|
|
75403
|
-
const
|
|
75404
|
-
if (!
|
|
75670
|
+
const timing2 = this.liveTurnTimings.get(this.turnTimingKey(item.threadId, item.turnId));
|
|
75671
|
+
if (!timing2) {
|
|
75405
75672
|
return item;
|
|
75406
75673
|
}
|
|
75407
75674
|
return {
|
|
75408
75675
|
...item,
|
|
75409
|
-
...item.turnStartedAt === void 0 ? { turnStartedAt:
|
|
75410
|
-
...item.turnEndedAt === void 0 &&
|
|
75411
|
-
...item.turnOutcome === void 0 &&
|
|
75676
|
+
...item.turnStartedAt === void 0 ? { turnStartedAt: timing2.startedAt } : {},
|
|
75677
|
+
...item.turnEndedAt === void 0 && timing2.endedAt !== void 0 ? { turnEndedAt: timing2.endedAt } : {},
|
|
75678
|
+
...item.turnOutcome === void 0 && timing2.outcome !== void 0 ? { turnOutcome: timing2.outcome } : {}
|
|
75412
75679
|
};
|
|
75413
75680
|
}
|
|
75414
75681
|
enrichTimelineItemTiming(item, historyItems = []) {
|
|
@@ -75428,9 +75695,9 @@ var init_timeline_publication = __esm({
|
|
|
75428
75695
|
turnTimingKey(threadId2, turnId) {
|
|
75429
75696
|
return `${threadId2}:${turnId}`;
|
|
75430
75697
|
}
|
|
75431
|
-
setLiveTurnTiming(key,
|
|
75698
|
+
setLiveTurnTiming(key, timing2) {
|
|
75432
75699
|
this.liveTurnTimings.delete(key);
|
|
75433
|
-
this.liveTurnTimings.set(key,
|
|
75700
|
+
this.liveTurnTimings.set(key, timing2);
|
|
75434
75701
|
while (this.liveTurnTimings.size > LIVE_TURN_TIMING_LIMIT) {
|
|
75435
75702
|
const oldestKey = this.liveTurnTimings.keys().next().value;
|
|
75436
75703
|
if (typeof oldestKey !== "string") break;
|
|
@@ -83912,8 +84179,7 @@ var init_native_admission = __esm({
|
|
|
83912
84179
|
else if (kind === "ordinary") this.hidden.delete(thread4.id);
|
|
83913
84180
|
const old = this.entries.get(thread4.id);
|
|
83914
84181
|
this.failures.delete(thread4.id);
|
|
83915
|
-
|
|
83916
|
-
const token3 = { threadId: thread4.id, generation: ++this.sequence, executionGeneration };
|
|
84182
|
+
const token3 = old && old.kind === kind ? old.token : { threadId: thread4.id, generation: ++this.sequence, executionGeneration };
|
|
83917
84183
|
this.entries.set(thread4.id, { token: token3, kind });
|
|
83918
84184
|
try {
|
|
83919
84185
|
if (kind !== previous) this.ports.onChange?.(thread4.id, previous, kind);
|
|
@@ -83923,7 +84189,7 @@ var init_native_admission = __esm({
|
|
|
83923
84189
|
}
|
|
83924
84190
|
const pending = this.jobs.get(thread4.id);
|
|
83925
84191
|
if (pending) {
|
|
83926
|
-
this.finishWait(pending, kind);
|
|
84192
|
+
this.finishWait(pending, kind, thread4, token3);
|
|
83927
84193
|
if (!pending.started) {
|
|
83928
84194
|
this.removeQueued(pending);
|
|
83929
84195
|
this.removeJob(pending);
|
|
@@ -83931,13 +84197,20 @@ var init_native_admission = __esm({
|
|
|
83931
84197
|
}
|
|
83932
84198
|
return token3;
|
|
83933
84199
|
}
|
|
83934
|
-
ensure(id5, executionGeneration) {
|
|
83935
|
-
|
|
84200
|
+
async ensure(id5, executionGeneration) {
|
|
84201
|
+
return (await this.query(id5, executionGeneration, false)).kind;
|
|
84202
|
+
}
|
|
84203
|
+
/** 目录缺项时请求摘要,与未知准入共用单飞、退避和物理槽。 */
|
|
84204
|
+
ensureSummary(id5, executionGeneration) {
|
|
84205
|
+
return this.query(id5, executionGeneration, true);
|
|
84206
|
+
}
|
|
84207
|
+
query(id5, executionGeneration, needSummary) {
|
|
84208
|
+
if (executionGeneration !== this.execution) return Promise.resolve({ kind: "unknown" });
|
|
83936
84209
|
const known = this.kind(id5);
|
|
83937
|
-
if (known !== "unknown") return Promise.resolve(known);
|
|
84210
|
+
if (known !== "unknown" && (!needSummary || known === "subagent")) return Promise.resolve({ kind: known });
|
|
83938
84211
|
const pending = this.jobs.get(id5);
|
|
83939
|
-
if (pending) return pending.execution === this.execution ? pending.promise : Promise.resolve("unknown");
|
|
83940
|
-
if ((this.failures.get(id5) ?? 0) > this.now() || this.queue.length >= 64) return Promise.resolve("unknown");
|
|
84212
|
+
if (pending) return pending.execution === this.execution ? pending.promise : Promise.resolve({ kind: "unknown" });
|
|
84213
|
+
if ((this.failures.get(id5) ?? 0) > this.now() || this.queue.length >= 64) return Promise.resolve({ kind: "unknown" });
|
|
83941
84214
|
let resolve5;
|
|
83942
84215
|
const promise = new Promise((done) => {
|
|
83943
84216
|
resolve5 = done;
|
|
@@ -83994,11 +84267,11 @@ var init_native_admission = __esm({
|
|
|
83994
84267
|
removeJob(job) {
|
|
83995
84268
|
if (this.jobs.get(job.id) === job) this.jobs.delete(job.id);
|
|
83996
84269
|
}
|
|
83997
|
-
finishWait(job, kind) {
|
|
84270
|
+
finishWait(job, kind, summary, token3) {
|
|
83998
84271
|
if (job.settled) return;
|
|
83999
84272
|
job.settled = true;
|
|
84000
84273
|
job.cancel();
|
|
84001
|
-
job.resolve(kind);
|
|
84274
|
+
job.resolve({ kind, ...summary ? { summary, token: token3 } : {} });
|
|
84002
84275
|
}
|
|
84003
84276
|
fail(job) {
|
|
84004
84277
|
if (job.execution === this.execution) {
|
|
@@ -84032,7 +84305,7 @@ var init_native_admission = __esm({
|
|
|
84032
84305
|
this.observe(result.thread, job.execution);
|
|
84033
84306
|
const kind = this.kind(job.id);
|
|
84034
84307
|
if (kind === "unknown") this.fail(job);
|
|
84035
|
-
this.finishWait(job, kind);
|
|
84308
|
+
this.finishWait(job, kind, result.thread, this.token(job.id));
|
|
84036
84309
|
}).catch(() => {
|
|
84037
84310
|
if (!job.settled) {
|
|
84038
84311
|
this.fail(job);
|
|
@@ -85028,19 +85301,19 @@ function withoutPersistentImageBytes(value, key = "", seen = /* @__PURE__ */ new
|
|
|
85028
85301
|
if (seen.has(value)) return "[circular]";
|
|
85029
85302
|
seen.add(value);
|
|
85030
85303
|
try {
|
|
85031
|
-
const
|
|
85032
|
-
if (
|
|
85033
|
-
return { type: "binary_omitted", byteSize:
|
|
85304
|
+
const object12 = value;
|
|
85305
|
+
if (object12.type === "Buffer" && Array.isArray(object12.data)) {
|
|
85306
|
+
return { type: "binary_omitted", byteSize: object12.data.length };
|
|
85034
85307
|
}
|
|
85035
|
-
if (
|
|
85036
|
-
const payload =
|
|
85037
|
-
const metadata = Object.fromEntries(Object.entries(
|
|
85308
|
+
if (object12.event === "app_server_stdout") {
|
|
85309
|
+
const payload = object12.rawPayload;
|
|
85310
|
+
const metadata = Object.fromEntries(Object.entries(object12).filter(([name2]) => name2 !== "rawPayload").map(([name2, entry]) => [name2, withoutPersistentImageBytes(entry, name2, seen)]));
|
|
85038
85311
|
return { ...metadata, rawPayload: { type: "stdout_fragment", bytes: typeof payload?.bytes === "number" ? payload.bytes : typeof payload?.fragment === "string" ? Buffer.byteLength(payload.fragment) : 0 } };
|
|
85039
85312
|
}
|
|
85040
85313
|
if (Array.isArray(value)) return value.map((entry) => withoutPersistentImageBytes(entry, key, seen));
|
|
85041
|
-
return Object.fromEntries(Object.entries(
|
|
85314
|
+
return Object.fromEntries(Object.entries(object12).map(([name2, entry]) => [
|
|
85042
85315
|
name2,
|
|
85043
|
-
withoutPersistentImageBytes(entry,
|
|
85316
|
+
withoutPersistentImageBytes(entry, object12.type === "image" && name2 === "data" ? "base64" : name2, seen)
|
|
85044
85317
|
]));
|
|
85045
85318
|
} finally {
|
|
85046
85319
|
seen.delete(value);
|
|
@@ -85145,6 +85418,7 @@ var init_debug_log = __esm({
|
|
|
85145
85418
|
"ipc_recovery",
|
|
85146
85419
|
"ipc_forwarding_flow",
|
|
85147
85420
|
"notification_delivery",
|
|
85421
|
+
"ipc_thread_discovery",
|
|
85148
85422
|
"startup_timing",
|
|
85149
85423
|
"thread_settings_cache",
|
|
85150
85424
|
"thread_list_cache",
|
|
@@ -85378,6 +85652,7 @@ var init_debug_log = __esm({
|
|
|
85378
85652
|
"inFlight"
|
|
85379
85653
|
],
|
|
85380
85654
|
// 启动性能仅保留固定阶段耗时和汇总计数,禁止记录路径、会话或异常原文。
|
|
85655
|
+
ipc_thread_discovery: ["durationMs"],
|
|
85381
85656
|
startup_timing: [
|
|
85382
85657
|
"durationMs",
|
|
85383
85658
|
"threadCount",
|
|
@@ -85924,6 +86199,7 @@ var init_debug_log = __esm({
|
|
|
85924
86199
|
"dropped_busy",
|
|
85925
86200
|
"deadline_expired"
|
|
85926
86201
|
],
|
|
86202
|
+
ipc_thread_discovery: ["received", "ignored", "deduplicated", "capacity", "read_completed", "rejected", "stale", "published", "failed"],
|
|
85927
86203
|
startup_timing: [
|
|
85928
86204
|
"app_server_initialized",
|
|
85929
86205
|
"thread_baseline_scanned",
|
|
@@ -86456,6 +86732,7 @@ var NiumaDaemonRuntime;
|
|
|
86456
86732
|
var init_composition = __esm({
|
|
86457
86733
|
"apps/desktop/src/daemon/runtime/composition.ts"() {
|
|
86458
86734
|
"use strict";
|
|
86735
|
+
init_ipc_thread_discovery();
|
|
86459
86736
|
init_legacy_question_operation();
|
|
86460
86737
|
init_pending_response_operation();
|
|
86461
86738
|
init_settings_update_operation();
|
|
@@ -86559,7 +86836,7 @@ var init_composition = __esm({
|
|
|
86559
86836
|
init_settings_selection();
|
|
86560
86837
|
init_thread_routing();
|
|
86561
86838
|
init_device_name();
|
|
86562
|
-
|
|
86839
|
+
init_thread_load_trace2();
|
|
86563
86840
|
init_paths2();
|
|
86564
86841
|
init_message_submission_store();
|
|
86565
86842
|
init_client2();
|
|
@@ -87189,6 +87466,7 @@ var init_composition = __esm({
|
|
|
87189
87466
|
}
|
|
87190
87467
|
desktopTrackers = new RuntimeDesktopIngressTrackers();
|
|
87191
87468
|
desktopIngress = new RuntimeDesktopIngress({
|
|
87469
|
+
discoverThread: (id5) => this.ipcThreadDiscovery.discover(id5),
|
|
87192
87470
|
nativeAdmission: () => this.nativeAdmission,
|
|
87193
87471
|
ensureNativeAdmission: (id5) => this.ensureNativeAdmission(id5),
|
|
87194
87472
|
requestReadFileRefresh: () => this.followerCoordination.desktopReadStateFileValue?.requestRefresh(),
|
|
@@ -87724,6 +88002,33 @@ var init_composition = __esm({
|
|
|
87724
88002
|
}
|
|
87725
88003
|
}
|
|
87726
88004
|
});
|
|
88005
|
+
ipcThreadDiscovery = new RuntimeIpcThreadDiscovery({
|
|
88006
|
+
eligible: (id5) => !this.lifecycle.stoppingValue && this.desktopSession.desktopIpcStateValue === "ready" && this.executionHost.appServerStateValue === "ready" && !this.archiveState.isConfirmed(id5) && !this.catalog.hasActiveTombstone(id5) && this.nativeAdmission.isVisible(id5) && !this.catalog.storeValue.getPublicThreadSummary(id5),
|
|
88007
|
+
capture: () => {
|
|
88008
|
+
const runtime = this.lifecycle.runtimeGenerationValue, ipc = this.desktopSession.ipcConnectionGenerationValue;
|
|
88009
|
+
const client = this.executionHost.appServerValue, generation = this.appServerLoads.connectionGeneration;
|
|
88010
|
+
return () => !this.lifecycle.stoppingValue && runtime === this.lifecycle.runtimeGenerationValue && ipc === this.desktopSession.ipcConnectionGenerationValue && client === this.executionHost.appServerValue && generation === this.appServerLoads.connectionGeneration;
|
|
88011
|
+
},
|
|
88012
|
+
read: (id5) => this.nativeAdmission.ensureSummary(id5, this.appServerLoads.connectionGeneration),
|
|
88013
|
+
current: (token3) => this.nativeAdmission.isCurrent(token3),
|
|
88014
|
+
enqueue: (run) => this.eventSequencer.enqueue(async () => {
|
|
88015
|
+
run();
|
|
88016
|
+
}),
|
|
88017
|
+
commit: (thread4) => {
|
|
88018
|
+
this.directoryAuthority.begin(false);
|
|
88019
|
+
this.catalog.upsertAuthoritativeThreadSummary(thread4);
|
|
88020
|
+
this.emitEvent(this.publication.threadUpdatedEvent(thread4.id, "app_server", nowSeconds()));
|
|
88021
|
+
this.activityPublication.publishGlobalStatusIfChanged();
|
|
88022
|
+
},
|
|
88023
|
+
diagnostic: (threadId2, phase, elapsedMs) => this.diagnostics.writeDebug({
|
|
88024
|
+
component: "daemon",
|
|
88025
|
+
channel: "ipc",
|
|
88026
|
+
event: "ipc_thread_discovery",
|
|
88027
|
+
threadId: threadId2,
|
|
88028
|
+
phase,
|
|
88029
|
+
attributes: { durationMs: elapsedMs }
|
|
88030
|
+
})
|
|
88031
|
+
});
|
|
87727
88032
|
async ensureNativeAdmission(id5) {
|
|
87728
88033
|
return !this.lifecycle.stoppingValue && !this.archiveState.isConfirmed(id5) && await this.nativeAdmission.ensure(id5, this.appServerLoads.connectionGeneration) === "ordinary";
|
|
87729
88034
|
}
|
|
@@ -88410,7 +88715,7 @@ var init_composition = __esm({
|
|
|
88410
88715
|
isBlocked: isStartBlockedByLifecycle
|
|
88411
88716
|
});
|
|
88412
88717
|
// 所有 runtime 与 coordinator 共用同一审计实例,确保 thread-scope 事件可关联当前 trace。
|
|
88413
|
-
threadLoadReports = new ThreadLoadReports();
|
|
88718
|
+
threadLoadReports = new ThreadLoadReports(Date.now, () => this.followerOpenTraceAudit);
|
|
88414
88719
|
followerOpenTraceAudit;
|
|
88415
88720
|
// 异步选择只等待目录;端口在实际调用时读取,不能提前冻结Owner或缓存。
|
|
88416
88721
|
settingsSelection = new RuntimeSettingsSelection({
|
|
@@ -88758,6 +89063,41 @@ var init_runtime2 = __esm({
|
|
|
88758
89063
|
}
|
|
88759
89064
|
});
|
|
88760
89065
|
|
|
89066
|
+
// apps/desktop/src/daemon/thread-load-record.ts
|
|
89067
|
+
import { z as z17 } from "zod";
|
|
89068
|
+
var LoadRecordSchema;
|
|
89069
|
+
var init_thread_load_record = __esm({
|
|
89070
|
+
"apps/desktop/src/daemon/thread-load-record.ts"() {
|
|
89071
|
+
"use strict";
|
|
89072
|
+
init_src2();
|
|
89073
|
+
LoadRecordSchema = z17.object({
|
|
89074
|
+
schema_version: z17.literal(3),
|
|
89075
|
+
record_type: z17.enum(["load_start", "load_sample", "load_terminal", "load_close"]),
|
|
89076
|
+
load_id: z17.string().uuid(),
|
|
89077
|
+
thread_id: z17.string().min(1).max(256),
|
|
89078
|
+
sequence: z17.number().int().nonnegative(),
|
|
89079
|
+
occurred_at_ms: z17.number().int().nonnegative().max(864e13),
|
|
89080
|
+
clock: z17.enum(["client", "daemon"]),
|
|
89081
|
+
phase: z17.enum([...CLIENT_LOAD_PHASES, "open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent", "stream_closed", "failed", "cancelled", "superseded", "closed", "expired"]),
|
|
89082
|
+
elapsed_ms: z17.number().int().min(0).max(9e5),
|
|
89083
|
+
event_at_ms: z17.number().int().min(1).max(864e13).optional(),
|
|
89084
|
+
source_transport: z17.enum(["local", "direct", "relay"]).optional(),
|
|
89085
|
+
client_class: z17.enum(["web", "ios", "other"]).optional(),
|
|
89086
|
+
title: z17.string().max(256).optional(),
|
|
89087
|
+
lease_id: z17.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u).optional(),
|
|
89088
|
+
trace_id: z17.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u).optional(),
|
|
89089
|
+
terminal_phase: z17.enum(["request_started", "snapshot_received", "history_ready", "open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent"]).optional(),
|
|
89090
|
+
reason: z17.enum(["open_rejected", "history_failed", "left_view", "user_cancelled", "stream_replaced"]).optional()
|
|
89091
|
+
}).strict().superRefine((v, ctx) => {
|
|
89092
|
+
const fail18 = () => ctx.addIssue({ code: "custom", message: "invalid_load_record" });
|
|
89093
|
+
if (v.record_type === "load_start" && (v.phase !== "open_received" || v.clock !== "daemon" || !v.source_transport)) fail18();
|
|
89094
|
+
if (v.record_type === "load_terminal" && !["failed", "cancelled", "superseded", "expired"].includes(v.phase)) fail18();
|
|
89095
|
+
if (v.record_type === "load_close" && (v.phase !== "closed" || v.clock !== "daemon")) fail18();
|
|
89096
|
+
if (v.record_type === "load_sample" && (v.clock === "client" ? !CLIENT_LOAD_PHASES.includes(v.phase) : !["open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent", "stream_closed"].includes(v.phase))) fail18();
|
|
89097
|
+
});
|
|
89098
|
+
}
|
|
89099
|
+
});
|
|
89100
|
+
|
|
88761
89101
|
// apps/desktop/src/daemon/follower-open-trace.ts
|
|
88762
89102
|
import { randomUUID as randomUUID52 } from "node:crypto";
|
|
88763
89103
|
import path52 from "node:path";
|
|
@@ -88782,6 +89122,9 @@ function isOptionalTraceTitle(value) {
|
|
|
88782
89122
|
function hasOnlyKeys2(value, allowed) {
|
|
88783
89123
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.includes(key));
|
|
88784
89124
|
}
|
|
89125
|
+
function isRecent(value, nowMs) {
|
|
89126
|
+
return value <= nowMs && nowMs - value <= DAEMON_LOG_RETENTION_MS;
|
|
89127
|
+
}
|
|
88785
89128
|
function dateFileName2(timestampMs) {
|
|
88786
89129
|
return `${new Date(timestampMs).toISOString().slice(0, 10)}.ndjson`;
|
|
88787
89130
|
}
|
|
@@ -88888,6 +89231,10 @@ function parseRecord2(line) {
|
|
|
88888
89231
|
}
|
|
88889
89232
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
88890
89233
|
const record25 = value;
|
|
89234
|
+
if (record25.schema_version === 3) {
|
|
89235
|
+
const parsed = LoadRecordSchema.safeParse(record25);
|
|
89236
|
+
return parsed.success ? parsed.data : null;
|
|
89237
|
+
}
|
|
88891
89238
|
if (record25.schema_version === 1) return parseV1Record(record25);
|
|
88892
89239
|
if (record25.schema_version === 2) return parseV2Record(record25);
|
|
88893
89240
|
return null;
|
|
@@ -88923,6 +89270,46 @@ function readPrivateTraceFile(file, remainingBytes, storage) {
|
|
|
88923
89270
|
return { bytesRead: error2 instanceof PrivateLogFileError ? error2.bytesRead : 0, incomplete: true };
|
|
88924
89271
|
}
|
|
88925
89272
|
}
|
|
89273
|
+
function readRecords(runtimeDir, nowMs, storage) {
|
|
89274
|
+
if (!Number.isFinite(nowMs)) return { records: [], incomplete: true };
|
|
89275
|
+
const candidates = listPrivateTraceFiles(runtimeDir, storage);
|
|
89276
|
+
const records = [];
|
|
89277
|
+
let incomplete = candidates.incomplete;
|
|
89278
|
+
let totalBytes = 0;
|
|
89279
|
+
let processedLines = 0;
|
|
89280
|
+
for (const filePath of candidates.files) {
|
|
89281
|
+
if (totalBytes >= MAX_TOTAL_BYTES2) {
|
|
89282
|
+
incomplete = true;
|
|
89283
|
+
break;
|
|
89284
|
+
}
|
|
89285
|
+
const file = readPrivateTraceFile(filePath, MAX_TOTAL_BYTES2 - totalBytes, storage);
|
|
89286
|
+
totalBytes += file.bytesRead;
|
|
89287
|
+
if (file.incomplete) incomplete = true;
|
|
89288
|
+
if (file.content === void 0) continue;
|
|
89289
|
+
let end = file.content.endsWith("\n") ? file.content.length - 1 : file.content.length;
|
|
89290
|
+
while (end > 0 && processedLines < MAX_PROCESSED_LINES2) {
|
|
89291
|
+
const newline = file.content.lastIndexOf("\n", end - 1);
|
|
89292
|
+
const start = newline + 1;
|
|
89293
|
+
const length = end - start;
|
|
89294
|
+
processedLines += 1;
|
|
89295
|
+
if (length > 0 && length <= MAX_LINE_BYTES2) {
|
|
89296
|
+
const line = file.content.slice(start, end);
|
|
89297
|
+
if (Buffer.byteLength(line, "utf8") <= MAX_LINE_BYTES2) {
|
|
89298
|
+
const record25 = parseRecord2(line);
|
|
89299
|
+
if (record25 && timestampOf(record25) <= nowMs) records.push(record25);
|
|
89300
|
+
else incomplete = true;
|
|
89301
|
+
} else incomplete = true;
|
|
89302
|
+
} else if (length > 0) incomplete = true;
|
|
89303
|
+
end = Math.max(0, newline);
|
|
89304
|
+
}
|
|
89305
|
+
if (totalBytes >= MAX_TOTAL_BYTES2 || processedLines >= MAX_PROCESSED_LINES2) {
|
|
89306
|
+
if (end > 0 || filePath !== candidates.files.at(-1)) incomplete = true;
|
|
89307
|
+
break;
|
|
89308
|
+
}
|
|
89309
|
+
}
|
|
89310
|
+
records.reverse();
|
|
89311
|
+
return { records, incomplete: incomplete || hasIncompleteSubscriptionHistory(records, nowMs) };
|
|
89312
|
+
}
|
|
88926
89313
|
function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
88927
89314
|
let maximum = 0;
|
|
88928
89315
|
let totalBytes = 0;
|
|
@@ -88941,14 +89328,65 @@ function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
|
88941
89328
|
}
|
|
88942
89329
|
return maximum;
|
|
88943
89330
|
}
|
|
89331
|
+
function subscriptionIdentity(record25) {
|
|
89332
|
+
return `${record25.trace_id}\0${record25.thread_id}\0${record25.lease_epoch}`;
|
|
89333
|
+
}
|
|
89334
|
+
function occursAfterStart(record25, trace) {
|
|
89335
|
+
return record25.occurred_at_ms > trace.opened_at_ms || record25.occurred_at_ms === trace.opened_at_ms && record25.sequence > trace.sequence;
|
|
89336
|
+
}
|
|
89337
|
+
function occursBeforeClose(record25, close) {
|
|
89338
|
+
return record25.occurred_at_ms < close.occurred_at_ms || record25.occurred_at_ms === close.occurred_at_ms && record25.sequence < close.sequence;
|
|
89339
|
+
}
|
|
89340
|
+
function hasIncompleteSubscriptionHistory(records, nowMs) {
|
|
89341
|
+
const starts = /* @__PURE__ */ new Map();
|
|
89342
|
+
const eventsByIdentity = /* @__PURE__ */ new Map();
|
|
89343
|
+
const closesByIdentity = /* @__PURE__ */ new Map();
|
|
89344
|
+
for (const record25 of records) {
|
|
89345
|
+
if (record25.record_type === "subscription_start") {
|
|
89346
|
+
const identity6 = subscriptionIdentity(record25);
|
|
89347
|
+
if (starts.has(identity6)) return true;
|
|
89348
|
+
starts.set(identity6, record25);
|
|
89349
|
+
continue;
|
|
89350
|
+
}
|
|
89351
|
+
if (record25.record_type === "lease_event" || record25.record_type === "subscription_event") {
|
|
89352
|
+
const identity6 = subscriptionIdentity(record25);
|
|
89353
|
+
const events = eventsByIdentity.get(identity6) ?? [];
|
|
89354
|
+
events.push(record25);
|
|
89355
|
+
eventsByIdentity.set(identity6, events);
|
|
89356
|
+
continue;
|
|
89357
|
+
}
|
|
89358
|
+
if (record25.record_type === "subscription_close") {
|
|
89359
|
+
const identity6 = subscriptionIdentity(record25);
|
|
89360
|
+
const closes = closesByIdentity.get(identity6) ?? [];
|
|
89361
|
+
closes.push(record25);
|
|
89362
|
+
closesByIdentity.set(identity6, closes);
|
|
89363
|
+
}
|
|
89364
|
+
}
|
|
89365
|
+
for (const [identity6, events] of eventsByIdentity) {
|
|
89366
|
+
const start = starts.get(identity6);
|
|
89367
|
+
if (!start || events.some((event) => !occursAfterStart(event, start))) return true;
|
|
89368
|
+
}
|
|
89369
|
+
for (const start of starts.values()) {
|
|
89370
|
+
const identity6 = subscriptionIdentity(start);
|
|
89371
|
+
const closes = closesByIdentity.get(identity6) ?? [];
|
|
89372
|
+
if (closes.some((close2) => !occursAfterStart(close2, start))) return true;
|
|
89373
|
+
if (closes.length > 1) return true;
|
|
89374
|
+
const close = closes[0];
|
|
89375
|
+
if (close && (eventsByIdentity.get(identity6) ?? []).some((event) => !occursBeforeClose(event, close))) return true;
|
|
89376
|
+
if (!close && !isRecent(start.opened_at_ms, nowMs)) return true;
|
|
89377
|
+
}
|
|
89378
|
+
if ([...closesByIdentity.keys()].some((identity6) => !starts.has(identity6))) return true;
|
|
89379
|
+
return false;
|
|
89380
|
+
}
|
|
88944
89381
|
function createFollowerOpenTraceAudit(input) {
|
|
88945
89382
|
return new FollowerOpenTraceAuditWriter(input.runtimeDir ?? daemonRuntimeDir(), input.nowMs ?? Date.now, input.files ?? privateAuditFiles);
|
|
88946
89383
|
}
|
|
88947
|
-
var TRACE_DIRECTORY_NAME, MAX_FILE_BYTES2, MAX_TOTAL_BYTES2, MAX_LINE_BYTES2, MAX_DIRECTORY_ENTRIES3, SUBSCRIPTION_TRACE_SAFE_ID, FOLLOWER_OPEN_TRACE_TITLE_MAX_LENGTH, TRANSPORTS, CLIENT_CLASSES, PURPOSES, STAGES, OUTCOMES, SUBSCRIPTION_LEASE_ACTIONS, SUBSCRIPTION_LEASE_SOURCES, SUBSCRIPTION_LEASE_TRANSITIONS, SUBSCRIPTION_CLOSE_OUTCOMES, SUBSCRIPTION_SOURCE_BY_LEASE_KIND, LEASE_KINDS, FINAL_OUTCOMES, THREAD_SCOPE_STAGES, TRACE_SCOPE_STAGES, DURATION_STAGES, PURPOSE_STAGES, LEASE_KIND_STAGES, OUTCOMES_BY_STAGE, runtimeWriteFailures, persistedSequenceFloors, FollowerOpenTraceAuditWriter;
|
|
89384
|
+
var TRACE_DIRECTORY_NAME, MAX_FILE_BYTES2, MAX_TOTAL_BYTES2, MAX_LINE_BYTES2, MAX_DIRECTORY_ENTRIES3, MAX_PROCESSED_LINES2, SUBSCRIPTION_TRACE_SAFE_ID, FOLLOWER_OPEN_TRACE_TITLE_MAX_LENGTH, TRANSPORTS, CLIENT_CLASSES, PURPOSES, STAGES, OUTCOMES, SUBSCRIPTION_LEASE_ACTIONS, SUBSCRIPTION_LEASE_SOURCES, SUBSCRIPTION_LEASE_TRANSITIONS, SUBSCRIPTION_CLOSE_OUTCOMES, SUBSCRIPTION_SOURCE_BY_LEASE_KIND, LEASE_KINDS, FINAL_OUTCOMES, THREAD_SCOPE_STAGES, TRACE_SCOPE_STAGES, DURATION_STAGES, PURPOSE_STAGES, LEASE_KIND_STAGES, OUTCOMES_BY_STAGE, runtimeWriteFailures, persistedSequenceFloors, FollowerOpenTraceAuditWriter;
|
|
88948
89385
|
var init_follower_open_trace = __esm({
|
|
88949
89386
|
"apps/desktop/src/daemon/follower-open-trace.ts"() {
|
|
88950
89387
|
"use strict";
|
|
88951
|
-
|
|
89388
|
+
init_thread_load_record();
|
|
89389
|
+
init_thread_load_trace2();
|
|
88952
89390
|
init_private_log_files();
|
|
88953
89391
|
init_log_retention();
|
|
88954
89392
|
init_paths();
|
|
@@ -88957,6 +89395,7 @@ var init_follower_open_trace = __esm({
|
|
|
88957
89395
|
MAX_TOTAL_BYTES2 = 20 * 1024 * 1024;
|
|
88958
89396
|
MAX_LINE_BYTES2 = 64 * 1024;
|
|
88959
89397
|
MAX_DIRECTORY_ENTRIES3 = 256;
|
|
89398
|
+
MAX_PROCESSED_LINES2 = 1e4;
|
|
88960
89399
|
SUBSCRIPTION_TRACE_SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
88961
89400
|
FOLLOWER_OPEN_TRACE_TITLE_MAX_LENGTH = 256;
|
|
88962
89401
|
TRANSPORTS = /* @__PURE__ */ new Set(["local", "direct", "relay"]);
|
|
@@ -89110,6 +89549,30 @@ var init_follower_open_trace = __esm({
|
|
|
89110
89549
|
nowMs;
|
|
89111
89550
|
files;
|
|
89112
89551
|
sequence;
|
|
89552
|
+
loadEpoch = 0;
|
|
89553
|
+
loadIds;
|
|
89554
|
+
reserveLoadId(id5) {
|
|
89555
|
+
if (!this.loadIds) {
|
|
89556
|
+
try {
|
|
89557
|
+
this.ensureTraceDirectory(path52.join(this.runtimeDir, TRACE_DIRECTORY_NAME));
|
|
89558
|
+
} catch {
|
|
89559
|
+
return false;
|
|
89560
|
+
}
|
|
89561
|
+
const read = readRecords(this.runtimeDir, this.nowMs(), this.files);
|
|
89562
|
+
if (read.incomplete) return false;
|
|
89563
|
+
this.loadIds = new Set(read.records.filter((r) => r.schema_version === 3).map((r) => r.load_id));
|
|
89564
|
+
}
|
|
89565
|
+
if (this.loadIds.size >= 1e4 || this.loadIds.has(id5)) return false;
|
|
89566
|
+
this.loadIds.add(id5);
|
|
89567
|
+
return true;
|
|
89568
|
+
}
|
|
89569
|
+
loadGeneration() {
|
|
89570
|
+
return this.loadEpoch;
|
|
89571
|
+
}
|
|
89572
|
+
recordLoad(input) {
|
|
89573
|
+
const parsed = LoadRecordSchema.safeParse({ ...input, schema_version: 3, sequence: this.nextSequence() });
|
|
89574
|
+
if (parsed.success) this.write(parsed.data);
|
|
89575
|
+
}
|
|
89113
89576
|
traceDirectoryInitialized = false;
|
|
89114
89577
|
/** 只缓存当前追加文件;日期切换或清空后重新发现已有分片。 */
|
|
89115
89578
|
appendFilePath;
|
|
@@ -89243,6 +89706,7 @@ var init_follower_open_trace = __esm({
|
|
|
89243
89706
|
for (const entry of matching) this.files.remove(entry.file);
|
|
89244
89707
|
}
|
|
89245
89708
|
this.appendFilePath = void 0;
|
|
89709
|
+
this.loadEpoch += 1;
|
|
89246
89710
|
this.activeTraces.clear();
|
|
89247
89711
|
this.activeSubscriptionTraces.clear();
|
|
89248
89712
|
this.activeSubscriptionTraceHandles.clear();
|
|
@@ -89484,21 +89948,21 @@ var init_local_gateway_supervisor = __esm({
|
|
|
89484
89948
|
|
|
89485
89949
|
// apps/desktop/src/daemon/async-input-notification-store.ts
|
|
89486
89950
|
import { createHash as createHash41 } from "node:crypto";
|
|
89487
|
-
import { z as
|
|
89951
|
+
import { z as z18 } from "zod";
|
|
89488
89952
|
var ASYNC_INPUT_NOTIFICATION_MAX_BYTES, identityText, entrySchema2, documentSchema2, AsyncInputNotificationStore;
|
|
89489
89953
|
var init_async_input_notification_store = __esm({
|
|
89490
89954
|
"apps/desktop/src/daemon/async-input-notification-store.ts"() {
|
|
89491
89955
|
"use strict";
|
|
89492
89956
|
init_src2();
|
|
89493
89957
|
ASYNC_INPUT_NOTIFICATION_MAX_BYTES = 2 * 1024 * 1024;
|
|
89494
|
-
identityText =
|
|
89495
|
-
entrySchema2 =
|
|
89496
|
-
key:
|
|
89958
|
+
identityText = z18.string().min(1).max(8e3);
|
|
89959
|
+
entrySchema2 = z18.object({
|
|
89960
|
+
key: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
89497
89961
|
threadId: identityText,
|
|
89498
89962
|
turnId: identityText,
|
|
89499
|
-
stage:
|
|
89963
|
+
stage: z18.enum(["admitted", "sent"])
|
|
89500
89964
|
}).strict();
|
|
89501
|
-
documentSchema2 =
|
|
89965
|
+
documentSchema2 = z18.object({ version: z18.literal(1), entries: z18.array(entrySchema2).max(4096) }).strict();
|
|
89502
89966
|
AsyncInputNotificationStore = class _AsyncInputNotificationStore {
|
|
89503
89967
|
constructor(journal, document) {
|
|
89504
89968
|
this.journal = journal;
|