@oxagen/cli 2.1.5-60 → 2.1.5-69
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/oxagen.mjs +979 -317
- package/package.json +1 -1
package/oxagen.mjs
CHANGED
|
@@ -3589,15 +3589,15 @@ var init_types = __esm({
|
|
|
3589
3589
|
}
|
|
3590
3590
|
const valueType = this._def.valueType;
|
|
3591
3591
|
function finalizeSet(elements2) {
|
|
3592
|
-
const
|
|
3592
|
+
const parsedSet2 = /* @__PURE__ */ new Set();
|
|
3593
3593
|
for (const element of elements2) {
|
|
3594
3594
|
if (element.status === "aborted")
|
|
3595
3595
|
return INVALID;
|
|
3596
3596
|
if (element.status === "dirty")
|
|
3597
3597
|
status2.dirty();
|
|
3598
|
-
|
|
3598
|
+
parsedSet2.add(element.value);
|
|
3599
3599
|
}
|
|
3600
|
-
return { status: status2.value, value:
|
|
3600
|
+
return { status: status2.value, value: parsedSet2 };
|
|
3601
3601
|
}
|
|
3602
3602
|
const elements = [...ctx.data.values()].map((item, i2) => valueType._parse(new ParseInputLazyPath(ctx, item, ctx.path, i2)));
|
|
3603
3603
|
if (ctx.common.async) {
|
|
@@ -5656,7 +5656,7 @@ function bundleSkillChars(skill) {
|
|
|
5656
5656
|
chars += file.path.length + file.content.length;
|
|
5657
5657
|
return chars;
|
|
5658
5658
|
}
|
|
5659
|
-
var protocolTimestampSchema, machineGroupSchema, TACHO_BATCH_SCHEMA, TACHO_BUNDLE_SCHEMA, TACHO_COMMANDS_SCHEMA, TACHO_ENROLLMENT_CLAIMS_SCHEMA, TACHO_ENFORCEMENT_TIER_ATTR, TACHO_GATEWAY_TIER, TACHO_GATEWAY_SESSION_HEADER, TACHO_GATEWAY_GENESIS_HEADER, REFUSAL_META_KEY, MCP_STREAMABLE_HTTP_ACCEPT, TACHO_METERING_ATTR, TACHO_METERING_OBSERVED, TACHO_MODEL_SESSION_HEADER, TACHO_CREDENTIAL_BASIS_ATTR, TACHO_CREDENTIAL_GATEWAY_BROKERED, TACHO_CREDENTIAL_HARNESS_HELD, TACHO_CREDENTIAL_BASES, TACHO_RUN_TOKEN_ATTR, BUNDLE_FEATURE_GATEWAY_TOOLS, BUNDLE_FEATURE_MODEL_PRICES, BUNDLE_FEATURE_MODEL_ALLOWLIST, BUNDLE_FEATURE_INDEPENDENT_MODELS, BUNDLE_FEATURE_HOOK_FAIL_OPEN, BUNDLE_FEATURE_STEERING_MANIFEST, BUNDLE_FEATURE_STEERING_INCOMPLETE, BUNDLE_FEATURE_CONTAINMENT, BUNDLE_FEATURE_DAILY_BUDGET, BUNDLE_FEATURE_STEER_NEXT_STEP, BUNDLE_FEATURE_UNBOUND_REPO, BUNDLE_FEATURE_CEDAR, BUNDLE_FEATURE_CEDAR_TOOLBELT, BUNDLE_FEATURE_SKILLS, BUNDLE_FEATURE_CACHE_KEEP_ALIVE, BUNDLE_FEATURE_WORK_ORDERS, BUNDLE_FEATURE_WORK_ORDER_START, BUNDLE_FEATURE_GATEWAY_POLICY, GATEWAY_MIN_TIERS, SENSITIVE_SCREEN_ACTIONS, PROMPT_REDACTION_PATTERNS_MAX, PROMPT_REDACTION_PATTERN_MAX, gatewayPolicySchema, TACHO_BUNDLE_FEATURES, bundleFeaturesSchema, hostEnrollmentIdSchema, tachoPlatformSchema, tachoHarnessSchema, TACHO_HARNESS_LABELS, TACHO_HARNESS_TIERS, WRAPPED_HARNESSES, CONNECTED_HARNESSES, HARNESS_BINARY, MODEL_HARNESS_ROUTES, MODEL_ROUTED_HARNESSES, BROKERABLE_HARNESSES, BROKERABLE_HARNESS_PROVIDER, TACHO_TIER_SUMMARY, CUSTOM_AGENT_NAME_PATTERN, RESERVED_AGENT_NAMES, tachoHostStatusSchema, tachoBundleModeSchema, tachoCommandSchema, tachoCommandStatusSchema, tachoCommandAckStatusSchema, tachoDeliveryModeSchema, denyGenerationSchema, deliveredCommandSchema, deliveredCommandResponseSchema, WORK_ORDER_ID_PATTERN, WORK_ITEM_ID_PATTERN, workOrderCommandPayloadSchema, WORK_ORDER_CLAIM_PATH, WORK_ORDER_REJECT_PATH, workOrderClaimResponseSchema, workOrderRejectResponseSchema, WORK_CRITERION_CLAIM_PATH, WORK_CRITERION_ID_PATTERN, WORK_HEAD_SHA_PATTERN, WORK_CRITERION_CLAIM_TEXT_MAX, workCriterionClaimResponseSchema, WORK_ORDER_ENV, WORK_ORDER_ATTR, steeringForceSchema, steeringItemKindSchema, steeringCutReasonSchema, steeringManifestItemSchema, STEERING_MANIFEST_SCHEMA, steeringManifestSchema, steeringManifestFrameSchema, cedarIdSchema, cedarPrincipalSchema, cedarToolSchema, cedarBundleSchema, BUNDLE_SKILLS_MAX, BUNDLE_SKILL_FILES_MAX, BUNDLE_SKILLS_CHARS_MAX, BASE64_PATTERN, bundleSkillFileSchema, bundleSkillSchema, policyBundleSchema, enrollmentClaimsSchema, tachoEventWireSchema, daemonHealthSchema, TACHO_MAX_BATCH, TACHO_MAX_BODY_BYTES, TACHO_MAX_REQUEST_BYTES, TACHO_REQUEST_ENVELOPE_BYTES, tachoBodySchema, tachoBatchSchema, agentDaySpendSchema, controlEnvelopeSchema, ingestResponseSchema, bundleResponseSchema, commandAcknowledgementSchema, commandsResponseSchema, enrollmentResponseSchema, tokenEnrollmentResponseSchema;
|
|
5659
|
+
var protocolTimestampSchema, machineGroupSchema, TACHO_BATCH_SCHEMA, TACHO_BUNDLE_SCHEMA, TACHO_COMMANDS_SCHEMA, TACHO_ENROLLMENT_CLAIMS_SCHEMA, TACHO_ENFORCEMENT_TIER_ATTR, TACHO_GATEWAY_TIER, TACHO_GATEWAY_SESSION_HEADER, TACHO_GATEWAY_GENESIS_HEADER, REFUSAL_META_KEY, MCP_STREAMABLE_HTTP_ACCEPT, TACHO_METERING_ATTR, TACHO_METERING_OBSERVED, TACHO_MODEL_SESSION_HEADER, TACHO_CREDENTIAL_BASIS_ATTR, TACHO_CREDENTIAL_GATEWAY_BROKERED, TACHO_CREDENTIAL_HARNESS_HELD, TACHO_CREDENTIAL_BASES, TACHO_RUN_TOKEN_ATTR, BUNDLE_FEATURE_GATEWAY_TOOLS, BUNDLE_FEATURE_MODEL_PRICES, BUNDLE_FEATURE_MODEL_ALLOWLIST, BUNDLE_FEATURE_INDEPENDENT_MODELS, BUNDLE_FEATURE_HOOK_FAIL_OPEN, BUNDLE_FEATURE_STEERING_MANIFEST, BUNDLE_FEATURE_STEERING_INCOMPLETE, BUNDLE_FEATURE_CONTAINMENT, BUNDLE_FEATURE_DAILY_BUDGET, BUNDLE_FEATURE_STEER_NEXT_STEP, BUNDLE_FEATURE_UNBOUND_REPO, BUNDLE_FEATURE_CEDAR, BUNDLE_FEATURE_CEDAR_TOOLBELT, BUNDLE_FEATURE_SKILLS, BUNDLE_FEATURE_CACHE_KEEP_ALIVE, BUNDLE_FEATURE_WORK_ORDERS, BUNDLE_FEATURE_WORK_ORDER_START, BUNDLE_FEATURE_MCP_RULE_SETS, BUNDLE_FEATURE_GATEWAY_POLICY, GATEWAY_MIN_TIERS, SENSITIVE_SCREEN_ACTIONS, PROMPT_REDACTION_PATTERNS_MAX, PROMPT_REDACTION_PATTERN_MAX, gatewayPolicySchema, TACHO_BUNDLE_FEATURES, bundleFeaturesSchema, hostEnrollmentIdSchema, tachoPlatformSchema, tachoHarnessSchema, TACHO_HARNESS_LABELS, TACHO_HARNESS_TIERS, WRAPPED_HARNESSES, CONNECTED_HARNESSES, HARNESS_BINARY, MODEL_HARNESS_ROUTES, MODEL_ROUTED_HARNESSES, BROKERABLE_HARNESSES, BROKERABLE_HARNESS_PROVIDER, TACHO_TIER_SUMMARY, CUSTOM_AGENT_NAME_PATTERN, RESERVED_AGENT_NAMES, tachoHostStatusSchema, tachoBundleModeSchema, tachoCommandSchema, tachoCommandStatusSchema, tachoCommandAckStatusSchema, tachoDeliveryModeSchema, denyGenerationSchema, deliveredCommandSchema, deliveredCommandResponseSchema, WORK_ORDER_ID_PATTERN, WORK_ITEM_ID_PATTERN, workOrderCommandPayloadSchema, WORK_ORDER_CLAIM_PATH, WORK_ORDER_REJECT_PATH, workOrderClaimResponseSchema, workOrderRejectResponseSchema, WORK_CRITERION_CLAIM_PATH, WORK_CRITERION_ID_PATTERN, WORK_HEAD_SHA_PATTERN, WORK_CRITERION_CLAIM_TEXT_MAX, workCriterionClaimResponseSchema, WORK_ORDER_ENV, WORK_ORDER_ATTR, steeringForceSchema, steeringItemKindSchema, steeringCutReasonSchema, steeringManifestItemSchema, STEERING_MANIFEST_SCHEMA, steeringManifestSchema, steeringManifestFrameSchema, cedarIdSchema, cedarPrincipalSchema, cedarToolSchema, cedarBundleSchema, BUNDLE_SKILLS_MAX, BUNDLE_SKILL_FILES_MAX, BUNDLE_SKILLS_CHARS_MAX, BASE64_PATTERN, bundleSkillFileSchema, bundleSkillSchema, policyBundleSchema, enrollmentClaimsSchema, tachoEventWireSchema, daemonHealthSchema, TACHO_MAX_BATCH, TACHO_MAX_BODY_BYTES, TACHO_MAX_REQUEST_BYTES, TACHO_REQUEST_ENVELOPE_BYTES, tachoBodySchema, tachoBatchSchema, agentDaySpendSchema, controlEnvelopeSchema, ingestResponseSchema, bundleResponseSchema, commandAcknowledgementSchema, commandsResponseSchema, enrollmentResponseSchema, tokenEnrollmentResponseSchema;
|
|
5660
5660
|
var init_wire = __esm({
|
|
5661
5661
|
"../../packages/tacho/src/wire.ts"() {
|
|
5662
5662
|
"use strict";
|
|
@@ -5709,6 +5709,7 @@ var init_wire = __esm({
|
|
|
5709
5709
|
BUNDLE_FEATURE_CACHE_KEEP_ALIVE = "cache_keep_alive";
|
|
5710
5710
|
BUNDLE_FEATURE_WORK_ORDERS = "work_orders";
|
|
5711
5711
|
BUNDLE_FEATURE_WORK_ORDER_START = "work_order_start";
|
|
5712
|
+
BUNDLE_FEATURE_MCP_RULE_SETS = "mcp_rule_sets";
|
|
5712
5713
|
BUNDLE_FEATURE_GATEWAY_POLICY = "gateway_policy";
|
|
5713
5714
|
GATEWAY_MIN_TIERS = ["harness", "gateway", "contained"];
|
|
5714
5715
|
SENSITIVE_SCREEN_ACTIONS = ["flag", "strip", "reject"];
|
|
@@ -5755,6 +5756,7 @@ var init_wire = __esm({
|
|
|
5755
5756
|
BUNDLE_FEATURE_WORK_ORDERS,
|
|
5756
5757
|
BUNDLE_FEATURE_WORK_ORDER_START,
|
|
5757
5758
|
BUNDLE_FEATURE_STEERING_INCOMPLETE,
|
|
5759
|
+
BUNDLE_FEATURE_MCP_RULE_SETS,
|
|
5758
5760
|
BUNDLE_FEATURE_GATEWAY_POLICY
|
|
5759
5761
|
];
|
|
5760
5762
|
bundleFeaturesSchema = external_exports.array(external_exports.string().max(64)).max(32);
|
|
@@ -6072,6 +6074,25 @@ var init_wire = __esm({
|
|
|
6072
6074
|
deny: external_exports.array(external_exports.string().max(512)).max(1024),
|
|
6073
6075
|
ask: external_exports.array(external_exports.string().max(512)).max(1024)
|
|
6074
6076
|
}).strict(),
|
|
6077
|
+
/**
|
|
6078
|
+
* The agent's MCP tool rules as the app holds them (#5398): one list per
|
|
6079
|
+
* rule set, each rule in its set's order. The host takes the first rule
|
|
6080
|
+
* that matches in each set and the most restrictive answer across the
|
|
6081
|
+
* sets (deny, then ask, then allow), and a set with no matching rule says
|
|
6082
|
+
* nothing. These rules are not also in `permissions`, whose fixed
|
|
6083
|
+
* deny-before-allow order would undo theirs.
|
|
6084
|
+
*
|
|
6085
|
+
* Emitted only to a host that advertised `BUNDLE_FEATURE_MCP_RULE_SETS`.
|
|
6086
|
+
* When it is absent, the same rules are sorted into `permissions`.
|
|
6087
|
+
*/
|
|
6088
|
+
mcp_rule_sets: external_exports.array(
|
|
6089
|
+
external_exports.array(
|
|
6090
|
+
external_exports.object({
|
|
6091
|
+
rule: external_exports.string().max(512),
|
|
6092
|
+
effect: external_exports.enum(["allow", "deny", "ask"])
|
|
6093
|
+
}).strict()
|
|
6094
|
+
).max(1024)
|
|
6095
|
+
).max(256).optional(),
|
|
6075
6096
|
tools: external_exports.record(
|
|
6076
6097
|
external_exports.string().max(256),
|
|
6077
6098
|
external_exports.object({
|
|
@@ -8121,12 +8142,12 @@ function cacheKeepAliveFinding(bundle2) {
|
|
|
8121
8142
|
}
|
|
8122
8143
|
function parseRule(raw) {
|
|
8123
8144
|
const rule = raw.trim();
|
|
8124
|
-
const
|
|
8125
|
-
if (
|
|
8145
|
+
const open7 = rule.indexOf("(");
|
|
8146
|
+
if (open7 === -1 || !rule.endsWith(")")) return { raw, tool: rule };
|
|
8126
8147
|
return {
|
|
8127
8148
|
raw,
|
|
8128
|
-
tool: rule.slice(0,
|
|
8129
|
-
spec: rule.slice(
|
|
8149
|
+
tool: rule.slice(0, open7).trim(),
|
|
8150
|
+
spec: rule.slice(open7 + 1, -1)
|
|
8130
8151
|
};
|
|
8131
8152
|
}
|
|
8132
8153
|
function escapeRegex(value) {
|
|
@@ -8427,6 +8448,29 @@ function firstMatch(rules, call2, context, effect) {
|
|
|
8427
8448
|
}
|
|
8428
8449
|
return void 0;
|
|
8429
8450
|
}
|
|
8451
|
+
function parsedSet(set) {
|
|
8452
|
+
const cached3 = parsedSetCache.get(set);
|
|
8453
|
+
if (cached3 !== void 0 && cached3.length === set.length && cached3.every((rule, index) => rule.raw === set[index]?.rule))
|
|
8454
|
+
return cached3;
|
|
8455
|
+
const parsed2 = set.map((entry2) => parseRule(entry2.rule));
|
|
8456
|
+
parsedSetCache.set(set, parsed2);
|
|
8457
|
+
return parsed2;
|
|
8458
|
+
}
|
|
8459
|
+
function ruleSetsMatch(sets, call2, context) {
|
|
8460
|
+
if (sets === void 0) return void 0;
|
|
8461
|
+
let result2;
|
|
8462
|
+
for (const set of sets) {
|
|
8463
|
+
const parsed2 = parsedSet(set);
|
|
8464
|
+
for (const [index, rule] of parsed2.entries()) {
|
|
8465
|
+
const effect = set[index].effect;
|
|
8466
|
+
if (!callMatches(rule, call2, context ?? {}, effect)) continue;
|
|
8467
|
+
if (result2 === void 0 || EFFECT_RANK[effect] > EFFECT_RANK[result2.effect])
|
|
8468
|
+
result2 = { effect, rule: rule.raw };
|
|
8469
|
+
break;
|
|
8470
|
+
}
|
|
8471
|
+
}
|
|
8472
|
+
return result2;
|
|
8473
|
+
}
|
|
8430
8474
|
function allowMatch(rules, call2, context) {
|
|
8431
8475
|
const single = firstMatch(rules, call2, context, "allow");
|
|
8432
8476
|
if (single !== void 0) return [single];
|
|
@@ -8559,12 +8603,8 @@ function evaluatePreToolUse(input) {
|
|
|
8559
8603
|
};
|
|
8560
8604
|
}
|
|
8561
8605
|
const call2 = toolCallOf(toolName3, toolInput);
|
|
8562
|
-
const
|
|
8563
|
-
|
|
8564
|
-
call2,
|
|
8565
|
-
input.context,
|
|
8566
|
-
"deny"
|
|
8567
|
-
);
|
|
8606
|
+
const ordered = ruleSetsMatch(bundle2.mcp_rule_sets, call2, input.context);
|
|
8607
|
+
const denied = firstMatch(bundle2.permissions.deny, call2, input.context, "deny") ?? (ordered?.effect === "deny" ? ordered.rule : void 0);
|
|
8568
8608
|
if (denied !== void 0) {
|
|
8569
8609
|
return {
|
|
8570
8610
|
decision: bundle2.mode === "observe" ? "allow" : "deny",
|
|
@@ -8588,7 +8628,7 @@ function evaluatePreToolUse(input) {
|
|
|
8588
8628
|
stale
|
|
8589
8629
|
};
|
|
8590
8630
|
}
|
|
8591
|
-
const ask = firstMatch(bundle2.permissions.ask, call2, input.context, "ask");
|
|
8631
|
+
const ask = firstMatch(bundle2.permissions.ask, call2, input.context, "ask") ?? (ordered?.effect === "ask" ? ordered.rule : void 0);
|
|
8592
8632
|
if (ask !== void 0) {
|
|
8593
8633
|
return {
|
|
8594
8634
|
decision: bundle2.mode === "observe" ? "allow" : "ask",
|
|
@@ -8603,7 +8643,7 @@ function evaluatePreToolUse(input) {
|
|
|
8603
8643
|
stale
|
|
8604
8644
|
};
|
|
8605
8645
|
}
|
|
8606
|
-
const allowed = allowMatch(bundle2.permissions.allow, call2, input.context);
|
|
8646
|
+
const allowed = allowMatch(bundle2.permissions.allow, call2, input.context) ?? (ordered?.effect === "allow" ? [ordered.rule] : void 0);
|
|
8607
8647
|
if (allowed !== void 0) {
|
|
8608
8648
|
const rule = allowed.join(" and ");
|
|
8609
8649
|
return {
|
|
@@ -8753,7 +8793,7 @@ function decideWithCedar(input) {
|
|
|
8753
8793
|
};
|
|
8754
8794
|
}
|
|
8755
8795
|
}
|
|
8756
|
-
var SHELL_OPERATORS, SHELL_LEADING_WORDS, WINDOWS_PATH, SHELL_TOOLS2, DECLARATION_SYNONYMS, GLOB_CACHE_LIMIT, globCache, parsedRuleCache, WRITE_EFFECTS;
|
|
8796
|
+
var SHELL_OPERATORS, SHELL_LEADING_WORDS, WINDOWS_PATH, SHELL_TOOLS2, DECLARATION_SYNONYMS, GLOB_CACHE_LIMIT, globCache, parsedRuleCache, EFFECT_RANK, parsedSetCache, WRITE_EFFECTS;
|
|
8757
8797
|
var init_bundle = __esm({
|
|
8758
8798
|
"../../packages/tacho/src/host/bundle.ts"() {
|
|
8759
8799
|
"use strict";
|
|
@@ -8795,6 +8835,8 @@ var init_bundle = __esm({
|
|
|
8795
8835
|
GLOB_CACHE_LIMIT = 1024;
|
|
8796
8836
|
globCache = /* @__PURE__ */ new Map();
|
|
8797
8837
|
parsedRuleCache = /* @__PURE__ */ new WeakMap();
|
|
8838
|
+
EFFECT_RANK = { allow: 0, ask: 1, deny: 2 };
|
|
8839
|
+
parsedSetCache = /* @__PURE__ */ new WeakMap();
|
|
8798
8840
|
WRITE_EFFECTS = /* @__PURE__ */ new Set([
|
|
8799
8841
|
"file_write",
|
|
8800
8842
|
"file_edit",
|
|
@@ -8853,6 +8895,13 @@ function withRecordedHarnessFiles(paths, host) {
|
|
|
8853
8895
|
claudeDesktopConfig: record.claude_desktop_config !== void 0 ? record.claude_desktop_config ?? void 0 : paths.claudeDesktopConfig
|
|
8854
8896
|
};
|
|
8855
8897
|
}
|
|
8898
|
+
function recordedHarnessHomes(host) {
|
|
8899
|
+
const record = host?.harness_files;
|
|
8900
|
+
return {
|
|
8901
|
+
...record?.claude_settings !== void 0 ? { claudeConfigDir: dirname2(record.claude_settings) } : {},
|
|
8902
|
+
...record?.codex_hooks !== void 0 ? { codexHome: dirname2(record.codex_hooks) } : {}
|
|
8903
|
+
};
|
|
8904
|
+
}
|
|
8856
8905
|
function mcpEndpointOverrideRequestFrom(env) {
|
|
8857
8906
|
const raw = env["TACHO_MCP_ENDPOINT"];
|
|
8858
8907
|
if (typeof raw !== "string" || raw.length === 0)
|
|
@@ -10917,12 +10966,12 @@ function procStartTicks(stat7) {
|
|
|
10917
10966
|
return ticks !== void 0 && /^\d+$/.test(ticks) ? ticks : void 0;
|
|
10918
10967
|
}
|
|
10919
10968
|
function procParent(stat7) {
|
|
10920
|
-
const
|
|
10969
|
+
const open7 = stat7.indexOf("(");
|
|
10921
10970
|
const close = stat7.lastIndexOf(")");
|
|
10922
|
-
if (
|
|
10971
|
+
if (open7 < 0 || close < open7) return void 0;
|
|
10923
10972
|
const ppid = stat7.slice(close + 1).trim().split(/\s+/)[1];
|
|
10924
10973
|
if (ppid === void 0 || !/^\d+$/.test(ppid)) return void 0;
|
|
10925
|
-
return { ppid: Number(ppid), comm: stat7.slice(
|
|
10974
|
+
return { ppid: Number(ppid), comm: stat7.slice(open7 + 1, close) };
|
|
10926
10975
|
}
|
|
10927
10976
|
function readProcParent(pid, read2 = readText) {
|
|
10928
10977
|
const stat7 = read2(`/proc/${pid}/stat`);
|
|
@@ -23229,7 +23278,7 @@ function openCredentialStore(paths) {
|
|
|
23229
23278
|
entriesSeen = { version: version2, entries: parsed2.data.entries };
|
|
23230
23279
|
return parsed2.data.entries;
|
|
23231
23280
|
}
|
|
23232
|
-
function
|
|
23281
|
+
function writeAll3(entries2) {
|
|
23233
23282
|
if (entries2.length === 0) {
|
|
23234
23283
|
if (existsSync5(paths.file)) unlinkSync4(paths.file);
|
|
23235
23284
|
return;
|
|
@@ -23273,7 +23322,7 @@ function openCredentialStore(paths) {
|
|
|
23273
23322
|
prefix: kind === "chatgpt" ? "login" : credentialPrefix(secret),
|
|
23274
23323
|
sealed: seal(keyForWrite(), secret, sealingContext(provider, owner))
|
|
23275
23324
|
};
|
|
23276
|
-
|
|
23325
|
+
writeAll3([
|
|
23277
23326
|
...readAll().filter((e) => !matches(e, provider, owner)),
|
|
23278
23327
|
entry2
|
|
23279
23328
|
]);
|
|
@@ -23289,7 +23338,7 @@ function openCredentialStore(paths) {
|
|
|
23289
23338
|
entry2.sealed,
|
|
23290
23339
|
sealingContext(provider, owner)
|
|
23291
23340
|
);
|
|
23292
|
-
|
|
23341
|
+
writeAll3(entries2.filter((e) => !matches(e, provider, owner)));
|
|
23293
23342
|
return { kind: entry2.kind, secret };
|
|
23294
23343
|
},
|
|
23295
23344
|
status: () => readAll().map(custodyOf),
|
|
@@ -26623,7 +26672,7 @@ import { readFileSync as readFileSync10 } from "node:fs";
|
|
|
26623
26672
|
import { dirname as dirname9, resolve as resolve3 } from "node:path";
|
|
26624
26673
|
import { fileURLToPath } from "node:url";
|
|
26625
26674
|
function readVersion() {
|
|
26626
|
-
if (true) return "2.1.5-
|
|
26675
|
+
if (true) return "2.1.5-69";
|
|
26627
26676
|
try {
|
|
26628
26677
|
const here = dirname9(fileURLToPath(import.meta.url));
|
|
26629
26678
|
const pkg = JSON.parse(
|
|
@@ -28194,13 +28243,15 @@ function* readLinesFrom(path2, from = 0, chunkBytes = SCAN_CHUNK_BYTES) {
|
|
|
28194
28243
|
closeSync5(fd2);
|
|
28195
28244
|
}
|
|
28196
28245
|
}
|
|
28197
|
-
async function* readLinesFromAsync(path2, from = 0) {
|
|
28246
|
+
async function* readLinesFromAsync(path2, from = 0, to = Number.POSITIVE_INFINITY) {
|
|
28198
28247
|
const handle = await open2(path2, "r");
|
|
28199
28248
|
try {
|
|
28200
28249
|
const splitter = new LineSplitter(from);
|
|
28201
28250
|
let position = from;
|
|
28202
|
-
|
|
28203
|
-
const chunk2 = Buffer.allocUnsafe(
|
|
28251
|
+
while (position < to) {
|
|
28252
|
+
const chunk2 = Buffer.allocUnsafe(
|
|
28253
|
+
Math.min(SCAN_CHUNK_BYTES, to - position)
|
|
28254
|
+
);
|
|
28204
28255
|
const { bytesRead } = await handle.read(chunk2, 0, chunk2.length, position);
|
|
28205
28256
|
if (bytesRead <= 0) break;
|
|
28206
28257
|
position += bytesRead;
|
|
@@ -28542,6 +28593,7 @@ import {
|
|
|
28542
28593
|
writeSync as writeSync4
|
|
28543
28594
|
} from "node:fs";
|
|
28544
28595
|
import { randomUUID } from "node:crypto";
|
|
28596
|
+
import { open as open3 } from "node:fs/promises";
|
|
28545
28597
|
import { join as join18 } from "node:path";
|
|
28546
28598
|
function activityAt(event) {
|
|
28547
28599
|
const at2 = Date.parse(event.ts);
|
|
@@ -28576,7 +28628,66 @@ function isResumeMark(value) {
|
|
|
28576
28628
|
function sizeOf(path2) {
|
|
28577
28629
|
return statSync6(path2, { throwIfNoEntry: false })?.size ?? 0;
|
|
28578
28630
|
}
|
|
28579
|
-
|
|
28631
|
+
function statIfExists2(path2) {
|
|
28632
|
+
return statSync6(path2, { throwIfNoEntry: false });
|
|
28633
|
+
}
|
|
28634
|
+
async function writeAll2(out, bytes) {
|
|
28635
|
+
let written2 = 0;
|
|
28636
|
+
while (written2 < bytes.length) {
|
|
28637
|
+
const { bytesWritten } = await out.write(
|
|
28638
|
+
bytes,
|
|
28639
|
+
written2,
|
|
28640
|
+
bytes.length - written2
|
|
28641
|
+
);
|
|
28642
|
+
written2 += bytesWritten;
|
|
28643
|
+
}
|
|
28644
|
+
}
|
|
28645
|
+
async function copyRange(path2, out, from, to, signal) {
|
|
28646
|
+
if (to <= from) return;
|
|
28647
|
+
const source = await open3(path2, "r");
|
|
28648
|
+
try {
|
|
28649
|
+
const buffer = Buffer.allocUnsafe(
|
|
28650
|
+
Math.min(BODY_PURGE_SLICE_BYTES, to - from)
|
|
28651
|
+
);
|
|
28652
|
+
for (let at2 = from; at2 < to; ) {
|
|
28653
|
+
signal?.throwIfAborted();
|
|
28654
|
+
const { bytesRead } = await source.read(
|
|
28655
|
+
buffer,
|
|
28656
|
+
0,
|
|
28657
|
+
Math.min(buffer.length, to - at2),
|
|
28658
|
+
at2
|
|
28659
|
+
);
|
|
28660
|
+
if (bytesRead <= 0) return;
|
|
28661
|
+
await writeAll2(out, buffer.subarray(0, bytesRead));
|
|
28662
|
+
at2 += bytesRead;
|
|
28663
|
+
}
|
|
28664
|
+
} finally {
|
|
28665
|
+
await source.close();
|
|
28666
|
+
}
|
|
28667
|
+
}
|
|
28668
|
+
function readRangeSync(path2, from, to) {
|
|
28669
|
+
const buffer = Buffer.alloc(Math.max(0, to - from));
|
|
28670
|
+
if (buffer.length === 0) return buffer;
|
|
28671
|
+
const fd2 = openSync6(path2, "r");
|
|
28672
|
+
try {
|
|
28673
|
+
let filled = 0;
|
|
28674
|
+
while (filled < buffer.length) {
|
|
28675
|
+
const read2 = readSync3(
|
|
28676
|
+
fd2,
|
|
28677
|
+
buffer,
|
|
28678
|
+
filled,
|
|
28679
|
+
buffer.length - filled,
|
|
28680
|
+
from + filled
|
|
28681
|
+
);
|
|
28682
|
+
if (read2 <= 0) break;
|
|
28683
|
+
filled += read2;
|
|
28684
|
+
}
|
|
28685
|
+
return buffer.subarray(0, filled);
|
|
28686
|
+
} finally {
|
|
28687
|
+
closeSync6(fd2);
|
|
28688
|
+
}
|
|
28689
|
+
}
|
|
28690
|
+
var BODY_READ_SLICE, BODY_DROP_SLICE_BYTES, BODY_DROP_SCANS, BODY_PURGE_SLICE_BYTES, BODY_PURGE_SCANS, BODY_PURGE_CATCH_UPS, NEWLINE, EVENT_TAIL_WINDOW, WalRecoveryConflict, Wal;
|
|
28580
28691
|
var init_wal = __esm({
|
|
28581
28692
|
"../../packages/tacho/src/host/wal.ts"() {
|
|
28582
28693
|
"use strict";
|
|
@@ -28586,6 +28697,9 @@ var init_wal = __esm({
|
|
|
28586
28697
|
BODY_READ_SLICE = 32;
|
|
28587
28698
|
BODY_DROP_SLICE_BYTES = 1024 * 1024;
|
|
28588
28699
|
BODY_DROP_SCANS = 3;
|
|
28700
|
+
BODY_PURGE_SLICE_BYTES = 1024 * 1024;
|
|
28701
|
+
BODY_PURGE_SCANS = 3;
|
|
28702
|
+
BODY_PURGE_CATCH_UPS = 3;
|
|
28589
28703
|
NEWLINE = 10;
|
|
28590
28704
|
EVENT_TAIL_WINDOW = 16 * 1024;
|
|
28591
28705
|
WalRecoveryConflict = class extends Error {
|
|
@@ -28685,6 +28799,18 @@ var init_wal = __esm({
|
|
|
28685
28799
|
* WAL has ever opened. See `flush` for why this exists.
|
|
28686
28800
|
*/
|
|
28687
28801
|
dirtyPaths = /* @__PURE__ */ new Set();
|
|
28802
|
+
/**
|
|
28803
|
+
* The awaited body sweeps running now, one entry per session scan
|
|
28804
|
+
* (`purgeBodiesOutsideMandateAsync`). Every write to a body file other than
|
|
28805
|
+
* an append marks the entries for its session, so a scan whose bytes moved
|
|
28806
|
+
* under it does not rename its copy over the file.
|
|
28807
|
+
*/
|
|
28808
|
+
bodyWatches = /* @__PURE__ */ new Set();
|
|
28809
|
+
/**
|
|
28810
|
+
* The temporary files those sweeps are writing. `compact` removes a
|
|
28811
|
+
* temporary file a crashed rewrite left, and must not remove one of these.
|
|
28812
|
+
*/
|
|
28813
|
+
liveTemps = /* @__PURE__ */ new Set();
|
|
28688
28814
|
fileFor(sessionUuid2) {
|
|
28689
28815
|
return join18(this.dir, `${sessionUuid2}.ndjson`);
|
|
28690
28816
|
}
|
|
@@ -29407,6 +29533,7 @@ ${lines.join("\n")}
|
|
|
29407
29533
|
if (next > 0) await new Promise((resolve26) => setImmediate(resolve26));
|
|
29408
29534
|
const slice = this.blankSlice(path2, found, next, idems);
|
|
29409
29535
|
if (slice === void 0) break;
|
|
29536
|
+
if (slice.blanked > 0) this.bodyRewritten(session);
|
|
29410
29537
|
blanked += slice.blanked;
|
|
29411
29538
|
moved ||= slice.moved;
|
|
29412
29539
|
next = slice.next;
|
|
@@ -29663,6 +29790,7 @@ ${lines.join("\n")}
|
|
|
29663
29790
|
this.dirtyPaths.add(path2);
|
|
29664
29791
|
}
|
|
29665
29792
|
this.bodyIndexes.invalidate(sessionUuid2);
|
|
29793
|
+
this.bodyRewritten(sessionUuid2);
|
|
29666
29794
|
return cut;
|
|
29667
29795
|
}
|
|
29668
29796
|
/**
|
|
@@ -29989,27 +30117,241 @@ ${lines.join("\n")}
|
|
|
29989
30117
|
* that withholds a body from a shipment. See `purgeBodiesNarrowedOut` in
|
|
29990
30118
|
* the daemon, which calls this when a replacement bundle verifies and
|
|
29991
30119
|
* narrows the clause.
|
|
30120
|
+
*
|
|
30121
|
+
* This reads every event file and every body file on the synchronous path,
|
|
30122
|
+
* which ADR-231 rules out on the daemon's thread. The daemon calls
|
|
30123
|
+
* `purgeBodiesOutsideMandateAsync`. It calls this only when it cannot record
|
|
30124
|
+
* the purge it owes, the one case where the erase has to finish before the
|
|
30125
|
+
* narrowed bundle is cached.
|
|
29992
30126
|
*/
|
|
29993
30127
|
purgeBodiesOutsideMandate(retention) {
|
|
29994
30128
|
let purged = 0;
|
|
29995
|
-
const
|
|
29996
|
-
|
|
29997
|
-
|
|
29998
|
-
|
|
29999
|
-
|
|
30129
|
+
for (const session of this.sessionsToPurge())
|
|
30130
|
+
purged += this.purgeSessionSync(session, retention);
|
|
30131
|
+
return purged;
|
|
30132
|
+
}
|
|
30133
|
+
/**
|
|
30134
|
+
* The same sweep, without holding the daemon's thread (#5176, ADR-231).
|
|
30135
|
+
* Every read is awaited, and a turn of the event loop separates two
|
|
30136
|
+
* sessions, so a hook or a proxied model call waits for one read and not
|
|
30137
|
+
* for the sweep.
|
|
30138
|
+
*
|
|
30139
|
+
* Each session is rewritten the way `rewriteBodies` rewrites it: the lines
|
|
30140
|
+
* kept go to a temporary file, and a rename puts it over the body file. A
|
|
30141
|
+
* crash part way leaves the old file whole, and the caller's record of the
|
|
30142
|
+
* purge it owes runs the sweep again. Hooks append to the file while the
|
|
30143
|
+
* scan awaits its reads, and three rules keep those appends:
|
|
30144
|
+
*
|
|
30145
|
+
* - The scan measures the body file and the event file in one synchronous
|
|
30146
|
+
* stretch, and reads each only up to that size. `append` writes a body
|
|
30147
|
+
* and then its event in one synchronous stretch too, so every body the
|
|
30148
|
+
* scan reads has its event in the part of the event file the scan reads,
|
|
30149
|
+
* or is a crash orphan. A body appended later is never judged an orphan.
|
|
30150
|
+
* - Bytes appended after that moment go to the new file as they are. They
|
|
30151
|
+
* were recorded under the mandate in force when they were appended, and
|
|
30152
|
+
* the daemon caches the narrowed mandate before it starts this sweep.
|
|
30153
|
+
* - The rename happens in one synchronous stretch, after a last check. When
|
|
30154
|
+
* the file was replaced, cut short, or written other than by an append
|
|
30155
|
+
* while the scan read it (`dropBodiesAsync` blanks lines in place), the
|
|
30156
|
+
* copy is thrown away and the session is scanned again. After
|
|
30157
|
+
* `BODY_PURGE_SCANS` scans the session goes through the synchronous sweep.
|
|
30158
|
+
*
|
|
30159
|
+
* The copy is synced to disk with an awaited call before that stretch, so
|
|
30160
|
+
* the stretch copies and syncs only what was appended since, about
|
|
30161
|
+
* `BODY_PURGE_SLICE_BYTES` at most.
|
|
30162
|
+
*/
|
|
30163
|
+
async purgeBodiesOutsideMandateAsync(retention, options = {}) {
|
|
30164
|
+
const { signal } = options;
|
|
30165
|
+
let purged = 0;
|
|
30166
|
+
for (const session of this.sessionsToPurge()) {
|
|
30167
|
+
await new Promise((resolve26) => setImmediate(resolve26));
|
|
30168
|
+
signal?.throwIfAborted();
|
|
30169
|
+
await options.beforeSession?.(session);
|
|
30170
|
+
signal?.throwIfAborted();
|
|
30000
30171
|
if (!existsSync12(this.bodyFileFor(session))) continue;
|
|
30001
|
-
|
|
30002
|
-
|
|
30003
|
-
|
|
30004
|
-
|
|
30005
|
-
);
|
|
30006
|
-
purged += this.rewriteBodies(
|
|
30007
|
-
session,
|
|
30008
|
-
(stored) => this.keeps(stored, kindOf2, retention)
|
|
30009
|
-
);
|
|
30172
|
+
let swept = "moved";
|
|
30173
|
+
for (let scan = 0; scan < BODY_PURGE_SCANS && swept === "moved"; scan++)
|
|
30174
|
+
swept = await this.purgeSessionAsync(session, retention, signal);
|
|
30175
|
+
purged += swept === "moved" ? this.purgeSessionSync(session, retention) : swept;
|
|
30010
30176
|
}
|
|
30011
30177
|
return purged;
|
|
30012
30178
|
}
|
|
30179
|
+
/**
|
|
30180
|
+
* Every session that has an event file OR a body file. `sessions()` lists
|
|
30181
|
+
* `.ndjson` only, so a crash between `append`'s body write and its first
|
|
30182
|
+
* event write leaves a `<uuid>.bodies.jsonl` with no `.ndjson` beside it,
|
|
30183
|
+
* invisible to a sweep that walked `sessions()` and to `compact`, which
|
|
30184
|
+
* does. Those bytes would outlive every mechanism meant to remove them.
|
|
30185
|
+
*/
|
|
30186
|
+
sessionsToPurge() {
|
|
30187
|
+
return /* @__PURE__ */ new Set([...this.sessions(), ...this.sessionsWithBodies()]);
|
|
30188
|
+
}
|
|
30189
|
+
/** One session of `purgeBodiesOutsideMandate`, read and rewritten at once. */
|
|
30190
|
+
purgeSessionSync(session, retention) {
|
|
30191
|
+
if (!existsSync12(this.bodyFileFor(session))) return 0;
|
|
30192
|
+
const kindOf2 = new Map(
|
|
30193
|
+
this.read(session).map(
|
|
30194
|
+
(event) => [event.event_id_idem, event.kind]
|
|
30195
|
+
)
|
|
30196
|
+
);
|
|
30197
|
+
return this.rewriteBodies(
|
|
30198
|
+
session,
|
|
30199
|
+
(stored) => this.keeps(stored, kindOf2, retention)
|
|
30200
|
+
);
|
|
30201
|
+
}
|
|
30202
|
+
/**
|
|
30203
|
+
* One scan of `purgeBodiesOutsideMandateAsync` over one session. Answers
|
|
30204
|
+
* how many lines went, or `moved` when the file changed under the scan
|
|
30205
|
+
* other than by an append, in which case nothing was renamed.
|
|
30206
|
+
*/
|
|
30207
|
+
async purgeSessionAsync(session, retention, signal) {
|
|
30208
|
+
const path2 = this.bodyFileFor(session);
|
|
30209
|
+
const start = statIfExists2(path2);
|
|
30210
|
+
if (start === void 0) return 0;
|
|
30211
|
+
const eventEnd = statIfExists2(this.fileFor(session))?.size ?? 0;
|
|
30212
|
+
const watch2 = { session, moved: false };
|
|
30213
|
+
this.bodyWatches.add(watch2);
|
|
30214
|
+
const tmp = `${path2}.${randomUUID()}.tmp`;
|
|
30215
|
+
let out;
|
|
30216
|
+
try {
|
|
30217
|
+
const kindOf2 = await this.eventKindsUpTo(session, eventEnd, signal);
|
|
30218
|
+
let cut = 0;
|
|
30219
|
+
let kept = 0;
|
|
30220
|
+
let held = [];
|
|
30221
|
+
let heldBytes = 0;
|
|
30222
|
+
const writeHeld = async (to) => {
|
|
30223
|
+
if (heldBytes === 0) return;
|
|
30224
|
+
await writeAll2(to, Buffer.concat(held, heldBytes));
|
|
30225
|
+
held = [];
|
|
30226
|
+
heldBytes = 0;
|
|
30227
|
+
};
|
|
30228
|
+
for await (const line of readLinesFromAsync(path2, 0, start.size)) {
|
|
30229
|
+
signal?.throwIfAborted();
|
|
30230
|
+
if (line.text.trim().length === 0) continue;
|
|
30231
|
+
if (this.keeps(parseStoredBody(line.text), kindOf2, retention)) {
|
|
30232
|
+
kept += 1;
|
|
30233
|
+
if (out === void 0) continue;
|
|
30234
|
+
const bytes = Buffer.from(`${line.text}
|
|
30235
|
+
`);
|
|
30236
|
+
held.push(bytes);
|
|
30237
|
+
heldBytes += bytes.length;
|
|
30238
|
+
if (heldBytes >= BODY_PURGE_SLICE_BYTES) await writeHeld(out);
|
|
30239
|
+
continue;
|
|
30240
|
+
}
|
|
30241
|
+
cut += 1;
|
|
30242
|
+
if (out === void 0) {
|
|
30243
|
+
this.liveTemps.add(tmp);
|
|
30244
|
+
out = await open3(tmp, "wx", 384);
|
|
30245
|
+
await copyRange(path2, out, 0, line.offset, signal);
|
|
30246
|
+
}
|
|
30247
|
+
}
|
|
30248
|
+
if (out === void 0) return watch2.moved ? "moved" : 0;
|
|
30249
|
+
await writeHeld(out);
|
|
30250
|
+
let copied = start.size;
|
|
30251
|
+
for (let round = 0; round < BODY_PURGE_CATCH_UPS; round += 1) {
|
|
30252
|
+
const size = statIfExists2(path2)?.size;
|
|
30253
|
+
if (size === void 0 || size - copied <= BODY_PURGE_SLICE_BYTES)
|
|
30254
|
+
break;
|
|
30255
|
+
await copyRange(path2, out, copied, size, signal);
|
|
30256
|
+
copied = size;
|
|
30257
|
+
}
|
|
30258
|
+
await out.sync();
|
|
30259
|
+
await out.close();
|
|
30260
|
+
out = void 0;
|
|
30261
|
+
signal?.throwIfAborted();
|
|
30262
|
+
if (watch2.moved) return "moved";
|
|
30263
|
+
return this.commitPurge(session, tmp, {
|
|
30264
|
+
start,
|
|
30265
|
+
copied,
|
|
30266
|
+
keptAny: kept > 0 || copied > start.size,
|
|
30267
|
+
cut
|
|
30268
|
+
});
|
|
30269
|
+
} catch (error) {
|
|
30270
|
+
if (error.code === "ENOENT" && !existsSync12(path2))
|
|
30271
|
+
return 0;
|
|
30272
|
+
throw error;
|
|
30273
|
+
} finally {
|
|
30274
|
+
this.bodyWatches.delete(watch2);
|
|
30275
|
+
if (out !== void 0) await out.close().catch(() => void 0);
|
|
30276
|
+
if (existsSync12(tmp)) unlinkSync9(tmp);
|
|
30277
|
+
this.liveTemps.delete(tmp);
|
|
30278
|
+
}
|
|
30279
|
+
}
|
|
30280
|
+
/**
|
|
30281
|
+
* The kind of every event in the first `end` bytes of a session's event
|
|
30282
|
+
* file, by event id, read with awaited reads. A line that does not parse is
|
|
30283
|
+
* reported and skipped, as `read` does. A line cut off at `end` was torn by
|
|
30284
|
+
* a crash, since `append` ends every write with a newline, and is skipped.
|
|
30285
|
+
*/
|
|
30286
|
+
async eventKindsUpTo(session, end, signal) {
|
|
30287
|
+
const kindOf2 = /* @__PURE__ */ new Map();
|
|
30288
|
+
if (end === 0) return kindOf2;
|
|
30289
|
+
for await (const line of readLinesFromAsync(
|
|
30290
|
+
this.fileFor(session),
|
|
30291
|
+
0,
|
|
30292
|
+
end
|
|
30293
|
+
)) {
|
|
30294
|
+
signal?.throwIfAborted();
|
|
30295
|
+
if (!line.terminated || line.text.trim().length === 0) continue;
|
|
30296
|
+
try {
|
|
30297
|
+
const event = parseEventLine(line.text);
|
|
30298
|
+
kindOf2.set(event.event_id_idem, event.kind);
|
|
30299
|
+
} catch (error) {
|
|
30300
|
+
this.reportEventParseFailure({
|
|
30301
|
+
session_uuid: session,
|
|
30302
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
30303
|
+
});
|
|
30304
|
+
}
|
|
30305
|
+
}
|
|
30306
|
+
return kindOf2;
|
|
30307
|
+
}
|
|
30308
|
+
/**
|
|
30309
|
+
* The rename of `purgeSessionAsync`, in one synchronous stretch, so nothing
|
|
30310
|
+
* else can write the body file between the check and the rename. Copies
|
|
30311
|
+
* what was appended since `copied`, syncs it, and puts the copy over the
|
|
30312
|
+
* file, or removes the file when nothing in it is left.
|
|
30313
|
+
*/
|
|
30314
|
+
commitPurge(session, tmp, scan) {
|
|
30315
|
+
const path2 = this.bodyFileFor(session);
|
|
30316
|
+
const now = statIfExists2(path2);
|
|
30317
|
+
if (now === void 0) return 0;
|
|
30318
|
+
if (now.ino !== scan.start.ino || now.dev !== scan.start.dev || now.size < scan.copied)
|
|
30319
|
+
return "moved";
|
|
30320
|
+
const tail = readRangeSync(path2, scan.copied, now.size);
|
|
30321
|
+
if (!scan.keptAny && tail.toString("utf8").trim().length === 0) {
|
|
30322
|
+
unlinkSync9(path2);
|
|
30323
|
+
} else {
|
|
30324
|
+
const fd2 = openSync6(tmp, "r+");
|
|
30325
|
+
try {
|
|
30326
|
+
let written2 = 0;
|
|
30327
|
+
const at2 = fstatSync(fd2).size;
|
|
30328
|
+
while (written2 < tail.length)
|
|
30329
|
+
written2 += writeSync4(
|
|
30330
|
+
fd2,
|
|
30331
|
+
tail,
|
|
30332
|
+
written2,
|
|
30333
|
+
tail.length - written2,
|
|
30334
|
+
at2 + written2
|
|
30335
|
+
);
|
|
30336
|
+
fdatasyncSync(fd2);
|
|
30337
|
+
} finally {
|
|
30338
|
+
closeSync6(fd2);
|
|
30339
|
+
}
|
|
30340
|
+
renameSync3(tmp, path2);
|
|
30341
|
+
}
|
|
30342
|
+
this.bodyIndexes.invalidate(session);
|
|
30343
|
+
this.bodyRewritten(session);
|
|
30344
|
+
return scan.cut;
|
|
30345
|
+
}
|
|
30346
|
+
/**
|
|
30347
|
+
* Tell every awaited sweep of this session that its body file changed
|
|
30348
|
+
* other than by an append. Each write that cuts, blanks, or replaces body
|
|
30349
|
+
* bytes calls this in the same synchronous stretch as the write.
|
|
30350
|
+
*/
|
|
30351
|
+
bodyRewritten(session) {
|
|
30352
|
+
for (const watch2 of this.bodyWatches)
|
|
30353
|
+
if (watch2.session === session) watch2.moved = true;
|
|
30354
|
+
}
|
|
30013
30355
|
/**
|
|
30014
30356
|
* Whether one stored body survives this mandate. Three answers, each for a
|
|
30015
30357
|
* reason:
|
|
@@ -30027,7 +30369,9 @@ ${lines.join("\n")}
|
|
|
30027
30369
|
* the two writes and no event will ever arrive for it. Keeping it kept
|
|
30028
30370
|
* prompt or tool bytes that no mandate covers and that nothing would
|
|
30029
30371
|
* ever ship, delete or compact, because every one of those paths starts
|
|
30030
|
-
* from the event.
|
|
30372
|
+
* from the event. The awaited sweep does let appends land while it reads,
|
|
30373
|
+
* so it judges only the bodies written before it measured the files, and
|
|
30374
|
+
* their events are all in the part of the event file it reads.
|
|
30031
30375
|
* - Otherwise the class comes from the event's kind and the one retention
|
|
30032
30376
|
* gate answers. A kind the table does not name has no class, so no mandate
|
|
30033
30377
|
* can cover it and the body goes.
|
|
@@ -30089,6 +30433,7 @@ ${lines.join("\n")}
|
|
|
30089
30433
|
if (kept === 0) unlinkSync9(path2);
|
|
30090
30434
|
else renameSync3(tmp, path2);
|
|
30091
30435
|
this.bodyIndexes.invalidate(sessionUuid2);
|
|
30436
|
+
this.bodyRewritten(sessionUuid2);
|
|
30092
30437
|
return cut;
|
|
30093
30438
|
} finally {
|
|
30094
30439
|
if (existsSync12(tmp)) unlinkSync9(tmp);
|
|
@@ -30116,6 +30461,7 @@ ${lines.join("\n")}
|
|
|
30116
30461
|
`^${uuid}\\.bodies\\.jsonl\\.${uuid}\\.tmp$`
|
|
30117
30462
|
);
|
|
30118
30463
|
for (const name of readdirSync7(this.dir)) {
|
|
30464
|
+
if (this.liveTemps.has(join18(this.dir, name))) continue;
|
|
30119
30465
|
if (abandonedRewrite.test(name)) {
|
|
30120
30466
|
try {
|
|
30121
30467
|
unlinkSync9(join18(this.dir, name));
|
|
@@ -30199,6 +30545,7 @@ ${lines.join("\n")}
|
|
|
30199
30545
|
const path2 = this.bodyFileFor(session);
|
|
30200
30546
|
if (existsSync12(path2)) unlinkSync9(path2);
|
|
30201
30547
|
this.bodyIndexes.invalidate(session);
|
|
30548
|
+
this.bodyRewritten(session);
|
|
30202
30549
|
return true;
|
|
30203
30550
|
} catch (error) {
|
|
30204
30551
|
this.bodyFailure(session, "cleanup", error);
|
|
@@ -30551,8 +30898,12 @@ function daemonServiceSpec(daemonCommand, deps) {
|
|
|
30551
30898
|
command: daemonCommand,
|
|
30552
30899
|
env: {
|
|
30553
30900
|
...deps.env["TACHO_HOME"] !== void 0 ? { TACHO_HOME: deps.env["TACHO_HOME"] } : {},
|
|
30554
|
-
// The harness homes
|
|
30555
|
-
//
|
|
30901
|
+
// The harness homes this shell moved. Each collector reads its agent's
|
|
30902
|
+
// harness files where that agent's host.json recorded them at enroll
|
|
30903
|
+
// (`harness_files`), so these decide nothing for an agent with a
|
|
30904
|
+
// record. They stay for an agent enrolled before the record existed.
|
|
30905
|
+
// One service serves every agent, so they come from whichever shell
|
|
30906
|
+
// installed it last (#5409).
|
|
30556
30907
|
...Object.fromEntries(
|
|
30557
30908
|
HARNESS_HOME_VARS.flatMap((key) => {
|
|
30558
30909
|
const value = deps.env[key];
|
|
@@ -43081,7 +43432,11 @@ async function renewStaticToken(harness, deps) {
|
|
|
43081
43432
|
const label2 = TACHO_HARNESS_LABELS[harness];
|
|
43082
43433
|
if (deps.host.host_status !== "active" || !deps.inCustody(provider, harness))
|
|
43083
43434
|
return "skipped";
|
|
43084
|
-
const dirs =
|
|
43435
|
+
const dirs = {
|
|
43436
|
+
...deps.stellaHome !== void 0 ? { stellaHome: deps.stellaHome } : {},
|
|
43437
|
+
...deps.codexHome !== void 0 ? { codexHome: deps.codexHome } : {},
|
|
43438
|
+
...deps.claudeConfigDir !== void 0 ? { claudeConfigDir: deps.claudeConfigDir } : {}
|
|
43439
|
+
};
|
|
43085
43440
|
let brokered = false;
|
|
43086
43441
|
try {
|
|
43087
43442
|
brokered = (await readModelCredentialState({
|
|
@@ -44021,8 +44376,33 @@ var init_git_facts = __esm({
|
|
|
44021
44376
|
|
|
44022
44377
|
// ../../packages/tacho/src/collector/work-order-autostart.ts
|
|
44023
44378
|
import { spawn as spawn7 } from "node:child_process";
|
|
44024
|
-
import { closeSync as closeSync7, existsSync as existsSync21, openSync as openSync7 } from "node:fs";
|
|
44379
|
+
import { closeSync as closeSync7, existsSync as existsSync21, openSync as openSync7, readSync as readSync4, statSync as statSync12 } from "node:fs";
|
|
44025
44380
|
import { dirname as dirname20, join as join36 } from "node:path";
|
|
44381
|
+
function lastLogLine(path2) {
|
|
44382
|
+
let fd2;
|
|
44383
|
+
try {
|
|
44384
|
+
const size = statSync12(path2).size;
|
|
44385
|
+
const length = Math.min(size, 4096);
|
|
44386
|
+
const buffer = Buffer.alloc(length);
|
|
44387
|
+
fd2 = openSync7(path2, "r");
|
|
44388
|
+
readSync4(fd2, buffer, 0, length, size - length);
|
|
44389
|
+
const line = buffer.toString("utf8").replace(TERMINAL_CODE, "").split(/\r?\n/).map((text5) => text5.trim()).filter((text5) => text5.length > 0).pop();
|
|
44390
|
+
if (line === void 0) return void 0;
|
|
44391
|
+
return line.length > EXIT_REPORT_QUOTE ? `${line.slice(0, EXIT_REPORT_QUOTE - 1)}\u2026` : line;
|
|
44392
|
+
} catch {
|
|
44393
|
+
return void 0;
|
|
44394
|
+
} finally {
|
|
44395
|
+
if (fd2 !== void 0) {
|
|
44396
|
+
try {
|
|
44397
|
+
closeSync7(fd2);
|
|
44398
|
+
} catch {
|
|
44399
|
+
}
|
|
44400
|
+
}
|
|
44401
|
+
}
|
|
44402
|
+
}
|
|
44403
|
+
function exitPhrase(exit) {
|
|
44404
|
+
return exit.signal !== null ? `ended on ${exit.signal}` : `exited with code ${String(exit.code)}`;
|
|
44405
|
+
}
|
|
44026
44406
|
function asError(error) {
|
|
44027
44407
|
return error instanceof Error ? error : new Error(String(error));
|
|
44028
44408
|
}
|
|
@@ -44037,6 +44417,10 @@ function isPlainBranchName(name) {
|
|
|
44037
44417
|
function createWorkOrderAutostart(deps) {
|
|
44038
44418
|
const { paths, log } = deps;
|
|
44039
44419
|
const isAlive = deps.isAlive ?? processIsAlive;
|
|
44420
|
+
const wait = deps.wait ?? ((ms) => new Promise((done) => {
|
|
44421
|
+
setTimeout(done, ms).unref();
|
|
44422
|
+
}));
|
|
44423
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
44040
44424
|
const spawnHarness = deps.spawn ?? spawnDetached;
|
|
44041
44425
|
let searchPath;
|
|
44042
44426
|
const pathForHarness = () => {
|
|
@@ -44222,7 +44606,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
44222
44606
|
`work order ${id2}: could not clear its running mark: ${asError(error).message}`
|
|
44223
44607
|
);
|
|
44224
44608
|
}
|
|
44225
|
-
const ended = exit === void 0 ? "ended while the daemon was stopped" : "never" in exit ? `never started (${exit.never})` :
|
|
44609
|
+
const ended = exit === void 0 ? "ended while the daemon was stopped" : "never" in exit ? `never started (${exit.never})` : exitPhrase(exit);
|
|
44226
44610
|
const { worktree, root, branch, base_sha: base2 } = mark;
|
|
44227
44611
|
if (worktree === void 0 || !existsSync21(worktree)) {
|
|
44228
44612
|
log(`work order ${id2}: the harness ${ended}`);
|
|
@@ -44276,13 +44660,28 @@ function createWorkOrderAutostart(deps) {
|
|
|
44276
44660
|
`work order ${id2}: the harness ${ended} and left nothing that is not on a remote, so its worktree is removed${mark.log !== void 0 ? `. Its output is in ${mark.log}` : ""}.`
|
|
44277
44661
|
);
|
|
44278
44662
|
}
|
|
44279
|
-
function
|
|
44663
|
+
async function reportExit(id2, binary, exit, logPath) {
|
|
44664
|
+
if (sessions.has(id2)) return;
|
|
44665
|
+
await wait(EXIT_REPORT_GRACE_MS);
|
|
44666
|
+
if (sessions.has(id2)) return;
|
|
44667
|
+
const said = lastLogLine(logPath);
|
|
44668
|
+
const reason3 = `${binary} ${exitPhrase(exit)} before it opened a run.${said !== void 0 ? ` Its last output: ${said}` : ""} The full output is in ${logPath} on this machine.`;
|
|
44669
|
+
const failed3 = await refuseWorkOrder(deps.client, id2, reason3.slice(0, 512));
|
|
44670
|
+
log(
|
|
44671
|
+
failed3 === void 0 ? `work order ${id2}: ${reason3} Oxagen ended the send.` : `work order ${id2}: ${reason3} Oxagen kept the send (${failed3}).`
|
|
44672
|
+
);
|
|
44673
|
+
}
|
|
44674
|
+
function watch2(id2, binary, workspace, exited) {
|
|
44280
44675
|
void exited.then((exit) => {
|
|
44281
|
-
const done =
|
|
44676
|
+
const done = Promise.all([
|
|
44677
|
+
cleanUp({ work_order: id2, ...workspace }, exit),
|
|
44678
|
+
reportExit(id2, binary, exit, workspace.log)
|
|
44679
|
+
]).then(() => void 0).catch((error) => {
|
|
44282
44680
|
log(
|
|
44283
44681
|
`work order ${id2}: cleanup after the harness failed: ${asError(error).message}`
|
|
44284
44682
|
);
|
|
44285
44683
|
}).finally(() => {
|
|
44684
|
+
sessions.delete(id2);
|
|
44286
44685
|
cleanups.delete(done);
|
|
44287
44686
|
});
|
|
44288
44687
|
cleanups.add(done);
|
|
@@ -44292,8 +44691,8 @@ function createWorkOrderAutostart(deps) {
|
|
|
44292
44691
|
const id2 = order.work_order;
|
|
44293
44692
|
const running = runningWorkOrder(paths, id2, isAlive);
|
|
44294
44693
|
if (running !== void 0) return;
|
|
44295
|
-
const
|
|
44296
|
-
if (
|
|
44694
|
+
const wait2 = retry.get(id2);
|
|
44695
|
+
if (wait2 !== void 0 && deps.now() < wait2.at) return;
|
|
44297
44696
|
const outcome = await claimForStart(deps.client, deps.host(), id2);
|
|
44298
44697
|
if (outcome.kind === "refused" && outcome.final) {
|
|
44299
44698
|
log(
|
|
@@ -44389,7 +44788,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
44389
44788
|
log(
|
|
44390
44789
|
`work order ${id2} for ${claim.work_order.item_number} started ${binary} (process ${started.pid}) in ${workspace.worktree}; output goes to ${workspace.log}`
|
|
44391
44790
|
);
|
|
44392
|
-
watch2(id2, workspace, started.exited);
|
|
44791
|
+
watch2(id2, binary, workspace, started.exited);
|
|
44393
44792
|
}
|
|
44394
44793
|
async function runPass() {
|
|
44395
44794
|
let orders;
|
|
@@ -44438,6 +44837,9 @@ function createWorkOrderAutostart(deps) {
|
|
|
44438
44837
|
}
|
|
44439
44838
|
}
|
|
44440
44839
|
},
|
|
44840
|
+
noteSession: (workOrder) => {
|
|
44841
|
+
sessions.add(workOrder);
|
|
44842
|
+
},
|
|
44441
44843
|
idle: async () => {
|
|
44442
44844
|
while (pass2 !== void 0 || cleanups.size > 0) {
|
|
44443
44845
|
await Promise.allSettled([pass2, ...cleanups]);
|
|
@@ -44445,7 +44847,7 @@ function createWorkOrderAutostart(deps) {
|
|
|
44445
44847
|
}
|
|
44446
44848
|
};
|
|
44447
44849
|
}
|
|
44448
|
-
var SLOW_GIT_MS, RETRY_MIN_MS, RETRY_MAX_MS, spawnDetached;
|
|
44850
|
+
var SLOW_GIT_MS, RETRY_MIN_MS, RETRY_MAX_MS, EXIT_REPORT_GRACE_MS, TERMINAL_CODE, EXIT_REPORT_QUOTE, spawnDetached;
|
|
44449
44851
|
var init_work_order_autostart = __esm({
|
|
44450
44852
|
"../../packages/tacho/src/collector/work-order-autostart.ts"() {
|
|
44451
44853
|
"use strict";
|
|
@@ -44459,6 +44861,12 @@ var init_work_order_autostart = __esm({
|
|
|
44459
44861
|
SLOW_GIT_MS = 12e4;
|
|
44460
44862
|
RETRY_MIN_MS = 15e3;
|
|
44461
44863
|
RETRY_MAX_MS = 5 * 6e4;
|
|
44864
|
+
EXIT_REPORT_GRACE_MS = 6e4;
|
|
44865
|
+
TERMINAL_CODE = new RegExp(
|
|
44866
|
+
`${String.fromCharCode(27)}\\[[0-9;?]*[A-Za-z]`,
|
|
44867
|
+
"g"
|
|
44868
|
+
);
|
|
44869
|
+
EXIT_REPORT_QUOTE = 240;
|
|
44462
44870
|
spawnDetached = (command2, args, options) => new Promise((resolve26) => {
|
|
44463
44871
|
let fd2;
|
|
44464
44872
|
try {
|
|
@@ -44468,10 +44876,10 @@ var init_work_order_autostart = __esm({
|
|
|
44468
44876
|
resolve26({ ok: false, error: asError(error) });
|
|
44469
44877
|
return;
|
|
44470
44878
|
}
|
|
44471
|
-
let
|
|
44879
|
+
let open7 = true;
|
|
44472
44880
|
const close = () => {
|
|
44473
|
-
if (!
|
|
44474
|
-
|
|
44881
|
+
if (!open7) return;
|
|
44882
|
+
open7 = false;
|
|
44475
44883
|
try {
|
|
44476
44884
|
closeSync7(fd2);
|
|
44477
44885
|
} catch {
|
|
@@ -44559,7 +44967,7 @@ import { createReadStream } from "node:fs";
|
|
|
44559
44967
|
import {
|
|
44560
44968
|
lstat,
|
|
44561
44969
|
mkdir,
|
|
44562
|
-
open as
|
|
44970
|
+
open as open4,
|
|
44563
44971
|
readdir,
|
|
44564
44972
|
readlink,
|
|
44565
44973
|
rename,
|
|
@@ -44612,7 +45020,7 @@ async function contentHash(absolutePath, kind, keep) {
|
|
|
44612
45020
|
const temp2 = join37(keep.dir, `.partial-${randomUUID3()}`);
|
|
44613
45021
|
copy = {
|
|
44614
45022
|
temp: temp2,
|
|
44615
|
-
handle: await
|
|
45023
|
+
handle: await open4(temp2, "wx", keep.executable ? 448 : 384)
|
|
44616
45024
|
};
|
|
44617
45025
|
} catch {
|
|
44618
45026
|
copy = null;
|
|
@@ -46380,22 +46788,41 @@ var init_interjection = __esm({
|
|
|
46380
46788
|
function showsRefusedPrompt(harness) {
|
|
46381
46789
|
return harness !== "stella";
|
|
46382
46790
|
}
|
|
46791
|
+
function questionBoundary(harness) {
|
|
46792
|
+
return showsRefusedPrompt(harness) ? "UserPromptSubmit" : "SessionStart";
|
|
46793
|
+
}
|
|
46794
|
+
function holdToolCall(evaluation, record) {
|
|
46795
|
+
const held = record.control.interjection;
|
|
46796
|
+
if (held === void 0 || evaluation.decision === "deny") return evaluation;
|
|
46797
|
+
const refused2 = {
|
|
46798
|
+
...evaluation,
|
|
46799
|
+
decision: "deny",
|
|
46800
|
+
evaluated: "deny",
|
|
46801
|
+
source: "bundle",
|
|
46802
|
+
reason_code: INTERJECTION_OPEN,
|
|
46803
|
+
reason: held.question
|
|
46804
|
+
};
|
|
46805
|
+
delete refused2.rule;
|
|
46806
|
+
delete refused2.rules;
|
|
46807
|
+
return refused2;
|
|
46808
|
+
}
|
|
46383
46809
|
function isBound(clause, remote) {
|
|
46384
46810
|
const bound = new Set(clause.bound_remote_digests);
|
|
46385
46811
|
return bound.has(remote.remote_digest) || bound.has(remote.remote_digest_folded);
|
|
46386
46812
|
}
|
|
46387
|
-
function interjectionQuestion(clause) {
|
|
46813
|
+
function interjectionQuestion(clause, harness) {
|
|
46388
46814
|
const minutes = Math.max(1, Math.round(clause.timeout_ms / 6e4));
|
|
46389
46815
|
const slug = clause.workspace_slug;
|
|
46390
|
-
|
|
46816
|
+
const hold = showsRefusedPrompt(harness) ? `Oxagen is holding this session before its first model call. ` : `Oxagen is refusing this session's tool calls until a person answers. `;
|
|
46817
|
+
return hold + `It started in a repository that no workspace in your organization has bound, and skills are on for workspace ${slug}. Should Oxagen link this repository to ${slug}, or create a new workspace for it with skills off? A person with access answers on this run's page in Oxagen. With no answer in ${minutes} minutes, the session goes on without skills.`;
|
|
46391
46818
|
}
|
|
46392
46819
|
function proposedSlug(name) {
|
|
46393
46820
|
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+/, "").slice(0, SLUG_MAX).replace(/-+$/, "");
|
|
46394
46821
|
return slug.length >= SLUG_MIN && SLUG_PATTERN.test(slug) ? slug : null;
|
|
46395
46822
|
}
|
|
46396
|
-
function
|
|
46823
|
+
function prepareInterjection(record, clause, remote, now) {
|
|
46397
46824
|
const key = ulid(now);
|
|
46398
|
-
const question = interjectionQuestion(clause);
|
|
46825
|
+
const question = interjectionQuestion(clause, record.harness);
|
|
46399
46826
|
const expiresAt = toProtocolTimestamp(now + clause.timeout_ms);
|
|
46400
46827
|
const name = remote.name !== void 0 && remote.name.length <= NAME_MAX2 ? remote.name : null;
|
|
46401
46828
|
const unknown2 = repoUnknownBodySchema.safeParse({
|
|
@@ -46432,21 +46859,28 @@ function raiseInterjection(record, clause, remote, now, fields) {
|
|
|
46432
46859
|
]
|
|
46433
46860
|
});
|
|
46434
46861
|
if (!unknown2.success || !interject.success) return void 0;
|
|
46862
|
+
return {
|
|
46863
|
+
unknown: unknown2.data,
|
|
46864
|
+
interject: interject.data,
|
|
46865
|
+
held: {
|
|
46866
|
+
key,
|
|
46867
|
+
question,
|
|
46868
|
+
expiresAt,
|
|
46869
|
+
workspaceSlug: clause.workspace_slug,
|
|
46870
|
+
configVersion: clause.config_version
|
|
46871
|
+
}
|
|
46872
|
+
};
|
|
46873
|
+
}
|
|
46874
|
+
function sealInterjection(record, pending, fields) {
|
|
46435
46875
|
const events = [
|
|
46436
|
-
record.recorder.sealCollectorEvent("repo.unknown",
|
|
46876
|
+
record.recorder.sealCollectorEvent("repo.unknown", pending.unknown, fields),
|
|
46437
46877
|
record.recorder.sealCollectorEvent(
|
|
46438
46878
|
"control.interject",
|
|
46439
|
-
interject
|
|
46879
|
+
pending.interject,
|
|
46440
46880
|
fields
|
|
46441
46881
|
)
|
|
46442
46882
|
];
|
|
46443
|
-
record.control.interjection = {
|
|
46444
|
-
key,
|
|
46445
|
-
question,
|
|
46446
|
-
expiresAt,
|
|
46447
|
-
workspaceSlug: clause.workspace_slug,
|
|
46448
|
-
configVersion: clause.config_version
|
|
46449
|
-
};
|
|
46883
|
+
record.control.interjection = { ...pending.held };
|
|
46450
46884
|
return events;
|
|
46451
46885
|
}
|
|
46452
46886
|
function expireInterjection(record, now, fields) {
|
|
@@ -46533,7 +46967,7 @@ function settle(record, held, answer, payload, fields) {
|
|
|
46533
46967
|
record.control.interjection = void 0;
|
|
46534
46968
|
return events;
|
|
46535
46969
|
}
|
|
46536
|
-
var SLUG_PATTERN, SLUG_MIN, SLUG_MAX, NAME_MAX2, INTERJECTION_TIMED_OUT_TEXT;
|
|
46970
|
+
var SLUG_PATTERN, SLUG_MIN, SLUG_MAX, NAME_MAX2, INTERJECTION_OPEN, INTERJECTION_TIMED_OUT_TEXT;
|
|
46537
46971
|
var init_interjection2 = __esm({
|
|
46538
46972
|
"../../packages/tacho/src/collector/interjection.ts"() {
|
|
46539
46973
|
"use strict";
|
|
@@ -46544,6 +46978,7 @@ var init_interjection2 = __esm({
|
|
|
46544
46978
|
SLUG_MIN = 2;
|
|
46545
46979
|
SLUG_MAX = 40;
|
|
46546
46980
|
NAME_MAX2 = 120;
|
|
46981
|
+
INTERJECTION_OPEN = "interjection_open";
|
|
46547
46982
|
INTERJECTION_TIMED_OUT_TEXT = "Oxagen asked a person whether to bind this repository to a workspace, and nobody answered in time. This session goes on without skills.";
|
|
46548
46983
|
}
|
|
46549
46984
|
});
|
|
@@ -46809,21 +47244,23 @@ function promptBlock(view, record) {
|
|
|
46809
47244
|
const block = operatorBlock(view, record);
|
|
46810
47245
|
if (block !== void 0) return block;
|
|
46811
47246
|
const held = record.control.interjection;
|
|
46812
|
-
if (held === void 0
|
|
46813
|
-
|
|
47247
|
+
if (held === void 0 || !showsRefusedPrompt(record.harness))
|
|
47248
|
+
return void 0;
|
|
47249
|
+
return { code: INTERJECTION_OPEN, reason: held.question, source: "bundle" };
|
|
46814
47250
|
}
|
|
46815
|
-
async function
|
|
46816
|
-
if (record.control.repoChecked === true)
|
|
47251
|
+
async function repositoryQuestion(record, view, deps, replay, boundary) {
|
|
47252
|
+
if (record.control.repoChecked === true || questionBoundary(record.harness) !== boundary)
|
|
47253
|
+
return void 0;
|
|
46817
47254
|
record.control.repoChecked = true;
|
|
46818
47255
|
const clause = view.verified ? view.bundle.unbound_repo : void 0;
|
|
46819
|
-
if (clause === void 0 || replay !== void 0 ||
|
|
46820
|
-
return
|
|
47256
|
+
if (clause === void 0 || replay !== void 0 || record.recorder.hasModelCall || record.cwd === void 0 || deps.repositoryRemote === void 0)
|
|
47257
|
+
return void 0;
|
|
46821
47258
|
const remote = await readRepository(
|
|
46822
47259
|
recallView(record),
|
|
46823
47260
|
deps.repositoryRemote
|
|
46824
47261
|
);
|
|
46825
|
-
if (remote === void 0 || isBound(clause, remote)) return
|
|
46826
|
-
return
|
|
47262
|
+
if (remote === void 0 || isBound(clause, remote)) return void 0;
|
|
47263
|
+
return prepareInterjection(record, clause, remote, deps.now());
|
|
46827
47264
|
}
|
|
46828
47265
|
function invocationToolUseId(raw, input, record) {
|
|
46829
47266
|
const derived = input.tool_use_id;
|
|
@@ -47274,12 +47711,19 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
47274
47711
|
switch (input.hook_event_name) {
|
|
47275
47712
|
case "SessionStart": {
|
|
47276
47713
|
const block = operatorBlock(view, record);
|
|
47714
|
+
const question = input.agent_id === void 0 ? await repositoryQuestion(record, view, deps, replay, "SessionStart") : void 0;
|
|
47715
|
+
const questionText = question?.held.question;
|
|
47277
47716
|
const steering = block === void 0 && replay === void 0 ? await runSteeringBundle(record, deps) ?? view.bundle : view.bundle;
|
|
47278
47717
|
const context = steering.context.system;
|
|
47279
47718
|
if (block === void 0 && replay === void 0)
|
|
47280
47719
|
await placeSessionSkills(view, record, deps, env);
|
|
47281
|
-
const messages = block === void 0 && replay === void 0 && input.agent_id === void 0 ? drainMessages(
|
|
47282
|
-
|
|
47720
|
+
const messages = block === void 0 && replay === void 0 && input.agent_id === void 0 ? drainMessages(
|
|
47721
|
+
record,
|
|
47722
|
+
deps,
|
|
47723
|
+
events,
|
|
47724
|
+
(context?.length ?? 0) + (questionText?.length ?? 0)
|
|
47725
|
+
) : [];
|
|
47726
|
+
const additional = block === void 0 ? [questionText ?? "", context ?? "", ...messages.map((m) => m.text)].filter((s2) => s2.length > 0).join(CONTEXT_JOINER) : "";
|
|
47283
47727
|
const delivered = replay === void 0 ? void 0 : readDeliveredContext(replay.deliveredContext);
|
|
47284
47728
|
const deliveryAttrs = replay === void 0 ? {
|
|
47285
47729
|
// A blocked start hands the agent nothing, so it names no text.
|
|
@@ -47306,6 +47750,13 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
47306
47750
|
})
|
|
47307
47751
|
)
|
|
47308
47752
|
);
|
|
47753
|
+
if (question !== void 0)
|
|
47754
|
+
events.push(
|
|
47755
|
+
...sealInterjection(record, question, {
|
|
47756
|
+
hook_event_name: "SessionStart",
|
|
47757
|
+
attrs: replayed
|
|
47758
|
+
})
|
|
47759
|
+
);
|
|
47309
47760
|
if (block !== void 0) {
|
|
47310
47761
|
events.push(
|
|
47311
47762
|
record.recorder.sealCollectorEvent(
|
|
@@ -47355,14 +47806,15 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
47355
47806
|
};
|
|
47356
47807
|
const timedOut = replay === void 0 ? expireInterjection(record, deps.now(), questionFields) : void 0;
|
|
47357
47808
|
if (timedOut !== void 0) events.push(...timedOut);
|
|
47358
|
-
const asked = await
|
|
47809
|
+
const asked = await repositoryQuestion(
|
|
47359
47810
|
record,
|
|
47360
47811
|
view,
|
|
47361
47812
|
deps,
|
|
47362
47813
|
replay,
|
|
47363
|
-
|
|
47814
|
+
"UserPromptSubmit"
|
|
47364
47815
|
);
|
|
47365
|
-
|
|
47816
|
+
if (asked !== void 0)
|
|
47817
|
+
events.push(...sealInterjection(record, asked, questionFields));
|
|
47366
47818
|
const block = promptBlock(view, record);
|
|
47367
47819
|
const notice = block === void 0 && timedOut !== void 0 ? INTERJECTION_TIMED_OUT_TEXT : void 0;
|
|
47368
47820
|
const messages = block === void 0 && replay === void 0 && input.agent_id === void 0 && deliversMessages(record.harness, input.hook_event_name) ? drainMessages(record, deps, events, notice?.length ?? 0) : [];
|
|
@@ -47440,12 +47892,17 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
47440
47892
|
const toolInput = input.tool_input;
|
|
47441
47893
|
noteToolCall(record, toolName3, toolInput);
|
|
47442
47894
|
noteRecallHints(record, input.tool_name, toolInput);
|
|
47895
|
+
const timedOut = replay === void 0 ? expireInterjection(record, deps.now(), {
|
|
47896
|
+
hook_event_name: "PreToolUse",
|
|
47897
|
+
attrs: replayed
|
|
47898
|
+
}) : void 0;
|
|
47899
|
+
if (timedOut !== void 0) events.push(...timedOut);
|
|
47443
47900
|
const decided = await decideToolCall(view, record, input, deps, replay, {
|
|
47444
47901
|
toolName: toolName3,
|
|
47445
47902
|
toolInput
|
|
47446
47903
|
});
|
|
47447
47904
|
const currentView = decided.view;
|
|
47448
|
-
let evaluation = decided.evaluation;
|
|
47905
|
+
let evaluation = replay === void 0 ? holdToolCall(decided.evaluation, record) : decided.evaluation;
|
|
47449
47906
|
if (replay === void 0 && evaluation.decision === "deny" && evaluation.reason_code === "session_paused" && record.control.pauseEffect === void 0)
|
|
47450
47907
|
record.control.pauseEffect = "refused";
|
|
47451
47908
|
const refusal = evaluation.decision === "deny" ? void 0 : refusesForSteer(record.harness, record.control.messages);
|
|
@@ -47471,7 +47928,7 @@ async function routeHook(raw, env, deps, replay, harness, agent, hookId) {
|
|
|
47471
47928
|
};
|
|
47472
47929
|
}
|
|
47473
47930
|
}
|
|
47474
|
-
if (evaluation.decision === "deny" && evaluation.source !== "human")
|
|
47931
|
+
if (evaluation.decision === "deny" && evaluation.source !== "human" && evaluation.reason_code !== INTERJECTION_OPEN)
|
|
47475
47932
|
notePolicyDenial(record, toolName3);
|
|
47476
47933
|
const facts = policyFacts2(evaluation, currentView);
|
|
47477
47934
|
const attrs2 = policyAttrs(evaluation, replay);
|
|
@@ -48182,6 +48639,14 @@ function expiredAt(command2, now) {
|
|
|
48182
48639
|
}
|
|
48183
48640
|
async function applyCommands(commands, deps) {
|
|
48184
48641
|
const now = deps.now();
|
|
48642
|
+
if (newCommands(commands, deps).fresh.some(
|
|
48643
|
+
(command2) => command2.session_uuid === null && command2.command === "refresh_bundle" && !expiredAt(command2, now)
|
|
48644
|
+
))
|
|
48645
|
+
await deps.refreshBundle();
|
|
48646
|
+
const seal2 = () => sealNewCommands(commands, deps, now);
|
|
48647
|
+
return deps.exclusive !== void 0 ? deps.exclusive(seal2) : seal2();
|
|
48648
|
+
}
|
|
48649
|
+
function newCommands(commands, deps) {
|
|
48185
48650
|
const fresh = [];
|
|
48186
48651
|
const repeated = [];
|
|
48187
48652
|
for (const command2 of commands) {
|
|
@@ -48189,10 +48654,10 @@ async function applyCommands(commands, deps) {
|
|
|
48189
48654
|
repeated.push(command2.id);
|
|
48190
48655
|
else fresh.push(command2);
|
|
48191
48656
|
}
|
|
48192
|
-
|
|
48193
|
-
|
|
48194
|
-
|
|
48195
|
-
|
|
48657
|
+
return { fresh, repeated };
|
|
48658
|
+
}
|
|
48659
|
+
function sealNewCommands(commands, deps, now) {
|
|
48660
|
+
const { fresh, repeated } = newCommands(commands, deps);
|
|
48196
48661
|
const result2 = sealCommands(fresh, deps, now);
|
|
48197
48662
|
for (const ack of result2.acknowledgements) deps.handled?.remember(ack);
|
|
48198
48663
|
for (const id2 of repeated) {
|
|
@@ -53461,6 +53926,19 @@ import {
|
|
|
53461
53926
|
} from "node:http";
|
|
53462
53927
|
import { Agent as HttpsAgent, request as httpsRequest } from "node:https";
|
|
53463
53928
|
import { brotliDecompress, gunzip, inflate, zstdDecompress } from "node:zlib";
|
|
53929
|
+
async function landedWithin(landing, ms) {
|
|
53930
|
+
let timer;
|
|
53931
|
+
try {
|
|
53932
|
+
return await Promise.race([
|
|
53933
|
+
landing.then(() => true),
|
|
53934
|
+
new Promise((resolve26) => {
|
|
53935
|
+
timer = setTimeout(() => resolve26(false), ms);
|
|
53936
|
+
})
|
|
53937
|
+
]);
|
|
53938
|
+
} finally {
|
|
53939
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
53940
|
+
}
|
|
53941
|
+
}
|
|
53464
53942
|
function streamsAnthropicMessages(route, body2) {
|
|
53465
53943
|
return route.api === "anthropic.messages" && body2?.["stream"] === true;
|
|
53466
53944
|
}
|
|
@@ -53651,6 +54129,7 @@ function createModelProxy(deps) {
|
|
|
53651
54129
|
const maxRequestBytes = deps.maxRequestBytes ?? DEFAULT_MAX_REQUEST_BYTES;
|
|
53652
54130
|
const upstreamIdleMs = deps.upstreamIdleMs ?? DEFAULT_UPSTREAM_IDLE_MS;
|
|
53653
54131
|
const hookTimeoutMs = deps.beforeForwardTimeoutMs ?? DEFAULT_BEFORE_FORWARD_TIMEOUT_MS;
|
|
54132
|
+
const refusalWaitMs = deps.refusalFrameWaitMs ?? DEFAULT_REFUSAL_FRAME_WAIT_MS;
|
|
53654
54133
|
const httpAgent = new HttpAgent({ keepAlive: true, maxSockets: Infinity });
|
|
53655
54134
|
const httpsAgent = new HttpsAgent({ keepAlive: true, maxSockets: Infinity });
|
|
53656
54135
|
const inFlight = /* @__PURE__ */ new Map();
|
|
@@ -53776,10 +54255,10 @@ function createModelProxy(deps) {
|
|
|
53776
54255
|
if (known !== void 0 && !known.sealed && !known.pendingTerminal)
|
|
53777
54256
|
return { record: known, how };
|
|
53778
54257
|
if (known !== void 0) {
|
|
53779
|
-
const
|
|
54258
|
+
const open7 = deps.registry.list().find(
|
|
53780
54259
|
(record2) => record2.harnessSessionId === id2 && !record2.sealed && !record2.pendingTerminal
|
|
53781
54260
|
);
|
|
53782
|
-
if (
|
|
54261
|
+
if (open7 !== void 0) return { record: open7, how };
|
|
53783
54262
|
return { how: "session_closed" };
|
|
53784
54263
|
}
|
|
53785
54264
|
const { record } = deps.registry.ensure(id2, { harness, ambient: true });
|
|
@@ -54006,59 +54485,75 @@ function createModelProxy(deps) {
|
|
|
54006
54485
|
found = { how: "unattributed" };
|
|
54007
54486
|
}
|
|
54008
54487
|
return {
|
|
54488
|
+
...found.record !== void 0 ? { record: found.record } : {},
|
|
54009
54489
|
recorder: found.record?.recorder ?? deps.hostRecorder(),
|
|
54010
54490
|
how: found.how,
|
|
54011
54491
|
attrs: attrsFor(route, found.how)
|
|
54012
54492
|
};
|
|
54013
54493
|
}
|
|
54494
|
+
function landingChain(record, how) {
|
|
54495
|
+
if (record === void 0) return { chain: deps.hostRecorder(), attrs: {} };
|
|
54496
|
+
const owner = deps.registry.byUuid(record.recorder.sessionUuid);
|
|
54497
|
+
if (owner !== void 0 && !owner.sealed && owner.pendingTerminal !== true)
|
|
54498
|
+
return { chain: owner.recorder, attrs: {} };
|
|
54499
|
+
return {
|
|
54500
|
+
chain: deps.hostRecorder(),
|
|
54501
|
+
attrs: {
|
|
54502
|
+
"oxagen.correlation": "session_closed",
|
|
54503
|
+
"oxagen.session_correlation": how,
|
|
54504
|
+
"oxagen.session_uuid": record.recorder.sessionUuid
|
|
54505
|
+
}
|
|
54506
|
+
};
|
|
54507
|
+
}
|
|
54014
54508
|
function sealNotForwarded(req, route, attempt, reason3, status2) {
|
|
54015
54509
|
if (attempt.done) return;
|
|
54016
54510
|
attempt.done = true;
|
|
54017
54511
|
if (route.api === "other") return;
|
|
54018
|
-
let
|
|
54019
|
-
|
|
54512
|
+
let session;
|
|
54513
|
+
const lost = (error) => {
|
|
54514
|
+
deps.log(
|
|
54515
|
+
`model proxy: sealing the frame of a call it did not forward (${reason3}) failed: ${error instanceof Error ? error.message : String(error)} session=${session ?? "unattributed"}`
|
|
54516
|
+
);
|
|
54517
|
+
};
|
|
54020
54518
|
try {
|
|
54021
54519
|
const attribution2 = attempt.attribution ?? attributeByHeaders(req, route);
|
|
54022
|
-
|
|
54023
|
-
recorder = chain;
|
|
54024
|
-
mark = chain.markChain();
|
|
54520
|
+
session = attribution2.recorder.sessionUuid;
|
|
54025
54521
|
const at2 = deps.now();
|
|
54026
|
-
|
|
54027
|
-
|
|
54028
|
-
|
|
54029
|
-
|
|
54030
|
-
|
|
54031
|
-
|
|
54032
|
-
|
|
54033
|
-
|
|
54034
|
-
|
|
54035
|
-
|
|
54036
|
-
|
|
54037
|
-
|
|
54038
|
-
|
|
54039
|
-
|
|
54040
|
-
|
|
54041
|
-
|
|
54042
|
-
|
|
54043
|
-
|
|
54044
|
-
|
|
54045
|
-
|
|
54046
|
-
|
|
54047
|
-
|
|
54048
|
-
|
|
54522
|
+
const body2 = {
|
|
54523
|
+
provider: route.provider,
|
|
54524
|
+
...attempt.model !== void 0 ? { model: attempt.model.slice(0, 512) } : {},
|
|
54525
|
+
...status2 !== void 0 ? { api_status_code: status2 } : {},
|
|
54526
|
+
api_error_class: reason3,
|
|
54527
|
+
api_duration_ms: Math.max(0, at2 - attempt.startedAt)
|
|
54528
|
+
};
|
|
54529
|
+
const attrs2 = {
|
|
54530
|
+
...attribution2.attrs,
|
|
54531
|
+
[NOT_FORWARDED_ATTR]: reason3,
|
|
54532
|
+
"oxagen.provider": route.provider,
|
|
54533
|
+
"oxagen.request_bytes_read": String(attempt.bytesRead),
|
|
54534
|
+
...attempt.request !== void 0 ? { "oxagen.request_digest": digestBytes(attempt.request) } : {}
|
|
54535
|
+
};
|
|
54536
|
+
const land = () => {
|
|
54537
|
+
const landing = landingChain(attribution2.record, attribution2.how);
|
|
54538
|
+
recordOnChain(
|
|
54539
|
+
landing.chain,
|
|
54540
|
+
(chain) => [
|
|
54541
|
+
chain.sealCollectorEvent("error", body2, {
|
|
54542
|
+
ts: toProtocolTimestamp(at2),
|
|
54543
|
+
fidelity: "proxy",
|
|
54544
|
+
attrs: { ...attrs2, ...landing.attrs }
|
|
54545
|
+
})
|
|
54546
|
+
],
|
|
54547
|
+
deps.record
|
|
54548
|
+
);
|
|
54549
|
+
};
|
|
54550
|
+
if (attribution2.record === void 0) land();
|
|
54551
|
+
else
|
|
54552
|
+
void onSessionQueue(deps.exclusive, attribution2.record, land).catch(
|
|
54553
|
+
lost
|
|
54554
|
+
);
|
|
54049
54555
|
} catch (error) {
|
|
54050
|
-
|
|
54051
|
-
try {
|
|
54052
|
-
recorder.rollbackChain(mark);
|
|
54053
|
-
} catch (rollbackError) {
|
|
54054
|
-
deps.log(
|
|
54055
|
-
`model proxy: rolling the chain back after a failed frame failed too: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)} session=${recorder.sessionUuid}`
|
|
54056
|
-
);
|
|
54057
|
-
}
|
|
54058
|
-
}
|
|
54059
|
-
deps.log(
|
|
54060
|
-
`model proxy: sealing the frame of a call it did not forward (${reason3}) failed: ${error instanceof Error ? error.message : String(error)} session=${recorder?.sessionUuid ?? "unattributed"}`
|
|
54061
|
-
);
|
|
54556
|
+
lost(error);
|
|
54062
54557
|
}
|
|
54063
54558
|
}
|
|
54064
54559
|
function sendProviderError(res, route, status2, code, message, retryable = false) {
|
|
@@ -54347,29 +54842,6 @@ function createModelProxy(deps) {
|
|
|
54347
54842
|
}
|
|
54348
54843
|
callsObserved += 1;
|
|
54349
54844
|
observed.set(sessionKey, (observed.get(sessionKey) ?? 0) + 1);
|
|
54350
|
-
const closed2 = record.sealed || record.pendingTerminal === true;
|
|
54351
|
-
const requestText = payload.body.toString("utf8");
|
|
54352
|
-
const memory = new RequestPrefixMemory();
|
|
54353
|
-
if (payload.priorShape !== void 0 && !closed2)
|
|
54354
|
-
memory.remember("parent", {
|
|
54355
|
-
text: "",
|
|
54356
|
-
fullDigest: payload.priorShape.requestDigest,
|
|
54357
|
-
fullBytes: 0,
|
|
54358
|
-
storedBytes: 0,
|
|
54359
|
-
prior: void 0,
|
|
54360
|
-
shape: payload.priorShape,
|
|
54361
|
-
priorPayload: void 0
|
|
54362
|
-
});
|
|
54363
|
-
const fold = memory.fold("parent", requestText);
|
|
54364
|
-
const capped = cappedExchange(
|
|
54365
|
-
fold.storedBytes > TACHO_MAX_BODY_BYTES ? void 0 : fold.text,
|
|
54366
|
-
{
|
|
54367
|
-
text: answer.responseText,
|
|
54368
|
-
tooLarge: answer.responseTooLarge,
|
|
54369
|
-
bytes: answer.responseBytes
|
|
54370
|
-
}
|
|
54371
|
-
);
|
|
54372
|
-
const chain = closed2 ? deps.hostRecorder() : record.recorder;
|
|
54373
54845
|
const callBody2 = llmCallBody({
|
|
54374
54846
|
provider: "anthropic",
|
|
54375
54847
|
model,
|
|
@@ -54385,10 +54857,33 @@ function createModelProxy(deps) {
|
|
|
54385
54857
|
failed: answer.errorClass ?? (answer.status >= 400 ? `http_${answer.status}` : void 0),
|
|
54386
54858
|
requestId: answer.requestId
|
|
54387
54859
|
});
|
|
54388
|
-
const
|
|
54389
|
-
|
|
54390
|
-
|
|
54391
|
-
|
|
54860
|
+
const land = () => {
|
|
54861
|
+
const owner = deps.registry.byUuid(record.recorder.sessionUuid);
|
|
54862
|
+
const closed2 = owner === void 0 || owner.sealed || owner.pendingTerminal === true;
|
|
54863
|
+
const requestText = payload.body.toString("utf8");
|
|
54864
|
+
const memory = new RequestPrefixMemory();
|
|
54865
|
+
if (payload.priorShape !== void 0 && !closed2)
|
|
54866
|
+
memory.remember("parent", {
|
|
54867
|
+
text: "",
|
|
54868
|
+
fullDigest: payload.priorShape.requestDigest,
|
|
54869
|
+
fullBytes: 0,
|
|
54870
|
+
storedBytes: 0,
|
|
54871
|
+
prior: void 0,
|
|
54872
|
+
shape: payload.priorShape,
|
|
54873
|
+
priorPayload: void 0
|
|
54874
|
+
});
|
|
54875
|
+
const fold = memory.fold("parent", requestText);
|
|
54876
|
+
const capped = cappedExchange(
|
|
54877
|
+
fold.storedBytes > TACHO_MAX_BODY_BYTES ? void 0 : fold.text,
|
|
54878
|
+
{
|
|
54879
|
+
text: answer.responseText,
|
|
54880
|
+
tooLarge: answer.responseTooLarge,
|
|
54881
|
+
bytes: answer.responseBytes
|
|
54882
|
+
}
|
|
54883
|
+
);
|
|
54884
|
+
recordOnChain(
|
|
54885
|
+
closed2 ? deps.hostRecorder() : owner.recorder,
|
|
54886
|
+
(chain) => [
|
|
54392
54887
|
chain.sealCollectorEvent("llm_call", callBody2, {
|
|
54393
54888
|
ts: toProtocolTimestamp(settledAt),
|
|
54394
54889
|
fidelity: "proxy",
|
|
@@ -54427,20 +54922,16 @@ function createModelProxy(deps) {
|
|
|
54427
54922
|
}
|
|
54428
54923
|
})
|
|
54429
54924
|
],
|
|
54430
|
-
|
|
54925
|
+
deps.record
|
|
54431
54926
|
);
|
|
54432
|
-
}
|
|
54433
|
-
|
|
54434
|
-
|
|
54435
|
-
} catch (rollbackError) {
|
|
54927
|
+
};
|
|
54928
|
+
void onSessionQueue(deps.exclusive, record, land).catch(
|
|
54929
|
+
(error) => {
|
|
54436
54930
|
deps.log(
|
|
54437
|
-
`model proxy:
|
|
54931
|
+
`model proxy: sealing a cache keep-alive's frame failed: ${error instanceof Error ? error.message : String(error)} session=${sessionKey}`
|
|
54438
54932
|
);
|
|
54439
54933
|
}
|
|
54440
|
-
|
|
54441
|
-
`model proxy: sealing a cache keep-alive's frame failed: ${error instanceof Error ? error.message : String(error)} session=${sessionKey}`
|
|
54442
|
-
);
|
|
54443
|
-
}
|
|
54934
|
+
);
|
|
54444
54935
|
return usage2.cacheReadTokens ?? 0;
|
|
54445
54936
|
}
|
|
54446
54937
|
async function forward(req, res, route, admitted, attempt) {
|
|
@@ -54481,7 +54972,12 @@ function createModelProxy(deps) {
|
|
|
54481
54972
|
const sessionKey = record?.recorder.sessionUuid ?? HOST_KEY;
|
|
54482
54973
|
const credential = resolveCredential(req, route);
|
|
54483
54974
|
const attrs2 = attrsFor(route, how, credential);
|
|
54484
|
-
attempt.attribution = {
|
|
54975
|
+
attempt.attribution = {
|
|
54976
|
+
...record !== void 0 ? { record } : {},
|
|
54977
|
+
recorder,
|
|
54978
|
+
how,
|
|
54979
|
+
attrs: attrs2
|
|
54980
|
+
};
|
|
54485
54981
|
const metered = route.api !== "other";
|
|
54486
54982
|
const { model: askedModel, ambiguous: modelAmbiguous } = modelOf(
|
|
54487
54983
|
readable,
|
|
@@ -54527,44 +55023,58 @@ function createModelProxy(deps) {
|
|
|
54527
55023
|
if (refusal !== void 0) {
|
|
54528
55024
|
refused2 += 1;
|
|
54529
55025
|
const view = deps.policy();
|
|
54530
|
-
const
|
|
54531
|
-
|
|
54532
|
-
|
|
54533
|
-
|
|
54534
|
-
|
|
54535
|
-
|
|
54536
|
-
|
|
54537
|
-
|
|
54538
|
-
|
|
54539
|
-
|
|
54540
|
-
|
|
54541
|
-
|
|
54542
|
-
|
|
54543
|
-
|
|
55026
|
+
const decision = {
|
|
55027
|
+
policy_decision: "deny",
|
|
55028
|
+
policy_source: refusal.source,
|
|
55029
|
+
policy_reason_code: refusal.code,
|
|
55030
|
+
policy_reason_digest: digestText(refusal.message),
|
|
55031
|
+
bundle_version: view.bundle.version,
|
|
55032
|
+
bundle_mode: view.bundle.mode
|
|
55033
|
+
};
|
|
55034
|
+
const decisionAttrs = {
|
|
55035
|
+
...attrs2,
|
|
55036
|
+
"oxagen.refused": "model_call",
|
|
55037
|
+
"oxagen.provider": route.provider,
|
|
55038
|
+
"oxagen.request_digest": digestBytes(body2),
|
|
55039
|
+
// The model the refusal was about, when the proxy could read one. A
|
|
55040
|
+
// `model_not_permitted` frame that does not name the model leaves the
|
|
55041
|
+
// operator guessing which entry to add.
|
|
55042
|
+
...askedModel !== void 0 ? { "oxagen.model": askedModel.slice(0, 512) } : {},
|
|
55043
|
+
...modelAmbiguous ? { "oxagen.model_ambiguous": "true" } : {},
|
|
55044
|
+
...record !== void 0 ? {
|
|
55045
|
+
"oxagen.session_spend_usd_micros": String(spendFor(sessionKey))
|
|
55046
|
+
} : {},
|
|
55047
|
+
..."attrs" in refusal ? refusal.attrs : {}
|
|
55048
|
+
};
|
|
55049
|
+
const land = () => {
|
|
55050
|
+
const landing = landingChain(record, how);
|
|
55051
|
+
recordOnChain(
|
|
55052
|
+
landing.chain,
|
|
55053
|
+
(chain) => [
|
|
55054
|
+
chain.sealCollectorEvent("policy_decision", decision, {
|
|
54544
55055
|
fidelity: "proxy",
|
|
54545
|
-
attrs: {
|
|
54546
|
-
|
|
54547
|
-
|
|
54548
|
-
|
|
54549
|
-
|
|
54550
|
-
|
|
54551
|
-
|
|
54552
|
-
|
|
54553
|
-
|
|
54554
|
-
|
|
54555
|
-
|
|
54556
|
-
|
|
54557
|
-
|
|
54558
|
-
|
|
54559
|
-
|
|
54560
|
-
|
|
54561
|
-
|
|
54562
|
-
|
|
54563
|
-
|
|
54564
|
-
|
|
54565
|
-
|
|
54566
|
-
|
|
54567
|
-
throw error;
|
|
55056
|
+
attrs: { ...decisionAttrs, ...landing.attrs }
|
|
55057
|
+
})
|
|
55058
|
+
],
|
|
55059
|
+
deps.record
|
|
55060
|
+
);
|
|
55061
|
+
};
|
|
55062
|
+
if (record === void 0) land();
|
|
55063
|
+
else {
|
|
55064
|
+
let answered = false;
|
|
55065
|
+
const written2 = onSessionQueue(deps.exclusive, record, land);
|
|
55066
|
+
void written2.catch((error) => {
|
|
55067
|
+
if (answered)
|
|
55068
|
+
deps.log(
|
|
55069
|
+
`model proxy: the frame of a refusal already answered was not written: ${error instanceof Error ? error.message : String(error)} session=${sessionKey}`
|
|
55070
|
+
);
|
|
55071
|
+
});
|
|
55072
|
+
if (!await landedWithin(written2, refusalWaitMs)) {
|
|
55073
|
+
answered = true;
|
|
55074
|
+
deps.log(
|
|
55075
|
+
`model proxy: answered a refused call before its frame could land, because the session's queue was busy for ${refusalWaitMs} ms session=${sessionKey}`
|
|
55076
|
+
);
|
|
55077
|
+
}
|
|
54568
55078
|
}
|
|
54569
55079
|
attempt.done = true;
|
|
54570
55080
|
deps.log(
|
|
@@ -55245,9 +55755,9 @@ function createModelProxy(deps) {
|
|
|
55245
55755
|
callsObservedFor: (sessionUuid2) => observed.get(sessionUuid2) ?? 0,
|
|
55246
55756
|
keepAliveTick: () => keepAlive.tick(),
|
|
55247
55757
|
stats: () => {
|
|
55248
|
-
let
|
|
55249
|
-
for (const calls of inFlight.values())
|
|
55250
|
-
return { callsObserved, refused: refused2, inFlight:
|
|
55758
|
+
let open7 = 0;
|
|
55759
|
+
for (const calls of inFlight.values()) open7 += calls.size;
|
|
55760
|
+
return { callsObserved, refused: refused2, inFlight: open7 };
|
|
55251
55761
|
},
|
|
55252
55762
|
close: () => {
|
|
55253
55763
|
clearInterval(keepAliveTimer);
|
|
@@ -55262,7 +55772,7 @@ function createModelProxy(deps) {
|
|
|
55262
55772
|
}
|
|
55263
55773
|
};
|
|
55264
55774
|
}
|
|
55265
|
-
var DEFAULT_MAX_REQUEST_BYTES, NOT_FORWARDED_ATTR, DEFAULT_UPSTREAM_IDLE_MS, DEFAULT_BEFORE_FORWARD_TIMEOUT_MS, DEFAULT_UPSTREAM_CONNECT_MS, DEFAULT_PAUSE_HOLD_MS, DEFAULT_PAUSE_STREAM_HOLD_MS, DEFAULT_PAUSE_HOLD_PING_MS, DEFAULT_PAUSE_HOLD_CHECK_MS, MAX_HELD_CALLS_PER_SESSION, PAUSE_HOLD_CODES, ANTHROPIC_PING_EVENT, HELD_STREAM_ERROR_BYTES, FREE_SOCKET_TIMEOUT_MS, KEEP_ALIVE_TIMEOUT_MS, KEEP_ALIVE_MAX_RESPONSE_BYTES, BodyCapture, EXCHANGE_OPEN_BYTES, EXCHANGE_JOIN_BYTES, DECODERS, REQUEST_EFFORT_MAX, CREDENTIAL_MESSAGES;
|
|
55775
|
+
var DEFAULT_MAX_REQUEST_BYTES, NOT_FORWARDED_ATTR, DEFAULT_UPSTREAM_IDLE_MS, DEFAULT_BEFORE_FORWARD_TIMEOUT_MS, DEFAULT_UPSTREAM_CONNECT_MS, DEFAULT_REFUSAL_FRAME_WAIT_MS, DEFAULT_PAUSE_HOLD_MS, DEFAULT_PAUSE_STREAM_HOLD_MS, DEFAULT_PAUSE_HOLD_PING_MS, DEFAULT_PAUSE_HOLD_CHECK_MS, MAX_HELD_CALLS_PER_SESSION, PAUSE_HOLD_CODES, ANTHROPIC_PING_EVENT, HELD_STREAM_ERROR_BYTES, FREE_SOCKET_TIMEOUT_MS, KEEP_ALIVE_TIMEOUT_MS, KEEP_ALIVE_MAX_RESPONSE_BYTES, BodyCapture, EXCHANGE_OPEN_BYTES, EXCHANGE_JOIN_BYTES, DECODERS, REQUEST_EFFORT_MAX, CREDENTIAL_MESSAGES;
|
|
55266
55776
|
var init_model_proxy = __esm({
|
|
55267
55777
|
"../../packages/tacho/src/collector/model-proxy.ts"() {
|
|
55268
55778
|
"use strict";
|
|
@@ -55293,6 +55803,7 @@ var init_model_proxy = __esm({
|
|
|
55293
55803
|
DEFAULT_UPSTREAM_IDLE_MS = 10 * 6e4;
|
|
55294
55804
|
DEFAULT_BEFORE_FORWARD_TIMEOUT_MS = 250;
|
|
55295
55805
|
DEFAULT_UPSTREAM_CONNECT_MS = 3e4;
|
|
55806
|
+
DEFAULT_REFUSAL_FRAME_WAIT_MS = 1e3;
|
|
55296
55807
|
DEFAULT_PAUSE_HOLD_MS = 12e4;
|
|
55297
55808
|
DEFAULT_PAUSE_STREAM_HOLD_MS = 12 * 60 * 6e4;
|
|
55298
55809
|
DEFAULT_PAUSE_HOLD_PING_MS = 15e3;
|
|
@@ -55477,7 +55988,7 @@ var init_model_proxy_listener = __esm({
|
|
|
55477
55988
|
import {
|
|
55478
55989
|
createServer as createServer5
|
|
55479
55990
|
} from "node:http";
|
|
55480
|
-
import { chmodSync as chmodSync9, existsSync as existsSync23, statSync as
|
|
55991
|
+
import { chmodSync as chmodSync9, existsSync as existsSync23, statSync as statSync13, unlinkSync as unlinkSync11 } from "node:fs";
|
|
55481
55992
|
import { randomBytes as randomBytes11, timingSafeEqual as timingSafeEqual2 } from "node:crypto";
|
|
55482
55993
|
import { createConnection } from "node:net";
|
|
55483
55994
|
function isExportFormat(value) {
|
|
@@ -55853,7 +56364,7 @@ function createRequestHandler(api, log, options = {}) {
|
|
|
55853
56364
|
}
|
|
55854
56365
|
async function removeStaleSocket(socketPath) {
|
|
55855
56366
|
if (!existsSync23(socketPath)) return;
|
|
55856
|
-
if (!
|
|
56367
|
+
if (!statSync13(socketPath).isSocket()) {
|
|
55857
56368
|
throw new Error(`collector socket path is not a socket: ${socketPath}`);
|
|
55858
56369
|
}
|
|
55859
56370
|
const stale = await new Promise((resolve26, reject) => {
|
|
@@ -56022,7 +56533,7 @@ var init_server = __esm({
|
|
|
56022
56533
|
});
|
|
56023
56534
|
|
|
56024
56535
|
// ../../packages/tacho/src/collector/refused.ts
|
|
56025
|
-
import { readdirSync as readdirSync12, readFileSync as readFileSync20, statSync as
|
|
56536
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync20, statSync as statSync14 } from "node:fs";
|
|
56026
56537
|
import { join as join45 } from "node:path";
|
|
56027
56538
|
function refusalRetryable(refusal) {
|
|
56028
56539
|
return refusal === "malformed" || refusal === "parked";
|
|
@@ -56072,7 +56583,7 @@ function readRefusedEntry(file) {
|
|
|
56072
56583
|
let mtimeMs;
|
|
56073
56584
|
try {
|
|
56074
56585
|
record = JSON.parse(readFileSync20(file, "utf8"));
|
|
56075
|
-
mtimeMs =
|
|
56586
|
+
mtimeMs = statSync14(file).mtimeMs;
|
|
56076
56587
|
} catch {
|
|
56077
56588
|
return void 0;
|
|
56078
56589
|
}
|
|
@@ -57025,7 +57536,7 @@ import {
|
|
|
57025
57536
|
readdirSync as readdirSync13,
|
|
57026
57537
|
readFileSync as readFileSync22,
|
|
57027
57538
|
renameSync as renameSync4,
|
|
57028
|
-
statSync as
|
|
57539
|
+
statSync as statSync15,
|
|
57029
57540
|
unlinkSync as unlinkSync13
|
|
57030
57541
|
} from "node:fs";
|
|
57031
57542
|
import { readdir as readdir3, readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
@@ -57224,7 +57735,8 @@ async function startDaemon(options) {
|
|
|
57224
57735
|
}
|
|
57225
57736
|
}
|
|
57226
57737
|
async function initializeDaemon(options, server, port, ready) {
|
|
57227
|
-
const paths = options.paths;
|
|
57738
|
+
const paths = withRecordedHarnessFiles(options.paths, options.host);
|
|
57739
|
+
const harnessHomes = recordedHarnessHomes(options.host);
|
|
57228
57740
|
const now = options.now ?? (() => Date.now());
|
|
57229
57741
|
const log = options.log;
|
|
57230
57742
|
const timers = { ...DEFAULT_TIMERS, ...options.timers };
|
|
@@ -57374,7 +57886,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57374
57886
|
processStarts: hookProcessStarts,
|
|
57375
57887
|
adoptedChain: (sessionUuid2) => backfillLedger.chainHead(sessionUuid2)
|
|
57376
57888
|
});
|
|
57377
|
-
const priorStateWrittenAt = existsSync25(paths.daemonState) ?
|
|
57889
|
+
const priorStateWrittenAt = existsSync25(paths.daemonState) ? statSync15(paths.daemonState).mtimeMs : void 0;
|
|
57378
57890
|
const sealedState = parseSealedState(
|
|
57379
57891
|
readJsonStateFile(
|
|
57380
57892
|
paths.daemonSealedState,
|
|
@@ -57521,7 +58033,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57521
58033
|
},
|
|
57522
58034
|
...options.workOrders?.spawn !== void 0 ? { spawn: options.workOrders.spawn } : {},
|
|
57523
58035
|
...options.workOrders?.isAlive !== void 0 ? { isAlive: options.workOrders.isAlive } : {},
|
|
57524
|
-
...options.workOrders?.findCheckout !== void 0 ? { findCheckout: options.workOrders.findCheckout } : {}
|
|
58036
|
+
...options.workOrders?.findCheckout !== void 0 ? { findCheckout: options.workOrders.findCheckout } : {},
|
|
58037
|
+
...options.workOrders?.wait !== void 0 ? { wait: options.workOrders.wait } : {}
|
|
57525
58038
|
});
|
|
57526
58039
|
void workOrderAutostart.clearDeadMarks();
|
|
57527
58040
|
function persistState(options2 = {}) {
|
|
@@ -57736,25 +58249,24 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57736
58249
|
});
|
|
57737
58250
|
}
|
|
57738
58251
|
async function applyCommandsRecorded(commands, deps) {
|
|
57739
|
-
|
|
57740
|
-
|
|
57741
|
-
|
|
57742
|
-
|
|
57743
|
-
|
|
57744
|
-
|
|
57745
|
-
|
|
57746
|
-
|
|
57747
|
-
|
|
58252
|
+
return applyCommands2(commands, {
|
|
58253
|
+
...deps,
|
|
58254
|
+
exclusive: (seal2) => queues.host(async () => {
|
|
58255
|
+
if (hostRecord.sealed) throw new Error(STOPPING);
|
|
58256
|
+
const marks = markCommandChains(commands);
|
|
58257
|
+
let result2;
|
|
58258
|
+
try {
|
|
58259
|
+
result2 = seal2();
|
|
58260
|
+
record(result2.events);
|
|
58261
|
+
return result2;
|
|
58262
|
+
} catch (error) {
|
|
58263
|
+
for (const { session, mark } of [...marks].reverse())
|
|
58264
|
+
session.recorder.rollbackChain(mark);
|
|
58265
|
+
result2?.restore();
|
|
58266
|
+
throw error;
|
|
57748
58267
|
}
|
|
57749
|
-
})
|
|
57750
|
-
|
|
57751
|
-
return result2;
|
|
57752
|
-
} catch (error) {
|
|
57753
|
-
for (const { session, mark } of [...marks].reverse())
|
|
57754
|
-
session.recorder.rollbackChain(mark);
|
|
57755
|
-
result2?.restore();
|
|
57756
|
-
throw error;
|
|
57757
|
-
}
|
|
58268
|
+
})
|
|
58269
|
+
});
|
|
57758
58270
|
}
|
|
57759
58271
|
let modelBaseUrls = [];
|
|
57760
58272
|
const spoolFacts = /* @__PURE__ */ new Map();
|
|
@@ -57876,6 +58388,31 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57876
58388
|
}
|
|
57877
58389
|
}
|
|
57878
58390
|
function retryOwedBodyPurge() {
|
|
58391
|
+
if (existsSync25(bodyPurgeOwedPath)) void settleOwedBodyPurge("owed");
|
|
58392
|
+
}
|
|
58393
|
+
let bodyPurge;
|
|
58394
|
+
let bodyPurgeAgain = false;
|
|
58395
|
+
let bodyPurgeNarrowing = false;
|
|
58396
|
+
function settleOwedBodyPurge(trigger) {
|
|
58397
|
+
if (trigger === "narrowed") bodyPurgeNarrowing = true;
|
|
58398
|
+
if (bodyPurge !== void 0) {
|
|
58399
|
+
bodyPurgeAgain = true;
|
|
58400
|
+
return bodyPurge;
|
|
58401
|
+
}
|
|
58402
|
+
const run3 = (async () => {
|
|
58403
|
+
do {
|
|
58404
|
+
bodyPurgeAgain = false;
|
|
58405
|
+
const narrowing = bodyPurgeNarrowing;
|
|
58406
|
+
bodyPurgeNarrowing = false;
|
|
58407
|
+
await sweepOwedBodies(narrowing);
|
|
58408
|
+
} while (bodyPurgeAgain && !stopped2);
|
|
58409
|
+
})().finally(() => {
|
|
58410
|
+
if (bodyPurge === run3) bodyPurge = void 0;
|
|
58411
|
+
});
|
|
58412
|
+
bodyPurge = run3;
|
|
58413
|
+
return run3;
|
|
58414
|
+
}
|
|
58415
|
+
async function sweepOwedBodies(narrowing) {
|
|
57879
58416
|
const owed = owedBodyPurge();
|
|
57880
58417
|
if (owed === void 0) return;
|
|
57881
58418
|
let clause = owed.retention;
|
|
@@ -57885,16 +58422,28 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57885
58422
|
clause = inForce.mandate;
|
|
57886
58423
|
}
|
|
57887
58424
|
try {
|
|
57888
|
-
const purged = wal.
|
|
58425
|
+
const purged = await wal.purgeBodiesOutsideMandateAsync(clause, {
|
|
58426
|
+
signal: stopping.signal
|
|
58427
|
+
}) + purgePendingEndBodies(clause);
|
|
57889
58428
|
purgeQueuedPrompts(clause);
|
|
57890
|
-
clearBodyPurgeOwed();
|
|
58429
|
+
if (!bodyPurgeAgain) clearBodyPurgeOwed();
|
|
57891
58430
|
log(
|
|
57892
|
-
`completed an owed body purge: erased ${purged} queued body(ies) the mandate does not cover`
|
|
58431
|
+
narrowing ? `mandate narrowed (${owed.classes.join(", ")}): erased ${purged} queued body(ies) from the WAL` : `completed an owed body purge: erased ${purged} queued body(ies) the mandate does not cover`
|
|
57893
58432
|
);
|
|
57894
58433
|
} catch (error) {
|
|
57895
|
-
|
|
57896
|
-
|
|
57897
|
-
|
|
58434
|
+
const reason3 = error instanceof Error ? error.message : String(error);
|
|
58435
|
+
if (stopping.signal.aborted)
|
|
58436
|
+
log(
|
|
58437
|
+
"stop: left an owed body purge unfinished; the next start finishes it"
|
|
58438
|
+
);
|
|
58439
|
+
else if (narrowing)
|
|
58440
|
+
log(
|
|
58441
|
+
`failed to erase bodies the narrowed mandate no longer covers (${owed.classes.join(", ")}); content remains in the WAL: ${reason3}; check free space and permissions under ${paths.wal}. The purge is retried at each bundle confirmation`
|
|
58442
|
+
);
|
|
58443
|
+
else
|
|
58444
|
+
log(
|
|
58445
|
+
`an owed body purge failed again; content remains in the WAL: ${reason3}; check free space and permissions under ${paths.wal}. The purge is retried at each bundle confirmation`
|
|
58446
|
+
);
|
|
57898
58447
|
}
|
|
57899
58448
|
}
|
|
57900
58449
|
function purgeQueuedPrompts(clause) {
|
|
@@ -57917,21 +58466,30 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57917
58466
|
const dropped = HOST_RETENTION_CLASSES.filter(
|
|
57918
58467
|
(contentClass) => retentionAllows(previous, contentClass) && !retentionAllows(next, contentClass)
|
|
57919
58468
|
);
|
|
57920
|
-
if (dropped.length === 0) return
|
|
57921
|
-
|
|
58469
|
+
if (dropped.length === 0) return "none";
|
|
58470
|
+
if (markBodyPurgeOwed(next, dropped)) {
|
|
58471
|
+
try {
|
|
58472
|
+
purgePendingEndBodies(next);
|
|
58473
|
+
purgeQueuedPrompts(next);
|
|
58474
|
+
} catch (error) {
|
|
58475
|
+
log(
|
|
58476
|
+
`failed to erase bodies the narrowed mandate no longer covers (${dropped.join(", ")}); content remains on disk: ${error instanceof Error ? error.message : String(error)}`
|
|
58477
|
+
);
|
|
58478
|
+
}
|
|
58479
|
+
return "owed";
|
|
58480
|
+
}
|
|
57922
58481
|
try {
|
|
57923
58482
|
const purged = wal.purgeBodiesOutsideMandate(next) + purgePendingEndBodies(next);
|
|
57924
58483
|
purgeQueuedPrompts(next);
|
|
57925
|
-
clearBodyPurgeOwed();
|
|
57926
58484
|
log(
|
|
57927
58485
|
`mandate narrowed (${dropped.join(", ")}): erased ${purged} queued body(ies) from the WAL`
|
|
57928
58486
|
);
|
|
57929
|
-
return
|
|
58487
|
+
return "swept";
|
|
57930
58488
|
} catch (error) {
|
|
57931
58489
|
log(
|
|
57932
58490
|
`failed to erase bodies the narrowed mandate no longer covers (${dropped.join(", ")}); content remains in the WAL: ${error instanceof Error ? error.message : String(error)}`
|
|
57933
58491
|
);
|
|
57934
|
-
return
|
|
58492
|
+
return "refused";
|
|
57935
58493
|
}
|
|
57936
58494
|
}
|
|
57937
58495
|
async function fetchBundle() {
|
|
@@ -57963,10 +58521,11 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57963
58521
|
);
|
|
57964
58522
|
return "refused";
|
|
57965
58523
|
}
|
|
57966
|
-
|
|
58524
|
+
const narrowing = purgeBodiesNarrowedOut(
|
|
57967
58525
|
host.bundle.retention,
|
|
57968
58526
|
response.bundle.retention
|
|
57969
|
-
)
|
|
58527
|
+
);
|
|
58528
|
+
if (narrowing === "refused") {
|
|
57970
58529
|
log(
|
|
57971
58530
|
"refusing to cache a narrowed bundle this host can neither enforce on disk nor remember owing; the old etag stands so the next poll retries"
|
|
57972
58531
|
);
|
|
@@ -57979,6 +58538,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
57979
58538
|
bundleVerified = true;
|
|
57980
58539
|
mandateConfirmedAt = now();
|
|
57981
58540
|
log(`bundle ${response.bundle.version} (${response.bundle.etag}) cached`);
|
|
58541
|
+
if (narrowing === "owed") void settleOwedBodyPurge("narrowed");
|
|
57982
58542
|
return "cached";
|
|
57983
58543
|
} catch (error) {
|
|
57984
58544
|
log(
|
|
@@ -58341,7 +58901,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
58341
58901
|
lastIngestAt ?? -Infinity,
|
|
58342
58902
|
lastCommandPollAt ?? -Infinity
|
|
58343
58903
|
);
|
|
58344
|
-
|
|
58904
|
+
const pollEveryMs = registry2.live().some((session) => session !== hostRecord) ? timers.commandsPollMs : timers.commandsPollMs * IDLE_COMMAND_POLL_FACTOR;
|
|
58905
|
+
if (pendingAcks.length === 0 && now() - lastEnvelopeAt < pollEveryMs) {
|
|
58345
58906
|
return;
|
|
58346
58907
|
}
|
|
58347
58908
|
if (now() < commandPollNextAttemptAt) return;
|
|
@@ -58742,6 +59303,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
58742
59303
|
restoreEveryQueue(queued);
|
|
58743
59304
|
throw error;
|
|
58744
59305
|
}
|
|
59306
|
+
const workOrder = workOrderIdOf(envelope2.env?.[WORK_ORDER_ENV]);
|
|
59307
|
+
if (workOrder !== void 0) workOrderAutostart.noteSession(workOrder);
|
|
58745
59308
|
if (pending !== void 0) {
|
|
58746
59309
|
const state = registry2.state();
|
|
58747
59310
|
const key = sessionMapKey(harnessSessionId, {
|
|
@@ -59244,7 +59807,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
59244
59807
|
const state = await readModelBaseUrlState({
|
|
59245
59808
|
home: options.home ?? homedir8(),
|
|
59246
59809
|
port: modelProxyPortFor(host),
|
|
59247
|
-
stellaHome: dirname26(
|
|
59810
|
+
stellaHome: dirname26(paths.stellaToml),
|
|
59811
|
+
...harnessHomes,
|
|
59248
59812
|
harnesses: ["claude-code", "codex", "stella"]
|
|
59249
59813
|
});
|
|
59250
59814
|
const next = {};
|
|
@@ -59807,7 +60371,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
59807
60371
|
if (!name.endsWith(".json")) continue;
|
|
59808
60372
|
const file = join47(paths.quarantine, name);
|
|
59809
60373
|
try {
|
|
59810
|
-
const refusedAt = readRefusedEntry(file)?.refusedAt ??
|
|
60374
|
+
const refusedAt = readRefusedEntry(file)?.refusedAt ?? statSync15(file).mtimeMs;
|
|
59811
60375
|
if (at2 - refusedAt < retainMs) continue;
|
|
59812
60376
|
unlinkSync13(file);
|
|
59813
60377
|
removed += 1;
|
|
@@ -60080,7 +60644,11 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
60080
60644
|
else if (typeof refreshed === "object")
|
|
60081
60645
|
log(`ChatGPT login refresh: ${refreshed.failed}`);
|
|
60082
60646
|
if (refreshed !== "none")
|
|
60083
|
-
restateCodexLastRefresh(
|
|
60647
|
+
restateCodexLastRefresh(
|
|
60648
|
+
options.home ?? homedir8(),
|
|
60649
|
+
now(),
|
|
60650
|
+
harnessHomes
|
|
60651
|
+
);
|
|
60084
60652
|
} catch (error) {
|
|
60085
60653
|
log(
|
|
60086
60654
|
`ChatGPT login refresh: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -60093,6 +60661,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
60093
60661
|
await renewStaticToken(harness, {
|
|
60094
60662
|
home: options.home ?? homedir8(),
|
|
60095
60663
|
stellaHome: dirname26(paths.stellaToml),
|
|
60664
|
+
...harnessHomes,
|
|
60096
60665
|
host,
|
|
60097
60666
|
runTokenKeyPath: paths.runTokenKey,
|
|
60098
60667
|
now,
|
|
@@ -60222,6 +60791,9 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
60222
60791
|
drainSpool: () => queues.host(() => drainSpool()),
|
|
60223
60792
|
queues,
|
|
60224
60793
|
refreshBundle: () => refreshBundle({ force: true }),
|
|
60794
|
+
bodyPurgeIdle: async () => {
|
|
60795
|
+
while (bodyPurge !== void 0) await bodyPurge;
|
|
60796
|
+
},
|
|
60225
60797
|
workOrdersIdle: () => workOrderAutostart.idle(),
|
|
60226
60798
|
stop: async () => {
|
|
60227
60799
|
if (stopped2) return;
|
|
@@ -60240,7 +60812,8 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
60240
60812
|
}
|
|
60241
60813
|
const [gitSettled, memorySettled] = await Promise.all([
|
|
60242
60814
|
settleWithin(gitLane, timers.stopLaneMs),
|
|
60243
|
-
settleWithin(memoryScan, timers.stopLaneMs)
|
|
60815
|
+
settleWithin(memoryScan, timers.stopLaneMs),
|
|
60816
|
+
settleWithin(bodyPurge, timers.stopLaneMs)
|
|
60244
60817
|
]);
|
|
60245
60818
|
if (!gitSettled)
|
|
60246
60819
|
log(
|
|
@@ -60281,7 +60854,7 @@ async function initializeDaemon(options, server, port, ready) {
|
|
|
60281
60854
|
}
|
|
60282
60855
|
};
|
|
60283
60856
|
}
|
|
60284
|
-
var DEFAULT_TIMERS, STATIC_TOKEN_RENEWAL_CHECK_MS, CHATGPT_LOGIN_CHECK_MS, MEMORY_SCAN_MS, CLOUD_GATEWAY_ORIGIN, CLOUD_GATEWAY_BASE_PATH, QUEUED_PROMPT_CLASS, TRACE_DRAIN_TIMEOUT_MS, RECORDER_EVENTS_KEPT, owedBodyPurgeSchema, objectSchema, spoolFileSchema, otlpResourceListSchema, otlpPayloadSchema, defaultExecAsync, STOPPING, STOPPED_EXEC, STATE_WRITE_DEFER_MS;
|
|
60857
|
+
var IDLE_COMMAND_POLL_FACTOR, DEFAULT_TIMERS, STATIC_TOKEN_RENEWAL_CHECK_MS, CHATGPT_LOGIN_CHECK_MS, MEMORY_SCAN_MS, CLOUD_GATEWAY_ORIGIN, CLOUD_GATEWAY_BASE_PATH, QUEUED_PROMPT_CLASS, TRACE_DRAIN_TIMEOUT_MS, RECORDER_EVENTS_KEPT, owedBodyPurgeSchema, objectSchema, spoolFileSchema, otlpResourceListSchema, otlpPayloadSchema, defaultExecAsync, STOPPING, STOPPED_EXEC, STATE_WRITE_DEFER_MS;
|
|
60285
60858
|
var init_daemon = __esm({
|
|
60286
60859
|
"../../packages/tacho/src/collector/daemon.ts"() {
|
|
60287
60860
|
"use strict";
|
|
@@ -60357,6 +60930,7 @@ var init_daemon = __esm({
|
|
|
60357
60930
|
init_refused();
|
|
60358
60931
|
init_session_heads();
|
|
60359
60932
|
init_transcript_tailer();
|
|
60933
|
+
IDLE_COMMAND_POLL_FACTOR = 8;
|
|
60360
60934
|
DEFAULT_TIMERS = {
|
|
60361
60935
|
shipMs: 5e3,
|
|
60362
60936
|
bundleRefreshMs: 5 * 6e4,
|
|
@@ -60650,7 +61224,7 @@ import {
|
|
|
60650
61224
|
lstatSync as lstatSync8,
|
|
60651
61225
|
mkdirSync as mkdirSync7,
|
|
60652
61226
|
openSync as openSync8,
|
|
60653
|
-
readSync as
|
|
61227
|
+
readSync as readSync5,
|
|
60654
61228
|
realpathSync as realpathSync6,
|
|
60655
61229
|
writeFileSync as writeFileSync4
|
|
60656
61230
|
} from "node:fs";
|
|
@@ -60696,11 +61270,11 @@ function readBounded(root, relative11, limit = ARP_MAX_BLOB_BYTES) {
|
|
|
60696
61270
|
const bytes = Buffer.alloc(stat7.size);
|
|
60697
61271
|
let offset = 0;
|
|
60698
61272
|
while (offset < bytes.length) {
|
|
60699
|
-
const count12 =
|
|
61273
|
+
const count12 = readSync5(fd2, bytes, offset, bytes.length - offset, offset);
|
|
60700
61274
|
if (!count12) arpFail(`The bundle file ${relative11} changed while it was read.`);
|
|
60701
61275
|
offset += count12;
|
|
60702
61276
|
}
|
|
60703
|
-
if (
|
|
61277
|
+
if (readSync5(fd2, Buffer.alloc(1), 0, 1, offset) !== 0)
|
|
60704
61278
|
arpFail(`The bundle file ${relative11} changed while it was read.`);
|
|
60705
61279
|
return bytes;
|
|
60706
61280
|
} finally {
|
|
@@ -60883,13 +61457,13 @@ function verifySettledEvidence(events) {
|
|
|
60883
61457
|
}
|
|
60884
61458
|
}
|
|
60885
61459
|
if (tools.size || children.size || approvals.size) {
|
|
60886
|
-
const
|
|
61460
|
+
const open7 = [
|
|
60887
61461
|
...[...tools].map((id2) => `tool ${id2}`),
|
|
60888
61462
|
...[...approvals].map((id2) => `approval ${id2}`),
|
|
60889
61463
|
...[...children].map((id2) => `child work ${id2}`)
|
|
60890
61464
|
];
|
|
60891
61465
|
arpFail(
|
|
60892
|
-
`The source has unsettled tools, approvals, or child work at its boundary: ${
|
|
61466
|
+
`The source has unsettled tools, approvals, or child work at its boundary: ${open7.join(", ")}.`
|
|
60893
61467
|
);
|
|
60894
61468
|
}
|
|
60895
61469
|
const present = (value) => value !== void 0 && value !== null && value !== false && !(Array.isArray(value) && value.length === 0);
|
|
@@ -61621,7 +62195,7 @@ import {
|
|
|
61621
62195
|
lstatSync as lstatSync9,
|
|
61622
62196
|
mkdirSync as mkdirSync8,
|
|
61623
62197
|
openSync as openSync9,
|
|
61624
|
-
readSync as
|
|
62198
|
+
readSync as readSync6,
|
|
61625
62199
|
realpathSync as realpathSync7,
|
|
61626
62200
|
rmSync as rmSync9,
|
|
61627
62201
|
writeFileSync as writeFileSync5
|
|
@@ -61647,14 +62221,14 @@ function readRegular(label2, path2, limit) {
|
|
|
61647
62221
|
const bytes = Buffer.alloc(before.size);
|
|
61648
62222
|
let offset = 0;
|
|
61649
62223
|
while (offset < bytes.length) {
|
|
61650
|
-
const count12 =
|
|
62224
|
+
const count12 = readSync6(fd2, bytes, offset, bytes.length - offset, offset);
|
|
61651
62225
|
if (count12 === 0)
|
|
61652
62226
|
arpFail(
|
|
61653
62227
|
`${label2} ${path2} changed while it was read. Stop its writer and capture again.`
|
|
61654
62228
|
);
|
|
61655
62229
|
offset += count12;
|
|
61656
62230
|
}
|
|
61657
|
-
if (
|
|
62231
|
+
if (readSync6(fd2, Buffer.alloc(1), 0, 1, offset) !== 0)
|
|
61658
62232
|
arpFail(
|
|
61659
62233
|
`${label2} ${path2} grew while it was read. Stop its writer and capture again.`
|
|
61660
62234
|
);
|
|
@@ -62672,7 +63246,7 @@ var init_package = __esm({
|
|
|
62672
63246
|
"package.json"() {
|
|
62673
63247
|
package_default = {
|
|
62674
63248
|
name: "@oxagen/cli",
|
|
62675
|
-
version: "2.1.5-
|
|
63249
|
+
version: "2.1.5-69",
|
|
62676
63250
|
description: "Oxagen governance CLI \u2014 spend, lineage, grounding, credentials, and audit (agentic coding lives in the stella CLI)",
|
|
62677
63251
|
type: "module",
|
|
62678
63252
|
main: "./dist/index.js",
|
|
@@ -62768,7 +63342,7 @@ var init_atomic_write = __esm({
|
|
|
62768
63342
|
// src/lib/config.ts
|
|
62769
63343
|
import { homedir as homedir9 } from "os";
|
|
62770
63344
|
import { join as join51 } from "path";
|
|
62771
|
-
import { readFileSync as readFileSync25, mkdirSync as mkdirSync9, existsSync as existsSync27, statSync as
|
|
63345
|
+
import { readFileSync as readFileSync25, mkdirSync as mkdirSync9, existsSync as existsSync27, statSync as statSync16 } from "fs";
|
|
62772
63346
|
function getConfigDir() {
|
|
62773
63347
|
return CONFIG_DIR;
|
|
62774
63348
|
}
|
|
@@ -62798,7 +63372,7 @@ function parseConfig(raw) {
|
|
|
62798
63372
|
function readConfig() {
|
|
62799
63373
|
let identity;
|
|
62800
63374
|
try {
|
|
62801
|
-
const info =
|
|
63375
|
+
const info = statSync16(CONFIG_FILE);
|
|
62802
63376
|
identity = `${info.ino}:${info.size}:${info.mtimeMs}`;
|
|
62803
63377
|
} catch {
|
|
62804
63378
|
cached2 = void 0;
|
|
@@ -81663,14 +82237,17 @@ var init_digest_shared = __esm({
|
|
|
81663
82237
|
});
|
|
81664
82238
|
|
|
81665
82239
|
// ../../packages/oxagen/src/contracts/run.shared.ts
|
|
82240
|
+
var LATEST_ACTIVITY_MESSAGES, LATEST_ACTIVITY_TEXT_MAX;
|
|
81666
82241
|
var init_run_shared = __esm({
|
|
81667
82242
|
"../../packages/oxagen/src/contracts/run.shared.ts"() {
|
|
81668
82243
|
"use strict";
|
|
82244
|
+
LATEST_ACTIVITY_MESSAGES = 5;
|
|
82245
|
+
LATEST_ACTIVITY_TEXT_MAX = 300;
|
|
81669
82246
|
}
|
|
81670
82247
|
});
|
|
81671
82248
|
|
|
81672
82249
|
// ../../packages/oxagen/src/contracts/run.list.ts
|
|
81673
|
-
var runPublicIdSchema, frameSeqSchema, runStatusSchema, runOutcomeSchema, runCostSchema, replayGradeSchema, generatedRunSummarySchema, editedRunSummarySchema, runSummarySchema, operatorKindSchema, RUN_OPERATOR_ROLES, runOperatorRoleSchema, runModelSchema, runMachineSnapshotSchema, runMachineSchema, COMMAND_BLOCKS, HOST_POLL_WINDOW_MS, RUN_PULL_REQUEST_MAX, runPullRequestSchema, runDiffSchema, runAttributionSchema, RUN_PULL_REQUEST_FILTERS, RUN_PAUSE_STATES, runPauseSchema, RUN_REPLAY_FILTERS, RUN_SORT_KEYS, RUN_LIST_TOTAL_BOUND, RUN_LABEL_MAX, runItemSchema, runList;
|
|
82250
|
+
var runPublicIdSchema, frameSeqSchema, runStatusSchema, runOutcomeSchema, runCostSchema, replayGradeSchema, generatedRunSummarySchema, editedRunSummarySchema, runSummarySchema, latestActivitySchema, operatorKindSchema, RUN_OPERATOR_ROLES, runOperatorRoleSchema, runModelSchema, runMachineSnapshotSchema, runMachineSchema, COMMAND_BLOCKS, HOST_POLL_WINDOW_MS, RUN_PULL_REQUEST_MAX, runPullRequestSchema, runDiffSchema, runAttributionSchema, RUN_PULL_REQUEST_FILTERS, RUN_PAUSE_STATES, runPauseSchema, RUN_REPLAY_FILTERS, RUN_SORT_KEYS, RUN_LIST_TOTAL_BOUND, RUN_LABEL_MAX, runItemSchema, runList;
|
|
81674
82251
|
var init_run_list = __esm({
|
|
81675
82252
|
"../../packages/oxagen/src/contracts/run.list.ts"() {
|
|
81676
82253
|
"use strict";
|
|
@@ -81681,6 +82258,7 @@ var init_run_list = __esm({
|
|
|
81681
82258
|
init_run_enrichment();
|
|
81682
82259
|
init_run_fit();
|
|
81683
82260
|
init_digest_shared();
|
|
82261
|
+
init_run_shared();
|
|
81684
82262
|
init_spend_shared();
|
|
81685
82263
|
init_run_shared();
|
|
81686
82264
|
runPublicIdSchema = external_exports.string().regex(/^(arun|tse)_[0-9a-z]+$/, "a run public id (arun_\u2026 or tse_\u2026)");
|
|
@@ -81715,6 +82293,18 @@ var init_run_list = __esm({
|
|
|
81715
82293
|
editedRunSummarySchema,
|
|
81716
82294
|
generatedRunSummarySchema
|
|
81717
82295
|
]);
|
|
82296
|
+
latestActivitySchema = external_exports.object({
|
|
82297
|
+
/** RFC 3339; when the newest message was recorded. */
|
|
82298
|
+
at: external_exports.string().datetime(),
|
|
82299
|
+
messages: external_exports.array(
|
|
82300
|
+
external_exports.object({
|
|
82301
|
+
role: external_exports.enum(["person", "agent"]),
|
|
82302
|
+
text: external_exports.string().max(LATEST_ACTIVITY_TEXT_MAX),
|
|
82303
|
+
/** RFC 3339. */
|
|
82304
|
+
at: external_exports.string().datetime()
|
|
82305
|
+
}).strict()
|
|
82306
|
+
).min(1).max(LATEST_ACTIVITY_MESSAGES)
|
|
82307
|
+
}).strict();
|
|
81718
82308
|
operatorKindSchema = external_exports.enum(["human", "agent", "service"]);
|
|
81719
82309
|
RUN_OPERATOR_ROLES = [
|
|
81720
82310
|
"owner",
|
|
@@ -82132,6 +82722,11 @@ var init_run_list = __esm({
|
|
|
82132
82722
|
* one. With automatic accounts turned off, only a person's is read.
|
|
82133
82723
|
*/
|
|
82134
82724
|
summary: runSummarySchema.nullable(),
|
|
82725
|
+
/**
|
|
82726
|
+
* The last few messages of the run's transcript, newest last. Absent
|
|
82727
|
+
* until the first read of its tail (#6109).
|
|
82728
|
+
*/
|
|
82729
|
+
latestActivity: latestActivitySchema.optional(),
|
|
82135
82730
|
/**
|
|
82136
82731
|
* The pull requests the run's frames name, earliest first. Absent when
|
|
82137
82732
|
* they were not read: the session's frames could not be read (the page
|
|
@@ -87486,7 +88081,7 @@ __export(verify_exports, {
|
|
|
87486
88081
|
readBundle: () => readBundle,
|
|
87487
88082
|
verifyBundle: () => verifyBundle3
|
|
87488
88083
|
});
|
|
87489
|
-
import { existsSync as existsSync30, readFileSync as readFileSync27, statSync as
|
|
88084
|
+
import { existsSync as existsSync30, readFileSync as readFileSync27, statSync as statSync17 } from "node:fs";
|
|
87490
88085
|
import { join as join61 } from "node:path";
|
|
87491
88086
|
function readDirectory(dir) {
|
|
87492
88087
|
const read2 = (name) => {
|
|
@@ -87537,7 +88132,7 @@ function readBundle(path2) {
|
|
|
87537
88132
|
if (!existsSync30(path2)) {
|
|
87538
88133
|
throw new BundleReadError(`${path2} does not exist.`);
|
|
87539
88134
|
}
|
|
87540
|
-
return
|
|
88135
|
+
return statSync17(path2).isDirectory() ? readDirectory(path2) : readZip(path2);
|
|
87541
88136
|
}
|
|
87542
88137
|
function plural3(count12, one, many) {
|
|
87543
88138
|
return `${count12} ${count12 === 1 ? one : many}`;
|
|
@@ -91236,7 +91831,7 @@ var init_upstream_tool = __esm({
|
|
|
91236
91831
|
});
|
|
91237
91832
|
|
|
91238
91833
|
// ../../packages/mcp-studio/src/contract/lock.ts
|
|
91239
|
-
var LOCK_BYTES_MAX, serverVersionSchema, lockPackageSchema, pypiLockFileSchema, fileOnlyForPypi, registryLockPackageSchema, remoteLockSourceSchema, urlOrPackage, transportOnlyWithUrl, launchOnlyWithPackage, registryLockSourceSchema, localLockSourceSchema, mcpLockSourceSchema, DEFINITION_LABELS, fromFitsType, definitionLockSourceSchema, versionSchema, definitionHashSchema, upstreamHashSchema, mcpLockedToolSchema, definitionLockedToolSchema, mcpLockSchema, definitionLockSchema, mcpToolsLockSchema;
|
|
91834
|
+
var LOCK_BYTES_MAX, PACKAGE_NAME_MAX, PACKAGE_VERSION_MAX, LAUNCH_ARG_MAX, LAUNCH_ARGS_MAX, serverVersionSchema, lockPackageSchema, pypiLockFileSchema, fileOnlyForPypi, registryLockPackageSchema, remoteLockSourceSchema, urlOrPackage, transportOnlyWithUrl, launchOnlyWithPackage, registryLockSourceSchema, localLockSourceSchema, mcpLockSourceSchema, DEFINITION_LABELS, fromFitsType, definitionLockSourceSchema, versionSchema, definitionHashSchema, upstreamHashSchema, mcpLockedToolSchema, definitionLockedToolSchema, mcpLockSchema, definitionLockSchema, mcpToolsLockSchema;
|
|
91240
91835
|
var init_lock = __esm({
|
|
91241
91836
|
"../../packages/mcp-studio/src/contract/lock.ts"() {
|
|
91242
91837
|
"use strict";
|
|
@@ -91249,14 +91844,18 @@ var init_lock = __esm({
|
|
|
91249
91844
|
init_primitives();
|
|
91250
91845
|
init_server2();
|
|
91251
91846
|
LOCK_BYTES_MAX = 5 * 1024 * 1024;
|
|
91847
|
+
PACKAGE_NAME_MAX = 214;
|
|
91848
|
+
PACKAGE_VERSION_MAX = 64;
|
|
91849
|
+
LAUNCH_ARG_MAX = 4096;
|
|
91850
|
+
LAUNCH_ARGS_MAX = 1024;
|
|
91252
91851
|
serverVersionSchema = external_exports.string().min(1).max(64).optional().describe(
|
|
91253
91852
|
"The version the server reported in initialize, when it reported one."
|
|
91254
91853
|
);
|
|
91255
91854
|
lockPackageSchema = external_exports.object({
|
|
91256
|
-
name: external_exports.string().min(1).max(
|
|
91855
|
+
name: external_exports.string().min(1).max(PACKAGE_NAME_MAX).describe(
|
|
91257
91856
|
"The package or binary: @modelcontextprotocol/server-filesystem."
|
|
91258
91857
|
),
|
|
91259
|
-
version: external_exports.string().min(1).max(
|
|
91858
|
+
version: external_exports.string().min(1).max(PACKAGE_VERSION_MAX),
|
|
91260
91859
|
digest: sha256Schema2.describe("SHA-256 of the package or binary.")
|
|
91261
91860
|
}).strict();
|
|
91262
91861
|
pypiLockFileSchema = external_exports.object({
|
|
@@ -91359,7 +91958,7 @@ var init_lock = __esm({
|
|
|
91359
91958
|
command: external_exports.string().min(1).max(1024).optional().describe(
|
|
91360
91959
|
"For a package: the command the local gateway runs, npx, uvx, docker, or dnx."
|
|
91361
91960
|
),
|
|
91362
|
-
args: external_exports.array(external_exports.string().max(
|
|
91961
|
+
args: external_exports.array(external_exports.string().max(LAUNCH_ARG_MAX)).max(LAUNCH_ARGS_MAX).optional().describe(
|
|
91363
91962
|
"For a package: the command's arguments. ${NAME} stays for the local gateway to fill from the machine, and $$ writes one $."
|
|
91364
91963
|
),
|
|
91365
91964
|
server_version: serverVersionSchema
|
|
@@ -92018,6 +92617,9 @@ function keyProblems(all, given, type) {
|
|
|
92018
92617
|
}
|
|
92019
92618
|
return problems;
|
|
92020
92619
|
}
|
|
92620
|
+
function fromPackage(texts) {
|
|
92621
|
+
return texts.map((text5) => ({ text: text5, field: "source.registry_type" }));
|
|
92622
|
+
}
|
|
92021
92623
|
function words(slot, given, problems) {
|
|
92022
92624
|
const { argument, label: label2, key } = slot;
|
|
92023
92625
|
const field = key === void 0 ? "source.registry_type" : `source.arguments.${key}`;
|
|
@@ -92057,7 +92659,38 @@ function words(slot, given, problems) {
|
|
|
92057
92659
|
}
|
|
92058
92660
|
return [];
|
|
92059
92661
|
}
|
|
92060
|
-
|
|
92662
|
+
const valueWord = { text: value, field };
|
|
92663
|
+
return argument.type === "named" ? [...fromPackage([literal2(argument.name)]), valueWord] : [valueWord];
|
|
92664
|
+
}
|
|
92665
|
+
function lockLimitProblems(type, pkg, version2, launch) {
|
|
92666
|
+
const problems = [];
|
|
92667
|
+
if (pkg.identifier.length > PACKAGE_NAME_MAX) {
|
|
92668
|
+
problems.push({
|
|
92669
|
+
field: "source.registry_type",
|
|
92670
|
+
message: `the ${type} package's identifier is ${pkg.identifier.length} characters long, and the lock holds at most ${PACKAGE_NAME_MAX}`
|
|
92671
|
+
});
|
|
92672
|
+
}
|
|
92673
|
+
if (version2.length > PACKAGE_VERSION_MAX) {
|
|
92674
|
+
problems.push({
|
|
92675
|
+
field: "source.registry_type",
|
|
92676
|
+
message: `the ${type} package's version is ${version2.length} characters long, and the lock holds at most ${PACKAGE_VERSION_MAX}`
|
|
92677
|
+
});
|
|
92678
|
+
}
|
|
92679
|
+
launch.forEach(({ text: text5, field }, index) => {
|
|
92680
|
+
if (text5.length > LAUNCH_ARG_MAX) {
|
|
92681
|
+
problems.push({
|
|
92682
|
+
field,
|
|
92683
|
+
message: `args[${index}] is ${text5.length} characters long once each $ is written $$, and the lock holds at most ${LAUNCH_ARG_MAX}`
|
|
92684
|
+
});
|
|
92685
|
+
}
|
|
92686
|
+
});
|
|
92687
|
+
if (launch.length > LAUNCH_ARGS_MAX) {
|
|
92688
|
+
problems.push({
|
|
92689
|
+
field: "source.registry_type",
|
|
92690
|
+
message: `the ${type} package's launch has ${launch.length} args, and the lock holds at most ${LAUNCH_ARGS_MAX}`
|
|
92691
|
+
});
|
|
92692
|
+
}
|
|
92693
|
+
return problems;
|
|
92061
92694
|
}
|
|
92062
92695
|
function registryLaunch({
|
|
92063
92696
|
source,
|
|
@@ -92123,18 +92756,22 @@ function registryLaunch({
|
|
|
92123
92756
|
const reference = pinned !== void 0 ? ["--from", literal2(pinned.url), literal2(pkg.identifier)] : [
|
|
92124
92757
|
`${literal2(pkg.identifier)}@${runner.pin === "digest" ? digest6 : literal2(version2)}`
|
|
92125
92758
|
];
|
|
92126
|
-
const
|
|
92127
|
-
...runner.flags,
|
|
92128
|
-
...type === "oci" ? env.flatMap((name) => [
|
|
92759
|
+
const launch = [
|
|
92760
|
+
...fromPackage(runner.flags),
|
|
92761
|
+
...type === "oci" ? env.flatMap((name) => [
|
|
92762
|
+
...fromPackage(["-e"]),
|
|
92763
|
+
{ text: name, field: "source.env" }
|
|
92764
|
+
]) : [],
|
|
92129
92765
|
...runtime.flatMap((slot) => words(slot, given, problems)),
|
|
92130
|
-
...reference,
|
|
92766
|
+
...fromPackage(reference),
|
|
92131
92767
|
...packaged.flatMap((slot) => words(slot, given, problems))
|
|
92132
92768
|
];
|
|
92769
|
+
problems.push(...lockLimitProblems(type, pkg, version2, launch));
|
|
92133
92770
|
if (problems.length > 0) return { ok: false, problems };
|
|
92134
92771
|
return {
|
|
92135
92772
|
ok: true,
|
|
92136
92773
|
command: runner.command,
|
|
92137
|
-
args,
|
|
92774
|
+
args: launch.map((word) => word.text),
|
|
92138
92775
|
package: {
|
|
92139
92776
|
name: pkg.identifier,
|
|
92140
92777
|
version: version2,
|
|
@@ -92148,6 +92785,7 @@ var REGISTRY_RUNNERS2, ONE_VARIABLE;
|
|
|
92148
92785
|
var init_registry_launch = __esm({
|
|
92149
92786
|
"../../packages/mcp-studio/src/model/registry-launch.ts"() {
|
|
92150
92787
|
"use strict";
|
|
92788
|
+
init_lock();
|
|
92151
92789
|
REGISTRY_RUNNERS2 = {
|
|
92152
92790
|
npm: { command: "npx", flags: ["--yes"], pin: "version" },
|
|
92153
92791
|
pypi: { command: "uvx", flags: [], pin: "file" },
|
|
@@ -106293,15 +106931,15 @@ var init_print = __esm({
|
|
|
106293
106931
|
// ── Extensions ─────────────────────────────────────────────────────────────
|
|
106294
106932
|
/** `extend` blocks, one for each run of extensions of the same message. */
|
|
106295
106933
|
extensions(fields, scope, path2) {
|
|
106296
|
-
let
|
|
106934
|
+
let open7;
|
|
106297
106935
|
fields.forEach((field, index) => {
|
|
106298
106936
|
const where = `the extension ${scope === "" ? "" : `${scope}.`}${field.name}`;
|
|
106299
106937
|
if (field.extendee === "")
|
|
106300
106938
|
this.refuse(`${where} names no message to extend`);
|
|
106301
106939
|
if (isFieldSet(field, FieldDescriptorProtoSchema.field.oneofIndex))
|
|
106302
106940
|
this.refuse(`${where} is in a oneof`);
|
|
106303
|
-
if (field.extendee !==
|
|
106304
|
-
if (
|
|
106941
|
+
if (field.extendee !== open7) {
|
|
106942
|
+
if (open7 !== void 0) this.close();
|
|
106305
106943
|
const extendee = this.typeName(
|
|
106306
106944
|
field.extendee,
|
|
106307
106945
|
scope,
|
|
@@ -106311,7 +106949,7 @@ var init_print = __esm({
|
|
|
106311
106949
|
this.gap();
|
|
106312
106950
|
this.line(`extend ${extendee} {`);
|
|
106313
106951
|
this.depth += 1;
|
|
106314
|
-
|
|
106952
|
+
open7 = field.extendee;
|
|
106315
106953
|
}
|
|
106316
106954
|
this.comment([...path2, index]);
|
|
106317
106955
|
this.line(
|
|
@@ -106324,7 +106962,7 @@ var init_print = __esm({
|
|
|
106324
106962
|
)
|
|
106325
106963
|
);
|
|
106326
106964
|
});
|
|
106327
|
-
if (
|
|
106965
|
+
if (open7 !== void 0) this.close();
|
|
106328
106966
|
}
|
|
106329
106967
|
// ── Options ────────────────────────────────────────────────────────────────
|
|
106330
106968
|
/**
|
|
@@ -106820,7 +107458,7 @@ function importOrder(sources, loaded) {
|
|
|
106820
107458
|
const done = /* @__PURE__ */ new Set();
|
|
106821
107459
|
const stack = [];
|
|
106822
107460
|
const onStack = /* @__PURE__ */ new Set();
|
|
106823
|
-
const
|
|
107461
|
+
const open7 = (name, importer) => {
|
|
106824
107462
|
const entry2 = load(name, importer, sources);
|
|
106825
107463
|
loaded.set(name, entry2);
|
|
106826
107464
|
const imports = entry2.kind === "source" ? entry2.parsed.header.imports.map((each) => each.path) : entry2.proto.dependency;
|
|
@@ -106829,7 +107467,7 @@ function importOrder(sources, loaded) {
|
|
|
106829
107467
|
};
|
|
106830
107468
|
for (const root of [...sources.keys()].sort()) {
|
|
106831
107469
|
if (done.has(root)) continue;
|
|
106832
|
-
|
|
107470
|
+
open7(root, void 0);
|
|
106833
107471
|
for (let top = stack.at(-1); top !== void 0; top = stack.at(-1)) {
|
|
106834
107472
|
const next = top.imports[top.next];
|
|
106835
107473
|
top.next += 1;
|
|
@@ -106842,7 +107480,7 @@ function importOrder(sources, loaded) {
|
|
|
106842
107480
|
const at2 = stack.findIndex((frame) => frame.name === next);
|
|
106843
107481
|
throw cycle([...stack.slice(at2).map((frame) => frame.name), next]);
|
|
106844
107482
|
} else if (!done.has(next)) {
|
|
106845
|
-
|
|
107483
|
+
open7(next, top.name);
|
|
106846
107484
|
}
|
|
106847
107485
|
}
|
|
106848
107486
|
}
|
|
@@ -107329,8 +107967,8 @@ var init_json_schema4 = __esm({
|
|
|
107329
107967
|
description: `Cut: messages nest past ${DEPTH_MAX} levels here.`
|
|
107330
107968
|
};
|
|
107331
107969
|
}
|
|
107332
|
-
const
|
|
107333
|
-
if (
|
|
107970
|
+
const open7 = this.active.get(name) ?? 0;
|
|
107971
|
+
if (open7 >= RECURSION_DEPTH) {
|
|
107334
107972
|
this.note(
|
|
107335
107973
|
`Import cut the recursive message ${name} at depth ${RECURSION_DEPTH}.`
|
|
107336
107974
|
);
|
|
@@ -107348,12 +107986,12 @@ var init_json_schema4 = __esm({
|
|
|
107348
107986
|
description: `Cut: this tool's schemas passed ${count8(TOOL_NODES_SOFT_MAX)} nodes.`
|
|
107349
107987
|
};
|
|
107350
107988
|
}
|
|
107351
|
-
this.active.set(name,
|
|
107989
|
+
this.active.set(name, open7 + 1);
|
|
107352
107990
|
try {
|
|
107353
107991
|
return this.fieldsOf(desc, direction, depth);
|
|
107354
107992
|
} finally {
|
|
107355
|
-
if (
|
|
107356
|
-
else this.active.set(name,
|
|
107993
|
+
if (open7 === 0) this.active.delete(name);
|
|
107994
|
+
else this.active.set(name, open7);
|
|
107357
107995
|
}
|
|
107358
107996
|
}
|
|
107359
107997
|
fieldsOf(desc, direction, depth) {
|
|
@@ -107869,7 +108507,7 @@ function selectOutput(outputSchema, select) {
|
|
|
107869
108507
|
return trimObject(outputSchema, selectTree(select));
|
|
107870
108508
|
}
|
|
107871
108509
|
function selectionProblem(selection) {
|
|
107872
|
-
const
|
|
108510
|
+
const open7 = [];
|
|
107873
108511
|
let quoted3 = false;
|
|
107874
108512
|
for (let index = 0; index < selection.length; index += 1) {
|
|
107875
108513
|
const char = selection[index];
|
|
@@ -107879,15 +108517,15 @@ function selectionProblem(selection) {
|
|
|
107879
108517
|
continue;
|
|
107880
108518
|
}
|
|
107881
108519
|
if (char === '"') quoted3 = true;
|
|
107882
|
-
else if (char === "{" || char === "(")
|
|
108520
|
+
else if (char === "{" || char === "(") open7.push(char);
|
|
107883
108521
|
else if (char === "}" || char === ")") {
|
|
107884
108522
|
const expected = char === "}" ? "{" : "(";
|
|
107885
|
-
if (
|
|
108523
|
+
if (open7.pop() !== expected)
|
|
107886
108524
|
return `selection has an unmatched ${char} at character ${index + 1}.`;
|
|
107887
108525
|
}
|
|
107888
108526
|
}
|
|
107889
108527
|
if (quoted3) return "selection has a string with no closing quote.";
|
|
107890
|
-
const unclosed =
|
|
108528
|
+
const unclosed = open7.pop();
|
|
107891
108529
|
if (unclosed !== void 0) return `selection has an unclosed ${unclosed}.`;
|
|
107892
108530
|
if (!/[_A-Za-z]/.test(selection)) return "selection names no field.";
|
|
107893
108531
|
return void 0;
|
|
@@ -109670,8 +110308,7 @@ function locationWithoutQuery(location) {
|
|
|
109670
110308
|
url = new URL(location);
|
|
109671
110309
|
} catch {
|
|
109672
110310
|
const cut = location.search(/[?#]/);
|
|
109673
|
-
|
|
109674
|
-
return head2.replace(/^\/\/[^/]*@/, "//");
|
|
110311
|
+
return withoutUserinfo(cut === -1 ? location : location.slice(0, cut));
|
|
109675
110312
|
}
|
|
109676
110313
|
url.username = "";
|
|
109677
110314
|
url.password = "";
|
|
@@ -109679,6 +110316,13 @@ function locationWithoutQuery(location) {
|
|
|
109679
110316
|
url.hash = "";
|
|
109680
110317
|
return url.href;
|
|
109681
110318
|
}
|
|
110319
|
+
function withoutUserinfo(head2) {
|
|
110320
|
+
const match = UNPARSED_USERINFO.exec(head2);
|
|
110321
|
+
if (match === null) return head2;
|
|
110322
|
+
const prefix = match[1] ?? "";
|
|
110323
|
+
const rest = head2.slice(match[0].length);
|
|
110324
|
+
return rest === "" || /^[\\/]/.test(rest) ? `${prefix}@${rest}` : `${prefix}${rest}`;
|
|
110325
|
+
}
|
|
109682
110326
|
function recordedResponseHeaders(headers) {
|
|
109683
110327
|
const out = /* @__PURE__ */ new Map();
|
|
109684
110328
|
for (const [name, raw] of headers) {
|
|
@@ -109712,12 +110356,13 @@ function recordHttpResponse(response, bytes) {
|
|
|
109712
110356
|
...body2 === void 0 ? {} : { body: body2 }
|
|
109713
110357
|
};
|
|
109714
110358
|
}
|
|
109715
|
-
var REFUSED_RESPONSE_HEADERS;
|
|
110359
|
+
var UNPARSED_USERINFO, REFUSED_RESPONSE_HEADERS;
|
|
109716
110360
|
var init_exchange = __esm({
|
|
109717
110361
|
"../../packages/mcp-studio/src/execute/exchange.ts"() {
|
|
109718
110362
|
"use strict";
|
|
109719
110363
|
init_tests_files();
|
|
109720
110364
|
init_body();
|
|
110365
|
+
UNPARSED_USERINFO = /^([A-Za-z][A-Za-z0-9+.-]*:[\\/]*|[\\/]{2})[^/\\]*@/;
|
|
109721
110366
|
REFUSED_RESPONSE_HEADERS = new Set(
|
|
109722
110367
|
CREDENTIAL_RESPONSE_HEADERS
|
|
109723
110368
|
);
|
|
@@ -110227,14 +110872,17 @@ async function notifyInitialized(session) {
|
|
|
110227
110872
|
});
|
|
110228
110873
|
return read2.ok ? { ok: true, value: void 0 } : read2;
|
|
110229
110874
|
}
|
|
110230
|
-
|
|
110231
|
-
|
|
110232
|
-
const sent = await post(session, {
|
|
110875
|
+
function toolsCallMessage(template, args) {
|
|
110876
|
+
return {
|
|
110233
110877
|
jsonrpc: "2.0",
|
|
110234
110878
|
id: CALL_ID,
|
|
110235
110879
|
method: "tools/call",
|
|
110236
110880
|
params: { name: template.tool, arguments: args }
|
|
110237
|
-
}
|
|
110881
|
+
};
|
|
110882
|
+
}
|
|
110883
|
+
async function callTool2(session) {
|
|
110884
|
+
const { template, args } = session.call;
|
|
110885
|
+
const sent = await post(session, toolsCallMessage(template, args));
|
|
110238
110886
|
if (!sent.ok) return { attempt: sent, exchange: void 0 };
|
|
110239
110887
|
const response = sent.value;
|
|
110240
110888
|
if (response.status < 200 || response.status >= 300) {
|
|
@@ -111150,7 +111798,7 @@ async function attemptCall(call2, context, deadline, settings) {
|
|
|
111150
111798
|
const controller = new AbortController();
|
|
111151
111799
|
const clock2 = new Clock(deadline, context.signal, controller);
|
|
111152
111800
|
try {
|
|
111153
|
-
const opening =
|
|
111801
|
+
const opening = open5(context.transport, {
|
|
111154
111802
|
...call2.request,
|
|
111155
111803
|
deadline_ms: Math.max(1, deadline - Date.now()),
|
|
111156
111804
|
signal: controller.signal
|
|
@@ -111170,7 +111818,7 @@ async function attemptCall(call2, context, deadline, settings) {
|
|
|
111170
111818
|
clock2.dispose();
|
|
111171
111819
|
}
|
|
111172
111820
|
}
|
|
111173
|
-
async function
|
|
111821
|
+
async function open5(transport, request3) {
|
|
111174
111822
|
return transport.grpc(request3);
|
|
111175
111823
|
}
|
|
111176
111824
|
async function read(response, call2, clock2, settings) {
|
|
@@ -130575,6 +131223,19 @@ var init_transport2 = __esm({
|
|
|
130575
131223
|
}
|
|
130576
131224
|
});
|
|
130577
131225
|
|
|
131226
|
+
// ../../packages/mcp-studio/src/execute/request-size.ts
|
|
131227
|
+
var init_request_size = __esm({
|
|
131228
|
+
"../../packages/mcp-studio/src/execute/request-size.ts"() {
|
|
131229
|
+
"use strict";
|
|
131230
|
+
init_body();
|
|
131231
|
+
init_graphql2();
|
|
131232
|
+
init_http();
|
|
131233
|
+
init_mcp();
|
|
131234
|
+
init_shape_input();
|
|
131235
|
+
init_util4();
|
|
131236
|
+
}
|
|
131237
|
+
});
|
|
131238
|
+
|
|
130578
131239
|
// ../../packages/mcp-studio/src/execute/index.ts
|
|
130579
131240
|
var init_execute = __esm({
|
|
130580
131241
|
"../../packages/mcp-studio/src/execute/index.ts"() {
|
|
@@ -130591,6 +131252,7 @@ var init_execute = __esm({
|
|
|
130591
131252
|
init_http();
|
|
130592
131253
|
init_mcp();
|
|
130593
131254
|
init_senders();
|
|
131255
|
+
init_request_size();
|
|
130594
131256
|
init_validate();
|
|
130595
131257
|
init_body();
|
|
130596
131258
|
init_http_call();
|
|
@@ -133294,7 +133956,7 @@ import {
|
|
|
133294
133956
|
mkdirSync as mkdirSync13,
|
|
133295
133957
|
readFileSync as readFileSync30,
|
|
133296
133958
|
readlinkSync as readlinkSync4,
|
|
133297
|
-
statSync as
|
|
133959
|
+
statSync as statSync18
|
|
133298
133960
|
} from "node:fs";
|
|
133299
133961
|
import { dirname as dirname36, isAbsolute as isAbsolute18, join as join64, relative as relative9, resolve as resolve25, sep as sep12 } from "node:path";
|
|
133300
133962
|
function git5(cwd, args, input) {
|
|
@@ -133407,14 +134069,14 @@ function chooseBase(root, ref2) {
|
|
|
133407
134069
|
}
|
|
133408
134070
|
function isFile(path2) {
|
|
133409
134071
|
try {
|
|
133410
|
-
return
|
|
134072
|
+
return statSync18(path2).isFile();
|
|
133411
134073
|
} catch {
|
|
133412
134074
|
return false;
|
|
133413
134075
|
}
|
|
133414
134076
|
}
|
|
133415
134077
|
function isDir(path2) {
|
|
133416
134078
|
try {
|
|
133417
|
-
return
|
|
134079
|
+
return statSync18(path2).isDirectory();
|
|
133418
134080
|
} catch {
|
|
133419
134081
|
return false;
|
|
133420
134082
|
}
|
|
@@ -136706,16 +137368,16 @@ function assignmentValue(bytes, assignment, nameStart, nameEnd) {
|
|
|
136706
137368
|
if (!assignment.names.some((k) => containsLower(name, k))) return null;
|
|
136707
137369
|
while (isBlank2(bytes[p])) p += 1;
|
|
136708
137370
|
if (p >= n2) return null;
|
|
136709
|
-
const
|
|
137371
|
+
const open7 = bytes[p];
|
|
136710
137372
|
let start;
|
|
136711
137373
|
let end;
|
|
136712
137374
|
let quoted3;
|
|
136713
|
-
if (
|
|
137375
|
+
if (open7 === QUOTE || open7 === APOSTROPHE || open7 === BACKTICK) {
|
|
136714
137376
|
start = p + 1;
|
|
136715
137377
|
end = start;
|
|
136716
|
-
while (end < n2 && bytes[end] !==
|
|
137378
|
+
while (end < n2 && bytes[end] !== open7 && bytes[end] !== NEWLINE2)
|
|
136717
137379
|
end += bytes[end] === BACKSLASH ? 2 : 1;
|
|
136718
|
-
if (end >= n2 || bytes[end] !==
|
|
137380
|
+
if (end >= n2 || bytes[end] !== open7) return null;
|
|
136719
137381
|
quoted3 = true;
|
|
136720
137382
|
} else {
|
|
136721
137383
|
start = p;
|
|
@@ -137891,7 +138553,7 @@ __export(logs_exports, {
|
|
|
137891
138553
|
handleLogs: () => handleLogs
|
|
137892
138554
|
});
|
|
137893
138555
|
import { watch } from "node:fs";
|
|
137894
|
-
import { open as
|
|
138556
|
+
import { open as open6, stat as stat6 } from "node:fs/promises";
|
|
137895
138557
|
function formatEntry(entry2) {
|
|
137896
138558
|
const head2 = `${entry2.ts} ${entry2.category.padEnd(11)} ${entry2.event}`;
|
|
137897
138559
|
if (entry2.data === void 0) return head2;
|
|
@@ -137922,7 +138584,7 @@ async function logSize(file) {
|
|
|
137922
138584
|
async function readAppended(file, offset) {
|
|
137923
138585
|
let handle;
|
|
137924
138586
|
try {
|
|
137925
|
-
handle = await
|
|
138587
|
+
handle = await open6(file, "r");
|
|
137926
138588
|
} catch {
|
|
137927
138589
|
return { entries: [], offset: 0 };
|
|
137928
138590
|
}
|