impel-cli 0.20.17 → 0.20.18
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/RELEASE_NOTES.md +8 -0
- package/package.json +1 -1
- package/scripts/profile-native-codex.mjs +35 -8
package/RELEASE_NOTES.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Release notes
|
|
2
2
|
|
|
3
|
+
## 0.20.18 — Recoverable Codex profiling cohorts
|
|
4
|
+
|
|
5
|
+
- Widens the bounded retry window for transient current-tenant reads while
|
|
6
|
+
still rejecting an exact tenant mismatch before a Codex attempt starts.
|
|
7
|
+
- Stops scheduling new work after an attempt-infrastructure failure, waits for
|
|
8
|
+
active workers to settle, and retains an explicitly incomplete private
|
|
9
|
+
aggregate so valid samples are not silently lost.
|
|
10
|
+
|
|
3
11
|
## 0.20.17 — Managed desktop task views
|
|
4
12
|
|
|
5
13
|
- Enables the reviewed MCP Apps renderer only in exact managed Codex Desktop
|
package/package.json
CHANGED
|
@@ -14,6 +14,7 @@ const PROFILE_SCHEMA = "impel.native-codex-profile.v1";
|
|
|
14
14
|
const DEFAULT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
15
15
|
const DEFAULT_GRACE_MS = 5_000;
|
|
16
16
|
const MAX_CAPTURE_BYTES = 256 * 1024 * 1024;
|
|
17
|
+
const TENANT_PREFLIGHT_RETRY_DELAYS_MS = [250, 750, 1_500];
|
|
17
18
|
|
|
18
19
|
function privateDirectory(directory) {
|
|
19
20
|
if (fs.existsSync(directory) && fs.lstatSync(directory).isSymbolicLink()) {
|
|
@@ -211,16 +212,17 @@ function runCaptured(command, args, { environment = process.env, timeoutMs = 60_
|
|
|
211
212
|
}
|
|
212
213
|
|
|
213
214
|
async function currentTenant(impelBinary, environment) {
|
|
214
|
-
for (let attempt = 0; attempt
|
|
215
|
+
for (let attempt = 0; attempt <= TENANT_PREFLIGHT_RETRY_DELAYS_MS.length; attempt += 1) {
|
|
215
216
|
const invocation = impelInvocation(impelBinary, ["tenant", "current"], environment);
|
|
216
217
|
const result = await runCaptured(invocation.command, invocation.args, { environment });
|
|
217
218
|
const lines = result.stdout.split(/\r?\n/u).map((line) => line.trim()).filter(Boolean);
|
|
218
219
|
if (result.code === 0 && lines.length === 1 && /^[A-Za-z0-9_.:-]{1,160}$/u.test(lines[0])) {
|
|
219
220
|
return lines[0];
|
|
220
221
|
}
|
|
221
|
-
|
|
222
|
+
const retryDelay = TENANT_PREFLIGHT_RETRY_DELAYS_MS[attempt];
|
|
223
|
+
if (retryDelay !== undefined) await delay(retryDelay);
|
|
222
224
|
}
|
|
223
|
-
throw new Error("could not establish one exact current Impel tenant after
|
|
225
|
+
throw new Error("could not establish one exact current Impel tenant after bounded attempts");
|
|
224
226
|
}
|
|
225
227
|
|
|
226
228
|
export async function assertExpectedTenant({ expectedTenant, impelBinary = "impel", environment = process.env }) {
|
|
@@ -495,19 +497,38 @@ async function profileAttempt(options, sessionDir, index) {
|
|
|
495
497
|
return record;
|
|
496
498
|
}
|
|
497
499
|
|
|
498
|
-
|
|
500
|
+
function profilerFailureClass(error) {
|
|
501
|
+
if (/could not establish one exact current Impel tenant/u.test(error?.message || "")) {
|
|
502
|
+
return "tenant-preflight-unavailable";
|
|
503
|
+
}
|
|
504
|
+
if (/selected tenant .* does not match expected tenant/u.test(error?.message || "")) {
|
|
505
|
+
return "tenant-mismatch";
|
|
506
|
+
}
|
|
507
|
+
return "attempt-infrastructure";
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
export async function runWorkers(options, sessionDir, profileAttemptImpl = profileAttempt) {
|
|
499
511
|
const results = new Array(options.attempts);
|
|
500
512
|
let next = 0;
|
|
513
|
+
let abort = null;
|
|
501
514
|
const worker = async () => {
|
|
502
515
|
for (;;) {
|
|
516
|
+
if (abort) return;
|
|
503
517
|
const index = next;
|
|
504
518
|
next += 1;
|
|
505
519
|
if (index >= options.attempts) return;
|
|
506
|
-
|
|
520
|
+
try {
|
|
521
|
+
results[index] = await profileAttemptImpl(options, sessionDir, index);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
abort ||= {
|
|
524
|
+
failureClass: profilerFailureClass(error),
|
|
525
|
+
attemptId: `${options.cohort}-${String(index + 1 + options.attemptOffset).padStart(3, "0")}`,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
507
528
|
}
|
|
508
529
|
};
|
|
509
530
|
await Promise.all(Array.from({ length: options.concurrency }, () => worker()));
|
|
510
|
-
return results;
|
|
531
|
+
return { attempts: results.filter(Boolean), abort };
|
|
511
532
|
}
|
|
512
533
|
|
|
513
534
|
async function restoreTenant(originalTenant, options) {
|
|
@@ -553,7 +574,7 @@ async function main(argv) {
|
|
|
553
574
|
privateDirectory(sessionDir);
|
|
554
575
|
let restored = false;
|
|
555
576
|
try {
|
|
556
|
-
const
|
|
577
|
+
const result = await runWorkers(options, sessionDir);
|
|
557
578
|
const aggregate = {
|
|
558
579
|
schema: PROFILE_SCHEMA,
|
|
559
580
|
sessionId,
|
|
@@ -564,12 +585,18 @@ async function main(argv) {
|
|
|
564
585
|
cohort: options.cohort,
|
|
565
586
|
cliVersion: options.hostBuild,
|
|
566
587
|
promptSha256: options.promptSha256,
|
|
567
|
-
attempts,
|
|
588
|
+
complete: result.abort === null && result.attempts.length === options.attempts,
|
|
589
|
+
expectedAttempts: options.attempts,
|
|
590
|
+
abort: result.abort,
|
|
591
|
+
attempts: result.attempts,
|
|
568
592
|
};
|
|
569
593
|
const aggregatePath = path.join(sessionDir, "aggregate.json");
|
|
570
594
|
privateWrite(aggregatePath, `${JSON.stringify(aggregate, null, 2)}\n`);
|
|
571
595
|
process.stderr.write(`Private Codex profile written under ${sessionDir}\n`);
|
|
572
596
|
process.stdout.write(`${JSON.stringify(aggregate)}\n`);
|
|
597
|
+
if (!aggregate.complete) {
|
|
598
|
+
throw new Error(`cohort aborted (${aggregate.abort?.failureClass || "incomplete"}); partial aggregate retained`);
|
|
599
|
+
}
|
|
573
600
|
} finally {
|
|
574
601
|
restored = await restoreTenant(originalTenant, options);
|
|
575
602
|
if (!restored) process.stderr.write("profile-native-codex: could not verify restoration of the original tenant\n");
|