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.js
CHANGED
|
@@ -8485,9 +8485,42 @@ function parseAttachmentTaskV2StatusQuery(value) {
|
|
|
8485
8485
|
return { ...parseAttachmentTaskStatusQuery(normalize(value, true)), version: 2 };
|
|
8486
8486
|
}
|
|
8487
8487
|
|
|
8488
|
+
// packages/protocol/src/thread-load-trace.ts
|
|
8489
|
+
var CLIENT_LOAD_PHASES = ["selected", "restored", "request_started", "snapshot_received", "history_ready", "content_presented"];
|
|
8490
|
+
function object8(value, required, optional = []) {
|
|
8491
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) throw new TypeError("invalid_load_report");
|
|
8492
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
8493
|
+
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");
|
|
8494
|
+
return value;
|
|
8495
|
+
}
|
|
8496
|
+
function timing(value) {
|
|
8497
|
+
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");
|
|
8498
|
+
}
|
|
8499
|
+
function parseThreadLoadReportV2(value) {
|
|
8500
|
+
const v = object8(value, ["version", "thread_id", "load_id", "client_class", "samples"], ["terminal"]);
|
|
8501
|
+
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");
|
|
8502
|
+
for (const sample of v.samples) {
|
|
8503
|
+
const s = object8(sample, ["phase", "elapsed_ms"], ["occurred_at_ms"]);
|
|
8504
|
+
timing(s);
|
|
8505
|
+
if (!CLIENT_LOAD_PHASES.includes(s.phase)) throw new TypeError("invalid_load_phase");
|
|
8506
|
+
}
|
|
8507
|
+
if (v.terminal !== void 0) {
|
|
8508
|
+
const t = object8(v.terminal, ["kind", "phase", "reason", "elapsed_ms"], ["occurred_at_ms"]);
|
|
8509
|
+
timing(t);
|
|
8510
|
+
const reasons = { failed: ["open_rejected", "history_failed"], cancelled: ["left_view", "user_cancelled"], superseded: ["stream_replaced"] };
|
|
8511
|
+
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");
|
|
8512
|
+
}
|
|
8513
|
+
return v;
|
|
8514
|
+
}
|
|
8515
|
+
function reduceThreadLoadOutcome(current2, event) {
|
|
8516
|
+
if (event === "closed" || event === "expired") return current2.status === "loading" ? { ...current2, status: "incomplete" } : current2;
|
|
8517
|
+
if (current2.status === "loading" || current2.status === "incomplete" && ["cancelled", "superseded"].includes(event)) return { ...current2, status: event };
|
|
8518
|
+
return current2.status === event ? current2 : { ...current2, conflict: true };
|
|
8519
|
+
}
|
|
8520
|
+
|
|
8488
8521
|
// apps/desktop/src/release-version.ts
|
|
8489
8522
|
function desktopReleaseVersion() {
|
|
8490
|
-
return false ? null : "0.0.1-beta.
|
|
8523
|
+
return false ? null : "0.0.1-beta.29";
|
|
8491
8524
|
}
|
|
8492
8525
|
var sourcePresenceVersion = (() => {
|
|
8493
8526
|
if (true) return null;
|
|
@@ -11986,6 +12019,59 @@ function discoverDirectGatewayOrigins(host, port, interfaces = networkInterfaces
|
|
|
11986
12019
|
// apps/desktop/src/daemon/launcher.ts
|
|
11987
12020
|
var BACKGROUND_DAEMON_STARTUP_TIMEOUT_MS = Math.max(6e4, desktopPlatform().daemon.startupTimeoutMs);
|
|
11988
12021
|
|
|
12022
|
+
// apps/desktop/src/daemon/runtime/ipc-thread-discovery.ts
|
|
12023
|
+
var RuntimeIpcThreadDiscovery = class {
|
|
12024
|
+
constructor(ports) {
|
|
12025
|
+
this.ports = ports;
|
|
12026
|
+
}
|
|
12027
|
+
ports;
|
|
12028
|
+
pending = /* @__PURE__ */ new Map();
|
|
12029
|
+
discover(id5) {
|
|
12030
|
+
const started2 = Date.now();
|
|
12031
|
+
const report = (phase) => {
|
|
12032
|
+
try {
|
|
12033
|
+
this.ports.diagnostic(id5, phase, Date.now() - started2);
|
|
12034
|
+
} catch {
|
|
12035
|
+
}
|
|
12036
|
+
};
|
|
12037
|
+
if (!this.ports.eligible(id5)) {
|
|
12038
|
+
report("ignored");
|
|
12039
|
+
return;
|
|
12040
|
+
}
|
|
12041
|
+
if (this.pending.has(id5)) {
|
|
12042
|
+
report("deduplicated");
|
|
12043
|
+
return;
|
|
12044
|
+
}
|
|
12045
|
+
if (this.pending.size >= 66) {
|
|
12046
|
+
report("capacity");
|
|
12047
|
+
return;
|
|
12048
|
+
}
|
|
12049
|
+
const current2 = this.ports.capture();
|
|
12050
|
+
report("received");
|
|
12051
|
+
const task = this.run(id5, current2, report).catch(() => report("failed")).finally(() => {
|
|
12052
|
+
if (this.pending.get(id5) === task) this.pending.delete(id5);
|
|
12053
|
+
});
|
|
12054
|
+
this.pending.set(id5, task);
|
|
12055
|
+
}
|
|
12056
|
+
async run(id5, current2, report) {
|
|
12057
|
+
const result = await this.ports.read(id5);
|
|
12058
|
+
report("read_completed");
|
|
12059
|
+
const valid = () => current2() && this.ports.eligible(id5) && result.kind === "ordinary" && result.summary?.id === id5 && !!result.token && this.ports.current(result.token);
|
|
12060
|
+
if (!valid()) {
|
|
12061
|
+
report("rejected");
|
|
12062
|
+
return;
|
|
12063
|
+
}
|
|
12064
|
+
await this.ports.enqueue(() => {
|
|
12065
|
+
if (!valid()) {
|
|
12066
|
+
report("stale");
|
|
12067
|
+
return;
|
|
12068
|
+
}
|
|
12069
|
+
this.ports.commit(result.summary);
|
|
12070
|
+
report("published");
|
|
12071
|
+
});
|
|
12072
|
+
}
|
|
12073
|
+
};
|
|
12074
|
+
|
|
11989
12075
|
// apps/desktop/src/daemon/async-question-response.ts
|
|
11990
12076
|
import { createHash } from "node:crypto";
|
|
11991
12077
|
function submissionId(input) {
|
|
@@ -14763,11 +14849,11 @@ var RuntimeActivityPublication = class {
|
|
|
14763
14849
|
if (!thread4) {
|
|
14764
14850
|
return null;
|
|
14765
14851
|
}
|
|
14766
|
-
const
|
|
14767
|
-
const timingFields =
|
|
14768
|
-
turnStartedAt:
|
|
14769
|
-
...
|
|
14770
|
-
...
|
|
14852
|
+
const timing2 = this.ports.turnTiming(signal.threadId, signal.turnId);
|
|
14853
|
+
const timingFields = timing2 ? {
|
|
14854
|
+
turnStartedAt: timing2.startedAt,
|
|
14855
|
+
...timing2.endedAt !== void 0 ? { turnEndedAt: timing2.endedAt } : {},
|
|
14856
|
+
...timing2.outcome !== void 0 ? { turnOutcome: timing2.outcome } : {}
|
|
14771
14857
|
} : {};
|
|
14772
14858
|
if (signal.type === "turn_aborted") {
|
|
14773
14859
|
return {
|
|
@@ -20297,7 +20383,7 @@ function fail14(reason) {
|
|
|
20297
20383
|
var clone = (value) => structuredClone(value);
|
|
20298
20384
|
var diskEntry = (entry) => ({ ...entry, nativeToken: entry.nativeToken !== null });
|
|
20299
20385
|
var byteSize = (value) => Buffer.byteLength(JSON.stringify(value));
|
|
20300
|
-
function
|
|
20386
|
+
function object9(value, keys3, optional = []) {
|
|
20301
20387
|
if (!value || typeof value !== "object" || Array.isArray(value)) return fail14("invalid");
|
|
20302
20388
|
const record25 = value;
|
|
20303
20389
|
if (Object.keys(record25).some((key) => !keys3.includes(key) && !optional.includes(key)) || !keys3.every((key) => Object.hasOwn(record25, key))) return fail14("invalid");
|
|
@@ -20331,7 +20417,7 @@ function parseReceipt(value, clientMessageId) {
|
|
|
20331
20417
|
return receipt;
|
|
20332
20418
|
}
|
|
20333
20419
|
function parsePost(value, clientMessageId) {
|
|
20334
|
-
const record25 =
|
|
20420
|
+
const record25 = object9(value, ["httpStatus", "code", "message", "data"]);
|
|
20335
20421
|
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");
|
|
20336
20422
|
if (record25.code === 0) {
|
|
20337
20423
|
if (record25.httpStatus !== 200) fail14("invalid");
|
|
@@ -20344,10 +20430,10 @@ function parsePost(value, clientMessageId) {
|
|
|
20344
20430
|
} else if (record25.data !== null) {
|
|
20345
20431
|
const data = record25.data;
|
|
20346
20432
|
if (data.state === "unknown") {
|
|
20347
|
-
|
|
20433
|
+
object9(data, ["client_message_id", "state"]);
|
|
20348
20434
|
if (data.client_message_id !== clientMessageId) fail14("invalid");
|
|
20349
20435
|
} else {
|
|
20350
|
-
|
|
20436
|
+
object9(data, ["dispatch_state"]);
|
|
20351
20437
|
if (data.dispatch_state !== "not_dispatched") fail14("invalid");
|
|
20352
20438
|
}
|
|
20353
20439
|
}
|
|
@@ -20380,13 +20466,13 @@ function parseDocument(raw, maxEntries) {
|
|
|
20380
20466
|
} catch {
|
|
20381
20467
|
return fail14("invalid");
|
|
20382
20468
|
}
|
|
20383
|
-
const document =
|
|
20469
|
+
const document = object9(value, ["version", "entries"]);
|
|
20384
20470
|
if (document.version !== 1 || !Array.isArray(document.entries)) fail14("invalid");
|
|
20385
20471
|
if (document.entries.length > maxEntries) fail14("capacity");
|
|
20386
20472
|
const entries = /* @__PURE__ */ new Map();
|
|
20387
20473
|
const nativeItems = /* @__PURE__ */ new Set();
|
|
20388
20474
|
for (const value2 of document.entries) {
|
|
20389
|
-
const record25 =
|
|
20475
|
+
const record25 = object9(value2, ["principal", "threadId", "clientMessageId", "fingerprint", "nativeToken", "receipt", "firstResult", "createdAt", "updatedAt"], ["questionId"]);
|
|
20390
20476
|
if (typeof record25.nativeToken !== "boolean" || !Number.isSafeInteger(record25.createdAt) || record25.createdAt < 0 || !Number.isSafeInteger(record25.updatedAt) || record25.updatedAt < 0) fail14("invalid");
|
|
20391
20477
|
const entry = { ...record25, nativeToken: record25.nativeToken ? record25.clientMessageId : null };
|
|
20392
20478
|
validateReservation(entry);
|
|
@@ -20478,7 +20564,7 @@ async function openMessageSubmissionStore(options) {
|
|
|
20478
20564
|
reserve(input) {
|
|
20479
20565
|
const captured = clone(input);
|
|
20480
20566
|
return enqueue(async () => {
|
|
20481
|
-
|
|
20567
|
+
object9(captured, ["principal", "threadId", "clientMessageId", "fingerprint", "nativeToken"], ["questionId"]);
|
|
20482
20568
|
validateReservation(captured);
|
|
20483
20569
|
const existing = entries.get(captured.clientMessageId);
|
|
20484
20570
|
if (existing) {
|
|
@@ -23728,8 +23814,8 @@ var AppServerTransport = class {
|
|
|
23728
23814
|
/** 慢响应只保留每分钟首条及抑制数;超时和协议失败仍逐次保留。 */
|
|
23729
23815
|
auditSlowResponse(id5, pending, bytes3, failed) {
|
|
23730
23816
|
if (!Number.isFinite(pending.startedAtMs)) return;
|
|
23731
|
-
const
|
|
23732
|
-
if (
|
|
23817
|
+
const timing2 = this.requestTiming(pending), now = performance.now();
|
|
23818
|
+
if (timing2.elapsedMs < 5e3) return;
|
|
23733
23819
|
if (now - this.lastSlowAuditAtMs < 6e4) {
|
|
23734
23820
|
this.suppressedSlowAudits++;
|
|
23735
23821
|
return;
|
|
@@ -23740,7 +23826,7 @@ var AppServerTransport = class {
|
|
|
23740
23826
|
...typeof id5 === "number" ? { requestId: id5 } : {},
|
|
23741
23827
|
...isSafeErrorAuditOperation(pending.method) ? { method: pending.method } : {},
|
|
23742
23828
|
bytes: bytes3,
|
|
23743
|
-
requestTiming:
|
|
23829
|
+
requestTiming: timing2,
|
|
23744
23830
|
responseDisposition: failed ? "error" : "success",
|
|
23745
23831
|
suppressedCount: this.suppressedSlowAudits
|
|
23746
23832
|
});
|
|
@@ -28051,7 +28137,7 @@ import { randomBytes as randomBytes3 } from "node:crypto";
|
|
|
28051
28137
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
28052
28138
|
function logicalDescriptor(descriptor) {
|
|
28053
28139
|
if (descriptor.pathname !== "/api/v1/thread/open") return descriptor;
|
|
28054
|
-
const { load_id: _loadId, range_resume_token: _rangeToken, ...query2 } = descriptor.query;
|
|
28140
|
+
const { load_id: _loadId, load_trace: _loadTrace, range_resume_token: _rangeToken, ...query2 } = descriptor.query;
|
|
28055
28141
|
return { pathname: descriptor.pathname, query: query2 };
|
|
28056
28142
|
}
|
|
28057
28143
|
function fail15(code, message) {
|
|
@@ -29320,6 +29406,11 @@ var AutostartError = class extends Error {
|
|
|
29320
29406
|
};
|
|
29321
29407
|
|
|
29322
29408
|
// apps/desktop/src/pairing-web/settings.ts
|
|
29409
|
+
function dispatchSettingsVersion(request2) {
|
|
29410
|
+
if (request2.url !== "/api/v1/settings/version" || request2.method !== "GET") throw new HttpApiError(404, 900005, "\u63A5\u53E3\u4E0D\u5B58\u5728");
|
|
29411
|
+
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");
|
|
29412
|
+
return { daemon_version: desktopPresenceVersion() };
|
|
29413
|
+
}
|
|
29323
29414
|
function projection(s) {
|
|
29324
29415
|
return {
|
|
29325
29416
|
supported: s.supported,
|
|
@@ -30253,8 +30344,7 @@ function invalidPushServerOrigin() {
|
|
|
30253
30344
|
function resolvePushServerOrigin(environment) {
|
|
30254
30345
|
const value = environment.NIUMA_PUSH_SERVER_ORIGIN;
|
|
30255
30346
|
if (value === void 0 || isBlankConfigValue(value)) {
|
|
30256
|
-
|
|
30257
|
-
return release2 ? DEFAULT_PUSH_PUBLIC_URL : resolveLocalServerOrigin(environment);
|
|
30347
|
+
return DEFAULT_PUSH_PUBLIC_URL;
|
|
30258
30348
|
}
|
|
30259
30349
|
if (URL_CONTROL_OR_SPACE_PATTERN.test(value)) {
|
|
30260
30350
|
throw invalidPushServerOrigin();
|
|
@@ -30357,6 +30447,20 @@ var ThreadLoadReportSchema = z8.object({
|
|
|
30357
30447
|
load_id: z8.string().uuid(),
|
|
30358
30448
|
samples: z8.array(LoadSampleSchema).min(1).max(6)
|
|
30359
30449
|
}).strict();
|
|
30450
|
+
var ThreadLoadReportV2Schema = z8.object({
|
|
30451
|
+
version: z8.literal(2),
|
|
30452
|
+
thread_id: z8.string().min(1).max(256),
|
|
30453
|
+
load_id: z8.string().uuid(),
|
|
30454
|
+
client_class: z8.enum(["web", "ios", "other"]),
|
|
30455
|
+
samples: z8.array(LoadSampleSchema).max(6),
|
|
30456
|
+
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()
|
|
30457
|
+
}).strict().superRefine((value, context) => {
|
|
30458
|
+
try {
|
|
30459
|
+
parseThreadLoadReportV2(value);
|
|
30460
|
+
} catch {
|
|
30461
|
+
context.addIssue({ code: "custom", message: "\u52A0\u8F7D\u91C7\u6837\u7EC4\u5408\u65E0\u6548" });
|
|
30462
|
+
}
|
|
30463
|
+
});
|
|
30360
30464
|
var LoadingTraceSchema = z8.object({
|
|
30361
30465
|
load_id: z8.string().uuid(),
|
|
30362
30466
|
lease_id: z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u),
|
|
@@ -30366,27 +30470,128 @@ var LoadingTraceSchema = z8.object({
|
|
|
30366
30470
|
occurred_at_ms: occurredAtSchema
|
|
30367
30471
|
}).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));
|
|
30368
30472
|
var ThreadLoadReports = class {
|
|
30369
|
-
constructor(now = Date.now) {
|
|
30473
|
+
constructor(now = Date.now, audit = () => void 0) {
|
|
30370
30474
|
this.now = now;
|
|
30475
|
+
this.audit = audit;
|
|
30371
30476
|
}
|
|
30372
30477
|
now;
|
|
30478
|
+
audit;
|
|
30373
30479
|
entries = /* @__PURE__ */ new Map();
|
|
30374
|
-
|
|
30480
|
+
used = /* @__PURE__ */ new Set();
|
|
30481
|
+
clear() {
|
|
30482
|
+
this.entries.clear();
|
|
30483
|
+
}
|
|
30484
|
+
begin(input) {
|
|
30375
30485
|
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
30376
|
-
if (!z8.string().uuid().safeParse(loadId).success || this.entries.size >= 256 || this.
|
|
30486
|
+
if (!z8.string().uuid().safeParse(input.loadId).success || this.entries.size >= 256 || this.used.size >= 1e4 || this.used.has(input.loadId)) return null;
|
|
30487
|
+
const id5 = input.loadId;
|
|
30488
|
+
const writer = this.audit();
|
|
30489
|
+
if (writer?.reserveLoadId && !writer.reserveLoadId(id5)) {
|
|
30490
|
+
this.used.add(id5);
|
|
30491
|
+
return null;
|
|
30492
|
+
}
|
|
30493
|
+
this.used.add(id5);
|
|
30494
|
+
const epoch = writer?.loadGeneration?.();
|
|
30495
|
+
let outcome = { status: "loading", conflict: false };
|
|
30496
|
+
let lease, trace;
|
|
30497
|
+
const entry = { threadId: input.threadId, owner: input.owner, expires: input.nowMs + 9e5, seen: /* @__PURE__ */ new Set(), record: () => {
|
|
30498
|
+
}, valid: () => this.entries.get(id5) === entry && writer?.loadGeneration?.() === epoch && this.now() <= entry.expires };
|
|
30499
|
+
const write = (record25) => {
|
|
30500
|
+
if (!entry.valid?.()) return;
|
|
30501
|
+
try {
|
|
30502
|
+
writer?.recordLoad?.({ ...record25, load_id: id5, thread_id: input.threadId, occurred_at_ms: this.now(), ...lease ? { lease_id: lease } : {}, ...trace ? { trace_id: trace } : {} });
|
|
30503
|
+
} catch {
|
|
30504
|
+
}
|
|
30377
30505
|
};
|
|
30378
|
-
const
|
|
30506
|
+
const end = (event) => {
|
|
30507
|
+
outcome = reduceThreadLoadOutcome(outcome, event);
|
|
30508
|
+
entry.expires = Math.min(entry.expires, this.now() + 3e4);
|
|
30509
|
+
};
|
|
30510
|
+
const elapsed = () => Math.max(0, Math.min(9e5, this.now() - input.nowMs));
|
|
30511
|
+
const handle = {
|
|
30512
|
+
markDaemon: (phase, elapsedMs, occurredAtMs = this.now()) => {
|
|
30513
|
+
if (!entry.valid?.() || entry.seen.has("daemon:" + phase)) return;
|
|
30514
|
+
entry.seen.add("daemon:" + phase);
|
|
30515
|
+
write({ record_type: "load_sample", clock: "daemon", phase, elapsed_ms: elapsedMs, event_at_ms: occurredAtMs });
|
|
30516
|
+
},
|
|
30517
|
+
attachLease: (leaseId, traceId) => {
|
|
30518
|
+
lease = leaseId;
|
|
30519
|
+
trace = traceId;
|
|
30520
|
+
},
|
|
30521
|
+
// 每种确定终态只记一次;保留不同证据供 reducer 标示冲突,不延长授权期限。
|
|
30522
|
+
finish: (kind, evidence = {}) => {
|
|
30523
|
+
if (!entry.valid?.() || entry.seen.has("terminal:" + kind)) return;
|
|
30524
|
+
entry.seen.add("terminal:" + kind);
|
|
30525
|
+
write({ record_type: "load_terminal", clock: "daemon", phase: kind, elapsed_ms: elapsed(), ...evidence });
|
|
30526
|
+
end(kind);
|
|
30527
|
+
},
|
|
30528
|
+
close: () => {
|
|
30529
|
+
if (!entry.valid?.() || entry.seen.has("closed")) return;
|
|
30530
|
+
entry.seen.add("closed");
|
|
30531
|
+
write({ record_type: "load_close", clock: "daemon", phase: "closed", elapsed_ms: elapsed() });
|
|
30532
|
+
end("closed");
|
|
30533
|
+
},
|
|
30534
|
+
outcome: () => outcome
|
|
30535
|
+
};
|
|
30536
|
+
entry.handle = handle;
|
|
30537
|
+
entry.accept = (samples, client, terminal) => {
|
|
30538
|
+
for (const sample of samples) if (!entry.seen.has("client:" + sample.phase)) {
|
|
30539
|
+
entry.seen.add("client:" + sample.phase);
|
|
30540
|
+
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 } : {} });
|
|
30541
|
+
if (sample.phase === "content_presented") end("presented");
|
|
30542
|
+
try {
|
|
30543
|
+
entry.record(sample);
|
|
30544
|
+
} catch {
|
|
30545
|
+
}
|
|
30546
|
+
}
|
|
30547
|
+
if (terminal && !entry.seen.has("terminal")) {
|
|
30548
|
+
entry.seen.add("terminal");
|
|
30549
|
+
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 } : {} });
|
|
30550
|
+
end(terminal.kind);
|
|
30551
|
+
}
|
|
30552
|
+
};
|
|
30553
|
+
this.entries.set(id5, entry);
|
|
30554
|
+
write({ record_type: "load_start", clock: "daemon", phase: "open_received", elapsed_ms: 0, source_transport: input.transport });
|
|
30555
|
+
return handle;
|
|
30556
|
+
}
|
|
30557
|
+
register(loadId, threadId2, owner2, record25, attempt) {
|
|
30558
|
+
for (const [key, value] of this.entries) if (value.expires < this.now()) this.entries.delete(key);
|
|
30559
|
+
const existing = this.entries.get(loadId);
|
|
30560
|
+
if (existing?.handle && existing.handle === attempt && existing.threadId === threadId2 && existing.owner === owner2) {
|
|
30561
|
+
existing.record = record25;
|
|
30562
|
+
return () => {
|
|
30563
|
+
};
|
|
30564
|
+
}
|
|
30565
|
+
if (!z8.string().uuid().safeParse(loadId).success || this.entries.size >= 256 || this.used.size >= 1e4 || this.entries.has(loadId) || this.used.has(loadId)) return () => {
|
|
30566
|
+
};
|
|
30567
|
+
const writer = this.audit(), epoch = writer?.loadGeneration?.();
|
|
30568
|
+
if (writer?.reserveLoadId && !writer.reserveLoadId(loadId)) {
|
|
30569
|
+
this.used.add(loadId);
|
|
30570
|
+
return () => {
|
|
30571
|
+
};
|
|
30572
|
+
}
|
|
30573
|
+
this.used.add(loadId);
|
|
30574
|
+
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 };
|
|
30379
30575
|
this.entries.set(loadId, entry);
|
|
30380
30576
|
return () => {
|
|
30381
30577
|
if (this.entries.get(loadId) === entry) this.entries.delete(loadId);
|
|
30382
30578
|
};
|
|
30383
30579
|
}
|
|
30384
30580
|
report(input, owner2) {
|
|
30385
|
-
|
|
30581
|
+
let parsed;
|
|
30582
|
+
try {
|
|
30583
|
+
parsed = input?.version === 2 ? { success: true, data: parseThreadLoadReportV2(input) } : ThreadLoadReportSchema.safeParse(input);
|
|
30584
|
+
} catch {
|
|
30585
|
+
parsed = { success: false };
|
|
30586
|
+
}
|
|
30386
30587
|
if (!parsed.success) return { accepted: false };
|
|
30387
30588
|
const { load_id, thread_id, samples } = parsed.data;
|
|
30388
30589
|
const entry = this.entries.get(load_id);
|
|
30389
|
-
if (!entry || entry.threadId !== thread_id || entry.owner !== owner2 || entry.expires < this.now()) return { accepted: false };
|
|
30590
|
+
if (!entry || entry.threadId !== thread_id || entry.owner !== owner2 || entry.expires < this.now() || entry.valid && !entry.valid()) return { accepted: false };
|
|
30591
|
+
if (entry.accept) {
|
|
30592
|
+
entry.accept(samples, parsed.data.client_class, parsed.data.terminal);
|
|
30593
|
+
return { accepted: true };
|
|
30594
|
+
}
|
|
30390
30595
|
for (const sample of samples) if (!entry.seen.has(sample.phase)) {
|
|
30391
30596
|
entry.seen.add(sample.phase);
|
|
30392
30597
|
try {
|
|
@@ -30613,6 +30818,8 @@ var ThreadOpenQuerySchema = z9.object({
|
|
|
30613
30818
|
range_resume_version: z9.literal("1").transform(() => 1).optional(),
|
|
30614
30819
|
range_resume_token: z9.string().regex(/^[A-Za-z0-9_-]{43}$/).optional(),
|
|
30615
30820
|
load_id: z9.string().uuid().optional(),
|
|
30821
|
+
// 恢复关联仍保留,只有首屏采样可显式关闭。
|
|
30822
|
+
load_trace: z9.literal("false").transform(() => false).optional(),
|
|
30616
30823
|
include_execution: z9.literal("true").transform(() => true).optional(),
|
|
30617
30824
|
include_message_times: z9.literal("true").transform(() => true).optional(),
|
|
30618
30825
|
include_async_questions: z9.literal("true").transform(() => true).optional(),
|
|
@@ -31733,6 +31940,7 @@ function createThreadOpenSseProjection(rawQuery, options = {}) {
|
|
|
31733
31940
|
...query2.range_resume_version ? { rangeResumeVersion: 1 } : {},
|
|
31734
31941
|
...query2.range_resume_token ? { rangeResumeToken: query2.range_resume_token } : {},
|
|
31735
31942
|
...query2.load_id ? { loadId: query2.load_id } : {},
|
|
31943
|
+
...query2.load_trace === false ? { loadTrace: false } : {},
|
|
31736
31944
|
viewVersion: THREAD_VIEW_VERSION,
|
|
31737
31945
|
...query2.include_async_questions ? { includeAsyncQuestions: true } : {},
|
|
31738
31946
|
...query2.include_read_receipts ? { includeReadReceipts: true } : {},
|
|
@@ -32767,7 +32975,7 @@ async function dispatchRestRoute(request2, dependencies) {
|
|
|
32767
32975
|
}
|
|
32768
32976
|
}
|
|
32769
32977
|
if (route === "POST /api/v1/thread/load/report") {
|
|
32770
|
-
const body = ThreadLoadReportSchema.parse(request2.body);
|
|
32978
|
+
const body = request2.body?.version === 2 ? ThreadLoadReportV2Schema.parse(request2.body) : ThreadLoadReportSchema.parse(request2.body);
|
|
32771
32979
|
const result = await daemonClient.request("thread/load/report", body, {
|
|
32772
32980
|
...daemonRequestOptions(5e3, request2.signal),
|
|
32773
32981
|
...request2.authenticatedMessageSubmissionScope !== void 0 ? { authenticatedMessageSubmissionScope: request2.authenticatedMessageSubmissionScope } : {}
|
|
@@ -42937,7 +43145,7 @@ var PairingWebServer = class {
|
|
|
42937
43145
|
const api = raw.startsWith("/api/");
|
|
42938
43146
|
authorizePairingRequest(request2, request2.socket.localPort, api);
|
|
42939
43147
|
if (api) {
|
|
42940
|
-
sendJson(response, 200, successResponse(await (raw.startsWith("/api/v1/settings/") && this.settings ? dispatchAutostartSettings(request2, this.settings) : dispatchPairingRoute(request2, this.service))));
|
|
43148
|
+
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))));
|
|
42941
43149
|
return;
|
|
42942
43150
|
}
|
|
42943
43151
|
const asset = ASSETS[raw];
|
|
@@ -43063,8 +43271,8 @@ function createRelayAttachmentDataLink(options) {
|
|
|
43063
43271
|
const child = { permit, lease: null, ws: null, receiver: null, closed: false, paired: false, ready: false, opening: null, cleanup: null, unregister: null };
|
|
43064
43272
|
children.set(permit.transfer_id, child);
|
|
43065
43273
|
const registrationStarted = Date.now();
|
|
43066
|
-
const
|
|
43067
|
-
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "started", ...
|
|
43274
|
+
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 });
|
|
43275
|
+
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "started", ...timing2() });
|
|
43068
43276
|
try {
|
|
43069
43277
|
const reply = await options.control.requestFileControl("file.register", {
|
|
43070
43278
|
version: 1,
|
|
@@ -43076,7 +43284,7 @@ function createRelayAttachmentDataLink(options) {
|
|
|
43076
43284
|
max_wire_bytes: attachmentTransferWireBudget(permit.context.byte_size)
|
|
43077
43285
|
});
|
|
43078
43286
|
if (reply.code !== 0) {
|
|
43079
|
-
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...
|
|
43287
|
+
recordAttachmentDiagnostic(options.diagnostic, { phase: "file.register", reason: "failed", code: reply.code, ...timing2() });
|
|
43080
43288
|
const error2 = unavailable7();
|
|
43081
43289
|
error2.cause = { stage: "file.register", relayCode: reply.code };
|
|
43082
43290
|
throw error2;
|
|
@@ -46641,7 +46849,7 @@ var RuntimeDesktopIngress = class {
|
|
|
46641
46849
|
resetMethodValidity() {
|
|
46642
46850
|
this.ipcMethodInvalidatedThreads.clear();
|
|
46643
46851
|
}
|
|
46644
|
-
async process(frame, ownClientId = this.ports.ipc()?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.ipcConnectionGeneration(),
|
|
46852
|
+
async process(frame, ownClientId = this.ports.ipc()?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.ipcConnectionGeneration(), timing2, readDiagnostic) {
|
|
46645
46853
|
this.ports.writeDebug({
|
|
46646
46854
|
component: "daemon",
|
|
46647
46855
|
channel: "ipc",
|
|
@@ -46651,7 +46859,7 @@ var RuntimeDesktopIngress = class {
|
|
|
46651
46859
|
attributes: {
|
|
46652
46860
|
type: frame.type,
|
|
46653
46861
|
...typeof frame.method === "string" ? { method: frame.method } : {},
|
|
46654
|
-
...
|
|
46862
|
+
...timing2
|
|
46655
46863
|
}
|
|
46656
46864
|
});
|
|
46657
46865
|
this.ports.writeRawDebug({
|
|
@@ -46683,6 +46891,9 @@ var RuntimeDesktopIngress = class {
|
|
|
46683
46891
|
}
|
|
46684
46892
|
const status2 = objectRecord(frame.params);
|
|
46685
46893
|
const methodThreadId = extractThreadIdFromIpcFrame(frame);
|
|
46894
|
+
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)) {
|
|
46895
|
+
this.ports.discoverThread(methodThreadId);
|
|
46896
|
+
}
|
|
46686
46897
|
if (frame.method === "thread-stream-state-changed" && methodThreadId && this.ipcMethodInvalidatedThreads.has(methodThreadId) && objectRecord(status2.change).type !== "snapshot") {
|
|
46687
46898
|
if (readDiagnostic) readDiagnostic.reason = "baseline_required";
|
|
46688
46899
|
return;
|
|
@@ -47338,19 +47549,19 @@ var DesktopIpcClient = class {
|
|
|
47338
47549
|
this.events.on("requestDiagnostic", listener);
|
|
47339
47550
|
return () => this.events.off("requestDiagnostic", listener);
|
|
47340
47551
|
}
|
|
47341
|
-
emitRequestDiagnostic(
|
|
47552
|
+
emitRequestDiagnostic(timing2, phase, outcome) {
|
|
47342
47553
|
this.events.emit("requestDiagnostic", {
|
|
47343
|
-
requestId:
|
|
47344
|
-
method:
|
|
47345
|
-
threadId:
|
|
47554
|
+
requestId: timing2.requestId,
|
|
47555
|
+
method: timing2.method,
|
|
47556
|
+
threadId: timing2.threadId,
|
|
47346
47557
|
phase,
|
|
47347
47558
|
outcome,
|
|
47348
|
-
durationMs: Math.max(0, Math.floor(performance.now() -
|
|
47559
|
+
durationMs: Math.max(0, Math.floor(performance.now() - timing2.startedAt))
|
|
47349
47560
|
});
|
|
47350
47561
|
}
|
|
47351
47562
|
pruneTimedOutRequests() {
|
|
47352
|
-
for (const [id5,
|
|
47353
|
-
if (performance.now() -
|
|
47563
|
+
for (const [id5, timing2] of this.timedOutRequests) {
|
|
47564
|
+
if (performance.now() - timing2.startedAt > 12e4) this.timedOutRequests.delete(id5);
|
|
47354
47565
|
}
|
|
47355
47566
|
while (this.timedOutRequests.size > 128) this.timedOutRequests.delete(this.timedOutRequests.keys().next().value);
|
|
47356
47567
|
}
|
|
@@ -47487,20 +47698,20 @@ var DesktopIpcClient = class {
|
|
|
47487
47698
|
this.pruneTimedOutRequests();
|
|
47488
47699
|
const localParams = params && typeof params === "object" ? params : {};
|
|
47489
47700
|
const threadId2 = typeof localParams.threadId === "string" ? localParams.threadId : typeof localParams.conversationId === "string" ? localParams.conversationId : void 0;
|
|
47490
|
-
const
|
|
47701
|
+
const timing2 = { requestId, method: method2, threadId: threadId2, startedAt: performance.now() };
|
|
47491
47702
|
const responsePromise = new Promise((resolve5, reject3) => {
|
|
47492
47703
|
const timer = setTimeout(() => {
|
|
47493
47704
|
this.pending.delete(requestId);
|
|
47494
|
-
this.timedOutRequests.set(requestId,
|
|
47705
|
+
this.timedOutRequests.set(requestId, timing2);
|
|
47495
47706
|
this.pruneTimedOutRequests();
|
|
47496
|
-
this.emitRequestDiagnostic(
|
|
47707
|
+
this.emitRequestDiagnostic(timing2, "timeout", "unknown");
|
|
47497
47708
|
reject3(new NiumaError("UNKNOWN_RESULT", `IPC \u8BF7\u6C42\u8D85\u65F6: ${method2}`, { method: method2 }));
|
|
47498
47709
|
}, options.timeoutMs ?? this.requestTimeoutMs);
|
|
47499
|
-
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing });
|
|
47710
|
+
this.pending.set(requestId, { timer, resolve: resolve5, reject: reject3, timing: timing2 });
|
|
47500
47711
|
});
|
|
47501
47712
|
try {
|
|
47502
47713
|
await this.write(frame);
|
|
47503
|
-
this.emitRequestDiagnostic(
|
|
47714
|
+
this.emitRequestDiagnostic(timing2, "sent", "pending");
|
|
47504
47715
|
} catch (error2) {
|
|
47505
47716
|
this.clearPending(requestId);
|
|
47506
47717
|
throw error2 instanceof Error ? new NiumaError("IPC_NOT_INITIALIZED", error2.message) : new NiumaError("IPC_NOT_INITIALIZED", String(error2));
|
|
@@ -47599,10 +47810,10 @@ var DesktopIpcClient = class {
|
|
|
47599
47810
|
this.pruneTimedOutRequests();
|
|
47600
47811
|
const outcome = frame.resultType === "error" ? "error" : "success";
|
|
47601
47812
|
if (!pending) {
|
|
47602
|
-
const
|
|
47603
|
-
if (
|
|
47813
|
+
const timing2 = this.timedOutRequests.get(requestId);
|
|
47814
|
+
if (timing2) {
|
|
47604
47815
|
this.timedOutRequests.delete(requestId);
|
|
47605
|
-
this.emitRequestDiagnostic(
|
|
47816
|
+
this.emitRequestDiagnostic(timing2, "late_response", outcome);
|
|
47606
47817
|
}
|
|
47607
47818
|
return;
|
|
47608
47819
|
}
|
|
@@ -56315,15 +56526,46 @@ function createHistoryHandlers(ports) {
|
|
|
56315
56526
|
if (negotiated && (!handoffScope || !scope || scope.bindingId !== handoffScope.bindingId)) {
|
|
56316
56527
|
throw new HttpApiError(200, 200004, "\u6B63\u6587\u4EA4\u63A5\u9700\u8981\u8BA4\u8BC1\u4F1A\u8BDD");
|
|
56317
56528
|
}
|
|
56529
|
+
const loadStartedAt = performance.now();
|
|
56530
|
+
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() });
|
|
56531
|
+
const loadElapsed = () => Math.max(0, Math.min(9e5, Math.round(performance.now() - loadStartedAt)));
|
|
56532
|
+
let loadFailurePhase = "open_received";
|
|
56533
|
+
const failOpen = (error2) => {
|
|
56534
|
+
if (!options.signal?.aborted && normalizeHttpError(error2).httpStatus === 200) loadAttempt?.finish("failed", { terminal_phase: loadFailurePhase, reason: "open_rejected" });
|
|
56535
|
+
};
|
|
56318
56536
|
if (negotiated && typeof params.handoffTicket === "string") {
|
|
56319
|
-
if (options.signal?.aborted || socket.destroyed || socket.writableEnded)
|
|
56320
|
-
|
|
56321
|
-
|
|
56322
|
-
|
|
56323
|
-
|
|
56324
|
-
|
|
56325
|
-
|
|
56326
|
-
|
|
56537
|
+
if (options.signal?.aborted || socket.destroyed || socket.writableEnded) {
|
|
56538
|
+
loadAttempt?.close();
|
|
56539
|
+
return STREAMING_RESPONSE;
|
|
56540
|
+
}
|
|
56541
|
+
let consumer;
|
|
56542
|
+
try {
|
|
56543
|
+
consumer = ports.connectionHandoff().claim(
|
|
56544
|
+
handoffScope,
|
|
56545
|
+
params.handoffDescriptor,
|
|
56546
|
+
params.handoffTicket,
|
|
56547
|
+
{ emit: (frame) => {
|
|
56548
|
+
socket.write(`${JSON.stringify(successEnvelope(frame))}
|
|
56549
|
+
`);
|
|
56550
|
+
if (frame.type === "thread_view_snapshot") {
|
|
56551
|
+
loadFailurePhase = "shell_sent";
|
|
56552
|
+
loadAttempt?.markDaemon("shell_sent", loadElapsed());
|
|
56553
|
+
}
|
|
56554
|
+
const view = frame.data;
|
|
56555
|
+
if (view?.availability?.state === "ready") {
|
|
56556
|
+
loadFailurePhase = "history_sent";
|
|
56557
|
+
loadAttempt?.markDaemon("history_sent", loadElapsed());
|
|
56558
|
+
}
|
|
56559
|
+
}, onClose: () => {
|
|
56560
|
+
loadAttempt?.close();
|
|
56561
|
+
socket.end();
|
|
56562
|
+
} }
|
|
56563
|
+
);
|
|
56564
|
+
} catch (error2) {
|
|
56565
|
+
failOpen(error2);
|
|
56566
|
+
loadAttempt?.close();
|
|
56567
|
+
throw error2;
|
|
56568
|
+
}
|
|
56327
56569
|
let recoveryClosed = false;
|
|
56328
56570
|
let unregisterRecovery2 = () => {
|
|
56329
56571
|
};
|
|
@@ -56336,12 +56578,14 @@ function createHistoryHandlers(ports) {
|
|
|
56336
56578
|
}) : () => {
|
|
56337
56579
|
};
|
|
56338
56580
|
} catch (error2) {
|
|
56581
|
+
loadAttempt?.close();
|
|
56339
56582
|
consumer.close();
|
|
56340
56583
|
throw error2;
|
|
56341
56584
|
}
|
|
56342
56585
|
let unregisterArchive2 = () => {
|
|
56343
56586
|
};
|
|
56344
56587
|
const close2 = () => {
|
|
56588
|
+
loadAttempt?.close();
|
|
56345
56589
|
unregisterArchive2();
|
|
56346
56590
|
recoveryClosed = true;
|
|
56347
56591
|
unregisterRecovery2();
|
|
@@ -56368,7 +56612,6 @@ function createHistoryHandlers(ports) {
|
|
|
56368
56612
|
`);
|
|
56369
56613
|
return STREAMING_RESPONSE;
|
|
56370
56614
|
}
|
|
56371
|
-
const loadStartedAt = performance.now();
|
|
56372
56615
|
let loadTrace = null;
|
|
56373
56616
|
let loadLeaseId = null;
|
|
56374
56617
|
let unregisterLoad = () => {
|
|
@@ -56378,7 +56621,9 @@ function createHistoryHandlers(ports) {
|
|
|
56378
56621
|
const pendingLoad = [];
|
|
56379
56622
|
const loadSeen = /* @__PURE__ */ new Set();
|
|
56380
56623
|
const recordLoad = (phase, clock = "daemon", elapsed = Math.round(performance.now() - loadStartedAt), occurredAt4 = clock === "daemon" ? Date.now() : void 0) => {
|
|
56381
|
-
if (
|
|
56624
|
+
if (clock === "daemon" && ["open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent"].includes(phase)) loadFailurePhase = phase;
|
|
56625
|
+
if (params.loadTrace === false || typeof params.loadId !== "string" || elapsed < 0 || elapsed > 9e5) return;
|
|
56626
|
+
if (clock === "daemon") loadAttempt?.markDaemon(phase, elapsed, occurredAt4);
|
|
56382
56627
|
if (!loadLeaseId) {
|
|
56383
56628
|
if (pendingLoad.length < 8) pendingLoad.push({ phase, elapsed, occurredAt: occurredAt4 });
|
|
56384
56629
|
return;
|
|
@@ -56467,6 +56712,7 @@ function createHistoryHandlers(ports) {
|
|
|
56467
56712
|
readReceiptTimer = null;
|
|
56468
56713
|
}
|
|
56469
56714
|
recordLoad("stream_closed");
|
|
56715
|
+
loadAttempt?.close();
|
|
56470
56716
|
unregisterLoad();
|
|
56471
56717
|
unregisterRecovery();
|
|
56472
56718
|
closed = true;
|
|
@@ -56503,6 +56749,7 @@ function createHistoryHandlers(ports) {
|
|
|
56503
56749
|
const close = () => {
|
|
56504
56750
|
if (physicalClosed) return;
|
|
56505
56751
|
physicalClosed = true;
|
|
56752
|
+
loadAttempt?.close();
|
|
56506
56753
|
unregisterRecovery();
|
|
56507
56754
|
options.signal?.removeEventListener("abort", close);
|
|
56508
56755
|
publisher?.close();
|
|
@@ -56519,7 +56766,14 @@ function createHistoryHandlers(ports) {
|
|
|
56519
56766
|
return STREAMING_RESPONSE;
|
|
56520
56767
|
}
|
|
56521
56768
|
if (!ports.store().getThread(threadId2, { tailCount: 0 })) {
|
|
56522
|
-
|
|
56769
|
+
try {
|
|
56770
|
+
await ports.verifyThreadForOpen(threadId2);
|
|
56771
|
+
} catch (error2) {
|
|
56772
|
+
failOpen(error2);
|
|
56773
|
+
loadAttempt?.close();
|
|
56774
|
+
detachClose();
|
|
56775
|
+
throw error2;
|
|
56776
|
+
}
|
|
56523
56777
|
}
|
|
56524
56778
|
if (closed || socketIsClosed()) {
|
|
56525
56779
|
closed = true;
|
|
@@ -56568,13 +56822,15 @@ function createHistoryHandlers(ports) {
|
|
|
56568
56822
|
}
|
|
56569
56823
|
for (const sample of pendingLoad) recordLoad(sample.phase, "daemon", sample.elapsed, sample.occurredAt);
|
|
56570
56824
|
pendingLoad.length = 0;
|
|
56825
|
+
if (loadLeaseId && loadTrace) loadAttempt?.attachLease(loadLeaseId, loadTrace.traceId);
|
|
56571
56826
|
recordLoad("lease_acquired");
|
|
56572
56827
|
try {
|
|
56573
|
-
if (loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
56828
|
+
if (loadAttempt && loadLeaseId && loadTrace) unregisterLoad = ports.threadLoadReports().register(
|
|
56574
56829
|
params.loadId,
|
|
56575
56830
|
threadId2,
|
|
56576
56831
|
scope ? `binding:${scope.bindingId.toLowerCase()}` : "local",
|
|
56577
|
-
(sample) => recordLoad(sample.phase, "browser", sample.elapsed_ms, sample.occurred_at_ms)
|
|
56832
|
+
(sample) => recordLoad(sample.phase, "browser", sample.elapsed_ms, sample.occurred_at_ms),
|
|
56833
|
+
loadAttempt
|
|
56578
56834
|
);
|
|
56579
56835
|
} catch {
|
|
56580
56836
|
}
|
|
@@ -56688,6 +56944,7 @@ function createHistoryHandlers(ports) {
|
|
|
56688
56944
|
ports.requestThreadAuthorityRecovery(threadId2, true);
|
|
56689
56945
|
ports.history().onHistoryLeaseStateChanged(threadId2, ports.activeThreadFollowerCoordinator()?.leaseKindsFor(threadId2) ?? []);
|
|
56690
56946
|
unsubscribeHistoryWindow = historyWindow.subscribe(() => {
|
|
56947
|
+
if (historyWindow?.initialWindowState === "failed") loadAttempt?.finish("failed", { terminal_phase: "shell_sent", reason: "history_failed" });
|
|
56691
56948
|
if (rangeClaim && historyWindow?.initialWindowState === "failed") {
|
|
56692
56949
|
socket.write(`${JSON.stringify(errorEnvelope(new NiumaError("HISTORY_SNAPSHOT_EXPIRED", "\u5386\u53F2\u6062\u590D\u8303\u56F4\u4E0D\u53EF\u7528\u6216\u5DF2\u8FC7\u671F")))}
|
|
56693
56950
|
`);
|
|
@@ -56762,6 +57019,7 @@ function createHistoryHandlers(ports) {
|
|
|
56762
57019
|
`);
|
|
56763
57020
|
}
|
|
56764
57021
|
} catch (error2) {
|
|
57022
|
+
failOpen(error2);
|
|
56765
57023
|
try {
|
|
56766
57024
|
const sites = [
|
|
56767
57025
|
["historySourceAssertion", "Object.sourceCurrent"],
|
|
@@ -56833,20 +57091,20 @@ function text10(value) {
|
|
|
56833
57091
|
return false;
|
|
56834
57092
|
}
|
|
56835
57093
|
}
|
|
56836
|
-
function
|
|
57094
|
+
function object10(value, keys3) {
|
|
56837
57095
|
if (!value || typeof value !== "object" || Array.isArray(value) || ![Object.prototype, null].includes(Object.getPrototypeOf(value))) return fail16("invalid");
|
|
56838
57096
|
const own = Reflect.ownKeys(value);
|
|
56839
57097
|
if (own.length !== keys3.length || !own.every((key) => typeof key === "string" && keys3.includes(key) && "value" in Object.getOwnPropertyDescriptor(value, key))) return fail16("invalid");
|
|
56840
57098
|
return value;
|
|
56841
57099
|
}
|
|
56842
57100
|
function parseAsyncQuestionBatch(value) {
|
|
56843
|
-
const raw =
|
|
57101
|
+
const raw = object10(value, ["thread_id", "group_id", "revision", "idempotency_key", "question_ids", "answers"]);
|
|
56844
57102
|
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");
|
|
56845
57103
|
const questionIds = Array.from(raw.question_ids);
|
|
56846
57104
|
if (!questionIds.every(id3) || new Set(questionIds).size !== questionIds.length) return fail16("invalid");
|
|
56847
57105
|
const seen = /* @__PURE__ */ new Set();
|
|
56848
57106
|
const answers = Array.from(raw.answers, (value2) => {
|
|
56849
|
-
const answer =
|
|
57107
|
+
const answer = object10(value2, ["question_id", "title", "answer"]);
|
|
56850
57108
|
if (!id3(answer.question_id) || !questionIds.includes(answer.question_id) || seen.has(answer.question_id) || !text10(answer.title) || !text10(answer.answer)) return fail16("invalid");
|
|
56851
57109
|
seen.add(answer.question_id);
|
|
56852
57110
|
return { question_id: answer.question_id, title: answer.title, answer: answer.answer };
|
|
@@ -59635,10 +59893,10 @@ var ThreadHistoryWindowLoader = class {
|
|
|
59635
59893
|
sourceRevision: 0
|
|
59636
59894
|
};
|
|
59637
59895
|
for (let attempt = 0; attempt < 2; attempt++) {
|
|
59638
|
-
const
|
|
59896
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
59639
59897
|
this.assertSource(epoch);
|
|
59640
59898
|
signal.throwIfAborted();
|
|
59641
|
-
const versionKey = JSON.stringify([epoch, description.contentVersion,
|
|
59899
|
+
const versionKey = JSON.stringify([epoch, description.contentVersion, timing2]);
|
|
59642
59900
|
let cached = this.turns.get(identity6);
|
|
59643
59901
|
if (cached?.current?.version === versionKey) {
|
|
59644
59902
|
if (description.sourceRevision >= cached.sourceRevision && cached.nativeOrder !== description.nativeOrder) {
|
|
@@ -59655,7 +59913,7 @@ var ThreadHistoryWindowLoader = class {
|
|
|
59655
59913
|
this.assertSource(epoch);
|
|
59656
59914
|
signal.throwIfAborted();
|
|
59657
59915
|
if (enriched.turnId !== turn.id) throw new RangeError("\u7A97\u53E3\u65F6\u95F4\u8865\u9F50 Turn \u8EAB\u4EFD\u4E0D\u5339\u914D");
|
|
59658
|
-
if (await this.timestampVersion(turn, signal) !==
|
|
59916
|
+
if (await this.timestampVersion(turn, signal) !== timing2) continue;
|
|
59659
59917
|
this.assertSource(epoch);
|
|
59660
59918
|
signal.throwIfAborted();
|
|
59661
59919
|
const freeze = (value) => {
|
|
@@ -59713,11 +59971,11 @@ var ThreadHistoryWindowLoader = class {
|
|
|
59713
59971
|
const epoch = this.sourceEpoch;
|
|
59714
59972
|
this.currentProtection.addTurnIds([turn.id]);
|
|
59715
59973
|
const description = this.reader.describeTurn?.(turn) ?? { contentVersion: createHash26("sha256").update(JSON.stringify(turn)).digest("hex") };
|
|
59716
|
-
const
|
|
59974
|
+
const timing2 = await this.timestampVersion(turn, signal);
|
|
59717
59975
|
this.assertSource(epoch);
|
|
59718
59976
|
signal.throwIfAborted();
|
|
59719
59977
|
const cached = this.turns.get(JSON.stringify([this.currentThreadId, turn.id]));
|
|
59720
|
-
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion,
|
|
59978
|
+
if (cached?.current?.version === JSON.stringify([epoch, description.contentVersion, timing2])) {
|
|
59721
59979
|
this.holdVersion(this.currentProtection, cached.current);
|
|
59722
59980
|
return cached.current.projection.displayItemCount;
|
|
59723
59981
|
}
|
|
@@ -60937,17 +61195,17 @@ var AppServerThreadViewAdapter = class {
|
|
|
60937
61195
|
lastError: null
|
|
60938
61196
|
}).status;
|
|
60939
61197
|
const terminalStatus = failed || aborted || status2 === "completed" ? lifecycleStatus : "completed";
|
|
60940
|
-
const
|
|
61198
|
+
const timing2 = context.getTurnLifecycle?.(turnId);
|
|
60941
61199
|
return [{
|
|
60942
61200
|
type: "ThreadStatusChanged",
|
|
60943
61201
|
thread_id: context.threadId,
|
|
60944
61202
|
status: terminalStatus,
|
|
60945
61203
|
turn_id: turnId,
|
|
60946
61204
|
terminal_item_state: terminalStatus === "error" ? "failed" : "completed",
|
|
60947
|
-
...
|
|
60948
|
-
startedAt: lifecycleTime(
|
|
60949
|
-
endedAt: lifecycleTime(
|
|
60950
|
-
outcome:
|
|
61205
|
+
...timing2 ? { process_lifecycle: {
|
|
61206
|
+
startedAt: lifecycleTime(timing2.startedAt),
|
|
61207
|
+
endedAt: lifecycleTime(timing2.endedAt),
|
|
61208
|
+
outcome: timing2.outcome
|
|
60951
61209
|
} } : {},
|
|
60952
61210
|
last_error: terminalStatus === "error" ? {
|
|
60953
61211
|
code: 900001,
|
|
@@ -61202,10 +61460,10 @@ var ThreadHistoryWindowProjection = class {
|
|
|
61202
61460
|
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);
|
|
61203
61461
|
const timingById = new Map(sources.map((source2, index) => [source2.id, enriched[index]]));
|
|
61204
61462
|
const items = projected.items.map((item) => {
|
|
61205
|
-
const
|
|
61463
|
+
const timing2 = timingById.get(item.id);
|
|
61206
61464
|
const fact = item.process_fact;
|
|
61207
|
-
if (!
|
|
61208
|
-
const merged = mergeThreadHistoryTimelineLifecycle(
|
|
61465
|
+
if (!timing2 || !fact) return item;
|
|
61466
|
+
const merged = mergeThreadHistoryTimelineLifecycle(timing2, {
|
|
61209
61467
|
...fact.startedAt !== null ? { turnStartedAt: fact.startedAt } : {},
|
|
61210
61468
|
...fact.endedAt !== null ? { turnEndedAt: fact.endedAt } : {},
|
|
61211
61469
|
...fact.durationMs != null ? { turnDurationMs: fact.durationMs } : {},
|
|
@@ -62054,7 +62312,7 @@ function readStateDiagnostic(before, after, candidate = after.confirmed) {
|
|
|
62054
62312
|
sameCycle: candidate ? candidate.cycle === after.cycle : null
|
|
62055
62313
|
};
|
|
62056
62314
|
}
|
|
62057
|
-
function
|
|
62315
|
+
function object11(value) {
|
|
62058
62316
|
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
62059
62317
|
}
|
|
62060
62318
|
function field(value, present, count) {
|
|
@@ -62064,15 +62322,15 @@ function field(value, present, count) {
|
|
|
62064
62322
|
}
|
|
62065
62323
|
function unreadFrameDiagnostic(frame) {
|
|
62066
62324
|
if (frame.method !== "thread-stream-state-changed") return null;
|
|
62067
|
-
const params =
|
|
62325
|
+
const params = object11(frame.params), change = object11(params.change);
|
|
62068
62326
|
const kind = change.type === "snapshot" ? "snapshot" : change.type === "patches" ? "patch" : "invalid";
|
|
62069
|
-
const values = kind === "snapshot" ?
|
|
62327
|
+
const values = kind === "snapshot" ? object11(change.conversationState) : {};
|
|
62070
62328
|
let unread = field(values.hasUnreadTurn, Object.hasOwn(values, "hasUnreadTurn"), false);
|
|
62071
62329
|
let count = field(values.unreadMessageCount, Object.hasOwn(values, "unreadMessageCount"), true);
|
|
62072
62330
|
let countValue = values.unreadMessageCount;
|
|
62073
62331
|
if (kind === "patch") {
|
|
62074
62332
|
for (const value of Array.isArray(change.patches) ? change.patches : []) {
|
|
62075
|
-
const patch =
|
|
62333
|
+
const patch = object11(value), path54 = Array.isArray(patch.path) ? patch.path : [];
|
|
62076
62334
|
const name2 = path54.length === 1 ? path54[0] : path54.length === 2 && path54[0] === "conversationState" ? path54[1] : null;
|
|
62077
62335
|
if (name2 !== "hasUnreadTurn" && name2 !== "unreadMessageCount") continue;
|
|
62078
62336
|
const state = patch.op === "remove" ? "removed" : ["add", "replace"].includes(String(patch.op)) ? field(patch.value, Object.hasOwn(patch, "value"), name2 === "unreadMessageCount") : "invalid";
|
|
@@ -62114,10 +62372,10 @@ var RuntimeIngressDispatch = class {
|
|
|
62114
62372
|
}
|
|
62115
62373
|
ports;
|
|
62116
62374
|
/** 单帧入站与最终结果成对记录;原始字段与业务结果分开,拒绝帧同样留证。 */
|
|
62117
|
-
async handleIpcFrame(frame, ownClientId = this.ports.desktopSession().ipcValue?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.desktopSession().ipcConnectionGenerationValue,
|
|
62375
|
+
async handleIpcFrame(frame, ownClientId = this.ports.desktopSession().ipcValue?.getClientId?.() ?? null, receivedIpcGeneration = this.ports.desktopSession().ipcConnectionGenerationValue, timing2) {
|
|
62118
62376
|
const attributes = this.ports.options().debugLogger ? unreadFrameDiagnostic(frame) : null;
|
|
62119
62377
|
const threadId2 = attributes ? extractThreadIdFromIpcFrame(frame) : null;
|
|
62120
|
-
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
62378
|
+
if (!attributes || !threadId2) return this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2);
|
|
62121
62379
|
const before = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 })?.unread;
|
|
62122
62380
|
const diagnostic = { reason: "processed" };
|
|
62123
62381
|
const metadata = { ...attributes, sequence: this.ports.diagnostics().threadReadDiagnosticSequenceValue++, generation: receivedIpcGeneration, currentGeneration: this.ports.desktopSession().ipcConnectionGenerationValue };
|
|
@@ -62130,7 +62388,7 @@ var RuntimeIngressDispatch = class {
|
|
|
62130
62388
|
}
|
|
62131
62389
|
});
|
|
62132
62390
|
try {
|
|
62133
|
-
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration,
|
|
62391
|
+
await this.ports.desktopIngress().process(frame, ownClientId, receivedIpcGeneration, timing2, diagnostic);
|
|
62134
62392
|
} catch (error2) {
|
|
62135
62393
|
diagnostic.reason = "processing_failed";
|
|
62136
62394
|
throw error2;
|
|
@@ -63858,11 +64116,11 @@ var RuntimeProjectionContext = class {
|
|
|
63858
64116
|
} : null),
|
|
63859
64117
|
enrichTimelineItemTiming: (item) => this.ports.timelinePublication().enrichTimelineItemTiming(item, timelineItems),
|
|
63860
64118
|
getTurnLifecycle: (turnId) => {
|
|
63861
|
-
const
|
|
63862
|
-
return
|
|
63863
|
-
startedAt:
|
|
63864
|
-
endedAt:
|
|
63865
|
-
outcome:
|
|
64119
|
+
const timing2 = this.ports.timelinePublication().turnTiming(threadId2, turnId);
|
|
64120
|
+
return timing2 ? {
|
|
64121
|
+
startedAt: timing2.startedAt,
|
|
64122
|
+
endedAt: timing2.endedAt ?? null,
|
|
64123
|
+
outcome: timing2.outcome ?? null
|
|
63866
64124
|
} : null;
|
|
63867
64125
|
},
|
|
63868
64126
|
resolveKnownLocalImage: (sourcePath, itemId, partIndex) => this.ports.resolveThreadViewImage(threadId2, sourcePath, () => this.ports.isCurrentAppServerAsyncFence(threadId2, fence), itemId, partIndex)
|
|
@@ -64391,7 +64649,7 @@ var DesktopThreadSettingsTracker = class {
|
|
|
64391
64649
|
|
|
64392
64650
|
// apps/desktop/src/daemon/active-thread-follower-coordinator.ts
|
|
64393
64651
|
init_session_history_file();
|
|
64394
|
-
var ACTIVE_THREAD_SCAN_INTERVAL_MS =
|
|
64652
|
+
var ACTIVE_THREAD_SCAN_INTERVAL_MS = 6e4;
|
|
64395
64653
|
var ACTIVE_THREAD_READ_CONCURRENCY = 4;
|
|
64396
64654
|
var ACTIVE_FOLLOWER_SNAPSHOT_TIMEOUT_MS = 12e3;
|
|
64397
64655
|
var ACTIVE_FOLLOWER_RETRY_DELAYS_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
|
|
@@ -71373,7 +71631,7 @@ var RuntimeThreadStateCoordination = class {
|
|
|
71373
71631
|
return token3;
|
|
71374
71632
|
}
|
|
71375
71633
|
/** 仅供已核验的同轮终态使用;同时收敛列表与详情,不伪造新的完成通知。 */
|
|
71376
|
-
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message,
|
|
71634
|
+
applyRecoveredTerminal(threadId2, turnId, outcome, occurredAt4, message, timing2) {
|
|
71377
71635
|
const previous = this.ports.catalog().storeValue.getThread(threadId2, { tailCount: 0 });
|
|
71378
71636
|
const mutation = this.ports.catalog().storeValue.applyActivitySignal({
|
|
71379
71637
|
type: "snapshot",
|
|
@@ -71393,7 +71651,7 @@ var RuntimeThreadStateCoordination = class {
|
|
|
71393
71651
|
turn_id: turnId,
|
|
71394
71652
|
status: outcome === "aborted" ? "idle" : outcome === "failed" ? "error" : "completed",
|
|
71395
71653
|
terminal_item_state: outcome === "failed" ? "failed" : "completed",
|
|
71396
|
-
process_lifecycle: { startedAt:
|
|
71654
|
+
process_lifecycle: { startedAt: timing2?.startedAt ?? null, endedAt: timing2?.endedAt ?? null, outcome },
|
|
71397
71655
|
last_error: outcome === "failed" && message ? { code: 900001, message, occurred_at: occurredAt4, turn_id: turnId } : null
|
|
71398
71656
|
},
|
|
71399
71657
|
{ type: "ThreadActivityChanged", thread_id: threadId2, turn_id: turnId, activity: null },
|
|
@@ -71632,15 +71890,15 @@ var RuntimeTimelinePublication = class {
|
|
|
71632
71890
|
if (!item.turnId) {
|
|
71633
71891
|
return item;
|
|
71634
71892
|
}
|
|
71635
|
-
const
|
|
71636
|
-
if (!
|
|
71893
|
+
const timing2 = this.liveTurnTimings.get(this.turnTimingKey(item.threadId, item.turnId));
|
|
71894
|
+
if (!timing2) {
|
|
71637
71895
|
return item;
|
|
71638
71896
|
}
|
|
71639
71897
|
return {
|
|
71640
71898
|
...item,
|
|
71641
|
-
...item.turnStartedAt === void 0 ? { turnStartedAt:
|
|
71642
|
-
...item.turnEndedAt === void 0 &&
|
|
71643
|
-
...item.turnOutcome === void 0 &&
|
|
71899
|
+
...item.turnStartedAt === void 0 ? { turnStartedAt: timing2.startedAt } : {},
|
|
71900
|
+
...item.turnEndedAt === void 0 && timing2.endedAt !== void 0 ? { turnEndedAt: timing2.endedAt } : {},
|
|
71901
|
+
...item.turnOutcome === void 0 && timing2.outcome !== void 0 ? { turnOutcome: timing2.outcome } : {}
|
|
71644
71902
|
};
|
|
71645
71903
|
}
|
|
71646
71904
|
enrichTimelineItemTiming(item, historyItems = []) {
|
|
@@ -71660,9 +71918,9 @@ var RuntimeTimelinePublication = class {
|
|
|
71660
71918
|
turnTimingKey(threadId2, turnId) {
|
|
71661
71919
|
return `${threadId2}:${turnId}`;
|
|
71662
71920
|
}
|
|
71663
|
-
setLiveTurnTiming(key,
|
|
71921
|
+
setLiveTurnTiming(key, timing2) {
|
|
71664
71922
|
this.liveTurnTimings.delete(key);
|
|
71665
|
-
this.liveTurnTimings.set(key,
|
|
71923
|
+
this.liveTurnTimings.set(key, timing2);
|
|
71666
71924
|
while (this.liveTurnTimings.size > LIVE_TURN_TIMING_LIMIT) {
|
|
71667
71925
|
const oldestKey = this.liveTurnTimings.keys().next().value;
|
|
71668
71926
|
if (typeof oldestKey !== "string") break;
|
|
@@ -79785,8 +80043,7 @@ var RuntimeNativeAdmission = class {
|
|
|
79785
80043
|
else if (kind === "ordinary") this.hidden.delete(thread4.id);
|
|
79786
80044
|
const old = this.entries.get(thread4.id);
|
|
79787
80045
|
this.failures.delete(thread4.id);
|
|
79788
|
-
|
|
79789
|
-
const token3 = { threadId: thread4.id, generation: ++this.sequence, executionGeneration };
|
|
80046
|
+
const token3 = old && old.kind === kind ? old.token : { threadId: thread4.id, generation: ++this.sequence, executionGeneration };
|
|
79790
80047
|
this.entries.set(thread4.id, { token: token3, kind });
|
|
79791
80048
|
try {
|
|
79792
80049
|
if (kind !== previous) this.ports.onChange?.(thread4.id, previous, kind);
|
|
@@ -79796,7 +80053,7 @@ var RuntimeNativeAdmission = class {
|
|
|
79796
80053
|
}
|
|
79797
80054
|
const pending = this.jobs.get(thread4.id);
|
|
79798
80055
|
if (pending) {
|
|
79799
|
-
this.finishWait(pending, kind);
|
|
80056
|
+
this.finishWait(pending, kind, thread4, token3);
|
|
79800
80057
|
if (!pending.started) {
|
|
79801
80058
|
this.removeQueued(pending);
|
|
79802
80059
|
this.removeJob(pending);
|
|
@@ -79804,13 +80061,20 @@ var RuntimeNativeAdmission = class {
|
|
|
79804
80061
|
}
|
|
79805
80062
|
return token3;
|
|
79806
80063
|
}
|
|
79807
|
-
ensure(id5, executionGeneration) {
|
|
79808
|
-
|
|
80064
|
+
async ensure(id5, executionGeneration) {
|
|
80065
|
+
return (await this.query(id5, executionGeneration, false)).kind;
|
|
80066
|
+
}
|
|
80067
|
+
/** 目录缺项时请求摘要,与未知准入共用单飞、退避和物理槽。 */
|
|
80068
|
+
ensureSummary(id5, executionGeneration) {
|
|
80069
|
+
return this.query(id5, executionGeneration, true);
|
|
80070
|
+
}
|
|
80071
|
+
query(id5, executionGeneration, needSummary) {
|
|
80072
|
+
if (executionGeneration !== this.execution) return Promise.resolve({ kind: "unknown" });
|
|
79809
80073
|
const known = this.kind(id5);
|
|
79810
|
-
if (known !== "unknown") return Promise.resolve(known);
|
|
80074
|
+
if (known !== "unknown" && (!needSummary || known === "subagent")) return Promise.resolve({ kind: known });
|
|
79811
80075
|
const pending = this.jobs.get(id5);
|
|
79812
|
-
if (pending) return pending.execution === this.execution ? pending.promise : Promise.resolve("unknown");
|
|
79813
|
-
if ((this.failures.get(id5) ?? 0) > this.now() || this.queue.length >= 64) return Promise.resolve("unknown");
|
|
80076
|
+
if (pending) return pending.execution === this.execution ? pending.promise : Promise.resolve({ kind: "unknown" });
|
|
80077
|
+
if ((this.failures.get(id5) ?? 0) > this.now() || this.queue.length >= 64) return Promise.resolve({ kind: "unknown" });
|
|
79814
80078
|
let resolve5;
|
|
79815
80079
|
const promise = new Promise((done) => {
|
|
79816
80080
|
resolve5 = done;
|
|
@@ -79867,11 +80131,11 @@ var RuntimeNativeAdmission = class {
|
|
|
79867
80131
|
removeJob(job) {
|
|
79868
80132
|
if (this.jobs.get(job.id) === job) this.jobs.delete(job.id);
|
|
79869
80133
|
}
|
|
79870
|
-
finishWait(job, kind) {
|
|
80134
|
+
finishWait(job, kind, summary, token3) {
|
|
79871
80135
|
if (job.settled) return;
|
|
79872
80136
|
job.settled = true;
|
|
79873
80137
|
job.cancel();
|
|
79874
|
-
job.resolve(kind);
|
|
80138
|
+
job.resolve({ kind, ...summary ? { summary, token: token3 } : {} });
|
|
79875
80139
|
}
|
|
79876
80140
|
fail(job) {
|
|
79877
80141
|
if (job.execution === this.execution) {
|
|
@@ -79905,7 +80169,7 @@ var RuntimeNativeAdmission = class {
|
|
|
79905
80169
|
this.observe(result.thread, job.execution);
|
|
79906
80170
|
const kind = this.kind(job.id);
|
|
79907
80171
|
if (kind === "unknown") this.fail(job);
|
|
79908
|
-
this.finishWait(job, kind);
|
|
80172
|
+
this.finishWait(job, kind, result.thread, this.token(job.id));
|
|
79909
80173
|
}).catch(() => {
|
|
79910
80174
|
if (!job.settled) {
|
|
79911
80175
|
this.fail(job);
|
|
@@ -80268,6 +80532,7 @@ var DEBUG_EVENTS = [
|
|
|
80268
80532
|
"ipc_recovery",
|
|
80269
80533
|
"ipc_forwarding_flow",
|
|
80270
80534
|
"notification_delivery",
|
|
80535
|
+
"ipc_thread_discovery",
|
|
80271
80536
|
"startup_timing",
|
|
80272
80537
|
"thread_settings_cache",
|
|
80273
80538
|
"thread_list_cache",
|
|
@@ -80501,6 +80766,7 @@ var SAFE_ATTRIBUTE_KEYS = {
|
|
|
80501
80766
|
"inFlight"
|
|
80502
80767
|
],
|
|
80503
80768
|
// 启动性能仅保留固定阶段耗时和汇总计数,禁止记录路径、会话或异常原文。
|
|
80769
|
+
ipc_thread_discovery: ["durationMs"],
|
|
80504
80770
|
startup_timing: [
|
|
80505
80771
|
"durationMs",
|
|
80506
80772
|
"threadCount",
|
|
@@ -81050,6 +81316,7 @@ var SAFE_PHASES = {
|
|
|
81050
81316
|
"dropped_busy",
|
|
81051
81317
|
"deadline_expired"
|
|
81052
81318
|
],
|
|
81319
|
+
ipc_thread_discovery: ["received", "ignored", "deduplicated", "capacity", "read_completed", "rejected", "stale", "published", "failed"],
|
|
81053
81320
|
startup_timing: [
|
|
81054
81321
|
"app_server_initialized",
|
|
81055
81322
|
"thread_baseline_scanned",
|
|
@@ -81743,19 +82010,19 @@ function withoutPersistentImageBytes(value, key = "", seen = /* @__PURE__ */ new
|
|
|
81743
82010
|
if (seen.has(value)) return "[circular]";
|
|
81744
82011
|
seen.add(value);
|
|
81745
82012
|
try {
|
|
81746
|
-
const
|
|
81747
|
-
if (
|
|
81748
|
-
return { type: "binary_omitted", byteSize:
|
|
82013
|
+
const object12 = value;
|
|
82014
|
+
if (object12.type === "Buffer" && Array.isArray(object12.data)) {
|
|
82015
|
+
return { type: "binary_omitted", byteSize: object12.data.length };
|
|
81749
82016
|
}
|
|
81750
|
-
if (
|
|
81751
|
-
const payload =
|
|
81752
|
-
const metadata = Object.fromEntries(Object.entries(
|
|
82017
|
+
if (object12.event === "app_server_stdout") {
|
|
82018
|
+
const payload = object12.rawPayload;
|
|
82019
|
+
const metadata = Object.fromEntries(Object.entries(object12).filter(([name2]) => name2 !== "rawPayload").map(([name2, entry]) => [name2, withoutPersistentImageBytes(entry, name2, seen)]));
|
|
81753
82020
|
return { ...metadata, rawPayload: { type: "stdout_fragment", bytes: typeof payload?.bytes === "number" ? payload.bytes : typeof payload?.fragment === "string" ? Buffer.byteLength(payload.fragment) : 0 } };
|
|
81754
82021
|
}
|
|
81755
82022
|
if (Array.isArray(value)) return value.map((entry) => withoutPersistentImageBytes(entry, key, seen));
|
|
81756
|
-
return Object.fromEntries(Object.entries(
|
|
82023
|
+
return Object.fromEntries(Object.entries(object12).map(([name2, entry]) => [
|
|
81757
82024
|
name2,
|
|
81758
|
-
withoutPersistentImageBytes(entry,
|
|
82025
|
+
withoutPersistentImageBytes(entry, object12.type === "image" && name2 === "data" ? "base64" : name2, seen)
|
|
81759
82026
|
]));
|
|
81760
82027
|
} finally {
|
|
81761
82028
|
seen.delete(value);
|
|
@@ -82849,6 +83116,7 @@ var NiumaDaemonRuntime = class {
|
|
|
82849
83116
|
}
|
|
82850
83117
|
desktopTrackers = new RuntimeDesktopIngressTrackers();
|
|
82851
83118
|
desktopIngress = new RuntimeDesktopIngress({
|
|
83119
|
+
discoverThread: (id5) => this.ipcThreadDiscovery.discover(id5),
|
|
82852
83120
|
nativeAdmission: () => this.nativeAdmission,
|
|
82853
83121
|
ensureNativeAdmission: (id5) => this.ensureNativeAdmission(id5),
|
|
82854
83122
|
requestReadFileRefresh: () => this.followerCoordination.desktopReadStateFileValue?.requestRefresh(),
|
|
@@ -83384,6 +83652,33 @@ var NiumaDaemonRuntime = class {
|
|
|
83384
83652
|
}
|
|
83385
83653
|
}
|
|
83386
83654
|
});
|
|
83655
|
+
ipcThreadDiscovery = new RuntimeIpcThreadDiscovery({
|
|
83656
|
+
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),
|
|
83657
|
+
capture: () => {
|
|
83658
|
+
const runtime = this.lifecycle.runtimeGenerationValue, ipc = this.desktopSession.ipcConnectionGenerationValue;
|
|
83659
|
+
const client = this.executionHost.appServerValue, generation = this.appServerLoads.connectionGeneration;
|
|
83660
|
+
return () => !this.lifecycle.stoppingValue && runtime === this.lifecycle.runtimeGenerationValue && ipc === this.desktopSession.ipcConnectionGenerationValue && client === this.executionHost.appServerValue && generation === this.appServerLoads.connectionGeneration;
|
|
83661
|
+
},
|
|
83662
|
+
read: (id5) => this.nativeAdmission.ensureSummary(id5, this.appServerLoads.connectionGeneration),
|
|
83663
|
+
current: (token3) => this.nativeAdmission.isCurrent(token3),
|
|
83664
|
+
enqueue: (run) => this.eventSequencer.enqueue(async () => {
|
|
83665
|
+
run();
|
|
83666
|
+
}),
|
|
83667
|
+
commit: (thread4) => {
|
|
83668
|
+
this.directoryAuthority.begin(false);
|
|
83669
|
+
this.catalog.upsertAuthoritativeThreadSummary(thread4);
|
|
83670
|
+
this.emitEvent(this.publication.threadUpdatedEvent(thread4.id, "app_server", nowSeconds()));
|
|
83671
|
+
this.activityPublication.publishGlobalStatusIfChanged();
|
|
83672
|
+
},
|
|
83673
|
+
diagnostic: (threadId2, phase, elapsedMs) => this.diagnostics.writeDebug({
|
|
83674
|
+
component: "daemon",
|
|
83675
|
+
channel: "ipc",
|
|
83676
|
+
event: "ipc_thread_discovery",
|
|
83677
|
+
threadId: threadId2,
|
|
83678
|
+
phase,
|
|
83679
|
+
attributes: { durationMs: elapsedMs }
|
|
83680
|
+
})
|
|
83681
|
+
});
|
|
83387
83682
|
async ensureNativeAdmission(id5) {
|
|
83388
83683
|
return !this.lifecycle.stoppingValue && !this.archiveState.isConfirmed(id5) && await this.nativeAdmission.ensure(id5, this.appServerLoads.connectionGeneration) === "ordinary";
|
|
83389
83684
|
}
|
|
@@ -84070,7 +84365,7 @@ var NiumaDaemonRuntime = class {
|
|
|
84070
84365
|
isBlocked: isStartBlockedByLifecycle
|
|
84071
84366
|
});
|
|
84072
84367
|
// 所有 runtime 与 coordinator 共用同一审计实例,确保 thread-scope 事件可关联当前 trace。
|
|
84073
|
-
threadLoadReports = new ThreadLoadReports();
|
|
84368
|
+
threadLoadReports = new ThreadLoadReports(Date.now, () => this.followerOpenTraceAudit);
|
|
84074
84369
|
followerOpenTraceAudit;
|
|
84075
84370
|
// 异步选择只等待目录;端口在实际调用时读取,不能提前冻结Owner或缓存。
|
|
84076
84371
|
settingsSelection = new RuntimeSettingsSelection({
|
|
@@ -84408,6 +84703,34 @@ var NiumaDaemonRuntime = class {
|
|
|
84408
84703
|
});
|
|
84409
84704
|
};
|
|
84410
84705
|
|
|
84706
|
+
// apps/desktop/src/daemon/thread-load-record.ts
|
|
84707
|
+
import { z as z17 } from "zod";
|
|
84708
|
+
var LoadRecordSchema = z17.object({
|
|
84709
|
+
schema_version: z17.literal(3),
|
|
84710
|
+
record_type: z17.enum(["load_start", "load_sample", "load_terminal", "load_close"]),
|
|
84711
|
+
load_id: z17.string().uuid(),
|
|
84712
|
+
thread_id: z17.string().min(1).max(256),
|
|
84713
|
+
sequence: z17.number().int().nonnegative(),
|
|
84714
|
+
occurred_at_ms: z17.number().int().nonnegative().max(864e13),
|
|
84715
|
+
clock: z17.enum(["client", "daemon"]),
|
|
84716
|
+
phase: z17.enum([...CLIENT_LOAD_PHASES, "open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent", "stream_closed", "failed", "cancelled", "superseded", "closed", "expired"]),
|
|
84717
|
+
elapsed_ms: z17.number().int().min(0).max(9e5),
|
|
84718
|
+
event_at_ms: z17.number().int().min(1).max(864e13).optional(),
|
|
84719
|
+
source_transport: z17.enum(["local", "direct", "relay"]).optional(),
|
|
84720
|
+
client_class: z17.enum(["web", "ios", "other"]).optional(),
|
|
84721
|
+
title: z17.string().max(256).optional(),
|
|
84722
|
+
lease_id: z17.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u).optional(),
|
|
84723
|
+
trace_id: z17.string().regex(/^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u).optional(),
|
|
84724
|
+
terminal_phase: z17.enum(["request_started", "snapshot_received", "history_ready", "open_received", "identity_ready", "lease_acquired", "shell_sent", "history_sent"]).optional(),
|
|
84725
|
+
reason: z17.enum(["open_rejected", "history_failed", "left_view", "user_cancelled", "stream_replaced"]).optional()
|
|
84726
|
+
}).strict().superRefine((v, ctx) => {
|
|
84727
|
+
const fail18 = () => ctx.addIssue({ code: "custom", message: "invalid_load_record" });
|
|
84728
|
+
if (v.record_type === "load_start" && (v.phase !== "open_received" || v.clock !== "daemon" || !v.source_transport)) fail18();
|
|
84729
|
+
if (v.record_type === "load_terminal" && !["failed", "cancelled", "superseded", "expired"].includes(v.phase)) fail18();
|
|
84730
|
+
if (v.record_type === "load_close" && (v.phase !== "closed" || v.clock !== "daemon")) fail18();
|
|
84731
|
+
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();
|
|
84732
|
+
});
|
|
84733
|
+
|
|
84411
84734
|
// apps/desktop/src/daemon/follower-open-trace.ts
|
|
84412
84735
|
import { randomUUID as randomUUID52 } from "node:crypto";
|
|
84413
84736
|
import path51 from "node:path";
|
|
@@ -84416,6 +84739,7 @@ var MAX_FILE_BYTES2 = 5 * 1024 * 1024;
|
|
|
84416
84739
|
var MAX_TOTAL_BYTES2 = 20 * 1024 * 1024;
|
|
84417
84740
|
var MAX_LINE_BYTES2 = 64 * 1024;
|
|
84418
84741
|
var MAX_DIRECTORY_ENTRIES3 = 256;
|
|
84742
|
+
var MAX_PROCESSED_LINES2 = 1e4;
|
|
84419
84743
|
var SUBSCRIPTION_TRACE_SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/u;
|
|
84420
84744
|
var FOLLOWER_OPEN_TRACE_TITLE_MAX_LENGTH = 256;
|
|
84421
84745
|
var TRANSPORTS = /* @__PURE__ */ new Set(["local", "direct", "relay"]);
|
|
@@ -84577,6 +84901,9 @@ function isOptionalTraceTitle(value) {
|
|
|
84577
84901
|
function hasOnlyKeys2(value, allowed) {
|
|
84578
84902
|
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).every((key) => allowed.includes(key));
|
|
84579
84903
|
}
|
|
84904
|
+
function isRecent(value, nowMs) {
|
|
84905
|
+
return value <= nowMs && nowMs - value <= DAEMON_LOG_RETENTION_MS;
|
|
84906
|
+
}
|
|
84580
84907
|
function dateFileName2(timestampMs) {
|
|
84581
84908
|
return `${new Date(timestampMs).toISOString().slice(0, 10)}.ndjson`;
|
|
84582
84909
|
}
|
|
@@ -84683,6 +85010,10 @@ function parseRecord2(line) {
|
|
|
84683
85010
|
}
|
|
84684
85011
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
84685
85012
|
const record25 = value;
|
|
85013
|
+
if (record25.schema_version === 3) {
|
|
85014
|
+
const parsed = LoadRecordSchema.safeParse(record25);
|
|
85015
|
+
return parsed.success ? parsed.data : null;
|
|
85016
|
+
}
|
|
84686
85017
|
if (record25.schema_version === 1) return parseV1Record(record25);
|
|
84687
85018
|
if (record25.schema_version === 2) return parseV2Record(record25);
|
|
84688
85019
|
return null;
|
|
@@ -84718,6 +85049,46 @@ function readPrivateTraceFile(file, remainingBytes, storage) {
|
|
|
84718
85049
|
return { bytesRead: error2 instanceof PrivateLogFileError ? error2.bytesRead : 0, incomplete: true };
|
|
84719
85050
|
}
|
|
84720
85051
|
}
|
|
85052
|
+
function readRecords(runtimeDir, nowMs, storage) {
|
|
85053
|
+
if (!Number.isFinite(nowMs)) return { records: [], incomplete: true };
|
|
85054
|
+
const candidates = listPrivateTraceFiles(runtimeDir, storage);
|
|
85055
|
+
const records = [];
|
|
85056
|
+
let incomplete = candidates.incomplete;
|
|
85057
|
+
let totalBytes = 0;
|
|
85058
|
+
let processedLines = 0;
|
|
85059
|
+
for (const filePath of candidates.files) {
|
|
85060
|
+
if (totalBytes >= MAX_TOTAL_BYTES2) {
|
|
85061
|
+
incomplete = true;
|
|
85062
|
+
break;
|
|
85063
|
+
}
|
|
85064
|
+
const file = readPrivateTraceFile(filePath, MAX_TOTAL_BYTES2 - totalBytes, storage);
|
|
85065
|
+
totalBytes += file.bytesRead;
|
|
85066
|
+
if (file.incomplete) incomplete = true;
|
|
85067
|
+
if (file.content === void 0) continue;
|
|
85068
|
+
let end = file.content.endsWith("\n") ? file.content.length - 1 : file.content.length;
|
|
85069
|
+
while (end > 0 && processedLines < MAX_PROCESSED_LINES2) {
|
|
85070
|
+
const newline = file.content.lastIndexOf("\n", end - 1);
|
|
85071
|
+
const start = newline + 1;
|
|
85072
|
+
const length = end - start;
|
|
85073
|
+
processedLines += 1;
|
|
85074
|
+
if (length > 0 && length <= MAX_LINE_BYTES2) {
|
|
85075
|
+
const line = file.content.slice(start, end);
|
|
85076
|
+
if (Buffer.byteLength(line, "utf8") <= MAX_LINE_BYTES2) {
|
|
85077
|
+
const record25 = parseRecord2(line);
|
|
85078
|
+
if (record25 && timestampOf(record25) <= nowMs) records.push(record25);
|
|
85079
|
+
else incomplete = true;
|
|
85080
|
+
} else incomplete = true;
|
|
85081
|
+
} else if (length > 0) incomplete = true;
|
|
85082
|
+
end = Math.max(0, newline);
|
|
85083
|
+
}
|
|
85084
|
+
if (totalBytes >= MAX_TOTAL_BYTES2 || processedLines >= MAX_PROCESSED_LINES2) {
|
|
85085
|
+
if (end > 0 || filePath !== candidates.files.at(-1)) incomplete = true;
|
|
85086
|
+
break;
|
|
85087
|
+
}
|
|
85088
|
+
}
|
|
85089
|
+
records.reverse();
|
|
85090
|
+
return { records, incomplete: incomplete || hasIncompleteSubscriptionHistory(records, nowMs) };
|
|
85091
|
+
}
|
|
84721
85092
|
function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
84722
85093
|
let maximum = 0;
|
|
84723
85094
|
let totalBytes = 0;
|
|
@@ -84736,6 +85107,56 @@ function readPersistedSequenceFloor(runtimeDir, storage) {
|
|
|
84736
85107
|
}
|
|
84737
85108
|
return maximum;
|
|
84738
85109
|
}
|
|
85110
|
+
function subscriptionIdentity(record25) {
|
|
85111
|
+
return `${record25.trace_id}\0${record25.thread_id}\0${record25.lease_epoch}`;
|
|
85112
|
+
}
|
|
85113
|
+
function occursAfterStart(record25, trace) {
|
|
85114
|
+
return record25.occurred_at_ms > trace.opened_at_ms || record25.occurred_at_ms === trace.opened_at_ms && record25.sequence > trace.sequence;
|
|
85115
|
+
}
|
|
85116
|
+
function occursBeforeClose(record25, close) {
|
|
85117
|
+
return record25.occurred_at_ms < close.occurred_at_ms || record25.occurred_at_ms === close.occurred_at_ms && record25.sequence < close.sequence;
|
|
85118
|
+
}
|
|
85119
|
+
function hasIncompleteSubscriptionHistory(records, nowMs) {
|
|
85120
|
+
const starts = /* @__PURE__ */ new Map();
|
|
85121
|
+
const eventsByIdentity = /* @__PURE__ */ new Map();
|
|
85122
|
+
const closesByIdentity = /* @__PURE__ */ new Map();
|
|
85123
|
+
for (const record25 of records) {
|
|
85124
|
+
if (record25.record_type === "subscription_start") {
|
|
85125
|
+
const identity6 = subscriptionIdentity(record25);
|
|
85126
|
+
if (starts.has(identity6)) return true;
|
|
85127
|
+
starts.set(identity6, record25);
|
|
85128
|
+
continue;
|
|
85129
|
+
}
|
|
85130
|
+
if (record25.record_type === "lease_event" || record25.record_type === "subscription_event") {
|
|
85131
|
+
const identity6 = subscriptionIdentity(record25);
|
|
85132
|
+
const events = eventsByIdentity.get(identity6) ?? [];
|
|
85133
|
+
events.push(record25);
|
|
85134
|
+
eventsByIdentity.set(identity6, events);
|
|
85135
|
+
continue;
|
|
85136
|
+
}
|
|
85137
|
+
if (record25.record_type === "subscription_close") {
|
|
85138
|
+
const identity6 = subscriptionIdentity(record25);
|
|
85139
|
+
const closes = closesByIdentity.get(identity6) ?? [];
|
|
85140
|
+
closes.push(record25);
|
|
85141
|
+
closesByIdentity.set(identity6, closes);
|
|
85142
|
+
}
|
|
85143
|
+
}
|
|
85144
|
+
for (const [identity6, events] of eventsByIdentity) {
|
|
85145
|
+
const start = starts.get(identity6);
|
|
85146
|
+
if (!start || events.some((event) => !occursAfterStart(event, start))) return true;
|
|
85147
|
+
}
|
|
85148
|
+
for (const start of starts.values()) {
|
|
85149
|
+
const identity6 = subscriptionIdentity(start);
|
|
85150
|
+
const closes = closesByIdentity.get(identity6) ?? [];
|
|
85151
|
+
if (closes.some((close2) => !occursAfterStart(close2, start))) return true;
|
|
85152
|
+
if (closes.length > 1) return true;
|
|
85153
|
+
const close = closes[0];
|
|
85154
|
+
if (close && (eventsByIdentity.get(identity6) ?? []).some((event) => !occursBeforeClose(event, close))) return true;
|
|
85155
|
+
if (!close && !isRecent(start.opened_at_ms, nowMs)) return true;
|
|
85156
|
+
}
|
|
85157
|
+
if ([...closesByIdentity.keys()].some((identity6) => !starts.has(identity6))) return true;
|
|
85158
|
+
return false;
|
|
85159
|
+
}
|
|
84739
85160
|
var FollowerOpenTraceAuditWriter = class {
|
|
84740
85161
|
constructor(runtimeDir, nowMs, files) {
|
|
84741
85162
|
this.runtimeDir = runtimeDir;
|
|
@@ -84749,6 +85170,30 @@ var FollowerOpenTraceAuditWriter = class {
|
|
|
84749
85170
|
nowMs;
|
|
84750
85171
|
files;
|
|
84751
85172
|
sequence;
|
|
85173
|
+
loadEpoch = 0;
|
|
85174
|
+
loadIds;
|
|
85175
|
+
reserveLoadId(id5) {
|
|
85176
|
+
if (!this.loadIds) {
|
|
85177
|
+
try {
|
|
85178
|
+
this.ensureTraceDirectory(path51.join(this.runtimeDir, TRACE_DIRECTORY_NAME));
|
|
85179
|
+
} catch {
|
|
85180
|
+
return false;
|
|
85181
|
+
}
|
|
85182
|
+
const read = readRecords(this.runtimeDir, this.nowMs(), this.files);
|
|
85183
|
+
if (read.incomplete) return false;
|
|
85184
|
+
this.loadIds = new Set(read.records.filter((r) => r.schema_version === 3).map((r) => r.load_id));
|
|
85185
|
+
}
|
|
85186
|
+
if (this.loadIds.size >= 1e4 || this.loadIds.has(id5)) return false;
|
|
85187
|
+
this.loadIds.add(id5);
|
|
85188
|
+
return true;
|
|
85189
|
+
}
|
|
85190
|
+
loadGeneration() {
|
|
85191
|
+
return this.loadEpoch;
|
|
85192
|
+
}
|
|
85193
|
+
recordLoad(input) {
|
|
85194
|
+
const parsed = LoadRecordSchema.safeParse({ ...input, schema_version: 3, sequence: this.nextSequence() });
|
|
85195
|
+
if (parsed.success) this.write(parsed.data);
|
|
85196
|
+
}
|
|
84752
85197
|
traceDirectoryInitialized = false;
|
|
84753
85198
|
/** 只缓存当前追加文件;日期切换或清空后重新发现已有分片。 */
|
|
84754
85199
|
appendFilePath;
|
|
@@ -84882,6 +85327,7 @@ var FollowerOpenTraceAuditWriter = class {
|
|
|
84882
85327
|
for (const entry of matching) this.files.remove(entry.file);
|
|
84883
85328
|
}
|
|
84884
85329
|
this.appendFilePath = void 0;
|
|
85330
|
+
this.loadEpoch += 1;
|
|
84885
85331
|
this.activeTraces.clear();
|
|
84886
85332
|
this.activeSubscriptionTraces.clear();
|
|
84887
85333
|
this.activeSubscriptionTraceHandles.clear();
|
|
@@ -85121,16 +85567,16 @@ import { dirname as dirname5, join as join3 } from "node:path";
|
|
|
85121
85567
|
|
|
85122
85568
|
// apps/desktop/src/daemon/async-input-notification-store.ts
|
|
85123
85569
|
import { createHash as createHash41 } from "node:crypto";
|
|
85124
|
-
import { z as
|
|
85570
|
+
import { z as z18 } from "zod";
|
|
85125
85571
|
var ASYNC_INPUT_NOTIFICATION_MAX_BYTES = 2 * 1024 * 1024;
|
|
85126
|
-
var identityText =
|
|
85127
|
-
var entrySchema2 =
|
|
85128
|
-
key:
|
|
85572
|
+
var identityText = z18.string().min(1).max(8e3);
|
|
85573
|
+
var entrySchema2 = z18.object({
|
|
85574
|
+
key: z18.string().regex(/^[a-f0-9]{64}$/),
|
|
85129
85575
|
threadId: identityText,
|
|
85130
85576
|
turnId: identityText,
|
|
85131
|
-
stage:
|
|
85577
|
+
stage: z18.enum(["admitted", "sent"])
|
|
85132
85578
|
}).strict();
|
|
85133
|
-
var documentSchema2 =
|
|
85579
|
+
var documentSchema2 = z18.object({ version: z18.literal(1), entries: z18.array(entrySchema2).max(4096) }).strict();
|
|
85134
85580
|
var AsyncInputNotificationStore = class _AsyncInputNotificationStore {
|
|
85135
85581
|
constructor(journal, document) {
|
|
85136
85582
|
this.journal = journal;
|