blun-king-cli 9.1.19 → 9.1.21
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/bin/update-notice.js +145 -21
- package/blun.mjs +2052 -176
- package/package.json +1 -1
- package/standard-tools/language-guard/blun_language_guard.py +22 -15
package/blun.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// BLUN_BUILD_INPUT_SHA256:
|
|
2
|
+
// BLUN_BUILD_INPUT_SHA256:18b6ba1c5baca9739e0e2b5c280d073bac714589178a987d0bc9fd63d56020f0
|
|
3
3
|
import { fileURLToPath as __cjsShimFileURLToPath } from 'node:url';
|
|
4
4
|
import { dirname as __cjsShimDirname } from 'node:path';
|
|
5
5
|
const __filename = __cjsShimFileURLToPath(import.meta.url);
|
|
@@ -1167,7 +1167,7 @@ function normalizeBlunToolSchema(schema) {
|
|
|
1167
1167
|
}
|
|
1168
1168
|
function ensureBlunPropertyTypes(schema) {
|
|
1169
1169
|
const normalized = cloneJsonValue(schema);
|
|
1170
|
-
if (!isRecord$
|
|
1170
|
+
if (!isRecord$23(normalized)) throw new Error("JSON Schema root must normalize to an object.");
|
|
1171
1171
|
recurseSchema(normalized);
|
|
1172
1172
|
return normalized;
|
|
1173
1173
|
}
|
|
@@ -1228,7 +1228,7 @@ function resolveLocalJsonPointer(root, ref) {
|
|
|
1228
1228
|
let current = root;
|
|
1229
1229
|
for (const rawPart of ref.slice(2).split("/")) {
|
|
1230
1230
|
const part = unescapeJsonPointerPart(rawPart);
|
|
1231
|
-
if (isRecord$
|
|
1231
|
+
if (isRecord$23(current)) {
|
|
1232
1232
|
if (!hasOwn(current, part)) return { found: false };
|
|
1233
1233
|
current = current[part];
|
|
1234
1234
|
} else if (Array.isArray(current)) {
|
|
@@ -1250,20 +1250,20 @@ function parseJsonPointerArrayIndex(part) {
|
|
|
1250
1250
|
return Number(part);
|
|
1251
1251
|
}
|
|
1252
1252
|
function recurseSchema(node) {
|
|
1253
|
-
if (!isRecord$
|
|
1253
|
+
if (!isRecord$23(node)) return;
|
|
1254
1254
|
visitChildSchemas(node, normalizeProperty);
|
|
1255
1255
|
}
|
|
1256
1256
|
function visitChildSchemas(node, visit) {
|
|
1257
1257
|
for (const { key, kind } of CHILD_SCHEMA_SLOTS) {
|
|
1258
1258
|
const value = node[key];
|
|
1259
1259
|
if (kind === "single") {
|
|
1260
|
-
if (isRecord$
|
|
1260
|
+
if (isRecord$23(value)) visit(value);
|
|
1261
1261
|
} else if (kind === "array") {
|
|
1262
1262
|
if (Array.isArray(value)) for (const item of value) visit(item);
|
|
1263
1263
|
} else if (kind === "map") {
|
|
1264
|
-
if (isRecord$
|
|
1264
|
+
if (isRecord$23(value)) for (const item of Object.values(value)) visit(item);
|
|
1265
1265
|
} else if (kind === "schema-or-array") {
|
|
1266
|
-
if (isRecord$
|
|
1266
|
+
if (isRecord$23(value)) visit(value);
|
|
1267
1267
|
else if (Array.isArray(value)) for (const item of value) visit(item);
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
@@ -1275,7 +1275,7 @@ function childSchemaKeysForParentType(parentType) {
|
|
|
1275
1275
|
});
|
|
1276
1276
|
}
|
|
1277
1277
|
function normalizeProperty(node) {
|
|
1278
|
-
if (!isRecord$
|
|
1278
|
+
if (!isRecord$23(node)) return;
|
|
1279
1279
|
if (!hasOwn(node, "type") && !hasAnyKey(node, TYPE_COMPLETION_SKIP_KEYS)) {
|
|
1280
1280
|
const enumValues = node["enum"];
|
|
1281
1281
|
if (Array.isArray(enumValues) && enumValues.length > 0) node["type"] = inferTypeFromValues(enumValues);
|
|
@@ -1359,14 +1359,14 @@ function hasAnyKey(obj, keys) {
|
|
|
1359
1359
|
}
|
|
1360
1360
|
function cloneJsonValue(value) {
|
|
1361
1361
|
if (Array.isArray(value)) return value.map((item) => cloneJsonValue(item));
|
|
1362
|
-
if (isRecord$
|
|
1362
|
+
if (isRecord$23(value)) {
|
|
1363
1363
|
const cloned = {};
|
|
1364
1364
|
for (const [key, child] of Object.entries(value)) cloned[key] = cloneJsonValue(child);
|
|
1365
1365
|
return cloned;
|
|
1366
1366
|
}
|
|
1367
1367
|
return value;
|
|
1368
1368
|
}
|
|
1369
|
-
function isRecord$
|
|
1369
|
+
function isRecord$23(value) {
|
|
1370
1370
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1371
1371
|
}
|
|
1372
1372
|
function hasOwn(obj, key) {
|
|
@@ -1587,7 +1587,7 @@ function isProviderRateLimitError(error) {
|
|
|
1587
1587
|
if (error instanceof APIProviderRateLimitError) return true;
|
|
1588
1588
|
const statusCode = getStatusCode(error);
|
|
1589
1589
|
if (statusCode !== void 0) return statusCode === 429;
|
|
1590
|
-
const lowerMessage = errorMessage$
|
|
1590
|
+
const lowerMessage = errorMessage$13(error).toLowerCase();
|
|
1591
1591
|
return PROVIDER_RATE_LIMIT_MESSAGE_PATTERNS.some((pattern) => pattern.test(lowerMessage));
|
|
1592
1592
|
}
|
|
1593
1593
|
function getStatusCode(error) {
|
|
@@ -1605,7 +1605,7 @@ function getStatusCode(error) {
|
|
|
1605
1605
|
const responseStatus = responseRecord["status"];
|
|
1606
1606
|
return typeof responseStatus === "number" ? responseStatus : void 0;
|
|
1607
1607
|
}
|
|
1608
|
-
function errorMessage$
|
|
1608
|
+
function errorMessage$13(error) {
|
|
1609
1609
|
return error instanceof Error ? error.message : String(error);
|
|
1610
1610
|
}
|
|
1611
1611
|
var ChatProviderError, APIConnectionError, APITimeoutError, APIStatusError, APIContextOverflowError, APIProviderRateLimitError, APIPaymentRequiredError, APIEmptyResponseError, CompactionStallError$1, NETWORK_RE, TIMEOUT_RE, CONTEXT_OVERFLOW_MESSAGE_PATTERNS, PROVIDER_RATE_LIMIT_MESSAGE_PATTERNS, PROVIDER_QUOTA_EXHAUSTED_MESSAGE_PATTERN, PROVIDER_QUOTA_EXHAUSTED_CONTEXT_PATTERNS, TOOL_EXCHANGE_ADJACENCY_MESSAGE_PATTERNS, STRUCTURAL_REQUEST_MESSAGE_PATTERNS;
|
|
@@ -1824,7 +1824,7 @@ function retryAfterHeaderMs(headers) {
|
|
|
1824
1824
|
const fromDate = Math.max(0, retryAt - Date.now());
|
|
1825
1825
|
return fromDate <= MAX_RETRY_DELAY_MS ? fromDate : null;
|
|
1826
1826
|
}
|
|
1827
|
-
async function readJson(response) {
|
|
1827
|
+
async function readJson$1(response) {
|
|
1828
1828
|
const body = await response.text();
|
|
1829
1829
|
if (body.trim().length === 0) throw new ChatProviderError("Provider returned an empty JSON response.");
|
|
1830
1830
|
try {
|
|
@@ -1924,7 +1924,7 @@ var init_fetch_http_client = __esmMin((() => {
|
|
|
1924
1924
|
signal: options?.signal
|
|
1925
1925
|
}, options?.maxRetries);
|
|
1926
1926
|
if (isStream) return parseServerSentJson(response);
|
|
1927
|
-
return readJson(response);
|
|
1927
|
+
return readJson$1(response);
|
|
1928
1928
|
}
|
|
1929
1929
|
async uploadFile(params, options) {
|
|
1930
1930
|
const form = new FormData();
|
|
@@ -1932,7 +1932,7 @@ var init_fetch_http_client = __esmMin((() => {
|
|
|
1932
1932
|
form.append("file", params.file);
|
|
1933
1933
|
const headers = this.requestHeaders();
|
|
1934
1934
|
headers.delete("content-type");
|
|
1935
|
-
const uploaded = await readJson(await this.fetchWithRetries("/files", {
|
|
1935
|
+
const uploaded = await readJson$1(await this.fetchWithRetries("/files", {
|
|
1936
1936
|
method: "POST",
|
|
1937
1937
|
headers,
|
|
1938
1938
|
body: form,
|
|
@@ -5436,16 +5436,16 @@ function esc(str) {
|
|
|
5436
5436
|
function slugify(input) {
|
|
5437
5437
|
return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
5438
5438
|
}
|
|
5439
|
-
function isObject$
|
|
5439
|
+
function isObject$5(data) {
|
|
5440
5440
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
5441
5441
|
}
|
|
5442
5442
|
function isPlainObject$4(o) {
|
|
5443
|
-
if (isObject$
|
|
5443
|
+
if (isObject$5(o) === false) return false;
|
|
5444
5444
|
const ctor = o.constructor;
|
|
5445
5445
|
if (ctor === void 0) return true;
|
|
5446
5446
|
if (typeof ctor !== "function") return true;
|
|
5447
5447
|
const prot = ctor.prototype;
|
|
5448
|
-
if (isObject$
|
|
5448
|
+
if (isObject$5(prot) === false) return false;
|
|
5449
5449
|
if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) return false;
|
|
5450
5450
|
return true;
|
|
5451
5451
|
}
|
|
@@ -5454,7 +5454,7 @@ function shallowClone(o) {
|
|
|
5454
5454
|
if (Array.isArray(o)) return [...o];
|
|
5455
5455
|
return o;
|
|
5456
5456
|
}
|
|
5457
|
-
function escapeRegex$
|
|
5457
|
+
function escapeRegex$3(str) {
|
|
5458
5458
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5459
5459
|
}
|
|
5460
5460
|
function clone$1(inst, def, params) {
|
|
@@ -6201,7 +6201,7 @@ var init_checks$2 = __esmMin((() => {
|
|
|
6201
6201
|
});
|
|
6202
6202
|
$ZodCheckIncludes = /* @__PURE__ */ $constructor("$ZodCheckIncludes", (inst, def) => {
|
|
6203
6203
|
$ZodCheck.init(inst, def);
|
|
6204
|
-
const escapedRegex = escapeRegex$
|
|
6204
|
+
const escapedRegex = escapeRegex$3(def.includes);
|
|
6205
6205
|
const pattern = new RegExp(typeof def.position === "number" ? `^.{${def.position}}${escapedRegex}` : escapedRegex);
|
|
6206
6206
|
def.pattern = pattern;
|
|
6207
6207
|
inst._zod.onattach.push((inst) => {
|
|
@@ -6224,7 +6224,7 @@ var init_checks$2 = __esmMin((() => {
|
|
|
6224
6224
|
});
|
|
6225
6225
|
$ZodCheckStartsWith = /* @__PURE__ */ $constructor("$ZodCheckStartsWith", (inst, def) => {
|
|
6226
6226
|
$ZodCheck.init(inst, def);
|
|
6227
|
-
const pattern = new RegExp(`^${escapeRegex$
|
|
6227
|
+
const pattern = new RegExp(`^${escapeRegex$3(def.prefix)}.*`);
|
|
6228
6228
|
def.pattern ?? (def.pattern = pattern);
|
|
6229
6229
|
inst._zod.onattach.push((inst) => {
|
|
6230
6230
|
const bag = inst._zod.bag;
|
|
@@ -6246,7 +6246,7 @@ var init_checks$2 = __esmMin((() => {
|
|
|
6246
6246
|
});
|
|
6247
6247
|
$ZodCheckEndsWith = /* @__PURE__ */ $constructor("$ZodCheckEndsWith", (inst, def) => {
|
|
6248
6248
|
$ZodCheck.init(inst, def);
|
|
6249
|
-
const pattern = new RegExp(`.*${escapeRegex$
|
|
6249
|
+
const pattern = new RegExp(`.*${escapeRegex$3(def.suffix)}$`);
|
|
6250
6250
|
def.pattern ?? (def.pattern = pattern);
|
|
6251
6251
|
inst._zod.onattach.push((inst) => {
|
|
6252
6252
|
const bag = inst._zod.bag;
|
|
@@ -7008,7 +7008,7 @@ var init_schemas$2 = __esmMin((() => {
|
|
|
7008
7008
|
}
|
|
7009
7009
|
return propValues;
|
|
7010
7010
|
});
|
|
7011
|
-
const isObject = isObject$
|
|
7011
|
+
const isObject = isObject$5;
|
|
7012
7012
|
const catchall = def.catchall;
|
|
7013
7013
|
let value;
|
|
7014
7014
|
inst._zod.parse = (payload, ctx) => {
|
|
@@ -7108,7 +7108,7 @@ var init_schemas$2 = __esmMin((() => {
|
|
|
7108
7108
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
7109
7109
|
};
|
|
7110
7110
|
let fastpass;
|
|
7111
|
-
const isObject = isObject$
|
|
7111
|
+
const isObject = isObject$5;
|
|
7112
7112
|
const jit = !globalConfig.jitless;
|
|
7113
7113
|
const fastEnabled = jit && allowsEval.value;
|
|
7114
7114
|
const catchall = def.catchall;
|
|
@@ -7203,7 +7203,7 @@ var init_schemas$2 = __esmMin((() => {
|
|
|
7203
7203
|
});
|
|
7204
7204
|
inst._zod.parse = (payload, ctx) => {
|
|
7205
7205
|
const input = payload.value;
|
|
7206
|
-
if (!isObject$
|
|
7206
|
+
if (!isObject$5(input)) {
|
|
7207
7207
|
payload.issues.push({
|
|
7208
7208
|
code: "invalid_type",
|
|
7209
7209
|
expected: "object",
|
|
@@ -7341,7 +7341,7 @@ var init_schemas$2 = __esmMin((() => {
|
|
|
7341
7341
|
const values = getEnumValues(def.entries);
|
|
7342
7342
|
const valuesSet = new Set(values);
|
|
7343
7343
|
inst._zod.values = valuesSet;
|
|
7344
|
-
inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex$
|
|
7344
|
+
inst._zod.pattern = new RegExp(`^(${values.filter((k) => propertyKeyTypes.has(typeof k)).map((o) => typeof o === "string" ? escapeRegex$3(o) : o.toString()).join("|")})$`);
|
|
7345
7345
|
inst._zod.parse = (payload, _ctx) => {
|
|
7346
7346
|
const input = payload.value;
|
|
7347
7347
|
if (valuesSet.has(input)) return payload;
|
|
@@ -7359,7 +7359,7 @@ var init_schemas$2 = __esmMin((() => {
|
|
|
7359
7359
|
if (def.values.length === 0) throw new Error("Cannot create literal schema with no valid values");
|
|
7360
7360
|
const values = new Set(def.values);
|
|
7361
7361
|
inst._zod.values = values;
|
|
7362
|
-
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex$
|
|
7362
|
+
inst._zod.pattern = new RegExp(`^(${def.values.map((o) => typeof o === "string" ? escapeRegex$3(o) : o ? escapeRegex$3(o.toString()) : String(o)).join("|")})$`);
|
|
7363
7363
|
inst._zod.parse = (payload, _ctx) => {
|
|
7364
7364
|
const input = payload.value;
|
|
7365
7365
|
if (values.has(input)) return payload;
|
|
@@ -9987,6 +9987,7 @@ var init_schema = __esmMin((() => {
|
|
|
9987
9987
|
ServicesConfigSchema = object({
|
|
9988
9988
|
blunSearch: BlunServiceConfigSchema.optional(),
|
|
9989
9989
|
blunFetch: BlunServiceConfigSchema.optional(),
|
|
9990
|
+
blunMedia: BlunServiceConfigSchema.optional(),
|
|
9990
9991
|
visionReader: VisionReaderConfigSchema.optional()
|
|
9991
9992
|
});
|
|
9992
9993
|
McpServerCommonFields = {
|
|
@@ -10081,6 +10082,7 @@ var init_schema = __esmMin((() => {
|
|
|
10081
10082
|
ServicesConfigPatchSchema = object({
|
|
10082
10083
|
blunSearch: BlunServiceConfigPatchSchema.optional(),
|
|
10083
10084
|
blunFetch: BlunServiceConfigPatchSchema.optional(),
|
|
10085
|
+
blunMedia: BlunServiceConfigPatchSchema.optional(),
|
|
10084
10086
|
visionReader: VisionReaderConfigPatchSchema.optional()
|
|
10085
10087
|
});
|
|
10086
10088
|
BlunConfigPatchSchema = object({
|
|
@@ -10431,7 +10433,7 @@ function tokenFromWire(wire) {
|
|
|
10431
10433
|
var init_types$17 = __esmMin((() => {}));
|
|
10432
10434
|
//#endregion
|
|
10433
10435
|
//#region ../../packages/oauth/src/utils.ts
|
|
10434
|
-
function isRecord$
|
|
10436
|
+
function isRecord$22(value) {
|
|
10435
10437
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
10436
10438
|
}
|
|
10437
10439
|
var init_utils$1 = __esmMin((() => {}));
|
|
@@ -10755,7 +10757,7 @@ var init_storage = __esmMin((() => {
|
|
|
10755
10757
|
} catch {
|
|
10756
10758
|
return;
|
|
10757
10759
|
}
|
|
10758
|
-
if (!isRecord$
|
|
10760
|
+
if (!isRecord$22(parsed)) return void 0;
|
|
10759
10761
|
return tokenFromWire(parsed);
|
|
10760
10762
|
}
|
|
10761
10763
|
async save(name, token) {
|
|
@@ -10849,15 +10851,15 @@ function extractApiErrorMessage(value) {
|
|
|
10849
10851
|
}
|
|
10850
10852
|
return;
|
|
10851
10853
|
}
|
|
10852
|
-
if (!isRecord$
|
|
10854
|
+
if (!isRecord$22(value)) return void 0;
|
|
10853
10855
|
for (const key of DIRECT_ERROR_KEYS) {
|
|
10854
10856
|
const message = stringField$4(value, key);
|
|
10855
10857
|
if (message !== void 0) return message;
|
|
10856
10858
|
}
|
|
10857
10859
|
const error = value["error"];
|
|
10858
|
-
const errorString = nonEmptyString$
|
|
10860
|
+
const errorString = nonEmptyString$7(error);
|
|
10859
10861
|
if (errorString !== void 0) return errorString;
|
|
10860
|
-
if (isRecord$
|
|
10862
|
+
if (isRecord$22(error)) for (const key of NESTED_ERROR_KEYS) {
|
|
10861
10863
|
const message = stringField$4(error, key);
|
|
10862
10864
|
if (message !== void 0) return message;
|
|
10863
10865
|
}
|
|
@@ -10877,9 +10879,9 @@ async function readApiErrorMessage(response, fallback) {
|
|
|
10877
10879
|
return extractApiErrorMessage(parsed) ?? fallback;
|
|
10878
10880
|
}
|
|
10879
10881
|
function stringField$4(record, key) {
|
|
10880
|
-
return nonEmptyString$
|
|
10882
|
+
return nonEmptyString$7(record[key]);
|
|
10881
10883
|
}
|
|
10882
|
-
function nonEmptyString$
|
|
10884
|
+
function nonEmptyString$7(value) {
|
|
10883
10885
|
if (typeof value !== "string") return void 0;
|
|
10884
10886
|
const trimmed = value.trim();
|
|
10885
10887
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -10947,7 +10949,7 @@ async function postForm(url, params, deviceHeaders, options) {
|
|
|
10947
10949
|
let data = {};
|
|
10948
10950
|
try {
|
|
10949
10951
|
const parsed = await response.json();
|
|
10950
|
-
if (isRecord$
|
|
10952
|
+
if (isRecord$22(parsed)) data = parsed;
|
|
10951
10953
|
} catch {}
|
|
10952
10954
|
return {
|
|
10953
10955
|
status,
|
|
@@ -12859,9 +12861,9 @@ function blunContextWindowsUrl(oauthHost) {
|
|
|
12859
12861
|
return `${(oauthHost ?? process.env["BLUN_OAUTH_HOST"] ?? "https://account.blun.ai").replace(/\/+$/, "")}/api/verbrauch/tarife`;
|
|
12860
12862
|
}
|
|
12861
12863
|
function parseManagedContextWindow(payload, plan) {
|
|
12862
|
-
if (!isRecord$
|
|
12864
|
+
if (!isRecord$22(payload)) return void 0;
|
|
12863
12865
|
const contextWindows = payload["kontext"];
|
|
12864
|
-
if (!isRecord$
|
|
12866
|
+
if (!isRecord$22(contextWindows)) return void 0;
|
|
12865
12867
|
const value = contextWindows[plan];
|
|
12866
12868
|
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : void 0;
|
|
12867
12869
|
}
|
|
@@ -12896,7 +12898,7 @@ function parseManagedUsagePayload(payload) {
|
|
|
12896
12898
|
const plan = typeof rec["plan"] === "string" && rec["plan"].trim().length > 0 ? rec["plan"].trim() : void 0;
|
|
12897
12899
|
const contextWindowTokens = managedContextWindowFrom(rec);
|
|
12898
12900
|
const unlimited = rec["unlimited"] === true;
|
|
12899
|
-
const stand = isRecord$
|
|
12901
|
+
const stand = isRecord$22(rec["stand"]) ? rec["stand"] : void 0;
|
|
12900
12902
|
if (stand !== void 0) for (const [sourceKey, id, label] of ACCOUNT_USAGE_WINDOWS) {
|
|
12901
12903
|
const row = toAccountUsageRow(stand[sourceKey], id, label, unlimited);
|
|
12902
12904
|
if (row !== null) limits.push(row);
|
|
@@ -12906,9 +12908,9 @@ function parseManagedUsagePayload(payload) {
|
|
|
12906
12908
|
const item = rawLimits[idx];
|
|
12907
12909
|
if (!item || typeof item !== "object") continue;
|
|
12908
12910
|
const detailRaw = item["detail"];
|
|
12909
|
-
const detail = isRecord$
|
|
12911
|
+
const detail = isRecord$22(detailRaw) ? detailRaw : item;
|
|
12910
12912
|
const windowRaw = item["window"];
|
|
12911
|
-
const row = toUsageRow(detail, limitLabel(item, detail, isRecord$
|
|
12913
|
+
const row = toUsageRow(detail, limitLabel(item, detail, isRecord$22(windowRaw) ? windowRaw : {}, idx));
|
|
12912
12914
|
if (row !== null) limits.push(row);
|
|
12913
12915
|
}
|
|
12914
12916
|
return {
|
|
@@ -12932,7 +12934,7 @@ function managedContextWindowFrom(payload) {
|
|
|
12932
12934
|
return values.every((value) => value === first) ? first : void 0;
|
|
12933
12935
|
}
|
|
12934
12936
|
function toAccountUsageRow(raw, id, label, accountUnlimited) {
|
|
12935
|
-
if (!isRecord$
|
|
12937
|
+
if (!isRecord$22(raw)) return null;
|
|
12936
12938
|
const used = toInt(raw["verbraucht"]);
|
|
12937
12939
|
const unlimited = accountUnlimited || raw["unlimited"] === true;
|
|
12938
12940
|
const fraction = raw["anteil"];
|
|
@@ -12965,7 +12967,7 @@ function toAccountUsageRow(raw, id, label, accountUnlimited) {
|
|
|
12965
12967
|
};
|
|
12966
12968
|
}
|
|
12967
12969
|
function toUsageRow(raw, defaultLabel) {
|
|
12968
|
-
if (!isRecord$
|
|
12970
|
+
if (!isRecord$22(raw)) return null;
|
|
12969
12971
|
const unlimited = raw["unlimited"] === true;
|
|
12970
12972
|
const limit = toInt(raw["limit"]);
|
|
12971
12973
|
let used = toInt(raw["used"]);
|
|
@@ -13086,7 +13088,7 @@ function isManagedQuotaErrorMessage(message) {
|
|
|
13086
13088
|
return /you(?:'|’)?ve reached your usage limit/.test(normalized) && /billing cycle|quota will be (?:refreshed|reset)|purchase extra usage/.test(normalized);
|
|
13087
13089
|
}
|
|
13088
13090
|
function hasManagedUsageShape(payload) {
|
|
13089
|
-
if (!isRecord$
|
|
13091
|
+
if (!isRecord$22(payload)) return false;
|
|
13090
13092
|
let recognized = false;
|
|
13091
13093
|
if ("context_window_tokens" in payload || "contextWindowTokens" in payload) {
|
|
13092
13094
|
recognized = true;
|
|
@@ -13102,15 +13104,15 @@ function hasManagedUsageShape(payload) {
|
|
|
13102
13104
|
if (!Array.isArray(limits)) return false;
|
|
13103
13105
|
for (let index = 0; index < limits.length; index++) {
|
|
13104
13106
|
const item = limits[index];
|
|
13105
|
-
if (!isRecord$
|
|
13106
|
-
const detail = isRecord$
|
|
13107
|
-
if (toUsageRow(detail, limitLabel(item, detail, isRecord$
|
|
13107
|
+
if (!isRecord$22(item)) return false;
|
|
13108
|
+
const detail = isRecord$22(item["detail"]) ? item["detail"] : item;
|
|
13109
|
+
if (toUsageRow(detail, limitLabel(item, detail, isRecord$22(item["window"]) ? item["window"] : {}, index)) === null) return false;
|
|
13108
13110
|
}
|
|
13109
13111
|
}
|
|
13110
13112
|
if ("stand" in payload) {
|
|
13111
13113
|
recognized = true;
|
|
13112
13114
|
const stand = payload["stand"];
|
|
13113
|
-
if (!isRecord$
|
|
13115
|
+
if (!isRecord$22(stand)) return false;
|
|
13114
13116
|
const windows = ACCOUNT_USAGE_WINDOWS.filter(([sourceKey]) => sourceKey in stand);
|
|
13115
13117
|
if (windows.length === 0) return false;
|
|
13116
13118
|
const unlimited = payload["unlimited"] === true;
|
|
@@ -13206,8 +13208,8 @@ function userExtras(existing, remoteOwnedFields) {
|
|
|
13206
13208
|
return out;
|
|
13207
13209
|
}
|
|
13208
13210
|
function mergeRefreshedModelAlias(existing, remote, remoteOwnedFields) {
|
|
13209
|
-
const current = isRecord$
|
|
13210
|
-
const overrides = cloneOverrides(isRecord$
|
|
13211
|
+
const current = isRecord$22(existing) ? existing : {};
|
|
13212
|
+
const overrides = cloneOverrides(isRecord$22(current["overrides"]) ? current["overrides"] : void 0);
|
|
13211
13213
|
return {
|
|
13212
13214
|
...userExtras(current, remoteOwnedFields),
|
|
13213
13215
|
...remote,
|
|
@@ -13389,7 +13391,7 @@ function parseModelContextLength(item, modelId) {
|
|
|
13389
13391
|
return values[0];
|
|
13390
13392
|
}
|
|
13391
13393
|
function toModelInfo(item) {
|
|
13392
|
-
if (!isRecord$
|
|
13394
|
+
if (!isRecord$22(item) || typeof item["id"] !== "string" || item["id"].length === 0) return;
|
|
13393
13395
|
const contextLength = parseModelContextLength(item, item["id"]);
|
|
13394
13396
|
const displayName = item["display_name"];
|
|
13395
13397
|
const normalizedDisplayName = typeof displayName === "string" && displayName.length > 0 ? displayName : void 0;
|
|
@@ -13476,7 +13478,7 @@ async function fetchManagedBlunCodeModels(options) {
|
|
|
13476
13478
|
throw new Error(message);
|
|
13477
13479
|
}
|
|
13478
13480
|
const payload = await response.json();
|
|
13479
|
-
if (!isRecord$
|
|
13481
|
+
if (!isRecord$22(payload) || !Array.isArray(payload["data"])) throw new Error(`Unexpected models response for ${baseUrl}.`);
|
|
13480
13482
|
return payload["data"].map((item) => toModelInfo(item)).filter((item) => item !== void 0);
|
|
13481
13483
|
}
|
|
13482
13484
|
throw new Error(`Failed to list BLUN models for ${baseUrl}.`);
|
|
@@ -13519,11 +13521,11 @@ function applyManagedBlunCodeConfig(config, options) {
|
|
|
13519
13521
|
apiKey
|
|
13520
13522
|
};
|
|
13521
13523
|
const upstreamKeys = new Set(options.models.map((m) => managedModelKey(m.id)));
|
|
13522
|
-
for (const [key, model] of Object.entries(existingModels)) if (RETIRED_BLUN_MODEL_KEYS.has(key) || isRecord$
|
|
13524
|
+
for (const [key, model] of Object.entries(existingModels)) if (RETIRED_BLUN_MODEL_KEYS.has(key) || isRecord$22(model) && model["provider"] === "managed:blun" && !upstreamKeys.has(key)) delete existingModels[key];
|
|
13523
13525
|
for (const model of options.models) {
|
|
13524
13526
|
const capabilities = capabilitiesForModel(model);
|
|
13525
13527
|
const key = managedModelKey(model.id);
|
|
13526
|
-
const existing = isRecord$
|
|
13528
|
+
const existing = isRecord$22(existingModels[key]) ? existingModels[key] : {};
|
|
13527
13529
|
const supportsAdaptiveThinking = capabilities?.includes("thinking") === true || capabilities?.includes("always_thinking") === true;
|
|
13528
13530
|
existingModels[key] = mergeRefreshedModelAlias(existing, {
|
|
13529
13531
|
provider: BLUN_PROVIDER_NAME$1,
|
|
@@ -13555,6 +13557,10 @@ function applyManagedBlunCodeConfig(config, options) {
|
|
|
13555
13557
|
blunFetch: {
|
|
13556
13558
|
baseUrl: `${auxiliaryBaseUrl}/fetch`,
|
|
13557
13559
|
...serviceCredential
|
|
13560
|
+
},
|
|
13561
|
+
blunMedia: {
|
|
13562
|
+
baseUrl,
|
|
13563
|
+
...serviceCredential
|
|
13558
13564
|
}
|
|
13559
13565
|
};
|
|
13560
13566
|
return {
|
|
@@ -13567,7 +13573,7 @@ function applyManagedBlunCodeLogoutConfig(config) {
|
|
|
13567
13573
|
let removedDefaultModel = false;
|
|
13568
13574
|
const existingModels = config.models ?? {};
|
|
13569
13575
|
for (const [key, model] of Object.entries(existingModels)) {
|
|
13570
|
-
if (!isRecord$
|
|
13576
|
+
if (!isRecord$22(model) || model["provider"] !== "managed:blun") continue;
|
|
13571
13577
|
delete existingModels[key];
|
|
13572
13578
|
if (config.defaultModel === key) removedDefaultModel = true;
|
|
13573
13579
|
}
|
|
@@ -13577,6 +13583,7 @@ function applyManagedBlunCodeLogoutConfig(config) {
|
|
|
13577
13583
|
if (config.services !== void 0) {
|
|
13578
13584
|
delete config.services.blunSearch;
|
|
13579
13585
|
delete config.services.blunFetch;
|
|
13586
|
+
delete config.services.blunMedia;
|
|
13580
13587
|
if (Object.keys(config.services).length === 0) config.services = void 0;
|
|
13581
13588
|
}
|
|
13582
13589
|
}
|
|
@@ -13606,7 +13613,7 @@ function selectDefaultModel(config, models, options) {
|
|
|
13606
13613
|
function canPreserveDefaultModel(existingModels, defaultModel, managedModels) {
|
|
13607
13614
|
if (managedModels.has(defaultModel)) return true;
|
|
13608
13615
|
const existing = existingModels[defaultModel];
|
|
13609
|
-
return isRecord$
|
|
13616
|
+
return isRecord$22(existing) && existing["provider"] !== "managed:blun";
|
|
13610
13617
|
}
|
|
13611
13618
|
function assertPositiveContextLength(model) {
|
|
13612
13619
|
if (!Number.isInteger(model.contextLength) || model.contextLength <= 0) throw new Error(`BLUN model "${model.id}" must include a positive context_length.`);
|
|
@@ -13684,13 +13691,13 @@ function blunManagedQuotaUrl(oauthHost) {
|
|
|
13684
13691
|
return `${(oauthHost ?? process.env["BLUN_OAUTH_HOST"] ?? "https://account.blun.ai").replace(/\/+$/, "")}${MANAGED_QUOTA_PATH}`;
|
|
13685
13692
|
}
|
|
13686
13693
|
function parseManagedQuotaPayload(payload) {
|
|
13687
|
-
if (!isRecord$
|
|
13688
|
-
const plan = nonEmptyString$
|
|
13694
|
+
if (!isRecord$22(payload)) return void 0;
|
|
13695
|
+
const plan = nonEmptyString$6(payload["plan"]);
|
|
13689
13696
|
const paid = payload["bezahlt"];
|
|
13690
13697
|
const creditCents = payload["guthaben_cent"];
|
|
13691
|
-
const billingKind = nonEmptyString$
|
|
13698
|
+
const billingKind = nonEmptyString$6(payload["art"]);
|
|
13692
13699
|
const globalUnlimited = payload["unlimited"];
|
|
13693
|
-
if (plan === void 0 || typeof paid !== "boolean" || !Number.isSafeInteger(creditCents) || creditCents < 0 || billingKind === void 0 || globalUnlimited !== void 0 && typeof globalUnlimited !== "boolean" || !isRecord$
|
|
13700
|
+
if (plan === void 0 || typeof paid !== "boolean" || !Number.isSafeInteger(creditCents) || creditCents < 0 || billingKind === void 0 || globalUnlimited !== void 0 && typeof globalUnlimited !== "boolean" || !isRecord$22(payload["stand"])) return;
|
|
13694
13701
|
if (!hasStrictQuotaStand(payload["stand"], globalUnlimited === true)) return void 0;
|
|
13695
13702
|
const limits = parseManagedUsagePayload(payload).limits;
|
|
13696
13703
|
if (limits.length !== REQUIRED_WINDOWS.length || REQUIRED_WINDOWS.some(([, id]) => limits.filter((row) => row.id === id).length !== 1)) return;
|
|
@@ -13752,7 +13759,7 @@ async function managedQuotaErrorCode(response) {
|
|
|
13752
13759
|
if (response.status !== 403) return "unavailable";
|
|
13753
13760
|
return isManagedQuotaErrorMessage(await readApiErrorMessage(response, "")) ? "unavailable" : "unauthenticated";
|
|
13754
13761
|
}
|
|
13755
|
-
function nonEmptyString$
|
|
13762
|
+
function nonEmptyString$6(value) {
|
|
13756
13763
|
if (typeof value !== "string") return void 0;
|
|
13757
13764
|
const normalized = value.trim();
|
|
13758
13765
|
return normalized.length === 0 ? void 0 : normalized;
|
|
@@ -13760,7 +13767,7 @@ function nonEmptyString$5(value) {
|
|
|
13760
13767
|
function hasStrictQuotaStand(stand, globalUnlimited) {
|
|
13761
13768
|
return REQUIRED_WINDOWS.every(([sourceKey]) => {
|
|
13762
13769
|
const row = stand[sourceKey];
|
|
13763
|
-
if (!isRecord$
|
|
13770
|
+
if (!isRecord$22(row)) return false;
|
|
13764
13771
|
const used = row["verbraucht"];
|
|
13765
13772
|
const rowUnlimited = row["unlimited"];
|
|
13766
13773
|
if (rowUnlimited !== void 0 && typeof rowUnlimited !== "boolean") return false;
|
|
@@ -14312,15 +14319,15 @@ function readModel(config, alias) {
|
|
|
14312
14319
|
const model = config.models?.[alias];
|
|
14313
14320
|
return model === void 0 ? void 0 : model;
|
|
14314
14321
|
}
|
|
14315
|
-
function nonEmptyString$
|
|
14322
|
+
function nonEmptyString$5(value) {
|
|
14316
14323
|
const trimmed = value?.trim();
|
|
14317
14324
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
14318
14325
|
}
|
|
14319
14326
|
function providerApiKey$1(provider) {
|
|
14320
|
-
return nonEmptyString$
|
|
14327
|
+
return nonEmptyString$5(provider.apiKey) ?? nonEmptyString$5(provider.env?.["BLUN_API_KEY"]);
|
|
14321
14328
|
}
|
|
14322
14329
|
function providerBaseUrl(provider) {
|
|
14323
|
-
return nonEmptyString$
|
|
14330
|
+
return nonEmptyString$5(provider.baseUrl) ?? nonEmptyString$5(provider.env?.["BLUN_BASE_URL"]);
|
|
14324
14331
|
}
|
|
14325
14332
|
function collectModelIdsForAliases(config, aliasKeys) {
|
|
14326
14333
|
const ids = /* @__PURE__ */ new Set();
|
|
@@ -14367,6 +14374,14 @@ function providerModelsEqual(config, nextConfig, providerId, aliasKeys) {
|
|
|
14367
14374
|
function providerConfigEqual(config, nextConfig, providerId) {
|
|
14368
14375
|
return JSON.stringify(config.providers[providerId] ?? null) === JSON.stringify(nextConfig.providers[providerId] ?? null);
|
|
14369
14376
|
}
|
|
14377
|
+
function managedServicesEqual(config, nextConfig) {
|
|
14378
|
+
const snapshot = (candidate) => JSON.stringify({
|
|
14379
|
+
blunSearch: candidate.services?.blunSearch ?? null,
|
|
14380
|
+
blunFetch: candidate.services?.blunFetch ?? null,
|
|
14381
|
+
blunMedia: candidate.services?.blunMedia ?? null
|
|
14382
|
+
});
|
|
14383
|
+
return snapshot(config) === snapshot(nextConfig);
|
|
14384
|
+
}
|
|
14370
14385
|
async function refreshProviderModels(host, options = {}) {
|
|
14371
14386
|
const changed = [];
|
|
14372
14387
|
const unchanged = [];
|
|
@@ -14386,7 +14401,7 @@ async function refreshProviderModels(host, options = {}) {
|
|
|
14386
14401
|
failed
|
|
14387
14402
|
};
|
|
14388
14403
|
}
|
|
14389
|
-
const managedApiKey = nonEmptyString$
|
|
14404
|
+
const managedApiKey = nonEmptyString$5(managedProvider?.apiKey);
|
|
14390
14405
|
const managedHasOAuth = managedProvider?.oauth !== void 0;
|
|
14391
14406
|
if (managedWanted && managedProvider !== void 0 && managedProvider.type === "blun" && (managedApiKey !== void 0 || managedHasOAuth)) try {
|
|
14392
14407
|
if (managedApiKey !== void 0 && managedHasOAuth) throw new Error("Managed BLUN OAuth and API key credentials are mutually exclusive.");
|
|
@@ -14414,7 +14429,7 @@ async function refreshProviderModels(host, options = {}) {
|
|
|
14414
14429
|
});
|
|
14415
14430
|
const refreshedAliasKeys = providerAliasKeys(config, BLUN_PROVIDER_NAME$1);
|
|
14416
14431
|
for (const alias of providerAliasKeys(next, BLUN_PROVIDER_NAME$1)) refreshedAliasKeys.add(alias);
|
|
14417
|
-
if (providerModelsEqual(config, next, "managed:blun", refreshedAliasKeys) && config.defaultModel === next.defaultModel) unchanged.push(BLUN_PROVIDER_NAME$1);
|
|
14432
|
+
if (providerModelsEqual(config, next, "managed:blun", refreshedAliasKeys) && config.defaultModel === next.defaultModel && managedServicesEqual(config, next)) unchanged.push(BLUN_PROVIDER_NAME$1);
|
|
14418
14433
|
else {
|
|
14419
14434
|
const { added, removed } = computeChanges(collectModelIdsForAliases(config, refreshedAliasKeys), collectModelIdsForAliases(next, refreshedAliasKeys));
|
|
14420
14435
|
await host.removeProvider(BLUN_PROVIDER_NAME$1);
|
|
@@ -14422,7 +14437,8 @@ async function refreshProviderModels(host, options = {}) {
|
|
|
14422
14437
|
providers: next.providers,
|
|
14423
14438
|
models: next.models,
|
|
14424
14439
|
defaultModel: next.defaultModel,
|
|
14425
|
-
thinking: next.thinking
|
|
14440
|
+
thinking: next.thinking,
|
|
14441
|
+
services: next.services
|
|
14426
14442
|
});
|
|
14427
14443
|
changed.push({
|
|
14428
14444
|
providerId: BLUN_PROVIDER_NAME$1,
|
|
@@ -16051,6 +16067,8 @@ function servicesToToml(services, rawServices) {
|
|
|
16051
16067
|
else delete out["blun_search"];
|
|
16052
16068
|
if (services.blunFetch !== void 0) out["blun_fetch"] = serviceToToml(services.blunFetch);
|
|
16053
16069
|
else delete out["blun_fetch"];
|
|
16070
|
+
if (services.blunMedia !== void 0) out["blun_media"] = serviceToToml(services.blunMedia);
|
|
16071
|
+
else delete out["blun_media"];
|
|
16054
16072
|
if (services.visionReader !== void 0) out["vision_reader"] = visionReaderToToml(services.visionReader);
|
|
16055
16073
|
else delete out["vision_reader"];
|
|
16056
16074
|
return out;
|
|
@@ -20925,11 +20943,11 @@ function parseSkillText(options) {
|
|
|
20925
20943
|
throw error;
|
|
20926
20944
|
}
|
|
20927
20945
|
const frontmatter = parsed.data ?? {};
|
|
20928
|
-
if (!isRecord$
|
|
20946
|
+
if (!isRecord$21(frontmatter)) throw new SkillParseError(`Frontmatter in ${options.skillMdPath} must be a mapping at the top level`);
|
|
20929
20947
|
const metadata = normalizeMetadata(frontmatter);
|
|
20930
20948
|
if (!isSupportedSkillType(metadata.type)) throw new UnsupportedSkillTypeError(metadata.type ?? String(frontmatter["type"]));
|
|
20931
|
-
const name = nonEmptyString$
|
|
20932
|
-
const description = nonEmptyString$
|
|
20949
|
+
const name = nonEmptyString$4(metadata.name);
|
|
20950
|
+
const description = nonEmptyString$4(metadata.description);
|
|
20933
20951
|
if (isDirectorySkill && (name === void 0 || description === void 0)) throw new SkillParseError(`Missing required frontmatter field ${name === void 0 ? "\"name\"" : "\"description\""} in ${options.skillMdPath}`);
|
|
20934
20952
|
const skillPath = posix$2.resolve(options.skillMdPath);
|
|
20935
20953
|
const content = parsed.body.trim();
|
|
@@ -20989,11 +21007,11 @@ function normalizeMetadata(raw) {
|
|
|
20989
21007
|
const key = METADATA_ALIASES[rawKey] ?? rawKey;
|
|
20990
21008
|
out[key] = value;
|
|
20991
21009
|
}
|
|
20992
|
-
const type = nonEmptyString$
|
|
21010
|
+
const type = nonEmptyString$4(out["type"]);
|
|
20993
21011
|
if (type !== void 0) out["type"] = type;
|
|
20994
|
-
const name = nonEmptyString$
|
|
21012
|
+
const name = nonEmptyString$4(out["name"]);
|
|
20995
21013
|
if (name !== void 0) out["name"] = name;
|
|
20996
|
-
const description = nonEmptyString$
|
|
21014
|
+
const description = nonEmptyString$4(out["description"]);
|
|
20997
21015
|
if (description !== void 0) out["description"] = description;
|
|
20998
21016
|
return out;
|
|
20999
21017
|
}
|
|
@@ -21035,10 +21053,10 @@ function tokenizeArgs(raw) {
|
|
|
21035
21053
|
if (hasContent) out.push(current);
|
|
21036
21054
|
return out;
|
|
21037
21055
|
}
|
|
21038
|
-
function nonEmptyString$
|
|
21056
|
+
function nonEmptyString$4(value) {
|
|
21039
21057
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
21040
21058
|
}
|
|
21041
|
-
function isRecord$
|
|
21059
|
+
function isRecord$21(value) {
|
|
21042
21060
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21043
21061
|
}
|
|
21044
21062
|
var import_regexp_escape, FrontmatterError, SkillParseError, UnsupportedSkillTypeError, FENCE, METADATA_ALIASES;
|
|
@@ -21087,14 +21105,14 @@ var init_parser$1 = __esmMin((() => {
|
|
|
21087
21105
|
function parseCommandText(input) {
|
|
21088
21106
|
const { text, commandPath, pluginId } = input;
|
|
21089
21107
|
const parsed = parseFrontmatter(text);
|
|
21090
|
-
const frontmatter = isRecord$
|
|
21108
|
+
const frontmatter = isRecord$20(parsed.data) ? parsed.data : {};
|
|
21091
21109
|
const baseName = input.fallbackName ?? path.basename(commandPath).replace(/\.md$/i, "");
|
|
21092
|
-
const name = nonEmptyString$
|
|
21110
|
+
const name = nonEmptyString$3(frontmatter["name"]) ?? baseName;
|
|
21093
21111
|
const body = parsed.body.trim();
|
|
21094
21112
|
return {
|
|
21095
21113
|
pluginId,
|
|
21096
21114
|
name,
|
|
21097
|
-
description: nonEmptyString$
|
|
21115
|
+
description: nonEmptyString$3(frontmatter["description"]) ?? descriptionFromBody(body),
|
|
21098
21116
|
body,
|
|
21099
21117
|
path: path.resolve(commandPath)
|
|
21100
21118
|
};
|
|
@@ -21121,7 +21139,7 @@ function expandCommandArguments(body, args) {
|
|
|
21121
21139
|
if (!body.includes("$ARGUMENTS") && args.length > 0) return `${replaced}\n\nARGUMENTS: ${args}`;
|
|
21122
21140
|
return replaced;
|
|
21123
21141
|
}
|
|
21124
|
-
function nonEmptyString$
|
|
21142
|
+
function nonEmptyString$3(value) {
|
|
21125
21143
|
return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0;
|
|
21126
21144
|
}
|
|
21127
21145
|
function descriptionFromBody(body) {
|
|
@@ -21129,7 +21147,7 @@ function descriptionFromBody(body) {
|
|
|
21129
21147
|
if (firstLine === void 0) return "No description provided.";
|
|
21130
21148
|
return firstLine.length > 240 ? `${firstLine.slice(0, 239)}…` : firstLine;
|
|
21131
21149
|
}
|
|
21132
|
-
function isRecord$
|
|
21150
|
+
function isRecord$20(value) {
|
|
21133
21151
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21134
21152
|
}
|
|
21135
21153
|
var init_commands = __esmMin((() => {
|
|
@@ -28340,7 +28358,7 @@ var init_load = __esmMin((() => {
|
|
|
28340
28358
|
//#region ../../packages/agent-core/src/profile/default/agent.yaml?raw
|
|
28341
28359
|
var agent_default$1;
|
|
28342
28360
|
var init_agent$3 = __esmMin((() => {
|
|
28343
|
-
agent_default$1 = "name: agent\ndescription: Default BLUN King agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - TaskList\n - TaskOutput\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - ReadMediaFile\n - TodoList\n - Skill\n - WebSearch\n - Agent\n - AgentSwarm\n - FetchURL\n - AskUserQuestion\n - MistakeRecord\n - CodebaseSearch\n - EnterPlanMode\n - ExitPlanMode\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - mcp__*\n\nsubagents:\n coder:\n description: General software engineering agent — the only subagent type with file-editing tools; use it for any delegated task that must modify code.\n explore:\n description: Fast codebase exploration with prompt-enforced read-only behavior.\n plan:\n description: Read-only implementation planning and architecture design.\n";
|
|
28361
|
+
agent_default$1 = "name: agent\ndescription: Default BLUN King agent\n\nsystemPromptPath: ./system.md\npromptVars:\n roleAdditional: ''\n\ntools:\n - Read\n - Write\n - Edit\n - Grep\n - Glob\n - Bash\n - TaskList\n - TaskOutput\n - TaskStop\n - CronCreate\n - CronList\n - CronDelete\n - ReadMediaFile\n - TodoList\n - Skill\n - WebSearch\n - Agent\n - AgentSwarm\n - FetchURL\n - GenerateImage\n - GenerateVideo\n - GenerateSpeech\n - GetMedia\n - AskUserQuestion\n - MistakeRecord\n - CodebaseSearch\n - EnterPlanMode\n - ExitPlanMode\n - CreateGoal\n - GetGoal\n - SetGoalBudget\n - UpdateGoal\n - mcp__*\n\nsubagents:\n coder:\n description: General software engineering agent — the only subagent type with file-editing tools; use it for any delegated task that must modify code.\n explore:\n description: Fast codebase exploration with prompt-enforced read-only behavior.\n plan:\n description: Read-only implementation planning and architecture design.\n";
|
|
28344
28362
|
}));
|
|
28345
28363
|
//#endregion
|
|
28346
28364
|
//#region ../../packages/agent-core/src/profile/default/coder.yaml?raw
|
|
@@ -28476,7 +28494,7 @@ function isAbortError$4(err) {
|
|
|
28476
28494
|
if (err instanceof Error) return err.name === "AbortError";
|
|
28477
28495
|
return false;
|
|
28478
28496
|
}
|
|
28479
|
-
function errorMessage$
|
|
28497
|
+
function errorMessage$12(err) {
|
|
28480
28498
|
if (err instanceof Error) return err.message;
|
|
28481
28499
|
return String(err);
|
|
28482
28500
|
}
|
|
@@ -28700,7 +28718,7 @@ function normalizePersistedTask$1(task) {
|
|
|
28700
28718
|
}
|
|
28701
28719
|
function legacyPersistedTaskToInfo$1(task) {
|
|
28702
28720
|
const status = legacyStatusToCurrent$1(task);
|
|
28703
|
-
const stopReason = optionalNonEmptyString$
|
|
28721
|
+
const stopReason = optionalNonEmptyString$2(task.stop_reason);
|
|
28704
28722
|
const timeoutMs = typeof task.timeout_ms === "number" ? task.timeout_ms : void 0;
|
|
28705
28723
|
const base = {
|
|
28706
28724
|
taskId: task.task_id,
|
|
@@ -28715,8 +28733,8 @@ function legacyPersistedTaskToInfo$1(task) {
|
|
|
28715
28733
|
if (task.task_id.startsWith("agent-")) return {
|
|
28716
28734
|
...base,
|
|
28717
28735
|
kind: "agent",
|
|
28718
|
-
agentId: optionalNonEmptyString$
|
|
28719
|
-
subagentType: optionalNonEmptyString$
|
|
28736
|
+
agentId: optionalNonEmptyString$2(task.agent_id),
|
|
28737
|
+
subagentType: optionalNonEmptyString$2(task.subagent_type)
|
|
28720
28738
|
};
|
|
28721
28739
|
return {
|
|
28722
28740
|
...base,
|
|
@@ -28732,15 +28750,15 @@ function legacyStatusToCurrent$1(task) {
|
|
|
28732
28750
|
return task.status;
|
|
28733
28751
|
}
|
|
28734
28752
|
function isReadablePersistedTask$1(obj) {
|
|
28735
|
-
return isRecord$
|
|
28753
|
+
return isRecord$19(obj) && (typeof obj["taskId"] === "string" || typeof obj["task_id"] === "string");
|
|
28736
28754
|
}
|
|
28737
28755
|
function isLegacyPersistedTask$1(task) {
|
|
28738
28756
|
return "task_id" in task;
|
|
28739
28757
|
}
|
|
28740
|
-
function isRecord$
|
|
28758
|
+
function isRecord$19(value) {
|
|
28741
28759
|
return typeof value === "object" && value !== null;
|
|
28742
28760
|
}
|
|
28743
|
-
function optionalNonEmptyString$
|
|
28761
|
+
function optionalNonEmptyString$2(value) {
|
|
28744
28762
|
if (value === void 0) return void 0;
|
|
28745
28763
|
const trimmed = value.trim();
|
|
28746
28764
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
@@ -28914,7 +28932,7 @@ var init_agent_task = __esmMin((() => {
|
|
|
28914
28932
|
}
|
|
28915
28933
|
await sink.settle({
|
|
28916
28934
|
status: "failed",
|
|
28917
|
-
stopReason: errorMessage$
|
|
28935
|
+
stopReason: errorMessage$12(error)
|
|
28918
28936
|
});
|
|
28919
28937
|
} finally {
|
|
28920
28938
|
sink.signal.removeEventListener("abort", requestAbort);
|
|
@@ -29040,7 +29058,7 @@ var init_process_task = __esmMin((() => {
|
|
|
29040
29058
|
this.exitCode = this.proc.exitCode;
|
|
29041
29059
|
settlement = {
|
|
29042
29060
|
status: sink.signal.aborted ? "killed" : "failed",
|
|
29043
|
-
stopReason: sink.signal.aborted ? void 0 : errorMessage$
|
|
29061
|
+
stopReason: sink.signal.aborted ? void 0 : errorMessage$12(error)
|
|
29044
29062
|
};
|
|
29045
29063
|
} finally {
|
|
29046
29064
|
sink.signal.removeEventListener("abort", requestStop);
|
|
@@ -29114,7 +29132,7 @@ var init_question_task = __esmMin((() => {
|
|
|
29114
29132
|
}
|
|
29115
29133
|
await sink.settle({
|
|
29116
29134
|
status: "failed",
|
|
29117
|
-
stopReason: errorMessage$
|
|
29135
|
+
stopReason: errorMessage$12(error)
|
|
29118
29136
|
});
|
|
29119
29137
|
}
|
|
29120
29138
|
}
|
|
@@ -29676,7 +29694,7 @@ var init_background = __esmMin((() => {
|
|
|
29676
29694
|
})).catch((error) => {
|
|
29677
29695
|
settleWorker({
|
|
29678
29696
|
status: entry.abortController.signal.aborted ? "killed" : "failed",
|
|
29679
|
-
stopReason: entry.abortController.signal.aborted ? void 0 : errorMessage$
|
|
29697
|
+
stopReason: entry.abortController.signal.aborted ? void 0 : errorMessage$12(error)
|
|
29680
29698
|
});
|
|
29681
29699
|
});
|
|
29682
29700
|
const timeout = resettableTimeoutOutcome(entry.options.timeoutMs, { kind: "timeout" });
|
|
@@ -73836,10 +73854,10 @@ function escapeXml(value) {
|
|
|
73836
73854
|
function locationKey(messageIndex, partIndex) {
|
|
73837
73855
|
return `${String(messageIndex)}:${String(partIndex)}`;
|
|
73838
73856
|
}
|
|
73839
|
-
function isRecord$
|
|
73857
|
+
function isRecord$18(value) {
|
|
73840
73858
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
73841
73859
|
}
|
|
73842
|
-
function isNonNegativeInteger(value) {
|
|
73860
|
+
function isNonNegativeInteger$1(value) {
|
|
73843
73861
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
73844
73862
|
}
|
|
73845
73863
|
function abortReason(signal) {
|
|
@@ -74035,7 +74053,7 @@ var init_vision_reader = __esmMin((() => {
|
|
|
74035
74053
|
reason: "malformed"
|
|
74036
74054
|
};
|
|
74037
74055
|
}
|
|
74038
|
-
if (!isRecord$
|
|
74056
|
+
if (!isRecord$18(payload) || payload["done"] !== true || typeof payload["response"] !== "string" || !isNonNegativeInteger$1(payload["prompt_eval_count"]) || !isNonNegativeInteger$1(payload["eval_count"])) return {
|
|
74039
74057
|
ok: false,
|
|
74040
74058
|
reason: "malformed"
|
|
74041
74059
|
};
|
|
@@ -229699,7 +229717,7 @@ async function runHook(command, input, options) {
|
|
|
229699
229717
|
} : void 0
|
|
229700
229718
|
});
|
|
229701
229719
|
} catch (error) {
|
|
229702
|
-
return allowResult({ stderr: errorMessage$
|
|
229720
|
+
return allowResult({ stderr: errorMessage$11(error) });
|
|
229703
229721
|
}
|
|
229704
229722
|
return new Promise((resolve) => {
|
|
229705
229723
|
let stdout = "";
|
|
@@ -229747,7 +229765,7 @@ async function runHook(command, input, options) {
|
|
|
229747
229765
|
child.on("error", (error) => {
|
|
229748
229766
|
settle(allowResult({
|
|
229749
229767
|
stdout,
|
|
229750
|
-
stderr: stderr + errorMessage$
|
|
229768
|
+
stderr: stderr + errorMessage$11(error)
|
|
229751
229769
|
}));
|
|
229752
229770
|
});
|
|
229753
229771
|
child.on("close", (code) => {
|
|
@@ -229867,10 +229885,10 @@ function killProcessTreeWindows(child, force) {
|
|
|
229867
229885
|
} catch {}
|
|
229868
229886
|
}
|
|
229869
229887
|
}
|
|
229870
|
-
function isRecord$
|
|
229888
|
+
function isRecord$17(value) {
|
|
229871
229889
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
229872
229890
|
}
|
|
229873
|
-
function errorMessage$
|
|
229891
|
+
function errorMessage$11(error) {
|
|
229874
229892
|
return error instanceof Error ? error.message : String(error);
|
|
229875
229893
|
}
|
|
229876
229894
|
var DEFAULT_TIMEOUT_SECONDS, KILL_GRACE_MS$2, OptionalStringSchema, HookSpecificOutputSchema, HookJsonOutputSchema;
|
|
@@ -229883,7 +229901,7 @@ var init_runner = __esmMin((() => {
|
|
|
229883
229901
|
if (typeof value === "string") return value;
|
|
229884
229902
|
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") return String(value);
|
|
229885
229903
|
}, string().optional());
|
|
229886
|
-
HookSpecificOutputSchema = preprocess((value) => isRecord$
|
|
229904
|
+
HookSpecificOutputSchema = preprocess((value) => isRecord$17(value) ? value : void 0, looseObject({
|
|
229887
229905
|
message: OptionalStringSchema,
|
|
229888
229906
|
permissionDecision: unknown().optional(),
|
|
229889
229907
|
permissionDecisionReason: OptionalStringSchema
|
|
@@ -230793,7 +230811,7 @@ function parsePersonalMemoryRecall(output) {
|
|
|
230793
230811
|
} catch {
|
|
230794
230812
|
return { kind: "invalid" };
|
|
230795
230813
|
}
|
|
230796
|
-
if (!isRecord$
|
|
230814
|
+
if (!isRecord$16(parsed) || !isRecord$16(parsed["personal_memory"])) return { kind: "invalid" };
|
|
230797
230815
|
const memory = parsed["personal_memory"];
|
|
230798
230816
|
const savedRaw = memory["saved"];
|
|
230799
230817
|
const threadsRaw = memory["threads"];
|
|
@@ -230802,7 +230820,7 @@ function parsePersonalMemoryRecall(output) {
|
|
|
230802
230820
|
if (savedRaw.length > MAX_SAVED_MEMORIES || threadsRaw.length > MAX_THREADS || historyRaw.length > 0) return { kind: "invalid" };
|
|
230803
230821
|
const saved = [];
|
|
230804
230822
|
for (const value of savedRaw) {
|
|
230805
|
-
if (!isRecord$
|
|
230823
|
+
if (!isRecord$16(value)) return { kind: "invalid" };
|
|
230806
230824
|
const text = boundedTrimmedString(value["text"], MAX_MEMORY_TEXT_CHARS);
|
|
230807
230825
|
const confidence = value["confidence"];
|
|
230808
230826
|
if (text === void 0 || typeof confidence !== "string" || !CONFIDENCE_VALUES.has(confidence)) return { kind: "invalid" };
|
|
@@ -230813,7 +230831,7 @@ function parsePersonalMemoryRecall(output) {
|
|
|
230813
230831
|
}
|
|
230814
230832
|
const threads = [];
|
|
230815
230833
|
for (const value of threadsRaw) {
|
|
230816
|
-
if (!isRecord$
|
|
230834
|
+
if (!isRecord$16(value)) return { kind: "invalid" };
|
|
230817
230835
|
const title = boundedTrimmedString(value["title"], MAX_THREAD_TITLE_CHARS);
|
|
230818
230836
|
const summary = boundedTrimmedString(value["summary"], MAX_THREAD_SUMMARY_CHARS);
|
|
230819
230837
|
if (title === void 0 || summary === void 0) return { kind: "invalid" };
|
|
@@ -230867,7 +230885,7 @@ function boundedTrimmedString(value, maxChars) {
|
|
|
230867
230885
|
const trimmed = value.trim();
|
|
230868
230886
|
return trimmed.length > 0 ? trimmed : void 0;
|
|
230869
230887
|
}
|
|
230870
|
-
function isRecord$
|
|
230888
|
+
function isRecord$16(value) {
|
|
230871
230889
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
230872
230890
|
}
|
|
230873
230891
|
var PERSONAL_MEMORY_HOST_RECALL_HANDLER$1, RECALL_LIMIT, RECALL_TIMEOUT_MS, MAX_QUERY_CHARS, MAX_WIRE_CHARS, MAX_SAVED_MEMORIES, MAX_THREADS, MAX_MEMORY_TEXT_CHARS, MAX_THREAD_TITLE_CHARS, MAX_THREAD_SUMMARY_CHARS, CONFIDENCE_VALUES, TELEGRAM_GROUP_MARKER_RE, TELEGRAM_MARKER_RE, TELEGRAM_CHANNEL_RE, TELEGRAM_SOURCE_RE, TELEGRAM_CHAT_ID_RE, TELEGRAM_SENDER_LINE_RE, TELEGRAM_ATTACHMENT_BLOCK_RE, TELEGRAM_ATTACHMENT_NOTICE_RE, TELEGRAM_IMAGE_ATTACHMENT_RE, GENERIC_IMAGE_QUERY, GENERIC_FILE_QUERY, GENERIC_EMPTY_QUERY, PERSONAL_MEMORY_RECALL_VARIANT, PersonalMemoryRecallInjector;
|
|
@@ -231657,7 +231675,7 @@ function createEvidenceApi(dependencies) {
|
|
|
231657
231675
|
var init_mission_contract_evidence = __esmMin((() => {}));
|
|
231658
231676
|
//#endregion
|
|
231659
231677
|
//#region ../../packages/agent-core/src/agent/injection/mission-contract.js
|
|
231660
|
-
var missionContractApi, SCHEMA_VERSION, CONTRACT_STATUSES, REQUIREMENT_TYPES, normalize$2, createDraft, validate$1, publicContract, contractPrompt, redact, createEvidenceState, recordToolStart, recordToolResult, recordFile, recordUrl, recordScreenshot, recordSecurity, recordDecision, recordCheckpoint, evaluateCriteria, canonicalString$1, sha256$
|
|
231678
|
+
var missionContractApi, SCHEMA_VERSION, CONTRACT_STATUSES, REQUIREMENT_TYPES, normalize$2, createDraft, validate$1, publicContract, contractPrompt, redact, createEvidenceState, recordToolStart, recordToolResult, recordFile, recordUrl, recordScreenshot, recordSecurity, recordDecision, recordCheckpoint, evaluateCriteria, canonicalString$1, sha256$4, finalizeEvidence;
|
|
231661
231679
|
var init_mission_contract = __esmMin((() => {
|
|
231662
231680
|
init_mission_contract_evidence();
|
|
231663
231681
|
missionContractApi = (function(root, factory) {
|
|
@@ -231935,7 +231953,7 @@ var init_mission_contract = __esmMin((() => {
|
|
|
231935
231953
|
})
|
|
231936
231954
|
};
|
|
231937
231955
|
});
|
|
231938
|
-
({SCHEMA_VERSION, CONTRACT_STATUSES, REQUIREMENT_TYPES, normalize: normalize$2, createDraft, validate: validate$1, publicContract, contractPrompt, redact, createEvidenceState, recordToolStart, recordToolResult, recordFile, recordUrl, recordScreenshot, recordSecurity, recordDecision, recordCheckpoint, evaluateCriteria, canonicalString: canonicalString$1, sha256: sha256$
|
|
231956
|
+
({SCHEMA_VERSION, CONTRACT_STATUSES, REQUIREMENT_TYPES, normalize: normalize$2, createDraft, validate: validate$1, publicContract, contractPrompt, redact, createEvidenceState, recordToolStart, recordToolResult, recordFile, recordUrl, recordScreenshot, recordSecurity, recordDecision, recordCheckpoint, evaluateCriteria, canonicalString: canonicalString$1, sha256: sha256$4, finalizeEvidence} = missionContractApi);
|
|
231939
231957
|
}));
|
|
231940
231958
|
//#endregion
|
|
231941
231959
|
//#region ../../packages/agent-core/src/agent/injection/mission-contract-bridge.ts
|
|
@@ -242727,7 +242745,7 @@ function parseToolCallArguments$1(raw) {
|
|
|
242727
242745
|
success: true,
|
|
242728
242746
|
data: {},
|
|
242729
242747
|
parseFailed: true,
|
|
242730
|
-
error: errorMessage$
|
|
242748
|
+
error: errorMessage$12(error)
|
|
242731
242749
|
};
|
|
242732
242750
|
}
|
|
242733
242751
|
}
|
|
@@ -242914,7 +242932,7 @@ async function prepareToolCall(step, call) {
|
|
|
242914
242932
|
toolCallId: call.toolCall.id,
|
|
242915
242933
|
error
|
|
242916
242934
|
});
|
|
242917
|
-
return settleError(effectiveArgs, error instanceof PathSecurityError ? error.message : `Tool "${call.toolName}" failed to resolve execution: ${errorMessage$
|
|
242935
|
+
return settleError(effectiveArgs, error instanceof PathSecurityError ? error.message : `Tool "${call.toolName}" failed to resolve execution: ${errorMessage$12(error)}`);
|
|
242918
242936
|
}
|
|
242919
242937
|
const displayFields = toolCallDisplayFieldsFromExecution(execution);
|
|
242920
242938
|
const settleAborted = () => settleError(effectiveArgs, abortedToolOutput(call.toolName, step.signal), displayFields);
|
|
@@ -242977,7 +242995,7 @@ async function runPrepareToolExecutionHook(step, call) {
|
|
|
242977
242995
|
return {
|
|
242978
242996
|
kind: "hookFailed",
|
|
242979
242997
|
args,
|
|
242980
|
-
output: `prepareToolExecution hook failed for "${call.toolName}": ${errorMessage$
|
|
242998
|
+
output: `prepareToolExecution hook failed for "${call.toolName}": ${errorMessage$12(error)}`
|
|
242981
242999
|
};
|
|
242982
243000
|
}
|
|
242983
243001
|
const effectiveArgs = hookResult?.updatedArgs ?? args;
|
|
@@ -243019,7 +243037,7 @@ async function runAuthorizeToolExecutionHook(step, call, args, execution) {
|
|
|
243019
243037
|
};
|
|
243020
243038
|
return {
|
|
243021
243039
|
block: true,
|
|
243022
|
-
reason: `authorizeToolExecution hook failed for "${call.toolName}": ${errorMessage$
|
|
243040
|
+
reason: `authorizeToolExecution hook failed for "${call.toolName}": ${errorMessage$12(error)}`
|
|
243023
243041
|
};
|
|
243024
243042
|
}
|
|
243025
243043
|
}
|
|
@@ -243046,7 +243064,7 @@ async function runRunnableToolCall(step, call, effectiveArgs, metadata, executio
|
|
|
243046
243064
|
toolCallId: toolCall.id,
|
|
243047
243065
|
error
|
|
243048
243066
|
});
|
|
243049
|
-
return makeErrorToolResult(call, effectiveArgs, aborted ? abortedToolOutput(toolName, signal) : `Tool "${toolName}" failed: ${errorMessage$
|
|
243067
|
+
return makeErrorToolResult(call, effectiveArgs, aborted ? abortedToolOutput(toolName, signal) : `Tool "${toolName}" failed: ${errorMessage$12(error)}`);
|
|
243050
243068
|
}
|
|
243051
243069
|
return makeToolResult(call, effectiveArgs, toolResult);
|
|
243052
243070
|
}
|
|
@@ -243079,7 +243097,7 @@ async function finalizePendingToolResult(step, pendingResult) {
|
|
|
243079
243097
|
toolCallId: pendingResult.toolCall.id,
|
|
243080
243098
|
error
|
|
243081
243099
|
});
|
|
243082
|
-
const output = aborted ? `Tool "${pendingResult.toolName}" aborted during finalizeToolResult hook.` : `finalizeToolResult hook failed for "${pendingResult.toolName}": ${errorMessage$
|
|
243100
|
+
const output = aborted ? `Tool "${pendingResult.toolName}" aborted during finalizeToolResult hook.` : `finalizeToolResult hook failed for "${pendingResult.toolName}": ${errorMessage$12(error)}`;
|
|
243083
243101
|
return {
|
|
243084
243102
|
...pendingResult,
|
|
243085
243103
|
stopTurn: pendingResult.stopTurn,
|
|
@@ -243338,8 +243356,8 @@ async function executeLoopStep(deps) {
|
|
|
243338
243356
|
log?.error("strict resend still rejected by provider; request remains wire-invalid", {
|
|
243339
243357
|
turnStep: `${turnId}.${String(currentStep)}`,
|
|
243340
243358
|
model: llm.modelName,
|
|
243341
|
-
originalError: errorMessage$
|
|
243342
|
-
strictError: errorMessage$
|
|
243359
|
+
originalError: errorMessage$12(error),
|
|
243360
|
+
strictError: errorMessage$12(strictError)
|
|
243343
243361
|
});
|
|
243344
243362
|
throw strictError;
|
|
243345
243363
|
}
|
|
@@ -243591,7 +243609,7 @@ async function runTurn(input) {
|
|
|
243591
243609
|
usage
|
|
243592
243610
|
};
|
|
243593
243611
|
}
|
|
243594
|
-
dispatchEvent(makeInterruptedEvent(isMaxStepsExceededError(error) ? "max_steps" : "error", steps, activeStep, errorMessage$
|
|
243612
|
+
dispatchEvent(makeInterruptedEvent(isMaxStepsExceededError(error) ? "max_steps" : "error", steps, activeStep, errorMessage$12(error)));
|
|
243595
243613
|
throw error;
|
|
243596
243614
|
}
|
|
243597
243615
|
return {
|
|
@@ -247004,7 +247022,7 @@ var init_classic = __esmMin((() => {
|
|
|
247004
247022
|
//#region ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/index.js
|
|
247005
247023
|
var init_v4 = __esmMin((() => {
|
|
247006
247024
|
init_classic();
|
|
247007
|
-
})), LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, isInitializedNotification, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, McpError, UrlElicitationRequiredError;
|
|
247025
|
+
})), LATEST_PROTOCOL_VERSION, SUPPORTED_PROTOCOL_VERSIONS, RELATED_TASK_META_KEY, AssertObjectSchema, ProgressTokenSchema, CursorSchema, TaskMetadataSchema, RelatedTaskMetadataSchema, RequestMetaSchema, BaseRequestParamsSchema, TaskAugmentedRequestParamsSchema, isTaskAugmentedRequestParams, RequestSchema, NotificationsParamsSchema, NotificationSchema, ResultSchema, RequestIdSchema, JSONRPCRequestSchema, isJSONRPCRequest, JSONRPCNotificationSchema, isJSONRPCNotification, JSONRPCResultResponseSchema, isJSONRPCResultResponse, ErrorCode, JSONRPCErrorResponseSchema, isJSONRPCErrorResponse, JSONRPCMessageSchema, EmptyResultSchema, CancelledNotificationParamsSchema, CancelledNotificationSchema, IconSchema, IconsSchema, BaseMetadataSchema, ImplementationSchema, FormElicitationCapabilitySchema, ElicitationCapabilitySchema, ClientTasksCapabilitySchema, ServerTasksCapabilitySchema, ClientCapabilitiesSchema, InitializeRequestParamsSchema, InitializeRequestSchema, ServerCapabilitiesSchema, InitializeResultSchema, InitializedNotificationSchema, isInitializedNotification, PingRequestSchema, ProgressSchema, ProgressNotificationParamsSchema, ProgressNotificationSchema, PaginatedRequestParamsSchema, PaginatedRequestSchema, PaginatedResultSchema, TaskStatusSchema, TaskSchema, CreateTaskResultSchema, TaskStatusNotificationParamsSchema, TaskStatusNotificationSchema, GetTaskRequestSchema, GetTaskResultSchema, GetTaskPayloadRequestSchema, ListTasksRequestSchema, ListTasksResultSchema, CancelTaskRequestSchema, CancelTaskResultSchema, ResourceContentsSchema, TextResourceContentsSchema, Base64Schema, BlobResourceContentsSchema, RoleSchema, AnnotationsSchema, ResourceSchema, ResourceTemplateSchema, ListResourcesRequestSchema, ListResourcesResultSchema, ListResourceTemplatesRequestSchema, ListResourceTemplatesResultSchema, ResourceRequestParamsSchema, ReadResourceRequestParamsSchema, ReadResourceRequestSchema, ReadResourceResultSchema, ResourceListChangedNotificationSchema, SubscribeRequestParamsSchema, SubscribeRequestSchema, UnsubscribeRequestParamsSchema, UnsubscribeRequestSchema, ResourceUpdatedNotificationParamsSchema, ResourceUpdatedNotificationSchema, PromptArgumentSchema, PromptSchema$1, ListPromptsRequestSchema, ListPromptsResultSchema, GetPromptRequestParamsSchema, GetPromptRequestSchema, TextContentSchema, ImageContentSchema, AudioContentSchema, ToolUseContentSchema, EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema, PromptMessageSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ToolAnnotationsSchema, ToolExecutionSchema, ToolSchema, ListToolsRequestSchema, ListToolsResultSchema, CallToolResultSchema, CallToolRequestParamsSchema, CallToolRequestSchema, ToolListChangedNotificationSchema, ListChangedOptionsBaseSchema, LoggingLevelSchema, SetLevelRequestParamsSchema, SetLevelRequestSchema, LoggingMessageNotificationParamsSchema, LoggingMessageNotificationSchema, ModelHintSchema, ModelPreferencesSchema, ToolChoiceSchema, ToolResultContentSchema, SamplingContentSchema, SamplingMessageContentBlockSchema, SamplingMessageSchema, CreateMessageRequestParamsSchema, CreateMessageRequestSchema, CreateMessageResultSchema, CreateMessageResultWithToolsSchema, BooleanSchemaSchema, StringSchemaSchema, NumberSchemaSchema, UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema, LegacyTitledEnumSchemaSchema, SingleSelectEnumSchemaSchema, UntitledMultiSelectEnumSchemaSchema, TitledMultiSelectEnumSchemaSchema, MultiSelectEnumSchemaSchema, EnumSchemaSchema, PrimitiveSchemaDefinitionSchema, ElicitRequestFormParamsSchema, ElicitRequestURLParamsSchema, ElicitRequestParamsSchema, ElicitRequestSchema, ElicitationCompleteNotificationParamsSchema, ElicitationCompleteNotificationSchema, ElicitResultSchema, ResourceTemplateReferenceSchema, PromptReferenceSchema, CompleteRequestParamsSchema, CompleteRequestSchema, CompleteResultSchema, RootSchema, ListRootsRequestSchema, ListRootsResultSchema, RootsListChangedNotificationSchema, McpError, UrlElicitationRequiredError;
|
|
247008
247026
|
var init_types$4 = __esmMin((() => {
|
|
247009
247027
|
init_v4();
|
|
247010
247028
|
LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
@@ -247646,7 +247664,7 @@ uri: string() });
|
|
|
247646
247664
|
*/
|
|
247647
247665
|
required: optional(boolean$1())
|
|
247648
247666
|
});
|
|
247649
|
-
PromptSchema = object({
|
|
247667
|
+
PromptSchema$1 = object({
|
|
247650
247668
|
...BaseMetadataSchema.shape,
|
|
247651
247669
|
...IconsSchema.shape,
|
|
247652
247670
|
/**
|
|
@@ -247664,7 +247682,7 @@ uri: string() });
|
|
|
247664
247682
|
_meta: optional(looseObject({}))
|
|
247665
247683
|
});
|
|
247666
247684
|
ListPromptsRequestSchema = PaginatedRequestSchema.extend({ method: literal("prompts/list") });
|
|
247667
|
-
ListPromptsResultSchema = PaginatedResultSchema.extend({ prompts: array(PromptSchema) });
|
|
247685
|
+
ListPromptsResultSchema = PaginatedResultSchema.extend({ prompts: array(PromptSchema$1) });
|
|
247668
247686
|
GetPromptRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
247669
247687
|
/**
|
|
247670
247688
|
* The name of the prompt or prompt template.
|
|
@@ -251881,7 +251899,7 @@ var init_ask_user = __esmMin((() => {
|
|
|
251881
251899
|
} catch (error) {
|
|
251882
251900
|
return {
|
|
251883
251901
|
isError: true,
|
|
251884
|
-
output: errorMessage$
|
|
251902
|
+
output: errorMessage$12(error)
|
|
251885
251903
|
};
|
|
251886
251904
|
}
|
|
251887
251905
|
const status = backgroundManager.getTask(taskId)?.status ?? "running";
|
|
@@ -261057,6 +261075,163 @@ var init_mistake_record = __esmMin((() => {
|
|
|
261057
261075
|
};
|
|
261058
261076
|
}));
|
|
261059
261077
|
//#endregion
|
|
261078
|
+
//#region ../../packages/agent-core/src/tools/builtin/media/blun-media.ts
|
|
261079
|
+
function contentPartFor(mimeType, url) {
|
|
261080
|
+
if (mimeType.startsWith("image/")) return {
|
|
261081
|
+
type: "image_url",
|
|
261082
|
+
imageUrl: { url }
|
|
261083
|
+
};
|
|
261084
|
+
if (mimeType.startsWith("audio/")) return {
|
|
261085
|
+
type: "audio_url",
|
|
261086
|
+
audioUrl: { url }
|
|
261087
|
+
};
|
|
261088
|
+
if (mimeType.startsWith("video/")) return {
|
|
261089
|
+
type: "video_url",
|
|
261090
|
+
videoUrl: { url }
|
|
261091
|
+
};
|
|
261092
|
+
}
|
|
261093
|
+
function errorMessage$10(error) {
|
|
261094
|
+
return error instanceof Error ? error.message : String(error);
|
|
261095
|
+
}
|
|
261096
|
+
var PromptSchema, MediaIdSchema, GenerateImageInputSchema, GenerateVideoInputSchema, GenerateSpeechInputSchema, GetMediaInputSchema, REQUEST_NOTE, MediaGenerationTool, GenerateImageTool, GenerateVideoTool, GenerateSpeechTool, GetMediaTool;
|
|
261097
|
+
var init_blun_media$1 = __esmMin((() => {
|
|
261098
|
+
init_zod$1();
|
|
261099
|
+
init_tool_access();
|
|
261100
|
+
init_input_schema();
|
|
261101
|
+
init_rule_match();
|
|
261102
|
+
PromptSchema = string().trim().min(1).max(2e4);
|
|
261103
|
+
MediaIdSchema = string().trim().min(1).max(200).regex(/^[A-Za-z0-9_-]+$/);
|
|
261104
|
+
GenerateImageInputSchema = object({ prompt: PromptSchema.describe("A complete visual description of the image to generate.") });
|
|
261105
|
+
GenerateVideoInputSchema = object({ prompt: PromptSchema.describe("A complete visual description of the video to generate.") });
|
|
261106
|
+
GenerateSpeechInputSchema = object({ input: PromptSchema.describe("The exact text to synthesize as speech.") });
|
|
261107
|
+
GetMediaInputSchema = object({ id: MediaIdSchema.describe("The media job id returned by a generation tool.") });
|
|
261108
|
+
REQUEST_NOTE = "The request is asynchronous. Use GetMedia with the returned id to check progress and retrieve the result.";
|
|
261109
|
+
MediaGenerationTool = class {
|
|
261110
|
+
provider;
|
|
261111
|
+
constructor(provider) {
|
|
261112
|
+
this.provider = provider;
|
|
261113
|
+
}
|
|
261114
|
+
resolveExecution(args) {
|
|
261115
|
+
const subject = this.subject(args);
|
|
261116
|
+
const preview = subject.length > 60 ? `${subject.slice(0, 60)}...` : subject;
|
|
261117
|
+
return {
|
|
261118
|
+
accesses: ToolAccesses.all(),
|
|
261119
|
+
description: `${this.name}: ${preview}`,
|
|
261120
|
+
approvalRule: literalRulePattern(this.name, subject),
|
|
261121
|
+
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, subject),
|
|
261122
|
+
execute: (ctx) => this.execution(args, ctx)
|
|
261123
|
+
};
|
|
261124
|
+
}
|
|
261125
|
+
async execution(args, ctx) {
|
|
261126
|
+
try {
|
|
261127
|
+
const job = await this.submit(args, {
|
|
261128
|
+
signal: ctx.signal,
|
|
261129
|
+
toolCallId: ctx.toolCallId
|
|
261130
|
+
});
|
|
261131
|
+
return {
|
|
261132
|
+
output: `Media job ${job.id} accepted with status ${job.status}. ${REQUEST_NOTE}`,
|
|
261133
|
+
isError: false
|
|
261134
|
+
};
|
|
261135
|
+
} catch (error) {
|
|
261136
|
+
return {
|
|
261137
|
+
isError: true,
|
|
261138
|
+
output: `Media request failed: ${errorMessage$10(error)}`
|
|
261139
|
+
};
|
|
261140
|
+
}
|
|
261141
|
+
}
|
|
261142
|
+
};
|
|
261143
|
+
GenerateImageTool = class extends MediaGenerationTool {
|
|
261144
|
+
name = "GenerateImage";
|
|
261145
|
+
description = "Generate a new image from text with BLUN IMAGINE. Use this when the user asks to create an image, illustration, logo, or visual. This starts a billed asynchronous media job.";
|
|
261146
|
+
parameters = toInputJsonSchema(GenerateImageInputSchema);
|
|
261147
|
+
subject(args) {
|
|
261148
|
+
return args.prompt;
|
|
261149
|
+
}
|
|
261150
|
+
submit(args, options) {
|
|
261151
|
+
return this.provider.generateImage(args.prompt, options);
|
|
261152
|
+
}
|
|
261153
|
+
};
|
|
261154
|
+
GenerateVideoTool = class extends MediaGenerationTool {
|
|
261155
|
+
name = "GenerateVideo";
|
|
261156
|
+
description = "Generate a new video from text with BLUN media models. Use this for motion or text-to-video requests, not for understanding an existing video. This starts a billed asynchronous media job.";
|
|
261157
|
+
parameters = toInputJsonSchema(GenerateVideoInputSchema);
|
|
261158
|
+
subject(args) {
|
|
261159
|
+
return args.prompt;
|
|
261160
|
+
}
|
|
261161
|
+
submit(args, options) {
|
|
261162
|
+
return this.provider.generateVideo(args.prompt, options);
|
|
261163
|
+
}
|
|
261164
|
+
};
|
|
261165
|
+
GenerateSpeechTool = class extends MediaGenerationTool {
|
|
261166
|
+
name = "GenerateSpeech";
|
|
261167
|
+
description = "Synthesize spoken audio from exact text with BLUN VOICE. Use this for voice or speech generation. This starts a billed asynchronous media job.";
|
|
261168
|
+
parameters = toInputJsonSchema(GenerateSpeechInputSchema);
|
|
261169
|
+
subject(args) {
|
|
261170
|
+
return args.input;
|
|
261171
|
+
}
|
|
261172
|
+
submit(args, options) {
|
|
261173
|
+
return this.provider.generateSpeech(args.input, options);
|
|
261174
|
+
}
|
|
261175
|
+
};
|
|
261176
|
+
GetMediaTool = class {
|
|
261177
|
+
provider;
|
|
261178
|
+
name = "GetMedia";
|
|
261179
|
+
description = "Check a BLUN media job. If it is complete, return the generated image, audio, or video. Use only ids returned by GenerateImage, GenerateVideo, or GenerateSpeech.";
|
|
261180
|
+
parameters = toInputJsonSchema(GetMediaInputSchema);
|
|
261181
|
+
constructor(provider) {
|
|
261182
|
+
this.provider = provider;
|
|
261183
|
+
}
|
|
261184
|
+
resolveExecution(args) {
|
|
261185
|
+
return {
|
|
261186
|
+
accesses: ToolAccesses.all(),
|
|
261187
|
+
description: `GetMedia: ${args.id}`,
|
|
261188
|
+
approvalRule: literalRulePattern(this.name, args.id),
|
|
261189
|
+
matchesRule: (ruleArgs) => matchesGlobRuleSubject(ruleArgs, args.id),
|
|
261190
|
+
execute: (ctx) => this.execution(args, ctx)
|
|
261191
|
+
};
|
|
261192
|
+
}
|
|
261193
|
+
async execution(args, ctx) {
|
|
261194
|
+
try {
|
|
261195
|
+
const result = await this.provider.getMedia(args.id, {
|
|
261196
|
+
signal: ctx.signal,
|
|
261197
|
+
toolCallId: ctx.toolCallId
|
|
261198
|
+
});
|
|
261199
|
+
if (result.kind === "status") {
|
|
261200
|
+
const terminalError = [
|
|
261201
|
+
"failed",
|
|
261202
|
+
"expired",
|
|
261203
|
+
"blocked"
|
|
261204
|
+
].includes(result.status.trim().toLowerCase());
|
|
261205
|
+
const source = result.sourceId === void 0 ? "" : ` Source job ${result.sourceId}${result.sourceStatus === void 0 ? "" : ` status: ${result.sourceStatus}`}.`;
|
|
261206
|
+
const retryable = result.retryable === void 0 ? "" : ` Retryable: ${result.retryable ? "yes" : "no"}.`;
|
|
261207
|
+
return {
|
|
261208
|
+
output: `Media job ${result.id} status: ${result.status}.${source}${retryable}`,
|
|
261209
|
+
isError: terminalError
|
|
261210
|
+
};
|
|
261211
|
+
}
|
|
261212
|
+
const url = `data:${result.mimeType};base64,${Buffer.from(result.data).toString("base64")}`;
|
|
261213
|
+
const mediaPart = contentPartFor(result.mimeType, url);
|
|
261214
|
+
if (mediaPart === void 0) return {
|
|
261215
|
+
isError: true,
|
|
261216
|
+
output: `Media job ${result.id} returned unsupported content type ${result.mimeType}.`
|
|
261217
|
+
};
|
|
261218
|
+
return {
|
|
261219
|
+
output: [{
|
|
261220
|
+
type: "text",
|
|
261221
|
+
text: `Media job ${result.id} is complete.`
|
|
261222
|
+
}, mediaPart],
|
|
261223
|
+
isError: false
|
|
261224
|
+
};
|
|
261225
|
+
} catch (error) {
|
|
261226
|
+
return {
|
|
261227
|
+
isError: true,
|
|
261228
|
+
output: `Media lookup failed: ${errorMessage$10(error)}`
|
|
261229
|
+
};
|
|
261230
|
+
}
|
|
261231
|
+
}
|
|
261232
|
+
};
|
|
261233
|
+
}));
|
|
261234
|
+
//#endregion
|
|
261060
261235
|
//#region ../../packages/agent-core/src/tools/builtin/index.ts
|
|
261061
261236
|
var init_builtin = __esmMin((() => {
|
|
261062
261237
|
init_task_list();
|
|
@@ -261087,6 +261262,7 @@ var init_builtin = __esmMin((() => {
|
|
|
261087
261262
|
init_web_search();
|
|
261088
261263
|
init_codebase_search();
|
|
261089
261264
|
init_mistake_record();
|
|
261265
|
+
init_blun_media$1();
|
|
261090
261266
|
}));
|
|
261091
261267
|
//#endregion
|
|
261092
261268
|
//#region ../../packages/agent-core/src/agent/tool/types.ts
|
|
@@ -261511,6 +261687,10 @@ var init_tool$1 = __esmMin((() => {
|
|
|
261511
261687
|
this.agent.subagentHost && new AgentSwarmTool(this.agent.subagentHost, this.agent.swarmMode),
|
|
261512
261688
|
toolServices?.webSearcher && new WebSearchTool(toolServices.webSearcher),
|
|
261513
261689
|
toolServices?.urlFetcher && new FetchURLTool(toolServices.urlFetcher),
|
|
261690
|
+
toolServices?.media && new GenerateImageTool(toolServices.media),
|
|
261691
|
+
toolServices?.media && new GenerateVideoTool(toolServices.media),
|
|
261692
|
+
toolServices?.media && new GenerateSpeechTool(toolServices.media),
|
|
261693
|
+
toolServices?.media && new GetMediaTool(toolServices.media),
|
|
261514
261694
|
new MistakeRecordTool(this.agent),
|
|
261515
261695
|
new CodebaseSearchTool(cwd)
|
|
261516
261696
|
].filter((tool) => !!tool).map((tool) => [tool.name, tool]));
|
|
@@ -294283,7 +294463,7 @@ async function parseManifest(pluginRoot) {
|
|
|
294283
294463
|
}]
|
|
294284
294464
|
};
|
|
294285
294465
|
}
|
|
294286
|
-
if (!isObject$
|
|
294466
|
+
if (!isObject$4(raw)) return {
|
|
294287
294467
|
manifestKind,
|
|
294288
294468
|
manifestPath,
|
|
294289
294469
|
shadowedManifestPath,
|
|
@@ -294430,7 +294610,7 @@ async function resolvePluginPathField(input) {
|
|
|
294430
294610
|
}
|
|
294431
294611
|
function readSessionStart(raw, diagnostics) {
|
|
294432
294612
|
if (raw === void 0) return void 0;
|
|
294433
|
-
if (!isObject$
|
|
294613
|
+
if (!isObject$4(raw)) {
|
|
294434
294614
|
diagnostics.push({
|
|
294435
294615
|
severity: "warn",
|
|
294436
294616
|
message: "\"sessionStart\" must be an object"
|
|
@@ -294449,7 +294629,7 @@ function readSessionStart(raw, diagnostics) {
|
|
|
294449
294629
|
}
|
|
294450
294630
|
async function readMcpServers(pluginRoot, raw, diagnostics) {
|
|
294451
294631
|
if (raw === void 0) return void 0;
|
|
294452
|
-
if (!isObject$
|
|
294632
|
+
if (!isObject$4(raw)) {
|
|
294453
294633
|
diagnostics.push({
|
|
294454
294634
|
severity: "warn",
|
|
294455
294635
|
message: "\"mcpServers\" must be an object"
|
|
@@ -294600,7 +294780,7 @@ async function normalizePluginMcpServer(input) {
|
|
|
294600
294780
|
}
|
|
294601
294781
|
function readAuthor(raw) {
|
|
294602
294782
|
if (typeof raw === "string") return { name: raw };
|
|
294603
|
-
if (!isObject$
|
|
294783
|
+
if (!isObject$4(raw)) return void 0;
|
|
294604
294784
|
const name = stringField$3(raw, "name");
|
|
294605
294785
|
const email = stringField$3(raw, "email");
|
|
294606
294786
|
if (name === void 0 && email === void 0) return void 0;
|
|
@@ -294610,7 +294790,7 @@ function readAuthor(raw) {
|
|
|
294610
294790
|
};
|
|
294611
294791
|
}
|
|
294612
294792
|
function readInterface(raw) {
|
|
294613
|
-
if (!isObject$
|
|
294793
|
+
if (!isObject$4(raw)) return void 0;
|
|
294614
294794
|
const out = {
|
|
294615
294795
|
displayName: stringField$3(raw, "displayName"),
|
|
294616
294796
|
shortDescription: stringField$3(raw, "shortDescription"),
|
|
@@ -294631,7 +294811,7 @@ function stringArrayField$1(raw, key) {
|
|
|
294631
294811
|
if (!Array.isArray(value) || !value.every((entry) => typeof entry === "string")) return;
|
|
294632
294812
|
return value;
|
|
294633
294813
|
}
|
|
294634
|
-
function isObject$
|
|
294814
|
+
function isObject$4(value) {
|
|
294635
294815
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
294636
294816
|
}
|
|
294637
294817
|
function isWithin$1(child, parent) {
|
|
@@ -302337,7 +302517,7 @@ var init_sort = __esmMin((() => {
|
|
|
302337
302517
|
}));
|
|
302338
302518
|
//#endregion
|
|
302339
302519
|
//#region ../../node_modules/.pnpm/css-select@5.2.2/node_modules/css-select/lib/esm/attributes.js
|
|
302340
|
-
function escapeRegex$
|
|
302520
|
+
function escapeRegex$2(value) {
|
|
302341
302521
|
return value.replace(reChars, "\\$&");
|
|
302342
302522
|
}
|
|
302343
302523
|
function shouldIgnoreCase(selector, options) {
|
|
@@ -302430,7 +302610,7 @@ var init_attributes = __esmMin((() => {
|
|
|
302430
302610
|
const { adapter } = options;
|
|
302431
302611
|
const { name, value } = data;
|
|
302432
302612
|
if (/\s/.test(value)) return import_boolbase$5.default.falseFunc;
|
|
302433
|
-
const regex = new RegExp(`(?:^|\\s)${escapeRegex$
|
|
302613
|
+
const regex = new RegExp(`(?:^|\\s)${escapeRegex$2(value)}(?:$|\\s)`, shouldIgnoreCase(data, options) ? "i" : "");
|
|
302434
302614
|
return function element(elem) {
|
|
302435
302615
|
const attr = adapter.getAttributeValue(elem, name);
|
|
302436
302616
|
return attr != null && attr.length >= value.length && regex.test(attr) && next(elem);
|
|
@@ -302480,7 +302660,7 @@ var init_attributes = __esmMin((() => {
|
|
|
302480
302660
|
const { name, value } = data;
|
|
302481
302661
|
if (value === "") return import_boolbase$5.default.falseFunc;
|
|
302482
302662
|
if (shouldIgnoreCase(data, options)) {
|
|
302483
|
-
const regex = new RegExp(escapeRegex$
|
|
302663
|
+
const regex = new RegExp(escapeRegex$2(value), "i");
|
|
302484
302664
|
return function anyIC(elem) {
|
|
302485
302665
|
const attr = adapter.getAttributeValue(elem, name);
|
|
302486
302666
|
return attr != null && attr.length >= value.length && regex.test(attr) && next(elem);
|
|
@@ -308946,6 +309126,137 @@ var init_blun_web_search = __esmMin((() => {
|
|
|
308946
309126
|
};
|
|
308947
309127
|
}));
|
|
308948
309128
|
//#endregion
|
|
309129
|
+
//#region ../../packages/agent-core/src/tools/providers/blun-media.ts
|
|
309130
|
+
async function parseBlockedStatus(response, id) {
|
|
309131
|
+
let payload = {};
|
|
309132
|
+
try {
|
|
309133
|
+
payload = await response.json();
|
|
309134
|
+
} catch {}
|
|
309135
|
+
const sourceId = payload["source_id"];
|
|
309136
|
+
const sourceStatus = payload["source_status"];
|
|
309137
|
+
const retryable = payload["retryable"];
|
|
309138
|
+
return {
|
|
309139
|
+
kind: "status",
|
|
309140
|
+
id,
|
|
309141
|
+
status: "blocked",
|
|
309142
|
+
...typeof sourceId === "string" && sourceId.length > 0 ? { sourceId } : {},
|
|
309143
|
+
...typeof sourceStatus === "string" && sourceStatus.length > 0 ? { sourceStatus } : {},
|
|
309144
|
+
...typeof retryable === "boolean" ? { retryable } : {}
|
|
309145
|
+
};
|
|
309146
|
+
}
|
|
309147
|
+
function parseJob(payload) {
|
|
309148
|
+
const id = payload["id"];
|
|
309149
|
+
const status = payload["status"];
|
|
309150
|
+
if (typeof id !== "string" || id.length === 0 || typeof status !== "string" || status.length === 0) throw new Error("Media request returned an invalid job response.");
|
|
309151
|
+
return {
|
|
309152
|
+
id,
|
|
309153
|
+
status
|
|
309154
|
+
};
|
|
309155
|
+
}
|
|
309156
|
+
function parseStatus(payload, expectedId) {
|
|
309157
|
+
const id = typeof payload["id"] === "string" && payload["id"].length > 0 ? payload["id"] : expectedId;
|
|
309158
|
+
const status = payload["status"];
|
|
309159
|
+
if (typeof status !== "string" || status.length === 0) throw new Error("Media lookup returned an invalid status response.");
|
|
309160
|
+
return {
|
|
309161
|
+
kind: "status",
|
|
309162
|
+
id,
|
|
309163
|
+
status
|
|
309164
|
+
};
|
|
309165
|
+
}
|
|
309166
|
+
async function assertSuccess(response, operation) {
|
|
309167
|
+
if (response.ok) return;
|
|
309168
|
+
let detail = "";
|
|
309169
|
+
try {
|
|
309170
|
+
detail = (await response.text()).trim();
|
|
309171
|
+
} catch {}
|
|
309172
|
+
throw new Error(`${operation} failed: HTTP ${String(response.status)}${detail ? `: ${detail}` : ""}`);
|
|
309173
|
+
}
|
|
309174
|
+
var BlunMediaService;
|
|
309175
|
+
var init_blun_media = __esmMin((() => {
|
|
309176
|
+
BlunMediaService = class {
|
|
309177
|
+
tokenProvider;
|
|
309178
|
+
apiKey;
|
|
309179
|
+
baseUrl;
|
|
309180
|
+
defaultHeaders;
|
|
309181
|
+
customHeaders;
|
|
309182
|
+
fetchImpl;
|
|
309183
|
+
constructor(options) {
|
|
309184
|
+
this.tokenProvider = options.tokenProvider;
|
|
309185
|
+
this.apiKey = options.apiKey;
|
|
309186
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
309187
|
+
this.defaultHeaders = options.defaultHeaders ?? {};
|
|
309188
|
+
this.customHeaders = options.customHeaders ?? {};
|
|
309189
|
+
this.fetchImpl = options.fetchImpl ?? globalThis.fetch.bind(globalThis);
|
|
309190
|
+
}
|
|
309191
|
+
generateImage(prompt, options) {
|
|
309192
|
+
return this.submit("/images/generations", { prompt }, options);
|
|
309193
|
+
}
|
|
309194
|
+
generateVideo(prompt, options) {
|
|
309195
|
+
return this.submit("/videos/generations", { prompt }, options);
|
|
309196
|
+
}
|
|
309197
|
+
generateSpeech(input, options) {
|
|
309198
|
+
return this.submit("/audio/speech", { input }, options);
|
|
309199
|
+
}
|
|
309200
|
+
async getMedia(id, options) {
|
|
309201
|
+
const response = await this.request(`/media/${encodeURIComponent(id)}`, { method: "GET" }, options);
|
|
309202
|
+
if (response.status === 409) return parseBlockedStatus(response, id);
|
|
309203
|
+
if (response.status === 410) return {
|
|
309204
|
+
kind: "status",
|
|
309205
|
+
id,
|
|
309206
|
+
status: "expired"
|
|
309207
|
+
};
|
|
309208
|
+
await assertSuccess(response, "Media lookup");
|
|
309209
|
+
const mimeType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase() ?? "";
|
|
309210
|
+
if (mimeType === "application/json" || mimeType.endsWith("+json")) return parseStatus(await response.json(), id);
|
|
309211
|
+
if (!mimeType.startsWith("image/") && !mimeType.startsWith("audio/") && !mimeType.startsWith("video/")) throw new Error(`Media lookup returned unsupported content type ${mimeType || "(missing)"}`);
|
|
309212
|
+
return {
|
|
309213
|
+
kind: "file",
|
|
309214
|
+
id,
|
|
309215
|
+
mimeType,
|
|
309216
|
+
data: new Uint8Array(await response.arrayBuffer())
|
|
309217
|
+
};
|
|
309218
|
+
}
|
|
309219
|
+
async submit(path, body, options) {
|
|
309220
|
+
const response = await this.request(path, {
|
|
309221
|
+
method: "POST",
|
|
309222
|
+
body: JSON.stringify(body)
|
|
309223
|
+
}, options);
|
|
309224
|
+
await assertSuccess(response, "Media request");
|
|
309225
|
+
return parseJob(await response.json());
|
|
309226
|
+
}
|
|
309227
|
+
async request(path, init, options) {
|
|
309228
|
+
const firstToken = await this.resolveToken(false);
|
|
309229
|
+
const first = await this.fetchWithToken(path, init, options, firstToken);
|
|
309230
|
+
if (first.status !== 401 || this.tokenProvider === void 0) return first;
|
|
309231
|
+
const refreshed = await this.resolveToken(true);
|
|
309232
|
+
return this.fetchWithToken(path, init, options, refreshed);
|
|
309233
|
+
}
|
|
309234
|
+
fetchWithToken(path, init, options, token) {
|
|
309235
|
+
return this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
309236
|
+
...init,
|
|
309237
|
+
signal: options?.signal,
|
|
309238
|
+
headers: {
|
|
309239
|
+
...this.defaultHeaders,
|
|
309240
|
+
Authorization: `Bearer ${token}`,
|
|
309241
|
+
...init.body === void 0 ? {} : { "Content-Type": "application/json" },
|
|
309242
|
+
...options?.toolCallId === void 0 ? {} : { "X-Msh-Tool-Call-Id": options.toolCallId },
|
|
309243
|
+
...this.customHeaders
|
|
309244
|
+
}
|
|
309245
|
+
});
|
|
309246
|
+
}
|
|
309247
|
+
async resolveToken(force) {
|
|
309248
|
+
if (this.tokenProvider !== void 0) try {
|
|
309249
|
+
return force ? await this.tokenProvider.getAccessToken({ force: true }) : await this.tokenProvider.getAccessToken();
|
|
309250
|
+
} catch (error) {
|
|
309251
|
+
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
309252
|
+
throw error;
|
|
309253
|
+
}
|
|
309254
|
+
if (this.apiKey !== void 0 && this.apiKey.length > 0) return this.apiKey;
|
|
309255
|
+
throw new Error("BLUN media service is not configured: missing API key or OAuth token provider.");
|
|
309256
|
+
}
|
|
309257
|
+
};
|
|
309258
|
+
}));
|
|
309259
|
+
//#endregion
|
|
308949
309260
|
//#region ../../packages/agent-core/src/session/export/manifest.ts
|
|
308950
309261
|
function buildExportManifest(args) {
|
|
308951
309262
|
return {
|
|
@@ -310046,12 +310357,12 @@ function assertBlunProviderType(provider) {
|
|
|
310046
310357
|
if (provider.type !== "blun") throw new BlunError(ErrorCodes.MODEL_CONFIG_INVALID, "Only the BLUN provider type is supported.");
|
|
310047
310358
|
}
|
|
310048
310359
|
function providerValue(configured, env, envKey) {
|
|
310049
|
-
return nonEmptyString$
|
|
310360
|
+
return nonEmptyString$2(configured) ?? envValue(env, envKey);
|
|
310050
310361
|
}
|
|
310051
310362
|
function envValue(env, key) {
|
|
310052
|
-
return nonEmptyString$
|
|
310363
|
+
return nonEmptyString$2(env?.[key]);
|
|
310053
310364
|
}
|
|
310054
|
-
function nonEmptyString$
|
|
310365
|
+
function nonEmptyString$2(value) {
|
|
310055
310366
|
const trimmed = value?.trim();
|
|
310056
310367
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
310057
310368
|
}
|
|
@@ -310682,10 +310993,10 @@ async function appendForkedMarkers(state) {
|
|
|
310682
310993
|
time: Date.now()
|
|
310683
310994
|
};
|
|
310684
310995
|
const agents = state["agents"];
|
|
310685
|
-
if (!isRecord$
|
|
310996
|
+
if (!isRecord$15(agents)) return;
|
|
310686
310997
|
const paths = /* @__PURE__ */ new Set();
|
|
310687
310998
|
for (const agentMeta of Object.values(agents)) {
|
|
310688
|
-
if (!isRecord$
|
|
310999
|
+
if (!isRecord$15(agentMeta)) continue;
|
|
310689
311000
|
const homedir = agentMeta["homedir"];
|
|
310690
311001
|
if (typeof homedir !== "string") continue;
|
|
310691
311002
|
paths.add(join$4(homedir, "wire.jsonl"));
|
|
@@ -310697,7 +311008,7 @@ async function appendForkedMarkers(state) {
|
|
|
310697
311008
|
}));
|
|
310698
311009
|
}
|
|
310699
311010
|
function customMetadataForFork(value) {
|
|
310700
|
-
if (!isRecord$
|
|
311011
|
+
if (!isRecord$15(value)) return {};
|
|
310701
311012
|
const custom = {};
|
|
310702
311013
|
for (const [key, entry] of Object.entries(value)) {
|
|
310703
311014
|
if (key === "goal" || key === "managedQuotaWarningThreshold") continue;
|
|
@@ -310752,10 +311063,10 @@ function normalizeForkTitle(title, fallback) {
|
|
|
310752
311063
|
return typeof fallback === "string" && fallback.trim().length > 0 ? fallback : "New Session";
|
|
310753
311064
|
}
|
|
310754
311065
|
function rewriteAgentHomedirs(value, sourceDir, targetDir) {
|
|
310755
|
-
if (!isRecord$
|
|
311066
|
+
if (!isRecord$15(value)) return {};
|
|
310756
311067
|
const agents = {};
|
|
310757
311068
|
for (const [agentId, agentMeta] of Object.entries(value)) {
|
|
310758
|
-
if (!isRecord$
|
|
311069
|
+
if (!isRecord$15(agentMeta)) {
|
|
310759
311070
|
agents[agentId] = agentMeta;
|
|
310760
311071
|
continue;
|
|
310761
311072
|
}
|
|
@@ -310773,7 +311084,7 @@ function remapSessionPath(value, sourceDir, targetDir) {
|
|
|
310773
311084
|
if (rel.startsWith("..") || isAbsolute$2(rel)) return value;
|
|
310774
311085
|
return join$4(targetDir, rel);
|
|
310775
311086
|
}
|
|
310776
|
-
function isRecord$
|
|
311087
|
+
function isRecord$15(value) {
|
|
310777
311088
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
310778
311089
|
}
|
|
310779
311090
|
async function statIfExists(path) {
|
|
@@ -311021,7 +311332,7 @@ var init_session_store$1 = __esmMin((() => {
|
|
|
311021
311332
|
} catch (error) {
|
|
311022
311333
|
throw new BlunError(ErrorCodes.SESSION_STATE_NOT_FOUND, `Session "${input.sourceId}" state.json was not found`, { cause: error });
|
|
311023
311334
|
}
|
|
311024
|
-
if (!isRecord$
|
|
311335
|
+
if (!isRecord$15(parsed)) throw new BlunError(ErrorCodes.SESSION_STATE_INVALID, `Session "${input.sourceId}" state.json is invalid`);
|
|
311025
311336
|
const title = normalizeForkTitle(input.title, parsed["title"]);
|
|
311026
311337
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
311027
311338
|
const next = {
|
|
@@ -312204,6 +312515,7 @@ async function createRuntimeConfig(input) {
|
|
|
312204
312515
|
const localFetcher = new LocalFetchURLProvider();
|
|
312205
312516
|
const searchService = input.config.services?.blunSearch;
|
|
312206
312517
|
const fetchService = input.config.services?.blunFetch;
|
|
312518
|
+
const mediaService = input.config.services?.blunMedia ?? managedBlunMediaService(input.config);
|
|
312207
312519
|
return {
|
|
312208
312520
|
urlFetcher: fetchService?.baseUrl === void 0 ? localFetcher : new BlunFetchURLProvider({
|
|
312209
312521
|
baseUrl: fetchService.baseUrl,
|
|
@@ -312215,17 +312527,33 @@ async function createRuntimeConfig(input) {
|
|
|
312215
312527
|
baseUrl: searchService.baseUrl,
|
|
312216
312528
|
defaultHeaders: input.blunRequestHeaders,
|
|
312217
312529
|
...serviceCredentials(searchService, input.resolveOAuthTokenProvider)
|
|
312530
|
+
}),
|
|
312531
|
+
media: mediaService?.baseUrl === void 0 ? void 0 : new BlunMediaService({
|
|
312532
|
+
baseUrl: mediaService.baseUrl,
|
|
312533
|
+
defaultHeaders: input.blunRequestHeaders,
|
|
312534
|
+
...serviceCredentials(mediaService, input.resolveOAuthTokenProvider)
|
|
312218
312535
|
})
|
|
312219
312536
|
};
|
|
312220
312537
|
}
|
|
312538
|
+
function managedBlunMediaService(config) {
|
|
312539
|
+
const provider = config.providers[BLUN_PROVIDER_NAME];
|
|
312540
|
+
if (provider?.type !== "blun") return void 0;
|
|
312541
|
+
const baseUrl = nonEmptyString$1(provider.baseUrl);
|
|
312542
|
+
if (baseUrl === void 0) return void 0;
|
|
312543
|
+
return {
|
|
312544
|
+
baseUrl,
|
|
312545
|
+
apiKey: provider.apiKey,
|
|
312546
|
+
oauth: provider.oauth
|
|
312547
|
+
};
|
|
312548
|
+
}
|
|
312221
312549
|
function serviceCredentials(service, resolveOAuthTokenProvider) {
|
|
312222
312550
|
return {
|
|
312223
|
-
apiKey: nonEmptyString(service.apiKey),
|
|
312551
|
+
apiKey: nonEmptyString$1(service.apiKey),
|
|
312224
312552
|
tokenProvider: service.oauth !== void 0 ? resolveOAuthTokenProvider?.(BLUN_PROVIDER_NAME, service.oauth) : void 0,
|
|
312225
312553
|
customHeaders: service.customHeaders
|
|
312226
312554
|
};
|
|
312227
312555
|
}
|
|
312228
|
-
function nonEmptyString(value) {
|
|
312556
|
+
function nonEmptyString$1(value) {
|
|
312229
312557
|
const trimmed = value?.trim();
|
|
312230
312558
|
return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
|
|
312231
312559
|
}
|
|
@@ -312309,6 +312637,7 @@ var init_core_impl = __esmMin((() => {
|
|
|
312309
312637
|
init_local_fetch_url();
|
|
312310
312638
|
init_blun_fetch_url();
|
|
312311
312639
|
init_blun_web_search();
|
|
312640
|
+
init_blun_media();
|
|
312312
312641
|
init_version();
|
|
312313
312642
|
init_thinking();
|
|
312314
312643
|
init_agent();
|
|
@@ -324034,7 +324363,7 @@ var SDKRpcClientBase = class {
|
|
|
324034
324363
|
type: "error",
|
|
324035
324364
|
sessionId: request.sessionId,
|
|
324036
324365
|
agentId: request.agentId,
|
|
324037
|
-
...makeErrorPayload(ErrorCodes.SESSION_APPROVAL_HANDLER_ERROR, errorMessage$
|
|
324366
|
+
...makeErrorPayload(ErrorCodes.SESSION_APPROVAL_HANDLER_ERROR, errorMessage$9(error))
|
|
324038
324367
|
});
|
|
324039
324368
|
return {
|
|
324040
324369
|
decision: "cancelled",
|
|
@@ -324052,7 +324381,7 @@ var SDKRpcClientBase = class {
|
|
|
324052
324381
|
type: "error",
|
|
324053
324382
|
sessionId: request.sessionId,
|
|
324054
324383
|
agentId: request.agentId,
|
|
324055
|
-
...makeErrorPayload(ErrorCodes.SESSION_QUESTION_HANDLER_ERROR, errorMessage$
|
|
324384
|
+
...makeErrorPayload(ErrorCodes.SESSION_QUESTION_HANDLER_ERROR, errorMessage$9(error))
|
|
324056
324385
|
});
|
|
324057
324386
|
return null;
|
|
324058
324387
|
}
|
|
@@ -324072,7 +324401,7 @@ var SDKRpcClientBase = class {
|
|
|
324072
324401
|
return await handler(request);
|
|
324073
324402
|
} catch (error) {
|
|
324074
324403
|
return {
|
|
324075
|
-
output: `Tool handler error for "${request.toolName ?? "(unknown)"}": ${errorMessage$
|
|
324404
|
+
output: `Tool handler error for "${request.toolName ?? "(unknown)"}": ${errorMessage$9(error)}`,
|
|
324076
324405
|
isError: true
|
|
324077
324406
|
};
|
|
324078
324407
|
}
|
|
@@ -324096,7 +324425,7 @@ var ClientAPI = class {
|
|
|
324096
324425
|
return this.client.toolCall(request);
|
|
324097
324426
|
}
|
|
324098
324427
|
};
|
|
324099
|
-
function errorMessage$
|
|
324428
|
+
function errorMessage$9(error) {
|
|
324100
324429
|
return error instanceof Error ? error.message : String(error);
|
|
324101
324430
|
}
|
|
324102
324431
|
//#endregion
|
|
@@ -333628,7 +333957,7 @@ var AcpSession = class {
|
|
|
333628
333957
|
break;
|
|
333629
333958
|
}
|
|
333630
333959
|
} catch (error) {
|
|
333631
|
-
await this.emitLocalCommandMessage(`/${name} failed: ${errorMessage$
|
|
333960
|
+
await this.emitLocalCommandMessage(`/${name} failed: ${errorMessage$8(error)}`);
|
|
333632
333961
|
}
|
|
333633
333962
|
return { stopReason: "end_turn" };
|
|
333634
333963
|
}
|
|
@@ -334019,7 +334348,7 @@ var AcpSession = class {
|
|
|
334019
334348
|
}
|
|
334020
334349
|
}
|
|
334021
334350
|
};
|
|
334022
|
-
function errorMessage$
|
|
334351
|
+
function errorMessage$8(error) {
|
|
334023
334352
|
return error instanceof Error ? error.message : String(error);
|
|
334024
334353
|
}
|
|
334025
334354
|
function formatHelpReport(commands) {
|
|
@@ -336508,8 +336837,8 @@ function createAccountMemoryClient(auth, options = {}) {
|
|
|
336508
336837
|
}
|
|
336509
336838
|
function readAccountMemoryConsentStatus(payload) {
|
|
336510
336839
|
const settings = unwrapPayload(payload)?.["settings"];
|
|
336511
|
-
const dataControls = isRecord$
|
|
336512
|
-
if (!isRecord$
|
|
336840
|
+
const dataControls = isRecord$14(settings) ? settings["data_controls"] : void 0;
|
|
336841
|
+
if (!isRecord$14(dataControls)) throw new Error("Account memory returned an invalid response.");
|
|
336513
336842
|
if (dataControls["memory_consent_asked"] !== true) return "never_asked";
|
|
336514
336843
|
if (dataControls["allow_memory"] === true) return "enabled";
|
|
336515
336844
|
if (dataControls["allow_memory"] === false) return "disabled";
|
|
@@ -336632,8 +336961,8 @@ function memoryContextSummary(facts, included) {
|
|
|
336632
336961
|
})}`;
|
|
336633
336962
|
}
|
|
336634
336963
|
function unwrapPayload(value) {
|
|
336635
|
-
if (!isRecord$
|
|
336636
|
-
return isRecord$
|
|
336964
|
+
if (!isRecord$14(value)) return void 0;
|
|
336965
|
+
return isRecord$14(value["data"]) ? value["data"] : value;
|
|
336637
336966
|
}
|
|
336638
336967
|
function readFacts(root) {
|
|
336639
336968
|
let rawFacts = [];
|
|
@@ -336641,7 +336970,7 @@ function readFacts(root) {
|
|
|
336641
336970
|
else {
|
|
336642
336971
|
const factsJson = parseFactsJson(root["facts_json"]);
|
|
336643
336972
|
if (Array.isArray(factsJson)) rawFacts = factsJson;
|
|
336644
|
-
else if (isRecord$
|
|
336973
|
+
else if (isRecord$14(factsJson) && Array.isArray(factsJson["facts"])) rawFacts = factsJson["facts"];
|
|
336645
336974
|
}
|
|
336646
336975
|
const facts = [];
|
|
336647
336976
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -336670,7 +336999,7 @@ function parseFactsJson(value) {
|
|
|
336670
336999
|
}
|
|
336671
337000
|
}
|
|
336672
337001
|
function normalizeFact(value) {
|
|
336673
|
-
const raw = typeof value === "string" ? value : isRecord$
|
|
337002
|
+
const raw = typeof value === "string" ? value : isRecord$14(value) && typeof value["text"] === "string" ? value["text"] : void 0;
|
|
336674
337003
|
if (raw === void 0) return void 0;
|
|
336675
337004
|
const normalized = raw.replaceAll(/\s+/gu, " ").trim();
|
|
336676
337005
|
if (normalized.length === 0) return void 0;
|
|
@@ -336679,7 +337008,7 @@ function normalizeFact(value) {
|
|
|
336679
337008
|
truncated: normalized.length > ACCOUNT_MEMORY_MAX_FACT_CHARS
|
|
336680
337009
|
};
|
|
336681
337010
|
}
|
|
336682
|
-
function isRecord$
|
|
337011
|
+
function isRecord$14(value) {
|
|
336683
337012
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
336684
337013
|
}
|
|
336685
337014
|
//#endregion
|
|
@@ -337848,7 +338177,7 @@ async function updateTuiAppearance(appearance, filePath = getTuiConfigPath()) {
|
|
|
337848
338177
|
throw new TuiConfigParseError(DEFAULT_TUI_CONFIG);
|
|
337849
338178
|
}
|
|
337850
338179
|
} catch (error) {
|
|
337851
|
-
if (!isNotFound$
|
|
338180
|
+
if (!isNotFound$3(error)) throw error;
|
|
337852
338181
|
}
|
|
337853
338182
|
const next = TuiConfigSchema.parse({
|
|
337854
338183
|
...current,
|
|
@@ -337946,7 +338275,7 @@ async function writeTuiConfigAtomic(config, filePath) {
|
|
|
337946
338275
|
throw error;
|
|
337947
338276
|
}
|
|
337948
338277
|
}
|
|
337949
|
-
function isNotFound$
|
|
338278
|
+
function isNotFound$3(error) {
|
|
337950
338279
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
337951
338280
|
}
|
|
337952
338281
|
function renderAppearanceConfig(appearance) {
|
|
@@ -337966,7 +338295,7 @@ function escapeTomlBasicString(value) {
|
|
|
337966
338295
|
//#region src/cli/sub/doctor.ts
|
|
337967
338296
|
init_zod$1();
|
|
337968
338297
|
async function handleDoctor(deps, options) {
|
|
337969
|
-
const resolved = resolveDeps(deps);
|
|
338298
|
+
const resolved = resolveDeps$1(deps);
|
|
337970
338299
|
const specs = await buildCheckSpecs(resolved, options, resolved.cwd());
|
|
337971
338300
|
const results = await Promise.all(specs.map((spec) => checkTomlFile(resolved, spec)));
|
|
337972
338301
|
const issueCount = results.filter((result) => result.status === "ERROR").length;
|
|
@@ -337993,11 +338322,11 @@ function registerDoctorCommand(parent, deps) {
|
|
|
337993
338322
|
});
|
|
337994
338323
|
}
|
|
337995
338324
|
async function runDoctorCommand(deps, options) {
|
|
337996
|
-
const resolved = resolveDeps(deps);
|
|
338325
|
+
const resolved = resolveDeps$1(deps);
|
|
337997
338326
|
const code = await handleDoctor(resolved, options);
|
|
337998
338327
|
if (code !== 0) resolved.exit(code);
|
|
337999
338328
|
}
|
|
338000
|
-
function resolveDeps(deps) {
|
|
338329
|
+
function resolveDeps$1(deps) {
|
|
338001
338330
|
let configRpc = deps?.configRpc;
|
|
338002
338331
|
const getConfigRpc = () => {
|
|
338003
338332
|
configRpc ??= createBlunConfigRpc();
|
|
@@ -338120,7 +338449,7 @@ function formatErrorMessage$4(error, filePath) {
|
|
|
338120
338449
|
function findValidationIssues(error) {
|
|
338121
338450
|
if (!(error instanceof Error)) return void 0;
|
|
338122
338451
|
const details = "details" in error ? error.details : void 0;
|
|
338123
|
-
if (!isRecord$
|
|
338452
|
+
if (!isRecord$13(details)) return void 0;
|
|
338124
338453
|
const validationIssues = details["validationIssues"];
|
|
338125
338454
|
return isValidationIssueArray(validationIssues) ? validationIssues : void 0;
|
|
338126
338455
|
}
|
|
@@ -338128,11 +338457,11 @@ function isValidationIssueArray(value) {
|
|
|
338128
338457
|
return Array.isArray(value) && value.every(isValidationIssue);
|
|
338129
338458
|
}
|
|
338130
338459
|
function isValidationIssue(value) {
|
|
338131
|
-
if (!isRecord$
|
|
338460
|
+
if (!isRecord$13(value) || typeof value["message"] !== "string") return false;
|
|
338132
338461
|
const path = value["path"];
|
|
338133
338462
|
return Array.isArray(path) && path.every((segment) => typeof segment === "string" || typeof segment === "number");
|
|
338134
338463
|
}
|
|
338135
|
-
function isRecord$
|
|
338464
|
+
function isRecord$13(value) {
|
|
338136
338465
|
return typeof value === "object" && value !== null;
|
|
338137
338466
|
}
|
|
338138
338467
|
function findZodError(error) {
|
|
@@ -338397,7 +338726,7 @@ async function handleExport(deps, sessionId, output, opts) {
|
|
|
338397
338726
|
});
|
|
338398
338727
|
deps.stdout.write(`${result.zipPath}\n`);
|
|
338399
338728
|
} catch (error) {
|
|
338400
|
-
deps.stderr.write(`${errorMessage$
|
|
338729
|
+
deps.stderr.write(`${errorMessage$7(error)}\n`);
|
|
338401
338730
|
deps.exit(1);
|
|
338402
338731
|
}
|
|
338403
338732
|
}
|
|
@@ -338500,7 +338829,7 @@ async function confirmPreviousSession(summary) {
|
|
|
338500
338829
|
rl.close();
|
|
338501
338830
|
}
|
|
338502
338831
|
}
|
|
338503
|
-
function errorMessage$
|
|
338832
|
+
function errorMessage$7(error) {
|
|
338504
338833
|
return error instanceof Error ? error.message : String(error);
|
|
338505
338834
|
}
|
|
338506
338835
|
//#endregion
|
|
@@ -338511,6 +338840,1444 @@ function registerLoginCommand(parent) {
|
|
|
338511
338840
|
});
|
|
338512
338841
|
}
|
|
338513
338842
|
//#endregion
|
|
338843
|
+
//#region src/mistakes/inflow-client.ts
|
|
338844
|
+
const MISTAKE_INVENTORY_STATUSES = [
|
|
338845
|
+
"counted",
|
|
338846
|
+
"uncounted",
|
|
338847
|
+
"unverified"
|
|
338848
|
+
];
|
|
338849
|
+
const MISTAKE_ACTUALITY_STATUSES = [
|
|
338850
|
+
"fresh",
|
|
338851
|
+
"stale",
|
|
338852
|
+
"unverified"
|
|
338853
|
+
];
|
|
338854
|
+
const MISTAKE_SOURCE_FORMS = [
|
|
338855
|
+
"case_collection",
|
|
338856
|
+
"class_collection",
|
|
338857
|
+
"finding_collection",
|
|
338858
|
+
"lesson_collection",
|
|
338859
|
+
"state_collection",
|
|
338860
|
+
"mixed",
|
|
338861
|
+
"unknown"
|
|
338862
|
+
];
|
|
338863
|
+
const MISTAKE_RECORD_TYPES = [
|
|
338864
|
+
"case",
|
|
338865
|
+
"class",
|
|
338866
|
+
"finding",
|
|
338867
|
+
"lesson",
|
|
338868
|
+
"state",
|
|
338869
|
+
"unknown"
|
|
338870
|
+
];
|
|
338871
|
+
const MISTAKE_RELATION_TYPES = [
|
|
338872
|
+
"instance_of",
|
|
338873
|
+
"lesson_from",
|
|
338874
|
+
"state_of",
|
|
338875
|
+
"independently_corroborates"
|
|
338876
|
+
];
|
|
338877
|
+
const MISTAKE_WATCHDOG_STATUSES = [
|
|
338878
|
+
"disabled",
|
|
338879
|
+
"green",
|
|
338880
|
+
"yellow",
|
|
338881
|
+
"red"
|
|
338882
|
+
];
|
|
338883
|
+
const DEFAULT_DEPS$2 = {
|
|
338884
|
+
fetch: globalThis.fetch,
|
|
338885
|
+
now: () => /* @__PURE__ */ new Date(),
|
|
338886
|
+
randomUUID
|
|
338887
|
+
};
|
|
338888
|
+
const SOURCE_ID_RE = /^[a-z0-9][a-z0-9._-]{0,79}$/;
|
|
338889
|
+
const SHA256_RE = /^[a-f0-9]{64}$/;
|
|
338890
|
+
const UUID_RE$1 = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
338891
|
+
const ENVELOPE_KEYS = [
|
|
338892
|
+
"version",
|
|
338893
|
+
"client_event_id",
|
|
338894
|
+
"source_id",
|
|
338895
|
+
"source_form",
|
|
338896
|
+
"declared_record_types",
|
|
338897
|
+
"original_name",
|
|
338898
|
+
"captured_at",
|
|
338899
|
+
"inventory",
|
|
338900
|
+
"declared_raw_bytes",
|
|
338901
|
+
"declared_raw_sha256",
|
|
338902
|
+
"payload_base64",
|
|
338903
|
+
"declarations"
|
|
338904
|
+
];
|
|
338905
|
+
const INVENTORY_KEYS = [
|
|
338906
|
+
"scope",
|
|
338907
|
+
"bestandsstatus",
|
|
338908
|
+
"aktualitaetsstatus",
|
|
338909
|
+
"declared_entry_count",
|
|
338910
|
+
"last_raw_observed_at"
|
|
338911
|
+
];
|
|
338912
|
+
const STATE_ACTION_KEYS = [
|
|
338913
|
+
"version",
|
|
338914
|
+
"action_id",
|
|
338915
|
+
"action",
|
|
338916
|
+
"target_event_id",
|
|
338917
|
+
"acted_at",
|
|
338918
|
+
"server_sequence",
|
|
338919
|
+
"principal_id",
|
|
338920
|
+
"reason"
|
|
338921
|
+
];
|
|
338922
|
+
const MAX_MISTAKE_SOURCE_BYTES = 20 * 1024 * 1024;
|
|
338923
|
+
function normalizeMistakeSourceId(value) {
|
|
338924
|
+
const normalized = value.normalize("NFKC").trim().toLocaleLowerCase("en-US");
|
|
338925
|
+
if (!SOURCE_ID_RE.test(normalized)) throw new Error("source id must use 1-80 lowercase letters, digits, dots, underscores, or hyphens");
|
|
338926
|
+
return normalized;
|
|
338927
|
+
}
|
|
338928
|
+
function assertSafeMistakeInflowEndpoint(value) {
|
|
338929
|
+
let url;
|
|
338930
|
+
try {
|
|
338931
|
+
url = new URL(value);
|
|
338932
|
+
} catch {
|
|
338933
|
+
throw new Error("mistake inflow endpoint is not a valid URL");
|
|
338934
|
+
}
|
|
338935
|
+
if (url.username !== "" || url.password !== "" || url.search !== "" || url.hash !== "") throw new Error("mistake inflow endpoint must not contain credentials, a query, or a fragment");
|
|
338936
|
+
if (url.pathname !== "/" && url.pathname !== "") throw new Error("mistake inflow endpoint must not include a path");
|
|
338937
|
+
if (url.protocol === "https:") return url;
|
|
338938
|
+
if (url.protocol !== "http:" || !isPrivateHttpHost(url.hostname)) throw new Error("plain HTTP mistake inflow is allowed only on loopback or Tailscale addresses");
|
|
338939
|
+
return url;
|
|
338940
|
+
}
|
|
338941
|
+
function isPrivateHttpHost(hostname) {
|
|
338942
|
+
if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]") return true;
|
|
338943
|
+
const parts = hostname.split(".").map(Number);
|
|
338944
|
+
const first = parts[0];
|
|
338945
|
+
const second = parts[1];
|
|
338946
|
+
return parts.length === 4 && parts.every((part) => Number.isInteger(part) && part >= 0 && part <= 255) && first === 100 && second !== void 0 && second >= 64 && second <= 127;
|
|
338947
|
+
}
|
|
338948
|
+
function assertIsoTimestamp$2(value, label) {
|
|
338949
|
+
const parsed = new Date(value);
|
|
338950
|
+
if (!Number.isFinite(parsed.valueOf()) || !/(?:Z|[+-]\d{2}:\d{2})$/.test(value)) throw new Error(`${label} must be an ISO-8601 timestamp with a timezone`);
|
|
338951
|
+
return value;
|
|
338952
|
+
}
|
|
338953
|
+
function assertEntryCount(value) {
|
|
338954
|
+
if (value === void 0) return null;
|
|
338955
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new Error("declared entry count must be a non-negative safe integer");
|
|
338956
|
+
return value;
|
|
338957
|
+
}
|
|
338958
|
+
function parseMistakeRecordDeclarations(value, sourceId, declaredRecordTypes) {
|
|
338959
|
+
if (!isRecord$12(value) || !hasOnlyKeys(value, [
|
|
338960
|
+
"version",
|
|
338961
|
+
"records",
|
|
338962
|
+
"relations"
|
|
338963
|
+
]) || value["version"] !== 1) throw new Error("record declarations must use version 1 and contain only records and relations");
|
|
338964
|
+
if (!Array.isArray(value["records"]) || value["records"].length > 1e5 || !Array.isArray(value["relations"]) || value["relations"].length > 1e5) throw new Error("record declarations require records and relations arrays of at most 100000 items");
|
|
338965
|
+
normalizeMistakeSourceId(sourceId);
|
|
338966
|
+
const allowedRecordTypes = new Set(declaredRecordTypes);
|
|
338967
|
+
if (allowedRecordTypes.size === 0 || [...allowedRecordTypes].some((type) => !MISTAKE_RECORD_TYPES.includes(type))) throw new Error("declared source record types are invalid");
|
|
338968
|
+
const recordIds = /* @__PURE__ */ new Set();
|
|
338969
|
+
return {
|
|
338970
|
+
version: 1,
|
|
338971
|
+
records: value["records"].map((candidate, index) => {
|
|
338972
|
+
if (!isRecord$12(candidate) || !hasOnlyKeys(candidate, [
|
|
338973
|
+
"source_record_id",
|
|
338974
|
+
"type",
|
|
338975
|
+
"raw_locator"
|
|
338976
|
+
])) throw new Error(`record declaration ${index} is invalid`);
|
|
338977
|
+
const recordId = candidate["source_record_id"];
|
|
338978
|
+
const type = candidate["type"];
|
|
338979
|
+
const rawLocator = candidate["raw_locator"];
|
|
338980
|
+
if (typeof recordId !== "string" || !isValidRecordId(recordId)) throw new Error(`record declaration ${index} has an invalid record id`);
|
|
338981
|
+
if (recordIds.has(recordId)) throw new Error(`duplicate record id: ${recordId}`);
|
|
338982
|
+
if (typeof type !== "string" || !MISTAKE_RECORD_TYPES.includes(type) || !allowedRecordTypes.has(type)) throw new Error(`record ${recordId} uses a type not declared by its source`);
|
|
338983
|
+
if (typeof rawLocator !== "string" || !isSafeRawLocator(rawLocator)) throw new Error(`record ${recordId} has an invalid raw locator`);
|
|
338984
|
+
recordIds.add(recordId);
|
|
338985
|
+
return {
|
|
338986
|
+
source_record_id: recordId,
|
|
338987
|
+
type,
|
|
338988
|
+
raw_locator: rawLocator
|
|
338989
|
+
};
|
|
338990
|
+
}),
|
|
338991
|
+
relations: value["relations"].map((candidate, index) => {
|
|
338992
|
+
if (!isRecord$12(candidate) || !hasOnlyKeys(candidate, [
|
|
338993
|
+
"from_source_record_id",
|
|
338994
|
+
"type",
|
|
338995
|
+
"to"
|
|
338996
|
+
])) throw new Error(`record relation ${index} is invalid`);
|
|
338997
|
+
const fromRecordId = candidate["from_source_record_id"];
|
|
338998
|
+
const type = candidate["type"];
|
|
338999
|
+
const target = candidate["to"];
|
|
339000
|
+
if (typeof fromRecordId !== "string" || !isValidRecordId(fromRecordId) || !recordIds.has(fromRecordId)) throw new Error(`record relation ${index} must start at a declared local record`);
|
|
339001
|
+
if (typeof type !== "string" || !MISTAKE_RELATION_TYPES.includes(type)) throw new Error(`record relation ${index} has an invalid relation type`);
|
|
339002
|
+
if (!isRecord$12(target) || !hasOnlyKeys(target, ["source_id", "source_record_id"])) throw new Error(`record relation ${index} has an invalid target`);
|
|
339003
|
+
const targetSourceId = target["source_id"];
|
|
339004
|
+
const targetRecordId = target["source_record_id"];
|
|
339005
|
+
if (typeof targetSourceId !== "string" || !isNormalizedSourceId(targetSourceId)) throw new Error(`record relation ${index} has an invalid target source id`);
|
|
339006
|
+
if (typeof targetRecordId !== "string" || !isValidRecordId(targetRecordId)) throw new Error(`record relation ${index} has an invalid target record id`);
|
|
339007
|
+
return {
|
|
339008
|
+
from_source_record_id: fromRecordId,
|
|
339009
|
+
type,
|
|
339010
|
+
to: {
|
|
339011
|
+
source_id: targetSourceId,
|
|
339012
|
+
source_record_id: targetRecordId
|
|
339013
|
+
}
|
|
339014
|
+
};
|
|
339015
|
+
})
|
|
339016
|
+
};
|
|
339017
|
+
}
|
|
339018
|
+
async function queueMistakeObservation(input, outboxDir, deps = DEFAULT_DEPS$2) {
|
|
339019
|
+
const sourceStat = await lstat(input.filePath);
|
|
339020
|
+
if (sourceStat.isSymbolicLink()) throw new Error("mistake source must not be a symbolic link");
|
|
339021
|
+
if (!sourceStat.isFile()) throw new Error("mistake source must be a regular file");
|
|
339022
|
+
if (sourceStat.size > 20971520) throw new Error(`mistake source exceeds ${MAX_MISTAKE_SOURCE_BYTES} bytes`);
|
|
339023
|
+
const sourceHandle = await open(input.filePath, "r");
|
|
339024
|
+
let raw;
|
|
339025
|
+
try {
|
|
339026
|
+
const openedStat = await sourceHandle.stat();
|
|
339027
|
+
if (!openedStat.isFile() || openedStat.dev !== sourceStat.dev || openedStat.ino !== sourceStat.ino) throw new Error("mistake source changed while it was being opened");
|
|
339028
|
+
raw = await sourceHandle.readFile();
|
|
339029
|
+
} finally {
|
|
339030
|
+
await sourceHandle.close();
|
|
339031
|
+
}
|
|
339032
|
+
if (raw.byteLength > 20971520) throw new Error(`mistake source exceeds ${MAX_MISTAKE_SOURCE_BYTES} bytes`);
|
|
339033
|
+
const clientEventId = input.clientEventId ?? deps.randomUUID();
|
|
339034
|
+
if (!UUID_RE$1.test(clientEventId)) throw new Error("client event id must be a UUID");
|
|
339035
|
+
const capturedAt = assertIsoTimestamp$2(input.capturedAt ?? deps.now().toISOString(), "captured at");
|
|
339036
|
+
const lastRawObservedAt = input.lastRawObservedAt === void 0 ? null : assertIsoTimestamp$2(input.lastRawObservedAt, "last raw observed at");
|
|
339037
|
+
const recordTypes = [...new Set(input.recordTypes)];
|
|
339038
|
+
if (recordTypes.length === 0 || recordTypes.some((type) => !MISTAKE_RECORD_TYPES.includes(type))) throw new Error("at least one valid declared record type is required");
|
|
339039
|
+
if (!MISTAKE_SOURCE_FORMS.includes(input.sourceForm)) throw new Error("invalid source form");
|
|
339040
|
+
if (!MISTAKE_INVENTORY_STATUSES.includes(input.bestandsstatus)) throw new Error("invalid bestandsstatus");
|
|
339041
|
+
if (!MISTAKE_ACTUALITY_STATUSES.includes(input.aktualitaetsstatus)) throw new Error("invalid aktualitaetsstatus");
|
|
339042
|
+
const declaredEntryCount = assertEntryCount(input.declaredEntryCount);
|
|
339043
|
+
assertInventoryInvariants(input.bestandsstatus, input.aktualitaetsstatus, declaredEntryCount, lastRawObservedAt, capturedAt);
|
|
339044
|
+
const sourceId = normalizeMistakeSourceId(input.sourceId);
|
|
339045
|
+
const declarations = input.declarations === void 0 ? void 0 : parseMistakeRecordDeclarations(input.declarations, sourceId, recordTypes);
|
|
339046
|
+
const envelope = {
|
|
339047
|
+
version: 1,
|
|
339048
|
+
client_event_id: clientEventId,
|
|
339049
|
+
source_id: sourceId,
|
|
339050
|
+
source_form: input.sourceForm,
|
|
339051
|
+
declared_record_types: recordTypes,
|
|
339052
|
+
original_name: basename(input.filePath),
|
|
339053
|
+
captured_at: capturedAt,
|
|
339054
|
+
inventory: {
|
|
339055
|
+
scope: "lower_bound",
|
|
339056
|
+
bestandsstatus: input.bestandsstatus,
|
|
339057
|
+
aktualitaetsstatus: input.aktualitaetsstatus,
|
|
339058
|
+
declared_entry_count: declaredEntryCount,
|
|
339059
|
+
last_raw_observed_at: lastRawObservedAt
|
|
339060
|
+
},
|
|
339061
|
+
declared_raw_bytes: raw.byteLength,
|
|
339062
|
+
declared_raw_sha256: createHash("sha256").update(raw).digest("hex"),
|
|
339063
|
+
payload_base64: raw.toString("base64"),
|
|
339064
|
+
declarations
|
|
339065
|
+
};
|
|
339066
|
+
const eventsDir = join(outboxDir, "events");
|
|
339067
|
+
await ensureDurableMistakeDirectory(eventsDir);
|
|
339068
|
+
await durableExclusiveWrite(join(eventsDir, `${clientEventId}.json`), `${JSON.stringify(envelope)}\n`);
|
|
339069
|
+
return envelope;
|
|
339070
|
+
}
|
|
339071
|
+
function endpointUrl(endpoint, path) {
|
|
339072
|
+
const base = assertSafeMistakeInflowEndpoint(endpoint);
|
|
339073
|
+
return new URL(path, base);
|
|
339074
|
+
}
|
|
339075
|
+
async function readJsonResponse(response) {
|
|
339076
|
+
const text = await response.text();
|
|
339077
|
+
try {
|
|
339078
|
+
return JSON.parse(text);
|
|
339079
|
+
} catch {
|
|
339080
|
+
throw new Error(`mistake inflow returned non-JSON HTTP ${response.status}`);
|
|
339081
|
+
}
|
|
339082
|
+
}
|
|
339083
|
+
function isReceipt(value) {
|
|
339084
|
+
if (typeof value !== "object" || value === null) return false;
|
|
339085
|
+
const item = value;
|
|
339086
|
+
return item["version"] === 1 && item["accepted"] === true && typeof item["event_id"] === "string" && UUID_RE$1.test(item["event_id"]) && typeof item["client_event_id"] === "string" && UUID_RE$1.test(item["client_event_id"]) && typeof item["source_id"] === "string" && isNormalizedSourceId(item["source_id"]) && typeof item["canonical_agent_id"] === "string" && isNormalizedSourceId(item["canonical_agent_id"]) && typeof item["received_at"] === "string" && isIsoTimestamp(item["received_at"]) && item["raw_count"] === 1 && item["accepted_count"] === 1 && item["rejected_count"] === 0 && Number.isSafeInteger(item["raw_bytes"]) && item["raw_bytes"] >= 0 && typeof item["raw_sha256"] === "string" && SHA256_RE.test(item["raw_sha256"]) && isNullableEntryCount(item["declared_entry_count"]);
|
|
339087
|
+
}
|
|
339088
|
+
async function deliverQueuedObservation(clientEventId, options, deps = DEFAULT_DEPS$2) {
|
|
339089
|
+
if (!UUID_RE$1.test(clientEventId)) throw new Error("client event id must be a UUID");
|
|
339090
|
+
const envelope = parseQueuedEnvelope(await readFile(join(options.outboxDir, "events", `${clientEventId}.json`), "utf8"), clientEventId);
|
|
339091
|
+
const controller = new AbortController();
|
|
339092
|
+
const timeout = setTimeout(() => {
|
|
339093
|
+
controller.abort();
|
|
339094
|
+
}, 15e3);
|
|
339095
|
+
let response;
|
|
339096
|
+
try {
|
|
339097
|
+
response = await deps.fetch(endpointUrl(options.endpoint, "/v1/observations"), {
|
|
339098
|
+
method: "POST",
|
|
339099
|
+
headers: {
|
|
339100
|
+
authorization: `Bearer ${options.token}`,
|
|
339101
|
+
"content-type": "application/json"
|
|
339102
|
+
},
|
|
339103
|
+
body: JSON.stringify(envelope),
|
|
339104
|
+
signal: controller.signal,
|
|
339105
|
+
redirect: "error"
|
|
339106
|
+
});
|
|
339107
|
+
} finally {
|
|
339108
|
+
clearTimeout(timeout);
|
|
339109
|
+
}
|
|
339110
|
+
const body = await readJsonResponse(response);
|
|
339111
|
+
if (response.status !== 202 || !isReceipt(body)) {
|
|
339112
|
+
const bodyError = typeof body === "object" && body !== null ? body["error"] : void 0;
|
|
339113
|
+
const message = typeof bodyError === "string" ? bodyError : `HTTP ${response.status}`;
|
|
339114
|
+
throw new Error(`mistake inflow rejected ${clientEventId}: ${message}`);
|
|
339115
|
+
}
|
|
339116
|
+
if (!receiptMatchesEnvelope(body, envelope)) throw new Error(`mistake inflow receipt mismatch for ${clientEventId}`);
|
|
339117
|
+
const receiptsDir = join(options.outboxDir, "receipts", clientEventId);
|
|
339118
|
+
await ensureDurableMistakeDirectory(receiptsDir);
|
|
339119
|
+
const receiptPath = join(receiptsDir, `${body.event_id}.json`);
|
|
339120
|
+
try {
|
|
339121
|
+
await durableExclusiveWrite(receiptPath, `${JSON.stringify(body)}\n`);
|
|
339122
|
+
} catch (error) {
|
|
339123
|
+
if (!isAlreadyExists$1(error)) throw error;
|
|
339124
|
+
const existing = await readReceipt(receiptPath);
|
|
339125
|
+
if (existing !== null && existing.event_id === body.event_id && receiptMatchesEnvelope(existing, envelope)) {
|
|
339126
|
+
if (!receiptsEqual(existing, body)) throw new Error(`conflicting local receipt for ${clientEventId}`, { cause: error });
|
|
339127
|
+
} else await durableExclusiveWrite(join(receiptsDir, `${body.event_id}.${randomUUID()}.json`), `${JSON.stringify(body)}\n`);
|
|
339128
|
+
}
|
|
339129
|
+
return body;
|
|
339130
|
+
}
|
|
339131
|
+
async function uploadMistakeObservation(input, options, deps = DEFAULT_DEPS$2) {
|
|
339132
|
+
return deliverQueuedObservation((await queueMistakeObservation(input, options.outboxDir, deps)).client_event_id, options, deps);
|
|
339133
|
+
}
|
|
339134
|
+
async function drainMistakeOutbox(options, deps = DEFAULT_DEPS$2) {
|
|
339135
|
+
const eventsDir = join(options.outboxDir, "events");
|
|
339136
|
+
await ensureDurableMistakeDirectory(eventsDir);
|
|
339137
|
+
const names = (await readdir(eventsDir)).filter((name) => UUID_RE$1.test(name.replace(/\.json$/, "")) && name.endsWith(".json")).toSorted();
|
|
339138
|
+
const delivered = [];
|
|
339139
|
+
const failed = [];
|
|
339140
|
+
const pending = [];
|
|
339141
|
+
for (const name of names) {
|
|
339142
|
+
const clientEventId = name.slice(0, -5);
|
|
339143
|
+
try {
|
|
339144
|
+
const envelope = parseQueuedEnvelope(await readFile(join(eventsDir, name), "utf8"), clientEventId);
|
|
339145
|
+
if (await findVerifiedLocalReceipt(envelope, options.outboxDir) !== null) continue;
|
|
339146
|
+
pending.push(envelope);
|
|
339147
|
+
} catch (error) {
|
|
339148
|
+
failed.push({
|
|
339149
|
+
clientEventId,
|
|
339150
|
+
error: errorMessage$6(error)
|
|
339151
|
+
});
|
|
339152
|
+
}
|
|
339153
|
+
}
|
|
339154
|
+
pending.sort(compareObservationOrder);
|
|
339155
|
+
for (const envelope of pending) try {
|
|
339156
|
+
delivered.push(await deliverQueuedObservation(envelope.client_event_id, options, deps));
|
|
339157
|
+
} catch (error) {
|
|
339158
|
+
failed.push({
|
|
339159
|
+
clientEventId: envelope.client_event_id,
|
|
339160
|
+
error: errorMessage$6(error)
|
|
339161
|
+
});
|
|
339162
|
+
}
|
|
339163
|
+
return {
|
|
339164
|
+
delivered,
|
|
339165
|
+
failed
|
|
339166
|
+
};
|
|
339167
|
+
}
|
|
339168
|
+
async function getMistakeInflowStatus(endpoint, token, deps = DEFAULT_DEPS$2) {
|
|
339169
|
+
const response = await deps.fetch(endpointUrl(endpoint, "/v1/status"), {
|
|
339170
|
+
headers: { authorization: `Bearer ${token}` },
|
|
339171
|
+
redirect: "error"
|
|
339172
|
+
});
|
|
339173
|
+
const body = await readJsonResponse(response);
|
|
339174
|
+
if (response.status !== 200) throw new Error(`mistake inflow status failed: HTTP ${response.status}`);
|
|
339175
|
+
if (!isMistakeInflowStatus(body)) throw new Error("mistake inflow status returned an invalid payload");
|
|
339176
|
+
return body;
|
|
339177
|
+
}
|
|
339178
|
+
async function changeMistakeObservationState(action, eventId, reason, endpoint, token, deps = DEFAULT_DEPS$2) {
|
|
339179
|
+
if (!UUID_RE$1.test(eventId)) throw new Error("event id must be a UUID");
|
|
339180
|
+
const trimmedReason = reason.trim();
|
|
339181
|
+
if (trimmedReason.length < 3 || trimmedReason.length > 500) throw new Error("reason must contain 3-500 characters");
|
|
339182
|
+
const actionId = deps.randomUUID();
|
|
339183
|
+
if (!UUID_RE$1.test(actionId)) throw new Error("generated action id must be a UUID");
|
|
339184
|
+
const response = await deps.fetch(endpointUrl(endpoint, `/v1/observations/${eventId}:${action}`), {
|
|
339185
|
+
method: "POST",
|
|
339186
|
+
headers: {
|
|
339187
|
+
authorization: `Bearer ${token}`,
|
|
339188
|
+
"content-type": "application/json"
|
|
339189
|
+
},
|
|
339190
|
+
body: JSON.stringify({
|
|
339191
|
+
action_id: actionId,
|
|
339192
|
+
reason: trimmedReason
|
|
339193
|
+
}),
|
|
339194
|
+
redirect: "error"
|
|
339195
|
+
});
|
|
339196
|
+
const body = await readJsonResponse(response);
|
|
339197
|
+
if (response.status !== 201) {
|
|
339198
|
+
const bodyError = typeof body === "object" && body !== null ? body["error"] : void 0;
|
|
339199
|
+
const detail = typeof bodyError === "string" ? bodyError : `HTTP ${response.status}`;
|
|
339200
|
+
throw new Error(`mistake inflow ${action} failed: ${detail}`);
|
|
339201
|
+
}
|
|
339202
|
+
if (!isStateActionReceipt(body) || body.action_id !== actionId || body.action !== action || body.target_event_id !== eventId || body.reason !== trimmedReason) throw new Error(`mistake inflow ${action} returned a mismatched action receipt`);
|
|
339203
|
+
return body;
|
|
339204
|
+
}
|
|
339205
|
+
function parseQueuedEnvelope(text, expectedClientEventId) {
|
|
339206
|
+
let value;
|
|
339207
|
+
try {
|
|
339208
|
+
value = JSON.parse(text);
|
|
339209
|
+
} catch {
|
|
339210
|
+
throw new Error(`queued mistake event ${expectedClientEventId} is not valid JSON`);
|
|
339211
|
+
}
|
|
339212
|
+
if (typeof value !== "object" || value === null) throw new Error(`queued mistake event ${expectedClientEventId} is invalid`);
|
|
339213
|
+
const item = value;
|
|
339214
|
+
if (!hasOnlyKeys(item, ENVELOPE_KEYS) || item["version"] !== 1 || item["client_event_id"] !== expectedClientEventId || !UUID_RE$1.test(expectedClientEventId)) throw new Error(`queued mistake event ${expectedClientEventId} has an invalid identity`);
|
|
339215
|
+
if (typeof item["source_id"] !== "string" || !isNormalizedSourceId(item["source_id"])) throw new Error(`queued mistake event ${expectedClientEventId} has an invalid source`);
|
|
339216
|
+
if (typeof item["source_form"] !== "string" || !MISTAKE_SOURCE_FORMS.includes(item["source_form"])) throw new Error(`queued mistake event ${expectedClientEventId} has an invalid source form`);
|
|
339217
|
+
const recordTypes = item["declared_record_types"];
|
|
339218
|
+
if (!Array.isArray(recordTypes) || recordTypes.length === 0 || new Set(recordTypes).size !== recordTypes.length || recordTypes.some((type) => typeof type !== "string" || !MISTAKE_RECORD_TYPES.includes(type))) throw new Error(`queued mistake event ${expectedClientEventId} has invalid record types`);
|
|
339219
|
+
if (typeof item["original_name"] !== "string" || item["original_name"] === "" || basename(item["original_name"]) !== item["original_name"]) throw new Error(`queued mistake event ${expectedClientEventId} has an invalid original name`);
|
|
339220
|
+
if (typeof item["captured_at"] !== "string" || !isIsoTimestamp(item["captured_at"])) throw new Error(`queued mistake event ${expectedClientEventId} has an invalid capture time`);
|
|
339221
|
+
const inventory = item["inventory"];
|
|
339222
|
+
if (typeof inventory !== "object" || inventory === null) throw new Error(`queued mistake event ${expectedClientEventId} has invalid inventory metadata`);
|
|
339223
|
+
const inventoryItem = inventory;
|
|
339224
|
+
if (!hasOnlyKeys(inventoryItem, INVENTORY_KEYS) || inventoryItem["scope"] !== "lower_bound" || typeof inventoryItem["bestandsstatus"] !== "string" || !MISTAKE_INVENTORY_STATUSES.includes(inventoryItem["bestandsstatus"]) || typeof inventoryItem["aktualitaetsstatus"] !== "string" || !MISTAKE_ACTUALITY_STATUSES.includes(inventoryItem["aktualitaetsstatus"]) || !isNullableEntryCount(inventoryItem["declared_entry_count"]) || inventoryItem["last_raw_observed_at"] !== null && (typeof inventoryItem["last_raw_observed_at"] !== "string" || !isIsoTimestamp(inventoryItem["last_raw_observed_at"]))) throw new Error(`queued mistake event ${expectedClientEventId} has invalid inventory metadata`);
|
|
339225
|
+
try {
|
|
339226
|
+
assertInventoryInvariants(inventoryItem["bestandsstatus"], inventoryItem["aktualitaetsstatus"], inventoryItem["declared_entry_count"], inventoryItem["last_raw_observed_at"], item["captured_at"]);
|
|
339227
|
+
} catch (error) {
|
|
339228
|
+
throw new Error(`queued mistake event ${expectedClientEventId} has contradictory inventory metadata`, { cause: error });
|
|
339229
|
+
}
|
|
339230
|
+
if (!Number.isSafeInteger(item["declared_raw_bytes"]) || item["declared_raw_bytes"] < 0 || item["declared_raw_bytes"] > 20971520 || typeof item["declared_raw_sha256"] !== "string" || !SHA256_RE.test(item["declared_raw_sha256"]) || typeof item["payload_base64"] !== "string") throw new Error(`queued mistake event ${expectedClientEventId} has invalid payload metadata`);
|
|
339231
|
+
const payload = Buffer.from(item["payload_base64"], "base64");
|
|
339232
|
+
if (payload.toString("base64") !== item["payload_base64"] || payload.byteLength !== item["declared_raw_bytes"] || createHash("sha256").update(payload).digest("hex") !== item["declared_raw_sha256"]) throw new Error(`queued mistake event ${expectedClientEventId} failed payload integrity verification`);
|
|
339233
|
+
if (item["declarations"] !== void 0) try {
|
|
339234
|
+
parseMistakeRecordDeclarations(item["declarations"], item["source_id"], recordTypes);
|
|
339235
|
+
} catch (error) {
|
|
339236
|
+
throw new Error(`queued mistake event ${expectedClientEventId} has invalid record declarations`, { cause: error });
|
|
339237
|
+
}
|
|
339238
|
+
return value;
|
|
339239
|
+
}
|
|
339240
|
+
async function findVerifiedLocalReceipt(envelope, outboxDir) {
|
|
339241
|
+
const receiptRoot = join(outboxDir, "receipts");
|
|
339242
|
+
const paths = [join(receiptRoot, `${envelope.client_event_id}.json`)];
|
|
339243
|
+
const eventReceiptDir = join(receiptRoot, envelope.client_event_id);
|
|
339244
|
+
try {
|
|
339245
|
+
const names = (await readdir(eventReceiptDir)).filter((name) => name.endsWith(".json")).toSorted();
|
|
339246
|
+
paths.push(...names.map((name) => join(eventReceiptDir, name)));
|
|
339247
|
+
} catch (error) {
|
|
339248
|
+
if (!isNotFound$2(error)) throw error;
|
|
339249
|
+
}
|
|
339250
|
+
for (const path of paths) {
|
|
339251
|
+
const candidate = await readReceipt(path);
|
|
339252
|
+
if (candidate !== null && receiptMatchesEnvelope(candidate, envelope)) return candidate;
|
|
339253
|
+
}
|
|
339254
|
+
return null;
|
|
339255
|
+
}
|
|
339256
|
+
async function readReceipt(path) {
|
|
339257
|
+
try {
|
|
339258
|
+
const value = JSON.parse(await readFile(path, "utf8"));
|
|
339259
|
+
return isReceipt(value) ? value : null;
|
|
339260
|
+
} catch (error) {
|
|
339261
|
+
if (isNotFound$2(error) || error instanceof SyntaxError) return null;
|
|
339262
|
+
throw error;
|
|
339263
|
+
}
|
|
339264
|
+
}
|
|
339265
|
+
function receiptMatchesEnvelope(receipt, envelope) {
|
|
339266
|
+
return receipt.client_event_id === envelope.client_event_id && receipt.source_id === envelope.source_id && receipt.raw_bytes === envelope.declared_raw_bytes && receipt.raw_sha256 === envelope.declared_raw_sha256 && receipt.declared_entry_count === envelope.inventory.declared_entry_count;
|
|
339267
|
+
}
|
|
339268
|
+
function receiptsEqual(left, right) {
|
|
339269
|
+
return left.version === right.version && left.accepted === right.accepted && left.event_id === right.event_id && left.client_event_id === right.client_event_id && left.source_id === right.source_id && left.canonical_agent_id === right.canonical_agent_id && left.received_at === right.received_at && left.raw_count === right.raw_count && left.accepted_count === right.accepted_count && left.rejected_count === right.rejected_count && left.raw_bytes === right.raw_bytes && left.raw_sha256 === right.raw_sha256 && left.declared_entry_count === right.declared_entry_count;
|
|
339270
|
+
}
|
|
339271
|
+
function isStateActionReceipt(value) {
|
|
339272
|
+
if (!isRecord$12(value) || !hasOnlyKeys(value, STATE_ACTION_KEYS)) return false;
|
|
339273
|
+
const reason = value["reason"];
|
|
339274
|
+
return value["version"] === 1 && typeof value["action_id"] === "string" && UUID_RE$1.test(value["action_id"]) && (value["action"] === "remove" || value["action"] === "restore") && typeof value["target_event_id"] === "string" && UUID_RE$1.test(value["target_event_id"]) && typeof value["acted_at"] === "string" && isIsoTimestamp(value["acted_at"]) && Number.isSafeInteger(value["server_sequence"]) && value["server_sequence"] >= 1 && typeof value["principal_id"] === "string" && isNormalizedSourceId(value["principal_id"]) && typeof reason === "string" && reason.trim() === reason && reason.length >= 3 && reason.length <= 500;
|
|
339275
|
+
}
|
|
339276
|
+
function compareObservationOrder(left, right) {
|
|
339277
|
+
const leftObservedAt = left.inventory.last_raw_observed_at ?? left.captured_at;
|
|
339278
|
+
const rightObservedAt = right.inventory.last_raw_observed_at ?? right.captured_at;
|
|
339279
|
+
return Date.parse(leftObservedAt) - Date.parse(rightObservedAt) || Date.parse(left.captured_at) - Date.parse(right.captured_at) || left.source_id.localeCompare(right.source_id) || left.client_event_id.localeCompare(right.client_event_id);
|
|
339280
|
+
}
|
|
339281
|
+
async function ensureDurableMistakeDirectory(path, deps) {
|
|
339282
|
+
const io = deps ?? {
|
|
339283
|
+
lstat,
|
|
339284
|
+
mkdir,
|
|
339285
|
+
syncDirectory
|
|
339286
|
+
};
|
|
339287
|
+
const missing = [];
|
|
339288
|
+
let cursor = resolve(path);
|
|
339289
|
+
while (true) try {
|
|
339290
|
+
const existing = await io.lstat(cursor);
|
|
339291
|
+
if (existing.isSymbolicLink() || !existing.isDirectory()) throw new Error(`mistake outbox path is not a real directory: ${cursor}`);
|
|
339292
|
+
break;
|
|
339293
|
+
} catch (error) {
|
|
339294
|
+
if (!isNotFound$2(error)) throw error;
|
|
339295
|
+
missing.push(cursor);
|
|
339296
|
+
const parent = dirname(cursor);
|
|
339297
|
+
if (parent === cursor) throw new Error(`mistake outbox has no existing parent: ${path}`, { cause: error });
|
|
339298
|
+
cursor = parent;
|
|
339299
|
+
}
|
|
339300
|
+
for (const directory of missing.toReversed()) {
|
|
339301
|
+
try {
|
|
339302
|
+
await io.mkdir(directory, { mode: 448 });
|
|
339303
|
+
} catch (error) {
|
|
339304
|
+
if (!isAlreadyExists$1(error)) throw error;
|
|
339305
|
+
const raced = await io.lstat(directory);
|
|
339306
|
+
if (raced.isSymbolicLink() || !raced.isDirectory()) throw new Error(`mistake outbox path is not a real directory: ${directory}`, { cause: error });
|
|
339307
|
+
}
|
|
339308
|
+
await io.syncDirectory(dirname(directory));
|
|
339309
|
+
}
|
|
339310
|
+
}
|
|
339311
|
+
async function durableExclusiveWrite(path, contents) {
|
|
339312
|
+
const directory = dirname(path);
|
|
339313
|
+
const temporaryPath = join(directory, `.${basename(path)}.${process.pid}.${randomUUID()}.tmp`);
|
|
339314
|
+
let handle;
|
|
339315
|
+
let failure;
|
|
339316
|
+
try {
|
|
339317
|
+
handle = await open(temporaryPath, "wx", 384);
|
|
339318
|
+
await handle.writeFile(contents, "utf8");
|
|
339319
|
+
await handle.sync();
|
|
339320
|
+
await handle.close();
|
|
339321
|
+
handle = void 0;
|
|
339322
|
+
await link(temporaryPath, path);
|
|
339323
|
+
await syncDirectory(directory);
|
|
339324
|
+
} catch (error) {
|
|
339325
|
+
failure = error;
|
|
339326
|
+
}
|
|
339327
|
+
if (handle !== void 0) try {
|
|
339328
|
+
await handle.close();
|
|
339329
|
+
} catch (error) {
|
|
339330
|
+
failure ??= error;
|
|
339331
|
+
}
|
|
339332
|
+
try {
|
|
339333
|
+
await unlink(temporaryPath);
|
|
339334
|
+
await syncDirectory(directory);
|
|
339335
|
+
} catch (error) {
|
|
339336
|
+
if (!isNotFound$2(error)) failure ??= error;
|
|
339337
|
+
}
|
|
339338
|
+
if (failure !== void 0) throw failure;
|
|
339339
|
+
}
|
|
339340
|
+
async function syncDirectory(path) {
|
|
339341
|
+
let handle;
|
|
339342
|
+
try {
|
|
339343
|
+
handle = await open(path, "r");
|
|
339344
|
+
await handle.sync();
|
|
339345
|
+
} catch (error) {
|
|
339346
|
+
if (process.platform !== "win32" || !isUnsupportedDirectorySync(error)) throw error;
|
|
339347
|
+
} finally {
|
|
339348
|
+
await handle?.close().catch(() => void 0);
|
|
339349
|
+
}
|
|
339350
|
+
}
|
|
339351
|
+
function isNormalizedSourceId(value) {
|
|
339352
|
+
try {
|
|
339353
|
+
return normalizeMistakeSourceId(value) === value;
|
|
339354
|
+
} catch {
|
|
339355
|
+
return false;
|
|
339356
|
+
}
|
|
339357
|
+
}
|
|
339358
|
+
function isIsoTimestamp(value) {
|
|
339359
|
+
try {
|
|
339360
|
+
assertIsoTimestamp$2(value, "timestamp");
|
|
339361
|
+
return true;
|
|
339362
|
+
} catch {
|
|
339363
|
+
return false;
|
|
339364
|
+
}
|
|
339365
|
+
}
|
|
339366
|
+
function isNullableEntryCount(value) {
|
|
339367
|
+
return value === null || Number.isSafeInteger(value) && value >= 0;
|
|
339368
|
+
}
|
|
339369
|
+
function assertInventoryInvariants(bestandsstatus, aktualitaetsstatus, declaredEntryCount, lastRawObservedAt, capturedAt) {
|
|
339370
|
+
if (bestandsstatus === "counted" && declaredEntryCount === null) throw new Error("counted inventory requires a declared entry count");
|
|
339371
|
+
if (bestandsstatus !== "counted" && declaredEntryCount !== null) throw new Error(`${bestandsstatus} inventory must not declare an entry count`);
|
|
339372
|
+
if (aktualitaetsstatus === "fresh" && lastRawObservedAt === null) throw new Error("fresh inventory requires a last raw observed timestamp");
|
|
339373
|
+
if (capturedAt !== void 0 && lastRawObservedAt !== null && Date.parse(lastRawObservedAt) > Date.parse(capturedAt)) throw new Error("last raw observed timestamp must not be later than captured at");
|
|
339374
|
+
}
|
|
339375
|
+
function isRecord$12(value) {
|
|
339376
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
339377
|
+
}
|
|
339378
|
+
function hasOnlyKeys(value, allowedKeys) {
|
|
339379
|
+
return Object.keys(value).every((key) => allowedKeys.includes(key));
|
|
339380
|
+
}
|
|
339381
|
+
function isValidRecordId(value) {
|
|
339382
|
+
const length = [...value].length;
|
|
339383
|
+
return length >= 1 && length <= 200 && value.normalize("NFKC").trim() === value && !hasControlCharacter(value);
|
|
339384
|
+
}
|
|
339385
|
+
function isSafeRawLocator(value) {
|
|
339386
|
+
const length = [...value].length;
|
|
339387
|
+
return length >= 1 && length <= 1e3 && !hasControlCharacter(value);
|
|
339388
|
+
}
|
|
339389
|
+
function hasControlCharacter(value) {
|
|
339390
|
+
return [...value].some((character) => {
|
|
339391
|
+
const codePoint = character.codePointAt(0);
|
|
339392
|
+
return codePoint !== void 0 && (codePoint < 32 || codePoint === 127);
|
|
339393
|
+
});
|
|
339394
|
+
}
|
|
339395
|
+
function isMistakeInflowStatus(value) {
|
|
339396
|
+
if (typeof value !== "object" || value === null) return false;
|
|
339397
|
+
const item = value;
|
|
339398
|
+
if (item["version"] !== 1 || item["scope"] !== "lower_bound" || typeof item["generated_at"] !== "string" || !isIsoTimestamp(item["generated_at"]) || !isNonNegativeInteger(item["stale_after_seconds"]) || !Array.isArray(item["sources"])) return false;
|
|
339399
|
+
const sourceIds = /* @__PURE__ */ new Set();
|
|
339400
|
+
for (const source of item["sources"]) {
|
|
339401
|
+
if (!isMistakeSourceStatus(source)) return false;
|
|
339402
|
+
const sourceId = source["source_id"];
|
|
339403
|
+
if (sourceIds.has(sourceId)) return false;
|
|
339404
|
+
sourceIds.add(sourceId);
|
|
339405
|
+
}
|
|
339406
|
+
return true;
|
|
339407
|
+
}
|
|
339408
|
+
function isMistakeSourceStatus(value) {
|
|
339409
|
+
if (typeof value !== "object" || value === null) return false;
|
|
339410
|
+
const item = value;
|
|
339411
|
+
const recordTypes = item["record_types"];
|
|
339412
|
+
const watchdogReasons = item["watchdog_reasons"];
|
|
339413
|
+
if (!(typeof item["source_id"] === "string" && isNormalizedSourceId(item["source_id"]) && typeof item["raw_agent_id"] === "string" && item["raw_agent_id"].trim() !== "" && typeof item["canonical_agent_id"] === "string" && isNormalizedSourceId(item["canonical_agent_id"]) && typeof item["source_form"] === "string" && MISTAKE_SOURCE_FORMS.includes(item["source_form"]) && Array.isArray(recordTypes) && recordTypes.length > 0 && new Set(recordTypes).size === recordTypes.length && recordTypes.every((type) => typeof type === "string" && MISTAKE_RECORD_TYPES.includes(type)) && typeof item["bestandsstatus"] === "string" && MISTAKE_INVENTORY_STATUSES.includes(item["bestandsstatus"]) && typeof item["aktualitaetsstatus"] === "string" && MISTAKE_ACTUALITY_STATUSES.includes(item["aktualitaetsstatus"]) && isNullableEntryCount(item["declared_entry_count"]) && isNullableIsoTimestamp(item["last_raw_observed_at"]) && isNullableIsoTimestamp(item["last_attempt_at"]) && isNullableIsoTimestamp(item["last_success_at"]) && isNonNegativeInteger(item["successful_observations"]) && isNonNegativeInteger(item["active_observations"]) && isNonNegativeInteger(item["rejected_attempts"]) && isNonNegativeInteger(item["seconds_since_success_or_monitor_start"]) && typeof item["watchdog"] === "string" && MISTAKE_WATCHDOG_STATUSES.includes(item["watchdog"]) && Array.isArray(watchdogReasons) && watchdogReasons.every((reason) => typeof reason === "string" && reason.trim() !== ""))) return false;
|
|
339414
|
+
try {
|
|
339415
|
+
assertInventoryInvariants(item["bestandsstatus"], item["aktualitaetsstatus"], item["declared_entry_count"], item["last_raw_observed_at"]);
|
|
339416
|
+
return true;
|
|
339417
|
+
} catch {
|
|
339418
|
+
return false;
|
|
339419
|
+
}
|
|
339420
|
+
}
|
|
339421
|
+
function isNullableIsoTimestamp(value) {
|
|
339422
|
+
return value === null || typeof value === "string" && isIsoTimestamp(value);
|
|
339423
|
+
}
|
|
339424
|
+
function isNonNegativeInteger(value) {
|
|
339425
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
339426
|
+
}
|
|
339427
|
+
function isAlreadyExists$1(error) {
|
|
339428
|
+
return typeof error === "object" && error !== null && error.code === "EEXIST";
|
|
339429
|
+
}
|
|
339430
|
+
function isNotFound$2(error) {
|
|
339431
|
+
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
339432
|
+
}
|
|
339433
|
+
function isUnsupportedDirectorySync(error) {
|
|
339434
|
+
if (typeof error !== "object" || error === null) return false;
|
|
339435
|
+
return [
|
|
339436
|
+
"EACCES",
|
|
339437
|
+
"EBADF",
|
|
339438
|
+
"EINVAL",
|
|
339439
|
+
"EPERM"
|
|
339440
|
+
].includes(error.code ?? "");
|
|
339441
|
+
}
|
|
339442
|
+
function errorMessage$6(error) {
|
|
339443
|
+
return error instanceof Error ? error.message : String(error);
|
|
339444
|
+
}
|
|
339445
|
+
//#endregion
|
|
339446
|
+
//#region src/mistakes/source-sync.ts
|
|
339447
|
+
const DIRECTORY_SNAPSHOT_FORMAT = "blun.mistakes.directory-snapshot.v1";
|
|
339448
|
+
const TOKEN_ENV_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
339449
|
+
const UUID_RE = /^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i;
|
|
339450
|
+
const TRANSPORT_STALE_AFTER_SECONDS = 1440 * 60;
|
|
339451
|
+
const DEFAULT_DEPS$1 = {
|
|
339452
|
+
drain: (options) => drainMistakeOutbox(options),
|
|
339453
|
+
upload: (input, options) => uploadMistakeObservation(input, options),
|
|
339454
|
+
now: () => /* @__PURE__ */ new Date()
|
|
339455
|
+
};
|
|
339456
|
+
async function loadMistakeSourceSyncConfig(configPath) {
|
|
339457
|
+
const absolutePath = resolve(configPath);
|
|
339458
|
+
const fileStat = await lstat(absolutePath);
|
|
339459
|
+
if (fileStat.isSymbolicLink() || !fileStat.isFile()) throw new Error("mistake source config must be a regular, non-symlink file");
|
|
339460
|
+
let value;
|
|
339461
|
+
try {
|
|
339462
|
+
value = JSON.parse(await readFile(absolutePath, "utf8"));
|
|
339463
|
+
} catch (error) {
|
|
339464
|
+
if (error instanceof SyntaxError) throw new Error("mistake source config is not valid JSON", { cause: error });
|
|
339465
|
+
throw error;
|
|
339466
|
+
}
|
|
339467
|
+
return parseConfig(value, dirname(absolutePath));
|
|
339468
|
+
}
|
|
339469
|
+
async function buildSourceSnapshot(adapter) {
|
|
339470
|
+
return adapter.type === "file" ? buildFileSnapshot(adapter.path) : buildDirectorySnapshot(adapter.path, {
|
|
339471
|
+
include: adapter.include,
|
|
339472
|
+
recursive: adapter.recursive
|
|
339473
|
+
});
|
|
339474
|
+
}
|
|
339475
|
+
async function buildDirectorySnapshot(path, options = {}) {
|
|
339476
|
+
const root = resolve(path);
|
|
339477
|
+
const rootStat = await lstat(root);
|
|
339478
|
+
if (rootStat.isSymbolicLink() || !rootStat.isDirectory()) throw new Error(`directory source must be a regular, non-symlink directory: ${root}`);
|
|
339479
|
+
const canonicalRoot = await realpath(root);
|
|
339480
|
+
const include = options.include === void 0 ? void 0 : validateIncludePatterns(options.include, "directory include");
|
|
339481
|
+
const recursive = options.recursive ?? true;
|
|
339482
|
+
const files = await readDirectoryFiles(root, canonicalRoot, recursive, include === void 0 ? void 0 : compileIncludePatterns(include));
|
|
339483
|
+
if (include !== void 0 && files.length === 0) throw new Error(`directory include matched no regular files: ${include.join(", ")}`);
|
|
339484
|
+
const orderedFiles = files.toSorted((left, right) => Buffer.compare(Buffer.from(left.path), Buffer.from(right.path)));
|
|
339485
|
+
const totalBytes = orderedFiles.reduce((sum, file) => sum + file.bytes, 0);
|
|
339486
|
+
const latestMtimeMs = orderedFiles.reduce((latest, file) => latest === null || file.mtimeMs > latest ? file.mtimeMs : latest, null);
|
|
339487
|
+
const document = {
|
|
339488
|
+
format: DIRECTORY_SNAPSHOT_FORMAT,
|
|
339489
|
+
version: 1,
|
|
339490
|
+
file_count: orderedFiles.length,
|
|
339491
|
+
total_bytes: totalBytes,
|
|
339492
|
+
latest_mtime: latestMtimeMs === null ? null : new Date(Math.trunc(latestMtimeMs)).toISOString(),
|
|
339493
|
+
selection: {
|
|
339494
|
+
include: include === void 0 ? null : include.toSorted(compareUtf8),
|
|
339495
|
+
recursive
|
|
339496
|
+
},
|
|
339497
|
+
files: orderedFiles.map(({ mtimeMs: _mtimeMs, ...file }) => file)
|
|
339498
|
+
};
|
|
339499
|
+
const payload = Buffer.from(`${JSON.stringify(document)}\n`, "utf8");
|
|
339500
|
+
assertSnapshotSize(payload);
|
|
339501
|
+
return snapshotResult("directory", "directory-snapshot.json", payload, orderedFiles.length, totalBytes, document.latest_mtime);
|
|
339502
|
+
}
|
|
339503
|
+
async function syncMistakeSources(options, deps = DEFAULT_DEPS$1) {
|
|
339504
|
+
const configPath = resolve(options.configPath);
|
|
339505
|
+
const config = await loadMistakeSourceSyncConfig(configPath);
|
|
339506
|
+
const baseOutbox = resolve(options.outboxDir ?? config.outbox ?? join(dirname(configPath), ".mistake-inflow-outbox"));
|
|
339507
|
+
const startedAt = deps.now().toISOString();
|
|
339508
|
+
const results = [];
|
|
339509
|
+
for (const source of config.sources.toSorted((left, right) => compareUtf8(left.sourceId, right.sourceId))) {
|
|
339510
|
+
if (source.adapter.type === "unsupported") {
|
|
339511
|
+
results.push({
|
|
339512
|
+
source_id: source.sourceId,
|
|
339513
|
+
agent_id: source.agentId,
|
|
339514
|
+
adapter: "unsupported",
|
|
339515
|
+
bestandsstatus: source.bestandsstatus,
|
|
339516
|
+
aktualitaetsstatus: source.aktualitaetsstatus,
|
|
339517
|
+
status: "blocked",
|
|
339518
|
+
retry: null,
|
|
339519
|
+
entry_count: entryCountResult(source),
|
|
339520
|
+
snapshot: null,
|
|
339521
|
+
reason: source.adapter.reason
|
|
339522
|
+
});
|
|
339523
|
+
continue;
|
|
339524
|
+
}
|
|
339525
|
+
const sourceOutbox = join(baseOutbox, "sources", source.sourceId);
|
|
339526
|
+
let retry = null;
|
|
339527
|
+
try {
|
|
339528
|
+
await assertOutboxOutsideSource(source.adapter, sourceOutbox);
|
|
339529
|
+
const endpoint = options.endpoint ?? source.endpoint ?? config.endpoint;
|
|
339530
|
+
if (!endpoint) throw new Error("no endpoint configured");
|
|
339531
|
+
const tokenEnv = source.tokenEnv;
|
|
339532
|
+
if (!tokenEnv) throw new Error("supported source has no token_env");
|
|
339533
|
+
const token = options.env[tokenEnv];
|
|
339534
|
+
if (!token || token.trim() === "") throw new Error(`missing bearer token in ${tokenEnv}`);
|
|
339535
|
+
const connection = {
|
|
339536
|
+
endpoint,
|
|
339537
|
+
token,
|
|
339538
|
+
outboxDir: sourceOutbox
|
|
339539
|
+
};
|
|
339540
|
+
retry = await deps.drain(connection);
|
|
339541
|
+
if (retry.failed.length > 0) throw new Error(`retry failed for ${retry.failed.length} queued observation(s)`);
|
|
339542
|
+
const snapshot = await buildSourceSnapshot(source.adapter);
|
|
339543
|
+
assertEntryCountBasis(source, snapshot);
|
|
339544
|
+
const declarations = source.declarationsPath === void 0 ? void 0 : await readExplicitDeclarations(source.declarationsPath, source.sourceId, source.recordTypes);
|
|
339545
|
+
const capturedAt = deps.now().toISOString();
|
|
339546
|
+
const input = observationInput(source, snapshot, capturedAt, declarations);
|
|
339547
|
+
const existing = await findVerifiedSnapshotReceipt(source, snapshot, input, sourceOutbox);
|
|
339548
|
+
const heartbeatIntervalSeconds = source.heartbeatIntervalSeconds ?? config.heartbeatIntervalSeconds;
|
|
339549
|
+
if (existing !== null && receiptIsWithinHeartbeat(existing, capturedAt, heartbeatIntervalSeconds)) {
|
|
339550
|
+
results.push(resultForSnapshot(source, snapshot, "unchanged", retry, existing));
|
|
339551
|
+
continue;
|
|
339552
|
+
}
|
|
339553
|
+
const materializedPath = await materializeSnapshot(snapshot, sourceOutbox);
|
|
339554
|
+
const receipt = await deps.upload({
|
|
339555
|
+
...input,
|
|
339556
|
+
filePath: materializedPath
|
|
339557
|
+
}, connection);
|
|
339558
|
+
assertReceiptIdentity(receipt, source, snapshot, input.declaredEntryCount);
|
|
339559
|
+
results.push(resultForSnapshot(source, snapshot, existing === null ? "uploaded" : "heartbeat", retry, receipt, existing ?? void 0));
|
|
339560
|
+
} catch (error) {
|
|
339561
|
+
results.push({
|
|
339562
|
+
source_id: source.sourceId,
|
|
339563
|
+
agent_id: source.agentId,
|
|
339564
|
+
adapter: source.adapter.type,
|
|
339565
|
+
bestandsstatus: source.bestandsstatus,
|
|
339566
|
+
aktualitaetsstatus: source.aktualitaetsstatus,
|
|
339567
|
+
status: "failed",
|
|
339568
|
+
retry: retry === null ? null : {
|
|
339569
|
+
delivered: retry.delivered.length,
|
|
339570
|
+
failed: retry.failed.length
|
|
339571
|
+
},
|
|
339572
|
+
entry_count: entryCountResult(source, false),
|
|
339573
|
+
snapshot: null,
|
|
339574
|
+
reason: errorMessage$5(error)
|
|
339575
|
+
});
|
|
339576
|
+
}
|
|
339577
|
+
}
|
|
339578
|
+
return {
|
|
339579
|
+
version: 1,
|
|
339580
|
+
config_path: configPath,
|
|
339581
|
+
started_at: startedAt,
|
|
339582
|
+
finished_at: deps.now().toISOString(),
|
|
339583
|
+
results
|
|
339584
|
+
};
|
|
339585
|
+
}
|
|
339586
|
+
async function watchMistakeSources(options, deps = DEFAULT_DEPS$1) {
|
|
339587
|
+
if (!Number.isSafeInteger(options.intervalMs) || options.intervalMs < 1e3) throw new Error("watch interval must be at least 1000 milliseconds");
|
|
339588
|
+
while (!options.signal?.aborted) {
|
|
339589
|
+
await options.onRun(await syncMistakeSources(options, deps));
|
|
339590
|
+
await waitForInterval(options.intervalMs, options.signal);
|
|
339591
|
+
}
|
|
339592
|
+
}
|
|
339593
|
+
function parseConfig(value, configDir) {
|
|
339594
|
+
const root = objectValue(value, "config");
|
|
339595
|
+
exactKeys(root, [
|
|
339596
|
+
"version",
|
|
339597
|
+
"endpoint",
|
|
339598
|
+
"outbox",
|
|
339599
|
+
"heartbeat_interval_seconds",
|
|
339600
|
+
"sources"
|
|
339601
|
+
], "config");
|
|
339602
|
+
if (root["version"] !== 1) throw new Error("mistake source config version must be 1");
|
|
339603
|
+
const endpoint = optionalNonEmptyString$1(root["endpoint"], "config.endpoint");
|
|
339604
|
+
const outboxValue = optionalNonEmptyString$1(root["outbox"], "config.outbox");
|
|
339605
|
+
const heartbeatIntervalSeconds = heartbeatInterval(root["heartbeat_interval_seconds"], "config.heartbeat_interval_seconds") ?? 43200;
|
|
339606
|
+
const sourcesValue = root["sources"];
|
|
339607
|
+
if (!Array.isArray(sourcesValue) || sourcesValue.length === 0) throw new Error("config.sources must be a non-empty array");
|
|
339608
|
+
const sources = sourcesValue.map((source, index) => parseSource(source, index, configDir));
|
|
339609
|
+
const sourceIds = sources.map((source) => source.sourceId);
|
|
339610
|
+
if (new Set(sourceIds).size !== sourceIds.length) throw new Error("config contains duplicate normalized source ids");
|
|
339611
|
+
const tokenEnvs = sources.flatMap((source) => source.tokenEnv === void 0 ? [] : [source.tokenEnv]);
|
|
339612
|
+
if (new Set(tokenEnvs).size !== tokenEnvs.length) throw new Error("each supported source must use its own token_env");
|
|
339613
|
+
return {
|
|
339614
|
+
version: 1,
|
|
339615
|
+
endpoint,
|
|
339616
|
+
outbox: outboxValue === void 0 ? void 0 : configuredPath(outboxValue, configDir, "config.outbox"),
|
|
339617
|
+
heartbeatIntervalSeconds,
|
|
339618
|
+
sources
|
|
339619
|
+
};
|
|
339620
|
+
}
|
|
339621
|
+
function parseSource(value, index, configDir) {
|
|
339622
|
+
const label = `config.sources[${index}]`;
|
|
339623
|
+
const source = objectValue(value, label);
|
|
339624
|
+
exactKeys(source, [
|
|
339625
|
+
"source_id",
|
|
339626
|
+
"agent_id",
|
|
339627
|
+
"endpoint",
|
|
339628
|
+
"token_env",
|
|
339629
|
+
"heartbeat_interval_seconds",
|
|
339630
|
+
"source_form",
|
|
339631
|
+
"record_types",
|
|
339632
|
+
"bestandsstatus",
|
|
339633
|
+
"aktualitaetsstatus",
|
|
339634
|
+
"declared_entry_count",
|
|
339635
|
+
"entry_count_basis",
|
|
339636
|
+
"declarations_path",
|
|
339637
|
+
"adapter"
|
|
339638
|
+
], label);
|
|
339639
|
+
const sourceId = normalizeMistakeSourceId(nonEmptyString(source["source_id"], `${label}.source_id`));
|
|
339640
|
+
const agentId = normalizeMistakeSourceId(nonEmptyString(source["agent_id"], `${label}.agent_id`));
|
|
339641
|
+
const sourceForm = enumValue(source["source_form"], MISTAKE_SOURCE_FORMS, `${label}.source_form`);
|
|
339642
|
+
const recordTypes = enumArray(source["record_types"], MISTAKE_RECORD_TYPES, `${label}.record_types`);
|
|
339643
|
+
const bestandsstatus = enumValue(source["bestandsstatus"], MISTAKE_INVENTORY_STATUSES, `${label}.bestandsstatus`);
|
|
339644
|
+
const aktualitaetsstatus = enumValue(source["aktualitaetsstatus"], MISTAKE_ACTUALITY_STATUSES, `${label}.aktualitaetsstatus`);
|
|
339645
|
+
const endpoint = optionalNonEmptyString$1(source["endpoint"], `${label}.endpoint`);
|
|
339646
|
+
const tokenEnv = optionalNonEmptyString$1(source["token_env"], `${label}.token_env`);
|
|
339647
|
+
const heartbeatIntervalSeconds = heartbeatInterval(source["heartbeat_interval_seconds"], `${label}.heartbeat_interval_seconds`);
|
|
339648
|
+
const declaredEntryCount = optionalCount(source["declared_entry_count"], `${label}.declared_entry_count`);
|
|
339649
|
+
const entryCountBasis = optionalEnumValue(source["entry_count_basis"], ["files", "declared"], `${label}.entry_count_basis`);
|
|
339650
|
+
const declarationsValue = optionalNonEmptyString$1(source["declarations_path"], `${label}.declarations_path`);
|
|
339651
|
+
const declarationsPath = declarationsValue === void 0 ? void 0 : configuredPath(declarationsValue, configDir, `${label}.declarations_path`);
|
|
339652
|
+
const adapter = parseAdapter(source["adapter"], label, configDir);
|
|
339653
|
+
if (bestandsstatus === "counted" && declaredEntryCount === void 0) throw new Error(`${label}.declared_entry_count is required when bestandsstatus is counted`);
|
|
339654
|
+
if (bestandsstatus === "counted" && entryCountBasis === void 0) throw new Error(`${label}.entry_count_basis is required when bestandsstatus is counted`);
|
|
339655
|
+
if (bestandsstatus !== "counted" && declaredEntryCount !== void 0) throw new Error(`${label}.declared_entry_count is forbidden unless bestandsstatus is counted`);
|
|
339656
|
+
if (bestandsstatus !== "counted" && entryCountBasis !== void 0) throw new Error(`${label}.entry_count_basis is forbidden unless bestandsstatus is counted`);
|
|
339657
|
+
if (adapter.type === "unsupported") {
|
|
339658
|
+
if (bestandsstatus !== "unverified" || aktualitaetsstatus !== "unverified") throw new Error(`${label} unsupported adapters must use unverified inventory and actuality statuses`);
|
|
339659
|
+
if (tokenEnv !== void 0 || endpoint !== void 0 || heartbeatIntervalSeconds !== void 0 || declarationsPath !== void 0) throw new Error(`${label} unsupported adapters must not declare endpoint, token_env, heartbeat_interval_seconds, or declarations_path`);
|
|
339660
|
+
} else if (tokenEnv === void 0 || !TOKEN_ENV_RE.test(tokenEnv)) throw new Error(`${label}.token_env must name a dedicated environment variable`);
|
|
339661
|
+
return {
|
|
339662
|
+
sourceId,
|
|
339663
|
+
agentId,
|
|
339664
|
+
endpoint,
|
|
339665
|
+
tokenEnv,
|
|
339666
|
+
heartbeatIntervalSeconds,
|
|
339667
|
+
sourceForm,
|
|
339668
|
+
recordTypes,
|
|
339669
|
+
bestandsstatus,
|
|
339670
|
+
aktualitaetsstatus,
|
|
339671
|
+
declaredEntryCount,
|
|
339672
|
+
entryCountBasis,
|
|
339673
|
+
declarationsPath,
|
|
339674
|
+
adapter
|
|
339675
|
+
};
|
|
339676
|
+
}
|
|
339677
|
+
function parseAdapter(value, sourceLabel, configDir) {
|
|
339678
|
+
const label = `${sourceLabel}.adapter`;
|
|
339679
|
+
const adapter = objectValue(value, label);
|
|
339680
|
+
const type = adapter["type"];
|
|
339681
|
+
if (type === "file" || type === "directory") {
|
|
339682
|
+
if (type === "file") {
|
|
339683
|
+
exactKeys(adapter, ["type", "path"], label);
|
|
339684
|
+
return {
|
|
339685
|
+
type,
|
|
339686
|
+
path: configuredPath(nonEmptyString(adapter["path"], `${label}.path`), configDir, `${label}.path`)
|
|
339687
|
+
};
|
|
339688
|
+
}
|
|
339689
|
+
exactKeys(adapter, [
|
|
339690
|
+
"type",
|
|
339691
|
+
"path",
|
|
339692
|
+
"include",
|
|
339693
|
+
"recursive"
|
|
339694
|
+
], label);
|
|
339695
|
+
const include = adapter["include"] === void 0 ? void 0 : validateIncludePatterns(adapter["include"], `${label}.include`);
|
|
339696
|
+
const recursive = adapter["recursive"] === void 0 ? true : booleanValue(adapter["recursive"], `${label}.recursive`);
|
|
339697
|
+
return {
|
|
339698
|
+
type,
|
|
339699
|
+
path: configuredPath(nonEmptyString(adapter["path"], `${label}.path`), configDir, `${label}.path`),
|
|
339700
|
+
include,
|
|
339701
|
+
recursive
|
|
339702
|
+
};
|
|
339703
|
+
}
|
|
339704
|
+
if (type === "unsupported") {
|
|
339705
|
+
exactKeys(adapter, [
|
|
339706
|
+
"type",
|
|
339707
|
+
"kind",
|
|
339708
|
+
"reason"
|
|
339709
|
+
], label);
|
|
339710
|
+
return {
|
|
339711
|
+
type,
|
|
339712
|
+
kind: nonEmptyString(adapter["kind"], `${label}.kind`),
|
|
339713
|
+
reason: nonEmptyString(adapter["reason"], `${label}.reason`)
|
|
339714
|
+
};
|
|
339715
|
+
}
|
|
339716
|
+
throw new Error(`${label}.type must be file, directory, or unsupported`);
|
|
339717
|
+
}
|
|
339718
|
+
async function buildFileSnapshot(path) {
|
|
339719
|
+
const absolutePath = resolve(path);
|
|
339720
|
+
const before = await lstat(absolutePath);
|
|
339721
|
+
if (before.isSymbolicLink() || !before.isFile()) throw new Error(`file source must be a regular, non-symlink file: ${absolutePath}`);
|
|
339722
|
+
const handle = await openWithoutFollowing(absolutePath);
|
|
339723
|
+
let payload;
|
|
339724
|
+
try {
|
|
339725
|
+
const opened = await handle.stat();
|
|
339726
|
+
if (!opened.isFile()) throw new Error(`file source changed while reading: ${absolutePath}`);
|
|
339727
|
+
if (before.size !== opened.size || before.mtimeMs !== opened.mtimeMs) throw new Error(`file source changed while opening: ${absolutePath}`);
|
|
339728
|
+
payload = await handle.readFile();
|
|
339729
|
+
const after = await handle.stat();
|
|
339730
|
+
if (opened.size !== after.size || opened.mtimeMs !== after.mtimeMs) throw new Error(`file source changed while reading: ${absolutePath}`);
|
|
339731
|
+
} finally {
|
|
339732
|
+
await handle.close();
|
|
339733
|
+
}
|
|
339734
|
+
assertSnapshotSize(payload);
|
|
339735
|
+
return snapshotResult("file", basename(absolutePath), payload, 1, payload.byteLength, new Date(Math.trunc(before.mtimeMs)).toISOString());
|
|
339736
|
+
}
|
|
339737
|
+
async function readDirectoryFiles(root, canonicalRoot, recursive, matches) {
|
|
339738
|
+
const files = [];
|
|
339739
|
+
async function visit(directory) {
|
|
339740
|
+
const entries = (await readdir(directory, { withFileTypes: true })).toSorted((left, right) => Buffer.compare(Buffer.from(left.name), Buffer.from(right.name)));
|
|
339741
|
+
for (const entry of entries) {
|
|
339742
|
+
const absolutePath = join(directory, entry.name);
|
|
339743
|
+
const entryStat = await lstat(absolutePath);
|
|
339744
|
+
if (entry.isSymbolicLink() || entryStat.isSymbolicLink()) throw new Error(`directory source contains a symlink: ${absolutePath}`);
|
|
339745
|
+
const relativePath = canonicalRelativePath(root, absolutePath);
|
|
339746
|
+
assertContained(canonicalRoot, await realpath(absolutePath), absolutePath);
|
|
339747
|
+
if (entryStat.isDirectory()) {
|
|
339748
|
+
if (recursive) await visit(absolutePath);
|
|
339749
|
+
continue;
|
|
339750
|
+
}
|
|
339751
|
+
if (!entryStat.isFile()) throw new Error(`directory source contains a non-regular entry: ${absolutePath}`);
|
|
339752
|
+
if (matches !== void 0 && !matches(relativePath)) continue;
|
|
339753
|
+
const handle = await openWithoutFollowing(absolutePath);
|
|
339754
|
+
let content;
|
|
339755
|
+
try {
|
|
339756
|
+
const before = await handle.stat();
|
|
339757
|
+
if (!before.isFile()) throw new Error(`directory source entry changed while reading: ${absolutePath}`);
|
|
339758
|
+
if (entryStat.size !== before.size || entryStat.mtimeMs !== before.mtimeMs) throw new Error(`directory source entry changed while opening: ${absolutePath}`);
|
|
339759
|
+
content = await handle.readFile();
|
|
339760
|
+
const after = await handle.stat();
|
|
339761
|
+
if (before.size !== after.size || before.mtimeMs !== after.mtimeMs) throw new Error(`directory source entry changed while reading: ${absolutePath}`);
|
|
339762
|
+
} finally {
|
|
339763
|
+
await handle.close();
|
|
339764
|
+
}
|
|
339765
|
+
files.push({
|
|
339766
|
+
path: relativePath,
|
|
339767
|
+
bytes: content.byteLength,
|
|
339768
|
+
sha256: sha256$3(content),
|
|
339769
|
+
mtime: new Date(Math.trunc(entryStat.mtimeMs)).toISOString(),
|
|
339770
|
+
content_base64: content.toString("base64"),
|
|
339771
|
+
mtimeMs: entryStat.mtimeMs
|
|
339772
|
+
});
|
|
339773
|
+
}
|
|
339774
|
+
}
|
|
339775
|
+
await visit(root);
|
|
339776
|
+
const secondScan = await scanDirectoryMetadata(root, canonicalRoot, recursive, matches);
|
|
339777
|
+
const firstScan = files.map((file) => ({
|
|
339778
|
+
path: file.path,
|
|
339779
|
+
bytes: file.bytes,
|
|
339780
|
+
mtimeMs: file.mtimeMs
|
|
339781
|
+
})).toSorted(compareMetadata);
|
|
339782
|
+
if (JSON.stringify(firstScan) !== JSON.stringify(secondScan)) throw new Error("directory source changed while snapshotting");
|
|
339783
|
+
return files;
|
|
339784
|
+
}
|
|
339785
|
+
async function scanDirectoryMetadata(root, canonicalRoot, recursive, matches) {
|
|
339786
|
+
const files = [];
|
|
339787
|
+
async function visit(directory) {
|
|
339788
|
+
const entries = (await readdir(directory, { withFileTypes: true })).toSorted((left, right) => Buffer.compare(Buffer.from(left.name), Buffer.from(right.name)));
|
|
339789
|
+
for (const entry of entries) {
|
|
339790
|
+
const absolutePath = join(directory, entry.name);
|
|
339791
|
+
const entryStat = await lstat(absolutePath);
|
|
339792
|
+
if (entry.isSymbolicLink() || entryStat.isSymbolicLink()) throw new Error(`directory source contains a symlink: ${absolutePath}`);
|
|
339793
|
+
const relativePath = canonicalRelativePath(root, absolutePath);
|
|
339794
|
+
assertContained(canonicalRoot, await realpath(absolutePath), absolutePath);
|
|
339795
|
+
if (entryStat.isDirectory()) {
|
|
339796
|
+
if (recursive) await visit(absolutePath);
|
|
339797
|
+
continue;
|
|
339798
|
+
}
|
|
339799
|
+
if (!entryStat.isFile()) throw new Error(`directory source contains a non-regular entry: ${absolutePath}`);
|
|
339800
|
+
if (matches === void 0 || matches(relativePath)) files.push({
|
|
339801
|
+
path: relativePath,
|
|
339802
|
+
bytes: entryStat.size,
|
|
339803
|
+
mtimeMs: entryStat.mtimeMs
|
|
339804
|
+
});
|
|
339805
|
+
}
|
|
339806
|
+
}
|
|
339807
|
+
await visit(root);
|
|
339808
|
+
return files.toSorted(compareMetadata);
|
|
339809
|
+
}
|
|
339810
|
+
function compareMetadata(left, right) {
|
|
339811
|
+
return compareUtf8(left.path, right.path) || left.bytes - right.bytes || left.mtimeMs - right.mtimeMs;
|
|
339812
|
+
}
|
|
339813
|
+
async function openWithoutFollowing(path) {
|
|
339814
|
+
const noFollow = typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
339815
|
+
try {
|
|
339816
|
+
return await open(path, constants.O_RDONLY | noFollow);
|
|
339817
|
+
} catch (error) {
|
|
339818
|
+
if (isSymlinkOpenError(error)) throw new Error(`refusing to follow source symlink: ${path}`, { cause: error });
|
|
339819
|
+
throw error;
|
|
339820
|
+
}
|
|
339821
|
+
}
|
|
339822
|
+
function canonicalRelativePath(root, path) {
|
|
339823
|
+
const value = relative(root, path);
|
|
339824
|
+
const segments = value.split(sep);
|
|
339825
|
+
if (value === "" || isAbsolute(value) || segments.some((segment) => segment === "" || segment === "." || segment === "..")) throw new Error(`source entry escapes its configured directory: ${path}`);
|
|
339826
|
+
const canonical = segments.join("/");
|
|
339827
|
+
if (canonical.startsWith("/") || canonical.includes("/../") || canonical.includes("\\")) throw new Error(`source entry has an unsafe relative path: ${path}`);
|
|
339828
|
+
return canonical;
|
|
339829
|
+
}
|
|
339830
|
+
function assertContained(root, candidate, originalPath) {
|
|
339831
|
+
const value = relative(root, candidate);
|
|
339832
|
+
if (value === ".." || value.startsWith(`..${sep}`) || isAbsolute(value)) throw new Error(`source entry resolves outside its configured directory: ${originalPath}`);
|
|
339833
|
+
}
|
|
339834
|
+
function snapshotResult(adapterType, originalName, payload, fileCount, totalBytes, latestMtime) {
|
|
339835
|
+
return {
|
|
339836
|
+
adapterType,
|
|
339837
|
+
originalName,
|
|
339838
|
+
payload,
|
|
339839
|
+
rawBytes: payload.byteLength,
|
|
339840
|
+
rawSha256: sha256$3(payload),
|
|
339841
|
+
fileCount,
|
|
339842
|
+
totalBytes,
|
|
339843
|
+
latestMtime
|
|
339844
|
+
};
|
|
339845
|
+
}
|
|
339846
|
+
function observationInput(source, snapshot, capturedAt, declarations) {
|
|
339847
|
+
return {
|
|
339848
|
+
sourceId: source.sourceId,
|
|
339849
|
+
sourceForm: source.sourceForm,
|
|
339850
|
+
recordTypes: source.recordTypes,
|
|
339851
|
+
bestandsstatus: source.bestandsstatus,
|
|
339852
|
+
aktualitaetsstatus: source.aktualitaetsstatus,
|
|
339853
|
+
declaredEntryCount: source.declaredEntryCount,
|
|
339854
|
+
lastRawObservedAt: snapshot.latestMtime ?? void 0,
|
|
339855
|
+
capturedAt,
|
|
339856
|
+
declarations
|
|
339857
|
+
};
|
|
339858
|
+
}
|
|
339859
|
+
async function readExplicitDeclarations(path, sourceId, recordTypes) {
|
|
339860
|
+
const fileStat = await lstat(path);
|
|
339861
|
+
if (fileStat.isSymbolicLink() || !fileStat.isFile()) throw new Error(`declarations_path must be a regular, non-symlink file: ${path}`);
|
|
339862
|
+
const handle = await openWithoutFollowing(path);
|
|
339863
|
+
let text;
|
|
339864
|
+
try {
|
|
339865
|
+
const opened = await handle.stat();
|
|
339866
|
+
if (fileStat.size !== opened.size || fileStat.mtimeMs !== opened.mtimeMs) throw new Error(`declarations_path changed while opening: ${path}`);
|
|
339867
|
+
text = await handle.readFile("utf8");
|
|
339868
|
+
const after = await handle.stat();
|
|
339869
|
+
if (opened.size !== after.size || opened.mtimeMs !== after.mtimeMs) throw new Error(`declarations_path changed while reading: ${path}`);
|
|
339870
|
+
} finally {
|
|
339871
|
+
await handle.close();
|
|
339872
|
+
}
|
|
339873
|
+
let value;
|
|
339874
|
+
try {
|
|
339875
|
+
value = JSON.parse(text);
|
|
339876
|
+
} catch (error) {
|
|
339877
|
+
throw new Error(`declarations_path is not valid JSON: ${path}`, { cause: error });
|
|
339878
|
+
}
|
|
339879
|
+
return parseMistakeRecordDeclarations(value, sourceId, recordTypes);
|
|
339880
|
+
}
|
|
339881
|
+
async function materializeSnapshot(snapshot, outboxDir) {
|
|
339882
|
+
const directory = join(outboxDir, "snapshots", snapshot.rawSha256);
|
|
339883
|
+
await mkdir(directory, {
|
|
339884
|
+
recursive: true,
|
|
339885
|
+
mode: 448
|
|
339886
|
+
});
|
|
339887
|
+
const path = join(directory, snapshot.originalName);
|
|
339888
|
+
try {
|
|
339889
|
+
await writeFile(path, snapshot.payload, {
|
|
339890
|
+
flag: "wx",
|
|
339891
|
+
mode: 384
|
|
339892
|
+
});
|
|
339893
|
+
} catch (error) {
|
|
339894
|
+
if (!isAlreadyExists(error)) throw error;
|
|
339895
|
+
if (!(await readFile(path)).equals(snapshot.payload)) throw new Error(`snapshot cache conflict for ${snapshot.rawSha256}`, { cause: error });
|
|
339896
|
+
}
|
|
339897
|
+
return path;
|
|
339898
|
+
}
|
|
339899
|
+
async function findVerifiedSnapshotReceipt(source, snapshot, input, outboxDir) {
|
|
339900
|
+
const eventsDir = join(outboxDir, "events");
|
|
339901
|
+
let names;
|
|
339902
|
+
try {
|
|
339903
|
+
names = (await readdir(eventsDir)).filter((name) => name.endsWith(".json")).toSorted();
|
|
339904
|
+
} catch (error) {
|
|
339905
|
+
if (isNotFound$1(error)) return null;
|
|
339906
|
+
throw error;
|
|
339907
|
+
}
|
|
339908
|
+
let newest = null;
|
|
339909
|
+
for (const name of names) {
|
|
339910
|
+
const event = await readJson(join(eventsDir, name));
|
|
339911
|
+
if (!eventMatchesSnapshot(event, source, snapshot, input)) continue;
|
|
339912
|
+
const clientEventId = event.client_event_id;
|
|
339913
|
+
const paths = [join(outboxDir, "receipts", `${clientEventId}.json`)];
|
|
339914
|
+
try {
|
|
339915
|
+
const receiptNames = (await readdir(join(outboxDir, "receipts", clientEventId))).filter((receiptName) => receiptName.endsWith(".json")).toSorted();
|
|
339916
|
+
paths.push(...receiptNames.map((receiptName) => join(outboxDir, "receipts", clientEventId, receiptName)));
|
|
339917
|
+
} catch (error) {
|
|
339918
|
+
if (!isNotFound$1(error)) throw error;
|
|
339919
|
+
}
|
|
339920
|
+
for (const path of paths) {
|
|
339921
|
+
const receipt = await readJson(path);
|
|
339922
|
+
if (receiptMatchesSnapshot(receipt, source, snapshot, event.inventory.declared_entry_count, event.client_event_id)) {
|
|
339923
|
+
if (newest === null || compareReceiptsByReceivedAt(receipt, newest) > 0) newest = receipt;
|
|
339924
|
+
}
|
|
339925
|
+
}
|
|
339926
|
+
}
|
|
339927
|
+
return newest;
|
|
339928
|
+
}
|
|
339929
|
+
function compareReceiptsByReceivedAt(left, right) {
|
|
339930
|
+
return Date.parse(left.received_at) - Date.parse(right.received_at) || compareUtf8(left.event_id, right.event_id);
|
|
339931
|
+
}
|
|
339932
|
+
function receiptIsWithinHeartbeat(receipt, nowIso, heartbeatIntervalSeconds) {
|
|
339933
|
+
const ageMilliseconds = Date.parse(nowIso) - Date.parse(receipt.received_at);
|
|
339934
|
+
return ageMilliseconds >= 0 && ageMilliseconds < heartbeatIntervalSeconds * 1e3;
|
|
339935
|
+
}
|
|
339936
|
+
function eventMatchesSnapshot(value, source, snapshot, input) {
|
|
339937
|
+
if (!isObject$3(value)) return false;
|
|
339938
|
+
const inventory = value["inventory"];
|
|
339939
|
+
if (!isObject$3(inventory)) return false;
|
|
339940
|
+
const payloadBase64 = value["payload_base64"];
|
|
339941
|
+
if (typeof payloadBase64 !== "string") return false;
|
|
339942
|
+
const payload = Buffer.from(payloadBase64, "base64");
|
|
339943
|
+
return payload.toString("base64") === payloadBase64 && payload.equals(snapshot.payload) && value["version"] === 1 && value["source_id"] === source.sourceId && value["source_form"] === source.sourceForm && arraysEqual(value["declared_record_types"], source.recordTypes) && value["declared_raw_bytes"] === snapshot.rawBytes && value["declared_raw_sha256"] === snapshot.rawSha256 && sha256$3(payload) === snapshot.rawSha256 && inventory["scope"] === "lower_bound" && inventory["bestandsstatus"] === source.bestandsstatus && inventory["aktualitaetsstatus"] === source.aktualitaetsstatus && inventory["declared_entry_count"] === (input.declaredEntryCount ?? null) && inventory["last_raw_observed_at"] === (input.lastRawObservedAt ?? null) && declarationsEqual(value["declarations"], input.declarations) && typeof value["client_event_id"] === "string" && UUID_RE.test(value["client_event_id"]);
|
|
339944
|
+
}
|
|
339945
|
+
function receiptMatchesSnapshot(value, source, snapshot, declaredEntryCount, expectedClientEventId) {
|
|
339946
|
+
if (!isObject$3(value)) return false;
|
|
339947
|
+
return value["version"] === 1 && value["accepted"] === true && value["source_id"] === source.sourceId && value["canonical_agent_id"] === source.agentId && value["raw_count"] === 1 && value["accepted_count"] === 1 && value["rejected_count"] === 0 && value["raw_bytes"] === snapshot.rawBytes && value["raw_sha256"] === snapshot.rawSha256 && value["declared_entry_count"] === declaredEntryCount && typeof value["event_id"] === "string" && UUID_RE.test(value["event_id"]) && typeof value["client_event_id"] === "string" && UUID_RE.test(value["client_event_id"]) && (expectedClientEventId === void 0 || value["client_event_id"] === expectedClientEventId) && typeof value["received_at"] === "string" && Number.isFinite(Date.parse(value["received_at"]));
|
|
339948
|
+
}
|
|
339949
|
+
function assertReceiptIdentity(receipt, source, snapshot, declaredEntryCount) {
|
|
339950
|
+
if (!receiptMatchesSnapshot(receipt, source, snapshot, declaredEntryCount ?? null, receipt.client_event_id)) throw new Error(`receipt identity mismatch for ${source.sourceId}`);
|
|
339951
|
+
}
|
|
339952
|
+
function resultForSnapshot(source, snapshot, status, retry, receipt, previousReceipt) {
|
|
339953
|
+
return {
|
|
339954
|
+
source_id: source.sourceId,
|
|
339955
|
+
agent_id: source.agentId,
|
|
339956
|
+
adapter: source.adapter.type,
|
|
339957
|
+
bestandsstatus: source.bestandsstatus,
|
|
339958
|
+
aktualitaetsstatus: source.aktualitaetsstatus,
|
|
339959
|
+
status,
|
|
339960
|
+
retry: {
|
|
339961
|
+
delivered: retry.delivered.length,
|
|
339962
|
+
failed: retry.failed.length
|
|
339963
|
+
},
|
|
339964
|
+
entry_count: entryCountResult(source),
|
|
339965
|
+
snapshot: {
|
|
339966
|
+
file_count: snapshot.fileCount,
|
|
339967
|
+
total_bytes: snapshot.totalBytes,
|
|
339968
|
+
raw_bytes: snapshot.rawBytes,
|
|
339969
|
+
raw_sha256: snapshot.rawSha256,
|
|
339970
|
+
latest_mtime: snapshot.latestMtime
|
|
339971
|
+
},
|
|
339972
|
+
receipt,
|
|
339973
|
+
...previousReceipt === void 0 ? {} : { previous_receipt_received_at: previousReceipt.received_at }
|
|
339974
|
+
};
|
|
339975
|
+
}
|
|
339976
|
+
function configuredPath(value, configDir, label) {
|
|
339977
|
+
if (isAbsolute(value)) return resolve(value);
|
|
339978
|
+
if (value.replaceAll("\\", "/").split("/").some((segment) => segment === "..")) throw new Error(`${label} must not traverse above the config directory; use an absolute path instead`);
|
|
339979
|
+
return resolve(configDir, value);
|
|
339980
|
+
}
|
|
339981
|
+
async function assertOutboxOutsideSource(adapter, outboxDir) {
|
|
339982
|
+
if (adapter.type !== "directory") return;
|
|
339983
|
+
const sourceStat = await lstat(adapter.path);
|
|
339984
|
+
if (sourceStat.isSymbolicLink() || !sourceStat.isDirectory()) throw new Error(`directory source must be a regular, non-symlink directory: ${adapter.path}`);
|
|
339985
|
+
const position = relative(await realpath(adapter.path), await canonicalProspectivePath(outboxDir));
|
|
339986
|
+
if (position === "" || !isAbsolute(position) && position !== ".." && !position.startsWith(`..${sep}`)) throw new Error(`outbox must not be the directory source or be contained by it: ${adapter.path}`);
|
|
339987
|
+
}
|
|
339988
|
+
async function canonicalProspectivePath(path) {
|
|
339989
|
+
let cursor = resolve(path);
|
|
339990
|
+
const tail = [];
|
|
339991
|
+
while (true) try {
|
|
339992
|
+
await lstat(cursor);
|
|
339993
|
+
return resolve(await realpath(cursor), ...tail.toReversed());
|
|
339994
|
+
} catch (error) {
|
|
339995
|
+
if (!isNotFound$1(error)) throw error;
|
|
339996
|
+
const parent = dirname(cursor);
|
|
339997
|
+
if (parent === cursor) throw error;
|
|
339998
|
+
tail.push(basename(cursor));
|
|
339999
|
+
cursor = parent;
|
|
340000
|
+
}
|
|
340001
|
+
}
|
|
340002
|
+
function objectValue(value, label) {
|
|
340003
|
+
if (!isObject$3(value) || Array.isArray(value)) throw new Error(`${label} must be an object`);
|
|
340004
|
+
return value;
|
|
340005
|
+
}
|
|
340006
|
+
function exactKeys(value, keys, label) {
|
|
340007
|
+
const allowed = new Set(keys);
|
|
340008
|
+
const unknown = Object.keys(value).filter((key) => !allowed.has(key));
|
|
340009
|
+
if (unknown.length > 0) throw new Error(`${label} contains unknown fields: ${unknown.join(", ")}`);
|
|
340010
|
+
}
|
|
340011
|
+
function nonEmptyString(value, label) {
|
|
340012
|
+
if (typeof value !== "string" || value.trim() === "") throw new Error(`${label} must be a non-empty string`);
|
|
340013
|
+
return value.trim();
|
|
340014
|
+
}
|
|
340015
|
+
function optionalNonEmptyString$1(value, label) {
|
|
340016
|
+
return value === void 0 ? void 0 : nonEmptyString(value, label);
|
|
340017
|
+
}
|
|
340018
|
+
function optionalCount(value, label) {
|
|
340019
|
+
if (value === void 0) return void 0;
|
|
340020
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new Error(`${label} must be a non-negative integer`);
|
|
340021
|
+
return value;
|
|
340022
|
+
}
|
|
340023
|
+
function heartbeatInterval(value, label) {
|
|
340024
|
+
if (value === void 0) return void 0;
|
|
340025
|
+
if (!Number.isSafeInteger(value) || value < 60 || value >= TRANSPORT_STALE_AFTER_SECONDS) throw new Error(`${label} must be an integer from 60 through 86399 seconds`);
|
|
340026
|
+
return value;
|
|
340027
|
+
}
|
|
340028
|
+
function optionalEnumValue(value, allowed, label) {
|
|
340029
|
+
return value === void 0 ? void 0 : enumValue(value, allowed, label);
|
|
340030
|
+
}
|
|
340031
|
+
function enumValue(value, allowed, label) {
|
|
340032
|
+
if (typeof value !== "string" || !allowed.includes(value)) throw new Error(`${label} must be one of: ${allowed.join(", ")}`);
|
|
340033
|
+
return value;
|
|
340034
|
+
}
|
|
340035
|
+
function enumArray(value, allowed, label) {
|
|
340036
|
+
if (!Array.isArray(value) || value.length === 0 || value.some((item) => typeof item !== "string" || !allowed.includes(item))) throw new Error(`${label} must contain one or more of: ${allowed.join(", ")}`);
|
|
340037
|
+
const unique = [...new Set(value)];
|
|
340038
|
+
if (unique.length !== value.length) throw new Error(`${label} must not contain duplicates`);
|
|
340039
|
+
return unique;
|
|
340040
|
+
}
|
|
340041
|
+
function arraysEqual(value, expected) {
|
|
340042
|
+
return Array.isArray(value) && value.length === expected.length && value.every((item, index) => item === expected[index]);
|
|
340043
|
+
}
|
|
340044
|
+
function booleanValue(value, label) {
|
|
340045
|
+
if (typeof value !== "boolean") throw new Error(`${label} must be a boolean`);
|
|
340046
|
+
return value;
|
|
340047
|
+
}
|
|
340048
|
+
function validateIncludePatterns(value, label) {
|
|
340049
|
+
if (!Array.isArray(value) || value.length === 0) throw new Error(`${label} must be a non-empty array`);
|
|
340050
|
+
const patterns = value.map((candidate, index) => {
|
|
340051
|
+
if (typeof candidate !== "string" || candidate === "" || candidate.startsWith("/") || candidate.includes("\\") || candidate.split("/").some((segment) => segment === "" || segment === "." || segment === "..")) throw new Error(`${label}[${index}] must be a safe relative glob using forward slashes`);
|
|
340052
|
+
if ([...candidate].length > 300 || candidate.includes("\0")) throw new Error(`${label}[${index}] is too long or unsafe`);
|
|
340053
|
+
return candidate;
|
|
340054
|
+
});
|
|
340055
|
+
if (new Set(patterns).size !== patterns.length) throw new Error(`${label} must not contain duplicates`);
|
|
340056
|
+
return patterns;
|
|
340057
|
+
}
|
|
340058
|
+
function compileIncludePatterns(patterns) {
|
|
340059
|
+
const expressions = patterns.map((pattern) => new RegExp(`^${globExpression(pattern)}$`, "u"));
|
|
340060
|
+
return (path) => expressions.some((expression) => expression.test(path));
|
|
340061
|
+
}
|
|
340062
|
+
function globExpression(pattern) {
|
|
340063
|
+
let expression = "";
|
|
340064
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
340065
|
+
const character = pattern[index];
|
|
340066
|
+
if (character === "*" && pattern[index + 1] === "*") if (pattern[index + 2] === "/") {
|
|
340067
|
+
expression += "(?:.*/)?";
|
|
340068
|
+
index += 2;
|
|
340069
|
+
} else {
|
|
340070
|
+
expression += ".*";
|
|
340071
|
+
index += 1;
|
|
340072
|
+
}
|
|
340073
|
+
else if (character === "*") expression += "[^/]*";
|
|
340074
|
+
else if (character === "?") expression += "[^/]";
|
|
340075
|
+
else expression += escapeRegex$1(character);
|
|
340076
|
+
}
|
|
340077
|
+
return expression;
|
|
340078
|
+
}
|
|
340079
|
+
function escapeRegex$1(value) {
|
|
340080
|
+
return /[\\^$.*+?()[\]{}|]/.test(value) ? `\\${value}` : value;
|
|
340081
|
+
}
|
|
340082
|
+
function compareUtf8(left, right) {
|
|
340083
|
+
return Buffer.compare(Buffer.from(left), Buffer.from(right));
|
|
340084
|
+
}
|
|
340085
|
+
function assertEntryCountBasis(source, snapshot) {
|
|
340086
|
+
if (source.entryCountBasis === "files" && source.declaredEntryCount !== snapshot.fileCount) throw new Error(`declared entry count ${source.declaredEntryCount} does not match snapshot file count ${snapshot.fileCount}`);
|
|
340087
|
+
}
|
|
340088
|
+
function entryCountResult(source, checked = true) {
|
|
340089
|
+
return {
|
|
340090
|
+
declared: source.declaredEntryCount ?? null,
|
|
340091
|
+
basis: source.entryCountBasis ?? null,
|
|
340092
|
+
verification: source.entryCountBasis === "files" ? checked ? "matched_file_count" : "not_checked" : source.entryCountBasis === "declared" ? "not_derivable_from_raw_files" : "not_declared"
|
|
340093
|
+
};
|
|
340094
|
+
}
|
|
340095
|
+
function declarationsEqual(value, expected) {
|
|
340096
|
+
return expected === void 0 ? value === void 0 : JSON.stringify(value) === JSON.stringify(expected);
|
|
340097
|
+
}
|
|
340098
|
+
async function readJson(path) {
|
|
340099
|
+
try {
|
|
340100
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
340101
|
+
} catch (error) {
|
|
340102
|
+
if (isNotFound$1(error) || error instanceof SyntaxError) return null;
|
|
340103
|
+
throw error;
|
|
340104
|
+
}
|
|
340105
|
+
}
|
|
340106
|
+
function assertSnapshotSize(payload) {
|
|
340107
|
+
if (payload.byteLength > 20971520) throw new Error(`source snapshot exceeds ${MAX_MISTAKE_SOURCE_BYTES} bytes`);
|
|
340108
|
+
}
|
|
340109
|
+
function sha256$3(value) {
|
|
340110
|
+
return createHash("sha256").update(value).digest("hex");
|
|
340111
|
+
}
|
|
340112
|
+
function isObject$3(value) {
|
|
340113
|
+
return typeof value === "object" && value !== null;
|
|
340114
|
+
}
|
|
340115
|
+
function isAlreadyExists(error) {
|
|
340116
|
+
return isObject$3(error) && error["code"] === "EEXIST";
|
|
340117
|
+
}
|
|
340118
|
+
function isNotFound$1(error) {
|
|
340119
|
+
return isObject$3(error) && error["code"] === "ENOENT";
|
|
340120
|
+
}
|
|
340121
|
+
function isSymlinkOpenError(error) {
|
|
340122
|
+
return isObject$3(error) && ["ELOOP", "EMLINK"].includes(String(error["code"]));
|
|
340123
|
+
}
|
|
340124
|
+
function errorMessage$5(error) {
|
|
340125
|
+
return error instanceof Error ? error.message : String(error);
|
|
340126
|
+
}
|
|
340127
|
+
function waitForInterval(milliseconds, signal) {
|
|
340128
|
+
if (signal?.aborted) return Promise.resolve();
|
|
340129
|
+
let timeout;
|
|
340130
|
+
const delay = new Promise((resolveDelay) => {
|
|
340131
|
+
timeout = setTimeout(resolveDelay, milliseconds);
|
|
340132
|
+
});
|
|
340133
|
+
if (signal === void 0) return delay;
|
|
340134
|
+
let stop;
|
|
340135
|
+
const aborted = new Promise((resolveAbort) => {
|
|
340136
|
+
stop = resolveAbort;
|
|
340137
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
340138
|
+
});
|
|
340139
|
+
return Promise.race([delay, aborted]).finally(() => {
|
|
340140
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
340141
|
+
if (stop !== void 0) signal.removeEventListener("abort", stop);
|
|
340142
|
+
});
|
|
340143
|
+
}
|
|
340144
|
+
//#endregion
|
|
340145
|
+
//#region src/cli/sub/mistakes.ts
|
|
340146
|
+
const DEFAULT_TOKEN_ENV = "BLUN_MISTAKE_INFLOW_TOKEN";
|
|
340147
|
+
const DEFAULT_ENDPOINT_ENV = "BLUN_MISTAKE_INFLOW_URL";
|
|
340148
|
+
function registerMistakesCommand(parent, overrides = {}) {
|
|
340149
|
+
const deps = resolveDeps(overrides);
|
|
340150
|
+
const mistakes = parent.command("mistakes").description("Upload and inspect append-only mistake source snapshots.");
|
|
340151
|
+
mistakes.command("upload").description("Queue a source snapshot locally, then upload it.").argument("<path>", "Source file to upload.").requiredOption("--source <id>", "Registered source id.").addOption(choiceOption("--form <form>", "Source form.", MISTAKE_SOURCE_FORMS, "unknown")).option("--record-types <types>", "Comma-separated declared record types.", "unknown").option("--entries <count>", "Declared logical entry count.", parseNonNegativeInteger).addOption(choiceOption("--bestandsstatus <status>", "Inventory status.", MISTAKE_INVENTORY_STATUSES, "unverified")).addOption(choiceOption("--aktualitaetsstatus <status>", "Actuality status.", MISTAKE_ACTUALITY_STATUSES, "unverified")).option("--last-entry-at <timestamp>", "Timestamp of the newest raw entry.").option("--endpoint <url>", `Inflow URL (or ${DEFAULT_ENDPOINT_ENV}).`).option("--token-env <name>", "Environment variable containing the bearer token.", DEFAULT_TOKEN_ENV).option("--outbox <path>", "Local durable outbox directory.").action(async (path, options) => {
|
|
340152
|
+
await run$1(deps, async () => {
|
|
340153
|
+
const connection = connectionOptions(deps, options);
|
|
340154
|
+
const receipt = await uploadMistakeObservation({
|
|
340155
|
+
filePath: resolve(path),
|
|
340156
|
+
sourceId: options.source,
|
|
340157
|
+
sourceForm: options.form,
|
|
340158
|
+
recordTypes: parseRecordTypes(options.recordTypes),
|
|
340159
|
+
bestandsstatus: options.bestandsstatus,
|
|
340160
|
+
aktualitaetsstatus: options.aktualitaetsstatus,
|
|
340161
|
+
declaredEntryCount: options.entries,
|
|
340162
|
+
lastRawObservedAt: options.lastEntryAt,
|
|
340163
|
+
capturedAt: deps.now().toISOString()
|
|
340164
|
+
}, connection);
|
|
340165
|
+
deps.stdout.write(`${JSON.stringify(receipt)}\n`);
|
|
340166
|
+
});
|
|
340167
|
+
});
|
|
340168
|
+
mistakes.command("retry").description("Retry every queued snapshot that has no verified receipt.").option("--endpoint <url>", `Inflow URL (or ${DEFAULT_ENDPOINT_ENV}).`).option("--token-env <name>", "Environment variable containing the bearer token.", DEFAULT_TOKEN_ENV).option("--outbox <path>", "Local durable outbox directory.").action(async (options) => {
|
|
340169
|
+
await run$1(deps, async () => {
|
|
340170
|
+
const result = await drainMistakeOutbox(connectionOptions(deps, options));
|
|
340171
|
+
deps.stdout.write(`${JSON.stringify(result)}\n`);
|
|
340172
|
+
if (result.failed.length > 0) deps.exit(1);
|
|
340173
|
+
});
|
|
340174
|
+
});
|
|
340175
|
+
mistakes.command("sync").description("Retry and upload every configured file or directory source once.").requiredOption("--config <path>", "Source registry JSON file.").option("--endpoint <url>", "Override the configured inflow URL for every supported source.").option("--outbox <path>", "Override the configured local outbox root.").action(async (options) => {
|
|
340176
|
+
await run$1(deps, async () => {
|
|
340177
|
+
const result = await syncMistakeSources({
|
|
340178
|
+
configPath: resolve(options.config),
|
|
340179
|
+
env: deps.env,
|
|
340180
|
+
endpoint: options.endpoint,
|
|
340181
|
+
outboxDir: options.outbox === void 0 ? void 0 : resolve(options.outbox)
|
|
340182
|
+
});
|
|
340183
|
+
deps.stdout.write(`${JSON.stringify(result)}\n`);
|
|
340184
|
+
if (result.results.some((item) => item.status === "failed" || item.status === "blocked")) deps.exit(2);
|
|
340185
|
+
});
|
|
340186
|
+
});
|
|
340187
|
+
mistakes.command("watch").description("Run source sync repeatedly in the foreground until interrupted.").requiredOption("--config <path>", "Source registry JSON file.").option("--endpoint <url>", "Override the configured inflow URL for every supported source.").option("--outbox <path>", "Override the configured local outbox root.").option("--interval <seconds>", "Foreground sync interval in seconds.", parseWatchInterval, 300).action(async (options) => {
|
|
340188
|
+
await run$1(deps, async () => {
|
|
340189
|
+
const controller = new AbortController();
|
|
340190
|
+
const stop = () => controller.abort();
|
|
340191
|
+
process.once("SIGINT", stop);
|
|
340192
|
+
process.once("SIGTERM", stop);
|
|
340193
|
+
try {
|
|
340194
|
+
await watchMistakeSources({
|
|
340195
|
+
configPath: resolve(options.config),
|
|
340196
|
+
env: deps.env,
|
|
340197
|
+
endpoint: options.endpoint,
|
|
340198
|
+
outboxDir: options.outbox === void 0 ? void 0 : resolve(options.outbox),
|
|
340199
|
+
intervalMs: options.interval * 1e3,
|
|
340200
|
+
signal: controller.signal,
|
|
340201
|
+
onRun: (result) => {
|
|
340202
|
+
deps.stdout.write(`${JSON.stringify(result)}\n`);
|
|
340203
|
+
}
|
|
340204
|
+
});
|
|
340205
|
+
} finally {
|
|
340206
|
+
process.off("SIGINT", stop);
|
|
340207
|
+
process.off("SIGTERM", stop);
|
|
340208
|
+
}
|
|
340209
|
+
});
|
|
340210
|
+
});
|
|
340211
|
+
mistakes.command("status").description("Show per-source inventory, actuality, and 24-hour watchdog state.").option("--endpoint <url>", `Inflow URL (or ${DEFAULT_ENDPOINT_ENV}).`).option("--token-env <name>", "Environment variable containing the bearer token.", DEFAULT_TOKEN_ENV).option("--no-fail-on-red", "Return success even when one or more sources are red.").action(async (options) => {
|
|
340212
|
+
await run$1(deps, async () => {
|
|
340213
|
+
const connection = connectionOptions(deps, options);
|
|
340214
|
+
const status = await getMistakeInflowStatus(connection.endpoint, connection.token);
|
|
340215
|
+
deps.stdout.write(`${JSON.stringify(status)}\n`);
|
|
340216
|
+
if (options.failOnRed && hasRedSource(status)) deps.exit(2);
|
|
340217
|
+
});
|
|
340218
|
+
});
|
|
340219
|
+
for (const action of ["remove", "restore"]) mistakes.command(action).description(action === "remove" ? "Append a manual removal marker without deleting raw data." : "Append a restore marker for a previously removed observation.").argument("<eventId>", "Observation event id.").requiredOption("--reason <text>", "Auditable reason for the state change.").option("--endpoint <url>", `Inflow URL (or ${DEFAULT_ENDPOINT_ENV}).`).option("--token-env <name>", "Environment variable containing the bearer token.", DEFAULT_TOKEN_ENV).action(async (eventId, options) => {
|
|
340220
|
+
await run$1(deps, async () => {
|
|
340221
|
+
const connection = connectionOptions(deps, options);
|
|
340222
|
+
const result = await changeMistakeObservationState(action, eventId, options.reason, connection.endpoint, connection.token);
|
|
340223
|
+
deps.stdout.write(`${JSON.stringify(result)}\n`);
|
|
340224
|
+
});
|
|
340225
|
+
});
|
|
340226
|
+
}
|
|
340227
|
+
async function run$1(deps, operation) {
|
|
340228
|
+
try {
|
|
340229
|
+
await operation();
|
|
340230
|
+
} catch (error) {
|
|
340231
|
+
deps.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
340232
|
+
deps.exit(1);
|
|
340233
|
+
}
|
|
340234
|
+
}
|
|
340235
|
+
function connectionOptions(deps, options) {
|
|
340236
|
+
const endpoint = options.endpoint ?? deps.env[DEFAULT_ENDPOINT_ENV];
|
|
340237
|
+
if (!endpoint) throw new Error(`missing --endpoint or ${DEFAULT_ENDPOINT_ENV}`);
|
|
340238
|
+
const token = deps.env[options.tokenEnv];
|
|
340239
|
+
if (!token || token.trim() === "") throw new Error(`missing bearer token in ${options.tokenEnv}`);
|
|
340240
|
+
return {
|
|
340241
|
+
endpoint,
|
|
340242
|
+
token,
|
|
340243
|
+
outboxDir: resolve(options.outbox ?? join(resolveBlunHome$1(), "mistake", "inflow-outbox"))
|
|
340244
|
+
};
|
|
340245
|
+
}
|
|
340246
|
+
function parseRecordTypes(value) {
|
|
340247
|
+
const values = [...new Set(value.split(",").map((item) => item.trim()).filter(Boolean))];
|
|
340248
|
+
if (values.length === 0 || values.some((value) => !MISTAKE_RECORD_TYPES.includes(value))) throw new Error(`record types must be one or more of: ${MISTAKE_RECORD_TYPES.join(", ")}`);
|
|
340249
|
+
return values;
|
|
340250
|
+
}
|
|
340251
|
+
function parseNonNegativeInteger(value) {
|
|
340252
|
+
if (!/^\d+$/.test(value)) throw new Error("entry count must be a non-negative integer");
|
|
340253
|
+
const parsed = Number(value);
|
|
340254
|
+
if (!Number.isSafeInteger(parsed)) throw new Error("entry count is too large");
|
|
340255
|
+
return parsed;
|
|
340256
|
+
}
|
|
340257
|
+
function parseWatchInterval(value) {
|
|
340258
|
+
if (!/^\d+$/.test(value)) throw new Error("watch interval must be a positive integer");
|
|
340259
|
+
const parsed = Number(value);
|
|
340260
|
+
if (!Number.isSafeInteger(parsed) || parsed < 1) throw new Error("watch interval must be at least one second");
|
|
340261
|
+
return parsed;
|
|
340262
|
+
}
|
|
340263
|
+
function hasRedSource(value) {
|
|
340264
|
+
if (typeof value !== "object" || value === null) return false;
|
|
340265
|
+
const sources = value["sources"];
|
|
340266
|
+
return Array.isArray(sources) && sources.some((source) => typeof source === "object" && source !== null && source["watchdog"] === "red");
|
|
340267
|
+
}
|
|
340268
|
+
function choiceOption(flags, description, choices, defaultValue) {
|
|
340269
|
+
return new Option(flags, description).choices([...choices]).default(defaultValue);
|
|
340270
|
+
}
|
|
340271
|
+
function resolveDeps(overrides) {
|
|
340272
|
+
return {
|
|
340273
|
+
env: overrides.env ?? process.env,
|
|
340274
|
+
now: overrides.now ?? (() => /* @__PURE__ */ new Date()),
|
|
340275
|
+
stdout: overrides.stdout ?? process.stdout,
|
|
340276
|
+
stderr: overrides.stderr ?? process.stderr,
|
|
340277
|
+
exit: overrides.exit ?? ((code) => process.exit(code))
|
|
340278
|
+
};
|
|
340279
|
+
}
|
|
340280
|
+
//#endregion
|
|
338514
340281
|
//#region src/personal-memory/phase1-contract.json
|
|
338515
340282
|
var clientOperations = {
|
|
338516
340283
|
"settingsRead": {
|
|
@@ -338829,9 +340596,9 @@ function isErrno$1(error, code) {
|
|
|
338829
340596
|
return error.code === code;
|
|
338830
340597
|
}
|
|
338831
340598
|
function outputFailure(error, cleanupError) {
|
|
338832
|
-
return new Error(`${errorMessage$
|
|
340599
|
+
return new Error(`${errorMessage$4(error)} Output reservation cleanup failed: ${errorMessage$4(cleanupError)}`, { cause: new AggregateError([error, cleanupError], "Output reservation cleanup failed.") });
|
|
338833
340600
|
}
|
|
338834
|
-
function errorMessage$
|
|
340601
|
+
function errorMessage$4(error) {
|
|
338835
340602
|
return error instanceof Error ? error.message : String(error);
|
|
338836
340603
|
}
|
|
338837
340604
|
//#endregion
|
|
@@ -339445,7 +341212,7 @@ async function handleProof(deps, options) {
|
|
|
339445
341212
|
await reservation.write(proof);
|
|
339446
341213
|
} catch (error) {
|
|
339447
341214
|
await reservation?.abort().catch(() => void 0);
|
|
339448
|
-
deps.stderr.write(`${errorMessage$
|
|
341215
|
+
deps.stderr.write(`${errorMessage$3(error)}\n`);
|
|
339449
341216
|
deps.exit(1);
|
|
339450
341217
|
}
|
|
339451
341218
|
deps.stdout.write(`${outputPath}\n`);
|
|
@@ -339477,7 +341244,7 @@ function createDefaultProofDeps(overrides = {}) {
|
|
|
339477
341244
|
function defaultProofFilename(now) {
|
|
339478
341245
|
return `proof-${now.toISOString().replaceAll(/[:.]/g, "-")}.json`;
|
|
339479
341246
|
}
|
|
339480
|
-
function errorMessage$
|
|
341247
|
+
function errorMessage$3(error) {
|
|
339481
341248
|
return error instanceof Error ? error.message : String(error);
|
|
339482
341249
|
}
|
|
339483
341250
|
function samePath$2(left, right) {
|
|
@@ -395793,7 +397560,7 @@ async function abortAndFail(deps, reservation, error) {
|
|
|
395793
397560
|
if (reservation !== void 0) try {
|
|
395794
397561
|
await reservation.abort();
|
|
395795
397562
|
} catch (cleanupError) {
|
|
395796
|
-
fail(deps, new Error(`${errorMessage$
|
|
397563
|
+
fail(deps, new Error(`${errorMessage$2(error)} Output reservation cleanup failed: ${errorMessage$2(cleanupError)}`, { cause: new AggregateError([error, cleanupError], "Output reservation cleanup failed.") }));
|
|
395797
397564
|
}
|
|
395798
397565
|
fail(deps, error);
|
|
395799
397566
|
}
|
|
@@ -395804,10 +397571,10 @@ function stringArray(value) {
|
|
|
395804
397571
|
return Array.isArray(value) && value.every((item) => typeof item === "string") ? value : [];
|
|
395805
397572
|
}
|
|
395806
397573
|
function fail(deps, error) {
|
|
395807
|
-
deps.stderr.write(`${errorMessage$
|
|
397574
|
+
deps.stderr.write(`${errorMessage$2(error)}\n`);
|
|
395808
397575
|
return deps.exit(1);
|
|
395809
397576
|
}
|
|
395810
|
-
function errorMessage$
|
|
397577
|
+
function errorMessage$2(error) {
|
|
395811
397578
|
return error instanceof Error ? error.message : String(error);
|
|
395812
397579
|
}
|
|
395813
397580
|
//#endregion
|
|
@@ -396534,14 +398301,14 @@ async function run(deps, operation) {
|
|
|
396534
398301
|
try {
|
|
396535
398302
|
await operation();
|
|
396536
398303
|
} catch (error) {
|
|
396537
|
-
deps.stderr.write(`${errorMessage(error)}\n`);
|
|
398304
|
+
deps.stderr.write(`${errorMessage$1(error)}\n`);
|
|
396538
398305
|
deps.exit(1);
|
|
396539
398306
|
}
|
|
396540
398307
|
}
|
|
396541
398308
|
function writeJson(deps, value) {
|
|
396542
398309
|
deps.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
396543
398310
|
}
|
|
396544
|
-
function errorMessage(error) {
|
|
398311
|
+
function errorMessage$1(error) {
|
|
396545
398312
|
return error instanceof Error ? error.message : String(error);
|
|
396546
398313
|
}
|
|
396547
398314
|
//#endregion
|
|
@@ -396574,6 +398341,7 @@ function createProgram(version, onMain, onPluginNodeRunner = () => {}, onUpgrade
|
|
|
396574
398341
|
registerAcpCommand(program);
|
|
396575
398342
|
registerServerCommand(program);
|
|
396576
398343
|
registerLoginCommand(program);
|
|
398344
|
+
registerMistakesCommand(program);
|
|
396577
398345
|
registerPersonalMemoryCommand(program);
|
|
396578
398346
|
registerDoctorCommand(program);
|
|
396579
398347
|
registerVisCommand(program);
|
|
@@ -414339,7 +416107,7 @@ function appearanceSelectorCopy() {
|
|
|
414339
416107
|
surface: uiText("appearance.surface"),
|
|
414340
416108
|
preview: uiText("appearance.preview"),
|
|
414341
416109
|
colorHint: uiText("appearance.colorHint"),
|
|
414342
|
-
contrastHint: uiText("appearance.contrastHint"),
|
|
416110
|
+
contrastHint: uiText("appearance.contrastHint", { ratio: "{ratio}" }),
|
|
414343
416111
|
footer: uiText("appearance.footer")
|
|
414344
416112
|
};
|
|
414345
416113
|
}
|
|
@@ -414491,7 +416259,6 @@ function showSettingsSelector(host) {
|
|
|
414491
416259
|
}));
|
|
414492
416260
|
}
|
|
414493
416261
|
function handleSettingsSelection(host, value) {
|
|
414494
|
-
host.restoreEditor();
|
|
414495
416262
|
switch (value) {
|
|
414496
416263
|
case "effort":
|
|
414497
416264
|
handleEffortCommand(host, "");
|
|
@@ -414515,9 +416282,11 @@ function handleSettingsSelection(host, value) {
|
|
|
414515
416282
|
showExperimentsPanel(host);
|
|
414516
416283
|
return;
|
|
414517
416284
|
case "usage":
|
|
416285
|
+
host.restoreEditor();
|
|
414518
416286
|
showUsage(host);
|
|
414519
416287
|
return;
|
|
414520
416288
|
case "inline-suggest":
|
|
416289
|
+
host.restoreEditor();
|
|
414521
416290
|
showInlineSuggestStatus(host);
|
|
414522
416291
|
return;
|
|
414523
416292
|
}
|
|
@@ -509766,7 +511535,11 @@ var BlunTUI = class {
|
|
|
509766
511535
|
this.applyStartupPermissionAndPlanToAppState();
|
|
509767
511536
|
}
|
|
509768
511537
|
this.hideSessionPicker();
|
|
509769
|
-
if (applyStartupModes)
|
|
511538
|
+
if (applyStartupModes) {
|
|
511539
|
+
await this.refreshPersonalMemory(true);
|
|
511540
|
+
await this.authFlow.refreshManagedQuotaWindows();
|
|
511541
|
+
await this.promptStartupResumeGoalIfNeeded();
|
|
511542
|
+
}
|
|
509770
511543
|
}
|
|
509771
511544
|
showApprovalPanel(payload) {
|
|
509772
511545
|
this.patchLivePane({ pendingApproval: { data: payload } });
|
|
@@ -511439,6 +513212,103 @@ function runNativeAssetSmokeIfRequested() {
|
|
|
511439
513212
|
return true;
|
|
511440
513213
|
}
|
|
511441
513214
|
//#endregion
|
|
513215
|
+
//#region src/mistakes/automatic-sync.ts
|
|
513216
|
+
const AUTOMATIC_MISTAKE_SYNC_CONFIG_ENV = "BLUN_MISTAKE_SYNC_CONFIG";
|
|
513217
|
+
const DEFAULT_DEPS = {
|
|
513218
|
+
lstat,
|
|
513219
|
+
lock: (path) => import_proper_lockfile.default.lock(path, {
|
|
513220
|
+
realpath: false,
|
|
513221
|
+
retries: 0,
|
|
513222
|
+
stale: 3e4,
|
|
513223
|
+
update: 1e4
|
|
513224
|
+
}),
|
|
513225
|
+
watch: (options) => watchMistakeSources(options),
|
|
513226
|
+
logger: log
|
|
513227
|
+
};
|
|
513228
|
+
async function startAutomaticMistakeSync(options, deps = DEFAULT_DEPS) {
|
|
513229
|
+
const env = options.env ?? process.env;
|
|
513230
|
+
const configuredPath = env[AUTOMATIC_MISTAKE_SYNC_CONFIG_ENV]?.trim();
|
|
513231
|
+
const configPath = resolve(configuredPath && configuredPath.length > 0 ? configuredPath : join(options.homeDir, "mistake", "source-sync.json"));
|
|
513232
|
+
const inactive = () => ({
|
|
513233
|
+
active: false,
|
|
513234
|
+
configPath,
|
|
513235
|
+
stop: async () => {}
|
|
513236
|
+
});
|
|
513237
|
+
try {
|
|
513238
|
+
const stat = await deps.lstat(configPath);
|
|
513239
|
+
if (stat.isSymbolicLink() || !stat.isFile()) {
|
|
513240
|
+
deps.logger.warn("automatic mistake sync config is not a regular file", { configPath });
|
|
513241
|
+
return inactive();
|
|
513242
|
+
}
|
|
513243
|
+
} catch (error) {
|
|
513244
|
+
if (isErrorCode(error, "ENOENT")) return inactive();
|
|
513245
|
+
deps.logger.warn("automatic mistake sync config is unavailable", {
|
|
513246
|
+
configPath,
|
|
513247
|
+
error: errorMessage(error)
|
|
513248
|
+
});
|
|
513249
|
+
return inactive();
|
|
513250
|
+
}
|
|
513251
|
+
let release;
|
|
513252
|
+
try {
|
|
513253
|
+
release = await deps.lock(configPath);
|
|
513254
|
+
} catch (error) {
|
|
513255
|
+
if (isErrorCode(error, "ELOCKED")) return inactive();
|
|
513256
|
+
deps.logger.warn("automatic mistake sync lock failed", {
|
|
513257
|
+
configPath,
|
|
513258
|
+
error: errorMessage(error)
|
|
513259
|
+
});
|
|
513260
|
+
return inactive();
|
|
513261
|
+
}
|
|
513262
|
+
const controller = new AbortController();
|
|
513263
|
+
let released = false;
|
|
513264
|
+
const releaseOnce = async () => {
|
|
513265
|
+
if (released) return;
|
|
513266
|
+
released = true;
|
|
513267
|
+
try {
|
|
513268
|
+
await release();
|
|
513269
|
+
} catch {}
|
|
513270
|
+
};
|
|
513271
|
+
const watchPromise = deps.watch({
|
|
513272
|
+
configPath,
|
|
513273
|
+
env,
|
|
513274
|
+
intervalMs: options.intervalMs ?? 3e5,
|
|
513275
|
+
signal: controller.signal,
|
|
513276
|
+
onRun: (run) => logRun(deps.logger, run)
|
|
513277
|
+
}).catch((error) => {
|
|
513278
|
+
deps.logger.warn("automatic mistake sync stopped", {
|
|
513279
|
+
configPath,
|
|
513280
|
+
error: errorMessage(error)
|
|
513281
|
+
});
|
|
513282
|
+
}).finally(releaseOnce);
|
|
513283
|
+
return {
|
|
513284
|
+
active: true,
|
|
513285
|
+
configPath,
|
|
513286
|
+
stop: async () => {
|
|
513287
|
+
controller.abort();
|
|
513288
|
+
await watchPromise;
|
|
513289
|
+
}
|
|
513290
|
+
};
|
|
513291
|
+
}
|
|
513292
|
+
function logRun(logger, run) {
|
|
513293
|
+
const counts = Object.fromEntries([
|
|
513294
|
+
"uploaded",
|
|
513295
|
+
"heartbeat",
|
|
513296
|
+
"unchanged",
|
|
513297
|
+
"blocked",
|
|
513298
|
+
"failed"
|
|
513299
|
+
].map((status) => [status, run.results.filter((result) => result.status === status).length]));
|
|
513300
|
+
logger.info("automatic mistake sync completed", {
|
|
513301
|
+
configPath: run.config_path,
|
|
513302
|
+
...counts
|
|
513303
|
+
});
|
|
513304
|
+
}
|
|
513305
|
+
function isErrorCode(error, code) {
|
|
513306
|
+
return typeof error === "object" && error !== null && error.code === code;
|
|
513307
|
+
}
|
|
513308
|
+
function errorMessage(error) {
|
|
513309
|
+
return error instanceof Error ? error.message : String(error);
|
|
513310
|
+
}
|
|
513311
|
+
//#endregion
|
|
511442
513312
|
//#region src/main.ts
|
|
511443
513313
|
/**
|
|
511444
513314
|
* BLUN King entry point.
|
|
@@ -511471,9 +513341,15 @@ async function handleMainCommand(opts, version) {
|
|
|
511471
513341
|
} : { track });
|
|
511472
513342
|
if (preflightResult === "exit") process.exit(0);
|
|
511473
513343
|
const updateStartupNotice = typeof preflightResult === "object" ? preflightResult.startupNotice : void 0;
|
|
511474
|
-
|
|
513344
|
+
const mistakeSync = await startAutomaticMistakeSync({
|
|
513345
|
+
homeDir: resolveBlunHome$1(),
|
|
513346
|
+
env: process.env
|
|
513347
|
+
});
|
|
513348
|
+
if (validated.uiMode === "print") try {
|
|
511475
513349
|
await runPrompt(validated.options, version);
|
|
511476
513350
|
return { headlessCompleted: true };
|
|
513351
|
+
} finally {
|
|
513352
|
+
await mistakeSync.stop();
|
|
511477
513353
|
}
|
|
511478
513354
|
await runShell(validated.options, version, updateStartupNotice);
|
|
511479
513355
|
return { headlessCompleted: false };
|