ever-works-node 0.2.4 → 0.2.5
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/cli.js +622 -22
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -5006,6 +5006,41 @@ function resolveExclusiveAgentCredentials(grantedNames, env) {
|
|
|
5006
5006
|
return { names: grantedNames.filter((name) => !dropped.has(name)), notes };
|
|
5007
5007
|
}
|
|
5008
5008
|
__name(resolveExclusiveAgentCredentials, "resolveExclusiveAgentCredentials");
|
|
5009
|
+
var CONVENTIONAL_SUBJECT = /^([a-z]+)(\([^)\n]{1,40}\))?(!)?:\s+(\S.*)$/;
|
|
5010
|
+
function classifyFleetChangedPaths(paths) {
|
|
5011
|
+
const list = (paths ?? []).map((path2) => path2.replace(/\\/g, "/").trim()).filter(Boolean);
|
|
5012
|
+
if (list.length === 0) return "none";
|
|
5013
|
+
if (list.every(isDocsPath)) return "docs";
|
|
5014
|
+
if (list.every(isTestPath)) return "test";
|
|
5015
|
+
return "mixed";
|
|
5016
|
+
}
|
|
5017
|
+
__name(classifyFleetChangedPaths, "classifyFleetChangedPaths");
|
|
5018
|
+
function retypeFleetCommitMessage(message, changedPaths) {
|
|
5019
|
+
if (typeof message !== "string" || !message) return message;
|
|
5020
|
+
const newline = message.indexOf("\n");
|
|
5021
|
+
const firstLine = newline === -1 ? message : message.slice(0, newline);
|
|
5022
|
+
const rest = newline === -1 ? "" : message.slice(newline);
|
|
5023
|
+
const parsed = CONVENTIONAL_SUBJECT.exec(firstLine);
|
|
5024
|
+
if (!parsed) return message;
|
|
5025
|
+
const change = classifyFleetChangedPaths(changedPaths);
|
|
5026
|
+
const type = change === "docs" ? "docs" : change === "test" ? "test" : null;
|
|
5027
|
+
if (!type || parsed[1] === type) return message;
|
|
5028
|
+
return `${type}${firstLine.slice(parsed[1].length)}${rest}`;
|
|
5029
|
+
}
|
|
5030
|
+
__name(retypeFleetCommitMessage, "retypeFleetCommitMessage");
|
|
5031
|
+
var DOC_EXTENSIONS = /\.(?:md|mdx|markdown|rst|adoc|txt)$/i;
|
|
5032
|
+
var DOC_DIRECTORY = /(?:^|\/)(?:docs?|documentation)\//i;
|
|
5033
|
+
var DOC_FILENAMES = /(?:^|\/)(?:readme|changelog|contributing|license|licence|notice|authors|code_of_conduct)(?:\.[a-z]+)?$/i;
|
|
5034
|
+
function isDocsPath(path2) {
|
|
5035
|
+
return DOC_EXTENSIONS.test(path2) || DOC_DIRECTORY.test(path2) || DOC_FILENAMES.test(path2);
|
|
5036
|
+
}
|
|
5037
|
+
__name(isDocsPath, "isDocsPath");
|
|
5038
|
+
var TEST_FILE = /(?:^|[./_-])(?:spec|test|tests|e2e)\.[cm]?[jt]sx?$|_test\.(?:go|py|rb)$|(?:^|\/)test_[^/]+\.py$/i;
|
|
5039
|
+
var TEST_DIRECTORY = /(?:^|\/)(?:__tests__|__snapshots__|__mocks__|__fixtures__|tests?|e2e|spec|fixtures)\//i;
|
|
5040
|
+
function isTestPath(path2) {
|
|
5041
|
+
return TEST_FILE.test(path2) || TEST_DIRECTORY.test(path2) || /\.snap$/i.test(path2);
|
|
5042
|
+
}
|
|
5043
|
+
__name(isTestPath, "isTestPath");
|
|
5009
5044
|
var INBOX_MAX_TITLE_CHARS = 300;
|
|
5010
5045
|
var FLEET_TASK_WORKSPACE_MAX_MOUNTS = 8;
|
|
5011
5046
|
var FLEET_TASK_WORKSPACE_MOUNT_DIR_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,62}[A-Za-z0-9_-])?$/;
|
|
@@ -5519,6 +5554,275 @@ function truncateToUtf8Bytes(value, maxBytes) {
|
|
|
5519
5554
|
return { value: decoded.replace(/\uFFFD+$/, "").trimEnd(), truncated: true };
|
|
5520
5555
|
}
|
|
5521
5556
|
__name(truncateToUtf8Bytes, "truncateToUtf8Bytes");
|
|
5557
|
+
var FLEET_JOB_FAILURE_KIND_MODEL_USAGE_LIMIT = "model_usage_limit";
|
|
5558
|
+
var FLEET_MODEL_USAGE_LIMIT_FALLBACK_MS = 60 * 60 * 1e3;
|
|
5559
|
+
var FLEET_MODEL_USAGE_LIMIT_MIN_MS = 60 * 1e3;
|
|
5560
|
+
var FLEET_MODEL_USAGE_LIMIT_MAX_MS = 8 * 24 * 60 * 60 * 1e3;
|
|
5561
|
+
var FLEET_MODEL_USAGE_LIMIT_RESET_SLACK_MS = 60 * 1e3;
|
|
5562
|
+
var FLEET_MODEL_USAGE_LIMIT_MAX_MESSAGE_LENGTH = 300;
|
|
5563
|
+
var LIMIT_SIGNATURES = [
|
|
5564
|
+
{ pattern: /\bhit (?:your|the) (?:[\w-]+ )?(?:usage |rate )?limit\b/i, strict: true },
|
|
5565
|
+
{
|
|
5566
|
+
pattern: /\b(?:usage|weekly|daily|session|5[- ]hour|five[- ]hour) limit (?:has been )?(?:reached|exceeded|hit)\b/i,
|
|
5567
|
+
strict: true
|
|
5568
|
+
},
|
|
5569
|
+
{ pattern: /\busage[_ ]limit[_ ](?:reached|exceeded)\b/i, strict: true },
|
|
5570
|
+
{ pattern: /\brate_limit_error\b/, strict: true },
|
|
5571
|
+
{ pattern: /\bexceeded retry limit,? last status:? 429\b/i, strict: true },
|
|
5572
|
+
{ pattern: /\b429\b[^\n]{0,40}\btoo many requests\b/i, strict: true },
|
|
5573
|
+
{ pattern: /\bAPI Error:? 429\b/i, strict: true },
|
|
5574
|
+
{ pattern: /\brate[- ]limit(?:ed)?\b[^\n]{0,20}\b(?:reached|exceeded)\b/i, strict: false },
|
|
5575
|
+
{ pattern: /\bout of (?:extra )?usage\b/i, strict: false }
|
|
5576
|
+
];
|
|
5577
|
+
function detectFleetModelUsageLimit(text, options = {}) {
|
|
5578
|
+
if (typeof text !== "string" || !text.trim()) return null;
|
|
5579
|
+
const strict = options.strict === true;
|
|
5580
|
+
const match = LIMIT_SIGNATURES.find((signature) => (!strict || signature.strict) && signature.pattern.test(text));
|
|
5581
|
+
if (!match) return null;
|
|
5582
|
+
const nowMs = toEpochMs(options.now);
|
|
5583
|
+
const provider = typeof options.provider === "string" && options.provider.trim() ? options.provider.trim() : "claude-code";
|
|
5584
|
+
const resetsAtMs = parseResetInstant(text, nowMs, options.timeZone);
|
|
5585
|
+
const resetsAt = resetsAtMs !== null && resetsAtMs > nowMs ? resetsAtMs : null;
|
|
5586
|
+
return {
|
|
5587
|
+
provider,
|
|
5588
|
+
window: classifyWindow(text),
|
|
5589
|
+
resetsAt: resetsAt === null ? null : new Date(resetsAt).toISOString(),
|
|
5590
|
+
retryAfter: new Date(
|
|
5591
|
+
clampRetryAfterMs(
|
|
5592
|
+
resetsAt === null ? nowMs + FLEET_MODEL_USAGE_LIMIT_FALLBACK_MS : resetsAt + FLEET_MODEL_USAGE_LIMIT_RESET_SLACK_MS,
|
|
5593
|
+
nowMs
|
|
5594
|
+
)
|
|
5595
|
+
).toISOString(),
|
|
5596
|
+
message: describeLimitSentence(text, match.pattern)
|
|
5597
|
+
};
|
|
5598
|
+
}
|
|
5599
|
+
__name(detectFleetModelUsageLimit, "detectFleetModelUsageLimit");
|
|
5600
|
+
function clampRetryAfterMs(retryAfterMs, nowMs) {
|
|
5601
|
+
const floor = nowMs + FLEET_MODEL_USAGE_LIMIT_MIN_MS;
|
|
5602
|
+
const ceiling = nowMs + FLEET_MODEL_USAGE_LIMIT_MAX_MS;
|
|
5603
|
+
if (!Number.isFinite(retryAfterMs)) return nowMs + FLEET_MODEL_USAGE_LIMIT_FALLBACK_MS;
|
|
5604
|
+
return Math.min(Math.max(retryAfterMs, floor), ceiling);
|
|
5605
|
+
}
|
|
5606
|
+
__name(clampRetryAfterMs, "clampRetryAfterMs");
|
|
5607
|
+
function describeFleetModelProvider(provider) {
|
|
5608
|
+
switch (provider) {
|
|
5609
|
+
case "claude-code":
|
|
5610
|
+
return "Claude Code";
|
|
5611
|
+
case "codex":
|
|
5612
|
+
return "Codex";
|
|
5613
|
+
default:
|
|
5614
|
+
return provider;
|
|
5615
|
+
}
|
|
5616
|
+
}
|
|
5617
|
+
__name(describeFleetModelProvider, "describeFleetModelProvider");
|
|
5618
|
+
function describeFleetModelUsageLimitWindow(window) {
|
|
5619
|
+
switch (window) {
|
|
5620
|
+
case "weekly":
|
|
5621
|
+
return "weekly limit";
|
|
5622
|
+
case "session":
|
|
5623
|
+
return "5-hour limit";
|
|
5624
|
+
case "daily":
|
|
5625
|
+
return "daily limit";
|
|
5626
|
+
case "rate":
|
|
5627
|
+
return "rate limit";
|
|
5628
|
+
default:
|
|
5629
|
+
return "usage limit";
|
|
5630
|
+
}
|
|
5631
|
+
}
|
|
5632
|
+
__name(describeFleetModelUsageLimitWindow, "describeFleetModelUsageLimitWindow");
|
|
5633
|
+
function toEpochMs(value) {
|
|
5634
|
+
if (value instanceof Date) return value.getTime();
|
|
5635
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
5636
|
+
return Date.now();
|
|
5637
|
+
}
|
|
5638
|
+
__name(toEpochMs, "toEpochMs");
|
|
5639
|
+
function classifyWindow(text) {
|
|
5640
|
+
if (/\bweekly\b|\bper week\b/i.test(text)) return "weekly";
|
|
5641
|
+
if (/\b(?:5|five)[- ]hour\b|\bsession limit\b/i.test(text)) return "session";
|
|
5642
|
+
if (/\bdaily\b|\bper day\b/i.test(text)) return "daily";
|
|
5643
|
+
if (/\b429\b|rate_limit_error|\brate[- ]limit/i.test(text)) return "rate";
|
|
5644
|
+
return "usage";
|
|
5645
|
+
}
|
|
5646
|
+
__name(classifyWindow, "classifyWindow");
|
|
5647
|
+
function trimSentence(text) {
|
|
5648
|
+
const clean = text.replace(/[\u0000-\u001f\u007f]+/g, " ").replace(/\s+/g, " ").trim();
|
|
5649
|
+
const points = Array.from(clean);
|
|
5650
|
+
return points.length > FLEET_MODEL_USAGE_LIMIT_MAX_MESSAGE_LENGTH ? `${points.slice(0, FLEET_MODEL_USAGE_LIMIT_MAX_MESSAGE_LENGTH - 1).join("").trimEnd()}\u2026` : clean;
|
|
5651
|
+
}
|
|
5652
|
+
__name(trimSentence, "trimSentence");
|
|
5653
|
+
function describeLimitSentence(text, pattern) {
|
|
5654
|
+
const line = text.split(/\r?\n/).find((candidate) => pattern.test(candidate));
|
|
5655
|
+
return trimSentence(line ?? text);
|
|
5656
|
+
}
|
|
5657
|
+
__name(describeLimitSentence, "describeLimitSentence");
|
|
5658
|
+
var MONTHS = {
|
|
5659
|
+
jan: 0,
|
|
5660
|
+
feb: 1,
|
|
5661
|
+
mar: 2,
|
|
5662
|
+
apr: 3,
|
|
5663
|
+
may: 4,
|
|
5664
|
+
jun: 5,
|
|
5665
|
+
jul: 6,
|
|
5666
|
+
aug: 7,
|
|
5667
|
+
sep: 8,
|
|
5668
|
+
sept: 8,
|
|
5669
|
+
oct: 9,
|
|
5670
|
+
nov: 10,
|
|
5671
|
+
dec: 11
|
|
5672
|
+
};
|
|
5673
|
+
function parseResetInstant(text, nowMs, timeZone) {
|
|
5674
|
+
const epoch = /usage limit reached\|(\d{10,13})\b/i.exec(text);
|
|
5675
|
+
if (epoch) {
|
|
5676
|
+
const value = Number(epoch[1]);
|
|
5677
|
+
return epoch[1].length >= 13 ? value : value * 1e3;
|
|
5678
|
+
}
|
|
5679
|
+
const iso = /\b(?:resets?|reset at|try again at|available again at|until)\s+(?:at\s+)?(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:?\d{2}))/i.exec(
|
|
5680
|
+
text
|
|
5681
|
+
);
|
|
5682
|
+
if (iso) {
|
|
5683
|
+
const value = Date.parse(iso[1]);
|
|
5684
|
+
if (Number.isFinite(value)) return value;
|
|
5685
|
+
}
|
|
5686
|
+
const relative6 = /\b(?:resets?|reset|try again|available again|retry)\s+in\s+((?:\d+\s*(?:d|days?|h|hrs?|hours?|m|mins?|minutes?|s|secs?|seconds?)\b(?:[\s,]+(?:and )?)?)+)/i.exec(
|
|
5687
|
+
text
|
|
5688
|
+
);
|
|
5689
|
+
if (relative6) {
|
|
5690
|
+
const ms = parseDuration(relative6[1]);
|
|
5691
|
+
if (ms > 0) return nowMs + ms;
|
|
5692
|
+
}
|
|
5693
|
+
const wall = /\b(?:resets?|reset at|will reset at|try again at|available again at)\s+(?:at\s+|on\s+)?(?:(jan|feb|mar|apr|may|jun|jul|aug|sept?|oct|nov|dec)[a-z]*\.?\s+(\d{1,2})(?:st|nd|rd|th)?,?\s+(?:at\s+)?)?(\d{1,2})(?::(\d{2}))?\s*(am|pm)?\b(?:\s*\(([A-Za-z_]+(?:\/[A-Za-z0-9_+-]+){0,2}|UTC|GMT)\))?/i.exec(
|
|
5694
|
+
text
|
|
5695
|
+
);
|
|
5696
|
+
if (wall) {
|
|
5697
|
+
const [, monthName, dayText, hourText, minuteText, meridiem, zoneText] = wall;
|
|
5698
|
+
let hour = Number(hourText);
|
|
5699
|
+
const minute = minuteText ? Number(minuteText) : 0;
|
|
5700
|
+
if (!meridiem && !minuteText && !monthName) {
|
|
5701
|
+
return null;
|
|
5702
|
+
}
|
|
5703
|
+
if (meridiem) {
|
|
5704
|
+
if (hour < 1 || hour > 12) return null;
|
|
5705
|
+
hour = hour % 12 + (meridiem.toLowerCase() === "pm" ? 12 : 0);
|
|
5706
|
+
}
|
|
5707
|
+
if (hour > 23 || minute > 59) return null;
|
|
5708
|
+
const zone = resolveZone(zoneText) ?? resolveZone(timeZone) ?? "UTC";
|
|
5709
|
+
const today = zonedParts(nowMs, zone);
|
|
5710
|
+
if (monthName) {
|
|
5711
|
+
const month = MONTHS[monthName.toLowerCase()];
|
|
5712
|
+
const day = Number(dayText);
|
|
5713
|
+
if (month === void 0 || day < 1 || day > 31) return null;
|
|
5714
|
+
let candidate2 = zonedWallTimeToUtc(today.year, month, day, hour, minute, zone);
|
|
5715
|
+
if (candidate2 < nowMs - 24 * 60 * 60 * 1e3) {
|
|
5716
|
+
candidate2 = zonedWallTimeToUtc(today.year + 1, month, day, hour, minute, zone);
|
|
5717
|
+
}
|
|
5718
|
+
return candidate2;
|
|
5719
|
+
}
|
|
5720
|
+
let candidate = zonedWallTimeToUtc(today.year, today.month, today.day, hour, minute, zone);
|
|
5721
|
+
if (candidate <= nowMs) {
|
|
5722
|
+
candidate = zonedWallTimeToUtc(today.year, today.month, today.day + 1, hour, minute, zone);
|
|
5723
|
+
}
|
|
5724
|
+
return candidate;
|
|
5725
|
+
}
|
|
5726
|
+
return null;
|
|
5727
|
+
}
|
|
5728
|
+
__name(parseResetInstant, "parseResetInstant");
|
|
5729
|
+
function parseDuration(text) {
|
|
5730
|
+
let total = 0;
|
|
5731
|
+
let index = 0;
|
|
5732
|
+
const length = Math.min(text.length, 200);
|
|
5733
|
+
while (index < length) {
|
|
5734
|
+
if (!isDigit(text.charCodeAt(index))) {
|
|
5735
|
+
index += 1;
|
|
5736
|
+
continue;
|
|
5737
|
+
}
|
|
5738
|
+
let value = 0;
|
|
5739
|
+
while (index < length && isDigit(text.charCodeAt(index))) {
|
|
5740
|
+
value = Math.min(value * 10 + (text.charCodeAt(index) - 48), 1e6);
|
|
5741
|
+
index += 1;
|
|
5742
|
+
}
|
|
5743
|
+
while (index < length && text[index] === " ") index += 1;
|
|
5744
|
+
let word = "";
|
|
5745
|
+
while (index < length && /[a-z]/i.test(text[index])) {
|
|
5746
|
+
word += text[index].toLowerCase();
|
|
5747
|
+
index += 1;
|
|
5748
|
+
}
|
|
5749
|
+
const unitMs = DURATION_UNITS[word];
|
|
5750
|
+
if (unitMs !== void 0) total += value * unitMs;
|
|
5751
|
+
}
|
|
5752
|
+
return total;
|
|
5753
|
+
}
|
|
5754
|
+
__name(parseDuration, "parseDuration");
|
|
5755
|
+
var DURATION_UNITS = {
|
|
5756
|
+
d: 864e5,
|
|
5757
|
+
day: 864e5,
|
|
5758
|
+
days: 864e5,
|
|
5759
|
+
h: 36e5,
|
|
5760
|
+
hr: 36e5,
|
|
5761
|
+
hrs: 36e5,
|
|
5762
|
+
hour: 36e5,
|
|
5763
|
+
hours: 36e5,
|
|
5764
|
+
m: 6e4,
|
|
5765
|
+
min: 6e4,
|
|
5766
|
+
mins: 6e4,
|
|
5767
|
+
minute: 6e4,
|
|
5768
|
+
minutes: 6e4,
|
|
5769
|
+
s: 1e3,
|
|
5770
|
+
sec: 1e3,
|
|
5771
|
+
secs: 1e3,
|
|
5772
|
+
second: 1e3,
|
|
5773
|
+
seconds: 1e3
|
|
5774
|
+
};
|
|
5775
|
+
function isDigit(code) {
|
|
5776
|
+
return code >= 48 && code <= 57;
|
|
5777
|
+
}
|
|
5778
|
+
__name(isDigit, "isDigit");
|
|
5779
|
+
function resolveZone(zone) {
|
|
5780
|
+
if (typeof zone !== "string" || !zone.trim()) return null;
|
|
5781
|
+
const candidate = zone.trim();
|
|
5782
|
+
try {
|
|
5783
|
+
new Intl.DateTimeFormat("en-US", { timeZone: candidate });
|
|
5784
|
+
return candidate;
|
|
5785
|
+
} catch {
|
|
5786
|
+
return null;
|
|
5787
|
+
}
|
|
5788
|
+
}
|
|
5789
|
+
__name(resolveZone, "resolveZone");
|
|
5790
|
+
function zonedParts(instantMs, zone) {
|
|
5791
|
+
const parts = new Intl.DateTimeFormat("en-US", {
|
|
5792
|
+
timeZone: zone,
|
|
5793
|
+
hourCycle: "h23",
|
|
5794
|
+
year: "numeric",
|
|
5795
|
+
month: "2-digit",
|
|
5796
|
+
day: "2-digit",
|
|
5797
|
+
hour: "2-digit",
|
|
5798
|
+
minute: "2-digit",
|
|
5799
|
+
second: "2-digit"
|
|
5800
|
+
}).formatToParts(new Date(instantMs));
|
|
5801
|
+
const get = /* @__PURE__ */ __name((type) => Number(parts.find((part) => part.type === type)?.value ?? 0), "get");
|
|
5802
|
+
return {
|
|
5803
|
+
year: get("year"),
|
|
5804
|
+
month: get("month") - 1,
|
|
5805
|
+
day: get("day"),
|
|
5806
|
+
hour: get("hour") % 24,
|
|
5807
|
+
minute: get("minute"),
|
|
5808
|
+
second: get("second")
|
|
5809
|
+
};
|
|
5810
|
+
}
|
|
5811
|
+
__name(zonedParts, "zonedParts");
|
|
5812
|
+
function zoneOffsetMs(instantMs, zone) {
|
|
5813
|
+
const whole = Math.floor(instantMs / 1e3) * 1e3;
|
|
5814
|
+
const p = zonedParts(whole, zone);
|
|
5815
|
+
return Date.UTC(p.year, p.month, p.day, p.hour, p.minute, p.second) - whole;
|
|
5816
|
+
}
|
|
5817
|
+
__name(zoneOffsetMs, "zoneOffsetMs");
|
|
5818
|
+
function zonedWallTimeToUtc(year, month, day, hour, minute, zone) {
|
|
5819
|
+
const asIfUtc = Date.UTC(year, month, day, hour, minute, 0);
|
|
5820
|
+
const firstOffset = zoneOffsetMs(asIfUtc, zone);
|
|
5821
|
+
const guess = asIfUtc - firstOffset;
|
|
5822
|
+
const secondOffset = zoneOffsetMs(guess, zone);
|
|
5823
|
+
return secondOffset === firstOffset ? guess : asIfUtc - secondOffset;
|
|
5824
|
+
}
|
|
5825
|
+
__name(zonedWallTimeToUtc, "zonedWallTimeToUtc");
|
|
5522
5826
|
var FLEET_ENROLLABLE_NODE_KINDS = ["desktop-node", "node"];
|
|
5523
5827
|
function isFleetEnrollableNodeKind(value) {
|
|
5524
5828
|
return typeof value === "string" && FLEET_ENROLLABLE_NODE_KINDS.includes(value);
|
|
@@ -6124,6 +6428,8 @@ var EVER_STATS_KEY_ID_HEADER = CONSTANTS.stats_headers.key_id;
|
|
|
6124
6428
|
var EVER_STATS_SIGNATURE_PREFIX = CONSTANTS.stats_signature_prefix;
|
|
6125
6429
|
var EVER_STATS_MAX_BODY_BYTES = CONSTANTS.stats.max_bytes;
|
|
6126
6430
|
var DOMAIN_EVENT_CATALOG = [
|
|
6431
|
+
// EW-P2-6 — `org:write` (and the app) create Organizations.
|
|
6432
|
+
{ type: "organization.created", domain: "organization", aggregateType: "organization", phase: "P2" },
|
|
6127
6433
|
{ type: "organization.updated", domain: "organization", aggregateType: "organization", phase: "P1" },
|
|
6128
6434
|
{
|
|
6129
6435
|
type: "organization.member.added",
|
|
@@ -6170,10 +6476,10 @@ var DOMAIN_EVENT_CATALOG = [
|
|
|
6170
6476
|
{ type: "mission.updated", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6171
6477
|
{ type: "mission.status_changed", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6172
6478
|
{ type: "mission.deleted", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6173
|
-
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6174
|
-
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6175
|
-
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6176
|
-
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
6479
|
+
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
6480
|
+
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
6481
|
+
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
6482
|
+
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
6177
6483
|
{ type: "goal.created", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
6178
6484
|
{ type: "goal.updated", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
6179
6485
|
{ type: "goal.status_changed", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
@@ -6230,6 +6536,11 @@ var DOMAIN_EVENT_TYPES = DOMAIN_EVENT_CATALOG.map((entry) => entry.type);
|
|
|
6230
6536
|
var CATALOG_BY_TYPE = new Map(
|
|
6231
6537
|
DOMAIN_EVENT_CATALOG.map((entry) => [entry.type, entry])
|
|
6232
6538
|
);
|
|
6539
|
+
var RECIPIENT_SCOPED_EVENT_DOMAINS = {
|
|
6540
|
+
inbox: "inbox:read",
|
|
6541
|
+
email: "email:read"
|
|
6542
|
+
};
|
|
6543
|
+
var RECIPIENT_EVENT_SCOPES = Object.values(RECIPIENT_SCOPED_EVENT_DOMAINS);
|
|
6233
6544
|
var INTEGRATION_SCOPES = [
|
|
6234
6545
|
"org:read",
|
|
6235
6546
|
"org:write",
|
|
@@ -8689,6 +9000,7 @@ __name(measureWorkspaceFreeBytes, "measureWorkspaceFreeBytes");
|
|
|
8689
9000
|
|
|
8690
9001
|
// src/core/worker-loop.ts
|
|
8691
9002
|
var DEFAULT_IDLE_POLL_MS = 5e3;
|
|
9003
|
+
var MODEL_THROTTLE_SYNC_GRACE_MS = 12e4;
|
|
8692
9004
|
var WORKER_BACKOFF_BASE_MS = 1e3;
|
|
8693
9005
|
var WORKER_BACKOFF_MAX_MS = 6e4;
|
|
8694
9006
|
var MIN_KEEPALIVE_MS = 5e3;
|
|
@@ -8787,6 +9099,8 @@ var WorkerLoop = class {
|
|
|
8787
9099
|
monotonicNow;
|
|
8788
9100
|
leasePollDrainTimeoutMs;
|
|
8789
9101
|
publishFenceMarginMs;
|
|
9102
|
+
/** Fleet usage limits: provider → the throttle in force (expiry checked on read). */
|
|
9103
|
+
modelThrottles = /* @__PURE__ */ new Map();
|
|
8790
9104
|
running = false;
|
|
8791
9105
|
stopping = false;
|
|
8792
9106
|
paused = false;
|
|
@@ -8846,7 +9160,118 @@ var WorkerLoop = class {
|
|
|
8846
9160
|
return [...this.executors.keys()];
|
|
8847
9161
|
}
|
|
8848
9162
|
getState() {
|
|
8849
|
-
|
|
9163
|
+
const modelThrottles = this.activeModelThrottles();
|
|
9164
|
+
return {
|
|
9165
|
+
...this.state,
|
|
9166
|
+
activeJobIds: [...this.state.activeJobIds],
|
|
9167
|
+
...modelThrottles.length > 0 ? { modelThrottles } : {}
|
|
9168
|
+
};
|
|
9169
|
+
}
|
|
9170
|
+
/**
|
|
9171
|
+
* Fleet usage limits — record that `limit.provider` is out of quota on this
|
|
9172
|
+
* machine until `limit.retryAfter`. From the next poll the loop leases no
|
|
9173
|
+
* `agent-task` for that CLI (all of `agent-task` when every CLI this node
|
|
9174
|
+
* has is out), and refuses — without starting it — any such job the
|
|
9175
|
+
* platform still hands it. Other job kinds keep leasing. A later reset
|
|
9176
|
+
* replaces an earlier one; an earlier one never shortens a later one.
|
|
9177
|
+
*/
|
|
9178
|
+
noteModelUsageLimit(limit) {
|
|
9179
|
+
const provider = typeof limit.provider === "string" ? limit.provider.trim() : "";
|
|
9180
|
+
const until = Date.parse(limit.retryAfter);
|
|
9181
|
+
if (!provider || !Number.isFinite(until) || until <= this.now()) return;
|
|
9182
|
+
const previous = this.modelThrottles.get(provider);
|
|
9183
|
+
if (previous && previous.until >= until) return;
|
|
9184
|
+
this.modelThrottles.set(provider, { until, window: limit.window, reason: limit.message, setAt: this.now() });
|
|
9185
|
+
if (!previous || previous.until <= this.now()) {
|
|
9186
|
+
this.options.logger?.warn(
|
|
9187
|
+
`${describeFleetModelProvider(provider)} hit its ${describeFleetModelUsageLimitWindow(limit.window)} on this node \u2014 not leasing ${provider} agent-task jobs until ${new Date(until).toISOString()} (other work still runs)`
|
|
9188
|
+
);
|
|
9189
|
+
}
|
|
9190
|
+
this.patch({});
|
|
9191
|
+
}
|
|
9192
|
+
/**
|
|
9193
|
+
* Fleet usage limits — reconcile with the platform's view of this node's
|
|
9194
|
+
* throttles, as carried on every heartbeat response (`node.modelThrottles`).
|
|
9195
|
+
*
|
|
9196
|
+
* The platform is authoritative both ways:
|
|
9197
|
+
* - a throttle it holds that this loop does not (a restarted daemon, a
|
|
9198
|
+
* limit another path recorded) is ADOPTED, so the node stops offering
|
|
9199
|
+
* itself for that CLI and says so on its next beat;
|
|
9200
|
+
* - a throttle this loop holds that the platform no longer does — the
|
|
9201
|
+
* owner pressed "clear limit now" — is LIFTED, but only once it is older
|
|
9202
|
+
* than `graceMs`: a heartbeat answered just before the platform recorded
|
|
9203
|
+
* the limit this node just reported must not undo it.
|
|
9204
|
+
* `null` / absent (an API older than the field) changes nothing.
|
|
9205
|
+
*/
|
|
9206
|
+
syncModelThrottles(server, graceMs = MODEL_THROTTLE_SYNC_GRACE_MS) {
|
|
9207
|
+
if (!Array.isArray(server)) return;
|
|
9208
|
+
const now = this.now();
|
|
9209
|
+
const held = /* @__PURE__ */ new Set();
|
|
9210
|
+
let changed = false;
|
|
9211
|
+
for (const entry of server) {
|
|
9212
|
+
const provider = typeof entry?.provider === "string" ? entry.provider.trim() : "";
|
|
9213
|
+
const until = typeof entry?.until === "string" ? Date.parse(entry.until) : Number.NaN;
|
|
9214
|
+
if (!provider || !Number.isFinite(until) || until <= now) continue;
|
|
9215
|
+
held.add(provider);
|
|
9216
|
+
const local = this.modelThrottles.get(provider);
|
|
9217
|
+
if (local && local.until >= until) continue;
|
|
9218
|
+
const window = typeof entry.window === "string" ? entry.window : "usage";
|
|
9219
|
+
const reason = typeof entry.reason === "string" ? entry.reason : `${provider} usage limit reached`;
|
|
9220
|
+
this.modelThrottles.set(provider, { until, window, reason, setAt: local?.setAt ?? now });
|
|
9221
|
+
changed = true;
|
|
9222
|
+
if (!local) {
|
|
9223
|
+
this.options.logger?.info(
|
|
9224
|
+
`${describeFleetModelProvider(provider)} is out of quota on this node per the platform \u2014 not leasing ${provider} agent-task jobs until ${new Date(until).toISOString()}`
|
|
9225
|
+
);
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9228
|
+
for (const [provider, local] of this.modelThrottles) {
|
|
9229
|
+
if (held.has(provider) || now - local.setAt < graceMs) continue;
|
|
9230
|
+
this.modelThrottles.delete(provider);
|
|
9231
|
+
changed = true;
|
|
9232
|
+
this.options.logger?.info(
|
|
9233
|
+
`${describeFleetModelProvider(provider)} usage limit was cleared on the platform \u2014 leasing ${provider} agent-task jobs again`
|
|
9234
|
+
);
|
|
9235
|
+
}
|
|
9236
|
+
if (changed) {
|
|
9237
|
+
this.patch({});
|
|
9238
|
+
this.pollSoon();
|
|
9239
|
+
}
|
|
9240
|
+
}
|
|
9241
|
+
/** The usage-limit throttles still in force; expired ones are dropped (and logged) here. */
|
|
9242
|
+
activeModelThrottles() {
|
|
9243
|
+
const now = this.now();
|
|
9244
|
+
const active = [];
|
|
9245
|
+
for (const [provider, throttle] of this.modelThrottles) {
|
|
9246
|
+
if (throttle.until <= now) {
|
|
9247
|
+
this.modelThrottles.delete(provider);
|
|
9248
|
+
this.options.logger?.info(
|
|
9249
|
+
`${describeFleetModelProvider(provider)} usage limit has reset \u2014 leasing ${provider} agent-task jobs again`
|
|
9250
|
+
);
|
|
9251
|
+
continue;
|
|
9252
|
+
}
|
|
9253
|
+
active.push({
|
|
9254
|
+
provider,
|
|
9255
|
+
window: throttle.window,
|
|
9256
|
+
until: new Date(throttle.until).toISOString(),
|
|
9257
|
+
reason: throttle.reason
|
|
9258
|
+
});
|
|
9259
|
+
}
|
|
9260
|
+
return active.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
9261
|
+
}
|
|
9262
|
+
/** True when every model CLI this node can run an agent-task with is out of quota. */
|
|
9263
|
+
allAgentCliThrottled() {
|
|
9264
|
+
const active = this.activeModelThrottles();
|
|
9265
|
+
if (active.length === 0) return false;
|
|
9266
|
+
let providers = [];
|
|
9267
|
+
try {
|
|
9268
|
+
providers = this.options.modelProviders?.() ?? [];
|
|
9269
|
+
} catch {
|
|
9270
|
+
providers = [];
|
|
9271
|
+
}
|
|
9272
|
+
if (providers.length === 0) return true;
|
|
9273
|
+
const out = new Set(active.map((throttle) => throttle.provider));
|
|
9274
|
+
return providers.every((provider) => out.has(provider));
|
|
8850
9275
|
}
|
|
8851
9276
|
onChange(listener) {
|
|
8852
9277
|
this.listeners.add(listener);
|
|
@@ -9124,8 +9549,10 @@ var WorkerLoop = class {
|
|
|
9124
9549
|
};
|
|
9125
9550
|
if (this.options.capabilities) request.capabilities = this.options.capabilities;
|
|
9126
9551
|
if (this.options.kinds && this.options.kinds.length > 0) request.kinds = [...this.options.kinds];
|
|
9127
|
-
|
|
9128
|
-
|
|
9552
|
+
const excludeKinds = new Set(this.options.excludeKinds ?? []);
|
|
9553
|
+
if (this.allAgentCliThrottled()) excludeKinds.add("agent-task");
|
|
9554
|
+
if (excludeKinds.size > 0) {
|
|
9555
|
+
request.excludeKinds = [...excludeKinds];
|
|
9129
9556
|
}
|
|
9130
9557
|
if (this.options.client.leaseOutcome) {
|
|
9131
9558
|
const outcome = await this.options.client.leaseOutcome(request, pollController.signal);
|
|
@@ -9362,6 +9789,14 @@ var WorkerLoop = class {
|
|
|
9362
9789
|
);
|
|
9363
9790
|
return;
|
|
9364
9791
|
}
|
|
9792
|
+
const throttled = this.throttledResultFor(job);
|
|
9793
|
+
if (throttled) {
|
|
9794
|
+
this.options.logger?.info(
|
|
9795
|
+
`Fleet job ${job.id} not started: ${String(throttled.failureReason)} \u2014 handed back for the platform to park`
|
|
9796
|
+
);
|
|
9797
|
+
await this.report(job.id, { success: true, result: throttled }, generation, run);
|
|
9798
|
+
return;
|
|
9799
|
+
}
|
|
9365
9800
|
const keepAlive = this.startKeepAlive(run);
|
|
9366
9801
|
let successAccepted = false;
|
|
9367
9802
|
try {
|
|
@@ -9370,6 +9805,7 @@ var WorkerLoop = class {
|
|
|
9370
9805
|
);
|
|
9371
9806
|
const result = await executor(job, signal, keepAlive.handle);
|
|
9372
9807
|
throwIfJobAborted(signal);
|
|
9808
|
+
this.noteUsageLimitResult(result);
|
|
9373
9809
|
if (this.settleDeferred(job.id, keepAlive.deferral())) return;
|
|
9374
9810
|
const accepted = await this.report(
|
|
9375
9811
|
job.id,
|
|
@@ -9404,6 +9840,57 @@ var WorkerLoop = class {
|
|
|
9404
9840
|
keepAlive.stop();
|
|
9405
9841
|
}
|
|
9406
9842
|
}
|
|
9843
|
+
/** A result that says its CLI hit a usage limit throttles that CLI here. */
|
|
9844
|
+
noteUsageLimitResult(result) {
|
|
9845
|
+
if (!result || result.failureKind !== FLEET_JOB_FAILURE_KIND_MODEL_USAGE_LIMIT) return;
|
|
9846
|
+
const limit = result.modelUsageLimit;
|
|
9847
|
+
if (!limit || typeof limit.provider !== "string" || typeof limit.retryAfter !== "string") return;
|
|
9848
|
+
this.noteModelUsageLimit({
|
|
9849
|
+
provider: limit.provider,
|
|
9850
|
+
window: limit.window ?? "usage",
|
|
9851
|
+
retryAfter: limit.retryAfter,
|
|
9852
|
+
message: typeof limit.message === "string" ? limit.message : `${limit.provider} usage limit reached`
|
|
9853
|
+
});
|
|
9854
|
+
}
|
|
9855
|
+
/**
|
|
9856
|
+
* The usage-limit outcome for an `agent-task` whose CLI is out of quota on
|
|
9857
|
+
* this node, or null. Shaped like a real run's result (model block
|
|
9858
|
+
* included) so the platform — current or older — reads it the same way.
|
|
9859
|
+
*/
|
|
9860
|
+
throttledResultFor(job) {
|
|
9861
|
+
if (job.kind !== "agent-task") return null;
|
|
9862
|
+
const payload = job.payload ?? {};
|
|
9863
|
+
const execution = payload.execution;
|
|
9864
|
+
const provider = typeof execution?.provider === "string" ? execution.provider : null;
|
|
9865
|
+
if (!provider) return null;
|
|
9866
|
+
const throttle = this.activeModelThrottles().find((entry) => entry.provider === provider);
|
|
9867
|
+
if (!throttle) return null;
|
|
9868
|
+
const failureReason = `${provider} is out of quota on this node until ${throttle.until} (${describeFleetModelUsageLimitWindow(throttle.window)}) \u2014 not started`;
|
|
9869
|
+
return {
|
|
9870
|
+
status: "failed",
|
|
9871
|
+
taskId: typeof payload.taskId === "string" ? payload.taskId : "",
|
|
9872
|
+
runId: typeof payload.runId === "string" ? payload.runId : null,
|
|
9873
|
+
workspace: null,
|
|
9874
|
+
steps: [],
|
|
9875
|
+
model: {
|
|
9876
|
+
provider,
|
|
9877
|
+
status: "failed",
|
|
9878
|
+
exitCode: null,
|
|
9879
|
+
durationMs: 0,
|
|
9880
|
+
summary: throttle.reason
|
|
9881
|
+
},
|
|
9882
|
+
gateStatus: "none",
|
|
9883
|
+
failureReason,
|
|
9884
|
+
failureKind: FLEET_JOB_FAILURE_KIND_MODEL_USAGE_LIMIT,
|
|
9885
|
+
modelUsageLimit: {
|
|
9886
|
+
provider,
|
|
9887
|
+
window: throttle.window,
|
|
9888
|
+
resetsAt: null,
|
|
9889
|
+
retryAfter: throttle.until,
|
|
9890
|
+
message: throttle.reason
|
|
9891
|
+
}
|
|
9892
|
+
};
|
|
9893
|
+
}
|
|
9407
9894
|
/**
|
|
9408
9895
|
* Record a job the executor handed back UNSETTLED, and report nothing.
|
|
9409
9896
|
*
|
|
@@ -10994,6 +11481,32 @@ __name(isReportableBytes, "isReportableBytes");
|
|
|
10994
11481
|
// src/core/worker-health.ts
|
|
10995
11482
|
function describeWorkerHealth(state) {
|
|
10996
11483
|
if (!state) return null;
|
|
11484
|
+
const projected = projectWorkerState(state);
|
|
11485
|
+
const usage = describeModelThrottles(state);
|
|
11486
|
+
if (!usage) return projected;
|
|
11487
|
+
switch (projected.workerState) {
|
|
11488
|
+
case "idle":
|
|
11489
|
+
return health("throttled", usage);
|
|
11490
|
+
case "throttled":
|
|
11491
|
+
case "working":
|
|
11492
|
+
return health(
|
|
11493
|
+
projected.workerState,
|
|
11494
|
+
projected.workerStateReason ? `${projected.workerStateReason}; ${usage}` : usage
|
|
11495
|
+
);
|
|
11496
|
+
default:
|
|
11497
|
+
return projected;
|
|
11498
|
+
}
|
|
11499
|
+
}
|
|
11500
|
+
__name(describeWorkerHealth, "describeWorkerHealth");
|
|
11501
|
+
function describeModelThrottles(state) {
|
|
11502
|
+
const throttles = state.modelThrottles ?? [];
|
|
11503
|
+
if (throttles.length === 0) return null;
|
|
11504
|
+
return throttles.map(
|
|
11505
|
+
(throttle) => `${throttle.provider}: ${describeFleetModelUsageLimitWindow(throttle.window)} until ${throttle.until}`
|
|
11506
|
+
).join("; ");
|
|
11507
|
+
}
|
|
11508
|
+
__name(describeModelThrottles, "describeModelThrottles");
|
|
11509
|
+
function projectWorkerState(state) {
|
|
10997
11510
|
switch (state.state) {
|
|
10998
11511
|
// The fail-closed stop. `lastError` carries the quarantine's own
|
|
10999
11512
|
// message (`markUnsafe` writes it there), which is the single most
|
|
@@ -11023,7 +11536,7 @@ function describeWorkerHealth(state) {
|
|
|
11023
11536
|
return health("idle", null);
|
|
11024
11537
|
}
|
|
11025
11538
|
}
|
|
11026
|
-
__name(
|
|
11539
|
+
__name(projectWorkerState, "projectWorkerState");
|
|
11027
11540
|
function health(workerState, reason) {
|
|
11028
11541
|
const trimmed = typeof reason === "string" ? reason.trim() : "";
|
|
11029
11542
|
if (!trimmed) {
|
|
@@ -12983,6 +13496,31 @@ async function runResolvedAgentTask(context, io, signal) {
|
|
|
12983
13496
|
containment = modelStep.containment;
|
|
12984
13497
|
throwIfAgentTaskAborted(signal);
|
|
12985
13498
|
if (model.status !== "succeeded") {
|
|
13499
|
+
const usageLimit = recognizeModelUsageLimit(model, io);
|
|
13500
|
+
if (usageLimit) {
|
|
13501
|
+
if (workspaceResolution.descriptor && io.removeRunEnvFiles) {
|
|
13502
|
+
await io.removeRunEnvFiles(taskId, workspaceResolution.descriptor).catch(() => void 0);
|
|
13503
|
+
}
|
|
13504
|
+
io.logger?.warn(
|
|
13505
|
+
`[fleet-node] job ${job.id}: ${model.provider} hit a usage limit (${usageLimit.window}) \u2014 retry after ${usageLimit.retryAfter}; steps, checks and publish skipped`
|
|
13506
|
+
);
|
|
13507
|
+
return fitNodeOutcomeToResultBudget({
|
|
13508
|
+
status: "failed",
|
|
13509
|
+
taskId,
|
|
13510
|
+
runId,
|
|
13511
|
+
workspace: workspaceResolution.descriptor,
|
|
13512
|
+
steps: [],
|
|
13513
|
+
...setupResults.length > 0 ? { setup: setupResults } : {},
|
|
13514
|
+
...setup.length > 0 ? { setupStatus } : {},
|
|
13515
|
+
model,
|
|
13516
|
+
gateStatus: "none",
|
|
13517
|
+
...mcp ? { mcp } : {},
|
|
13518
|
+
...containment ? { containment } : {},
|
|
13519
|
+
failureReason: `${describeModelFailure(model)} \u2014 usage limit, retry after ${usageLimit.retryAfter}`,
|
|
13520
|
+
failureKind: FLEET_JOB_FAILURE_KIND_MODEL_USAGE_LIMIT,
|
|
13521
|
+
modelUsageLimit: usageLimit
|
|
13522
|
+
});
|
|
13523
|
+
}
|
|
12986
13524
|
failures.push(describeModelFailure(model));
|
|
12987
13525
|
}
|
|
12988
13526
|
}
|
|
@@ -13688,6 +14226,22 @@ function resumeNeverOpened(model) {
|
|
|
13688
14226
|
return RESUME_NEVER_OPENED_SIGNATURES.some((signature) => signature.test(said));
|
|
13689
14227
|
}
|
|
13690
14228
|
__name(resumeNeverOpened, "resumeNeverOpened");
|
|
14229
|
+
function recognizeModelUsageLimit(model, io = {}) {
|
|
14230
|
+
if (model.status === "succeeded" || model.status === "timeout") return null;
|
|
14231
|
+
const now = io.usageLimitClock?.now() ?? Date.now();
|
|
14232
|
+
const timeZone = io.usageLimitClock?.timeZone ?? localTimeZone();
|
|
14233
|
+
const options = { provider: model.provider, now, ...timeZone ? { timeZone } : {} };
|
|
14234
|
+
return detectFleetModelUsageLimit(model.summary, options) ?? detectFleetModelUsageLimit(model.outputTail, { ...options, strict: true });
|
|
14235
|
+
}
|
|
14236
|
+
__name(recognizeModelUsageLimit, "recognizeModelUsageLimit");
|
|
14237
|
+
function localTimeZone() {
|
|
14238
|
+
try {
|
|
14239
|
+
return Intl.DateTimeFormat().resolvedOptions().timeZone || void 0;
|
|
14240
|
+
} catch {
|
|
14241
|
+
return void 0;
|
|
14242
|
+
}
|
|
14243
|
+
}
|
|
14244
|
+
__name(localTimeZone, "localTimeZone");
|
|
13691
14245
|
function describeModelFailure(model) {
|
|
13692
14246
|
switch (model.status) {
|
|
13693
14247
|
case "timeout":
|
|
@@ -15995,6 +16549,8 @@ Object.freeze(
|
|
|
15995
16549
|
ACTION_CATEGORIES2.filter((c) => c !== "read.internal")
|
|
15996
16550
|
);
|
|
15997
16551
|
var DOMAIN_EVENT_CATALOG2 = [
|
|
16552
|
+
// EW-P2-6 — `org:write` (and the app) create Organizations.
|
|
16553
|
+
{ type: "organization.created", domain: "organization", aggregateType: "organization", phase: "P2" },
|
|
15998
16554
|
{ type: "organization.updated", domain: "organization", aggregateType: "organization", phase: "P1" },
|
|
15999
16555
|
{
|
|
16000
16556
|
type: "organization.member.added",
|
|
@@ -16041,10 +16597,10 @@ var DOMAIN_EVENT_CATALOG2 = [
|
|
|
16041
16597
|
{ type: "mission.updated", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16042
16598
|
{ type: "mission.status_changed", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16043
16599
|
{ type: "mission.deleted", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16044
|
-
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16045
|
-
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16046
|
-
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16047
|
-
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
16600
|
+
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
16601
|
+
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
16602
|
+
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
16603
|
+
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
16048
16604
|
{ type: "goal.created", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
16049
16605
|
{ type: "goal.updated", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
16050
16606
|
{ type: "goal.status_changed", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
@@ -16591,6 +17147,7 @@ var LocalWorkspacePlugin = class _LocalWorkspacePlugin {
|
|
|
16591
17147
|
);
|
|
16592
17148
|
const dirty = status.stdout.trim().length > 0;
|
|
16593
17149
|
if (dirty) {
|
|
17150
|
+
const commitMessage = rewriteCommitMessage(opts, status.stdout);
|
|
16594
17151
|
const identity = opts.identity;
|
|
16595
17152
|
await this.gitOrThrow(
|
|
16596
17153
|
[
|
|
@@ -16602,7 +17159,7 @@ var LocalWorkspacePlugin = class _LocalWorkspacePlugin {
|
|
|
16602
17159
|
...opts.hardenRepoHooks ? ["--no-verify"] : [],
|
|
16603
17160
|
...identity ? [`--author=${identity.authorName} <${identity.authorEmail}>`] : [],
|
|
16604
17161
|
"-m",
|
|
16605
|
-
|
|
17162
|
+
commitMessage
|
|
16606
17163
|
],
|
|
16607
17164
|
dir,
|
|
16608
17165
|
opts.auth,
|
|
@@ -17845,6 +18402,31 @@ function isSafeCloneArgument(url) {
|
|
|
17845
18402
|
return !parsed.hostname.startsWith("-");
|
|
17846
18403
|
}
|
|
17847
18404
|
__name(isSafeCloneArgument, "isSafeCloneArgument");
|
|
18405
|
+
function parsePorcelainPaths(stdout) {
|
|
18406
|
+
const paths = [];
|
|
18407
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
18408
|
+
if (line.length < 4) continue;
|
|
18409
|
+
let path2 = line.slice(3);
|
|
18410
|
+
const arrow = path2.lastIndexOf(" -> ");
|
|
18411
|
+
if (arrow !== -1) path2 = path2.slice(arrow + 4);
|
|
18412
|
+
if (path2.startsWith('"') && path2.endsWith('"') && path2.length >= 2) {
|
|
18413
|
+
path2 = path2.slice(1, -1).replace(/\\(.)/g, "$1");
|
|
18414
|
+
}
|
|
18415
|
+
if (path2) paths.push(path2);
|
|
18416
|
+
}
|
|
18417
|
+
return paths;
|
|
18418
|
+
}
|
|
18419
|
+
__name(parsePorcelainPaths, "parsePorcelainPaths");
|
|
18420
|
+
function rewriteCommitMessage(opts, porcelain) {
|
|
18421
|
+
if (typeof opts.commitMessageFor !== "function") return opts.commitMessage;
|
|
18422
|
+
try {
|
|
18423
|
+
const next = opts.commitMessageFor(parsePorcelainPaths(porcelain), opts.commitMessage);
|
|
18424
|
+
return typeof next === "string" && next.trim() && !/[\0\r]/.test(next) ? next : opts.commitMessage;
|
|
18425
|
+
} catch {
|
|
18426
|
+
return opts.commitMessage;
|
|
18427
|
+
}
|
|
18428
|
+
}
|
|
18429
|
+
__name(rewriteCommitMessage, "rewriteCommitMessage");
|
|
17848
18430
|
|
|
17849
18431
|
// src/core/workspaces/push-credential.ts
|
|
17850
18432
|
var PUSH_CREDENTIAL_REVOKE_TIMEOUT_MS = 5e3;
|
|
@@ -18763,6 +19345,11 @@ var FleetTaskWorkspaceProvisioner = class {
|
|
|
18763
19345
|
// pool config. The credentialed push already does this; the flag
|
|
18764
19346
|
// extends it to the commit.
|
|
18765
19347
|
hardenRepoHooks: true,
|
|
19348
|
+
// Fleet commit messages: once the change is staged, a
|
|
19349
|
+
// docs-only change commits as `docs`, a tests-only one as
|
|
19350
|
+
// `test`, whatever the Task title implied. Only the type token
|
|
19351
|
+
// of the subject changes; the body and trailers are untouched.
|
|
19352
|
+
commitMessageFor: /* @__PURE__ */ __name((changedPaths, message) => retypeFleetCommitMessage(message, changedPaths), "commitMessageFor"),
|
|
18766
19353
|
...signal ? { signal } : {},
|
|
18767
19354
|
...opts.publishFence ? { publishFence: opts.publishFence } : {},
|
|
18768
19355
|
...authorization.identity ? { identity: authorization.identity } : {},
|
|
@@ -20313,6 +20900,8 @@ Object.freeze(
|
|
|
20313
20900
|
ACTION_CATEGORIES3.filter((c) => c !== "read.internal")
|
|
20314
20901
|
);
|
|
20315
20902
|
var DOMAIN_EVENT_CATALOG3 = [
|
|
20903
|
+
// EW-P2-6 — `org:write` (and the app) create Organizations.
|
|
20904
|
+
{ type: "organization.created", domain: "organization", aggregateType: "organization", phase: "P2" },
|
|
20316
20905
|
{ type: "organization.updated", domain: "organization", aggregateType: "organization", phase: "P1" },
|
|
20317
20906
|
{
|
|
20318
20907
|
type: "organization.member.added",
|
|
@@ -20359,10 +20948,10 @@ var DOMAIN_EVENT_CATALOG3 = [
|
|
|
20359
20948
|
{ type: "mission.updated", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20360
20949
|
{ type: "mission.status_changed", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20361
20950
|
{ type: "mission.deleted", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20362
|
-
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20363
|
-
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20364
|
-
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20365
|
-
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2" },
|
|
20951
|
+
{ type: "mission.goal.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
20952
|
+
{ type: "mission.goal.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "goal" },
|
|
20953
|
+
{ type: "mission.work.linked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
20954
|
+
{ type: "mission.work.unlinked", domain: "missions", aggregateType: "mission", phase: "P2", child: "work" },
|
|
20366
20955
|
{ type: "goal.created", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
20367
20956
|
{ type: "goal.updated", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
20368
20957
|
{ type: "goal.status_changed", domain: "goals", aggregateType: "goal", phase: "P2" },
|
|
@@ -21578,6 +22167,7 @@ function createNodeRuntime(config, io, options = {}) {
|
|
|
21578
22167
|
let attendedWake = null;
|
|
21579
22168
|
const holdableLanes = [];
|
|
21580
22169
|
let limitTarget = null;
|
|
22170
|
+
let throttleTarget = null;
|
|
21581
22171
|
const lifecycle = new NodeLifecycleTracker({
|
|
21582
22172
|
daemonVersion: io.version,
|
|
21583
22173
|
logger: io.logger,
|
|
@@ -21601,6 +22191,7 @@ function createNodeRuntime(config, io, options = {}) {
|
|
|
21601
22191
|
onAccepted: /* @__PURE__ */ __name((response) => {
|
|
21602
22192
|
attendedWake?.(response.pendingComputerSessions);
|
|
21603
22193
|
lifecycle.applyHeartbeat(response);
|
|
22194
|
+
throttleTarget?.(response.node?.modelThrottles);
|
|
21604
22195
|
}, "onAccepted")
|
|
21605
22196
|
};
|
|
21606
22197
|
const runtime = { client, loop: new HeartbeatLoop(loopOptions), lifecycle, cliCompat };
|
|
@@ -21642,7 +22233,11 @@ function createNodeRuntime(config, io, options = {}) {
|
|
|
21642
22233
|
// attended lane alone — never parked in (or holding a slot of) the
|
|
21643
22234
|
// work lane. Sent only under `--attend`, so a work-only node's lease
|
|
21644
22235
|
// body is exactly what it always was.
|
|
21645
|
-
...options.attendEnabled ? { excludeKinds: ["computer-session"] } : {}
|
|
22236
|
+
...options.attendEnabled ? { excludeKinds: ["computer-session"] } : {},
|
|
22237
|
+
// Fleet usage limits: the CLIs an agent-task can run with here, so a
|
|
22238
|
+
// node whose only CLI is out of quota stops leasing agent-task work
|
|
22239
|
+
// until the reset (other kinds keep leasing).
|
|
22240
|
+
modelProviders: /* @__PURE__ */ __name(() => Object.entries(options.modelCli ?? io.environment.modelCli ?? {}).filter(([, path2]) => typeof path2 === "string" && path2.length > 0).map(([provider]) => provider), "modelProviders")
|
|
21646
22241
|
});
|
|
21647
22242
|
holdableLanes.push(worker);
|
|
21648
22243
|
worker.onUpgradeRequired((hold) => lifecycle.applyLeaseRefusal(hold.minNodeVersion));
|
|
@@ -21654,6 +22249,9 @@ function createNodeRuntime(config, io, options = {}) {
|
|
|
21654
22249
|
}
|
|
21655
22250
|
}, "limitTarget");
|
|
21656
22251
|
telemetry.limits = () => worker.resourceLimits;
|
|
22252
|
+
throttleTarget = /* @__PURE__ */ __name((throttles) => {
|
|
22253
|
+
if (Array.isArray(throttles)) worker.syncModelThrottles(throttles);
|
|
22254
|
+
}, "throttleTarget");
|
|
21657
22255
|
telemetry.workerHealth = () => describeWorkerHealth(worker.getState());
|
|
21658
22256
|
const housekeeping = new NodeHousekeepingReporter({
|
|
21659
22257
|
minFreeDiskBytes: io.diskProbe ? effectiveMinFreeDiskBytes(limits) : null,
|
|
@@ -23303,10 +23901,12 @@ async function runStart(deps, options) {
|
|
|
23303
23901
|
}
|
|
23304
23902
|
const { loop, worker } = runtime;
|
|
23305
23903
|
const attendedWorker = runtime.attended?.worker ?? null;
|
|
23904
|
+
let lastLoggedBeat = null;
|
|
23306
23905
|
loop.onChange((state) => {
|
|
23307
|
-
if (state.state
|
|
23308
|
-
|
|
23309
|
-
}
|
|
23906
|
+
if (state.state !== "connected") return;
|
|
23907
|
+
if (lastLoggedBeat && lastLoggedBeat.node === state.node && lastLoggedBeat.at === state.lastHeartbeatAt) return;
|
|
23908
|
+
lastLoggedBeat = { node: state.node, at: state.lastHeartbeatAt };
|
|
23909
|
+
deps.io.logger.info(`Heartbeat accepted \u2014 node ${config.nodeId} is online`);
|
|
23310
23910
|
});
|
|
23311
23911
|
deps.out(`Starting node ${config.nodeId} \u2192 ${config.apiUrl} (every ${config.heartbeatIntervalMs / 1e3}s)`);
|
|
23312
23912
|
let requestShutdown = /* @__PURE__ */ __name(() => void 0, "requestShutdown");
|
|
@@ -24105,7 +24705,7 @@ function createLogger(options = {}) {
|
|
|
24105
24705
|
__name(createLogger, "createLogger");
|
|
24106
24706
|
|
|
24107
24707
|
// src/version.ts
|
|
24108
|
-
var NODE_APP_VERSION = "0.2.
|
|
24708
|
+
var NODE_APP_VERSION = "0.2.5";
|
|
24109
24709
|
|
|
24110
24710
|
// src/cli.ts
|
|
24111
24711
|
function buildDeps() {
|
package/package.json
CHANGED