weapp-ide-cli 6.3.0 → 6.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/automator-BqhUtMJp.js +1 -0
- package/dist/{automator-BOe32upt.js → automator-Esp3BjoT.js} +11 -18
- package/dist/{automator-session-VOB03glx.js → automator-session-Ba27VW0_.js} +4 -6
- package/dist/{automatorProject-DjYLqMj6.js → automatorProject-DPU-pEF0.js} +19 -38
- package/dist/{cli-CFlqFpIw.js → cli-Dd1RJ5PH.js} +41 -71
- package/dist/cli.js +3 -4
- package/dist/{commands-mslf7-sP.js → commands-5entj0Rh.js} +5 -7
- package/dist/commands-DR-8MVFm.js +1 -0
- package/dist/{devtoolsProjectOwnership-BMfSAg4n.js → devtoolsProjectOwnership-C4jj8msU.js} +116 -89
- package/dist/index.d.ts +0 -110
- package/dist/index.js +7 -7
- package/dist/{managed-B04Xo9U_.js → managed-hSCZXTon.js} +4 -6
- package/dist/{run-mcp-Ni139Z5C.js → run-mcp-CbmskSgr.js} +4 -7
- package/dist/run-mcp-D1w7-oPp.js +1 -0
- package/package.json +9 -9
- package/dist/automator-VSjgHujY.js +0 -1
- package/dist/commands-DmirGBy4.js +0 -1
- package/dist/run-mcp-83-VKZVA.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as withPowerShellUtf8Output, T as inspectWechatDevtoolsInstallation, g as resolveWechatInspectionTimeout, h as resolveWechatDevtoolsInstallationRoot, m as assertWechatDevtoolsPort, p as assertWechatDevtoolsHost, u as resolveWechatDevtoolsTarget } from "./automatorProject-
|
|
1
|
+
import { E as withPowerShellUtf8Output, T as inspectWechatDevtoolsInstallation, g as resolveWechatInspectionTimeout, h as resolveWechatDevtoolsInstallationRoot, m as assertWechatDevtoolsPort, p as assertWechatDevtoolsHost, u as resolveWechatDevtoolsTarget } from "./automatorProject-DPU-pEF0.js";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { TextDecoder, debuglog, isDeepStrictEqual, stripVTControlCharacters } from "node:util";
|
|
4
4
|
import { assertMachineE2ELeaseRecoveryScope, mutateLease, withMachineE2ELease, withMachineE2ELeaseRecoveryOperation } from "@weapp-vite/devtools-runtime";
|
|
@@ -11,7 +11,7 @@ import net from "node:net";
|
|
|
11
11
|
import { setTimeout } from "node:timers/promises";
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
import { performance as performance$1 } from "node:perf_hooks";
|
|
14
|
-
|
|
14
|
+
// src/cli/agentStart.ts
|
|
15
15
|
/** 提取独立的完整 JSON 对象,普通日志和嵌套对象不能替代命令响应。 */
|
|
16
16
|
function readResponseObjects(stdout) {
|
|
17
17
|
const objects = [];
|
|
@@ -116,8 +116,7 @@ async function startWechatIdeAgent(options) {
|
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
|
-
|
|
120
|
-
//#region src/devtoolsProjectOwnership/installationExit/darwinKernelPaths.ts
|
|
119
|
+
// src/devtoolsProjectOwnership/installationExit/darwinKernelPaths.ts
|
|
121
120
|
const inspectionTimeoutMs$1 = 1e4;
|
|
122
121
|
const kernelPathsScript = `
|
|
123
122
|
ObjC.import('Foundation');
|
|
@@ -174,66 +173,94 @@ async function readDarwinKernelPaths(pids, timeoutMs = inspectionTimeoutMs$1) {
|
|
|
174
173
|
if (entries.size !== pids.length || parsed.length !== pids.length || pids.some((pid) => !entries.has(pid))) throw new Error("Installation-exit recovery received incomplete kernel process identities.");
|
|
175
174
|
return entries;
|
|
176
175
|
}
|
|
177
|
-
|
|
178
|
-
//#region src/devtoolsProjectOwnership/darwinProcessIdentity.ts
|
|
176
|
+
// src/devtoolsProjectOwnership/darwinProcessIdentity.ts
|
|
179
177
|
const inspectionTimeoutMs = 3e3;
|
|
180
|
-
function invalidIdentity$2() {
|
|
181
|
-
return
|
|
182
|
-
|
|
183
|
-
|
|
178
|
+
function invalidIdentity$2(stage, reason, details = {}, cause) {
|
|
179
|
+
return new Error(`Managed DevTools process identity could not be verified; no project was closed. ${JSON.stringify({
|
|
180
|
+
stage,
|
|
181
|
+
reason,
|
|
182
|
+
...details
|
|
183
|
+
})}`, { cause });
|
|
184
|
+
}
|
|
185
|
+
async function readStarted(pids, remaining, stage) {
|
|
184
186
|
const result = await execa("/bin/ps", [
|
|
185
187
|
"-p",
|
|
186
188
|
pids.join(","),
|
|
187
189
|
"-o",
|
|
188
|
-
"pid=,lstart="
|
|
190
|
+
"pid=,stat=,lstart="
|
|
189
191
|
], {
|
|
190
192
|
timeout: remaining(),
|
|
191
193
|
reject: false,
|
|
192
194
|
env: { LC_ALL: "C" }
|
|
193
195
|
});
|
|
194
196
|
remaining();
|
|
195
|
-
if (result.timedOut || result.signal || result.stderr?.trim() || result.exitCode === 0 && !result.stdout.trim() || result.exitCode !== 0 && !(result.exitCode === 1 && !result.stdout.trim())) throw invalidIdentity$2();
|
|
197
|
+
if (result.timedOut || result.signal || result.stderr?.trim() || result.exitCode === 0 && !result.stdout.trim() || result.exitCode !== 0 && !(result.exitCode === 1 && !result.stdout.trim())) throw invalidIdentity$2(stage, "birth-query-failed", { requestedCount: pids.length });
|
|
196
198
|
const started = /* @__PURE__ */ new Map();
|
|
197
199
|
for (const line of result.stdout.split(/\r?\n/).filter((line) => line.trim())) {
|
|
198
|
-
const match = /^\s*(\d+)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s*$/.exec(line);
|
|
200
|
+
const match = /^\s*(\d+)\s+(\S+)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s*$/.exec(line);
|
|
199
201
|
const pid = Number(match?.[1]);
|
|
200
|
-
if (!match || !pids.includes(pid) || started.has(pid)) throw invalidIdentity$2();
|
|
201
|
-
started.set(pid,
|
|
202
|
+
if (!match || !pids.includes(pid) || started.has(pid)) throw invalidIdentity$2(stage, "invalid-birth-inventory", { requestedCount: pids.length });
|
|
203
|
+
started.set(pid, {
|
|
204
|
+
started: match[3].replace(/\s+/g, " "),
|
|
205
|
+
zombie: match[2].startsWith("Z")
|
|
206
|
+
});
|
|
202
207
|
}
|
|
203
208
|
return started;
|
|
204
209
|
}
|
|
205
210
|
/** 批量读取内核路径,并以前后启动时间绑定 PID;进程标题变化不改变身份。 */
|
|
206
211
|
async function readDarwinManagedProcessIdentities(pids) {
|
|
207
|
-
if (pids.some((pid) => !Number.isSafeInteger(pid) || pid <= 0)) throw invalidIdentity$2();
|
|
212
|
+
if (pids.some((pid) => !Number.isSafeInteger(pid) || pid <= 0)) throw invalidIdentity$2("request", "invalid-pid");
|
|
208
213
|
const requested = [...new Set(pids)];
|
|
209
214
|
const identities = new Map(requested.map((pid) => [pid, void 0]));
|
|
210
215
|
if (!requested.length) return identities;
|
|
211
216
|
const deadline = performance.now() + inspectionTimeoutMs;
|
|
217
|
+
let stage = "before";
|
|
212
218
|
const remaining = () => {
|
|
213
219
|
const timeout = Math.floor(deadline - performance.now());
|
|
214
|
-
if (timeout <= 0) throw invalidIdentity$2();
|
|
220
|
+
if (timeout <= 0) throw invalidIdentity$2(stage, "deadline-exceeded", { requestedCount: requested.length });
|
|
215
221
|
return timeout;
|
|
216
222
|
};
|
|
217
|
-
const before = await readStarted(requested, remaining);
|
|
223
|
+
const before = await readStarted(requested, remaining, "before");
|
|
218
224
|
if (!before.size) return identities;
|
|
219
|
-
|
|
220
|
-
const
|
|
225
|
+
stage = "kernel";
|
|
226
|
+
const paths = await readDarwinKernelPaths([...before.keys()], remaining()).catch((cause) => {
|
|
227
|
+
throw invalidIdentity$2("kernel", "kernel-query-failed", { requestedCount: before.size }, cause);
|
|
228
|
+
});
|
|
229
|
+
stage = "after";
|
|
230
|
+
const after = await readStarted(requested, remaining, "after");
|
|
221
231
|
for (const pid of requested) {
|
|
222
|
-
const
|
|
223
|
-
if (!
|
|
232
|
+
const current = after.get(pid);
|
|
233
|
+
if (!current) continue;
|
|
224
234
|
const executable = paths.get(pid);
|
|
225
|
-
|
|
235
|
+
const previous = before.get(pid);
|
|
236
|
+
if (previous?.started !== current.started) throw invalidIdentity$2("after", "birth-changed", {
|
|
237
|
+
pid,
|
|
238
|
+
beforePresent: before.has(pid),
|
|
239
|
+
afterPresent: true
|
|
240
|
+
});
|
|
241
|
+
if (previous.zombie && current.zombie) continue;
|
|
242
|
+
if (previous.zombie !== current.zombie) throw invalidIdentity$2("after", "terminal-state-changed", {
|
|
243
|
+
pid,
|
|
244
|
+
beforeZombie: previous.zombie,
|
|
245
|
+
afterZombie: current.zombie
|
|
246
|
+
});
|
|
247
|
+
if (!executable?.startsWith("/")) throw invalidIdentity$2("after", "kernel-path-unavailable", {
|
|
248
|
+
pid,
|
|
249
|
+
beforePresent: true,
|
|
250
|
+
afterPresent: true,
|
|
251
|
+
kernelPath: executable ? "non-absolute" : "empty"
|
|
252
|
+
});
|
|
226
253
|
identities.set(pid, {
|
|
227
254
|
pid,
|
|
228
|
-
started,
|
|
255
|
+
started: current.started,
|
|
229
256
|
executable
|
|
230
257
|
});
|
|
231
258
|
}
|
|
259
|
+
stage = "complete";
|
|
232
260
|
remaining();
|
|
233
261
|
return identities;
|
|
234
262
|
}
|
|
235
|
-
|
|
236
|
-
//#region src/devtoolsProjectOwnership/processIdentity.ts
|
|
263
|
+
// src/devtoolsProjectOwnership/processIdentity.ts
|
|
237
264
|
const inspectionOptions$2 = {
|
|
238
265
|
timeout: 3e3,
|
|
239
266
|
reject: false,
|
|
@@ -308,8 +335,7 @@ async function readManagedProcessIdentity(pid, platform = process.platform) {
|
|
|
308
335
|
function sameManagedProcess(first, second) {
|
|
309
336
|
return first.pid === second.pid && first.started === second.started && first.executable === second.executable;
|
|
310
337
|
}
|
|
311
|
-
|
|
312
|
-
//#region src/devtoolsProjectOwnership/host.ts
|
|
338
|
+
// src/devtoolsProjectOwnership/host.ts
|
|
313
339
|
const inspectionOptions$1 = {
|
|
314
340
|
timeout: 3e3,
|
|
315
341
|
reject: false,
|
|
@@ -377,8 +403,7 @@ async function waitForManagedPortClosed(port, timeoutMs = 1e4) {
|
|
|
377
403
|
} while (Date.now() < deadline);
|
|
378
404
|
throw new Error("Managed DevTools project close returned but its automator port remained open.");
|
|
379
405
|
}
|
|
380
|
-
|
|
381
|
-
//#region src/devtoolsProjectOwnership/installationExit/schema.ts
|
|
406
|
+
// src/devtoolsProjectOwnership/installationExit/schema.ts
|
|
382
407
|
const installationExitRecoverySchema = z.object({
|
|
383
408
|
protocol: z.literal("wechat-devtools-installation-exit-v1"),
|
|
384
409
|
recoveredAt: z.string().datetime(),
|
|
@@ -412,8 +437,7 @@ const installationExitRecoverySchema = z.object({
|
|
|
412
437
|
selectedProcessCount: z.literal(0)
|
|
413
438
|
}).strict()
|
|
414
439
|
}).strict();
|
|
415
|
-
|
|
416
|
-
//#region src/devtoolsProjectOwnership/journal/scope.ts
|
|
440
|
+
// src/devtoolsProjectOwnership/journal/scope.ts
|
|
417
441
|
const markerName = ".ownership-scope";
|
|
418
442
|
const scopeSchema = z.object({
|
|
419
443
|
schemaVersion: z.literal(1),
|
|
@@ -466,8 +490,7 @@ async function resolveManagedJournalScope(directory) {
|
|
|
466
490
|
if (path.resolve(rootPath, relative) !== currentPath) throw new Error("Managed DevTools journal path changed from its registered task children.");
|
|
467
491
|
return scope;
|
|
468
492
|
}
|
|
469
|
-
|
|
470
|
-
//#region src/devtoolsProjectOwnership/journal/windowsSelfIdentity/wire.ts
|
|
493
|
+
// src/devtoolsProjectOwnership/journal/windowsSelfIdentity/wire.ts
|
|
471
494
|
const SELF_IDENTITY_WIRE = "WEAPP_JOURNAL_SELF_V1";
|
|
472
495
|
const epochTicks = 621355968000000000n;
|
|
473
496
|
const maximumTicks = 3155378975999999999n;
|
|
@@ -501,8 +524,7 @@ function parseWindowsSelfIdentity(stdout, expectedPid) {
|
|
|
501
524
|
started
|
|
502
525
|
};
|
|
503
526
|
}
|
|
504
|
-
|
|
505
|
-
//#region src/devtoolsProjectOwnership/journal/windowsSelfIdentity/command.ts
|
|
527
|
+
// src/devtoolsProjectOwnership/journal/windowsSelfIdentity/command.ts
|
|
506
528
|
/** 当前 writer 的 PID 由 Node 进程提供;脚本只读查询,不执行任何进程或 IDE 清理。 */
|
|
507
529
|
function windowsSelfIdentityCommand(pid) {
|
|
508
530
|
if (!Number.isSafeInteger(pid) || pid <= 0) throw new TypeError("A positive writer PID is required.");
|
|
@@ -542,8 +564,7 @@ finally {
|
|
|
542
564
|
exit $writerExitCode
|
|
543
565
|
`;
|
|
544
566
|
}
|
|
545
|
-
|
|
546
|
-
//#region src/devtoolsProjectOwnership/journal/windowsSelfIdentity/trace.ts
|
|
567
|
+
// src/devtoolsProjectOwnership/journal/windowsSelfIdentity/trace.ts
|
|
547
568
|
const marker = `${SELF_IDENTITY_WIRE}:phase:`;
|
|
548
569
|
const statements = /* @__PURE__ */ new Map([
|
|
549
570
|
["$writerFirst=[System.Diagnostics.Process]", "lookup-before"],
|
|
@@ -590,8 +611,7 @@ function observeWindowsSelfIdentityPhases(report) {
|
|
|
590
611
|
function stripWindowsSelfIdentityPhases(stderr) {
|
|
591
612
|
return stderr.replace(phaseLines, "");
|
|
592
613
|
}
|
|
593
|
-
|
|
594
|
-
//#region src/devtoolsProjectOwnership/journal/windowsSelfIdentity/index.ts
|
|
614
|
+
// src/devtoolsProjectOwnership/journal/windowsSelfIdentity/index.ts
|
|
595
615
|
const debug = debuglog("weapp-ide-journal-writer");
|
|
596
616
|
/** 仅核验当前 Node 写入进程;不能用于任意宿主、旧锁存活判断或进程清理。 */
|
|
597
617
|
async function readWindowsJournalWriterIdentity() {
|
|
@@ -626,8 +646,7 @@ async function readWindowsJournalWriterIdentity() {
|
|
|
626
646
|
}
|
|
627
647
|
return parseWindowsSelfIdentity(result.stdout, process.pid);
|
|
628
648
|
}
|
|
629
|
-
|
|
630
|
-
//#region src/devtoolsProjectOwnership/journal/writerIdentity.ts
|
|
649
|
+
// src/devtoolsProjectOwnership/journal/writerIdentity.ts
|
|
631
650
|
let currentIdentity$1;
|
|
632
651
|
/** 共享在途与成功身份;失败仍拒绝当前调用,仅允许下一次显式操作重新核验。 */
|
|
633
652
|
function readManagedJournalWriterIdentity() {
|
|
@@ -643,8 +662,7 @@ function readManagedJournalWriterIdentity() {
|
|
|
643
662
|
}
|
|
644
663
|
return currentIdentity$1;
|
|
645
664
|
}
|
|
646
|
-
|
|
647
|
-
//#region src/devtoolsProjectOwnership/snapshot/schema.ts
|
|
665
|
+
// src/devtoolsProjectOwnership/snapshot/schema.ts
|
|
648
666
|
const managedSnapshotSchema = z.object({
|
|
649
667
|
protocol: z.literal("wechat-devtools-project-snapshot-v1"),
|
|
650
668
|
sourceProjectPath: z.string().min(1),
|
|
@@ -663,8 +681,7 @@ const managedSnapshotSchema = z.object({
|
|
|
663
681
|
removedAt: z.string().datetime().optional(),
|
|
664
682
|
cleanupError: z.string().optional()
|
|
665
683
|
}).strict();
|
|
666
|
-
|
|
667
|
-
//#region src/devtoolsProjectOwnership/windowClose/schema.ts
|
|
684
|
+
// src/devtoolsProjectOwnership/windowClose/schema.ts
|
|
668
685
|
const text = z.string().min(1);
|
|
669
686
|
const cursorSchema = z.object({
|
|
670
687
|
name: z.string().regex(/^[^/\\]+\.log$/),
|
|
@@ -705,8 +722,7 @@ const managedWindowCloseSchema = z.object({
|
|
|
705
722
|
cursors: z.array(cursorSchema).min(1)
|
|
706
723
|
}).optional()
|
|
707
724
|
});
|
|
708
|
-
|
|
709
|
-
//#region src/devtoolsProjectOwnership/journal.ts
|
|
725
|
+
// src/devtoolsProjectOwnership/journal.ts
|
|
710
726
|
const managedProcessToken = randomUUID();
|
|
711
727
|
const idSchema = z.string().uuid();
|
|
712
728
|
const hostSchema = z.object({
|
|
@@ -790,16 +806,15 @@ async function writeManagedRecord(record) {
|
|
|
790
806
|
await fs.rm(temporary, { force: true });
|
|
791
807
|
}
|
|
792
808
|
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
const directory = resolveManagedJournal(journalPath);
|
|
796
|
-
if (!directory) return [];
|
|
809
|
+
async function readManagedJournalDirectory(directory, parentScope) {
|
|
810
|
+
if (parentScope && !(await fs.lstat(directory)).isDirectory()) throw new Error("Managed DevTools journal scope must use regular directories.");
|
|
797
811
|
const entries = await fs.readdir(directory, { withFileTypes: true }).catch((error) => {
|
|
798
|
-
if (error.code === "ENOENT") return;
|
|
812
|
+
if (error.code === "ENOENT" && !parentScope) return;
|
|
799
813
|
throw error;
|
|
800
814
|
});
|
|
801
815
|
if (!entries) return [];
|
|
802
816
|
const scope = await resolveManagedJournalScope(directory);
|
|
817
|
+
if (parentScope && (parentScope.scopeId !== void 0 || scope.scopeId !== void 0) && (parentScope.scopeId !== scope.scopeId || parentScope.rootPath !== scope.rootPath)) throw new Error("Managed DevTools journal scope changed inside its registered children; refusing another task tree.");
|
|
803
818
|
const records = [];
|
|
804
819
|
for (const entry of entries) if (entry.name.endsWith(".json")) records.push(await readManagedRecord(directory, entry.name.slice(0, -5)));
|
|
805
820
|
else if (entry.name === "children") {
|
|
@@ -808,13 +823,17 @@ async function readManagedWechatProjectRecords(journalPath) {
|
|
|
808
823
|
for (const child of children) {
|
|
809
824
|
if (!child.isDirectory()) throw new Error("Managed DevTools child journal is not a regular directory.");
|
|
810
825
|
const childPath = path.join(directory, "children", child.name);
|
|
811
|
-
|
|
812
|
-
if ((scope.scopeId !== void 0 || childScope.scopeId !== void 0) && (scope.scopeId !== childScope.scopeId || scope.rootPath !== childScope.rootPath)) throw new Error("Managed DevTools journal scope changed inside its registered children; refusing another task tree.");
|
|
813
|
-
records.push(...await readManagedWechatProjectRecords(childPath));
|
|
826
|
+
records.push(...await readManagedJournalDirectory(childPath, scope));
|
|
814
827
|
}
|
|
815
828
|
}
|
|
816
829
|
return records;
|
|
817
830
|
}
|
|
831
|
+
/** 仅递归当前任务明确传递的 children;不扫描用户缓存,不跟随符号链接。 */
|
|
832
|
+
async function readManagedWechatProjectRecords(journalPath) {
|
|
833
|
+
const directory = resolveManagedJournal(journalPath);
|
|
834
|
+
if (!directory) return [];
|
|
835
|
+
return await readManagedJournalDirectory(directory);
|
|
836
|
+
}
|
|
818
837
|
const lockOwnerSchema = z.object({
|
|
819
838
|
token: idSchema,
|
|
820
839
|
identity: hostSchema
|
|
@@ -890,8 +909,7 @@ async function withManagedJournalLock(directory, run) {
|
|
|
890
909
|
return await run(scope.rootPath);
|
|
891
910
|
});
|
|
892
911
|
}
|
|
893
|
-
|
|
894
|
-
//#region src/devtoolsProjectOwnership/snapshot/index.ts
|
|
912
|
+
// src/devtoolsProjectOwnership/snapshot/index.ts
|
|
895
913
|
const MARKER = ".weapp-ide-snapshot-owner";
|
|
896
914
|
function managedSnapshotPath(journalPath, id) {
|
|
897
915
|
return path.join(journalPath, "snapshots", id);
|
|
@@ -994,8 +1012,7 @@ async function finalizeManagedProjectSnapshot(record) {
|
|
|
994
1012
|
throw error;
|
|
995
1013
|
}
|
|
996
1014
|
}
|
|
997
|
-
|
|
998
|
-
//#region src/devtoolsProjectOwnership/windowBudget.ts
|
|
1015
|
+
// src/devtoolsProjectOwnership/windowBudget.ts
|
|
999
1016
|
function maximumOwnedWindows(options) {
|
|
1000
1017
|
const selected = options.maxOwnedWindows ?? process.env["WEAPP_IDE_MANAGED_PROJECT_MAX_WINDOWS"] ?? 1;
|
|
1001
1018
|
if (selected !== 1 && selected !== 2 && selected !== "1" && selected !== "2") throw new Error("Managed DevTools maximum owned windows must be 1 or 2.");
|
|
@@ -1012,8 +1029,7 @@ function checkManagedWindowBudget(records, options) {
|
|
|
1012
1029
|
const owned = records.filter((record) => record.state === "owned").length;
|
|
1013
1030
|
if (owned >= maximum) throw new Error(`Managed DevTools window budget exhausted (${owned}/${maximum}); close the previous owned project before another start.`);
|
|
1014
1031
|
}
|
|
1015
|
-
|
|
1016
|
-
//#region src/devtoolsProjectOwnership/windowClose/logCursor.ts
|
|
1032
|
+
// src/devtoolsProjectOwnership/windowClose/logCursor.ts
|
|
1017
1033
|
const readLimit = 2097152;
|
|
1018
1034
|
const scanLimit = 33554432;
|
|
1019
1035
|
const scanChunkSize = 65536;
|
|
@@ -1217,8 +1233,7 @@ async function consumeFreshLogLines(directory, cursors, consume) {
|
|
|
1217
1233
|
await Promise.all(streams.map(({ file }) => file.close()));
|
|
1218
1234
|
}
|
|
1219
1235
|
}
|
|
1220
|
-
|
|
1221
|
-
//#region src/devtoolsProjectOwnership/windowClose/activeLog.ts
|
|
1236
|
+
// src/devtoolsProjectOwnership/windowClose/activeLog.ts
|
|
1222
1237
|
const inspectionOptions = {
|
|
1223
1238
|
timeout: 3e3,
|
|
1224
1239
|
reject: false,
|
|
@@ -1377,8 +1392,7 @@ async function captureActiveMainLogCursors(record, directory, platform = process
|
|
|
1377
1392
|
host: main
|
|
1378
1393
|
};
|
|
1379
1394
|
}
|
|
1380
|
-
|
|
1381
|
-
//#region src/devtoolsProjectOwnership/windowClose/protocol.ts
|
|
1395
|
+
// src/devtoolsProjectOwnership/windowClose/protocol.ts
|
|
1382
1396
|
function decodeString(value) {
|
|
1383
1397
|
const quote = value[0];
|
|
1384
1398
|
if (!quote || ![
|
|
@@ -1519,8 +1533,7 @@ function consumeWindowCloseTrace(evidence, projectPath, input) {
|
|
|
1519
1533
|
}
|
|
1520
1534
|
}
|
|
1521
1535
|
}
|
|
1522
|
-
|
|
1523
|
-
//#region src/devtoolsProjectOwnership/windowClose.ts
|
|
1536
|
+
// src/devtoolsProjectOwnership/windowClose.ts
|
|
1524
1537
|
/** 只捕获本次显式安装的日志,必须先于关闭命令持久化。 */
|
|
1525
1538
|
async function captureManagedWindowClose(record) {
|
|
1526
1539
|
if (!record.target.version) throw new Error("Managed DevTools window-close evidence requires the selected product version.");
|
|
@@ -1581,8 +1594,7 @@ async function waitForManagedWindowClosed(record, persist, options = {}) {
|
|
|
1581
1594
|
} while (true);
|
|
1582
1595
|
throw new Error("Managed DevTools project close has no complete native-window destruction evidence; stop the acceptance lane.");
|
|
1583
1596
|
}
|
|
1584
|
-
|
|
1585
|
-
//#region src/devtoolsProjectOwnership/installationExit/darwin.ts
|
|
1597
|
+
// src/devtoolsProjectOwnership/installationExit/darwin.ts
|
|
1586
1598
|
const options = {
|
|
1587
1599
|
timeout: 1e4,
|
|
1588
1600
|
reject: false,
|
|
@@ -1611,11 +1623,15 @@ function decodeTextImagePath(wire) {
|
|
|
1611
1623
|
return textImageDecoder.decode(bytes.subarray(0, length));
|
|
1612
1624
|
}
|
|
1613
1625
|
/** ps 仅用于 PID、启动时间和僵尸状态,不能用可修改的 comm 代替实际可执行文件。 */
|
|
1614
|
-
async function readDarwinProcessStates() {
|
|
1615
|
-
|
|
1626
|
+
async function readDarwinProcessStates(timeoutMs = options.timeout) {
|
|
1627
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) throw new Error("Installation-exit recovery cannot inspect the process inventory without a positive timeout.");
|
|
1628
|
+
const inspection = execa("/bin/ps", ["-axo", "pid=,stat=,lstart="], {
|
|
1629
|
+
...options,
|
|
1630
|
+
timeout: Math.min(options.timeout, timeoutMs)
|
|
1631
|
+
});
|
|
1616
1632
|
const inspectorPid = inspection.pid;
|
|
1617
1633
|
const result = await inspection;
|
|
1618
|
-
if (result.exitCode !== 0 || result.stderr?.trim() || !result.stdout.trim()) throw new Error("Installation-exit recovery could not read the complete process inventory.");
|
|
1634
|
+
if (result.exitCode !== 0 || result.timedOut || result.signal || result.stderr?.trim() || !result.stdout.trim()) throw new Error("Installation-exit recovery could not read the complete process inventory.");
|
|
1619
1635
|
const records = result.stdout.trim().split(/\r?\n/).map((line) => {
|
|
1620
1636
|
const match = /^\s*(\d+)\s+(\S+)\s+(\w{3}\s+\w{3}\s+\d+\s+\d{2}:\d{2}:\d{2}\s+\d{4})\s*$/.exec(line);
|
|
1621
1637
|
const pid = Number(match?.[1]);
|
|
@@ -1657,24 +1673,37 @@ async function readDarwinTextImages(pid, timeoutMs = options.timeout) {
|
|
|
1657
1673
|
}
|
|
1658
1674
|
return paths;
|
|
1659
1675
|
}
|
|
1660
|
-
|
|
1661
|
-
//#region src/devtoolsProjectOwnership/installationExit/processes.ts
|
|
1676
|
+
// src/devtoolsProjectOwnership/installationExit/processes.ts
|
|
1662
1677
|
/** 仅支持已验证的 macOS 全安装清单;未知平台、权限错误或不完整映像均拒绝推断退出。 */
|
|
1663
|
-
async function inspectExitedWechatInstallation(target, platform = process.platform) {
|
|
1678
|
+
async function inspectExitedWechatInstallation(target, platform = process.platform, options = {}) {
|
|
1664
1679
|
if (platform !== "darwin") throw new Error("Installation-exit recovery requires the verified macOS process inventory.");
|
|
1680
|
+
const timeoutMs = options.timeoutMs ?? 3e4;
|
|
1681
|
+
if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) throw new Error("Installation-exit recovery requires a positive process inventory timeout.");
|
|
1682
|
+
const deadline = performance.now() + Math.min(timeoutMs, 3e4);
|
|
1683
|
+
const remaining = () => {
|
|
1684
|
+
const timeout = Math.floor(deadline - performance.now());
|
|
1685
|
+
if (timeout <= 0) throw new Error("Installation-exit recovery process inventory deadline expired; continuing new process activity or incomplete inspection prevents proving exit.");
|
|
1686
|
+
return timeout;
|
|
1687
|
+
};
|
|
1688
|
+
const readStates = async () => {
|
|
1689
|
+
const states = await readDarwinProcessStates(remaining());
|
|
1690
|
+
remaining();
|
|
1691
|
+
return states;
|
|
1692
|
+
};
|
|
1665
1693
|
const selectedRoot = resolveWechatDevtoolsInstallationRoot(target, platform);
|
|
1666
1694
|
if (!selectedRoot || !path.isAbsolute(selectedRoot) || !selectedRoot.endsWith(".app") || !target.appPath.includes("/Contents/")) throw new Error("Installation-exit recovery cannot resolve the selected application bundle.");
|
|
1667
1695
|
const installationRoot = await fs.realpath(selectedRoot);
|
|
1668
|
-
let pending = await
|
|
1696
|
+
let pending = await readStates();
|
|
1669
1697
|
const verified = /* @__PURE__ */ new Map();
|
|
1670
1698
|
let kernelPathProcessCount = 0;
|
|
1671
1699
|
let textImageProcessCount = 0;
|
|
1672
1700
|
let exitedProcessCount = 0;
|
|
1673
1701
|
let zombieProcessCount = 0;
|
|
1674
|
-
|
|
1675
|
-
const kernelPaths = await readDarwinKernelPaths(pending.map((entry) => entry.pid));
|
|
1676
|
-
const after = new Map((await
|
|
1702
|
+
while (true) {
|
|
1703
|
+
const kernelPaths = await readDarwinKernelPaths(pending.map((entry) => entry.pid), remaining());
|
|
1704
|
+
const after = new Map((await readStates()).map((entry) => [entry.pid, entry]));
|
|
1677
1705
|
for (const entry of pending) {
|
|
1706
|
+
remaining();
|
|
1678
1707
|
const current = after.get(entry.pid);
|
|
1679
1708
|
if (!current) {
|
|
1680
1709
|
exitedProcessCount++;
|
|
@@ -1689,9 +1718,9 @@ async function inspectExitedWechatInstallation(target, platform = process.platfo
|
|
|
1689
1718
|
const executable = kernelPaths.get(entry.pid);
|
|
1690
1719
|
let images;
|
|
1691
1720
|
try {
|
|
1692
|
-
images = executable ? [executable] : await readDarwinTextImages(entry.pid);
|
|
1721
|
+
images = executable ? [executable] : await readDarwinTextImages(entry.pid, remaining());
|
|
1693
1722
|
} catch (error) {
|
|
1694
|
-
const latest = await
|
|
1723
|
+
const latest = await readStates().then((states) => states.find((process) => process.pid === entry.pid), (confirmationError) => {
|
|
1695
1724
|
throw new AggregateError([error, confirmationError], "Installation-exit recovery cannot independently confirm process exit after failed image inspection.");
|
|
1696
1725
|
});
|
|
1697
1726
|
if (!latest) {
|
|
@@ -1701,6 +1730,7 @@ async function inspectExitedWechatInstallation(target, platform = process.platfo
|
|
|
1701
1730
|
if (latest.started !== entry.started) throw new Error("Installation-exit recovery process identity changed during inspection.", { cause: error });
|
|
1702
1731
|
throw error;
|
|
1703
1732
|
}
|
|
1733
|
+
remaining();
|
|
1704
1734
|
if (!images.length) throw new Error("Installation-exit recovery received no verifiable executable text images.");
|
|
1705
1735
|
for (const image of images) {
|
|
1706
1736
|
if (!path.isAbsolute(image) || /[\r\n\0]/.test(image)) throw new Error("Installation-exit recovery received an unverifiable executable image path.");
|
|
@@ -1714,7 +1744,7 @@ async function inspectExitedWechatInstallation(target, platform = process.platfo
|
|
|
1714
1744
|
zombie: false
|
|
1715
1745
|
});
|
|
1716
1746
|
}
|
|
1717
|
-
const final = await
|
|
1747
|
+
const final = await readStates();
|
|
1718
1748
|
for (const entry of final) {
|
|
1719
1749
|
const previous = verified.get(entry.pid);
|
|
1720
1750
|
if (previous && (previous.started !== entry.started || previous.zombie && !entry.zombie)) throw new Error("Installation-exit recovery process identity changed during inspection.");
|
|
@@ -1722,7 +1752,7 @@ async function inspectExitedWechatInstallation(target, platform = process.platfo
|
|
|
1722
1752
|
pending = final.filter((entry) => !verified.has(entry.pid));
|
|
1723
1753
|
if (!pending.length) break;
|
|
1724
1754
|
}
|
|
1725
|
-
|
|
1755
|
+
remaining();
|
|
1726
1756
|
return {
|
|
1727
1757
|
platform,
|
|
1728
1758
|
installationRoot,
|
|
@@ -1735,8 +1765,7 @@ async function inspectExitedWechatInstallation(target, platform = process.platfo
|
|
|
1735
1765
|
selectedProcessCount: 0
|
|
1736
1766
|
};
|
|
1737
1767
|
}
|
|
1738
|
-
|
|
1739
|
-
//#region src/devtoolsProjectOwnership/installationExit/index.ts
|
|
1768
|
+
// src/devtoolsProjectOwnership/installationExit/index.ts
|
|
1740
1769
|
async function fingerprint(record) {
|
|
1741
1770
|
const file = managedRecordPath(record.journalPath, record.id);
|
|
1742
1771
|
const stat = await fs.lstat(file);
|
|
@@ -1827,8 +1856,7 @@ async function recoverAfterExit(options) {
|
|
|
1827
1856
|
function recoverManagedWechatProjectsAfterInstallationExit(options) {
|
|
1828
1857
|
return withMachineE2ELeaseRecoveryOperation(options.recoveryScope, () => recoverAfterExit(options));
|
|
1829
1858
|
}
|
|
1830
|
-
|
|
1831
|
-
//#region src/devtoolsProjectOwnership/index.ts
|
|
1859
|
+
// src/devtoolsProjectOwnership/index.ts
|
|
1832
1860
|
const pendingClosures = /* @__PURE__ */ new Map();
|
|
1833
1861
|
function describe(error) {
|
|
1834
1862
|
return error instanceof Error ? error.message : String(error);
|
|
@@ -2018,5 +2046,4 @@ async function cleanupManagedWechatProjects(options = {}) {
|
|
|
2018
2046
|
}
|
|
2019
2047
|
if (errors.length) throw new AggregateError(errors, "Managed DevTools project cleanup remains incomplete; stop the acceptance lane.");
|
|
2020
2048
|
}
|
|
2021
|
-
//#endregion
|
|
2022
2049
|
export { isManagedWechatProjectFullyReleased as a, resolveManagedJournal as c, assertManagedInstallation as d, inspectManagedProjectHost as f, recoverManagedWechatProjectsAfterInstallationExit as i, withManagedJournalLock as l, startWechatIdeAgent as m, cleanupManagedWechatProjects as n, readManagedRecord as o, sameManagedProcess as p, closeManagedWechatProject as r, readManagedWechatProjectRecords as s, beginManagedWechatProject as t, writeManagedRecord as u };
|