blun-king-cli 9.1.599 → 9.1.601
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/CHANGELOG.md +16 -2
- package/LIESMICH.txt +1 -1
- package/README.md +13 -3
- package/agent-spine-plugin/CHANGELOG.md +1 -1
- package/agent-spine-plugin/docs/host-integration.md +1 -15
- package/agent-spine-plugin/docs/preflight-recall.md +1 -1
- package/agent-spine-plugin/scripts/check-install.js +1 -6
- package/agent-spine-plugin/scripts/hermetic-process.js +8 -0
- package/agent-spine-plugin/scripts/release-check.js +2 -3
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +8 -11
- package/agent-spine-plugin/src/hook.js +40 -40
- package/agent-spine-plugin/src/lib/briefing.js +6 -3
- package/agent-spine-plugin/src/lib/hook-context.js +63 -64
- package/agent-spine-plugin/src/lib/hook-output.js +115 -94
- package/agent-spine-plugin/src/lib/hook-timeline.js +20 -11
- package/agent-spine-plugin/src/lib/host-instruction-budget.js +8 -14
- package/agent-spine-plugin/src/lib/mcp-timeline-tools.js +0 -7
- package/agent-spine-plugin/src/lib/pre-answer-timeline-recall.js +104 -0
- package/agent-spine-plugin/src/lib/session-timeline-codex.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-storage.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-enrollment-transport.js +0 -2
- package/agent-spine-plugin/src/lib/session-timeline-enrollment.js +0 -22
- package/agent-spine-plugin/src/lib/session-timeline-host-origin.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-prior.js +42 -50
- package/agent-spine-plugin/src/lib/session-timeline-provider.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-query.js +0 -1
- package/agent-spine-plugin/src/lib/session-timeline-sid-acl.js +0 -4
- package/agent-spine-plugin/src/lib/session-timeline-source.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline-transport.js +0 -8
- package/agent-spine-plugin/src/lib/session-timeline-windows-acl.js +0 -3
- package/agent-spine-plugin/src/lib/session-timeline.js +370 -408
- package/agent-spine-plugin/src/lib/source-roots.js +26 -16
- package/agent-spine-plugin/src/lib/timeline-user-feedback.js +0 -1
- package/bin/core-bootstrap.js +18 -10
- package/bin/launcher-mode.js +5 -0
- package/bin/launcher-runtime.js +27 -0
- package/bin/verify-bundled-agent-sources.cjs +28 -2
- package/blun.mjs +1628 -1194
- package/bundled-agent-sources.json +192 -155
- package/package.json +1 -1
- package/standard-skills/translate-native/README.md +1334 -1
- package/standard-skills/translate-native/SKILL.md +1 -1
- package/standard-skills/translate-native/VERSION +1 -1
- package/standard-skills/translate-native/docs/PREMORTEM.md +901 -0
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION.md +208 -41
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_API.md +1319 -77
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_EVIDENCE_HTTP.md +66 -11
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_HTTP_PROVIDER.md +19 -1
- package/standard-skills/translate-native/docs/WEBSITE_LOCALIZATION_RECEIPT_VERIFIER_HTTP.md +24 -6
- package/standard-skills/translate-native/integrations/commercial_localization_profile.py +23 -0
- package/standard-skills/translate-native/integrations/website_localization.py +234 -10
- package/standard-skills/translate-native/integrations/website_localization_benchmark.py +39 -3
- package/standard-skills/translate-native/integrations/website_localization_cms.py +512 -10
- package/standard-skills/translate-native/integrations/website_localization_cms_client.py +116 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver.py +101 -11
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_runtime.py +12 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_receiver_store.py +186 -24
- package/standard-skills/translate-native/integrations/website_localization_cms_source_client.py +64 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery.py +528 -5
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth.py +918 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_auth_runtime.py +609 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_client.py +885 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_http.py +1244 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_runtime.py +220 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_sidecar_adapter.py +331 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_capabilities_http.py +444 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_client.py +673 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch.py +1317 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_client.py +826 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_http.py +1152 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_openapi.py +896 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_dispatch_runtime.py +621 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_http.py +1180 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_delivery_submission_runtime.py +1479 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_source_http.py +133 -17
- package/standard-skills/translate-native/integrations/website_localization_cms_source_runtime.py +319 -4
- package/standard-skills/translate-native/integrations/website_localization_cms_source_service.py +72 -2
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_http.py +13 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver.py +56 -13
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_openapi.py +335 -0
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_notification_receiver_runtime.py +66 -1
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_processing_monitor.py +73 -7
- package/standard-skills/translate-native/integrations/website_localization_cms_terminal_receiver_client.py +93 -9
- package/standard-skills/translate-native/integrations/website_localization_evidence_http.py +221 -11
- package/standard-skills/translate-native/integrations/website_localization_health.py +6 -0
- package/standard-skills/translate-native/integrations/website_localization_http_provider.py +1 -1
- package/standard-skills/translate-native/integrations/website_localization_quality_profiles.py +350 -0
- package/standard-skills/translate-native/integrations/website_localization_queue.py +126 -56
- package/standard-skills/translate-native/integrations/website_localization_receipt_verifier_http.py +166 -13
- package/standard-skills/translate-native/integrations/website_localization_release.py +423 -17
- package/standard-skills/translate-native/integrations/website_localization_release_coordinator.py +168 -13
- package/standard-skills/translate-native/integrations/website_localization_runner.py +10 -0
- package/standard-skills/translate-native/integrations/website_localization_worker.py +213 -9
- package/standard-skills/translate-native/provenance.json +2 -2
- package/standard-skills/translate-native/references/commercial-localization.md +96 -17
- package/standard-skills/translate-native/scripts/blun_language_guard.py +3 -1
- package/standard-skills/translate-native/scripts/check_commercial_review.py +69 -9
- package/standard-skills/translate-native/scripts/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/VERSION +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +3 -1
- package/standard-tools/language-guard/check_commercial_review.py +69 -9
- package/standard-tools/language-guard/commercial_localization_profile.py +829 -31
- package/standard-tools/language-guard/provenance.json +2 -2
- package/standard-tools/manifest.json +1 -1
- package/worker-host.mjs +1951 -1585
- package/agent-spine-plugin/scripts/check-install-king.js +0 -37
package/blun.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:b5b19f76ccc092b4eba456b9da34bbda10f5c0717713caa03a28337eab2cac02
|
|
3
3
|
import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
@@ -181000,7 +181000,10 @@ function applyCompletionBudgetWithDetails(args) {
|
|
|
181000
181000
|
});
|
|
181001
181001
|
if (args.retry !== void 0) cap = Math.max(args.retry.minimumCompletionTokens, Math.ceil(cap * args.retry.multiplier));
|
|
181002
181002
|
const maxContextTokens = args.capability?.max_context_tokens;
|
|
181003
|
-
if (args.usedContextTokens !== void 0 && maxContextTokens !== void 0 && maxContextTokens > 0)
|
|
181003
|
+
if (args.usedContextTokens !== void 0 && maxContextTokens !== void 0 && maxContextTokens > 0) {
|
|
181004
|
+
const headroom = Math.min(2048, Math.ceil(maxContextTokens * .01));
|
|
181005
|
+
cap = Math.max(MIN_FLOOR, Math.min(cap, maxContextTokens - args.usedContextTokens - headroom));
|
|
181006
|
+
}
|
|
181004
181007
|
return {
|
|
181005
181008
|
provider: args.provider.withMaxCompletionTokens(cap, {
|
|
181006
181009
|
usedContextTokens: args.usedContextTokens,
|
|
@@ -230341,7 +230344,7 @@ var init_full = __esmMin((() => {
|
|
|
230341
230344
|
this.agent.log.error("failed to refresh system prompt after compaction", { error });
|
|
230342
230345
|
}
|
|
230343
230346
|
await this.agent.injection.injectAfterCompaction();
|
|
230344
|
-
this.fitRetainedInput();
|
|
230347
|
+
this.fitRetainedInput({}, result.keptHeadUserMessageCount !== void 0);
|
|
230345
230348
|
this.lastCompactedState = {
|
|
230346
230349
|
tokenCount: this.tokenCountWithPending,
|
|
230347
230350
|
modelAlias: this.agent.activeResponderModel ?? this.agent.config.modelAlias,
|
|
@@ -230377,17 +230380,18 @@ var init_full = __esmMin((() => {
|
|
|
230377
230380
|
this.agent.turn.onCompactionFinished();
|
|
230378
230381
|
}
|
|
230379
230382
|
}
|
|
230380
|
-
fitRetainedInput(context = {}) {
|
|
230383
|
+
fitRetainedInput(context = {}, freshBudgetedSelection = false) {
|
|
230381
230384
|
const budget = this.getCompactionBudgetTokens();
|
|
230382
230385
|
const window = this.getEffectiveMaxContextTokens();
|
|
230383
230386
|
const limit = window > 0 ? window - 1 : Infinity;
|
|
230387
|
+
const hardContextLimit = window > 0 && !freshBudgetedSelection ? window : void 0;
|
|
230384
230388
|
const estimate = (messages) => this.estimateProjectedRequestTokens({
|
|
230385
230389
|
...context,
|
|
230386
230390
|
messages
|
|
230387
230391
|
});
|
|
230388
230392
|
const preserveLatestUser = this.agent.turn.hasActiveTurn;
|
|
230389
|
-
if (budget === void 0) return this.agent.context.fitCompactionPrefix(limit, estimate, preserveLatestUser);
|
|
230390
|
-
return this.agent.context.fitCompactionPrefix(Math.min(Math.floor(budget * .8), limit), estimate, preserveLatestUser) || this.agent.context.fitCompactionPrefix(Math.min(Math.floor(budget * .9) - 1, limit), estimate, preserveLatestUser);
|
|
230393
|
+
if (budget === void 0) return this.agent.context.fitCompactionPrefix(limit, estimate, preserveLatestUser, hardContextLimit);
|
|
230394
|
+
return this.agent.context.fitCompactionPrefix(Math.min(Math.floor(budget * .8), limit), estimate, preserveLatestUser, hardContextLimit) || this.agent.context.fitCompactionPrefix(Math.min(Math.floor(budget * .9) - 1, limit), estimate, preserveLatestUser, hardContextLimit);
|
|
230391
230395
|
}
|
|
230392
230396
|
buildInstruction(customInstruction) {
|
|
230393
230397
|
return renderPrompt(compaction_instruction_default, { customInstruction: customInstruction?.trim() ?? "" }).trimEnd();
|
|
@@ -234338,7 +234342,7 @@ var init_context$2 = __esmMin((() => {
|
|
|
234338
234342
|
this.agent.microCompaction.reset();
|
|
234339
234343
|
this.agent.emitStatusUpdated();
|
|
234340
234344
|
}
|
|
234341
|
-
fitCompactionPrefix(maxRequestTokens, estimateRequest, preserveLatestUser = false) {
|
|
234345
|
+
fitCompactionPrefix(maxRequestTokens, estimateRequest, preserveLatestUser = false, hardContextLimit) {
|
|
234342
234346
|
const prefixLength = this._history.findIndex((message) => message.origin?.kind === "compaction_summary");
|
|
234343
234347
|
if (prefixLength <= 0 || !Number.isSafeInteger(maxRequestTokens) || maxRequestTokens <= 0) return false;
|
|
234344
234348
|
const suffix = this._history.slice(prefixLength);
|
|
@@ -234350,7 +234354,9 @@ var init_context$2 = __esmMin((() => {
|
|
|
234350
234354
|
];
|
|
234351
234355
|
return Math.max(estimateTokensForMessages(messages), estimateRequest(project(messages, { dropOrphanResults: true })));
|
|
234352
234356
|
};
|
|
234353
|
-
|
|
234357
|
+
const requestTokens = estimate(this._history.slice(0, prefixLength));
|
|
234358
|
+
if (requestTokens <= maxRequestTokens) return false;
|
|
234359
|
+
if (hardContextLimit !== void 0 && requestTokens >= hardContextLimit) return false;
|
|
234354
234360
|
const sourceKey = Symbol("compaction source");
|
|
234355
234361
|
const sources = collectCompactableUserMessages(this._history.slice(0, prefixLength)).map((message) => ({
|
|
234356
234362
|
...message,
|
|
@@ -235212,6 +235218,9 @@ var init_engine = __esmMin((() => {
|
|
|
235212
235218
|
for (const [event, hooks] of this.byEvent.entries()) result[event] = hooks.length;
|
|
235213
235219
|
return result;
|
|
235214
235220
|
}
|
|
235221
|
+
hasMatchingHook(event, matcherValue) {
|
|
235222
|
+
return this.matchingHooks(event, matcherValue).length > 0;
|
|
235223
|
+
}
|
|
235215
235224
|
closeAdmission() {
|
|
235216
235225
|
this.admissionClosed = true;
|
|
235217
235226
|
}
|
|
@@ -264964,6 +264973,1381 @@ var init_tool_result_budget = __esmMin((() => {
|
|
|
264964
264973
|
TOOL_RESULT_PREVIEW_CHARS = 2e3;
|
|
264965
264974
|
}));
|
|
264966
264975
|
//#endregion
|
|
264976
|
+
//#region ../../packages/kaos/src/errors.ts
|
|
264977
|
+
var KaosError, KaosFileExistsError, KaosShellNotFoundError;
|
|
264978
|
+
var init_errors$1 = __esmMin((() => {
|
|
264979
|
+
KaosError = class extends Error {
|
|
264980
|
+
constructor(message) {
|
|
264981
|
+
super(message);
|
|
264982
|
+
this.name = "KaosError";
|
|
264983
|
+
}
|
|
264984
|
+
};
|
|
264985
|
+
KaosFileExistsError = class extends KaosError {
|
|
264986
|
+
constructor(message) {
|
|
264987
|
+
super(message);
|
|
264988
|
+
this.name = "KaosFileExistsError";
|
|
264989
|
+
}
|
|
264990
|
+
};
|
|
264991
|
+
KaosShellNotFoundError = class extends KaosError {
|
|
264992
|
+
constructor(message) {
|
|
264993
|
+
super(message);
|
|
264994
|
+
this.name = "KaosShellNotFoundError";
|
|
264995
|
+
}
|
|
264996
|
+
};
|
|
264997
|
+
}));
|
|
264998
|
+
//#endregion
|
|
264999
|
+
//#region ../../packages/kaos/src/environment.ts
|
|
265000
|
+
/**
|
|
265001
|
+
* Environment — cross-platform probe of OS / shell.
|
|
265002
|
+
*
|
|
265003
|
+
* Detection is a pure function of injected probes (`platform` / `arch` /
|
|
265004
|
+
* `release` / `env` / `isFile` / `execFileText`) so the same suite runs
|
|
265005
|
+
* identically on any host OS. `detectEnvironmentFromNode()` bundles the Node
|
|
265006
|
+
* defaults for production callers.
|
|
265007
|
+
*
|
|
265008
|
+
* On Windows the probe expects Git Bash (the canonical POSIX shell that
|
|
265009
|
+
* ships with Git for Windows). If it cannot be located the function
|
|
265010
|
+
* throws `KaosShellNotFoundError`; the SDK layer can wrap that into a
|
|
265011
|
+
* user-facing install hint. Set `BLUN_SHELL_PATH` to override.
|
|
265012
|
+
*/
|
|
265013
|
+
function resolveOsKind(platform) {
|
|
265014
|
+
switch (platform) {
|
|
265015
|
+
case "darwin": return "macOS";
|
|
265016
|
+
case "linux": return "Linux";
|
|
265017
|
+
case "win32": return "Windows";
|
|
265018
|
+
default: return platform;
|
|
265019
|
+
}
|
|
265020
|
+
}
|
|
265021
|
+
async function detectEnvironment(deps) {
|
|
265022
|
+
const osKind = resolveOsKind(deps.platform);
|
|
265023
|
+
const osArch = deps.arch;
|
|
265024
|
+
const osVersion = deps.release;
|
|
265025
|
+
if (deps.platform === "win32") return {
|
|
265026
|
+
osKind,
|
|
265027
|
+
osArch,
|
|
265028
|
+
osVersion,
|
|
265029
|
+
shellName: "bash",
|
|
265030
|
+
shellPath: await locateWindowsGitBash(deps)
|
|
265031
|
+
};
|
|
265032
|
+
const candidates = [
|
|
265033
|
+
"/bin/bash",
|
|
265034
|
+
"/usr/bin/bash",
|
|
265035
|
+
"/usr/local/bin/bash"
|
|
265036
|
+
];
|
|
265037
|
+
let found;
|
|
265038
|
+
for (const p of candidates) if (await deps.isFile(p)) {
|
|
265039
|
+
found = p;
|
|
265040
|
+
break;
|
|
265041
|
+
}
|
|
265042
|
+
if (found !== void 0) return {
|
|
265043
|
+
osKind,
|
|
265044
|
+
osArch,
|
|
265045
|
+
osVersion,
|
|
265046
|
+
shellName: "bash",
|
|
265047
|
+
shellPath: found
|
|
265048
|
+
};
|
|
265049
|
+
return {
|
|
265050
|
+
osKind,
|
|
265051
|
+
osArch,
|
|
265052
|
+
osVersion,
|
|
265053
|
+
shellName: "sh",
|
|
265054
|
+
shellPath: "/bin/sh"
|
|
265055
|
+
};
|
|
265056
|
+
}
|
|
265057
|
+
async function locateWindowsGitBash(deps) {
|
|
265058
|
+
const checked = [];
|
|
265059
|
+
const override = deps.env["BLUN_SHELL_PATH"]?.trim();
|
|
265060
|
+
if (override !== void 0 && override.length > 0) {
|
|
265061
|
+
checked.push(override);
|
|
265062
|
+
if (await deps.isFile(override)) return override;
|
|
265063
|
+
}
|
|
265064
|
+
const gitExecutables = await findExecutablesOnPath("git.exe", deps.env["PATH"], deps.platform, deps.isFile);
|
|
265065
|
+
for (const gitExe of gitExecutables) {
|
|
265066
|
+
const inferred = gitBashCandidatesFromGitExe(gitExe);
|
|
265067
|
+
if (inferred !== void 0) for (const candidate of inferred) {
|
|
265068
|
+
checked.push(candidate);
|
|
265069
|
+
if (await deps.isFile(candidate)) return candidate;
|
|
265070
|
+
}
|
|
265071
|
+
const gitExecPath = await readGitExecPath(deps, gitExe);
|
|
265072
|
+
if (gitExecPath === void 0) continue;
|
|
265073
|
+
for (const candidate of gitBashCandidatesFromGitExecPath(gitExecPath)) {
|
|
265074
|
+
checked.push(candidate);
|
|
265075
|
+
if (await deps.isFile(candidate)) return candidate;
|
|
265076
|
+
}
|
|
265077
|
+
}
|
|
265078
|
+
const candidates = [
|
|
265079
|
+
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
265080
|
+
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
265081
|
+
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
265082
|
+
"C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
|
|
265083
|
+
];
|
|
265084
|
+
const localAppData = deps.env["LOCALAPPDATA"]?.trim();
|
|
265085
|
+
if (localAppData !== void 0 && localAppData.length > 0) {
|
|
265086
|
+
candidates.push(`${localAppData}\\Programs\\Git\\bin\\bash.exe`);
|
|
265087
|
+
candidates.push(`${localAppData}\\Programs\\Git\\usr\\bin\\bash.exe`);
|
|
265088
|
+
}
|
|
265089
|
+
for (const candidate of candidates) {
|
|
265090
|
+
checked.push(candidate);
|
|
265091
|
+
if (await deps.isFile(candidate)) return candidate;
|
|
265092
|
+
}
|
|
265093
|
+
throw new KaosShellNotFoundError(`Git Bash was not found on this Windows host. Install Git for Windows from https://gitforwindows.org/ or set BLUN_SHELL_PATH to a bash.exe. Checked: ${checked.join(", ")}.`);
|
|
265094
|
+
}
|
|
265095
|
+
async function readGitExecPath(deps, gitExe) {
|
|
265096
|
+
if (deps.platform === "win32" && !isAbsoluteWindowsPath(gitExe)) return void 0;
|
|
265097
|
+
const stdout = await deps.execFileText(gitExe, ["--exec-path"], GIT_EXEC_PATH_TIMEOUT_MS);
|
|
265098
|
+
if (stdout === void 0) return void 0;
|
|
265099
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
265100
|
+
const execPath = line.trim();
|
|
265101
|
+
if (execPath.length > 0) return execPath;
|
|
265102
|
+
}
|
|
265103
|
+
}
|
|
265104
|
+
function gitBashCandidatesFromGitExe(gitExe) {
|
|
265105
|
+
const normalizedGitExe = path$18.win32.normalize(normalizeWindowsPath(gitExe));
|
|
265106
|
+
const gitDir = path$18.win32.dirname(normalizedGitExe);
|
|
265107
|
+
const gitDirName = path$18.win32.basename(gitDir).toLowerCase();
|
|
265108
|
+
if (gitDirName !== "cmd" && gitDirName !== "bin") return;
|
|
265109
|
+
return gitBashCandidatesFromGitRoot(path$18.win32.dirname(gitDir));
|
|
265110
|
+
}
|
|
265111
|
+
function gitBashCandidatesFromGitExecPath(execPath) {
|
|
265112
|
+
const normalized = path$18.win32.normalize(normalizeWindowsPath(execPath));
|
|
265113
|
+
const parts = normalized.split("\\");
|
|
265114
|
+
for (let i = parts.length - 1; i >= 0; i -= 1) {
|
|
265115
|
+
const segment = parts[i]?.toLowerCase();
|
|
265116
|
+
if (segment === "mingw32" || segment === "mingw64") {
|
|
265117
|
+
const root = parts.slice(0, i).join("\\");
|
|
265118
|
+
if (root.length > 0) return gitBashCandidatesFromGitRoot(root);
|
|
265119
|
+
}
|
|
265120
|
+
}
|
|
265121
|
+
return gitBashCandidatesFromGitRoot(path$18.win32.join(normalized, "..", ".."));
|
|
265122
|
+
}
|
|
265123
|
+
function gitBashCandidatesFromGitRoot(root) {
|
|
265124
|
+
return [path$18.win32.normalize(path$18.win32.join(root, "bin", "bash.exe")), path$18.win32.normalize(path$18.win32.join(root, "usr", "bin", "bash.exe"))];
|
|
265125
|
+
}
|
|
265126
|
+
function normalizeWindowsPath(path) {
|
|
265127
|
+
return path.replaceAll("/", "\\");
|
|
265128
|
+
}
|
|
265129
|
+
function isAbsoluteWindowsPath(path) {
|
|
265130
|
+
return path$18.win32.isAbsolute(normalizeWindowsPath(path));
|
|
265131
|
+
}
|
|
265132
|
+
function dedupeWindowsPaths(paths) {
|
|
265133
|
+
const deduped = [];
|
|
265134
|
+
const seen = /* @__PURE__ */ new Set();
|
|
265135
|
+
for (const path of paths) {
|
|
265136
|
+
const key = normalizeWindowsPath(path).toLowerCase();
|
|
265137
|
+
if (seen.has(key)) continue;
|
|
265138
|
+
seen.add(key);
|
|
265139
|
+
deduped.push(path);
|
|
265140
|
+
}
|
|
265141
|
+
return deduped;
|
|
265142
|
+
}
|
|
265143
|
+
function detectEnvironmentFromNode() {
|
|
265144
|
+
if (detectedEnvironment !== void 0) return detectedEnvironment;
|
|
265145
|
+
const platform = process.platform;
|
|
265146
|
+
const env = process.env;
|
|
265147
|
+
const isFile = async (path) => {
|
|
265148
|
+
try {
|
|
265149
|
+
await access(path, constants.F_OK);
|
|
265150
|
+
return true;
|
|
265151
|
+
} catch {
|
|
265152
|
+
return false;
|
|
265153
|
+
}
|
|
265154
|
+
};
|
|
265155
|
+
detectedEnvironment = detectEnvironment({
|
|
265156
|
+
platform,
|
|
265157
|
+
arch: process.arch,
|
|
265158
|
+
release: nodeOs.release(),
|
|
265159
|
+
env,
|
|
265160
|
+
isFile,
|
|
265161
|
+
execFileText: execFileText$1
|
|
265162
|
+
});
|
|
265163
|
+
return detectedEnvironment;
|
|
265164
|
+
}
|
|
265165
|
+
async function findExecutablesOnPath(name, pathEnv, platform, isFile) {
|
|
265166
|
+
if (pathEnv === void 0 || pathEnv.length === 0) return [];
|
|
265167
|
+
const listSep = platform === "win32" ? ";" : ":";
|
|
265168
|
+
const dirSep = platform === "win32" ? "\\" : "/";
|
|
265169
|
+
const paths = [];
|
|
265170
|
+
for (const rawDir of pathEnv.split(listSep)) {
|
|
265171
|
+
const dir = rawDir.trim();
|
|
265172
|
+
if (dir.length === 0) continue;
|
|
265173
|
+
if (platform === "win32" && !isAbsoluteWindowsPath(dir)) continue;
|
|
265174
|
+
const candidate = dir.endsWith(dirSep) ? `${dir}${name}` : `${dir}${dirSep}${name}`;
|
|
265175
|
+
if (await isFile(candidate)) paths.push(candidate);
|
|
265176
|
+
}
|
|
265177
|
+
return platform === "win32" ? dedupeWindowsPaths(paths) : paths;
|
|
265178
|
+
}
|
|
265179
|
+
async function execFileText$1(file, args, timeoutMs) {
|
|
265180
|
+
return new Promise((resolve) => {
|
|
265181
|
+
execFile(file, [...args], {
|
|
265182
|
+
encoding: "utf8",
|
|
265183
|
+
timeout: timeoutMs,
|
|
265184
|
+
windowsHide: true
|
|
265185
|
+
}, (error, stdout) => {
|
|
265186
|
+
if (error !== null) {
|
|
265187
|
+
resolve(void 0);
|
|
265188
|
+
return;
|
|
265189
|
+
}
|
|
265190
|
+
resolve(stdout);
|
|
265191
|
+
});
|
|
265192
|
+
});
|
|
265193
|
+
}
|
|
265194
|
+
var GIT_EXEC_PATH_TIMEOUT_MS, detectedEnvironment;
|
|
265195
|
+
var init_environment$1 = __esmMin((() => {
|
|
265196
|
+
init_errors$1();
|
|
265197
|
+
GIT_EXEC_PATH_TIMEOUT_MS = 5e3;
|
|
265198
|
+
}));
|
|
265199
|
+
//#endregion
|
|
265200
|
+
//#region ../../packages/kaos/src/internal.ts
|
|
265201
|
+
function isUtf8Continuation(byte) {
|
|
265202
|
+
return byte >= 128 && byte <= 191;
|
|
265203
|
+
}
|
|
265204
|
+
function decodeUtf8Ignore(data) {
|
|
265205
|
+
let output = "";
|
|
265206
|
+
let i = 0;
|
|
265207
|
+
while (i < data.length) {
|
|
265208
|
+
const b0 = data[i];
|
|
265209
|
+
if (b0 === void 0) break;
|
|
265210
|
+
if (b0 <= 127) {
|
|
265211
|
+
output += String.fromCodePoint(b0);
|
|
265212
|
+
i += 1;
|
|
265213
|
+
continue;
|
|
265214
|
+
}
|
|
265215
|
+
if (b0 >= 194 && b0 <= 223) {
|
|
265216
|
+
const b1 = data[i + 1];
|
|
265217
|
+
if (b1 !== void 0 && isUtf8Continuation(b1)) {
|
|
265218
|
+
output += String.fromCodePoint((b0 & 31) << 6 | b1 & 63);
|
|
265219
|
+
i += 2;
|
|
265220
|
+
continue;
|
|
265221
|
+
}
|
|
265222
|
+
i += 1;
|
|
265223
|
+
continue;
|
|
265224
|
+
}
|
|
265225
|
+
if (b0 >= 224 && b0 <= 239) {
|
|
265226
|
+
const b1 = data[i + 1];
|
|
265227
|
+
const b2 = data[i + 2];
|
|
265228
|
+
if (b1 !== void 0 && (b0 === 224 && b1 >= 160 && b1 <= 191 || b0 >= 225 && b0 <= 236 && isUtf8Continuation(b1) || b0 === 237 && b1 >= 128 && b1 <= 159 || b0 >= 238 && b0 <= 239 && isUtf8Continuation(b1)) && b2 !== void 0 && isUtf8Continuation(b2)) {
|
|
265229
|
+
output += String.fromCodePoint((b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63);
|
|
265230
|
+
i += 3;
|
|
265231
|
+
continue;
|
|
265232
|
+
}
|
|
265233
|
+
i += 1;
|
|
265234
|
+
continue;
|
|
265235
|
+
}
|
|
265236
|
+
if (b0 >= 240 && b0 <= 244) {
|
|
265237
|
+
const b1 = data[i + 1];
|
|
265238
|
+
const b2 = data[i + 2];
|
|
265239
|
+
const b3 = data[i + 3];
|
|
265240
|
+
if (b1 !== void 0 && (b0 === 240 && b1 >= 144 && b1 <= 191 || b0 >= 241 && b0 <= 243 && isUtf8Continuation(b1) || b0 === 244 && b1 >= 128 && b1 <= 143) && b2 !== void 0 && b3 !== void 0 && isUtf8Continuation(b2) && isUtf8Continuation(b3)) {
|
|
265241
|
+
output += String.fromCodePoint((b0 & 7) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63);
|
|
265242
|
+
i += 4;
|
|
265243
|
+
continue;
|
|
265244
|
+
}
|
|
265245
|
+
i += 1;
|
|
265246
|
+
continue;
|
|
265247
|
+
}
|
|
265248
|
+
i += 1;
|
|
265249
|
+
}
|
|
265250
|
+
return output;
|
|
265251
|
+
}
|
|
265252
|
+
function decodeUtf16LeIgnore(data) {
|
|
265253
|
+
let output = "";
|
|
265254
|
+
let i = 0;
|
|
265255
|
+
while (i + 1 < data.length) {
|
|
265256
|
+
const first = data[i];
|
|
265257
|
+
const second = data[i + 1];
|
|
265258
|
+
if (first === void 0 || second === void 0) break;
|
|
265259
|
+
const codeUnit = first | second << 8;
|
|
265260
|
+
if (codeUnit >= 55296 && codeUnit <= 56319) {
|
|
265261
|
+
const lowFirst = data[i + 2];
|
|
265262
|
+
const lowSecond = data[i + 3];
|
|
265263
|
+
if (lowFirst !== void 0 && lowSecond !== void 0) {
|
|
265264
|
+
const low = lowFirst | lowSecond << 8;
|
|
265265
|
+
if (low >= 56320 && low <= 57343) {
|
|
265266
|
+
const codePoint = 65536 + (codeUnit - 55296 << 10) + (low - 56320);
|
|
265267
|
+
output += String.fromCodePoint(codePoint);
|
|
265268
|
+
i += 4;
|
|
265269
|
+
continue;
|
|
265270
|
+
}
|
|
265271
|
+
}
|
|
265272
|
+
i += 2;
|
|
265273
|
+
continue;
|
|
265274
|
+
}
|
|
265275
|
+
if (codeUnit >= 56320 && codeUnit <= 57343) {
|
|
265276
|
+
i += 2;
|
|
265277
|
+
continue;
|
|
265278
|
+
}
|
|
265279
|
+
output += String.fromCodePoint(codeUnit);
|
|
265280
|
+
i += 2;
|
|
265281
|
+
}
|
|
265282
|
+
return output;
|
|
265283
|
+
}
|
|
265284
|
+
/**
|
|
265285
|
+
* Decode a Buffer into a string with Python-compatible `errors` handling.
|
|
265286
|
+
*
|
|
265287
|
+
* - `'strict'` (default): throw on invalid sequences (via TextDecoder `fatal: true`)
|
|
265288
|
+
* - `'replace'`: substitute each invalid sequence with U+FFFD (TextDecoder default)
|
|
265289
|
+
* - `'ignore'`: drop invalid input sequences while preserving valid U+FFFD characters
|
|
265290
|
+
*
|
|
265291
|
+
* Falls back to `Buffer.toString(encoding)` for encodings TextDecoder does not
|
|
265292
|
+
* support (e.g. `hex`, `base64`, `binary`, `latin1`) — those are lossless
|
|
265293
|
+
* byte-to-character mappings so `errors` has no effect.
|
|
265294
|
+
* @internal
|
|
265295
|
+
*/
|
|
265296
|
+
function decodeTextWithErrors(data, encoding, errors = "strict", ignoreBOM = false) {
|
|
265297
|
+
let webLabel;
|
|
265298
|
+
switch (encoding) {
|
|
265299
|
+
case "utf-8":
|
|
265300
|
+
case "utf8":
|
|
265301
|
+
webLabel = "utf-8";
|
|
265302
|
+
break;
|
|
265303
|
+
case "utf16le":
|
|
265304
|
+
case "ucs2":
|
|
265305
|
+
case "ucs-2":
|
|
265306
|
+
webLabel = "utf-16le";
|
|
265307
|
+
break;
|
|
265308
|
+
default: webLabel = void 0;
|
|
265309
|
+
}
|
|
265310
|
+
if (webLabel === void 0) return data.toString(encoding);
|
|
265311
|
+
if (errors === "strict") return new TextDecoder(webLabel, {
|
|
265312
|
+
fatal: true,
|
|
265313
|
+
ignoreBOM
|
|
265314
|
+
}).decode(data);
|
|
265315
|
+
if (errors === "ignore") return webLabel === "utf-8" ? decodeUtf8Ignore(data) : decodeUtf16LeIgnore(data);
|
|
265316
|
+
return new TextDecoder(webLabel, {
|
|
265317
|
+
fatal: false,
|
|
265318
|
+
ignoreBOM
|
|
265319
|
+
}).decode(data);
|
|
265320
|
+
}
|
|
265321
|
+
/**
|
|
265322
|
+
* Convert a glob pattern segment (e.g. "*.txt", "file?.log") into a RegExp.
|
|
265323
|
+
* Mirrors Python pathlib behavior: includes dotfiles, case-sensitive by default.
|
|
265324
|
+
* @internal
|
|
265325
|
+
*/
|
|
265326
|
+
function globPatternToRegex(pattern, caseSensitive) {
|
|
265327
|
+
let regex = "^";
|
|
265328
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
265329
|
+
const ch = pattern[i];
|
|
265330
|
+
if (ch === void 0) break;
|
|
265331
|
+
switch (ch) {
|
|
265332
|
+
case "*":
|
|
265333
|
+
regex += "[^/]*";
|
|
265334
|
+
break;
|
|
265335
|
+
case "?":
|
|
265336
|
+
regex += "[^/]";
|
|
265337
|
+
break;
|
|
265338
|
+
case "[": {
|
|
265339
|
+
const end = pattern.indexOf("]", i + 1);
|
|
265340
|
+
if (end === -1) regex += "\\[";
|
|
265341
|
+
else {
|
|
265342
|
+
let charClass = pattern.slice(i + 1, end);
|
|
265343
|
+
charClass = charClass.replace(/\\/g, "\\\\");
|
|
265344
|
+
if (charClass.startsWith("!")) charClass = "^" + charClass.slice(1);
|
|
265345
|
+
else if (charClass.startsWith("^")) charClass = "\\" + charClass;
|
|
265346
|
+
regex += "[" + charClass + "]";
|
|
265347
|
+
i = end;
|
|
265348
|
+
}
|
|
265349
|
+
break;
|
|
265350
|
+
}
|
|
265351
|
+
case "\\":
|
|
265352
|
+
if (i + 1 < pattern.length) {
|
|
265353
|
+
const next = pattern.charAt(i + 1);
|
|
265354
|
+
regex += next.replaceAll(/[{}()+.\\[\]^$|]/g, "\\$&");
|
|
265355
|
+
i++;
|
|
265356
|
+
} else regex += "\\\\";
|
|
265357
|
+
break;
|
|
265358
|
+
default: regex += ch.replaceAll(/[{}()+.\\[\]^$|]/g, "\\$&");
|
|
265359
|
+
}
|
|
265360
|
+
}
|
|
265361
|
+
regex += "$";
|
|
265362
|
+
return new RegExp(regex, caseSensitive ? "" : "i");
|
|
265363
|
+
}
|
|
265364
|
+
var BufferedReadable;
|
|
265365
|
+
var init_internal = __esmMin((() => {
|
|
265366
|
+
BufferedReadable = class extends Readable$1 {
|
|
265367
|
+
_source;
|
|
265368
|
+
_ended = false;
|
|
265369
|
+
constructor(source) {
|
|
265370
|
+
super({ highWaterMark: 128 * 1024 });
|
|
265371
|
+
this._source = source;
|
|
265372
|
+
this._source.on("data", this._onData);
|
|
265373
|
+
this._source.on("end", this._onEnd);
|
|
265374
|
+
this._source.on("close", this._onClose);
|
|
265375
|
+
this._source.on("error", this._onError);
|
|
265376
|
+
}
|
|
265377
|
+
_read() {
|
|
265378
|
+
if (!this._ended && !this.destroyed) this._source.resume();
|
|
265379
|
+
}
|
|
265380
|
+
_destroy(error, callback) {
|
|
265381
|
+
this._source.off("data", this._onData);
|
|
265382
|
+
this._source.off("end", this._onEnd);
|
|
265383
|
+
this._source.off("close", this._onClose);
|
|
265384
|
+
this._source.off("error", this._onError);
|
|
265385
|
+
this._source.destroy();
|
|
265386
|
+
callback(error);
|
|
265387
|
+
}
|
|
265388
|
+
_onData = (chunk) => {
|
|
265389
|
+
if (!this.push(chunk)) this._source.pause();
|
|
265390
|
+
};
|
|
265391
|
+
_onEnd = () => {
|
|
265392
|
+
this._ended = true;
|
|
265393
|
+
this.push(null);
|
|
265394
|
+
};
|
|
265395
|
+
_onClose = () => {
|
|
265396
|
+
if (!this._ended) {
|
|
265397
|
+
this._ended = true;
|
|
265398
|
+
this.push(null);
|
|
265399
|
+
}
|
|
265400
|
+
};
|
|
265401
|
+
_onError = (error) => {
|
|
265402
|
+
this.destroy(error);
|
|
265403
|
+
};
|
|
265404
|
+
};
|
|
265405
|
+
}));
|
|
265406
|
+
//#endregion
|
|
265407
|
+
//#region ../../packages/kaos/src/login-shell-path.ts
|
|
265408
|
+
/**
|
|
265409
|
+
* Login-shell PATH probe — enrich `process.env.PATH` with entries from the
|
|
265410
|
+
* user's login shell.
|
|
265411
|
+
*
|
|
265412
|
+
* When blun is launched from a context that skipped the user's shell
|
|
265413
|
+
* profile (GUI launchers, non-login parent shells), `process.env.PATH`
|
|
265414
|
+
* misses entries like `/opt/homebrew/bin`, so commands spawned by the Bash
|
|
265415
|
+
* tool can't find tools the user has in their interactive shell (e.g.
|
|
265416
|
+
* `gh`). We run the user's login shell once (`$SHELL -l -c /usr/bin/env`),
|
|
265417
|
+
* extract its PATH, and append the entries the current PATH lacks. Existing
|
|
265418
|
+
* entries keep their order and priority; failures (no resolvable shell,
|
|
265419
|
+
* hung or broken profile) silently leave PATH untouched.
|
|
265420
|
+
*
|
|
265421
|
+
* launchd/daemon launches can leave `$SHELL` unset or blank (see
|
|
265422
|
+
* `defaultShell()` in agent-core's terminalService for the same case), so
|
|
265423
|
+
* the probe falls back to the OS account's login shell from the user
|
|
265424
|
+
* database before giving up.
|
|
265425
|
+
*
|
|
265426
|
+
* Like `detectEnvironment`, the probe is a pure function of injected deps
|
|
265427
|
+
* so the suite runs identically on any host. Windows is skipped: the
|
|
265428
|
+
* problem is specific to POSIX login-shell profiles.
|
|
265429
|
+
*/
|
|
265430
|
+
/**
|
|
265431
|
+
* Run the user's login shell and return its PATH, or `undefined` when the
|
|
265432
|
+
* probe does not apply (Windows, no resolvable shell) or fails (spawn
|
|
265433
|
+
* error, timeout, no PATH in the output).
|
|
265434
|
+
*/
|
|
265435
|
+
async function probeLoginShellPath(deps) {
|
|
265436
|
+
if (deps.platform === "win32") return void 0;
|
|
265437
|
+
const envShell = deps.env["SHELL"]?.trim();
|
|
265438
|
+
const shell = envShell === void 0 || envShell.length === 0 ? deps.userShell() : envShell;
|
|
265439
|
+
if (shell === void 0 || shell.length === 0) return void 0;
|
|
265440
|
+
const stdout = await deps.execFileText(shell, [
|
|
265441
|
+
"-l",
|
|
265442
|
+
"-c",
|
|
265443
|
+
"/usr/bin/env"
|
|
265444
|
+
], LOGIN_SHELL_ENV_TIMEOUT_MS);
|
|
265445
|
+
if (stdout === void 0) return void 0;
|
|
265446
|
+
let path;
|
|
265447
|
+
for (const line of stdout.split("\n")) if (line.startsWith("PATH=")) path = line.slice(5).trim();
|
|
265448
|
+
if (path === void 0 || path.length === 0) return void 0;
|
|
265449
|
+
return path;
|
|
265450
|
+
}
|
|
265451
|
+
/**
|
|
265452
|
+
* Union of the current PATH and the login-shell PATH: the current PATH
|
|
265453
|
+
* string is kept verbatim — including empty components, which POSIX
|
|
265454
|
+
* command lookup treats as the current directory — and login-shell
|
|
265455
|
+
* entries the current PATH lacks are appended in their own order. When
|
|
265456
|
+
* nothing is missing the current string is returned unchanged. Only
|
|
265457
|
+
* absolute login-shell entries are imported: empty, `.`, and relative
|
|
265458
|
+
* components are all cwd-dependent lookup, and appending one the user
|
|
265459
|
+
* did not already have would widen their search path — LocalKaos runs
|
|
265460
|
+
* commands from arbitrary workspace directories.
|
|
265461
|
+
*/
|
|
265462
|
+
function mergeLoginShellPath(currentPath, loginShellPath) {
|
|
265463
|
+
const current = currentPath ?? "";
|
|
265464
|
+
const seen = new Set(current.split(":").filter((entry) => entry.length > 0));
|
|
265465
|
+
const additions = [];
|
|
265466
|
+
for (const entry of loginShellPath.split(":")) {
|
|
265467
|
+
if (!entry.startsWith("/") || seen.has(entry)) continue;
|
|
265468
|
+
seen.add(entry);
|
|
265469
|
+
additions.push(entry);
|
|
265470
|
+
}
|
|
265471
|
+
if (additions.length === 0) return current;
|
|
265472
|
+
if (currentPath === void 0) return additions.join(":");
|
|
265473
|
+
return `${current}:${additions.join(":")}`;
|
|
265474
|
+
}
|
|
265475
|
+
/** Probe the login shell and merge its PATH into `deps.env['PATH']`. */
|
|
265476
|
+
async function applyLoginShellPath(deps) {
|
|
265477
|
+
const loginShellPath = await probeLoginShellPath(deps);
|
|
265478
|
+
if (loginShellPath === void 0) return;
|
|
265479
|
+
const currentPath = deps.env["PATH"];
|
|
265480
|
+
const merged = mergeLoginShellPath(currentPath, loginShellPath);
|
|
265481
|
+
if (merged === (currentPath ?? "")) return;
|
|
265482
|
+
deps.env["PATH"] = merged;
|
|
265483
|
+
}
|
|
265484
|
+
/**
|
|
265485
|
+
* Production convenience — apply the probe to `process.env` once per
|
|
265486
|
+
* process. Memoised like `detectEnvironmentFromNode`: the login-shell PATH
|
|
265487
|
+
* does not change for the lifetime of the process, and repeated
|
|
265488
|
+
* `LocalKaos.create()` calls must not re-spawn the shell.
|
|
265489
|
+
*/
|
|
265490
|
+
/**
|
|
265491
|
+
* Login shell from the OS user database (`/etc/passwd` via getpwuid on
|
|
265492
|
+
* Linux, Directory Services on macOS). `userInfo()` throws when the uid
|
|
265493
|
+
* has no database entry (e.g. containers running an arbitrary uid), and
|
|
265494
|
+
* service accounts may carry `/usr/sbin/nologin` — the latter needs no
|
|
265495
|
+
* special casing here because probing it simply fails and degrades
|
|
265496
|
+
* silently.
|
|
265497
|
+
*/
|
|
265498
|
+
function userShellFromNode() {
|
|
265499
|
+
try {
|
|
265500
|
+
const shell = userInfo().shell;
|
|
265501
|
+
return shell === null || shell.length === 0 ? void 0 : shell;
|
|
265502
|
+
} catch {
|
|
265503
|
+
return;
|
|
265504
|
+
}
|
|
265505
|
+
}
|
|
265506
|
+
function applyLoginShellPathFromNode() {
|
|
265507
|
+
if (appliedLoginShellPath !== void 0) return appliedLoginShellPath;
|
|
265508
|
+
appliedLoginShellPath = applyLoginShellPath({
|
|
265509
|
+
platform: process.platform,
|
|
265510
|
+
env: process.env,
|
|
265511
|
+
userShell: userShellFromNode,
|
|
265512
|
+
execFileText: execFileText$1
|
|
265513
|
+
});
|
|
265514
|
+
return appliedLoginShellPath;
|
|
265515
|
+
}
|
|
265516
|
+
var LOGIN_SHELL_ENV_TIMEOUT_MS, appliedLoginShellPath;
|
|
265517
|
+
var init_login_shell_path = __esmMin((() => {
|
|
265518
|
+
init_environment$1();
|
|
265519
|
+
LOGIN_SHELL_ENV_TIMEOUT_MS = 5e3;
|
|
265520
|
+
}));
|
|
265521
|
+
//#endregion
|
|
265522
|
+
//#region ../../packages/kaos/src/local.ts
|
|
265523
|
+
/**
|
|
265524
|
+
* Build the `(dev, ino)` cycle-detection key used by `_globWalk`'s
|
|
265525
|
+
* visited set. Returns `null` when `ino` is 0, which Node returns on
|
|
265526
|
+
* filesystems that don't carry inodes (Windows FAT/exFAT, some SMB/NFS
|
|
265527
|
+
* mounts). A null key signals "no reliable identity for this dir" so
|
|
265528
|
+
* the caller skips visited tracking for that descent — cycle safety
|
|
265529
|
+
* is weakened on those filesystems, but normal walking works instead
|
|
265530
|
+
* of every directory colliding on the shared key `"<dev>:0"`.
|
|
265531
|
+
*/
|
|
265532
|
+
function cycleKey(s) {
|
|
265533
|
+
if (s.ino === 0) return null;
|
|
265534
|
+
return `${String(s.dev)}:${String(s.ino)}`;
|
|
265535
|
+
}
|
|
265536
|
+
function buildLocalSpawnOptions(_isWindows, cwd, env) {
|
|
265537
|
+
return {
|
|
265538
|
+
cwd,
|
|
265539
|
+
env,
|
|
265540
|
+
stdio: [
|
|
265541
|
+
"pipe",
|
|
265542
|
+
"pipe",
|
|
265543
|
+
"pipe"
|
|
265544
|
+
],
|
|
265545
|
+
detached: true,
|
|
265546
|
+
windowsHide: true
|
|
265547
|
+
};
|
|
265548
|
+
}
|
|
265549
|
+
function isUtf8Encoding(encoding) {
|
|
265550
|
+
return encoding === "utf-8" || encoding === "utf8";
|
|
265551
|
+
}
|
|
265552
|
+
function* splitLinesKeepingTerminator(text) {
|
|
265553
|
+
if (text.length === 0) return;
|
|
265554
|
+
let start = 0;
|
|
265555
|
+
for (let i = 0; i < text.length; i += 1) if (text.codePointAt(i) === 10) {
|
|
265556
|
+
yield text.slice(start, i + 1);
|
|
265557
|
+
start = i + 1;
|
|
265558
|
+
}
|
|
265559
|
+
if (start < text.length) yield text.slice(start);
|
|
265560
|
+
}
|
|
265561
|
+
function updateLineEndingFlagsFromBytes(flags, chunk, prevWasCr) {
|
|
265562
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
265563
|
+
const byte = chunk[i];
|
|
265564
|
+
if (byte === void 0) continue;
|
|
265565
|
+
if (byte === 13) {
|
|
265566
|
+
if (prevWasCr) flags.hasLoneCr = true;
|
|
265567
|
+
prevWasCr = true;
|
|
265568
|
+
} else if (byte === 10) {
|
|
265569
|
+
if (prevWasCr) flags.hasCrLf = true;
|
|
265570
|
+
else flags.hasLf = true;
|
|
265571
|
+
prevWasCr = false;
|
|
265572
|
+
} else {
|
|
265573
|
+
if (prevWasCr) flags.hasLoneCr = true;
|
|
265574
|
+
prevWasCr = false;
|
|
265575
|
+
}
|
|
265576
|
+
}
|
|
265577
|
+
return prevWasCr;
|
|
265578
|
+
}
|
|
265579
|
+
function createUtf8Validator() {
|
|
265580
|
+
let needed = 0;
|
|
265581
|
+
let lower = 128;
|
|
265582
|
+
let upper = 191;
|
|
265583
|
+
const fail = () => {
|
|
265584
|
+
throw new TypeError("Invalid UTF-8 data");
|
|
265585
|
+
};
|
|
265586
|
+
return {
|
|
265587
|
+
write(chunk) {
|
|
265588
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
265589
|
+
const byte = chunk[i];
|
|
265590
|
+
if (byte === void 0) continue;
|
|
265591
|
+
if (needed === 0) {
|
|
265592
|
+
if (byte <= 127) continue;
|
|
265593
|
+
if (byte >= 194 && byte <= 223) needed = 1;
|
|
265594
|
+
else if (byte === 224) {
|
|
265595
|
+
needed = 2;
|
|
265596
|
+
lower = 160;
|
|
265597
|
+
} else if (byte >= 225 && byte <= 236) needed = 2;
|
|
265598
|
+
else if (byte === 237) {
|
|
265599
|
+
needed = 2;
|
|
265600
|
+
upper = 159;
|
|
265601
|
+
} else if (byte >= 238 && byte <= 239) needed = 2;
|
|
265602
|
+
else if (byte === 240) {
|
|
265603
|
+
needed = 3;
|
|
265604
|
+
lower = 144;
|
|
265605
|
+
} else if (byte >= 241 && byte <= 243) needed = 3;
|
|
265606
|
+
else if (byte === 244) {
|
|
265607
|
+
needed = 3;
|
|
265608
|
+
upper = 143;
|
|
265609
|
+
} else fail();
|
|
265610
|
+
} else {
|
|
265611
|
+
if (byte < lower || byte > upper) fail();
|
|
265612
|
+
lower = 128;
|
|
265613
|
+
upper = 191;
|
|
265614
|
+
needed -= 1;
|
|
265615
|
+
}
|
|
265616
|
+
}
|
|
265617
|
+
},
|
|
265618
|
+
end() {
|
|
265619
|
+
if (needed !== 0) fail();
|
|
265620
|
+
}
|
|
265621
|
+
};
|
|
265622
|
+
}
|
|
265623
|
+
async function readRange(fh, start, length) {
|
|
265624
|
+
const data = Buffer.alloc(length);
|
|
265625
|
+
let offset = 0;
|
|
265626
|
+
while (offset < length) {
|
|
265627
|
+
const { bytesRead } = await fh.read(data, offset, length - offset, start + offset);
|
|
265628
|
+
if (bytesRead === 0) break;
|
|
265629
|
+
offset += bytesRead;
|
|
265630
|
+
}
|
|
265631
|
+
return offset === length ? data : data.subarray(0, offset);
|
|
265632
|
+
}
|
|
265633
|
+
function waitForSpawn(child) {
|
|
265634
|
+
return new Promise((resolve, reject) => {
|
|
265635
|
+
const onSpawn = () => {
|
|
265636
|
+
child.off("error", onError);
|
|
265637
|
+
resolve();
|
|
265638
|
+
};
|
|
265639
|
+
const onError = (err) => {
|
|
265640
|
+
child.off("spawn", onSpawn);
|
|
265641
|
+
reject(err);
|
|
265642
|
+
};
|
|
265643
|
+
child.once("spawn", onSpawn);
|
|
265644
|
+
child.once("error", onError);
|
|
265645
|
+
});
|
|
265646
|
+
}
|
|
265647
|
+
var isWindows$1, READ_CHUNK_SIZE, LocalProcess, LocalKaos;
|
|
265648
|
+
var init_local = __esmMin((() => {
|
|
265649
|
+
init_dist$6();
|
|
265650
|
+
init_environment$1();
|
|
265651
|
+
init_errors$1();
|
|
265652
|
+
init_internal();
|
|
265653
|
+
init_login_shell_path();
|
|
265654
|
+
isWindows$1 = process.platform === "win32";
|
|
265655
|
+
READ_CHUNK_SIZE = 64 * 1024;
|
|
265656
|
+
LocalProcess = class {
|
|
265657
|
+
stdin;
|
|
265658
|
+
stdout;
|
|
265659
|
+
stderr;
|
|
265660
|
+
pid;
|
|
265661
|
+
_child;
|
|
265662
|
+
_exitCode = null;
|
|
265663
|
+
_exitPromise;
|
|
265664
|
+
_disposed = false;
|
|
265665
|
+
constructor(child) {
|
|
265666
|
+
if (child.stdin === null || child.stdout === null || child.stderr === null) throw new Error("Process must be created with stdin/stdout/stderr pipes.");
|
|
265667
|
+
this._child = child;
|
|
265668
|
+
this.stdin = child.stdin;
|
|
265669
|
+
this.stdout = new BufferedReadable(child.stdout);
|
|
265670
|
+
this.stderr = new BufferedReadable(child.stderr);
|
|
265671
|
+
this.pid = child.pid ?? -1;
|
|
265672
|
+
this._exitPromise = new Promise((resolve, reject) => {
|
|
265673
|
+
child.on("exit", (code) => {
|
|
265674
|
+
this._exitCode = code ?? -1;
|
|
265675
|
+
resolve(this._exitCode);
|
|
265676
|
+
});
|
|
265677
|
+
child.on("error", (error) => {
|
|
265678
|
+
reject(error);
|
|
265679
|
+
});
|
|
265680
|
+
});
|
|
265681
|
+
}
|
|
265682
|
+
get exitCode() {
|
|
265683
|
+
return this._exitCode;
|
|
265684
|
+
}
|
|
265685
|
+
async wait() {
|
|
265686
|
+
return this._exitPromise;
|
|
265687
|
+
}
|
|
265688
|
+
kill(signal) {
|
|
265689
|
+
if (this.pid <= 0) return Promise.resolve();
|
|
265690
|
+
if (isWindows$1) {
|
|
265691
|
+
const taskkillArgs = [
|
|
265692
|
+
"/T",
|
|
265693
|
+
"/F",
|
|
265694
|
+
"/PID",
|
|
265695
|
+
String(this.pid)
|
|
265696
|
+
];
|
|
265697
|
+
return new Promise((resolve) => {
|
|
265698
|
+
const killer = spawn("taskkill", taskkillArgs, {
|
|
265699
|
+
stdio: "ignore",
|
|
265700
|
+
windowsHide: true
|
|
265701
|
+
});
|
|
265702
|
+
const done = () => {
|
|
265703
|
+
resolve();
|
|
265704
|
+
};
|
|
265705
|
+
killer.once("error", done);
|
|
265706
|
+
killer.once("close", done);
|
|
265707
|
+
});
|
|
265708
|
+
}
|
|
265709
|
+
try {
|
|
265710
|
+
process.kill(-this.pid, signal ?? "SIGTERM");
|
|
265711
|
+
} catch (error) {
|
|
265712
|
+
const err = error;
|
|
265713
|
+
if (err.code === "ESRCH") return Promise.resolve();
|
|
265714
|
+
if (err.code === "EPERM") {
|
|
265715
|
+
try {
|
|
265716
|
+
this._child.kill(signal ?? "SIGTERM");
|
|
265717
|
+
} catch {}
|
|
265718
|
+
return Promise.resolve();
|
|
265719
|
+
}
|
|
265720
|
+
throw error;
|
|
265721
|
+
}
|
|
265722
|
+
return Promise.resolve();
|
|
265723
|
+
}
|
|
265724
|
+
dispose() {
|
|
265725
|
+
if (this._disposed) return;
|
|
265726
|
+
this._disposed = true;
|
|
265727
|
+
this.stdin.destroy();
|
|
265728
|
+
this.stdout.destroy();
|
|
265729
|
+
this.stderr.destroy();
|
|
265730
|
+
}
|
|
265731
|
+
};
|
|
265732
|
+
LocalKaos = class LocalKaos {
|
|
265733
|
+
name = "local";
|
|
265734
|
+
osEnv;
|
|
265735
|
+
_cwd;
|
|
265736
|
+
_envLayers;
|
|
265737
|
+
constructor(osEnv, cwd, envLayers = []) {
|
|
265738
|
+
this._cwd = normalize$4(cwd ?? process.cwd());
|
|
265739
|
+
this.osEnv = osEnv;
|
|
265740
|
+
this._envLayers = envLayers;
|
|
265741
|
+
}
|
|
265742
|
+
/**
|
|
265743
|
+
* Construct a fresh `LocalKaos` after probing the host environment.
|
|
265744
|
+
*
|
|
265745
|
+
* Each call returns a new instance with its own `_cwd`; concurrent
|
|
265746
|
+
* callers can therefore operate on independent working directories
|
|
265747
|
+
* without polluting one another.
|
|
265748
|
+
*/
|
|
265749
|
+
static async create() {
|
|
265750
|
+
const [osEnv] = await Promise.all([detectEnvironmentFromNode(), applyLoginShellPathFromNode()]);
|
|
265751
|
+
return new LocalKaos(osEnv);
|
|
265752
|
+
}
|
|
265753
|
+
withCwd(cwd) {
|
|
265754
|
+
return new LocalKaos(this.osEnv, cwd, this._envLayers);
|
|
265755
|
+
}
|
|
265756
|
+
withEnv(env) {
|
|
265757
|
+
return new LocalKaos(this.osEnv, this._cwd, [...this._envLayers, env]);
|
|
265758
|
+
}
|
|
265759
|
+
_resolvePath(path) {
|
|
265760
|
+
if (isAbsolute$2(path)) return normalize$4(path);
|
|
265761
|
+
return join$4(this._cwd, path);
|
|
265762
|
+
}
|
|
265763
|
+
pathClass() {
|
|
265764
|
+
return isWindows$1 ? "win32" : "posix";
|
|
265765
|
+
}
|
|
265766
|
+
normpath(path) {
|
|
265767
|
+
return normalize$4(path);
|
|
265768
|
+
}
|
|
265769
|
+
gethome() {
|
|
265770
|
+
return normalize$4(homedir());
|
|
265771
|
+
}
|
|
265772
|
+
getcwd() {
|
|
265773
|
+
return this._cwd;
|
|
265774
|
+
}
|
|
265775
|
+
/**
|
|
265776
|
+
* Change the working directory of this LocalKaos instance.
|
|
265777
|
+
*
|
|
265778
|
+
* Unlike Python's `os.chdir`, this is instance-scoped and never touches
|
|
265779
|
+
* `process.cwd()`. Child processes spawned via {@link exec} inherit this
|
|
265780
|
+
* instance's `_cwd`; concurrent LocalKaos instances each carry their own
|
|
265781
|
+
* independent cwd. If you need Python-compatible process-global cwd,
|
|
265782
|
+
* call `process.chdir(x)` directly.
|
|
265783
|
+
*/
|
|
265784
|
+
async chdir(path) {
|
|
265785
|
+
const resolved = this._resolvePath(path);
|
|
265786
|
+
if (!(await stat(resolved)).isDirectory()) throw new Error(`Not a directory: ${resolved}`);
|
|
265787
|
+
this._cwd = resolved;
|
|
265788
|
+
}
|
|
265789
|
+
async stat(path, options) {
|
|
265790
|
+
const resolved = this._resolvePath(path);
|
|
265791
|
+
const s = options?.followSymlinks ?? true ? await stat(resolved) : await lstat(resolved);
|
|
265792
|
+
return {
|
|
265793
|
+
stMode: s.mode,
|
|
265794
|
+
stIno: s.ino,
|
|
265795
|
+
stDev: s.dev,
|
|
265796
|
+
stNlink: s.nlink,
|
|
265797
|
+
stUid: s.uid,
|
|
265798
|
+
stGid: s.gid,
|
|
265799
|
+
stSize: s.size,
|
|
265800
|
+
stAtime: s.atimeMs / 1e3,
|
|
265801
|
+
stMtime: s.mtimeMs / 1e3,
|
|
265802
|
+
stCtime: isWindows$1 ? s.birthtimeMs / 1e3 : s.ctimeMs / 1e3
|
|
265803
|
+
};
|
|
265804
|
+
}
|
|
265805
|
+
async *iterdir(path) {
|
|
265806
|
+
const resolved = this._resolvePath(path);
|
|
265807
|
+
const entries = await readdir(resolved);
|
|
265808
|
+
for (const entry of entries) yield join$4(resolved, entry);
|
|
265809
|
+
}
|
|
265810
|
+
async *glob(path, pattern, options) {
|
|
265811
|
+
const resolved = this._resolvePath(path);
|
|
265812
|
+
const caseSensitive = options?.caseSensitive ?? true;
|
|
265813
|
+
const patternParts = pattern.split("/");
|
|
265814
|
+
const initVisited = /* @__PURE__ */ new Set();
|
|
265815
|
+
try {
|
|
265816
|
+
const rootKey = cycleKey(await stat(resolved));
|
|
265817
|
+
if (rootKey !== null) initVisited.add(rootKey);
|
|
265818
|
+
} catch {}
|
|
265819
|
+
yield* this._globWalk(resolved, patternParts, caseSensitive, initVisited);
|
|
265820
|
+
}
|
|
265821
|
+
async *_globWalk(basePath, patternParts, caseSensitive, visited) {
|
|
265822
|
+
if (patternParts.length === 0) return;
|
|
265823
|
+
const [currentPattern, ...remainingParts] = patternParts;
|
|
265824
|
+
if (currentPattern === "**") {
|
|
265825
|
+
if (remainingParts.length > 0) yield* this._globWalk(basePath, remainingParts, caseSensitive, visited);
|
|
265826
|
+
else yield basePath;
|
|
265827
|
+
let entries;
|
|
265828
|
+
try {
|
|
265829
|
+
entries = await readdir(basePath);
|
|
265830
|
+
} catch {
|
|
265831
|
+
return;
|
|
265832
|
+
}
|
|
265833
|
+
for (const entry of entries) {
|
|
265834
|
+
const fullPath = join$4(basePath, entry);
|
|
265835
|
+
let entryStat;
|
|
265836
|
+
try {
|
|
265837
|
+
entryStat = await stat(fullPath);
|
|
265838
|
+
} catch {
|
|
265839
|
+
continue;
|
|
265840
|
+
}
|
|
265841
|
+
if (entryStat.isDirectory()) {
|
|
265842
|
+
const key = cycleKey(entryStat);
|
|
265843
|
+
if (key !== null && visited.has(key)) continue;
|
|
265844
|
+
yield* this._globWalk(fullPath, patternParts, caseSensitive, key !== null ? new Set([...visited, key]) : visited);
|
|
265845
|
+
} else if (remainingParts.length === 0) yield fullPath;
|
|
265846
|
+
}
|
|
265847
|
+
} else {
|
|
265848
|
+
const regex = globPatternToRegex(currentPattern ?? "", caseSensitive);
|
|
265849
|
+
let entries;
|
|
265850
|
+
try {
|
|
265851
|
+
entries = await readdir(basePath);
|
|
265852
|
+
} catch {
|
|
265853
|
+
return;
|
|
265854
|
+
}
|
|
265855
|
+
for (const entry of entries) {
|
|
265856
|
+
if (!regex.test(entry)) continue;
|
|
265857
|
+
const fullPath = join$4(basePath, entry);
|
|
265858
|
+
if (remainingParts.length === 0) yield fullPath;
|
|
265859
|
+
else {
|
|
265860
|
+
let entryStat;
|
|
265861
|
+
try {
|
|
265862
|
+
entryStat = await stat(fullPath);
|
|
265863
|
+
} catch {
|
|
265864
|
+
continue;
|
|
265865
|
+
}
|
|
265866
|
+
if (entryStat.isDirectory()) {
|
|
265867
|
+
const key = cycleKey(entryStat);
|
|
265868
|
+
if (key !== null && visited.has(key)) continue;
|
|
265869
|
+
yield* this._globWalk(fullPath, remainingParts, caseSensitive, key !== null ? new Set([...visited, key]) : visited);
|
|
265870
|
+
}
|
|
265871
|
+
}
|
|
265872
|
+
}
|
|
265873
|
+
}
|
|
265874
|
+
}
|
|
265875
|
+
async readBytes(path, n) {
|
|
265876
|
+
const resolved = this._resolvePath(path);
|
|
265877
|
+
if (n === void 0) return Buffer.from(await readFile(resolved));
|
|
265878
|
+
const fh = await open(resolved, "r");
|
|
265879
|
+
try {
|
|
265880
|
+
const buf = Buffer.alloc(n);
|
|
265881
|
+
const { bytesRead } = await fh.read(buf, 0, n, 0);
|
|
265882
|
+
return buf.subarray(0, bytesRead);
|
|
265883
|
+
} finally {
|
|
265884
|
+
await fh.close();
|
|
265885
|
+
}
|
|
265886
|
+
}
|
|
265887
|
+
async readText(path, options) {
|
|
265888
|
+
const resolved = this._resolvePath(path);
|
|
265889
|
+
const encoding = options?.encoding ?? "utf-8";
|
|
265890
|
+
const errors = options?.errors ?? "strict";
|
|
265891
|
+
return decodeTextWithErrors(await readFile(resolved), encoding, errors);
|
|
265892
|
+
}
|
|
265893
|
+
async *readLines(path, options) {
|
|
265894
|
+
const resolved = this._resolvePath(path);
|
|
265895
|
+
const encoding = options?.encoding ?? "utf-8";
|
|
265896
|
+
const errors = options?.errors ?? "strict";
|
|
265897
|
+
if (!isUtf8Encoding(encoding)) {
|
|
265898
|
+
yield* splitLinesKeepingTerminator(decodeTextWithErrors(await readFile(resolved), encoding, errors));
|
|
265899
|
+
return;
|
|
265900
|
+
}
|
|
265901
|
+
yield* this._readUtf8Lines(resolved, errors);
|
|
265902
|
+
}
|
|
265903
|
+
async scanTextFile(path) {
|
|
265904
|
+
const fh = await open(this._resolvePath(path), "r");
|
|
265905
|
+
try {
|
|
265906
|
+
const buf = Buffer.alloc(READ_CHUNK_SIZE);
|
|
265907
|
+
const flags = {
|
|
265908
|
+
hasCrLf: false,
|
|
265909
|
+
hasLf: false,
|
|
265910
|
+
hasLoneCr: false
|
|
265911
|
+
};
|
|
265912
|
+
const validator = createUtf8Validator();
|
|
265913
|
+
let totalLines = 0;
|
|
265914
|
+
let totalBytes = 0;
|
|
265915
|
+
let endsWithNewline = false;
|
|
265916
|
+
let hasNul = false;
|
|
265917
|
+
let prevWasCr = false;
|
|
265918
|
+
while (true) {
|
|
265919
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
265920
|
+
if (bytesRead === 0) break;
|
|
265921
|
+
const chunk = buf.subarray(0, bytesRead);
|
|
265922
|
+
validator.write(chunk);
|
|
265923
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
265924
|
+
const byte = chunk[i];
|
|
265925
|
+
if (byte === void 0) continue;
|
|
265926
|
+
if (byte === 0) hasNul = true;
|
|
265927
|
+
if (byte === 10) totalLines += 1;
|
|
265928
|
+
}
|
|
265929
|
+
prevWasCr = updateLineEndingFlagsFromBytes(flags, chunk, prevWasCr);
|
|
265930
|
+
totalBytes += bytesRead;
|
|
265931
|
+
endsWithNewline = chunk[bytesRead - 1] === 10;
|
|
265932
|
+
}
|
|
265933
|
+
if (prevWasCr) flags.hasLoneCr = true;
|
|
265934
|
+
validator.end();
|
|
265935
|
+
if (totalBytes > 0 && !endsWithNewline) totalLines += 1;
|
|
265936
|
+
return {
|
|
265937
|
+
totalLines,
|
|
265938
|
+
endsWithNewline,
|
|
265939
|
+
hasNul,
|
|
265940
|
+
lineEndingFlags: flags
|
|
265941
|
+
};
|
|
265942
|
+
} finally {
|
|
265943
|
+
await fh.close();
|
|
265944
|
+
}
|
|
265945
|
+
}
|
|
265946
|
+
async *readLineRange(path, options) {
|
|
265947
|
+
const resolved = this._resolvePath(path);
|
|
265948
|
+
const errors = options.errors ?? "strict";
|
|
265949
|
+
yield* this._readUtf8Lines(resolved, errors, {
|
|
265950
|
+
startLine: options.startLine,
|
|
265951
|
+
maxLines: options.maxLines
|
|
265952
|
+
});
|
|
265953
|
+
}
|
|
265954
|
+
async *readTailLines(path, options) {
|
|
265955
|
+
if (options.tailCount <= 0) return;
|
|
265956
|
+
const resolved = this._resolvePath(path);
|
|
265957
|
+
const errors = options.errors ?? "strict";
|
|
265958
|
+
const fh = await open(resolved, "r");
|
|
265959
|
+
try {
|
|
265960
|
+
const s = await fh.stat();
|
|
265961
|
+
if (s.size === 0) return;
|
|
265962
|
+
let pos = s.size;
|
|
265963
|
+
let foundLf = 0;
|
|
265964
|
+
let startOffset = 0;
|
|
265965
|
+
let needLf = options.tailCount;
|
|
265966
|
+
let sawTailBlock = false;
|
|
265967
|
+
while (pos > 0 && foundLf < needLf) {
|
|
265968
|
+
const readSize = Math.min(READ_CHUNK_SIZE, pos);
|
|
265969
|
+
pos -= readSize;
|
|
265970
|
+
const buf = Buffer.alloc(readSize);
|
|
265971
|
+
await fh.read(buf, 0, readSize, pos);
|
|
265972
|
+
if (!sawTailBlock) {
|
|
265973
|
+
sawTailBlock = true;
|
|
265974
|
+
needLf = buf[readSize - 1] === 10 ? options.tailCount + 1 : options.tailCount;
|
|
265975
|
+
}
|
|
265976
|
+
for (let i = readSize - 1; i >= 0; i -= 1) {
|
|
265977
|
+
if (buf[i] !== 10) continue;
|
|
265978
|
+
foundLf += 1;
|
|
265979
|
+
if (foundLf === needLf) {
|
|
265980
|
+
startOffset = pos + i + 1;
|
|
265981
|
+
break;
|
|
265982
|
+
}
|
|
265983
|
+
}
|
|
265984
|
+
}
|
|
265985
|
+
if (foundLf < needLf) startOffset = 0;
|
|
265986
|
+
yield* splitLinesKeepingTerminator(decodeTextWithErrors(await readRange(fh, startOffset, s.size - startOffset), "utf-8", errors, startOffset !== 0));
|
|
265987
|
+
} finally {
|
|
265988
|
+
await fh.close();
|
|
265989
|
+
}
|
|
265990
|
+
}
|
|
265991
|
+
async *_readUtf8Lines(resolved, errors, range) {
|
|
265992
|
+
const startLine = range?.startLine ?? 1;
|
|
265993
|
+
const maxLines = range?.maxLines ?? Number.POSITIVE_INFINITY;
|
|
265994
|
+
const fh = await open(resolved, "r");
|
|
265995
|
+
try {
|
|
265996
|
+
const buf = Buffer.alloc(READ_CHUNK_SIZE);
|
|
265997
|
+
let pending = [];
|
|
265998
|
+
let pendingOffset = 0;
|
|
265999
|
+
let fileOffset = 0;
|
|
266000
|
+
let lineNo = 1;
|
|
266001
|
+
let yielded = 0;
|
|
266002
|
+
while (true) {
|
|
266003
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
266004
|
+
if (bytesRead === 0) break;
|
|
266005
|
+
const chunk = buf.subarray(0, bytesRead);
|
|
266006
|
+
let lineStart = 0;
|
|
266007
|
+
for (let i = 0; i < chunk.length; i += 1) {
|
|
266008
|
+
if (chunk[i] !== 10) continue;
|
|
266009
|
+
const piece = chunk.subarray(lineStart, i + 1);
|
|
266010
|
+
const lineOffset = pending.length === 0 ? fileOffset + lineStart : pendingOffset;
|
|
266011
|
+
const line = pending.length === 0 ? piece : Buffer.concat([...pending, piece]);
|
|
266012
|
+
if (lineNo >= startLine) {
|
|
266013
|
+
yield decodeTextWithErrors(line, "utf-8", errors, lineOffset !== 0);
|
|
266014
|
+
yielded += 1;
|
|
266015
|
+
if (yielded >= maxLines) return;
|
|
266016
|
+
}
|
|
266017
|
+
pending = [];
|
|
266018
|
+
lineStart = i + 1;
|
|
266019
|
+
lineNo += 1;
|
|
266020
|
+
}
|
|
266021
|
+
if (lineStart < chunk.length) {
|
|
266022
|
+
const tail = Buffer.from(chunk.subarray(lineStart));
|
|
266023
|
+
if (pending.length === 0) pendingOffset = fileOffset + lineStart;
|
|
266024
|
+
pending.push(tail);
|
|
266025
|
+
}
|
|
266026
|
+
fileOffset += bytesRead;
|
|
266027
|
+
}
|
|
266028
|
+
if (pending.length > 0) {
|
|
266029
|
+
const line = Buffer.concat(pending);
|
|
266030
|
+
if (lineNo >= startLine) yield decodeTextWithErrors(line, "utf-8", errors, pendingOffset !== 0);
|
|
266031
|
+
}
|
|
266032
|
+
} finally {
|
|
266033
|
+
await fh.close();
|
|
266034
|
+
}
|
|
266035
|
+
}
|
|
266036
|
+
async writeBytes(path, data) {
|
|
266037
|
+
await writeFile(this._resolvePath(path), data);
|
|
266038
|
+
return data.length;
|
|
266039
|
+
}
|
|
266040
|
+
async writeText(path, data, options) {
|
|
266041
|
+
const resolved = this._resolvePath(path);
|
|
266042
|
+
const encoding = options?.encoding ?? "utf-8";
|
|
266043
|
+
if ((options?.mode ?? "w") === "a") await appendFile(resolved, data, encoding);
|
|
266044
|
+
else await writeFile(resolved, data, encoding);
|
|
266045
|
+
return data.length;
|
|
266046
|
+
}
|
|
266047
|
+
async mkdir(path, options) {
|
|
266048
|
+
const resolved = this._resolvePath(path);
|
|
266049
|
+
const parents = options?.parents ?? false;
|
|
266050
|
+
const existOk = options?.existOk ?? false;
|
|
266051
|
+
if (parents) {
|
|
266052
|
+
if (!existOk) try {
|
|
266053
|
+
if ((await stat(resolved)).isDirectory()) throw new KaosFileExistsError(`${resolved} already exists`);
|
|
266054
|
+
} catch (error) {
|
|
266055
|
+
if (error instanceof KaosFileExistsError) throw error;
|
|
266056
|
+
if (error.code !== "ENOENT") throw error;
|
|
266057
|
+
}
|
|
266058
|
+
await mkdir(resolved, { recursive: true });
|
|
266059
|
+
return;
|
|
266060
|
+
}
|
|
266061
|
+
try {
|
|
266062
|
+
await mkdir(resolved);
|
|
266063
|
+
} catch (error) {
|
|
266064
|
+
if (existOk && error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
266065
|
+
if (!(await stat(resolved)).isDirectory()) throw new KaosFileExistsError(`${resolved} already exists but is not a directory`);
|
|
266066
|
+
return;
|
|
266067
|
+
}
|
|
266068
|
+
throw error;
|
|
266069
|
+
}
|
|
266070
|
+
}
|
|
266071
|
+
async exec(...args) {
|
|
266072
|
+
const command = args[0];
|
|
266073
|
+
if (command === void 0) throw new Error("LocalKaos.exec(): at least one argument (the command to run) is required.");
|
|
266074
|
+
const child = spawn(command, args.slice(1), buildLocalSpawnOptions(isWindows$1, this._cwd, this._buildExecEnv()));
|
|
266075
|
+
await waitForSpawn(child);
|
|
266076
|
+
return new LocalProcess(child);
|
|
266077
|
+
}
|
|
266078
|
+
async execWithEnv(args, env) {
|
|
266079
|
+
const command = args[0];
|
|
266080
|
+
if (command === void 0) throw new Error("LocalKaos.execWithEnv(): at least one argument (the command to run) is required.");
|
|
266081
|
+
const child = spawn(command, args.slice(1), buildLocalSpawnOptions(isWindows$1, this._cwd, this._buildExecEnv(env)));
|
|
266082
|
+
await waitForSpawn(child);
|
|
266083
|
+
return new LocalProcess(child);
|
|
266084
|
+
}
|
|
266085
|
+
_buildExecEnv(invocationEnv) {
|
|
266086
|
+
if (this._envLayers.length === 0) return invocationEnv;
|
|
266087
|
+
const merged = {
|
|
266088
|
+
...process.env,
|
|
266089
|
+
...invocationEnv
|
|
266090
|
+
};
|
|
266091
|
+
for (const layer of this._envLayers) Object.assign(merged, layer);
|
|
266092
|
+
return merged;
|
|
266093
|
+
}
|
|
266094
|
+
};
|
|
266095
|
+
}));
|
|
266096
|
+
var init_current = __esmMin((() => {
|
|
266097
|
+
new AsyncLocalStorage();
|
|
266098
|
+
}));
|
|
266099
|
+
//#endregion
|
|
266100
|
+
//#region ../../packages/kaos/src/index.ts
|
|
266101
|
+
var init_src$1 = __esmMin((() => {
|
|
266102
|
+
init_environment$1();
|
|
266103
|
+
init_errors$1();
|
|
266104
|
+
init_local();
|
|
266105
|
+
init_current();
|
|
266106
|
+
}));
|
|
266107
|
+
//#endregion
|
|
266108
|
+
//#region ../../packages/agent-core/src/agent/turn/historical-tool-projection.ts
|
|
266109
|
+
function identity(stat) {
|
|
266110
|
+
return `${stat.dev}:${stat.ino}:${stat.birthtimeNs}`;
|
|
266111
|
+
}
|
|
266112
|
+
function revision(stat) {
|
|
266113
|
+
return `${identity(stat)}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}:${stat.mode}`;
|
|
266114
|
+
}
|
|
266115
|
+
function canonical(path) {
|
|
266116
|
+
const normalized = resolve(path);
|
|
266117
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
266118
|
+
}
|
|
266119
|
+
async function checkedDirectory(path) {
|
|
266120
|
+
const stat = await lstat(path, { bigint: true });
|
|
266121
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || canonical(await realpath(path)) !== canonical(path)) throw new Error("Unsafe recovery directory");
|
|
266122
|
+
return stat;
|
|
266123
|
+
}
|
|
266124
|
+
async function checkedAncestors(path) {
|
|
266125
|
+
for (let current = resolve(path); current !== parse(current).root; current = dirname(current)) await checkedDirectory(current);
|
|
266126
|
+
}
|
|
266127
|
+
function persistableText(message) {
|
|
266128
|
+
if (message.isError === true || message.content.length !== 1) return void 0;
|
|
266129
|
+
const part = message.content[0];
|
|
266130
|
+
if (part?.type !== "text") return void 0;
|
|
266131
|
+
const text = part.text;
|
|
266132
|
+
if (text.length < MIN_CHARS || text.includes("\0") || RECOVERY_REFERENCE.test(text) || Buffer.from(text, "utf8").toString("utf8") !== text || text.split("\n").some((line) => line.length > 2e3)) return void 0;
|
|
266133
|
+
return text;
|
|
266134
|
+
}
|
|
266135
|
+
var MIN_CHARS, MAX_REFERENCE_CHARS, RECOVERY_REFERENCE, HistoricalToolProjection;
|
|
266136
|
+
var init_historical_tool_projection = __esmMin((() => {
|
|
266137
|
+
init_src$1();
|
|
266138
|
+
init_src$3();
|
|
266139
|
+
init_read();
|
|
266140
|
+
init_file_type$1();
|
|
266141
|
+
init_fs$3();
|
|
266142
|
+
MIN_CHARS = 3e3;
|
|
266143
|
+
MAX_REFERENCE_CHARS = 2500;
|
|
266144
|
+
RECOVERY_REFERENCE = /\[Tool result offloaded\]|\[Repeated tool result omitted\]|^output_path\s*:|Tool output exceeded \d+ characters/m;
|
|
266145
|
+
HistoricalToolProjection = class {
|
|
266146
|
+
agent;
|
|
266147
|
+
files = /* @__PURE__ */ new Map();
|
|
266148
|
+
directories = /* @__PURE__ */ new Map();
|
|
266149
|
+
dirtyDirectories = /* @__PURE__ */ new Set();
|
|
266150
|
+
pending = Promise.resolve();
|
|
266151
|
+
constructor(agent) {
|
|
266152
|
+
this.agent = agent;
|
|
266153
|
+
}
|
|
266154
|
+
async project(history, turnAnchor, tools, context) {
|
|
266155
|
+
const unchanged = {
|
|
266156
|
+
history,
|
|
266157
|
+
changed: false
|
|
266158
|
+
};
|
|
266159
|
+
const boundary = turnAnchor === void 0 ? -1 : history.indexOf(turnAnchor);
|
|
266160
|
+
const read = tools.find((tool) => tool.name === "Read");
|
|
266161
|
+
if (boundary < 0 || !(read instanceof ReadTool) || !(this.agent.kaos instanceof LocalKaos) || this.agent.homedir === void 0 || this.agent.hooks?.hasMatchingHook("PreToolUse", "Read")) return unchanged;
|
|
266162
|
+
const calls = /* @__PURE__ */ new Map();
|
|
266163
|
+
const results = /* @__PURE__ */ new Map();
|
|
266164
|
+
const knownTools = new Set(this.agent.tools.loopTools.map((tool) => tool.name));
|
|
266165
|
+
history.forEach((message, index) => {
|
|
266166
|
+
for (const call of message.toolCalls) {
|
|
266167
|
+
const previous = calls.get(call.id);
|
|
266168
|
+
calls.set(call.id, {
|
|
266169
|
+
index,
|
|
266170
|
+
name: call.name,
|
|
266171
|
+
count: (previous?.count ?? 0) + 1
|
|
266172
|
+
});
|
|
266173
|
+
}
|
|
266174
|
+
if (message.role === "tool" && message.toolCallId !== void 0) {
|
|
266175
|
+
const previous = results.get(message.toolCallId);
|
|
266176
|
+
results.set(message.toolCallId, {
|
|
266177
|
+
index,
|
|
266178
|
+
count: (previous?.count ?? 0) + 1
|
|
266179
|
+
});
|
|
266180
|
+
}
|
|
266181
|
+
});
|
|
266182
|
+
const closedBatches = /* @__PURE__ */ new Set();
|
|
266183
|
+
for (let index = 0; index < boundary; index++) {
|
|
266184
|
+
const message = history[index];
|
|
266185
|
+
if (message.role === "assistant" && message.toolCalls.length > 0 && message.toolCalls.every((call) => {
|
|
266186
|
+
const result = results.get(call.id);
|
|
266187
|
+
return calls.get(call.id)?.count === 1 && result?.count === 1 && result.index > index && result.index < boundary;
|
|
266188
|
+
})) closedBatches.add(index);
|
|
266189
|
+
}
|
|
266190
|
+
const projected = [...history];
|
|
266191
|
+
let changed = false;
|
|
266192
|
+
for (let index = 0; index < boundary; index++) {
|
|
266193
|
+
context.signal.throwIfAborted();
|
|
266194
|
+
const message = history[index];
|
|
266195
|
+
if (message.role !== "tool" || !message.toolCallId) continue;
|
|
266196
|
+
const call = calls.get(message.toolCallId);
|
|
266197
|
+
if (call === void 0 || call.count !== 1 || !closedBatches.has(call.index) || !knownTools.has(call.name)) continue;
|
|
266198
|
+
const text = persistableText(message);
|
|
266199
|
+
if (text === void 0) continue;
|
|
266200
|
+
const digest = createHash("sha256").update(JSON.stringify([
|
|
266201
|
+
canonical(this.agent.homedir),
|
|
266202
|
+
call.name,
|
|
266203
|
+
message.toolCallId,
|
|
266204
|
+
text
|
|
266205
|
+
])).digest("hex");
|
|
266206
|
+
const outputPath = join(resolve(this.agent.homedir), "tool-results", "historical", `${digest}.txt`);
|
|
266207
|
+
const header = `[Tool result offloaded]\noutput_path: ${outputPath}\noutput_size_chars: ${text.length}\nsha256: ${createHash("sha256").update(text).digest("hex")}\nnext_step: Use Read with this path and line_offset/n_lines to recover the complete output.
|
|
266208
|
+
|
|
266209
|
+
[preview]
|
|
266210
|
+
`;
|
|
266211
|
+
if (header.length >= MAX_REFERENCE_CHARS) continue;
|
|
266212
|
+
try {
|
|
266213
|
+
if (!await this.canRead(read, outputPath, context)) continue;
|
|
266214
|
+
const save = this.pending.then(() => this.persist(outputPath, text));
|
|
266215
|
+
this.pending = save.catch(() => void 0);
|
|
266216
|
+
await save;
|
|
266217
|
+
const stat = await this.agent.kaos.stat(outputPath);
|
|
266218
|
+
if ((stat.stMode & 61440) !== 32768 || stat.stSize !== Buffer.byteLength(text)) continue;
|
|
266219
|
+
const bytes = await this.agent.kaos.readBytes(outputPath, Buffer.byteLength(text) + 1);
|
|
266220
|
+
if (!Buffer.from(bytes).equals(Buffer.from(text)) || detectFileType(outputPath, Buffer.from(bytes).subarray(0, 512)).kind !== "text") continue;
|
|
266221
|
+
await this.verifyFile(outputPath, text);
|
|
266222
|
+
context.signal.throwIfAborted();
|
|
266223
|
+
if (!await this.canRead(read, outputPath, context)) continue;
|
|
266224
|
+
let preview = text.slice(0, MAX_REFERENCE_CHARS - header.length);
|
|
266225
|
+
if (/[\uD800-\uDBFF]$/.test(preview)) preview = preview.slice(0, -1);
|
|
266226
|
+
projected[index] = {
|
|
266227
|
+
...message,
|
|
266228
|
+
content: [{
|
|
266229
|
+
type: "text",
|
|
266230
|
+
text: header + preview
|
|
266231
|
+
}]
|
|
266232
|
+
};
|
|
266233
|
+
changed = true;
|
|
266234
|
+
} catch {
|
|
266235
|
+
context.signal.throwIfAborted();
|
|
266236
|
+
}
|
|
266237
|
+
}
|
|
266238
|
+
try {
|
|
266239
|
+
for (const path of this.dirtyDirectories) await this.verifyDirectory(path);
|
|
266240
|
+
this.dirtyDirectories.clear();
|
|
266241
|
+
} catch {
|
|
266242
|
+
return unchanged;
|
|
266243
|
+
}
|
|
266244
|
+
return {
|
|
266245
|
+
history: changed ? projected : history,
|
|
266246
|
+
changed
|
|
266247
|
+
};
|
|
266248
|
+
}
|
|
266249
|
+
async canRead(read, path, context) {
|
|
266250
|
+
if (this.agent.tools.loopTools.find((tool) => tool.name === "Read") !== read || this.agent.hooks?.hasMatchingHook("PreToolUse", "Read")) return false;
|
|
266251
|
+
const args = {
|
|
266252
|
+
path,
|
|
266253
|
+
line_offset: 1,
|
|
266254
|
+
n_lines: 1e3
|
|
266255
|
+
};
|
|
266256
|
+
const execution = read.resolveExecution(args);
|
|
266257
|
+
if ("isError" in execution) return false;
|
|
266258
|
+
const toolCall = {
|
|
266259
|
+
type: "function",
|
|
266260
|
+
id: "historical-recovery-check",
|
|
266261
|
+
name: "Read",
|
|
266262
|
+
arguments: JSON.stringify(args)
|
|
266263
|
+
};
|
|
266264
|
+
for (const policy of this.agent.permission.policies) {
|
|
266265
|
+
const result = await policy.evaluate({
|
|
266266
|
+
...context,
|
|
266267
|
+
tool: read,
|
|
266268
|
+
toolCall,
|
|
266269
|
+
toolCalls: [toolCall],
|
|
266270
|
+
args,
|
|
266271
|
+
execution
|
|
266272
|
+
});
|
|
266273
|
+
if (result !== void 0) return result.kind === "approve" && result.executionMetadata === void 0;
|
|
266274
|
+
}
|
|
266275
|
+
return false;
|
|
266276
|
+
}
|
|
266277
|
+
async ensureDirectory(path) {
|
|
266278
|
+
let created = false;
|
|
266279
|
+
try {
|
|
266280
|
+
await mkdir(path, { mode: 448 });
|
|
266281
|
+
created = true;
|
|
266282
|
+
} catch (error) {
|
|
266283
|
+
if (error.code !== "EEXIST") throw error;
|
|
266284
|
+
}
|
|
266285
|
+
if (created && this.directories.has(dirname(path))) this.dirtyDirectories.add(dirname(path));
|
|
266286
|
+
const stat = await checkedDirectory(path);
|
|
266287
|
+
const previous = this.directories.get(path);
|
|
266288
|
+
if (previous !== void 0 && previous.identity !== identity(stat)) throw new Error("Recovery directory replaced");
|
|
266289
|
+
if (previous === void 0) {
|
|
266290
|
+
if (created) await hardenPrivatePath(path, "directory");
|
|
266291
|
+
await this.verifyDirectory(path);
|
|
266292
|
+
} else if (previous.revision !== revision(stat) && !this.dirtyDirectories.has(path)) await this.verifyDirectory(path);
|
|
266293
|
+
}
|
|
266294
|
+
async verifyDirectory(path) {
|
|
266295
|
+
const before = await checkedDirectory(path);
|
|
266296
|
+
const previous = this.directories.get(path);
|
|
266297
|
+
if (previous !== void 0 && previous.identity !== identity(before)) throw new Error("Recovery directory replaced");
|
|
266298
|
+
if (process.platform === "win32") new WindowsPrivateAcl().verify(path, "directory");
|
|
266299
|
+
else if ((before.mode & 63n) !== 0n) throw new Error("Recovery directory is not private");
|
|
266300
|
+
const after = await checkedDirectory(path);
|
|
266301
|
+
if (revision(before) !== revision(after)) throw new Error("Recovery directory changed during verification");
|
|
266302
|
+
this.directories.set(path, {
|
|
266303
|
+
identity: identity(after),
|
|
266304
|
+
revision: revision(after)
|
|
266305
|
+
});
|
|
266306
|
+
}
|
|
266307
|
+
async persist(path, text) {
|
|
266308
|
+
await checkedAncestors(dirname(dirname(dirname(path))));
|
|
266309
|
+
await this.ensureDirectory(dirname(dirname(path)));
|
|
266310
|
+
await this.ensureDirectory(dirname(path));
|
|
266311
|
+
if (this.files.has(path)) {
|
|
266312
|
+
await this.verifyFile(path, text);
|
|
266313
|
+
return;
|
|
266314
|
+
}
|
|
266315
|
+
try {
|
|
266316
|
+
await lstat(path);
|
|
266317
|
+
await this.verifyFile(path, text);
|
|
266318
|
+
if (process.platform === "win32") new WindowsPrivateAcl().verify(path, "file");
|
|
266319
|
+
this.files.set(path, revision(await lstat(path, { bigint: true })));
|
|
266320
|
+
return;
|
|
266321
|
+
} catch (error) {
|
|
266322
|
+
if (error.code !== "ENOENT") throw error;
|
|
266323
|
+
}
|
|
266324
|
+
const staging = join(dirname(path), `${randomUUID()}.staging`);
|
|
266325
|
+
this.dirtyDirectories.add(dirname(path));
|
|
266326
|
+
try {
|
|
266327
|
+
await atomicWritePrivate$1(staging, text);
|
|
266328
|
+
await checkedAncestors(dirname(path));
|
|
266329
|
+
await link(staging, path);
|
|
266330
|
+
} finally {
|
|
266331
|
+
await unlink(staging).catch(() => void 0);
|
|
266332
|
+
}
|
|
266333
|
+
await this.verifyFile(path, text);
|
|
266334
|
+
this.files.set(path, revision(await lstat(path, { bigint: true })));
|
|
266335
|
+
}
|
|
266336
|
+
async verifyFile(path, text) {
|
|
266337
|
+
const before = await lstat(path, { bigint: true });
|
|
266338
|
+
if (!before.isFile() || before.isSymbolicLink() || before.nlink !== 1n || before.size !== BigInt(Buffer.byteLength(text)) || process.platform !== "win32" && (before.mode & 63n) !== 0n || canonical(await realpath(path)) !== canonical(path)) throw new Error("Unsafe recovery artifact");
|
|
266339
|
+
const previous = this.files.get(path);
|
|
266340
|
+
if (previous !== void 0 && previous !== revision(before)) throw new Error("Recovery artifact changed");
|
|
266341
|
+
const handle = await open(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
266342
|
+
try {
|
|
266343
|
+
if (revision(await handle.stat({ bigint: true })) !== revision(before) || !(await handle.readFile()).equals(Buffer.from(text)) || revision(await handle.stat({ bigint: true })) !== revision(before) || revision(await lstat(path, { bigint: true })) !== revision(before) || canonical(await realpath(path)) !== canonical(path)) throw new Error("Recovery artifact changed");
|
|
266344
|
+
} finally {
|
|
266345
|
+
await handle.close();
|
|
266346
|
+
}
|
|
266347
|
+
}
|
|
266348
|
+
};
|
|
266349
|
+
}));
|
|
266350
|
+
//#endregion
|
|
264967
266351
|
//#region ../../packages/agent-core/src/agent/response-review-decision.ts
|
|
264968
266352
|
/** Never carry provider/guard prose, signed receipts or arbitrary codes into logs. */
|
|
264969
266353
|
function rejectionFindings(report) {
|
|
@@ -265018,6 +266402,71 @@ var init_response_review_decision = __esmMin((() => {
|
|
|
265018
266402
|
]);
|
|
265019
266403
|
}));
|
|
265020
266404
|
//#endregion
|
|
266405
|
+
//#region ../../packages/agent-core/src/agent/response-review-deadline.ts
|
|
266406
|
+
function createResponseReviewDeadline(source) {
|
|
266407
|
+
const absoluteExpiresAt = performance.now() + ABSOLUTE_TIMEOUT_MS;
|
|
266408
|
+
const absolute = createDeadlineAbortSignal(source, ABSOLUTE_TIMEOUT_MS);
|
|
266409
|
+
const controller = new AbortController();
|
|
266410
|
+
const unlink = linkAbortSignal(absolute.signal, controller);
|
|
266411
|
+
let stage = "setup";
|
|
266412
|
+
let didTimeout = false;
|
|
266413
|
+
let closed = false;
|
|
266414
|
+
let idle;
|
|
266415
|
+
let idleExpiresAt = 0;
|
|
266416
|
+
const expire = () => {
|
|
266417
|
+
didTimeout = true;
|
|
266418
|
+
controller.abort(abortError$1());
|
|
266419
|
+
};
|
|
266420
|
+
const expireIfDue = () => {
|
|
266421
|
+
if (closed || controller.signal.aborted) return;
|
|
266422
|
+
const now = performance.now();
|
|
266423
|
+
if (now >= absoluteExpiresAt || now >= idleExpiresAt) expire();
|
|
266424
|
+
};
|
|
266425
|
+
const refresh = (timeoutMs) => {
|
|
266426
|
+
idleExpiresAt = performance.now() + timeoutMs;
|
|
266427
|
+
if (idle !== void 0) clearTimeout(idle);
|
|
266428
|
+
idle = setTimeout(expire, timeoutMs);
|
|
266429
|
+
};
|
|
266430
|
+
refresh(IDLE_TIMEOUT_MS);
|
|
266431
|
+
return {
|
|
266432
|
+
signal: controller.signal,
|
|
266433
|
+
timedOut: () => didTimeout || absolute.timedOut(),
|
|
266434
|
+
throwIfAborted: () => {
|
|
266435
|
+
expireIfDue();
|
|
266436
|
+
controller.signal.throwIfAborted();
|
|
266437
|
+
},
|
|
266438
|
+
progress: (event) => {
|
|
266439
|
+
expireIfDue();
|
|
266440
|
+
if (closed || controller.signal.aborted) return;
|
|
266441
|
+
if (event === "native.start" && stage === "setup") {
|
|
266442
|
+
stage = "native";
|
|
266443
|
+
refresh(NATIVE_FIRST_CONTENT_MS);
|
|
266444
|
+
} else if (event === "native.text" && stage === "native") refresh(IDLE_TIMEOUT_MS);
|
|
266445
|
+
else if (event === "release.start" && stage === "native") {
|
|
266446
|
+
stage = "release";
|
|
266447
|
+
refresh(IDLE_TIMEOUT_MS);
|
|
266448
|
+
} else if (event === "verification.start" && stage === "release") {
|
|
266449
|
+
stage = "verification";
|
|
266450
|
+
refresh(IDLE_TIMEOUT_MS);
|
|
266451
|
+
}
|
|
266452
|
+
},
|
|
266453
|
+
clear: () => {
|
|
266454
|
+
closed = true;
|
|
266455
|
+
if (idle !== void 0) clearTimeout(idle);
|
|
266456
|
+
idle = void 0;
|
|
266457
|
+
unlink();
|
|
266458
|
+
absolute.clear();
|
|
266459
|
+
}
|
|
266460
|
+
};
|
|
266461
|
+
}
|
|
266462
|
+
var IDLE_TIMEOUT_MS, NATIVE_FIRST_CONTENT_MS, ABSOLUTE_TIMEOUT_MS;
|
|
266463
|
+
var init_response_review_deadline = __esmMin((() => {
|
|
266464
|
+
init_abort();
|
|
266465
|
+
IDLE_TIMEOUT_MS = 3e4;
|
|
266466
|
+
NATIVE_FIRST_CONTENT_MS = 9e4;
|
|
266467
|
+
ABSOLUTE_TIMEOUT_MS = 12e4;
|
|
266468
|
+
}));
|
|
266469
|
+
//#endregion
|
|
265021
266470
|
//#region ../../packages/agent-core/src/agent/response-review.ts
|
|
265022
266471
|
function createReviewedOutputDispatcher(options) {
|
|
265023
266472
|
let pending = [];
|
|
@@ -265103,6 +266552,7 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265103
266552
|
if (pending.length === 0) return options.dispatch(event);
|
|
265104
266553
|
if (event.uuid !== stepUuid) throw new Error("Response review step mismatch");
|
|
265105
266554
|
const currentEpoch = epoch;
|
|
266555
|
+
const isCurrentCandidate = () => epoch === currentEpoch;
|
|
265106
266556
|
const parts = [...pending];
|
|
265107
266557
|
reviewing = true;
|
|
265108
266558
|
const text = parts.map((part) => part.part.type === "text" ? part.part.text : "").join("");
|
|
@@ -265116,8 +266566,9 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265116
266566
|
for (let attempt = 1; attempt <= MAX_REVIEW_ATTEMPTS; attempt += 1) {
|
|
265117
266567
|
options.signal.throwIfAborted();
|
|
265118
266568
|
if (epoch !== currentEpoch) throw new Error("Response review candidate changed during verification");
|
|
265119
|
-
const deadline =
|
|
266569
|
+
const deadline = createResponseReviewDeadline(options.signal);
|
|
265120
266570
|
let requested;
|
|
266571
|
+
const pendingOperations = [];
|
|
265121
266572
|
let attemptRejection;
|
|
265122
266573
|
let attemptNativeRejection = false;
|
|
265123
266574
|
try {
|
|
@@ -265126,6 +266577,12 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265126
266577
|
turnId: event.turnId,
|
|
265127
266578
|
step: event.step,
|
|
265128
266579
|
signal: deadline.signal,
|
|
266580
|
+
onProgress: (progress) => {
|
|
266581
|
+
if (isCurrentCandidate()) deadline.progress(progress);
|
|
266582
|
+
},
|
|
266583
|
+
onPendingOperation: (operation) => {
|
|
266584
|
+
pendingOperations.push(operation.then(() => void 0, () => void 0));
|
|
266585
|
+
},
|
|
265129
266586
|
onRejected: (decision) => {
|
|
265130
266587
|
if (!deadline.signal.aborted) {
|
|
265131
266588
|
const message = rejectionMessage(decision);
|
|
@@ -265135,13 +266592,14 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265135
266592
|
}
|
|
265136
266593
|
});
|
|
265137
266594
|
approval = await abortable(requested, deadline.signal);
|
|
266595
|
+
deadline.throwIfAborted();
|
|
265138
266596
|
rejection = attemptRejection;
|
|
265139
266597
|
nativeRejection = attemptNativeRejection;
|
|
265140
266598
|
break;
|
|
265141
266599
|
} catch {
|
|
265142
266600
|
options.signal.throwIfAborted();
|
|
265143
266601
|
if (attemptRejection !== void 0) throw new Error(attemptRejection);
|
|
265144
|
-
if (deadline.timedOut() && attempt < MAX_REVIEW_ATTEMPTS && requested !== void 0 && epoch === currentEpoch && await waitForCancelledReview(requested)) continue;
|
|
266602
|
+
if (deadline.timedOut() && attempt < MAX_REVIEW_ATTEMPTS && requested !== void 0 && epoch === currentEpoch && await waitForCancelledReview(requested, pendingOperations)) continue;
|
|
265145
266603
|
throw new Error(deadline.timedOut() ? "Response review timed out" : "Response review failed");
|
|
265146
266604
|
} finally {
|
|
265147
266605
|
deadline.clear();
|
|
@@ -265178,10 +266636,16 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265178
266636
|
if (epoch === currentEpoch) clear();
|
|
265179
266637
|
}
|
|
265180
266638
|
}
|
|
265181
|
-
async function waitForCancelledReview(requested) {
|
|
266639
|
+
async function waitForCancelledReview(requested, pendingOperations) {
|
|
265182
266640
|
const deadline = createDeadlineAbortSignal(options.signal, REVIEW_CANCEL_SETTLE_MS);
|
|
265183
266641
|
try {
|
|
265184
266642
|
await abortable(requested.then(() => void 0, () => void 0), deadline.signal);
|
|
266643
|
+
let observed = 0;
|
|
266644
|
+
while (observed < pendingOperations.length) {
|
|
266645
|
+
const batch = pendingOperations.slice(observed);
|
|
266646
|
+
observed = pendingOperations.length;
|
|
266647
|
+
await abortable(Promise.all(batch), deadline.signal);
|
|
266648
|
+
}
|
|
265185
266649
|
options.signal.throwIfAborted();
|
|
265186
266650
|
return true;
|
|
265187
266651
|
} catch {
|
|
@@ -265193,13 +266657,13 @@ function createReviewedOutputDispatcher(options) {
|
|
|
265193
266657
|
}
|
|
265194
266658
|
return dispatch;
|
|
265195
266659
|
}
|
|
265196
|
-
var MAX_CANDIDATE_BYTES, MAX_CANDIDATE_PARTS,
|
|
266660
|
+
var MAX_CANDIDATE_BYTES, MAX_CANDIDATE_PARTS, REVIEW_CANCEL_SETTLE_MS, MAX_REVIEW_ATTEMPTS;
|
|
265197
266661
|
var init_response_review = __esmMin((() => {
|
|
265198
266662
|
init_abort();
|
|
265199
266663
|
init_response_review_decision();
|
|
266664
|
+
init_response_review_deadline();
|
|
265200
266665
|
MAX_CANDIDATE_BYTES = 1048576;
|
|
265201
266666
|
MAX_CANDIDATE_PARTS = 4096;
|
|
265202
|
-
REVIEW_TIMEOUT_MS = 3e4;
|
|
265203
266667
|
REVIEW_CANCEL_SETTLE_MS = 1e3;
|
|
265204
266668
|
MAX_REVIEW_ATTEMPTS = 2;
|
|
265205
266669
|
}));
|
|
@@ -265528,6 +266992,7 @@ var init_turn = __esmMin((() => {
|
|
|
265528
266992
|
init_canonical_args();
|
|
265529
266993
|
init_tool_dedup();
|
|
265530
266994
|
init_tool_result_budget();
|
|
266995
|
+
init_historical_tool_projection();
|
|
265531
266996
|
init_response_review();
|
|
265532
266997
|
import_turn_tool_performance_policy = require_turn_tool_performance_policy();
|
|
265533
266998
|
BLUN_LEAN_TOOL_NAMES = new Set([
|
|
@@ -265610,8 +267075,10 @@ var init_turn = __esmMin((() => {
|
|
|
265610
267075
|
stepFailureByTurn = /* @__PURE__ */ new Map();
|
|
265611
267076
|
providerRequestFailureByTurn = /* @__PURE__ */ new Map();
|
|
265612
267077
|
currentStep = 0;
|
|
267078
|
+
historicalToolProjection;
|
|
265613
267079
|
constructor(agent) {
|
|
265614
267080
|
this.agent = agent;
|
|
267081
|
+
this.historicalToolProjection = new HistoricalToolProjection(agent);
|
|
265615
267082
|
}
|
|
265616
267083
|
/** Explicit host shutdown only; ordinary cancellation remains resumable. */
|
|
265617
267084
|
closeAdmission() {
|
|
@@ -266017,7 +267484,10 @@ var init_turn = __esmMin((() => {
|
|
|
266017
267484
|
turnId,
|
|
266018
267485
|
origin
|
|
266019
267486
|
});
|
|
267487
|
+
const previousLastMessage = this.agent.context.history.at(-1);
|
|
266020
267488
|
this.agent.context.appendUserMessage(input, origin);
|
|
267489
|
+
const appendedMessage = this.agent.context.history.at(-1);
|
|
267490
|
+
const turnAnchor = appendedMessage !== previousLastMessage && appendedMessage?.role === "user" && appendedMessage.origin === origin ? appendedMessage : void 0;
|
|
266021
267491
|
const startedAt = Date.now();
|
|
266022
267492
|
let ended;
|
|
266023
267493
|
let blockedByUserPromptHook = false;
|
|
@@ -266044,7 +267514,7 @@ var init_turn = __esmMin((() => {
|
|
|
266044
267514
|
this.agent.log.warn("Turn-start observation failed");
|
|
266045
267515
|
}
|
|
266046
267516
|
signal.throwIfAborted();
|
|
266047
|
-
const stopReason = await this.runStepLoop(turnId, signal, input, origin, (response) => {
|
|
267517
|
+
const stopReason = await this.runStepLoop(turnId, signal, input, origin, turnAnchor, (response) => {
|
|
266048
267518
|
completedResponse = response;
|
|
266049
267519
|
});
|
|
266050
267520
|
completedStopReason = stopReason;
|
|
@@ -266209,7 +267679,7 @@ var init_turn = __esmMin((() => {
|
|
|
266209
267679
|
content: hookResult.message
|
|
266210
267680
|
});
|
|
266211
267681
|
}
|
|
266212
|
-
async runStepLoop(turnId, signal, input, origin, onFinalResponse) {
|
|
267682
|
+
async runStepLoop(turnId, signal, input, origin, turnAnchor, onFinalResponse) {
|
|
266213
267683
|
let stopHookContinuationUsed = false;
|
|
266214
267684
|
let goalOutcomeMessageContinuationUsed = false;
|
|
266215
267685
|
const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
|
|
@@ -266222,11 +267692,25 @@ var init_turn = __esmMin((() => {
|
|
|
266222
267692
|
let taskToolsNeeded = turnNeedsThinking || blunTurnHasAttachment(input);
|
|
266223
267693
|
const greetingAnchor = this.agent.context.history.findLast((message) => message.role === "user" && message.origin?.kind === "user");
|
|
266224
267694
|
let partialContext = false;
|
|
266225
|
-
const turnHistory = () => {
|
|
266226
|
-
const
|
|
267695
|
+
const turnHistory = async (tools) => {
|
|
267696
|
+
const raw = [...this.agent.context.history];
|
|
267697
|
+
const history = personalMemoryRecall === void 0 ? raw : [...raw, personalMemoryRecall];
|
|
266227
267698
|
const selected = taskToolsNeeded ? history : greetingHistory(history, greetingAnchor);
|
|
266228
|
-
|
|
266229
|
-
|
|
267699
|
+
const projected = await this.historicalToolProjection.project(selected, turnAnchor, tools, {
|
|
267700
|
+
turnId: String(turnId),
|
|
267701
|
+
stepNumber: this.currentStep,
|
|
267702
|
+
signal,
|
|
267703
|
+
llm: turnLLM
|
|
267704
|
+
});
|
|
267705
|
+
const current = this.agent.context.history;
|
|
267706
|
+
if (current.length !== raw.length || current.some((message, index) => message !== raw[index])) {
|
|
267707
|
+
const latest = personalMemoryRecall === void 0 ? current : [...current, personalMemoryRecall];
|
|
267708
|
+
const retained = taskToolsNeeded ? latest : greetingHistory(latest, greetingAnchor);
|
|
267709
|
+
partialContext = retained.length < latest.length;
|
|
267710
|
+
return retained;
|
|
267711
|
+
}
|
|
267712
|
+
partialContext = selected.length < history.length || projected.changed;
|
|
267713
|
+
return projected.history;
|
|
266230
267714
|
};
|
|
266231
267715
|
const turnLLM = this.agent.llmForTurn(turnNeedsThinking ? void 0 : "off");
|
|
266232
267716
|
const turnTools = this.agent.tools.captureTurnTools();
|
|
@@ -266262,8 +267746,8 @@ var init_turn = __esmMin((() => {
|
|
|
266262
267746
|
}, completion);
|
|
266263
267747
|
},
|
|
266264
267748
|
llm: turnLLM,
|
|
266265
|
-
buildMessages: () => this.agent.context.project(turnHistory(), { dropOrphanResults: true }),
|
|
266266
|
-
buildMessagesStrict: () => this.agent.context.project(turnHistory(), {
|
|
267749
|
+
buildMessages: async () => this.agent.context.project(await turnHistory(selectedTools), { dropOrphanResults: true }),
|
|
267750
|
+
buildMessagesStrict: async () => this.agent.context.project(await turnHistory(selectedTools), {
|
|
266267
267751
|
synthesizeMissing: true,
|
|
266268
267752
|
dropOrphanResults: true,
|
|
266269
267753
|
dedupeDuplicateToolCalls: true,
|
|
@@ -269318,12 +270802,14 @@ function readPayload(result, includeError = false) {
|
|
|
269318
270802
|
/** Receipts never enter ordinary tool execution, hooks, replay or model history. */
|
|
269319
270803
|
function createGuardResponseReviewer(host) {
|
|
269320
270804
|
const { language, guardVersion } = host;
|
|
269321
|
-
return async ({ text, turnId, step, signal, onRejected }) => {
|
|
270805
|
+
return async ({ text, turnId, step, signal, onRejected, onPendingOperation, onProgress }) => {
|
|
269322
270806
|
const input = {
|
|
269323
270807
|
text,
|
|
269324
270808
|
turnId,
|
|
269325
270809
|
step,
|
|
269326
|
-
signal
|
|
270810
|
+
signal,
|
|
270811
|
+
onPendingOperation,
|
|
270812
|
+
onProgress
|
|
269327
270813
|
};
|
|
269328
270814
|
const targetSha256 = digest(text);
|
|
269329
270815
|
let stage = "setup";
|
|
@@ -269350,6 +270836,10 @@ function createGuardResponseReviewer(host) {
|
|
|
269350
270836
|
const blocked = (reason, findings) => {
|
|
269351
270837
|
record(signal.aborted ? "cancelled" : reason, findings);
|
|
269352
270838
|
};
|
|
270839
|
+
const track = (operation) => {
|
|
270840
|
+
onPendingOperation?.(operation.then(() => void 0, () => void 0));
|
|
270841
|
+
return operation;
|
|
270842
|
+
};
|
|
269353
270843
|
try {
|
|
269354
270844
|
if (!/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/.test(language) || /^(auto|all)$/i.test(language) || guardVersion.trim().length === 0) return blocked("invalid_settings");
|
|
269355
270845
|
const resolve = () => {
|
|
@@ -269362,13 +270852,14 @@ function createGuardResponseReviewer(host) {
|
|
|
269362
270852
|
const current = () => !signal.aborted && resolve()?.client === connection.client;
|
|
269363
270853
|
if (!current()) return blocked("connection_changed");
|
|
269364
270854
|
stage = "native";
|
|
269365
|
-
|
|
270855
|
+
onProgress?.("native.start");
|
|
270856
|
+
const native = await abortable(track(host.reviewNative({ ...input })), signal);
|
|
269366
270857
|
if (!current()) return blocked("connection_changed");
|
|
269367
270858
|
if (native === void 0) return blocked("native_unavailable");
|
|
269368
270859
|
if (!passed(native.nativeness) || !passed(native.orthography)) return blocked("native_rejected");
|
|
269369
270860
|
const authorized = async (name) => {
|
|
269370
270861
|
if (!current()) return false;
|
|
269371
|
-
return passed(await abortable(host.authorize({
|
|
270862
|
+
return passed(await abortable(track(host.authorize({
|
|
269372
270863
|
toolName: qualifyMcpToolName(SERVER_NAME, name),
|
|
269373
270864
|
targetSha256,
|
|
269374
270865
|
language,
|
|
@@ -269377,11 +270868,12 @@ function createGuardResponseReviewer(host) {
|
|
|
269377
270868
|
turnId,
|
|
269378
270869
|
step,
|
|
269379
270870
|
signal
|
|
269380
|
-
}), signal)) && current();
|
|
270871
|
+
})), signal)) && current();
|
|
269381
270872
|
};
|
|
269382
270873
|
stage = "release";
|
|
270874
|
+
onProgress?.("release.start");
|
|
269383
270875
|
if (!await authorized("release_response")) return blocked("release_denied");
|
|
269384
|
-
const releaseResult = await abortable(connection.client.callTool("release_response", {
|
|
270876
|
+
const releaseResult = await abortable(track(connection.client.callTool("release_response", {
|
|
269385
270877
|
target_text: text,
|
|
269386
270878
|
language,
|
|
269387
270879
|
content_type: "prose",
|
|
@@ -269390,7 +270882,7 @@ function createGuardResponseReviewer(host) {
|
|
|
269390
270882
|
nativeness: true,
|
|
269391
270883
|
orthography: true
|
|
269392
270884
|
}
|
|
269393
|
-
}, signal), signal);
|
|
270885
|
+
}, signal)), signal);
|
|
269394
270886
|
if (!current()) return blocked("connection_changed");
|
|
269395
270887
|
if (releaseResult.isError) return blocked("release_rejected", rejectionFindings(readPayload(releaseResult, true)));
|
|
269396
270888
|
const released = readPayload(releaseResult);
|
|
@@ -269398,8 +270890,9 @@ function createGuardResponseReviewer(host) {
|
|
|
269398
270890
|
if (!current()) return blocked("connection_changed");
|
|
269399
270891
|
if (status !== "PASS" || release_allowed !== true || blocking === true || typeof release_token !== "string" || release_token.length === 0 || release_token.length > 65536) return blocked("release_rejected", rejectionFindings(released));
|
|
269400
270892
|
stage = "verification";
|
|
270893
|
+
onProgress?.("verification.start");
|
|
269401
270894
|
if (!await authorized("verify_release_token")) return blocked("verification_denied");
|
|
269402
|
-
const { status: verificationStatus, valid, checks, payload } = readPayload(await abortable(connection.client.callTool("verify_release_token", {
|
|
270895
|
+
const { status: verificationStatus, valid, checks, payload } = readPayload(await abortable(track(connection.client.callTool("verify_release_token", {
|
|
269403
270896
|
release_token,
|
|
269404
270897
|
source_text: "",
|
|
269405
270898
|
target_text: text,
|
|
@@ -269407,7 +270900,7 @@ function createGuardResponseReviewer(host) {
|
|
|
269407
270900
|
purpose: "response",
|
|
269408
270901
|
content_type: "prose",
|
|
269409
270902
|
short_text_reviewed: false
|
|
269410
|
-
}, signal), signal)) ?? {};
|
|
270903
|
+
}, signal)), signal)) ?? {};
|
|
269411
270904
|
if (!current()) return blocked("connection_changed");
|
|
269412
270905
|
if (verificationStatus !== "PASS" || valid !== true || !isPlainRecord(checks) || !CHECK_NAMES.every((name) => checks[name] === true) || !isPlainRecord(payload)) return blocked("verification_rejected");
|
|
269413
270906
|
const { v, source_sha256, target_sha256, language: verifiedLanguage, purpose, content_type, short_text_reviewed, exp, iat } = payload;
|
|
@@ -269489,6 +270982,7 @@ async function reviewNativeResponse(agent, language, input) {
|
|
|
269489
270982
|
});
|
|
269490
270983
|
};
|
|
269491
270984
|
const valueType = (value) => value === null ? "null" : Array.isArray(value) ? "array" : typeof value;
|
|
270985
|
+
let formatRetry = false;
|
|
269492
270986
|
for (let attempt = 1; attempt <= 2; attempt += 1) {
|
|
269493
270987
|
let receivedBytes = 0;
|
|
269494
270988
|
let outputLimitExceeded = false;
|
|
@@ -269497,21 +270991,27 @@ async function reviewNativeResponse(agent, language, input) {
|
|
|
269497
270991
|
};
|
|
269498
270992
|
const options = {
|
|
269499
270993
|
signal,
|
|
270994
|
+
onExecution: (completion) => {
|
|
270995
|
+
input.onPendingOperation?.(completion.then(() => void 0, () => void 0));
|
|
270996
|
+
},
|
|
269500
270997
|
requestLogFields: {
|
|
269501
270998
|
turnStep: `review:${input.turnId}.${String(input.step)}`,
|
|
269502
270999
|
attempt: `${attempt}/2`
|
|
269503
271000
|
}
|
|
269504
271001
|
};
|
|
269505
|
-
const prompt =
|
|
271002
|
+
const prompt = !formatRetry ? NATIVE_REVIEW_PROMPT : `${NATIVE_REVIEW_PROMPT}\nThe previous review did not satisfy the required JSON format. Return exactly one object with the two required boolean keys nativeness and orthography, no wrapper or additional keys. Use true or false, not strings or null. Set a check to false if it fails or you are uncertain.`;
|
|
269506
271003
|
try {
|
|
269507
271004
|
signal.throwIfAborted();
|
|
269508
|
-
const
|
|
271005
|
+
const requested = agent.generate(provider, prompt, [], [createUserMessage(candidateMessage)], { onMessagePart: (part) => {
|
|
269509
271006
|
if (part.type === "text") receivedBytes += Buffer.byteLength(part.text);
|
|
269510
271007
|
if (receivedBytes > MAX_REVIEW_RESULT_BYTES) {
|
|
269511
271008
|
outputLimitExceeded = true;
|
|
269512
271009
|
throw new Error("Native review output exceeds limit");
|
|
269513
271010
|
}
|
|
269514
|
-
|
|
271011
|
+
if (!signal.aborted && part.type === "text" && part.text.trim().length > 0) input.onProgress?.("native.text");
|
|
271012
|
+
} }, options);
|
|
271013
|
+
input.onPendingOperation?.(requested.then(() => void 0, () => void 0));
|
|
271014
|
+
const response = await abortable(requested, signal);
|
|
269515
271015
|
if (response.usage !== null) agent.usage.record(modelAlias, response.usage, "turn");
|
|
269516
271016
|
signal.throwIfAborted();
|
|
269517
271017
|
if (response.message.toolCalls.length > 0) return invalid("tool_calls");
|
|
@@ -269524,7 +271024,10 @@ async function reviewNativeResponse(agent, language, input) {
|
|
|
269524
271024
|
parsed = JSON.parse(text);
|
|
269525
271025
|
} catch {
|
|
269526
271026
|
record("invalid_json", attempt);
|
|
269527
|
-
if (attempt === 1)
|
|
271027
|
+
if (attempt === 1) {
|
|
271028
|
+
formatRetry = true;
|
|
271029
|
+
continue;
|
|
271030
|
+
}
|
|
269528
271031
|
return;
|
|
269529
271032
|
}
|
|
269530
271033
|
if (!isPlainRecord(parsed) || Object.keys(parsed).length !== 2 || typeof parsed["nativeness"] !== "boolean" || typeof parsed["orthography"] !== "boolean") {
|
|
@@ -269535,7 +271038,10 @@ async function reviewNativeResponse(agent, language, input) {
|
|
|
269535
271038
|
nativenessType: fields ? valueType(fields["nativeness"]) : "missing",
|
|
269536
271039
|
orthographyType: fields ? valueType(fields["orthography"]) : "missing"
|
|
269537
271040
|
});
|
|
269538
|
-
if (attempt === 1 && !(fields && (fields["nativeness"] === false || fields["orthography"] === false)))
|
|
271041
|
+
if (attempt === 1 && !(fields && (fields["nativeness"] === false || fields["orthography"] === false))) {
|
|
271042
|
+
formatRetry = true;
|
|
271043
|
+
continue;
|
|
271044
|
+
}
|
|
269539
271045
|
return;
|
|
269540
271046
|
}
|
|
269541
271047
|
record(parsed["nativeness"] && parsed["orthography"] ? "approved" : "native_rejected", attempt, {
|
|
@@ -269546,7 +271052,12 @@ async function reviewNativeResponse(agent, language, input) {
|
|
|
269546
271052
|
nativeness: parsed["nativeness"],
|
|
269547
271053
|
orthography: parsed["orthography"]
|
|
269548
271054
|
};
|
|
269549
|
-
} catch {
|
|
271055
|
+
} catch (error) {
|
|
271056
|
+
if (!signal.aborted && !outputLimitExceeded && attempt === 1 && error instanceof APIProviderRateLimitError) {
|
|
271057
|
+
record("rate_limited", attempt);
|
|
271058
|
+
if (error.retryAfterMs === null) await agent.providerRetryWait.defer(providerRetryScope(modelAlias, provider), 1e3);
|
|
271059
|
+
continue;
|
|
271060
|
+
}
|
|
269550
271061
|
return invalid(signal.aborted ? "cancelled" : outputLimitExceeded ? "output_limit" : "generation_failed");
|
|
269551
271062
|
}
|
|
269552
271063
|
}
|
|
@@ -269601,6 +271112,7 @@ var init_response_review_host = __esmMin((() => {
|
|
|
269601
271112
|
init_src$4();
|
|
269602
271113
|
init_abort();
|
|
269603
271114
|
init_response_review_mcp();
|
|
271115
|
+
init_provider_retry_wait();
|
|
269604
271116
|
init_canonical_args();
|
|
269605
271117
|
NATIVE_REVIEW_PROMPT = [
|
|
269606
271118
|
"You are an independent language reviewer, not the author of the candidate.",
|
|
@@ -334128,1138 +335640,6 @@ var init_blun_media = __esmMin((() => {
|
|
|
334128
335640
|
};
|
|
334129
335641
|
}));
|
|
334130
335642
|
//#endregion
|
|
334131
|
-
//#region ../../packages/kaos/src/errors.ts
|
|
334132
|
-
var KaosError, KaosFileExistsError, KaosShellNotFoundError;
|
|
334133
|
-
var init_errors$1 = __esmMin((() => {
|
|
334134
|
-
KaosError = class extends Error {
|
|
334135
|
-
constructor(message) {
|
|
334136
|
-
super(message);
|
|
334137
|
-
this.name = "KaosError";
|
|
334138
|
-
}
|
|
334139
|
-
};
|
|
334140
|
-
KaosFileExistsError = class extends KaosError {
|
|
334141
|
-
constructor(message) {
|
|
334142
|
-
super(message);
|
|
334143
|
-
this.name = "KaosFileExistsError";
|
|
334144
|
-
}
|
|
334145
|
-
};
|
|
334146
|
-
KaosShellNotFoundError = class extends KaosError {
|
|
334147
|
-
constructor(message) {
|
|
334148
|
-
super(message);
|
|
334149
|
-
this.name = "KaosShellNotFoundError";
|
|
334150
|
-
}
|
|
334151
|
-
};
|
|
334152
|
-
}));
|
|
334153
|
-
//#endregion
|
|
334154
|
-
//#region ../../packages/kaos/src/environment.ts
|
|
334155
|
-
/**
|
|
334156
|
-
* Environment — cross-platform probe of OS / shell.
|
|
334157
|
-
*
|
|
334158
|
-
* Detection is a pure function of injected probes (`platform` / `arch` /
|
|
334159
|
-
* `release` / `env` / `isFile` / `execFileText`) so the same suite runs
|
|
334160
|
-
* identically on any host OS. `detectEnvironmentFromNode()` bundles the Node
|
|
334161
|
-
* defaults for production callers.
|
|
334162
|
-
*
|
|
334163
|
-
* On Windows the probe expects Git Bash (the canonical POSIX shell that
|
|
334164
|
-
* ships with Git for Windows). If it cannot be located the function
|
|
334165
|
-
* throws `KaosShellNotFoundError`; the SDK layer can wrap that into a
|
|
334166
|
-
* user-facing install hint. Set `BLUN_SHELL_PATH` to override.
|
|
334167
|
-
*/
|
|
334168
|
-
function resolveOsKind(platform) {
|
|
334169
|
-
switch (platform) {
|
|
334170
|
-
case "darwin": return "macOS";
|
|
334171
|
-
case "linux": return "Linux";
|
|
334172
|
-
case "win32": return "Windows";
|
|
334173
|
-
default: return platform;
|
|
334174
|
-
}
|
|
334175
|
-
}
|
|
334176
|
-
async function detectEnvironment(deps) {
|
|
334177
|
-
const osKind = resolveOsKind(deps.platform);
|
|
334178
|
-
const osArch = deps.arch;
|
|
334179
|
-
const osVersion = deps.release;
|
|
334180
|
-
if (deps.platform === "win32") return {
|
|
334181
|
-
osKind,
|
|
334182
|
-
osArch,
|
|
334183
|
-
osVersion,
|
|
334184
|
-
shellName: "bash",
|
|
334185
|
-
shellPath: await locateWindowsGitBash(deps)
|
|
334186
|
-
};
|
|
334187
|
-
const candidates = [
|
|
334188
|
-
"/bin/bash",
|
|
334189
|
-
"/usr/bin/bash",
|
|
334190
|
-
"/usr/local/bin/bash"
|
|
334191
|
-
];
|
|
334192
|
-
let found;
|
|
334193
|
-
for (const p of candidates) if (await deps.isFile(p)) {
|
|
334194
|
-
found = p;
|
|
334195
|
-
break;
|
|
334196
|
-
}
|
|
334197
|
-
if (found !== void 0) return {
|
|
334198
|
-
osKind,
|
|
334199
|
-
osArch,
|
|
334200
|
-
osVersion,
|
|
334201
|
-
shellName: "bash",
|
|
334202
|
-
shellPath: found
|
|
334203
|
-
};
|
|
334204
|
-
return {
|
|
334205
|
-
osKind,
|
|
334206
|
-
osArch,
|
|
334207
|
-
osVersion,
|
|
334208
|
-
shellName: "sh",
|
|
334209
|
-
shellPath: "/bin/sh"
|
|
334210
|
-
};
|
|
334211
|
-
}
|
|
334212
|
-
async function locateWindowsGitBash(deps) {
|
|
334213
|
-
const checked = [];
|
|
334214
|
-
const override = deps.env["BLUN_SHELL_PATH"]?.trim();
|
|
334215
|
-
if (override !== void 0 && override.length > 0) {
|
|
334216
|
-
checked.push(override);
|
|
334217
|
-
if (await deps.isFile(override)) return override;
|
|
334218
|
-
}
|
|
334219
|
-
const gitExecutables = await findExecutablesOnPath("git.exe", deps.env["PATH"], deps.platform, deps.isFile);
|
|
334220
|
-
for (const gitExe of gitExecutables) {
|
|
334221
|
-
const inferred = gitBashCandidatesFromGitExe(gitExe);
|
|
334222
|
-
if (inferred !== void 0) for (const candidate of inferred) {
|
|
334223
|
-
checked.push(candidate);
|
|
334224
|
-
if (await deps.isFile(candidate)) return candidate;
|
|
334225
|
-
}
|
|
334226
|
-
const gitExecPath = await readGitExecPath(deps, gitExe);
|
|
334227
|
-
if (gitExecPath === void 0) continue;
|
|
334228
|
-
for (const candidate of gitBashCandidatesFromGitExecPath(gitExecPath)) {
|
|
334229
|
-
checked.push(candidate);
|
|
334230
|
-
if (await deps.isFile(candidate)) return candidate;
|
|
334231
|
-
}
|
|
334232
|
-
}
|
|
334233
|
-
const candidates = [
|
|
334234
|
-
"C:\\Program Files\\Git\\bin\\bash.exe",
|
|
334235
|
-
"C:\\Program Files\\Git\\usr\\bin\\bash.exe",
|
|
334236
|
-
"C:\\Program Files (x86)\\Git\\bin\\bash.exe",
|
|
334237
|
-
"C:\\Program Files (x86)\\Git\\usr\\bin\\bash.exe"
|
|
334238
|
-
];
|
|
334239
|
-
const localAppData = deps.env["LOCALAPPDATA"]?.trim();
|
|
334240
|
-
if (localAppData !== void 0 && localAppData.length > 0) {
|
|
334241
|
-
candidates.push(`${localAppData}\\Programs\\Git\\bin\\bash.exe`);
|
|
334242
|
-
candidates.push(`${localAppData}\\Programs\\Git\\usr\\bin\\bash.exe`);
|
|
334243
|
-
}
|
|
334244
|
-
for (const candidate of candidates) {
|
|
334245
|
-
checked.push(candidate);
|
|
334246
|
-
if (await deps.isFile(candidate)) return candidate;
|
|
334247
|
-
}
|
|
334248
|
-
throw new KaosShellNotFoundError(`Git Bash was not found on this Windows host. Install Git for Windows from https://gitforwindows.org/ or set BLUN_SHELL_PATH to a bash.exe. Checked: ${checked.join(", ")}.`);
|
|
334249
|
-
}
|
|
334250
|
-
async function readGitExecPath(deps, gitExe) {
|
|
334251
|
-
if (deps.platform === "win32" && !isAbsoluteWindowsPath(gitExe)) return void 0;
|
|
334252
|
-
const stdout = await deps.execFileText(gitExe, ["--exec-path"], GIT_EXEC_PATH_TIMEOUT_MS);
|
|
334253
|
-
if (stdout === void 0) return void 0;
|
|
334254
|
-
for (const line of stdout.split(/\r?\n/)) {
|
|
334255
|
-
const execPath = line.trim();
|
|
334256
|
-
if (execPath.length > 0) return execPath;
|
|
334257
|
-
}
|
|
334258
|
-
}
|
|
334259
|
-
function gitBashCandidatesFromGitExe(gitExe) {
|
|
334260
|
-
const normalizedGitExe = path$18.win32.normalize(normalizeWindowsPath(gitExe));
|
|
334261
|
-
const gitDir = path$18.win32.dirname(normalizedGitExe);
|
|
334262
|
-
const gitDirName = path$18.win32.basename(gitDir).toLowerCase();
|
|
334263
|
-
if (gitDirName !== "cmd" && gitDirName !== "bin") return;
|
|
334264
|
-
return gitBashCandidatesFromGitRoot(path$18.win32.dirname(gitDir));
|
|
334265
|
-
}
|
|
334266
|
-
function gitBashCandidatesFromGitExecPath(execPath) {
|
|
334267
|
-
const normalized = path$18.win32.normalize(normalizeWindowsPath(execPath));
|
|
334268
|
-
const parts = normalized.split("\\");
|
|
334269
|
-
for (let i = parts.length - 1; i >= 0; i -= 1) {
|
|
334270
|
-
const segment = parts[i]?.toLowerCase();
|
|
334271
|
-
if (segment === "mingw32" || segment === "mingw64") {
|
|
334272
|
-
const root = parts.slice(0, i).join("\\");
|
|
334273
|
-
if (root.length > 0) return gitBashCandidatesFromGitRoot(root);
|
|
334274
|
-
}
|
|
334275
|
-
}
|
|
334276
|
-
return gitBashCandidatesFromGitRoot(path$18.win32.join(normalized, "..", ".."));
|
|
334277
|
-
}
|
|
334278
|
-
function gitBashCandidatesFromGitRoot(root) {
|
|
334279
|
-
return [path$18.win32.normalize(path$18.win32.join(root, "bin", "bash.exe")), path$18.win32.normalize(path$18.win32.join(root, "usr", "bin", "bash.exe"))];
|
|
334280
|
-
}
|
|
334281
|
-
function normalizeWindowsPath(path) {
|
|
334282
|
-
return path.replaceAll("/", "\\");
|
|
334283
|
-
}
|
|
334284
|
-
function isAbsoluteWindowsPath(path) {
|
|
334285
|
-
return path$18.win32.isAbsolute(normalizeWindowsPath(path));
|
|
334286
|
-
}
|
|
334287
|
-
function dedupeWindowsPaths(paths) {
|
|
334288
|
-
const deduped = [];
|
|
334289
|
-
const seen = /* @__PURE__ */ new Set();
|
|
334290
|
-
for (const path of paths) {
|
|
334291
|
-
const key = normalizeWindowsPath(path).toLowerCase();
|
|
334292
|
-
if (seen.has(key)) continue;
|
|
334293
|
-
seen.add(key);
|
|
334294
|
-
deduped.push(path);
|
|
334295
|
-
}
|
|
334296
|
-
return deduped;
|
|
334297
|
-
}
|
|
334298
|
-
function detectEnvironmentFromNode() {
|
|
334299
|
-
if (detectedEnvironment !== void 0) return detectedEnvironment;
|
|
334300
|
-
const platform = process.platform;
|
|
334301
|
-
const env = process.env;
|
|
334302
|
-
const isFile = async (path) => {
|
|
334303
|
-
try {
|
|
334304
|
-
await access(path, constants.F_OK);
|
|
334305
|
-
return true;
|
|
334306
|
-
} catch {
|
|
334307
|
-
return false;
|
|
334308
|
-
}
|
|
334309
|
-
};
|
|
334310
|
-
detectedEnvironment = detectEnvironment({
|
|
334311
|
-
platform,
|
|
334312
|
-
arch: process.arch,
|
|
334313
|
-
release: nodeOs.release(),
|
|
334314
|
-
env,
|
|
334315
|
-
isFile,
|
|
334316
|
-
execFileText: execFileText$1
|
|
334317
|
-
});
|
|
334318
|
-
return detectedEnvironment;
|
|
334319
|
-
}
|
|
334320
|
-
async function findExecutablesOnPath(name, pathEnv, platform, isFile) {
|
|
334321
|
-
if (pathEnv === void 0 || pathEnv.length === 0) return [];
|
|
334322
|
-
const listSep = platform === "win32" ? ";" : ":";
|
|
334323
|
-
const dirSep = platform === "win32" ? "\\" : "/";
|
|
334324
|
-
const paths = [];
|
|
334325
|
-
for (const rawDir of pathEnv.split(listSep)) {
|
|
334326
|
-
const dir = rawDir.trim();
|
|
334327
|
-
if (dir.length === 0) continue;
|
|
334328
|
-
if (platform === "win32" && !isAbsoluteWindowsPath(dir)) continue;
|
|
334329
|
-
const candidate = dir.endsWith(dirSep) ? `${dir}${name}` : `${dir}${dirSep}${name}`;
|
|
334330
|
-
if (await isFile(candidate)) paths.push(candidate);
|
|
334331
|
-
}
|
|
334332
|
-
return platform === "win32" ? dedupeWindowsPaths(paths) : paths;
|
|
334333
|
-
}
|
|
334334
|
-
async function execFileText$1(file, args, timeoutMs) {
|
|
334335
|
-
return new Promise((resolve) => {
|
|
334336
|
-
execFile(file, [...args], {
|
|
334337
|
-
encoding: "utf8",
|
|
334338
|
-
timeout: timeoutMs,
|
|
334339
|
-
windowsHide: true
|
|
334340
|
-
}, (error, stdout) => {
|
|
334341
|
-
if (error !== null) {
|
|
334342
|
-
resolve(void 0);
|
|
334343
|
-
return;
|
|
334344
|
-
}
|
|
334345
|
-
resolve(stdout);
|
|
334346
|
-
});
|
|
334347
|
-
});
|
|
334348
|
-
}
|
|
334349
|
-
var GIT_EXEC_PATH_TIMEOUT_MS, detectedEnvironment;
|
|
334350
|
-
var init_environment$1 = __esmMin((() => {
|
|
334351
|
-
init_errors$1();
|
|
334352
|
-
GIT_EXEC_PATH_TIMEOUT_MS = 5e3;
|
|
334353
|
-
}));
|
|
334354
|
-
//#endregion
|
|
334355
|
-
//#region ../../packages/kaos/src/internal.ts
|
|
334356
|
-
function isUtf8Continuation(byte) {
|
|
334357
|
-
return byte >= 128 && byte <= 191;
|
|
334358
|
-
}
|
|
334359
|
-
function decodeUtf8Ignore(data) {
|
|
334360
|
-
let output = "";
|
|
334361
|
-
let i = 0;
|
|
334362
|
-
while (i < data.length) {
|
|
334363
|
-
const b0 = data[i];
|
|
334364
|
-
if (b0 === void 0) break;
|
|
334365
|
-
if (b0 <= 127) {
|
|
334366
|
-
output += String.fromCodePoint(b0);
|
|
334367
|
-
i += 1;
|
|
334368
|
-
continue;
|
|
334369
|
-
}
|
|
334370
|
-
if (b0 >= 194 && b0 <= 223) {
|
|
334371
|
-
const b1 = data[i + 1];
|
|
334372
|
-
if (b1 !== void 0 && isUtf8Continuation(b1)) {
|
|
334373
|
-
output += String.fromCodePoint((b0 & 31) << 6 | b1 & 63);
|
|
334374
|
-
i += 2;
|
|
334375
|
-
continue;
|
|
334376
|
-
}
|
|
334377
|
-
i += 1;
|
|
334378
|
-
continue;
|
|
334379
|
-
}
|
|
334380
|
-
if (b0 >= 224 && b0 <= 239) {
|
|
334381
|
-
const b1 = data[i + 1];
|
|
334382
|
-
const b2 = data[i + 2];
|
|
334383
|
-
if (b1 !== void 0 && (b0 === 224 && b1 >= 160 && b1 <= 191 || b0 >= 225 && b0 <= 236 && isUtf8Continuation(b1) || b0 === 237 && b1 >= 128 && b1 <= 159 || b0 >= 238 && b0 <= 239 && isUtf8Continuation(b1)) && b2 !== void 0 && isUtf8Continuation(b2)) {
|
|
334384
|
-
output += String.fromCodePoint((b0 & 15) << 12 | (b1 & 63) << 6 | b2 & 63);
|
|
334385
|
-
i += 3;
|
|
334386
|
-
continue;
|
|
334387
|
-
}
|
|
334388
|
-
i += 1;
|
|
334389
|
-
continue;
|
|
334390
|
-
}
|
|
334391
|
-
if (b0 >= 240 && b0 <= 244) {
|
|
334392
|
-
const b1 = data[i + 1];
|
|
334393
|
-
const b2 = data[i + 2];
|
|
334394
|
-
const b3 = data[i + 3];
|
|
334395
|
-
if (b1 !== void 0 && (b0 === 240 && b1 >= 144 && b1 <= 191 || b0 >= 241 && b0 <= 243 && isUtf8Continuation(b1) || b0 === 244 && b1 >= 128 && b1 <= 143) && b2 !== void 0 && b3 !== void 0 && isUtf8Continuation(b2) && isUtf8Continuation(b3)) {
|
|
334396
|
-
output += String.fromCodePoint((b0 & 7) << 18 | (b1 & 63) << 12 | (b2 & 63) << 6 | b3 & 63);
|
|
334397
|
-
i += 4;
|
|
334398
|
-
continue;
|
|
334399
|
-
}
|
|
334400
|
-
i += 1;
|
|
334401
|
-
continue;
|
|
334402
|
-
}
|
|
334403
|
-
i += 1;
|
|
334404
|
-
}
|
|
334405
|
-
return output;
|
|
334406
|
-
}
|
|
334407
|
-
function decodeUtf16LeIgnore(data) {
|
|
334408
|
-
let output = "";
|
|
334409
|
-
let i = 0;
|
|
334410
|
-
while (i + 1 < data.length) {
|
|
334411
|
-
const first = data[i];
|
|
334412
|
-
const second = data[i + 1];
|
|
334413
|
-
if (first === void 0 || second === void 0) break;
|
|
334414
|
-
const codeUnit = first | second << 8;
|
|
334415
|
-
if (codeUnit >= 55296 && codeUnit <= 56319) {
|
|
334416
|
-
const lowFirst = data[i + 2];
|
|
334417
|
-
const lowSecond = data[i + 3];
|
|
334418
|
-
if (lowFirst !== void 0 && lowSecond !== void 0) {
|
|
334419
|
-
const low = lowFirst | lowSecond << 8;
|
|
334420
|
-
if (low >= 56320 && low <= 57343) {
|
|
334421
|
-
const codePoint = 65536 + (codeUnit - 55296 << 10) + (low - 56320);
|
|
334422
|
-
output += String.fromCodePoint(codePoint);
|
|
334423
|
-
i += 4;
|
|
334424
|
-
continue;
|
|
334425
|
-
}
|
|
334426
|
-
}
|
|
334427
|
-
i += 2;
|
|
334428
|
-
continue;
|
|
334429
|
-
}
|
|
334430
|
-
if (codeUnit >= 56320 && codeUnit <= 57343) {
|
|
334431
|
-
i += 2;
|
|
334432
|
-
continue;
|
|
334433
|
-
}
|
|
334434
|
-
output += String.fromCodePoint(codeUnit);
|
|
334435
|
-
i += 2;
|
|
334436
|
-
}
|
|
334437
|
-
return output;
|
|
334438
|
-
}
|
|
334439
|
-
/**
|
|
334440
|
-
* Decode a Buffer into a string with Python-compatible `errors` handling.
|
|
334441
|
-
*
|
|
334442
|
-
* - `'strict'` (default): throw on invalid sequences (via TextDecoder `fatal: true`)
|
|
334443
|
-
* - `'replace'`: substitute each invalid sequence with U+FFFD (TextDecoder default)
|
|
334444
|
-
* - `'ignore'`: drop invalid input sequences while preserving valid U+FFFD characters
|
|
334445
|
-
*
|
|
334446
|
-
* Falls back to `Buffer.toString(encoding)` for encodings TextDecoder does not
|
|
334447
|
-
* support (e.g. `hex`, `base64`, `binary`, `latin1`) — those are lossless
|
|
334448
|
-
* byte-to-character mappings so `errors` has no effect.
|
|
334449
|
-
* @internal
|
|
334450
|
-
*/
|
|
334451
|
-
function decodeTextWithErrors(data, encoding, errors = "strict", ignoreBOM = false) {
|
|
334452
|
-
let webLabel;
|
|
334453
|
-
switch (encoding) {
|
|
334454
|
-
case "utf-8":
|
|
334455
|
-
case "utf8":
|
|
334456
|
-
webLabel = "utf-8";
|
|
334457
|
-
break;
|
|
334458
|
-
case "utf16le":
|
|
334459
|
-
case "ucs2":
|
|
334460
|
-
case "ucs-2":
|
|
334461
|
-
webLabel = "utf-16le";
|
|
334462
|
-
break;
|
|
334463
|
-
default: webLabel = void 0;
|
|
334464
|
-
}
|
|
334465
|
-
if (webLabel === void 0) return data.toString(encoding);
|
|
334466
|
-
if (errors === "strict") return new TextDecoder(webLabel, {
|
|
334467
|
-
fatal: true,
|
|
334468
|
-
ignoreBOM
|
|
334469
|
-
}).decode(data);
|
|
334470
|
-
if (errors === "ignore") return webLabel === "utf-8" ? decodeUtf8Ignore(data) : decodeUtf16LeIgnore(data);
|
|
334471
|
-
return new TextDecoder(webLabel, {
|
|
334472
|
-
fatal: false,
|
|
334473
|
-
ignoreBOM
|
|
334474
|
-
}).decode(data);
|
|
334475
|
-
}
|
|
334476
|
-
/**
|
|
334477
|
-
* Convert a glob pattern segment (e.g. "*.txt", "file?.log") into a RegExp.
|
|
334478
|
-
* Mirrors Python pathlib behavior: includes dotfiles, case-sensitive by default.
|
|
334479
|
-
* @internal
|
|
334480
|
-
*/
|
|
334481
|
-
function globPatternToRegex(pattern, caseSensitive) {
|
|
334482
|
-
let regex = "^";
|
|
334483
|
-
for (let i = 0; i < pattern.length; i++) {
|
|
334484
|
-
const ch = pattern[i];
|
|
334485
|
-
if (ch === void 0) break;
|
|
334486
|
-
switch (ch) {
|
|
334487
|
-
case "*":
|
|
334488
|
-
regex += "[^/]*";
|
|
334489
|
-
break;
|
|
334490
|
-
case "?":
|
|
334491
|
-
regex += "[^/]";
|
|
334492
|
-
break;
|
|
334493
|
-
case "[": {
|
|
334494
|
-
const end = pattern.indexOf("]", i + 1);
|
|
334495
|
-
if (end === -1) regex += "\\[";
|
|
334496
|
-
else {
|
|
334497
|
-
let charClass = pattern.slice(i + 1, end);
|
|
334498
|
-
charClass = charClass.replace(/\\/g, "\\\\");
|
|
334499
|
-
if (charClass.startsWith("!")) charClass = "^" + charClass.slice(1);
|
|
334500
|
-
else if (charClass.startsWith("^")) charClass = "\\" + charClass;
|
|
334501
|
-
regex += "[" + charClass + "]";
|
|
334502
|
-
i = end;
|
|
334503
|
-
}
|
|
334504
|
-
break;
|
|
334505
|
-
}
|
|
334506
|
-
case "\\":
|
|
334507
|
-
if (i + 1 < pattern.length) {
|
|
334508
|
-
const next = pattern.charAt(i + 1);
|
|
334509
|
-
regex += next.replaceAll(/[{}()+.\\[\]^$|]/g, "\\$&");
|
|
334510
|
-
i++;
|
|
334511
|
-
} else regex += "\\\\";
|
|
334512
|
-
break;
|
|
334513
|
-
default: regex += ch.replaceAll(/[{}()+.\\[\]^$|]/g, "\\$&");
|
|
334514
|
-
}
|
|
334515
|
-
}
|
|
334516
|
-
regex += "$";
|
|
334517
|
-
return new RegExp(regex, caseSensitive ? "" : "i");
|
|
334518
|
-
}
|
|
334519
|
-
var BufferedReadable;
|
|
334520
|
-
var init_internal = __esmMin((() => {
|
|
334521
|
-
BufferedReadable = class extends Readable$1 {
|
|
334522
|
-
_source;
|
|
334523
|
-
_ended = false;
|
|
334524
|
-
constructor(source) {
|
|
334525
|
-
super({ highWaterMark: 128 * 1024 });
|
|
334526
|
-
this._source = source;
|
|
334527
|
-
this._source.on("data", this._onData);
|
|
334528
|
-
this._source.on("end", this._onEnd);
|
|
334529
|
-
this._source.on("close", this._onClose);
|
|
334530
|
-
this._source.on("error", this._onError);
|
|
334531
|
-
}
|
|
334532
|
-
_read() {
|
|
334533
|
-
if (!this._ended && !this.destroyed) this._source.resume();
|
|
334534
|
-
}
|
|
334535
|
-
_destroy(error, callback) {
|
|
334536
|
-
this._source.off("data", this._onData);
|
|
334537
|
-
this._source.off("end", this._onEnd);
|
|
334538
|
-
this._source.off("close", this._onClose);
|
|
334539
|
-
this._source.off("error", this._onError);
|
|
334540
|
-
this._source.destroy();
|
|
334541
|
-
callback(error);
|
|
334542
|
-
}
|
|
334543
|
-
_onData = (chunk) => {
|
|
334544
|
-
if (!this.push(chunk)) this._source.pause();
|
|
334545
|
-
};
|
|
334546
|
-
_onEnd = () => {
|
|
334547
|
-
this._ended = true;
|
|
334548
|
-
this.push(null);
|
|
334549
|
-
};
|
|
334550
|
-
_onClose = () => {
|
|
334551
|
-
if (!this._ended) {
|
|
334552
|
-
this._ended = true;
|
|
334553
|
-
this.push(null);
|
|
334554
|
-
}
|
|
334555
|
-
};
|
|
334556
|
-
_onError = (error) => {
|
|
334557
|
-
this.destroy(error);
|
|
334558
|
-
};
|
|
334559
|
-
};
|
|
334560
|
-
}));
|
|
334561
|
-
//#endregion
|
|
334562
|
-
//#region ../../packages/kaos/src/login-shell-path.ts
|
|
334563
|
-
/**
|
|
334564
|
-
* Login-shell PATH probe — enrich `process.env.PATH` with entries from the
|
|
334565
|
-
* user's login shell.
|
|
334566
|
-
*
|
|
334567
|
-
* When blun is launched from a context that skipped the user's shell
|
|
334568
|
-
* profile (GUI launchers, non-login parent shells), `process.env.PATH`
|
|
334569
|
-
* misses entries like `/opt/homebrew/bin`, so commands spawned by the Bash
|
|
334570
|
-
* tool can't find tools the user has in their interactive shell (e.g.
|
|
334571
|
-
* `gh`). We run the user's login shell once (`$SHELL -l -c /usr/bin/env`),
|
|
334572
|
-
* extract its PATH, and append the entries the current PATH lacks. Existing
|
|
334573
|
-
* entries keep their order and priority; failures (no resolvable shell,
|
|
334574
|
-
* hung or broken profile) silently leave PATH untouched.
|
|
334575
|
-
*
|
|
334576
|
-
* launchd/daemon launches can leave `$SHELL` unset or blank (see
|
|
334577
|
-
* `defaultShell()` in agent-core's terminalService for the same case), so
|
|
334578
|
-
* the probe falls back to the OS account's login shell from the user
|
|
334579
|
-
* database before giving up.
|
|
334580
|
-
*
|
|
334581
|
-
* Like `detectEnvironment`, the probe is a pure function of injected deps
|
|
334582
|
-
* so the suite runs identically on any host. Windows is skipped: the
|
|
334583
|
-
* problem is specific to POSIX login-shell profiles.
|
|
334584
|
-
*/
|
|
334585
|
-
/**
|
|
334586
|
-
* Run the user's login shell and return its PATH, or `undefined` when the
|
|
334587
|
-
* probe does not apply (Windows, no resolvable shell) or fails (spawn
|
|
334588
|
-
* error, timeout, no PATH in the output).
|
|
334589
|
-
*/
|
|
334590
|
-
async function probeLoginShellPath(deps) {
|
|
334591
|
-
if (deps.platform === "win32") return void 0;
|
|
334592
|
-
const envShell = deps.env["SHELL"]?.trim();
|
|
334593
|
-
const shell = envShell === void 0 || envShell.length === 0 ? deps.userShell() : envShell;
|
|
334594
|
-
if (shell === void 0 || shell.length === 0) return void 0;
|
|
334595
|
-
const stdout = await deps.execFileText(shell, [
|
|
334596
|
-
"-l",
|
|
334597
|
-
"-c",
|
|
334598
|
-
"/usr/bin/env"
|
|
334599
|
-
], LOGIN_SHELL_ENV_TIMEOUT_MS);
|
|
334600
|
-
if (stdout === void 0) return void 0;
|
|
334601
|
-
let path;
|
|
334602
|
-
for (const line of stdout.split("\n")) if (line.startsWith("PATH=")) path = line.slice(5).trim();
|
|
334603
|
-
if (path === void 0 || path.length === 0) return void 0;
|
|
334604
|
-
return path;
|
|
334605
|
-
}
|
|
334606
|
-
/**
|
|
334607
|
-
* Union of the current PATH and the login-shell PATH: the current PATH
|
|
334608
|
-
* string is kept verbatim — including empty components, which POSIX
|
|
334609
|
-
* command lookup treats as the current directory — and login-shell
|
|
334610
|
-
* entries the current PATH lacks are appended in their own order. When
|
|
334611
|
-
* nothing is missing the current string is returned unchanged. Only
|
|
334612
|
-
* absolute login-shell entries are imported: empty, `.`, and relative
|
|
334613
|
-
* components are all cwd-dependent lookup, and appending one the user
|
|
334614
|
-
* did not already have would widen their search path — LocalKaos runs
|
|
334615
|
-
* commands from arbitrary workspace directories.
|
|
334616
|
-
*/
|
|
334617
|
-
function mergeLoginShellPath(currentPath, loginShellPath) {
|
|
334618
|
-
const current = currentPath ?? "";
|
|
334619
|
-
const seen = new Set(current.split(":").filter((entry) => entry.length > 0));
|
|
334620
|
-
const additions = [];
|
|
334621
|
-
for (const entry of loginShellPath.split(":")) {
|
|
334622
|
-
if (!entry.startsWith("/") || seen.has(entry)) continue;
|
|
334623
|
-
seen.add(entry);
|
|
334624
|
-
additions.push(entry);
|
|
334625
|
-
}
|
|
334626
|
-
if (additions.length === 0) return current;
|
|
334627
|
-
if (currentPath === void 0) return additions.join(":");
|
|
334628
|
-
return `${current}:${additions.join(":")}`;
|
|
334629
|
-
}
|
|
334630
|
-
/** Probe the login shell and merge its PATH into `deps.env['PATH']`. */
|
|
334631
|
-
async function applyLoginShellPath(deps) {
|
|
334632
|
-
const loginShellPath = await probeLoginShellPath(deps);
|
|
334633
|
-
if (loginShellPath === void 0) return;
|
|
334634
|
-
const currentPath = deps.env["PATH"];
|
|
334635
|
-
const merged = mergeLoginShellPath(currentPath, loginShellPath);
|
|
334636
|
-
if (merged === (currentPath ?? "")) return;
|
|
334637
|
-
deps.env["PATH"] = merged;
|
|
334638
|
-
}
|
|
334639
|
-
/**
|
|
334640
|
-
* Production convenience — apply the probe to `process.env` once per
|
|
334641
|
-
* process. Memoised like `detectEnvironmentFromNode`: the login-shell PATH
|
|
334642
|
-
* does not change for the lifetime of the process, and repeated
|
|
334643
|
-
* `LocalKaos.create()` calls must not re-spawn the shell.
|
|
334644
|
-
*/
|
|
334645
|
-
/**
|
|
334646
|
-
* Login shell from the OS user database (`/etc/passwd` via getpwuid on
|
|
334647
|
-
* Linux, Directory Services on macOS). `userInfo()` throws when the uid
|
|
334648
|
-
* has no database entry (e.g. containers running an arbitrary uid), and
|
|
334649
|
-
* service accounts may carry `/usr/sbin/nologin` — the latter needs no
|
|
334650
|
-
* special casing here because probing it simply fails and degrades
|
|
334651
|
-
* silently.
|
|
334652
|
-
*/
|
|
334653
|
-
function userShellFromNode() {
|
|
334654
|
-
try {
|
|
334655
|
-
const shell = userInfo().shell;
|
|
334656
|
-
return shell === null || shell.length === 0 ? void 0 : shell;
|
|
334657
|
-
} catch {
|
|
334658
|
-
return;
|
|
334659
|
-
}
|
|
334660
|
-
}
|
|
334661
|
-
function applyLoginShellPathFromNode() {
|
|
334662
|
-
if (appliedLoginShellPath !== void 0) return appliedLoginShellPath;
|
|
334663
|
-
appliedLoginShellPath = applyLoginShellPath({
|
|
334664
|
-
platform: process.platform,
|
|
334665
|
-
env: process.env,
|
|
334666
|
-
userShell: userShellFromNode,
|
|
334667
|
-
execFileText: execFileText$1
|
|
334668
|
-
});
|
|
334669
|
-
return appliedLoginShellPath;
|
|
334670
|
-
}
|
|
334671
|
-
var LOGIN_SHELL_ENV_TIMEOUT_MS, appliedLoginShellPath;
|
|
334672
|
-
var init_login_shell_path = __esmMin((() => {
|
|
334673
|
-
init_environment$1();
|
|
334674
|
-
LOGIN_SHELL_ENV_TIMEOUT_MS = 5e3;
|
|
334675
|
-
}));
|
|
334676
|
-
//#endregion
|
|
334677
|
-
//#region ../../packages/kaos/src/local.ts
|
|
334678
|
-
/**
|
|
334679
|
-
* Build the `(dev, ino)` cycle-detection key used by `_globWalk`'s
|
|
334680
|
-
* visited set. Returns `null` when `ino` is 0, which Node returns on
|
|
334681
|
-
* filesystems that don't carry inodes (Windows FAT/exFAT, some SMB/NFS
|
|
334682
|
-
* mounts). A null key signals "no reliable identity for this dir" so
|
|
334683
|
-
* the caller skips visited tracking for that descent — cycle safety
|
|
334684
|
-
* is weakened on those filesystems, but normal walking works instead
|
|
334685
|
-
* of every directory colliding on the shared key `"<dev>:0"`.
|
|
334686
|
-
*/
|
|
334687
|
-
function cycleKey(s) {
|
|
334688
|
-
if (s.ino === 0) return null;
|
|
334689
|
-
return `${String(s.dev)}:${String(s.ino)}`;
|
|
334690
|
-
}
|
|
334691
|
-
function buildLocalSpawnOptions(_isWindows, cwd, env) {
|
|
334692
|
-
return {
|
|
334693
|
-
cwd,
|
|
334694
|
-
env,
|
|
334695
|
-
stdio: [
|
|
334696
|
-
"pipe",
|
|
334697
|
-
"pipe",
|
|
334698
|
-
"pipe"
|
|
334699
|
-
],
|
|
334700
|
-
detached: true,
|
|
334701
|
-
windowsHide: true
|
|
334702
|
-
};
|
|
334703
|
-
}
|
|
334704
|
-
function isUtf8Encoding(encoding) {
|
|
334705
|
-
return encoding === "utf-8" || encoding === "utf8";
|
|
334706
|
-
}
|
|
334707
|
-
function* splitLinesKeepingTerminator(text) {
|
|
334708
|
-
if (text.length === 0) return;
|
|
334709
|
-
let start = 0;
|
|
334710
|
-
for (let i = 0; i < text.length; i += 1) if (text.codePointAt(i) === 10) {
|
|
334711
|
-
yield text.slice(start, i + 1);
|
|
334712
|
-
start = i + 1;
|
|
334713
|
-
}
|
|
334714
|
-
if (start < text.length) yield text.slice(start);
|
|
334715
|
-
}
|
|
334716
|
-
function updateLineEndingFlagsFromBytes(flags, chunk, prevWasCr) {
|
|
334717
|
-
for (let i = 0; i < chunk.length; i += 1) {
|
|
334718
|
-
const byte = chunk[i];
|
|
334719
|
-
if (byte === void 0) continue;
|
|
334720
|
-
if (byte === 13) {
|
|
334721
|
-
if (prevWasCr) flags.hasLoneCr = true;
|
|
334722
|
-
prevWasCr = true;
|
|
334723
|
-
} else if (byte === 10) {
|
|
334724
|
-
if (prevWasCr) flags.hasCrLf = true;
|
|
334725
|
-
else flags.hasLf = true;
|
|
334726
|
-
prevWasCr = false;
|
|
334727
|
-
} else {
|
|
334728
|
-
if (prevWasCr) flags.hasLoneCr = true;
|
|
334729
|
-
prevWasCr = false;
|
|
334730
|
-
}
|
|
334731
|
-
}
|
|
334732
|
-
return prevWasCr;
|
|
334733
|
-
}
|
|
334734
|
-
function createUtf8Validator() {
|
|
334735
|
-
let needed = 0;
|
|
334736
|
-
let lower = 128;
|
|
334737
|
-
let upper = 191;
|
|
334738
|
-
const fail = () => {
|
|
334739
|
-
throw new TypeError("Invalid UTF-8 data");
|
|
334740
|
-
};
|
|
334741
|
-
return {
|
|
334742
|
-
write(chunk) {
|
|
334743
|
-
for (let i = 0; i < chunk.length; i += 1) {
|
|
334744
|
-
const byte = chunk[i];
|
|
334745
|
-
if (byte === void 0) continue;
|
|
334746
|
-
if (needed === 0) {
|
|
334747
|
-
if (byte <= 127) continue;
|
|
334748
|
-
if (byte >= 194 && byte <= 223) needed = 1;
|
|
334749
|
-
else if (byte === 224) {
|
|
334750
|
-
needed = 2;
|
|
334751
|
-
lower = 160;
|
|
334752
|
-
} else if (byte >= 225 && byte <= 236) needed = 2;
|
|
334753
|
-
else if (byte === 237) {
|
|
334754
|
-
needed = 2;
|
|
334755
|
-
upper = 159;
|
|
334756
|
-
} else if (byte >= 238 && byte <= 239) needed = 2;
|
|
334757
|
-
else if (byte === 240) {
|
|
334758
|
-
needed = 3;
|
|
334759
|
-
lower = 144;
|
|
334760
|
-
} else if (byte >= 241 && byte <= 243) needed = 3;
|
|
334761
|
-
else if (byte === 244) {
|
|
334762
|
-
needed = 3;
|
|
334763
|
-
upper = 143;
|
|
334764
|
-
} else fail();
|
|
334765
|
-
} else {
|
|
334766
|
-
if (byte < lower || byte > upper) fail();
|
|
334767
|
-
lower = 128;
|
|
334768
|
-
upper = 191;
|
|
334769
|
-
needed -= 1;
|
|
334770
|
-
}
|
|
334771
|
-
}
|
|
334772
|
-
},
|
|
334773
|
-
end() {
|
|
334774
|
-
if (needed !== 0) fail();
|
|
334775
|
-
}
|
|
334776
|
-
};
|
|
334777
|
-
}
|
|
334778
|
-
async function readRange(fh, start, length) {
|
|
334779
|
-
const data = Buffer.alloc(length);
|
|
334780
|
-
let offset = 0;
|
|
334781
|
-
while (offset < length) {
|
|
334782
|
-
const { bytesRead } = await fh.read(data, offset, length - offset, start + offset);
|
|
334783
|
-
if (bytesRead === 0) break;
|
|
334784
|
-
offset += bytesRead;
|
|
334785
|
-
}
|
|
334786
|
-
return offset === length ? data : data.subarray(0, offset);
|
|
334787
|
-
}
|
|
334788
|
-
function waitForSpawn(child) {
|
|
334789
|
-
return new Promise((resolve, reject) => {
|
|
334790
|
-
const onSpawn = () => {
|
|
334791
|
-
child.off("error", onError);
|
|
334792
|
-
resolve();
|
|
334793
|
-
};
|
|
334794
|
-
const onError = (err) => {
|
|
334795
|
-
child.off("spawn", onSpawn);
|
|
334796
|
-
reject(err);
|
|
334797
|
-
};
|
|
334798
|
-
child.once("spawn", onSpawn);
|
|
334799
|
-
child.once("error", onError);
|
|
334800
|
-
});
|
|
334801
|
-
}
|
|
334802
|
-
var isWindows$1, READ_CHUNK_SIZE, LocalProcess, LocalKaos;
|
|
334803
|
-
var init_local = __esmMin((() => {
|
|
334804
|
-
init_dist$6();
|
|
334805
|
-
init_environment$1();
|
|
334806
|
-
init_errors$1();
|
|
334807
|
-
init_internal();
|
|
334808
|
-
init_login_shell_path();
|
|
334809
|
-
isWindows$1 = process.platform === "win32";
|
|
334810
|
-
READ_CHUNK_SIZE = 64 * 1024;
|
|
334811
|
-
LocalProcess = class {
|
|
334812
|
-
stdin;
|
|
334813
|
-
stdout;
|
|
334814
|
-
stderr;
|
|
334815
|
-
pid;
|
|
334816
|
-
_child;
|
|
334817
|
-
_exitCode = null;
|
|
334818
|
-
_exitPromise;
|
|
334819
|
-
_disposed = false;
|
|
334820
|
-
constructor(child) {
|
|
334821
|
-
if (child.stdin === null || child.stdout === null || child.stderr === null) throw new Error("Process must be created with stdin/stdout/stderr pipes.");
|
|
334822
|
-
this._child = child;
|
|
334823
|
-
this.stdin = child.stdin;
|
|
334824
|
-
this.stdout = new BufferedReadable(child.stdout);
|
|
334825
|
-
this.stderr = new BufferedReadable(child.stderr);
|
|
334826
|
-
this.pid = child.pid ?? -1;
|
|
334827
|
-
this._exitPromise = new Promise((resolve, reject) => {
|
|
334828
|
-
child.on("exit", (code) => {
|
|
334829
|
-
this._exitCode = code ?? -1;
|
|
334830
|
-
resolve(this._exitCode);
|
|
334831
|
-
});
|
|
334832
|
-
child.on("error", (error) => {
|
|
334833
|
-
reject(error);
|
|
334834
|
-
});
|
|
334835
|
-
});
|
|
334836
|
-
}
|
|
334837
|
-
get exitCode() {
|
|
334838
|
-
return this._exitCode;
|
|
334839
|
-
}
|
|
334840
|
-
async wait() {
|
|
334841
|
-
return this._exitPromise;
|
|
334842
|
-
}
|
|
334843
|
-
kill(signal) {
|
|
334844
|
-
if (this.pid <= 0) return Promise.resolve();
|
|
334845
|
-
if (isWindows$1) {
|
|
334846
|
-
const taskkillArgs = [
|
|
334847
|
-
"/T",
|
|
334848
|
-
"/F",
|
|
334849
|
-
"/PID",
|
|
334850
|
-
String(this.pid)
|
|
334851
|
-
];
|
|
334852
|
-
return new Promise((resolve) => {
|
|
334853
|
-
const killer = spawn("taskkill", taskkillArgs, {
|
|
334854
|
-
stdio: "ignore",
|
|
334855
|
-
windowsHide: true
|
|
334856
|
-
});
|
|
334857
|
-
const done = () => {
|
|
334858
|
-
resolve();
|
|
334859
|
-
};
|
|
334860
|
-
killer.once("error", done);
|
|
334861
|
-
killer.once("close", done);
|
|
334862
|
-
});
|
|
334863
|
-
}
|
|
334864
|
-
try {
|
|
334865
|
-
process.kill(-this.pid, signal ?? "SIGTERM");
|
|
334866
|
-
} catch (error) {
|
|
334867
|
-
const err = error;
|
|
334868
|
-
if (err.code === "ESRCH") return Promise.resolve();
|
|
334869
|
-
if (err.code === "EPERM") {
|
|
334870
|
-
try {
|
|
334871
|
-
this._child.kill(signal ?? "SIGTERM");
|
|
334872
|
-
} catch {}
|
|
334873
|
-
return Promise.resolve();
|
|
334874
|
-
}
|
|
334875
|
-
throw error;
|
|
334876
|
-
}
|
|
334877
|
-
return Promise.resolve();
|
|
334878
|
-
}
|
|
334879
|
-
dispose() {
|
|
334880
|
-
if (this._disposed) return;
|
|
334881
|
-
this._disposed = true;
|
|
334882
|
-
this.stdin.destroy();
|
|
334883
|
-
this.stdout.destroy();
|
|
334884
|
-
this.stderr.destroy();
|
|
334885
|
-
}
|
|
334886
|
-
};
|
|
334887
|
-
LocalKaos = class LocalKaos {
|
|
334888
|
-
name = "local";
|
|
334889
|
-
osEnv;
|
|
334890
|
-
_cwd;
|
|
334891
|
-
_envLayers;
|
|
334892
|
-
constructor(osEnv, cwd, envLayers = []) {
|
|
334893
|
-
this._cwd = normalize$4(cwd ?? process.cwd());
|
|
334894
|
-
this.osEnv = osEnv;
|
|
334895
|
-
this._envLayers = envLayers;
|
|
334896
|
-
}
|
|
334897
|
-
/**
|
|
334898
|
-
* Construct a fresh `LocalKaos` after probing the host environment.
|
|
334899
|
-
*
|
|
334900
|
-
* Each call returns a new instance with its own `_cwd`; concurrent
|
|
334901
|
-
* callers can therefore operate on independent working directories
|
|
334902
|
-
* without polluting one another.
|
|
334903
|
-
*/
|
|
334904
|
-
static async create() {
|
|
334905
|
-
const [osEnv] = await Promise.all([detectEnvironmentFromNode(), applyLoginShellPathFromNode()]);
|
|
334906
|
-
return new LocalKaos(osEnv);
|
|
334907
|
-
}
|
|
334908
|
-
withCwd(cwd) {
|
|
334909
|
-
return new LocalKaos(this.osEnv, cwd, this._envLayers);
|
|
334910
|
-
}
|
|
334911
|
-
withEnv(env) {
|
|
334912
|
-
return new LocalKaos(this.osEnv, this._cwd, [...this._envLayers, env]);
|
|
334913
|
-
}
|
|
334914
|
-
_resolvePath(path) {
|
|
334915
|
-
if (isAbsolute$2(path)) return normalize$4(path);
|
|
334916
|
-
return join$4(this._cwd, path);
|
|
334917
|
-
}
|
|
334918
|
-
pathClass() {
|
|
334919
|
-
return isWindows$1 ? "win32" : "posix";
|
|
334920
|
-
}
|
|
334921
|
-
normpath(path) {
|
|
334922
|
-
return normalize$4(path);
|
|
334923
|
-
}
|
|
334924
|
-
gethome() {
|
|
334925
|
-
return normalize$4(homedir());
|
|
334926
|
-
}
|
|
334927
|
-
getcwd() {
|
|
334928
|
-
return this._cwd;
|
|
334929
|
-
}
|
|
334930
|
-
/**
|
|
334931
|
-
* Change the working directory of this LocalKaos instance.
|
|
334932
|
-
*
|
|
334933
|
-
* Unlike Python's `os.chdir`, this is instance-scoped and never touches
|
|
334934
|
-
* `process.cwd()`. Child processes spawned via {@link exec} inherit this
|
|
334935
|
-
* instance's `_cwd`; concurrent LocalKaos instances each carry their own
|
|
334936
|
-
* independent cwd. If you need Python-compatible process-global cwd,
|
|
334937
|
-
* call `process.chdir(x)` directly.
|
|
334938
|
-
*/
|
|
334939
|
-
async chdir(path) {
|
|
334940
|
-
const resolved = this._resolvePath(path);
|
|
334941
|
-
if (!(await stat(resolved)).isDirectory()) throw new Error(`Not a directory: ${resolved}`);
|
|
334942
|
-
this._cwd = resolved;
|
|
334943
|
-
}
|
|
334944
|
-
async stat(path, options) {
|
|
334945
|
-
const resolved = this._resolvePath(path);
|
|
334946
|
-
const s = options?.followSymlinks ?? true ? await stat(resolved) : await lstat(resolved);
|
|
334947
|
-
return {
|
|
334948
|
-
stMode: s.mode,
|
|
334949
|
-
stIno: s.ino,
|
|
334950
|
-
stDev: s.dev,
|
|
334951
|
-
stNlink: s.nlink,
|
|
334952
|
-
stUid: s.uid,
|
|
334953
|
-
stGid: s.gid,
|
|
334954
|
-
stSize: s.size,
|
|
334955
|
-
stAtime: s.atimeMs / 1e3,
|
|
334956
|
-
stMtime: s.mtimeMs / 1e3,
|
|
334957
|
-
stCtime: isWindows$1 ? s.birthtimeMs / 1e3 : s.ctimeMs / 1e3
|
|
334958
|
-
};
|
|
334959
|
-
}
|
|
334960
|
-
async *iterdir(path) {
|
|
334961
|
-
const resolved = this._resolvePath(path);
|
|
334962
|
-
const entries = await readdir(resolved);
|
|
334963
|
-
for (const entry of entries) yield join$4(resolved, entry);
|
|
334964
|
-
}
|
|
334965
|
-
async *glob(path, pattern, options) {
|
|
334966
|
-
const resolved = this._resolvePath(path);
|
|
334967
|
-
const caseSensitive = options?.caseSensitive ?? true;
|
|
334968
|
-
const patternParts = pattern.split("/");
|
|
334969
|
-
const initVisited = /* @__PURE__ */ new Set();
|
|
334970
|
-
try {
|
|
334971
|
-
const rootKey = cycleKey(await stat(resolved));
|
|
334972
|
-
if (rootKey !== null) initVisited.add(rootKey);
|
|
334973
|
-
} catch {}
|
|
334974
|
-
yield* this._globWalk(resolved, patternParts, caseSensitive, initVisited);
|
|
334975
|
-
}
|
|
334976
|
-
async *_globWalk(basePath, patternParts, caseSensitive, visited) {
|
|
334977
|
-
if (patternParts.length === 0) return;
|
|
334978
|
-
const [currentPattern, ...remainingParts] = patternParts;
|
|
334979
|
-
if (currentPattern === "**") {
|
|
334980
|
-
if (remainingParts.length > 0) yield* this._globWalk(basePath, remainingParts, caseSensitive, visited);
|
|
334981
|
-
else yield basePath;
|
|
334982
|
-
let entries;
|
|
334983
|
-
try {
|
|
334984
|
-
entries = await readdir(basePath);
|
|
334985
|
-
} catch {
|
|
334986
|
-
return;
|
|
334987
|
-
}
|
|
334988
|
-
for (const entry of entries) {
|
|
334989
|
-
const fullPath = join$4(basePath, entry);
|
|
334990
|
-
let entryStat;
|
|
334991
|
-
try {
|
|
334992
|
-
entryStat = await stat(fullPath);
|
|
334993
|
-
} catch {
|
|
334994
|
-
continue;
|
|
334995
|
-
}
|
|
334996
|
-
if (entryStat.isDirectory()) {
|
|
334997
|
-
const key = cycleKey(entryStat);
|
|
334998
|
-
if (key !== null && visited.has(key)) continue;
|
|
334999
|
-
yield* this._globWalk(fullPath, patternParts, caseSensitive, key !== null ? new Set([...visited, key]) : visited);
|
|
335000
|
-
} else if (remainingParts.length === 0) yield fullPath;
|
|
335001
|
-
}
|
|
335002
|
-
} else {
|
|
335003
|
-
const regex = globPatternToRegex(currentPattern ?? "", caseSensitive);
|
|
335004
|
-
let entries;
|
|
335005
|
-
try {
|
|
335006
|
-
entries = await readdir(basePath);
|
|
335007
|
-
} catch {
|
|
335008
|
-
return;
|
|
335009
|
-
}
|
|
335010
|
-
for (const entry of entries) {
|
|
335011
|
-
if (!regex.test(entry)) continue;
|
|
335012
|
-
const fullPath = join$4(basePath, entry);
|
|
335013
|
-
if (remainingParts.length === 0) yield fullPath;
|
|
335014
|
-
else {
|
|
335015
|
-
let entryStat;
|
|
335016
|
-
try {
|
|
335017
|
-
entryStat = await stat(fullPath);
|
|
335018
|
-
} catch {
|
|
335019
|
-
continue;
|
|
335020
|
-
}
|
|
335021
|
-
if (entryStat.isDirectory()) {
|
|
335022
|
-
const key = cycleKey(entryStat);
|
|
335023
|
-
if (key !== null && visited.has(key)) continue;
|
|
335024
|
-
yield* this._globWalk(fullPath, remainingParts, caseSensitive, key !== null ? new Set([...visited, key]) : visited);
|
|
335025
|
-
}
|
|
335026
|
-
}
|
|
335027
|
-
}
|
|
335028
|
-
}
|
|
335029
|
-
}
|
|
335030
|
-
async readBytes(path, n) {
|
|
335031
|
-
const resolved = this._resolvePath(path);
|
|
335032
|
-
if (n === void 0) return Buffer.from(await readFile(resolved));
|
|
335033
|
-
const fh = await open(resolved, "r");
|
|
335034
|
-
try {
|
|
335035
|
-
const buf = Buffer.alloc(n);
|
|
335036
|
-
const { bytesRead } = await fh.read(buf, 0, n, 0);
|
|
335037
|
-
return buf.subarray(0, bytesRead);
|
|
335038
|
-
} finally {
|
|
335039
|
-
await fh.close();
|
|
335040
|
-
}
|
|
335041
|
-
}
|
|
335042
|
-
async readText(path, options) {
|
|
335043
|
-
const resolved = this._resolvePath(path);
|
|
335044
|
-
const encoding = options?.encoding ?? "utf-8";
|
|
335045
|
-
const errors = options?.errors ?? "strict";
|
|
335046
|
-
return decodeTextWithErrors(await readFile(resolved), encoding, errors);
|
|
335047
|
-
}
|
|
335048
|
-
async *readLines(path, options) {
|
|
335049
|
-
const resolved = this._resolvePath(path);
|
|
335050
|
-
const encoding = options?.encoding ?? "utf-8";
|
|
335051
|
-
const errors = options?.errors ?? "strict";
|
|
335052
|
-
if (!isUtf8Encoding(encoding)) {
|
|
335053
|
-
yield* splitLinesKeepingTerminator(decodeTextWithErrors(await readFile(resolved), encoding, errors));
|
|
335054
|
-
return;
|
|
335055
|
-
}
|
|
335056
|
-
yield* this._readUtf8Lines(resolved, errors);
|
|
335057
|
-
}
|
|
335058
|
-
async scanTextFile(path) {
|
|
335059
|
-
const fh = await open(this._resolvePath(path), "r");
|
|
335060
|
-
try {
|
|
335061
|
-
const buf = Buffer.alloc(READ_CHUNK_SIZE);
|
|
335062
|
-
const flags = {
|
|
335063
|
-
hasCrLf: false,
|
|
335064
|
-
hasLf: false,
|
|
335065
|
-
hasLoneCr: false
|
|
335066
|
-
};
|
|
335067
|
-
const validator = createUtf8Validator();
|
|
335068
|
-
let totalLines = 0;
|
|
335069
|
-
let totalBytes = 0;
|
|
335070
|
-
let endsWithNewline = false;
|
|
335071
|
-
let hasNul = false;
|
|
335072
|
-
let prevWasCr = false;
|
|
335073
|
-
while (true) {
|
|
335074
|
-
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
335075
|
-
if (bytesRead === 0) break;
|
|
335076
|
-
const chunk = buf.subarray(0, bytesRead);
|
|
335077
|
-
validator.write(chunk);
|
|
335078
|
-
for (let i = 0; i < chunk.length; i += 1) {
|
|
335079
|
-
const byte = chunk[i];
|
|
335080
|
-
if (byte === void 0) continue;
|
|
335081
|
-
if (byte === 0) hasNul = true;
|
|
335082
|
-
if (byte === 10) totalLines += 1;
|
|
335083
|
-
}
|
|
335084
|
-
prevWasCr = updateLineEndingFlagsFromBytes(flags, chunk, prevWasCr);
|
|
335085
|
-
totalBytes += bytesRead;
|
|
335086
|
-
endsWithNewline = chunk[bytesRead - 1] === 10;
|
|
335087
|
-
}
|
|
335088
|
-
if (prevWasCr) flags.hasLoneCr = true;
|
|
335089
|
-
validator.end();
|
|
335090
|
-
if (totalBytes > 0 && !endsWithNewline) totalLines += 1;
|
|
335091
|
-
return {
|
|
335092
|
-
totalLines,
|
|
335093
|
-
endsWithNewline,
|
|
335094
|
-
hasNul,
|
|
335095
|
-
lineEndingFlags: flags
|
|
335096
|
-
};
|
|
335097
|
-
} finally {
|
|
335098
|
-
await fh.close();
|
|
335099
|
-
}
|
|
335100
|
-
}
|
|
335101
|
-
async *readLineRange(path, options) {
|
|
335102
|
-
const resolved = this._resolvePath(path);
|
|
335103
|
-
const errors = options.errors ?? "strict";
|
|
335104
|
-
yield* this._readUtf8Lines(resolved, errors, {
|
|
335105
|
-
startLine: options.startLine,
|
|
335106
|
-
maxLines: options.maxLines
|
|
335107
|
-
});
|
|
335108
|
-
}
|
|
335109
|
-
async *readTailLines(path, options) {
|
|
335110
|
-
if (options.tailCount <= 0) return;
|
|
335111
|
-
const resolved = this._resolvePath(path);
|
|
335112
|
-
const errors = options.errors ?? "strict";
|
|
335113
|
-
const fh = await open(resolved, "r");
|
|
335114
|
-
try {
|
|
335115
|
-
const s = await fh.stat();
|
|
335116
|
-
if (s.size === 0) return;
|
|
335117
|
-
let pos = s.size;
|
|
335118
|
-
let foundLf = 0;
|
|
335119
|
-
let startOffset = 0;
|
|
335120
|
-
let needLf = options.tailCount;
|
|
335121
|
-
let sawTailBlock = false;
|
|
335122
|
-
while (pos > 0 && foundLf < needLf) {
|
|
335123
|
-
const readSize = Math.min(READ_CHUNK_SIZE, pos);
|
|
335124
|
-
pos -= readSize;
|
|
335125
|
-
const buf = Buffer.alloc(readSize);
|
|
335126
|
-
await fh.read(buf, 0, readSize, pos);
|
|
335127
|
-
if (!sawTailBlock) {
|
|
335128
|
-
sawTailBlock = true;
|
|
335129
|
-
needLf = buf[readSize - 1] === 10 ? options.tailCount + 1 : options.tailCount;
|
|
335130
|
-
}
|
|
335131
|
-
for (let i = readSize - 1; i >= 0; i -= 1) {
|
|
335132
|
-
if (buf[i] !== 10) continue;
|
|
335133
|
-
foundLf += 1;
|
|
335134
|
-
if (foundLf === needLf) {
|
|
335135
|
-
startOffset = pos + i + 1;
|
|
335136
|
-
break;
|
|
335137
|
-
}
|
|
335138
|
-
}
|
|
335139
|
-
}
|
|
335140
|
-
if (foundLf < needLf) startOffset = 0;
|
|
335141
|
-
yield* splitLinesKeepingTerminator(decodeTextWithErrors(await readRange(fh, startOffset, s.size - startOffset), "utf-8", errors, startOffset !== 0));
|
|
335142
|
-
} finally {
|
|
335143
|
-
await fh.close();
|
|
335144
|
-
}
|
|
335145
|
-
}
|
|
335146
|
-
async *_readUtf8Lines(resolved, errors, range) {
|
|
335147
|
-
const startLine = range?.startLine ?? 1;
|
|
335148
|
-
const maxLines = range?.maxLines ?? Number.POSITIVE_INFINITY;
|
|
335149
|
-
const fh = await open(resolved, "r");
|
|
335150
|
-
try {
|
|
335151
|
-
const buf = Buffer.alloc(READ_CHUNK_SIZE);
|
|
335152
|
-
let pending = [];
|
|
335153
|
-
let pendingOffset = 0;
|
|
335154
|
-
let fileOffset = 0;
|
|
335155
|
-
let lineNo = 1;
|
|
335156
|
-
let yielded = 0;
|
|
335157
|
-
while (true) {
|
|
335158
|
-
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
335159
|
-
if (bytesRead === 0) break;
|
|
335160
|
-
const chunk = buf.subarray(0, bytesRead);
|
|
335161
|
-
let lineStart = 0;
|
|
335162
|
-
for (let i = 0; i < chunk.length; i += 1) {
|
|
335163
|
-
if (chunk[i] !== 10) continue;
|
|
335164
|
-
const piece = chunk.subarray(lineStart, i + 1);
|
|
335165
|
-
const lineOffset = pending.length === 0 ? fileOffset + lineStart : pendingOffset;
|
|
335166
|
-
const line = pending.length === 0 ? piece : Buffer.concat([...pending, piece]);
|
|
335167
|
-
if (lineNo >= startLine) {
|
|
335168
|
-
yield decodeTextWithErrors(line, "utf-8", errors, lineOffset !== 0);
|
|
335169
|
-
yielded += 1;
|
|
335170
|
-
if (yielded >= maxLines) return;
|
|
335171
|
-
}
|
|
335172
|
-
pending = [];
|
|
335173
|
-
lineStart = i + 1;
|
|
335174
|
-
lineNo += 1;
|
|
335175
|
-
}
|
|
335176
|
-
if (lineStart < chunk.length) {
|
|
335177
|
-
const tail = Buffer.from(chunk.subarray(lineStart));
|
|
335178
|
-
if (pending.length === 0) pendingOffset = fileOffset + lineStart;
|
|
335179
|
-
pending.push(tail);
|
|
335180
|
-
}
|
|
335181
|
-
fileOffset += bytesRead;
|
|
335182
|
-
}
|
|
335183
|
-
if (pending.length > 0) {
|
|
335184
|
-
const line = Buffer.concat(pending);
|
|
335185
|
-
if (lineNo >= startLine) yield decodeTextWithErrors(line, "utf-8", errors, pendingOffset !== 0);
|
|
335186
|
-
}
|
|
335187
|
-
} finally {
|
|
335188
|
-
await fh.close();
|
|
335189
|
-
}
|
|
335190
|
-
}
|
|
335191
|
-
async writeBytes(path, data) {
|
|
335192
|
-
await writeFile(this._resolvePath(path), data);
|
|
335193
|
-
return data.length;
|
|
335194
|
-
}
|
|
335195
|
-
async writeText(path, data, options) {
|
|
335196
|
-
const resolved = this._resolvePath(path);
|
|
335197
|
-
const encoding = options?.encoding ?? "utf-8";
|
|
335198
|
-
if ((options?.mode ?? "w") === "a") await appendFile(resolved, data, encoding);
|
|
335199
|
-
else await writeFile(resolved, data, encoding);
|
|
335200
|
-
return data.length;
|
|
335201
|
-
}
|
|
335202
|
-
async mkdir(path, options) {
|
|
335203
|
-
const resolved = this._resolvePath(path);
|
|
335204
|
-
const parents = options?.parents ?? false;
|
|
335205
|
-
const existOk = options?.existOk ?? false;
|
|
335206
|
-
if (parents) {
|
|
335207
|
-
if (!existOk) try {
|
|
335208
|
-
if ((await stat(resolved)).isDirectory()) throw new KaosFileExistsError(`${resolved} already exists`);
|
|
335209
|
-
} catch (error) {
|
|
335210
|
-
if (error instanceof KaosFileExistsError) throw error;
|
|
335211
|
-
if (error.code !== "ENOENT") throw error;
|
|
335212
|
-
}
|
|
335213
|
-
await mkdir(resolved, { recursive: true });
|
|
335214
|
-
return;
|
|
335215
|
-
}
|
|
335216
|
-
try {
|
|
335217
|
-
await mkdir(resolved);
|
|
335218
|
-
} catch (error) {
|
|
335219
|
-
if (existOk && error instanceof Error && "code" in error && error.code === "EEXIST") {
|
|
335220
|
-
if (!(await stat(resolved)).isDirectory()) throw new KaosFileExistsError(`${resolved} already exists but is not a directory`);
|
|
335221
|
-
return;
|
|
335222
|
-
}
|
|
335223
|
-
throw error;
|
|
335224
|
-
}
|
|
335225
|
-
}
|
|
335226
|
-
async exec(...args) {
|
|
335227
|
-
const command = args[0];
|
|
335228
|
-
if (command === void 0) throw new Error("LocalKaos.exec(): at least one argument (the command to run) is required.");
|
|
335229
|
-
const child = spawn(command, args.slice(1), buildLocalSpawnOptions(isWindows$1, this._cwd, this._buildExecEnv()));
|
|
335230
|
-
await waitForSpawn(child);
|
|
335231
|
-
return new LocalProcess(child);
|
|
335232
|
-
}
|
|
335233
|
-
async execWithEnv(args, env) {
|
|
335234
|
-
const command = args[0];
|
|
335235
|
-
if (command === void 0) throw new Error("LocalKaos.execWithEnv(): at least one argument (the command to run) is required.");
|
|
335236
|
-
const child = spawn(command, args.slice(1), buildLocalSpawnOptions(isWindows$1, this._cwd, this._buildExecEnv(env)));
|
|
335237
|
-
await waitForSpawn(child);
|
|
335238
|
-
return new LocalProcess(child);
|
|
335239
|
-
}
|
|
335240
|
-
_buildExecEnv(invocationEnv) {
|
|
335241
|
-
if (this._envLayers.length === 0) return invocationEnv;
|
|
335242
|
-
const merged = {
|
|
335243
|
-
...process.env,
|
|
335244
|
-
...invocationEnv
|
|
335245
|
-
};
|
|
335246
|
-
for (const layer of this._envLayers) Object.assign(merged, layer);
|
|
335247
|
-
return merged;
|
|
335248
|
-
}
|
|
335249
|
-
};
|
|
335250
|
-
}));
|
|
335251
|
-
var init_current = __esmMin((() => {
|
|
335252
|
-
new AsyncLocalStorage();
|
|
335253
|
-
}));
|
|
335254
|
-
//#endregion
|
|
335255
|
-
//#region ../../packages/kaos/src/index.ts
|
|
335256
|
-
var init_src$1 = __esmMin((() => {
|
|
335257
|
-
init_environment$1();
|
|
335258
|
-
init_errors$1();
|
|
335259
|
-
init_local();
|
|
335260
|
-
init_current();
|
|
335261
|
-
}));
|
|
335262
|
-
//#endregion
|
|
335263
335643
|
//#region ../../packages/agent-core/src/agent/replay/build.ts
|
|
335264
335644
|
async function buildReplay(persistence, range) {
|
|
335265
335645
|
const agent = new Agent$1({
|
|
@@ -393762,7 +394142,7 @@ var require_constants$2 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
393762
394142
|
};
|
|
393763
394143
|
}));
|
|
393764
394144
|
//#endregion
|
|
393765
|
-
//#region
|
|
394145
|
+
//#region ../../node_modules/node-gyp-build/node-gyp-build.js
|
|
393766
394146
|
var require_node_gyp_build$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
393767
394147
|
var fs$4 = __require("fs");
|
|
393768
394148
|
var path$6 = __require("path");
|
|
@@ -393918,14 +394298,14 @@ var require_node_gyp_build$1 = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
393918
394298
|
load.compareTuples = compareTuples;
|
|
393919
394299
|
}));
|
|
393920
394300
|
//#endregion
|
|
393921
|
-
//#region
|
|
394301
|
+
//#region ../../node_modules/node-gyp-build/index.js
|
|
393922
394302
|
var require_node_gyp_build = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
393923
394303
|
const runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
|
|
393924
394304
|
if (typeof runtimeRequire.addon === "function") module.exports = runtimeRequire.addon.bind(runtimeRequire);
|
|
393925
394305
|
else module.exports = require_node_gyp_build$1();
|
|
393926
394306
|
}));
|
|
393927
394307
|
//#endregion
|
|
393928
|
-
//#region
|
|
394308
|
+
//#region ../../node_modules/bufferutil/fallback.js
|
|
393929
394309
|
var require_fallback$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
393930
394310
|
/**
|
|
393931
394311
|
* Masks a buffer using the given mask.
|
|
@@ -393957,7 +394337,7 @@ var require_fallback$1 = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
393957
394337
|
};
|
|
393958
394338
|
}));
|
|
393959
394339
|
//#endregion
|
|
393960
|
-
//#region
|
|
394340
|
+
//#region ../../node_modules/bufferutil/index.js
|
|
393961
394341
|
var require_bufferutil = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
393962
394342
|
try {
|
|
393963
394343
|
module.exports = require_node_gyp_build()(__dirname);
|
|
@@ -394450,7 +394830,7 @@ var require_permessage_deflate = /* @__PURE__ */ __commonJSMin(((exports, module
|
|
|
394450
394830
|
}
|
|
394451
394831
|
}));
|
|
394452
394832
|
//#endregion
|
|
394453
|
-
//#region
|
|
394833
|
+
//#region ../../node_modules/utf-8-validate/fallback.js
|
|
394454
394834
|
var require_fallback = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
394455
394835
|
/**
|
|
394456
394836
|
* Checks if a given buffer contains only correct UTF-8.
|
|
@@ -394480,7 +394860,7 @@ var require_fallback = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
394480
394860
|
module.exports = isValidUTF8;
|
|
394481
394861
|
}));
|
|
394482
394862
|
//#endregion
|
|
394483
|
-
//#region
|
|
394863
|
+
//#region ../../node_modules/utf-8-validate/index.js
|
|
394484
394864
|
var require_utf_8_validate = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
394485
394865
|
try {
|
|
394486
394866
|
module.exports = require_node_gyp_build()(__dirname);
|
|
@@ -531781,6 +532161,7 @@ var SessionEventHandler = class {
|
|
|
531781
532161
|
}
|
|
531782
532162
|
}
|
|
531783
532163
|
handleSessionError(event) {
|
|
532164
|
+
if (event.code === "turn.agent_busy" && this.host.isManualPromptAdmissionPending?.(event.sessionId, event.agentId)) return;
|
|
531784
532165
|
this.host.streamingUI.flushNow();
|
|
531785
532166
|
this.host.streamingUI.resetToolUi();
|
|
531786
532167
|
this.host.streamingUI.finalizeLiveTextBuffers("idle");
|
|
@@ -539090,17 +539471,22 @@ var BlunTUI = class {
|
|
|
539090
539471
|
editorReplacement;
|
|
539091
539472
|
editorReplacementGeneration = 0;
|
|
539092
539473
|
preserveQueueAcrossSessionReset = false;
|
|
539474
|
+
manualPromptInFlight;
|
|
539475
|
+
isManualPromptAdmissionPending(sessionId, agentId) {
|
|
539476
|
+
const pending = this.manualPromptInFlight;
|
|
539477
|
+
return pending !== void 0 && this.session === pending.session && pending.session.id === sessionId && pending.agentId === agentId;
|
|
539478
|
+
}
|
|
539093
539479
|
hasWaitingChannelMessage() {
|
|
539094
539480
|
return this.state.queuedMessages.some((item) => item.mode === "channel");
|
|
539095
539481
|
}
|
|
539096
539482
|
canInterruptForQueuedChannel() {
|
|
539097
539483
|
const item = this.state.queuedMessages[0];
|
|
539098
539484
|
if (/^[1-9]\d*$/u.test(this.pendingChannelReplyGuard?.chatId ?? "") && item?.channelChatId?.startsWith("-") === true) return false;
|
|
539099
|
-
return item?.mode === "channel" && item.channelContextOnly !== true && this.session !== void 0 && this.queueSteerInFlight === void 0 && !this.deferUserMessages && !this.state.appState.isCompacting && this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell" && this.shellOutputStreams.size === 0 && !this.streamingUI.hasActiveToolCalls();
|
|
539485
|
+
return item?.mode === "channel" && item.channelContextOnly !== true && this.session !== void 0 && this.queueSteerInFlight === void 0 && this.manualPromptInFlight === void 0 && !this.deferUserMessages && !this.state.appState.isCompacting && this.state.appState.streamingPhase !== "idle" && this.state.appState.streamingPhase !== "shell" && this.shellOutputStreams.size === 0 && !this.streamingUI.hasActiveToolCalls();
|
|
539100
539486
|
}
|
|
539101
539487
|
canDeliverQueuedChannelHead() {
|
|
539102
539488
|
const item = this.state.queuedMessages[0];
|
|
539103
|
-
if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.editorReplacementActive || this.deferUserMessages || this.session === void 0 || this.state.appState.model.trim().length === 0 || item?.mode !== "channel") return false;
|
|
539489
|
+
if (this.isShuttingDown || this.queueCommandRunning || this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || this.editorReplacementActive || this.deferUserMessages || this.session === void 0 || this.state.appState.model.trim().length === 0 || item?.mode !== "channel") return false;
|
|
539104
539490
|
const guard = this.pendingChannelReplyGuard;
|
|
539105
539491
|
return guard === void 0 || item.channelChatId !== void 0 && guard.chatId === item.channelChatId;
|
|
539106
539492
|
}
|
|
@@ -539224,7 +539610,7 @@ var BlunTUI = class {
|
|
|
539224
539610
|
canDrainQueue() {
|
|
539225
539611
|
const head = this.state.queuedMessages[0];
|
|
539226
539612
|
const remoteControl = head?.mode === "command" && head.channelCommandEnvelope !== void 0 && channelCommandCanInterrupt(head.text);
|
|
539227
|
-
return !this.isShuttingDown && !this.queueCommandRunning && this.queueSteerInFlight === void 0 && !this.editorReplacementActive && !this.deferUserMessages && (remoteControl || this.state.appState.streamingPhase === "idle" && !this.state.appState.isCompacting);
|
|
539613
|
+
return !this.isShuttingDown && !this.queueCommandRunning && this.queueSteerInFlight === void 0 && this.manualPromptInFlight === void 0 && !this.editorReplacementActive && !this.deferUserMessages && (remoteControl || this.state.appState.streamingPhase === "idle" && !this.state.appState.isCompacting);
|
|
539228
539614
|
}
|
|
539229
539615
|
scheduleQueueDrain() {
|
|
539230
539616
|
if (this.queueDrainTimer !== void 0 || !this.canDrainQueue()) return;
|
|
@@ -539252,11 +539638,12 @@ var BlunTUI = class {
|
|
|
539252
539638
|
}
|
|
539253
539639
|
const inFlightCount = this.queueSteerInFlight?.items.length ?? 0;
|
|
539254
539640
|
this.queueFlushBatchRemaining = inFlightCount + this.state.queuedMessages.length;
|
|
539641
|
+
if (this.manualPromptInFlight !== void 0) this.manualPromptInFlight.flushRequested = this.queueFlushBatchRemaining > 0;
|
|
539255
539642
|
this.steerQueueFlushPrefix();
|
|
539256
539643
|
this.scheduleQueueDrain();
|
|
539257
539644
|
}
|
|
539258
539645
|
steerQueueFlushPrefix() {
|
|
539259
|
-
if (this.queueSteerInFlight !== void 0 || this.queueFlushBatchRemaining === 0 || this.deferUserMessages || this.state.appState.isCompacting || this.state.appState.streamingPhase === "idle" || this.state.appState.streamingPhase === "shell") return;
|
|
539646
|
+
if (this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || this.queueFlushBatchRemaining === 0 || this.deferUserMessages || this.state.appState.isCompacting || this.state.appState.streamingPhase === "idle" || this.state.appState.streamingPhase === "shell") return;
|
|
539260
539647
|
const session = this.session;
|
|
539261
539648
|
if (session === void 0 || this.state.appState.model.trim().length === 0) {
|
|
539262
539649
|
this.showError(llmNotSetMessage());
|
|
@@ -539280,13 +539667,16 @@ var BlunTUI = class {
|
|
|
539280
539667
|
turnEnded: false,
|
|
539281
539668
|
onCommit: () => {
|
|
539282
539669
|
this.queueFlushBatchRemaining = Math.max(0, this.queueFlushBatchRemaining - items.length);
|
|
539283
|
-
for (const item of items)
|
|
539284
|
-
|
|
539285
|
-
|
|
539286
|
-
|
|
539287
|
-
|
|
539288
|
-
|
|
539289
|
-
|
|
539670
|
+
for (const item of items) {
|
|
539671
|
+
if (item.transcriptRendered) continue;
|
|
539672
|
+
this.appendTranscriptEntry({
|
|
539673
|
+
id: nextTranscriptId(),
|
|
539674
|
+
kind: "user",
|
|
539675
|
+
turnId,
|
|
539676
|
+
renderMode: "plain",
|
|
539677
|
+
content: item.text.trim()
|
|
539678
|
+
});
|
|
539679
|
+
}
|
|
539290
539680
|
}
|
|
539291
539681
|
};
|
|
539292
539682
|
this.queueSteerInFlight = inFlight;
|
|
@@ -539358,7 +539748,7 @@ var BlunTUI = class {
|
|
|
539358
539748
|
channelCommandEnvelope: envelope,
|
|
539359
539749
|
channelAcknowledge: acknowledge
|
|
539360
539750
|
};
|
|
539361
|
-
const busy = this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting;
|
|
539751
|
+
const busy = this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting;
|
|
539362
539752
|
if (this.session === void 0 || this.deferUserMessages || this.queueCommandRunning || this.editorReplacementActive || busy && !channelCommandCanInterrupt(command)) {
|
|
539363
539753
|
this.state.queuedMessages.push(item);
|
|
539364
539754
|
this.scheduleQueueDrain();
|
|
@@ -539369,7 +539759,7 @@ var BlunTUI = class {
|
|
|
539369
539759
|
}
|
|
539370
539760
|
injectChannelEnvelope({
|
|
539371
539761
|
canDeliver: () => this.session !== void 0 && this.state.appState.model.trim().length > 0,
|
|
539372
|
-
isBusy: () => this.queueCommandRunning || this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.deferUserMessages || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting,
|
|
539762
|
+
isBusy: () => this.queueCommandRunning || this.state.queuedMessages.length > 0 || this.queueSteerInFlight !== void 0 || this.manualPromptInFlight !== void 0 || this.deferUserMessages || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting,
|
|
539373
539763
|
deliverNow: (modelInput, displayText, origin, contextOnly) => {
|
|
539374
539764
|
this.sendChannelMessageInternal(this.requireSession(), modelInput, displayText, origin, envelope.meta.chat_id, envelope.meta["image_path"], contextOnly, false, acknowledge);
|
|
539375
539765
|
},
|
|
@@ -539673,7 +540063,8 @@ var BlunTUI = class {
|
|
|
539673
540063
|
agentId: this.harness.interactiveAgentId,
|
|
539674
540064
|
parts: options?.parts,
|
|
539675
540065
|
imageAttachmentIds: options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? options.imageAttachmentIds : void 0,
|
|
539676
|
-
mode
|
|
540066
|
+
mode,
|
|
540067
|
+
transcriptRendered: options?.transcriptRendered
|
|
539677
540068
|
});
|
|
539678
540069
|
this.track("input_queue");
|
|
539679
540070
|
}
|
|
@@ -539732,7 +540123,8 @@ var BlunTUI = class {
|
|
|
539732
540123
|
this.harness.withInteractiveAgent(item.agentId ?? "main", () => {
|
|
539733
540124
|
this.sendMessageInternal(activeSession, item.text, {
|
|
539734
540125
|
parts: item.parts,
|
|
539735
|
-
imageAttachmentIds: item.imageAttachmentIds
|
|
540126
|
+
imageAttachmentIds: item.imageAttachmentIds,
|
|
540127
|
+
transcriptRendered: item.transcriptRendered
|
|
539736
540128
|
});
|
|
539737
540129
|
});
|
|
539738
540130
|
}
|
|
@@ -539751,9 +540143,13 @@ var BlunTUI = class {
|
|
|
539751
540143
|
this.sessionEventHandler.requestQueuedGoalPromotion();
|
|
539752
540144
|
}
|
|
539753
540145
|
sendMessageInternal(session, input, options) {
|
|
540146
|
+
if (this.manualPromptInFlight !== void 0) {
|
|
540147
|
+
this.enqueueMessage(input, options);
|
|
540148
|
+
return;
|
|
540149
|
+
}
|
|
539754
540150
|
armPersonalMemoryRememberIntent(session.id, input);
|
|
539755
540151
|
const imageAttachmentIds = options?.imageAttachmentIds !== void 0 && options.imageAttachmentIds.length > 0 ? options.imageAttachmentIds : void 0;
|
|
539756
|
-
this.appendTranscriptEntry({
|
|
540152
|
+
if (!options?.transcriptRendered) this.appendTranscriptEntry({
|
|
539757
540153
|
id: nextTranscriptId(),
|
|
539758
540154
|
kind: "user",
|
|
539759
540155
|
turnId: void 0,
|
|
@@ -539761,13 +540157,48 @@ var BlunTUI = class {
|
|
|
539761
540157
|
content: input,
|
|
539762
540158
|
imageAttachmentIds
|
|
539763
540159
|
});
|
|
540160
|
+
const agentId = this.harness.interactiveAgentId;
|
|
540161
|
+
const inFlight = {
|
|
540162
|
+
session,
|
|
540163
|
+
agentId
|
|
540164
|
+
};
|
|
540165
|
+
this.manualPromptInFlight = inFlight;
|
|
540166
|
+
let admissionResolved = false;
|
|
539764
540167
|
this.beginSessionRequest();
|
|
539765
540168
|
const sdkInput = options?.parts ?? input;
|
|
539766
540169
|
this.setAppState({
|
|
539767
540170
|
model: BLUN_KING_MODEL_ALIAS,
|
|
539768
540171
|
modelFallbackAllowed: false
|
|
539769
540172
|
});
|
|
539770
|
-
session.promptAccepted(sdkInput).
|
|
540173
|
+
session.promptAccepted(sdkInput).then((result) => {
|
|
540174
|
+
if (this.session !== session || this.manualPromptInFlight !== inFlight) return;
|
|
540175
|
+
admissionResolved = true;
|
|
540176
|
+
this.manualPromptInFlight = void 0;
|
|
540177
|
+
if (!result.accepted) {
|
|
540178
|
+
finishPersonalMemoryRememberIntentTurn(session.id);
|
|
540179
|
+
if (inFlight.flushRequested && this.queueFlushBatchRemaining > 0) this.queueFlushBatchRemaining += 1;
|
|
540180
|
+
this.state.queuedMessages = [{
|
|
540181
|
+
text: input,
|
|
540182
|
+
agentId,
|
|
540183
|
+
parts: options?.parts,
|
|
540184
|
+
imageAttachmentIds,
|
|
540185
|
+
transcriptRendered: true
|
|
540186
|
+
}, ...this.state.queuedMessages];
|
|
540187
|
+
this.track("input_queue");
|
|
540188
|
+
this.updateQueueDisplay();
|
|
540189
|
+
this.state.ui.requestRender();
|
|
540190
|
+
}
|
|
540191
|
+
this.syncChannelQueueDeadline();
|
|
540192
|
+
if (inFlight.flushRequested) this.steerQueueFlushPrefix();
|
|
540193
|
+
this.scheduleQueueDrain();
|
|
540194
|
+
}).catch((error) => {
|
|
540195
|
+
if (this.session !== session) return;
|
|
540196
|
+
if (admissionResolved) {
|
|
540197
|
+
this.showError(formatErrorMessage$2(error));
|
|
540198
|
+
return;
|
|
540199
|
+
}
|
|
540200
|
+
if (this.manualPromptInFlight !== inFlight) return;
|
|
540201
|
+
this.manualPromptInFlight = void 0;
|
|
539771
540202
|
finishPersonalMemoryRememberIntentTurn(session.id);
|
|
539772
540203
|
const message = formatErrorMessage$2(error);
|
|
539773
540204
|
this.failSessionRequest(uiText("blunTui.session.sendFailed", { error: message }));
|
|
@@ -539794,19 +540225,20 @@ var BlunTUI = class {
|
|
|
539794
540225
|
});
|
|
539795
540226
|
}
|
|
539796
540227
|
sendMessage(session, input, options) {
|
|
539797
|
-
if (this.deferUserMessages || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting) {
|
|
540228
|
+
if (this.deferUserMessages || this.manualPromptInFlight !== void 0 || this.state.queuedMessages.length > 0 || this.state.appState.streamingPhase !== "idle" || this.state.appState.isCompacting) {
|
|
539798
540229
|
this.enqueueMessage(input, options);
|
|
540230
|
+
this.scheduleQueueDrain();
|
|
539799
540231
|
return;
|
|
539800
540232
|
}
|
|
539801
540233
|
this.sendMessageInternal(session, input, options);
|
|
539802
540234
|
}
|
|
539803
540235
|
steerMessage(session, input) {
|
|
539804
|
-
if (this.deferUserMessages || this.state.appState.isCompacting) {
|
|
540236
|
+
if (this.deferUserMessages || this.state.appState.isCompacting || this.manualPromptInFlight !== void 0) {
|
|
539805
540237
|
for (const part of input) this.enqueueMessage(part);
|
|
539806
540238
|
return;
|
|
539807
540239
|
}
|
|
539808
540240
|
if (this.state.appState.streamingPhase === "idle") {
|
|
539809
|
-
for (const part of input) this.
|
|
540241
|
+
for (const part of input) this.sendMessage(session, part);
|
|
539810
540242
|
return;
|
|
539811
540243
|
}
|
|
539812
540244
|
for (const part of input) this.appendTranscriptEntry({
|
|
@@ -539826,6 +540258,7 @@ var BlunTUI = class {
|
|
|
539826
540258
|
this.state.startupState = "ready";
|
|
539827
540259
|
}
|
|
539828
540260
|
clearQueuedMessages() {
|
|
540261
|
+
this.manualPromptInFlight = void 0;
|
|
539829
540262
|
const discarded = [...this.state.queuedMessages, ...this.queueSteerInFlight?.items ?? []];
|
|
539830
540263
|
this.queueSteerInFlight?.onRestore?.();
|
|
539831
540264
|
this.state.queuedMessages = [];
|
|
@@ -540141,6 +540574,7 @@ var BlunTUI = class {
|
|
|
540141
540574
|
this.state.terminal.setTitle(label);
|
|
540142
540575
|
}
|
|
540143
540576
|
resetSessionRuntime() {
|
|
540577
|
+
this.manualPromptInFlight = void 0;
|
|
540144
540578
|
this.streamingUI.setSessionTotalTokens(void 0);
|
|
540145
540579
|
this.loopCountdown.dispose();
|
|
540146
540580
|
this.aborted = false;
|