niuma-codex 0.0.1-beta.27 → 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/assets/pairing-web/settings.js +14 -6
- package/dist/cli.js +1950 -1422
- package/dist/managed-tauri.js +600 -130
- package/dist/managed.js +570 -124
- 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) {
|
|
@@ -30086,6 +30185,11 @@ var init_types = __esm({
|
|
|
30086
30185
|
});
|
|
30087
30186
|
|
|
30088
30187
|
// apps/desktop/src/pairing-web/settings.ts
|
|
30188
|
+
function dispatchSettingsVersion(request2) {
|
|
30189
|
+
if (request2.url !== "/api/v1/settings/version" || request2.method !== "GET") throw new HttpApiError(404, 900005, "\u63A5\u53E3\u4E0D\u5B58\u5728");
|
|
30190
|
+
if (request2.headers["transfer-encoding"] || Number(request2.headers["content-length"] ?? 0) > 0) throw new HttpApiError(400, 100004, "\u67E5\u8BE2\u4E0D\u80FD\u643A\u5E26\u8BF7\u6C42\u4F53");
|
|
30191
|
+
return { daemon_version: desktopPresenceVersion() };
|
|
30192
|
+
}
|
|
30089
30193
|
function projection(s) {
|
|
30090
30194
|
return {
|
|
30091
30195
|
supported: s.supported,
|
|
@@ -30150,6 +30254,7 @@ var init_settings = __esm({
|
|
|
30150
30254
|
"use strict";
|
|
30151
30255
|
init_response();
|
|
30152
30256
|
init_types();
|
|
30257
|
+
init_release_version();
|
|
30153
30258
|
}
|
|
30154
30259
|
});
|
|
30155
30260
|
|
|
@@ -31088,8 +31193,7 @@ function invalidPushServerOrigin() {
|
|
|
31088
31193
|
function resolvePushServerOrigin(environment) {
|
|
31089
31194
|
const value = environment.NIUMA_PUSH_SERVER_ORIGIN;
|
|
31090
31195
|
if (value === void 0 || isBlankConfigValue(value)) {
|
|
31091
|
-
|
|
31092
|
-
return release2 ? DEFAULT_PUSH_PUBLIC_URL : resolveLocalServerOrigin(environment);
|
|
31196
|
+
return DEFAULT_PUSH_PUBLIC_URL;
|
|
31093
31197
|
}
|
|
31094
31198
|
if (URL_CONTROL_OR_SPACE_PATTERN.test(value)) {
|
|
31095
31199
|
throw invalidPushServerOrigin();
|
|
@@ -31191,10 +31295,11 @@ var init_server_client = __esm({
|
|
|
31191
31295
|
|
|
31192
31296
|
// apps/desktop/src/daemon/thread-load-trace.ts
|
|
31193
31297
|
import { z as z8 } from "zod";
|
|
31194
|
-
var ClientLoadPhaseSchema, occurredAtSchema, LoadSampleSchema, ThreadLoadReportSchema, LoadingTraceSchema, ThreadLoadReports;
|
|
31195
|
-
var
|
|
31298
|
+
var ClientLoadPhaseSchema, occurredAtSchema, LoadSampleSchema, ThreadLoadReportSchema, ThreadLoadReportV2Schema, LoadingTraceSchema, ThreadLoadReports;
|
|
31299
|
+
var init_thread_load_trace2 = __esm({
|
|
31196
31300
|
"apps/desktop/src/daemon/thread-load-trace.ts"() {
|
|
31197
31301
|
"use strict";
|
|
31302
|
+
init_src2();
|
|
31198
31303
|
ClientLoadPhaseSchema = z8.enum(["selected", "restored", "request_started", "snapshot_received", "history_ready", "content_presented"]);
|
|
31199
31304
|
occurredAtSchema = z8.number().int().min(1).max(864e13).optional();
|
|
31200
31305
|
LoadSampleSchema = z8.object({
|
|
@@ -31207,6 +31312,20 @@ var init_thread_load_trace = __esm({
|
|
|
31207
31312
|
load_id: z8.string().uuid(),
|
|
31208
31313
|
samples: z8.array(LoadSampleSchema).min(1).max(6)
|
|
31209
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
|
+
});
|
|
31210
31329
|
LoadingTraceSchema = z8.object({
|
|
31211
31330
|
load_id: z8.string().uuid(),
|
|
31212
31331
|
lease_id: z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u),
|
|
@@ -31216,27 +31335,128 @@ var init_thread_load_trace = __esm({
|
|
|
31216
31335
|
occurred_at_ms: occurredAtSchema
|
|
31217
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));
|
|
31218
31337
|
ThreadLoadReports = class {
|
|
31219
|
-
constructor(now = Date.now) {
|
|
31338
|
+
constructor(now = Date.now, audit = () => void 0) {
|
|
31220
31339
|
this.now = now;
|
|
31340
|
+
this.audit = audit;
|
|
31221
31341
|
}
|
|
31222
31342
|
now;
|
|
31343
|
+
audit;
|
|
31223
31344
|
entries = /* @__PURE__ */ new Map();
|
|
31224
|
-
|
|
31345
|
+
used = /* @__PURE__ */ new Set();
|
|
31346
|
+
clear() {
|
|
31347
|
+
this.entries.clear();
|
|
31348
|
+
}
|
|
31349
|
+
begin(input) {
|
|
31225
31350
|
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
31226
|
-
if (!z8.string().uuid().safeParse(loadId).success || this.entries.size >= 256 || this.
|
|
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);
|
|
31227
31374
|
};
|
|
31228
|
-
const
|
|
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) {
|
|
31423
|
+
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
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 () => {
|
|
31431
|
+
};
|
|
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 };
|
|
31229
31440
|
this.entries.set(loadId, entry);
|
|
31230
31441
|
return () => {
|
|
31231
31442
|
if (this.entries.get(loadId) === entry) this.entries.delete(loadId);
|
|
31232
31443
|
};
|
|
31233
31444
|
}
|
|
31234
31445
|
report(input, owner2) {
|
|
31235
|
-
|
|
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
|
+
}
|
|
31236
31452
|
if (!parsed.success) return { accepted: false };
|
|
31237
31453
|
const { load_id, thread_id, samples } = parsed.data;
|
|
31238
31454
|
const entry = this.entries.get(load_id);
|
|
31239
|
-
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
|
+
}
|
|
31240
31460
|
for (const sample of samples) if (!entry.seen.has(sample.phase)) {
|
|
31241
31461
|
entry.seen.add(sample.phase);
|
|
31242
31462
|
try {
|
|
@@ -31256,7 +31476,7 @@ var nonEmptyString5, booleanQuery, authorizationMode, canonicalBase64, boundedIn
|
|
|
31256
31476
|
var init_contracts2 = __esm({
|
|
31257
31477
|
"apps/desktop/src/http/contracts.ts"() {
|
|
31258
31478
|
"use strict";
|
|
31259
|
-
|
|
31479
|
+
init_thread_load_trace2();
|
|
31260
31480
|
init_src2();
|
|
31261
31481
|
nonEmptyString5 = z9.string().trim().min(1);
|
|
31262
31482
|
booleanQuery = z9.enum(["true", "false"]).transform((value) => value === "true");
|
|
@@ -31471,6 +31691,8 @@ var init_contracts2 = __esm({
|
|
|
31471
31691
|
range_resume_version: z9.literal("1").transform(() => 1).optional(),
|
|
31472
31692
|
range_resume_token: z9.string().regex(/^[A-Za-z0-9_-]{43}$/).optional(),
|
|
31473
31693
|
load_id: z9.string().uuid().optional(),
|
|
31694
|
+
// 恢复关联仍保留,只有首屏采样可显式关闭。
|
|
31695
|
+
load_trace: z9.literal("false").transform(() => false).optional(),
|
|
31474
31696
|
include_execution: z9.literal("true").transform(() => true).optional(),
|
|
31475
31697
|
include_message_times: z9.literal("true").transform(() => true).optional(),
|
|
31476
31698
|
include_async_questions: z9.literal("true").transform(() => true).optional(),
|
|
@@ -32516,6 +32738,7 @@ function createThreadOpenSseProjection(rawQuery, options = {}) {
|
|
|
32516
32738
|
...query2.range_resume_version ? { rangeResumeVersion: 1 } : {},
|
|
32517
32739
|
...query2.range_resume_token ? { rangeResumeToken: query2.range_resume_token } : {},
|
|
32518
32740
|
...query2.load_id ? { loadId: query2.load_id } : {},
|
|
32741
|
+
...query2.load_trace === false ? { loadTrace: false } : {},
|
|
32519
32742
|
viewVersion: THREAD_VIEW_VERSION,
|
|
32520
32743
|
...query2.include_async_questions ? { includeAsyncQuestions: true } : {},
|
|
32521
32744
|
...query2.include_read_receipts ? { includeReadReceipts: true } : {},
|
|
@@ -33550,7 +33773,7 @@ async function dispatchRestRoute(request2, dependencies) {
|
|
|
33550
33773
|
}
|
|
33551
33774
|
}
|
|
33552
33775
|
if (route === "POST /api/v1/thread/load/report") {
|
|
33553
|
-
const body = ThreadLoadReportSchema.parse(request2.body);
|
|
33776
|
+
const body = request2.body?.version === 2 ? ThreadLoadReportV2Schema.parse(request2.body) : ThreadLoadReportSchema.parse(request2.body);
|
|
33554
33777
|
const result = await daemonClient.request("thread/load/report", body, {
|
|
33555
33778
|
...daemonRequestOptions(5e3, request2.signal),
|
|
33556
33779
|
...request2.authenticatedMessageSubmissionScope !== void 0 ? { authenticatedMessageSubmissionScope: request2.authenticatedMessageSubmissionScope } : {}
|
|
@@ -44123,7 +44346,7 @@ var init_server3 = __esm({
|
|
|
44123
44346
|
const api = raw.startsWith("/api/");
|
|
44124
44347
|
authorizePairingRequest(request2, request2.socket.localPort, api);
|
|
44125
44348
|
if (api) {
|
|
44126
|
-
sendJson(response, 200, successResponse(await (raw.startsWith("/api/v1/settings/") && this.settings ? dispatchAutostartSettings(request2, this.settings) : dispatchPairingRoute(request2, this.service))));
|
|
44349
|
+
sendJson(response, 200, successResponse(await (raw === "/api/v1/settings/version" ? dispatchSettingsVersion(request2) : raw.startsWith("/api/v1/settings/") && this.settings ? dispatchAutostartSettings(request2, this.settings) : dispatchPairingRoute(request2, this.service))));
|
|
44127
44350
|
return;
|
|
44128
44351
|
}
|
|
44129
44352
|
const asset = ASSETS[raw];
|
|
@@ -44256,8 +44479,8 @@ function createRelayAttachmentDataLink(options) {
|
|
|
44256
44479
|
const child = { permit, lease: null, ws: null, receiver: null, closed: false, paired: false, ready: false, opening: null, cleanup: null, unregister: null };
|
|
44257
44480
|
children.set(permit.transfer_id, child);
|
|
44258
44481
|
const registrationStarted = Date.now();
|
|
44259
|
-
const
|
|
44260
|
-
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() });
|
|
44261
44484
|
try {
|
|
44262
44485
|
const reply = await options.control.requestFileControl("file.register", {
|
|
44263
44486
|
version: 1,
|
|
@@ -44269,7 +44492,7 @@ function createRelayAttachmentDataLink(options) {
|
|
|
44269
44492
|
max_wire_bytes: attachmentTransferWireBudget(permit.context.byte_size)
|
|
44270
44493
|
});
|
|
44271
44494
|
if (reply.code !== 0) {
|
|
44272
|
-
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...
|
|
44495
|
+
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...timing2() });
|
|
44273
44496
|
const error2 = unavailable7();
|
|
44274
44497
|
error2.cause = { stage: "file.register", relayCode: reply.code };
|
|
44275
44498
|
throw error2;
|
|
@@ -48020,7 +48243,7 @@ var init_desktop_ingress = __esm({
|
|
|
48020
48243
|
resetMethodValidity() {
|
|
48021
48244
|
this.ipcMethodInvalidatedThreads.clear();
|
|
48022
48245
|
}
|
|
48023
|
-
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) {
|
|
48024
48247
|
this.ports.writeDebug({
|
|
48025
48248
|
component: "daemon",
|
|
48026
48249
|
channel: "ipc",
|
|
@@ -48030,7 +48253,7 @@ var init_desktop_ingress = __esm({
|
|
|
48030
48253
|
attributes: {
|
|
48031
48254
|
type: frame.type,
|
|
48032
48255
|
...typeof frame.method === "string" ? { method: frame.method } : {},
|
|
48033
|
-
...
|
|
48256
|
+
...timing2
|
|
48034
48257
|
}
|
|
48035
48258
|
});
|
|
48036
48259
|
this.ports.writeRawDebug({
|
|
@@ -48062,6 +48285,9 @@ var init_desktop_ingress = __esm({
|
|
|
48062
48285
|
}
|
|
48063
48286
|
const status2 = objectRecord(frame.params);
|
|
48064
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
|
+
}
|
|
48065
48291
|
if (frame.method === "thread-stream-state-changed" && methodThreadId && this.ipcMethodInvalidatedThreads.has(methodThreadId) && objectRecord(status2.change).type !== "snapshot") {
|
|
48066
48292
|
if (readDiagnostic) readDiagnostic.reason = "baseline_required";
|
|
48067
48293
|
return;
|
|
@@ -48764,19 +48990,19 @@ var init_socket_client = __esm({
|
|
|
48764
48990
|
this.events.on("requestDiagnostic", listener);
|
|
48765
48991
|
return () => this.events.off("requestDiagnostic", listener);
|
|
48766
48992
|
}
|
|
48767
|
-
emitRequestDiagnostic(
|
|
48993
|
+
emitRequestDiagnostic(timing2, phase, outcome) {
|
|
48768
48994
|
this.events.emit("requestDiagnostic", {
|
|
48769
|
-
requestId:
|
|
48770
|
-
method:
|
|
48771
|
-
threadId:
|
|
48995
|
+
requestId: timing2.requestId,
|
|
48996
|
+
method: timing2.method,
|
|
48997
|
+
threadId: timing2.threadId,
|
|
48772
48998
|
phase,
|
|
48773
48999
|
outcome,
|
|
48774
|
-
durationMs: Math.max(0, Math.floor(performance.now() -
|
|
49000
|
+
durationMs: Math.max(0, Math.floor(performance.now() - timing2.startedAt))
|
|
48775
49001
|
});
|
|
48776
49002
|
}
|
|
48777
49003
|
pruneTimedOutRequests() {
|
|
48778
|
-
for (const [id5,
|
|
48779
|
-
if (performance.now() -
|
|
49004
|
+
for (const [id5, timing2] of this.timedOutRequests) {
|
|
49005
|
+
if (performance.now() - timing2.startedAt > 12e4) this.timedOutRequests.delete(id5);
|
|
48780
49006
|
}
|
|
48781
49007
|
while (this.timedOutRequests.size > 128) this.timedOutRequests.delete(this.timedOutRequests.keys().next().value);
|
|
48782
49008
|
}
|
|
@@ -48913,20 +49139,20 @@ var init_socket_client = __esm({
|
|
|
48913
49139
|
this.pruneTimedOutRequests();
|
|
48914
49140
|
const localParams = params && typeof params === "object" ? params : {};
|
|
48915
49141
|
const threadId2 = typeof localParams.threadId === "string" ? localParams.threadId : typeof localParams.conversationId === "string" ? localParams.conversationId : void 0;
|
|
48916
|
-
const
|
|
49142
|
+
const timing2 = { requestId, method: method2, threadId: threadId2, startedAt: performance.now() };
|
|
48917
49143
|
const responsePromise = new Promise((resolve5, reject3) => {
|
|
48918
49144
|
const timer = setTimeout(() => {
|
|
48919
49145
|
this.pending.delete(requestId);
|
|
48920
|
-
this.timedOutRequests.set(requestId,
|
|
49146
|
+
this.timedOutRequests.set(requestId, timing2);
|
|
48921
49147
|
this.pruneTimedOutRequests();
|
|
48922
|
-
this.emitRequestDiagnostic(
|
|
49148
|
+
this.emitRequestDiagnostic(timing2, "timeout", "unknown");
|
|
48923
49149
|
reject3(new NiumaError("UNKNOWN_RESULT", `IPC \u8BF7\u6C42\u8D85\u65F6: ${method2}`, { method: method2 }));
|
|
48924
49150
|
}, options.timeoutMs ?? this.requestTimeoutMs);
|
|
48925
|
-
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing });
|
|
49151
|
+
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing: timing2 });
|
|
48926
49152
|
});
|
|
48927
49153
|
try {
|
|
48928
49154
|
await this.write(frame);
|
|
48929
|
-
this.emitRequestDiagnostic(
|
|
49155
|
+
this.emitRequestDiagnostic(timing2, "sent", "pending");
|
|
48930
49156
|
} catch (error2) {
|
|
48931
49157
|
this.clearPending(requestId);
|
|
48932
49158
|
throw error2 instanceof Error ? new NiumaError("IPC_NOT_INITIALIZED", error2.message) : new NiumaError("IPC_NOT_INITIALIZED", String(error2));
|
|
@@ -49025,10 +49251,10 @@ var init_socket_client = __esm({
|
|
|
49025
49251
|
this.pruneTimedOutRequests();
|
|
49026
49252
|
const outcome = frame.resultType === "error" ? "error" : "success";
|
|
49027
49253
|
if (!pending) {
|
|
49028
|
-
const
|
|
49029
|
-
if (
|
|
49254
|
+
const timing2 = this.timedOutRequests.get(requestId);
|
|
49255
|
+
if (timing2) {
|
|
49030
49256
|
this.timedOutRequests.delete(requestId);
|
|
49031
|
-
this.emitRequestDiagnostic(
|
|
49257
|
+
this.emitRequestDiagnostic(timing2, "late_response", outcome);
|
|
49032
49258
|
}
|
|
49033
49259
|
return;
|
|
49034
49260
|
}
|
|
@@ -59539,15 +59765,46 @@ function createHistoryHandlers(ports) {
|
|
|
59539
59765
|
if (negotiated && (!handoffScope || !scope || scope.bindingId !== handoffScope.bindingId)) {
|
|
59540
59766
|
throw new HttpApiError(200, 200004, "\u6B63\u6587\u4EA4\u63A5\u9700\u8981\u8BA4\u8BC1\u4F1A\u8BDD");
|
|
59541
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
|
+
};
|
|
59542
59775
|
if (negotiated && typeof params.handoffTicket === "string") {
|
|
59543
|
-
if (options.signal?.aborted || socket.destroyed || socket.writableEnded)
|
|
59544
|
-
|
|
59545
|
-
|
|
59546
|
-
|
|
59547
|
-
|
|
59548
|
-
|
|
59549
|
-
|
|
59550
|
-
|
|
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
|
+
}
|
|
59551
59808
|
let recoveryClosed = false;
|
|
59552
59809
|
let unregisterRecovery2 = () => {
|
|
59553
59810
|
};
|
|
@@ -59560,12 +59817,14 @@ function createHistoryHandlers(ports) {
|
|
|
59560
59817
|
}) : () => {
|
|
59561
59818
|
};
|
|
59562
59819
|
} catch (error2) {
|
|
59820
|
+
loadAttempt?.close();
|
|
59563
59821
|
consumer.close();
|
|
59564
59822
|
throw error2;
|
|
59565
59823
|
}
|
|
59566
59824
|
let unregisterArchive2 = () => {
|
|
59567
59825
|
};
|
|
59568
59826
|
const close2 = () => {
|
|
59827
|
+
loadAttempt?.close();
|
|
59569
59828
|
unregisterArchive2();
|
|
59570
59829
|
recoveryClosed = true;
|
|
59571
59830
|
unregisterRecovery2();
|
|
@@ -59592,7 +59851,6 @@ function createHistoryHandlers(ports) {
|
|
|
59592
59851
|
`);
|
|
59593
59852
|
return STREAMING_RESPONSE;
|
|
59594
59853
|
}
|
|
59595
|
-
const loadStartedAt = performance.now();
|
|
59596
59854
|
let loadTrace = null;
|
|
59597
59855
|
let loadLeaseId = null;
|
|
59598
59856
|
let unregisterLoad = () => {
|
|
@@ -59602,7 +59860,9 @@ function createHistoryHandlers(ports) {
|
|
|
59602
59860
|
const pendingLoad = [];
|
|
59603
59861
|
const loadSeen = /* @__PURE__ */ new Set();
|
|
59604
59862
|
const recordLoad = (phase, clock = "daemon", elapsed = Math.round(performance.now() - loadStartedAt), occurredAt4 = clock === "daemon" ? Date.now() : void 0) => {
|
|
59605
|
-
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);
|
|
59606
59866
|
if (!loadLeaseId) {
|
|
59607
59867
|
if (pendingLoad.length < 8) pendingLoad.push({ phase, elapsed, occurredAt: occurredAt4 });
|
|
59608
59868
|
return;
|
|
@@ -59691,6 +59951,7 @@ function createHistoryHandlers(ports) {
|
|
|
59691
59951
|
readReceiptTimer = null;
|
|
59692
59952
|
}
|
|
59693
59953
|
recordLoad("stream_closed");
|
|
59954
|
+
loadAttempt?.close();
|
|
59694
59955
|
unregisterLoad();
|
|
59695
59956
|
unregisterRecovery();
|
|
59696
59957
|
closed = true;
|
|
@@ -59727,6 +59988,7 @@ function createHistoryHandlers(ports) {
|
|
|
59727
59988
|
const close = () => {
|
|
59728
59989
|
if (physicalClosed) return;
|
|
59729
59990
|
physicalClosed = true;
|
|
59991
|
+
loadAttempt?.close();
|
|
59730
59992
|
unregisterRecovery();
|
|
59731
59993
|
options.signal?.removeEventListener("abort", close);
|
|
59732
59994
|
publisher?.close();
|
|
@@ -59743,7 +60005,14 @@ function createHistoryHandlers(ports) {
|
|
|
59743
60005
|
return STREAMING_RESPONSE;
|
|
59744
60006
|
}
|
|
59745
60007
|
if (!ports.store().getThread(threadId2, { tailCount: 0 })) {
|
|
59746
|
-
|
|
60008
|
+
try {
|
|
60009
|
+
await ports.verifyThreadForOpen(threadId2);
|
|
60010
|
+
} catch (error2) {
|
|
60011
|
+
failOpen(error2);
|
|
60012
|
+
loadAttempt?.close();
|
|
60013
|
+
detachClose();
|
|
60014
|
+
throw error2;
|
|
60015
|
+
}
|
|
59747
60016
|
}
|
|
59748
60017
|
if (closed || socketIsClosed()) {
|
|
59749
60018
|
closed = true;
|
|
@@ -59792,13 +60061,15 @@ function createHistoryHandlers(ports) {
|
|
|
59792
60061
|
}
|
|
59793
60062
|
for (const sample of pendingLoad) recordLoad(sample.phase, "daemon", sample.elapsed, sample.occurredAt);
|
|
59794
60063
|
pendingLoad.length = 0;
|
|
60064
|
+
if (loadLeaseId && loadTrace) loadAttempt?.attachLease(loadLeaseId, loadTrace.traceId);
|
|
59795
60065
|
recordLoad("lease_acquired");
|
|
59796
60066
|
try {
|
|
59797
|
-
if (loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
60067
|
+
if (loadAttempt && loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
59798
60068
|
params.loadId,
|
|
59799
60069
|
threadId2,
|
|
59800
60070
|
scope ? `binding:${scope.bindingId.toLowerCase()}` : "local",
|
|
59801
|
-
(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
|
|
59802
60073
|
);
|
|
59803
60074
|
} catch {
|
|
59804
60075
|
}
|
|
@@ -59912,6 +60183,7 @@ function createHistoryHandlers(ports) {
|
|
|
59912
60183
|
ports.requestThreadAuthorityRecovery(threadId2, true);
|
|
59913
60184
|
ports.history().onHistoryLeaseStateChanged(threadId2, ports.activeThreadFollowerCoordinator()?.leaseKindsFor(threadId2) ?? []);
|
|
59914
60185
|
unsubscribeHistoryWindow = historyWindow.subscribe(() => {
|
|
60186
|
+
if (historyWindow?.initialWindowState === "failed") loadAttempt?.finish("failed", { terminal_phase: "shell_sent", reason: "history_failed" });
|
|
59915
60187
|
if (rangeClaim && historyWindow?.initialWindowState === "failed") {
|
|
59916
60188
|
socket.write(`${JSON.stringify(errorEnvelope(new NiumaError("HISTORY_SNAPSHOT_EXPIRED", "\u5386\u53F2\u6062\u590D\u8303\u56F4\u4E0D\u53EF\u7528\u6216\u5DF2\u8FC7\u671F")))}
|
|
59917
60189
|
`);
|
|
@@ -59986,6 +60258,7 @@ function createHistoryHandlers(ports) {
|
|
|
59986
60258
|
`);
|
|
59987
60259
|
}
|
|
59988
60260
|
} catch (error2) {
|
|
60261
|
+
failOpen(error2);
|
|
59989
60262
|
try {
|
|
59990
60263
|
const sites = [
|
|
59991
60264
|
["historySourceAssertion", "Object.sourceCurrent"],
|
|
@@ -60067,20 +60340,20 @@ function text10(value) {
|
|
|
60067
60340
|
return false;
|
|
60068
60341
|
}
|
|
60069
60342
|
}
|
|
60070
|
-
function
|
|
60343
|
+
function object10(value, keys3) {
|
|
60071
60344
|
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return fail16("invalid");
|
|
60072
60345
|
const own = Reflect.ownKeys(value);
|
|
60073
60346
|
if (own.length !== keys3.length || !own.every((key) => typeof key === "string" && keys3.includes(key) && "value" in Object.getOwnPropertyDescriptor(value, key))) return fail16("invalid");
|
|
60074
60347
|
return value;
|
|
60075
60348
|
}
|
|
60076
60349
|
function parseAsyncQuestionBatch(value) {
|
|
60077
|
-
const raw =
|
|
60350
|
+
const raw = object10(value, ["thread_id", "group_id", "revision", "idempotency_key", "question_ids", "answers"]);
|
|
60078
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");
|
|
60079
60352
|
const questionIds = Array.from(raw.question_ids);
|
|
60080
60353
|
if (!questionIds.every(id3) || new Set(questionIds).size !== questionIds.length) return fail16("invalid");
|
|
60081
60354
|
const seen = /* @__PURE__ */ new Set();
|
|
60082
60355
|
const answers = Array.from(raw.answers, (value2) => {
|
|
60083
|
-
const answer =
|
|
60356
|
+
const answer = object10(value2, ["question_id", "title", "answer"]);
|
|
60084
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");
|
|
60085
60358
|
seen.add(answer.question_id);
|
|
60086
60359
|
return { question_id: answer.question_id, title: answer.title, answer: answer.answer };
|
|
@@ -62991,10 +63264,10 @@ var init_thread_history_window_loader = __esm({
|
|
|
62991
63264
|
sourceRevision: 0
|
|
62992
63265
|
};
|
|
62993
63266
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
62994
|
-
const
|
|
63267
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
62995
63268
|
this.assertSource(epoch);
|
|
62996
63269
|
signal.throwIfAborted();
|
|
62997
|
-
const versionKey = JSON.stringify([epoch, description.contentVersion,
|
|
63270
|
+
const versionKey = JSON.stringify([epoch, description.contentVersion, timing2]);
|
|
62998
63271
|
let cached = this.turns.get(identity6);
|
|
62999
63272
|
if (cached?.current?.version === versionKey) {
|
|
63000
63273
|
if (description.sourceRevision >= cached.sourceRevision && cached.nativeOrder !== description.nativeOrder) {
|
|
@@ -63011,7 +63284,7 @@ var init_thread_history_window_loader = __esm({
|
|
|
63011
63284
|
this.assertSource(epoch);
|
|
63012
63285
|
signal.throwIfAborted();
|
|
63013
63286
|
if (enriched.turnId !== turn.id) throw new RangeError("\u7A97\u53E3\u65F6\u95F4\u8865\u9F50 Turn \u8EAB\u4EFD\u4E0D\u5339\u914D");
|
|
63014
|
-
if (await this.timestampVersion(turn, signal) !==
|
|
63287
|
+
if (await this.timestampVersion(turn, signal) !== timing2) continue;
|
|
63015
63288
|
this.assertSource(epoch);
|
|
63016
63289
|
signal.throwIfAborted();
|
|
63017
63290
|
const freeze = (value) => {
|
|
@@ -63069,11 +63342,11 @@ var init_thread_history_window_loader = __esm({
|
|
|
63069
63342
|
const epoch = this.sourceEpoch;
|
|
63070
63343
|
this.currentProtection.addTurnIds([turn.id]);
|
|
63071
63344
|
const description = this.reader.describeTurn?.(turn) ?? { contentVersion: createHash26("sha256").update(JSON.stringify(turn)).digest("hex") };
|
|
63072
|
-
const
|
|
63345
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
63073
63346
|
this.assertSource(epoch);
|
|
63074
63347
|
signal.throwIfAborted();
|
|
63075
63348
|
const cached = this.turns.get(JSON.stringify([this.currentThreadId, turn.id]));
|
|
63076
|
-
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion,
|
|
63349
|
+
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion, timing2])) {
|
|
63077
63350
|
this.holdVersion(this.currentProtection, cached.current);
|
|
63078
63351
|
return cached.current.projection.displayItemCount;
|
|
63079
63352
|
}
|
|
@@ -64334,17 +64607,17 @@ var init_app_server_thread_view_adapter = __esm({
|
|
|
64334
64607
|
lastError: null
|
|
64335
64608
|
}).status;
|
|
64336
64609
|
const terminalStatus = failed || aborted || status2 === "completed" ? lifecycleStatus : "completed";
|
|
64337
|
-
const
|
|
64610
|
+
const timing2 = context.getTurnLifecycle?.(turnId);
|
|
64338
64611
|
return [{
|
|
64339
64612
|
type: "ThreadStatusChanged",
|
|
64340
64613
|
thread_id: context.threadId,
|
|
64341
64614
|
status: terminalStatus,
|
|
64342
64615
|
turn_id: turnId,
|
|
64343
64616
|
terminal_item_state: terminalStatus === "error" ? "failed" : "completed",
|
|
64344
|
-
...
|
|
64345
|
-
startedAt: lifecycleTime(
|
|
64346
|
-
endedAt: lifecycleTime(
|
|
64347
|
-
outcome:
|
|
64617
|
+
...timing2 ? { process_lifecycle: {
|
|
64618
|
+
startedAt: lifecycleTime(timing2.startedAt),
|
|
64619
|
+
endedAt: lifecycleTime(timing2.endedAt),
|
|
64620
|
+
outcome: timing2.outcome
|
|
64348
64621
|
} } : {},
|
|
64349
64622
|
last_error: terminalStatus === "error" ? {
|
|
64350
64623
|
code: 900001,
|
|
@@ -64615,10 +64888,10 @@ var init_thread_history_window_projection = __esm({
|
|
|
64615
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);
|
|
64616
64889
|
const timingById = new Map(sources.map((source2, index) => [source2.id, enriched[index]]));
|
|
64617
64890
|
const items = projected.items.map((item) => {
|
|
64618
|
-
const
|
|
64891
|
+
const timing2 = timingById.get(item.id);
|
|
64619
64892
|
const fact = item.process_fact;
|
|
64620
|
-
if (!
|
|
64621
|
-
const merged = mergeThreadHistoryTimelineLifecycle(
|
|
64893
|
+
if (!timing2 || !fact) return item;
|
|
64894
|
+
const merged = mergeThreadHistoryTimelineLifecycle(timing2, {
|
|
64622
64895
|
...fact.startedAt !== null ? { turnStartedAt: fact.startedAt } : {},
|
|
64623
64896
|
...fact.endedAt !== null ? { turnEndedAt: fact.endedAt } : {},
|
|
64624
64897
|
...fact.durationMs != null ? { turnDurationMs: fact.durationMs } : {},
|
|
@@ -65439,7 +65712,7 @@ function readStateDiagnostic(before, after, candidate = after.confirmed) {
|
|
|
65439
65712
|
sameCycle: candidate ? candidate.cycle === after.cycle : null
|
|
65440
65713
|
};
|
|
65441
65714
|
}
|
|
65442
|
-
function
|
|
65715
|
+
function object11(value) {
|
|
65443
65716
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
65444
65717
|
}
|
|
65445
65718
|
function field(value, present, count) {
|
|
@@ -65449,15 +65722,15 @@ function field(value, present, count) {
|
|
|
65449
65722
|
}
|
|
65450
65723
|
function unreadFrameDiagnostic(frame) {
|
|
65451
65724
|
if (frame.method !== "thread-stream-state-changed") return null;
|
|
65452
|
-
const params =
|
|
65725
|
+
const params = object11(frame.params), change = object11(params.change);
|
|
65453
65726
|
const kind = change.type === "snapshot" ? "snapshot" : change.type === "patches" ? "patch" : "invalid";
|
|
65454
|
-
const values = kind === "snapshot" ?
|
|
65727
|
+
const values = kind === "snapshot" ? object11(change.conversationState) : {};
|
|
65455
65728
|
let unread = field(values.hasUnreadTurn, Object.hasOwn(values, "hasUnreadTurn"), false);
|
|
65456
65729
|
let count = field(values.unreadMessageCount, Object.hasOwn(values, "unreadMessageCount"), true);
|
|
65457
65730
|
let countValue = values.unreadMessageCount;
|
|
65458
65731
|
if (kind === "patch") {
|
|
65459
65732
|
for (const value of Array.isArray(change.patches) ? change.patches : []) {
|
|
65460
|
-
const patch =
|
|
65733
|
+
const patch = object11(value), path55 = Array.isArray(patch.path) ? patch.path : [];
|
|
65461
65734
|
const name2 = path55.length === 1 ? path55[0] : path55.length === 2 && path55[0] === "conversationState" ? path55[1] : null;
|
|
65462
65735
|
if (name2 !== "hasUnreadTurn" && name2 !== "unreadMessageCount") continue;
|
|
65463
65736
|
const state = patch.op === "remove" ? "removed" : ["add", "replace"].includes(String(patch.op)) ? field(patch.value, Object.hasOwn(patch, "value"), name2 === "unreadMessageCount") : "invalid";
|
|
@@ -65571,10 +65844,10 @@ var init_ingress_dispatch = __esm({
|
|
|
65571
65844
|
}
|
|
65572
65845
|
ports;
|
|
65573
65846
|
/** 单帧入站与最终结果成对记录;原始字段与业务结果分开,拒绝帧同样留证。 */
|
|
65574
|
-
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) {
|
|
65575
65848
|
const attributes = this.ports.options().debugLogger ? unreadFrameDiagnostic(frame) : null;
|
|
65576
65849
|
const threadId2 = attributes ? extractThreadIdFromIpcFrame(frame) : null;
|
|
65577
|
-
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
65850
|
+
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2);
|
|
65578
65851
|
const before = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 })?.unread;
|
|
65579
65852
|
const diagnostic = { reason: "processed" };
|
|
65580
65853
|
const metadata = { ...attributes, sequence: this.ports.diagnostics().threadReadDiagnosticSequenceValue++, generation: receivedIpcGeneration, currentGeneration: this.ports.desktopSession().ipcConnectionGenerationValue };
|
|
@@ -65587,7 +65860,7 @@ var init_ingress_dispatch = __esm({
|
|
|
65587
65860
|
}
|
|
65588
65861
|
});
|
|
65589
65862
|
try {
|
|
65590
|
-
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
65863
|
+
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2, diagnostic);
|
|
65591
65864
|
} catch (error2) {
|
|
65592
65865
|
diagnostic.reason = "processing_failed";
|
|
65593
65866
|
throw error2;
|
|
@@ -67399,11 +67672,11 @@ var init_projection_context = __esm({
|
|
|
67399
67672
|
} : null),
|
|
67400
67673
|
enrichTimelineItemTiming: (item) => this.ports.timelinePublication().enrichTimelineItemTiming(item, timelineItems),
|
|
67401
67674
|
getTurnLifecycle: (turnId) => {
|
|
67402
|
-
const
|
|
67403
|
-
return
|
|
67404
|
-
startedAt:
|
|
67405
|
-
endedAt:
|
|
67406
|
-
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
|
|
67407
67680
|
} : null;
|
|
67408
67681
|
},
|
|
67409
67682
|
resolveKnownLocalImage: (sourcePath, itemId, partIndex) => this.ports.resolveThreadViewImage(threadId2, sourcePath, () => this.ports.isCurrentAppServerAsyncFence(threadId2, fence), itemId, partIndex)
|
|
@@ -68021,7 +68294,7 @@ var init_active_thread_follower_coordinator = __esm({
|
|
|
68021
68294
|
init_errors();
|
|
68022
68295
|
init_session_history_file();
|
|
68023
68296
|
init_error_log();
|
|
68024
|
-
ACTIVE_THREAD_SCAN_INTERVAL_MS =
|
|
68297
|
+
ACTIVE_THREAD_SCAN_INTERVAL_MS = 6e4;
|
|
68025
68298
|
ACTIVE_THREAD_READ_CONCURRENCY = 4;
|
|
68026
68299
|
ACTIVE_FOLLOWER_SNAPSHOT_TIMEOUT_MS = 12e3;
|
|
68027
68300
|
ACTIVE_FOLLOWER_RETRY_DELAYS_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
@@ -75114,7 +75387,7 @@ var init_thread_state_coordination = __esm({
|
|
|
75114
75387
|
return token3;
|
|
75115
75388
|
}
|
|
75116
75389
|
/** 仅供已核验的同轮终态使用;同时收敛列表与详情,不伪造新的完成通知。 */
|
|
75117
|
-
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message,
|
|
75390
|
+
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message, timing2) {
|
|
75118
75391
|
const previous = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 });
|
|
75119
75392
|
const mutation = this.ports.catalog().storeValue.applyActivitySignal({
|
|
75120
75393
|
type: "snapshot",
|
|
@@ -75134,7 +75407,7 @@ var init_thread_state_coordination = __esm({
|
|
|
75134
75407
|
turn_id: turnId,
|
|
75135
75408
|
status: outcome === "aborted" ? "idle" : outcome === "failed" ? "error" : "completed",
|
|
75136
75409
|
terminal_item_state: outcome === "failed" ? "failed" : "completed",
|
|
75137
|
-
process_lifecycle: { startedAt:
|
|
75410
|
+
process_lifecycle: { startedAt: timing2?.startedAt ?? null, endedAt: timing2?.endedAt ?? null, outcome },
|
|
75138
75411
|
last_error: outcome === "failed" && message ? { code: 900001, message, occurred_at: occurredAt4, turn_id: turnId } : null
|
|
75139
75412
|
},
|
|
75140
75413
|
{ type: "ThreadActivityChanged", thread_id: threadId2, turn_id: turnId, activity: null },
|
|
@@ -75394,15 +75667,15 @@ var init_timeline_publication = __esm({
|
|
|
75394
75667
|
if (!item.turnId) {
|
|
75395
75668
|
return item;
|
|
75396
75669
|
}
|
|
75397
|
-
const
|
|
75398
|
-
if (!
|
|
75670
|
+
const timing2 = this.liveTurnTimings.get(this.turnTimingKey(item.threadId, item.turnId));
|
|
75671
|
+
if (!timing2) {
|
|
75399
75672
|
return item;
|
|
75400
75673
|
}
|
|
75401
75674
|
return {
|
|
75402
75675
|
...item,
|
|
75403
|
-
...item.turnStartedAt === void 0 ? { turnStartedAt:
|
|
75404
|
-
...item.turnEndedAt === void 0 &&
|
|
75405
|
-
...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 } : {}
|
|
75406
75679
|
};
|
|
75407
75680
|
}
|
|
75408
75681
|
enrichTimelineItemTiming(item, historyItems = []) {
|
|
@@ -75422,9 +75695,9 @@ var init_timeline_publication = __esm({
|
|
|
75422
75695
|
turnTimingKey(threadId2, turnId) {
|
|
75423
75696
|
return `${threadId2}:${turnId}`;
|
|
75424
75697
|
}
|
|
75425
|
-
setLiveTurnTiming(key,
|
|
75698
|
+
setLiveTurnTiming(key, timing2) {
|
|
75426
75699
|
this.liveTurnTimings.delete(key);
|
|
75427
|
-
this.liveTurnTimings.set(key,
|
|
75700
|
+
this.liveTurnTimings.set(key, timing2);
|
|
75428
75701
|
while (this.liveTurnTimings.size > LIVE_TURN_TIMING_LIMIT) {
|
|
75429
75702
|
const oldestKey = this.liveTurnTimings.keys().next().value;
|
|
75430
75703
|
if (typeof oldestKey !== "string") break;
|
|
@@ -83906,8 +84179,7 @@ var init_native_admission = __esm({
|
|
|
83906
84179
|
else if (kind === "ordinary") this.hidden.delete(thread4.id);
|
|
83907
84180
|
const old = this.entries.get(thread4.id);
|
|
83908
84181
|
this.failures.delete(thread4.id);
|
|
83909
|
-
|
|
83910
|
-
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 };
|
|
83911
84183
|
this.entries.set(thread4.id, { token: token3, kind });
|
|
83912
84184
|
try {
|
|
83913
84185
|
if (kind !== previous) this.ports.onChange?.(thread4.id, previous, kind);
|
|
@@ -83917,7 +84189,7 @@ var init_native_admission = __esm({
|
|
|
83917
84189
|
}
|
|
83918
84190
|
const pending = this.jobs.get(thread4.id);
|
|
83919
84191
|
if (pending) {
|
|
83920
|
-
this.finishWait(pending, kind);
|
|
84192
|
+
this.finishWait(pending, kind, thread4, token3);
|
|
83921
84193
|
if (!pending.started) {
|
|
83922
84194
|
this.removeQueued(pending);
|
|
83923
84195
|
this.removeJob(pending);
|
|
@@ -83925,13 +84197,20 @@ var init_native_admission = __esm({
|
|
|
83925
84197
|
}
|
|
83926
84198
|
return token3;
|
|
83927
84199
|
}
|
|
83928
|
-
ensure(id5, executionGeneration) {
|
|
83929
|
-
|
|
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" });
|
|
83930
84209
|
const known = this.kind(id5);
|
|
83931
|
-
if (known !== "unknown") return Promise.resolve(known);
|
|
84210
|
+
if (known !== "unknown" && (!needSummary || known === "subagent")) return Promise.resolve({ kind: known });
|
|
83932
84211
|
const pending = this.jobs.get(id5);
|
|
83933
|
-
if (pending) return pending.execution === this.execution ? pending.promise : Promise.resolve("unknown");
|
|
83934
|
-
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" });
|
|
83935
84214
|
let resolve5;
|
|
83936
84215
|
const promise = new Promise((done) => {
|
|
83937
84216
|
resolve5 = done;
|
|
@@ -83988,11 +84267,11 @@ var init_native_admission = __esm({
|
|
|
83988
84267
|
removeJob(job) {
|
|
83989
84268
|
if (this.jobs.get(job.id) === job) this.jobs.delete(job.id);
|
|
83990
84269
|
}
|
|
83991
|
-
finishWait(job, kind) {
|
|
84270
|
+
finishWait(job, kind, summary, token3) {
|
|
83992
84271
|
if (job.settled) return;
|
|
83993
84272
|
job.settled = true;
|
|
83994
84273
|
job.cancel();
|
|
83995
|
-
job.resolve(kind);
|
|
84274
|
+
job.resolve({ kind, ...summary ? { summary, token: token3 } : {} });
|
|
83996
84275
|
}
|
|
83997
84276
|
fail(job) {
|
|
83998
84277
|
if (job.execution === this.execution) {
|
|
@@ -84026,7 +84305,7 @@ var init_native_admission = __esm({
|
|
|
84026
84305
|
this.observe(result.thread, job.execution);
|
|
84027
84306
|
const kind = this.kind(job.id);
|
|
84028
84307
|
if (kind === "unknown") this.fail(job);
|
|
84029
|
-
this.finishWait(job, kind);
|
|
84308
|
+
this.finishWait(job, kind, result.thread, this.token(job.id));
|
|
84030
84309
|
}).catch(() => {
|
|
84031
84310
|
if (!job.settled) {
|
|
84032
84311
|
this.fail(job);
|
|
@@ -85022,19 +85301,19 @@ function withoutPersistentImageBytes(value, key = "", seen = /* @__PURE__ */ new
|
|
|
85022
85301
|
if (seen.has(value)) return "[circular]";
|
|
85023
85302
|
seen.add(value);
|
|
85024
85303
|
try {
|
|
85025
|
-
const
|
|
85026
|
-
if (
|
|
85027
|
-
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 };
|
|
85028
85307
|
}
|
|
85029
|
-
if (
|
|
85030
|
-
const payload =
|
|
85031
|
-
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)]));
|
|
85032
85311
|
return { ...metadata, rawPayload: { type: "stdout_fragment", bytes: typeof payload?.bytes === "number" ? payload.bytes : typeof payload?.fragment === "string" ? Buffer.byteLength(payload.fragment) : 0 } };
|
|
85033
85312
|
}
|
|
85034
85313
|
if (Array.isArray(value)) return value.map((entry) => withoutPersistentImageBytes(entry, key, seen));
|
|
85035
|
-
return Object.fromEntries(Object.entries(
|
|
85314
|
+
return Object.fromEntries(Object.entries(object12).map(([name2, entry]) => [
|
|
85036
85315
|
name2,
|
|
85037
|
-
withoutPersistentImageBytes(entry,
|
|
85316
|
+
withoutPersistentImageBytes(entry, object12.type === "image" && name2 === "data" ? "base64" : name2, seen)
|
|
85038
85317
|
]));
|
|
85039
85318
|
} finally {
|
|
85040
85319
|
seen.delete(value);
|
|
@@ -85139,6 +85418,7 @@ var init_debug_log = __esm({
|
|
|
85139
85418
|
"ipc_recovery",
|
|
85140
85419
|
"ipc_forwarding_flow",
|
|
85141
85420
|
"notification_delivery",
|
|
85421
|
+
"ipc_thread_discovery",
|
|
85142
85422
|
"startup_timing",
|
|
85143
85423
|
"thread_settings_cache",
|
|
85144
85424
|
"thread_list_cache",
|
|
@@ -85372,6 +85652,7 @@ var init_debug_log = __esm({
|
|
|
85372
85652
|
"inFlight"
|
|
85373
85653
|
],
|
|
85374
85654
|
// 启动性能仅保留固定阶段耗时和汇总计数,禁止记录路径、会话或异常原文。
|
|
85655
|
+
ipc_thread_discovery: ["durationMs"],
|
|
85375
85656
|
startup_timing: [
|
|
85376
85657
|
"durationMs",
|
|
85377
85658
|
"threadCount",
|
|
@@ -85918,6 +86199,7 @@ var init_debug_log = __esm({
|
|
|
85918
86199
|
"dropped_busy",
|
|
85919
86200
|
"deadline_expired"
|
|
85920
86201
|
],
|
|
86202
|
+
ipc_thread_discovery: ["received", "ignored", "deduplicated", "capacity", "read_completed", "rejected", "stale", "published", "failed"],
|
|
85921
86203
|
startup_timing: [
|
|
85922
86204
|
"app_server_initialized",
|
|
85923
86205
|
"thread_baseline_scanned",
|
|
@@ -86450,6 +86732,7 @@ var NiumaDaemonRuntime;
|
|
|
86450
86732
|
var init_composition = __esm({
|
|
86451
86733
|
"apps/desktop/src/daemon/runtime/composition.ts"() {
|
|
86452
86734
|
"use strict";
|
|
86735
|
+
init_ipc_thread_discovery();
|
|
86453
86736
|
init_legacy_question_operation();
|
|
86454
86737
|
init_pending_response_operation();
|
|
86455
86738
|
init_settings_update_operation();
|
|
@@ -86553,7 +86836,7 @@ var init_composition = __esm({
|
|
|
86553
86836
|
init_settings_selection();
|
|
86554
86837
|
init_thread_routing();
|
|
86555
86838
|
init_device_name();
|
|
86556
|
-
|
|
86839
|
+
init_thread_load_trace2();
|
|
86557
86840
|
init_paths2();
|
|
86558
86841
|
init_message_submission_store();
|
|
86559
86842
|
init_client2();
|
|
@@ -87183,6 +87466,7 @@ var init_composition = __esm({
|
|
|
87183
87466
|
}
|
|
87184
87467
|
desktopTrackers = new RuntimeDesktopIngressTrackers();
|
|
87185
87468
|
desktopIngress = new RuntimeDesktopIngress({
|
|
87469
|
+
discoverThread: (id5) => this.ipcThreadDiscovery.discover(id5),
|
|
87186
87470
|
nativeAdmission: () => this.nativeAdmission,
|
|
87187
87471
|
ensureNativeAdmission: (id5) => this.ensureNativeAdmission(id5),
|
|
87188
87472
|
requestReadFileRefresh: () => this.followerCoordination.desktopReadStateFileValue?.requestRefresh(),
|
|
@@ -87718,6 +88002,33 @@ var init_composition = __esm({
|
|
|
87718
88002
|
}
|
|
87719
88003
|
}
|
|
87720
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
|
+
});
|
|
87721
88032
|
async ensureNativeAdmission(id5) {
|
|
87722
88033
|
return !this.lifecycle.stoppingValue && !this.archiveState.isConfirmed(id5) && await this.nativeAdmission.ensure(id5, this.appServerLoads.connectionGeneration) === "ordinary";
|
|
87723
88034
|
}
|
|
@@ -88404,7 +88715,7 @@ var init_composition = __esm({
|
|
|
88404
88715
|
isBlocked: isStartBlockedByLifecycle
|
|
88405
88716
|
});
|
|
88406
88717
|
// 所有 runtime 与 coordinator 共用同一审计实例,确保 thread-scope 事件可关联当前 trace。
|
|
88407
|
-
threadLoadReports = new ThreadLoadReports();
|
|
88718
|
+
threadLoadReports = new ThreadLoadReports(Date.now, () => this.followerOpenTraceAudit);
|
|
88408
88719
|
followerOpenTraceAudit;
|
|
88409
88720
|
// 异步选择只等待目录;端口在实际调用时读取,不能提前冻结Owner或缓存。
|
|
88410
88721
|
settingsSelection = new RuntimeSettingsSelection({
|
|
@@ -88752,6 +89063,41 @@ var init_runtime2 = __esm({
|
|
|
88752
89063
|
}
|
|
88753
89064
|
});
|
|
88754
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
|
+
|
|
88755
89101
|
// apps/desktop/src/daemon/follower-open-trace.ts
|
|
88756
89102
|
import { randomUUID as randomUUID52 } from "node:crypto";
|
|
88757
89103
|
import path52 from "node:path";
|
|
@@ -88776,6 +89122,9 @@ function isOptionalTraceTitle(value) {
|
|
|
88776
89122
|
function hasOnlyKeys2(value, allowed) {
|
|
88777
89123
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.includes(key));
|
|
88778
89124
|
}
|
|
89125
|
+
function isRecent(value, nowMs) {
|
|
89126
|
+
return value <= nowMs && nowMs - value <= DAEMON_LOG_RETENTION_MS;
|
|
89127
|
+
}
|
|
88779
89128
|
function dateFileName2(timestampMs) {
|
|
88780
89129
|
return `${new Date(timestampMs).toISOString().slice(0, 10)}.ndjson`;
|
|
88781
89130
|
}
|
|
@@ -88882,6 +89231,10 @@ function parseRecord2(line) {
|
|
|
88882
89231
|
}
|
|
88883
89232
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
88884
89233
|
const record25 = value;
|
|
89234
|
+
if (record25.schema_version === 3) {
|
|
89235
|
+
const parsed = LoadRecordSchema.safeParse(record25);
|
|
89236
|
+
return parsed.success ? parsed.data : null;
|
|
89237
|
+
}
|
|
88885
89238
|
if (record25.schema_version === 1) return parseV1Record(record25);
|
|
88886
89239
|
if (record25.schema_version === 2) return parseV2Record(record25);
|
|
88887
89240
|
return null;
|
|
@@ -88917,6 +89270,46 @@ function readPrivateTraceFile(file, remainingBytes, storage) {
|
|
|
88917
89270
|
return { bytesRead: error2 instanceof PrivateLogFileError ? error2.bytesRead : 0, incomplete: true };
|
|
88918
89271
|
}
|
|
88919
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
|
+
}
|
|
88920
89313
|
function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
88921
89314
|
let maximum = 0;
|
|
88922
89315
|
let totalBytes = 0;
|
|
@@ -88935,14 +89328,65 @@ function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
|
88935
89328
|
}
|
|
88936
89329
|
return maximum;
|
|
88937
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
|
+
}
|
|
88938
89381
|
function createFollowerOpenTraceAudit(input) {
|
|
88939
89382
|
return new FollowerOpenTraceAuditWriter(input.runtimeDir ?? daemonRuntimeDir(), input.nowMs ?? Date.now, input.files ?? privateAuditFiles);
|
|
88940
89383
|
}
|
|
88941
|
-
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;
|
|
88942
89385
|
var init_follower_open_trace = __esm({
|
|
88943
89386
|
"apps/desktop/src/daemon/follower-open-trace.ts"() {
|
|
88944
89387
|
"use strict";
|
|
88945
|
-
|
|
89388
|
+
init_thread_load_record();
|
|
89389
|
+
init_thread_load_trace2();
|
|
88946
89390
|
init_private_log_files();
|
|
88947
89391
|
init_log_retention();
|
|
88948
89392
|
init_paths();
|
|
@@ -88951,6 +89395,7 @@ var init_follower_open_trace = __esm({
|
|
|
88951
89395
|
MAX_TOTAL_BYTES2 = 20 * 1024 * 1024;
|
|
88952
89396
|
MAX_LINE_BYTES2 = 64 * 1024;
|
|
88953
89397
|
MAX_DIRECTORY_ENTRIES3 = 256;
|
|
89398
|
+
MAX_PROCESSED_LINES2 = 1e4;
|
|
88954
89399
|
SUBSCRIPTION_TRACE_SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
88955
89400
|
FOLLOWER_OPEN_TRACE_TITLE_MAX_LENGTH = 256;
|
|
88956
89401
|
TRANSPORTS = /* @__PURE__ */ new Set(["local", "direct", "relay"]);
|
|
@@ -89104,6 +89549,30 @@ var init_follower_open_trace = __esm({
|
|
|
89104
89549
|
nowMs;
|
|
89105
89550
|
files;
|
|
89106
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
|
+
}
|
|
89107
89576
|
traceDirectoryInitialized = false;
|
|
89108
89577
|
/** 只缓存当前追加文件;日期切换或清空后重新发现已有分片。 */
|
|
89109
89578
|
appendFilePath;
|
|
@@ -89237,6 +89706,7 @@ var init_follower_open_trace = __esm({
|
|
|
89237
89706
|
for (const entry of matching) this.files.remove(entry.file);
|
|
89238
89707
|
}
|
|
89239
89708
|
this.appendFilePath = void 0;
|
|
89709
|
+
this.loadEpoch += 1;
|
|
89240
89710
|
this.activeTraces.clear();
|
|
89241
89711
|
this.activeSubscriptionTraces.clear();
|
|
89242
89712
|
this.activeSubscriptionTraceHandles.clear();
|
|
@@ -89478,21 +89948,21 @@ var init_local_gateway_supervisor = __esm({
|
|
|
89478
89948
|
|
|
89479
89949
|
// apps/desktop/src/daemon/async-input-notification-store.ts
|
|
89480
89950
|
import { createHash as createHash41 } from "node:crypto";
|
|
89481
|
-
import { z as
|
|
89951
|
+
import { z as z18 } from "zod";
|
|
89482
89952
|
var ASYNC_INPUT_NOTIFICATION_MAX_BYTES, identityText, entrySchema2, documentSchema2, AsyncInputNotificationStore;
|
|
89483
89953
|
var init_async_input_notification_store = __esm({
|
|
89484
89954
|
"apps/desktop/src/daemon/async-input-notification-store.ts"() {
|
|
89485
89955
|
"use strict";
|
|
89486
89956
|
init_src2();
|
|
89487
89957
|
ASYNC_INPUT_NOTIFICATION_MAX_BYTES = 2 * 1024 * 1024;
|
|
89488
|
-
identityText =
|
|
89489
|
-
entrySchema2 =
|
|
89490
|
-
key:
|
|
89958
|
+
identityText = z18.string().min(1).max(8e3);
|
|
89959
|
+
entrySchema2 = z18.object({
|
|
89960
|
+
key: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
89491
89961
|
threadId: identityText,
|
|
89492
89962
|
turnId: identityText,
|
|
89493
|
-
stage:
|
|
89963
|
+
stage: z18.enum(["admitted", "sent"])
|
|
89494
89964
|
}).strict();
|
|
89495
|
-
documentSchema2 =
|
|
89965
|
+
documentSchema2 = z18.object({ version: z18.literal(1), entries: z18.array(entrySchema2).max(4096) }).strict();
|
|
89496
89966
|
AsyncInputNotificationStore = class _AsyncInputNotificationStore {
|
|
89497
89967
|
constructor(journal, document) {
|
|
89498
89968
|
this.journal = journal;
|