@kubitnodes/stellaris 0.4.0 → 0.4.2
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/dist/cli/index.js +644 -36
- package/dist/server/index.js +901 -116
- package/package.json +1 -1
- package/web/dist/assets/{BackLink-BLiSCuKv.js → BackLink-DNHWkHmh.js} +1 -1
- package/web/dist/assets/{Button-D4-iu6aX.js → Button-B6EN7Lh7.js} +1 -1
- package/web/dist/assets/{ChannelForms-DjviQfVm.js → ChannelForms-BrcWrkej.js} +1 -1
- package/web/dist/assets/ChannelView-D7bT7d9q.js +2 -0
- package/web/dist/assets/CitizenView-D6d1KnS6.js +2 -0
- package/web/dist/assets/{CitizensView-DXD3qkq1.js → CitizensView-C55zOiYE.js} +1 -1
- package/web/dist/assets/{CliIcon-DL4ZwgZv.js → CliIcon-BRq1tnhu.js} +1 -1
- package/web/dist/assets/{CronsView-CX_G5D3h.js → CronsView-BTGiqn10.js} +1 -1
- package/web/dist/assets/{FileTree-BFa_KVI8.js → FileTree-BDhtTIzT.js} +1 -1
- package/web/dist/assets/{FileView-Cd9Ijarf.js → FileView-BkZPGEbO.js} +2 -2
- package/web/dist/assets/{KnowledgeView-D_a4pjGV.js → KnowledgeView-BiTS-lyE.js} +1 -1
- package/web/dist/assets/{Markdown-DPqvK--4.js → Markdown-DYk-gVwe.js} +4 -4
- package/web/dist/assets/{MessageItem-WBTzWwyj.js → MessageItem-WBBIzv48.js} +1 -1
- package/web/dist/assets/MetricsView-CYmnG6aQ.js +1 -0
- package/web/dist/assets/NeedsYouView-B-5olhZL.js +1 -0
- package/web/dist/assets/{Overview-BGUnf6K1.js → Overview-BO_lR1cu.js} +1 -1
- package/web/dist/assets/{Pane-C9TbEME4.js → Pane-DFJdAhv9.js} +1 -1
- package/web/dist/assets/{Picker-BK48MjLY.js → Picker-CAEREZF9.js} +1 -1
- package/web/dist/assets/{ProjectView-sL3aGAC6.js → ProjectView-LU59V2vh.js} +1 -1
- package/web/dist/assets/ProposalView-DHemTlkc.js +1 -0
- package/web/dist/assets/{ProposalsView-DTGx8NDn.js → ProposalsView-DBIOJAul.js} +1 -1
- package/web/dist/assets/{Quota-BkF7pa0u.js → Quota-D6_yyawu.js} +1 -1
- package/web/dist/assets/RunnersView-BNKgYuNw.js +1 -0
- package/web/dist/assets/{SkillFileList-BUpKUkaG.js → SkillFileList-Ntyv8noL.js} +1 -1
- package/web/dist/assets/SkillView-Dez1fvqU.js +1 -0
- package/web/dist/assets/{SocietyView-JSdVE50m.js → SocietyView-CbmbQXHi.js} +1 -1
- package/web/dist/assets/{StickyList-DafbJutb.js → StickyList-Q0KEWBUl.js} +1 -1
- package/web/dist/assets/{SubjectThread-Jyl5YCFL.js → SubjectThread-1PnxxtZc.js} +1 -1
- package/web/dist/assets/{TaskView-Jke2pVGT.js → TaskView-CcIlNHBh.js} +2 -2
- package/web/dist/assets/{TasksView-zJTIaqEA.js → TasksView-BkTU43PD.js} +1 -1
- package/web/dist/assets/{ThreadForms-DwUOktyP.js → ThreadForms-BlOEvY5E.js} +1 -1
- package/web/dist/assets/ThreadItem-D5N_Fw1K.js +1 -0
- package/web/dist/assets/{ThreadView-CdQpBb7M.js → ThreadView-BaYV77mQ.js} +1 -1
- package/web/dist/assets/{citizen-BOn5BBRL.js → citizen-BRg9UIgD.js} +1 -1
- package/web/dist/assets/{compose-D-X3BQgY.js → compose-BnOoMY1c.js} +1 -1
- package/web/dist/assets/format-hyYD8qd8.js +55 -0
- package/web/dist/assets/governance-D4hlG-xw.js +1 -0
- package/web/dist/assets/index-5CbC_NpF.js +24 -0
- package/web/dist/assets/{index-CA_njyMe.css → index-vxBI4BYp.css} +1 -1
- package/web/dist/assets/{mentions-S-r32HKM.js → mentions-Ckktc7nR.js} +1 -1
- package/web/dist/assets/{tasks-D_Fy7dtN.js → tasks-CFVtN9TK.js} +1 -1
- package/web/dist/assets/useMatch-BCaBBHc2.js +1 -0
- package/web/dist/favicon.svg +89 -4
- package/web/dist/index.html +9 -9
- package/web/dist/assets/ChannelView-B-0H7Ps8.js +0 -2
- package/web/dist/assets/CitizenView-gE5GgCBa.js +0 -2
- package/web/dist/assets/MetricsView-YUkYixqT.js +0 -1
- package/web/dist/assets/NeedsYouView-CE_B9bZQ.js +0 -1
- package/web/dist/assets/ProposalView-BhZR4MIR.js +0 -1
- package/web/dist/assets/RunnersView-Bl62pXNw.js +0 -1
- package/web/dist/assets/SkillView-BQJApSh7.js +0 -1
- package/web/dist/assets/ThreadItem-Blx8gSvO.js +0 -1
- package/web/dist/assets/format-Dhd2NUB3.js +0 -55
- package/web/dist/assets/governance-CWzi7hzX.js +0 -1
- package/web/dist/assets/index-iplooQqq.js +0 -24
- package/web/dist/assets/useMatch-DZXCHHaG.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -370,6 +370,18 @@ function mergeQuota(previous, next) {
|
|
|
370
370
|
windows: [...windows.values()]
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
|
+
var UNKNOWN_LIMIT_HOLD_MS = 30 * 6e4;
|
|
374
|
+
function stopsTurns(quota) {
|
|
375
|
+
return quota.status === "limited" && !(quota.source === "read" && quota.extraUsage?.enabled === true);
|
|
376
|
+
}
|
|
377
|
+
function limitHold(quota, now) {
|
|
378
|
+
if (!stopsTurns(quota)) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
const known = quota.limitedUntil !== null;
|
|
382
|
+
const until = quota.limitedUntil ?? new Date(Date.parse(quota.observedAt) + UNKNOWN_LIMIT_HOLD_MS).toISOString();
|
|
383
|
+
return Date.parse(until) > now.getTime() ? { until, known } : null;
|
|
384
|
+
}
|
|
373
385
|
function readings(quota) {
|
|
374
386
|
const windows = quota.windows.map((window) => `${window.key}=${window.usedPercent === null ? "?" : Math.round(window.usedPercent)}@${window.resetsAt === null ? "?" : Math.round(Date.parse(window.resetsAt) / 6e4)}`).toSorted();
|
|
375
387
|
return windows.join(",");
|
|
@@ -699,12 +711,16 @@ var RunnerSchema = z5.object({
|
|
|
699
711
|
function runnerPause(runner2, cli) {
|
|
700
712
|
return runner2.paused ?? runner2.pausedClis?.[cli];
|
|
701
713
|
}
|
|
702
|
-
function
|
|
714
|
+
function runnerLimitHold(runner2, cli, now) {
|
|
715
|
+
const quota = runner2.quotas?.[cli];
|
|
716
|
+
return quota === void 0 ? null : limitHold(quota, now);
|
|
717
|
+
}
|
|
718
|
+
function heldOn(runners, runner2, cli, now) {
|
|
703
719
|
if (runner2 === void 0 || cli === null) {
|
|
704
720
|
return false;
|
|
705
721
|
}
|
|
706
722
|
const record = runners.find((each) => each.name === runner2);
|
|
707
|
-
return record !== void 0 && runnerPause(record, cli) !== void 0;
|
|
723
|
+
return record !== void 0 && (runnerPause(record, cli) !== void 0 || runnerLimitHold(record, cli, now) !== null);
|
|
708
724
|
}
|
|
709
725
|
var ProposalKindSchema = z5.enum([
|
|
710
726
|
"role",
|
|
@@ -1024,6 +1040,12 @@ import { z as z7 } from "zod";
|
|
|
1024
1040
|
import { z as z6 } from "zod";
|
|
1025
1041
|
var IMAGE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1026
1042
|
var ImageTypeSchema = z6.enum(["png", "jpeg", "gif", "webp"]);
|
|
1043
|
+
var IMAGE_KIND_NAMES = {
|
|
1044
|
+
png: "PNG",
|
|
1045
|
+
jpeg: "JPEG",
|
|
1046
|
+
gif: "GIF",
|
|
1047
|
+
webp: "WebP"
|
|
1048
|
+
};
|
|
1027
1049
|
function startsWith(bytes, prefix, at = 0) {
|
|
1028
1050
|
for (let index = 0; index < prefix.length; index += 1) {
|
|
1029
1051
|
if (bytes[at + index] !== prefix[index]) {
|
|
@@ -1445,7 +1467,11 @@ var RunnerHelloSchema = z9.object({
|
|
|
1445
1467
|
gitIdentityMissing: z9.array(GitIdentityPartSchema).optional(),
|
|
1446
1468
|
/** Turns the runner runs at once, or null for no limit. */
|
|
1447
1469
|
slots: z9.number().int().positive().nullable(),
|
|
1448
|
-
/**
|
|
1470
|
+
/**
|
|
1471
|
+
* Turns the runner is still running, when it registers again: the server fails the rest of its
|
|
1472
|
+
* turns, and has any of these it has ended stopped once the stream opens, when the runner lists
|
|
1473
|
+
* a CLI it can stop.
|
|
1474
|
+
*/
|
|
1449
1475
|
turns: z9.array(UlidSchema).default([])
|
|
1450
1476
|
});
|
|
1451
1477
|
var RunnerWelcomeSchema = z9.object({ name: NameSchema, version: z9.string() });
|
|
@@ -1600,9 +1626,9 @@ var TurnOutcomeSchema = z9.object({
|
|
|
1600
1626
|
*/
|
|
1601
1627
|
resumeFailed: ResumeFailureSchema.optional(),
|
|
1602
1628
|
/**
|
|
1603
|
-
* Set when the model service turned
|
|
1604
|
-
*
|
|
1605
|
-
* runner from before never sends it.
|
|
1629
|
+
* Set when the turn failed for now: the model service turned it away or cut it off, or the runner
|
|
1630
|
+
* could not reach the board before the CLI started. The scheduler answers it by sending the same
|
|
1631
|
+
* wake again within minutes. A runner from before never sends it.
|
|
1606
1632
|
*/
|
|
1607
1633
|
transient: z9.boolean().optional(),
|
|
1608
1634
|
/** The model the CLI reported, when it reported one. */
|
|
@@ -1993,13 +2019,18 @@ var TurnRecordSchema = z10.object({
|
|
|
1993
2019
|
stoppedBy: NameSchema.optional(),
|
|
1994
2020
|
/** Why the CLI could not resume the turn's session, for a turn that failed so. */
|
|
1995
2021
|
resumeFailed: ResumeFailureSchema.optional(),
|
|
1996
|
-
/**
|
|
2022
|
+
/**
|
|
2023
|
+
* Whether the turn failed for now, which the same wake may get past in a minute: the model service
|
|
2024
|
+
* turned it away or cut it off, the runner could not reach the board before the CLI started, or
|
|
2025
|
+
* the job never reached the runner.
|
|
2026
|
+
*/
|
|
1997
2027
|
transient: z10.boolean().optional(),
|
|
1998
2028
|
/** How many turns in a row, this one included, could not resume the session for a `retry`. */
|
|
1999
2029
|
resumeRetries: z10.number().int().positive().optional(),
|
|
2000
2030
|
/**
|
|
2001
2031
|
* Whether the server dropped the conversation's session after this turn, which the next starts
|
|
2002
|
-
* anew: one its CLI could not resume, or a society role's home after a
|
|
2032
|
+
* anew: one its CLI could not resume, or a society role's or a project member's home after a
|
|
2033
|
+
* reflection completed.
|
|
2003
2034
|
*/
|
|
2004
2035
|
sessionDropped: z10.boolean().optional(),
|
|
2005
2036
|
/** The crons whose fire started the turn, which record how it ended. */
|
|
@@ -2244,6 +2275,11 @@ var ServerConfigSchema = z13.object({
|
|
|
2244
2275
|
dataDir: z13.string().min(1),
|
|
2245
2276
|
host: z13.string().min(1),
|
|
2246
2277
|
port: z13.number().int().positive().max(65535),
|
|
2278
|
+
/**
|
|
2279
|
+
* A second port, on the same host, that serves Prometheus's counters at `/metrics` and nothing
|
|
2280
|
+
* else, or null for none: the main port's `/metrics` is the interface's page.
|
|
2281
|
+
*/
|
|
2282
|
+
metricsPort: z13.number().int().positive().max(65535).nullable(),
|
|
2247
2283
|
/**
|
|
2248
2284
|
* An address every runner's agents reach this server at, for example https://board.example, or
|
|
2249
2285
|
* null for each runner to use the address it reaches the server at itself.
|
|
@@ -2284,7 +2320,7 @@ var RunnerConfigSchema = z13.object({
|
|
|
2284
2320
|
});
|
|
2285
2321
|
|
|
2286
2322
|
// packages/shared/dist/version.js
|
|
2287
|
-
var STELLARIS_VERSION = "0.4.
|
|
2323
|
+
var STELLARIS_VERSION = "0.4.2";
|
|
2288
2324
|
|
|
2289
2325
|
// packages/shared/dist/mentions.js
|
|
2290
2326
|
import { parse, postprocess, preprocess } from "micromark";
|
|
@@ -2976,6 +3012,451 @@ function filesOf(lines, status) {
|
|
|
2976
3012
|
return [...files.values()];
|
|
2977
3013
|
}
|
|
2978
3014
|
|
|
3015
|
+
// packages/shared/dist/image-metadata.js
|
|
3016
|
+
function withoutMetadata(bytes) {
|
|
3017
|
+
switch (imageTypeOf(bytes)) {
|
|
3018
|
+
case "jpeg":
|
|
3019
|
+
return jpegWithoutMetadata(bytes);
|
|
3020
|
+
case "png":
|
|
3021
|
+
return pngWithoutMetadata(bytes);
|
|
3022
|
+
case "gif":
|
|
3023
|
+
return gifWithoutMetadata(bytes);
|
|
3024
|
+
case "webp":
|
|
3025
|
+
return webpWithoutMetadata(bytes);
|
|
3026
|
+
default:
|
|
3027
|
+
return null;
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
function exifOrientation(block) {
|
|
3031
|
+
const tiff = startsWith2(block, EXIF_HEADER) ? block.subarray(EXIF_HEADER.length) : block;
|
|
3032
|
+
let little;
|
|
3033
|
+
if (tiff[0] === 73 && tiff[1] === 73) {
|
|
3034
|
+
little = true;
|
|
3035
|
+
} else if (tiff[0] === 77 && tiff[1] === 77) {
|
|
3036
|
+
little = false;
|
|
3037
|
+
} else {
|
|
3038
|
+
return 1;
|
|
3039
|
+
}
|
|
3040
|
+
const number = (offset, size) => offset >= 0 && size <= tiff.length && offset <= tiff.length - size ? numberAt(tiff, offset, size, little) : null;
|
|
3041
|
+
const directory = number(4, 4);
|
|
3042
|
+
const count = directory === null ? null : number(directory, 2);
|
|
3043
|
+
if (number(2, 2) !== 42 || directory === null || count === null) {
|
|
3044
|
+
return 1;
|
|
3045
|
+
}
|
|
3046
|
+
for (let entry = directory + 2; entry < directory + 2 + count * 12; entry += 12) {
|
|
3047
|
+
const tag = number(entry, 2);
|
|
3048
|
+
if (tag === null) {
|
|
3049
|
+
return 1;
|
|
3050
|
+
}
|
|
3051
|
+
if (tag === 274) {
|
|
3052
|
+
const value = number(entry + 8, 2);
|
|
3053
|
+
if (number(entry + 2, 2) !== 3 || number(entry + 4, 4) !== 1 || value === null || value < 1 || value > 8) {
|
|
3054
|
+
return 1;
|
|
3055
|
+
}
|
|
3056
|
+
return value;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
return 1;
|
|
3060
|
+
}
|
|
3061
|
+
function orientationOnly(orientation) {
|
|
3062
|
+
const block = new Uint8Array([
|
|
3063
|
+
77,
|
|
3064
|
+
77,
|
|
3065
|
+
0,
|
|
3066
|
+
42,
|
|
3067
|
+
0,
|
|
3068
|
+
0,
|
|
3069
|
+
0,
|
|
3070
|
+
8,
|
|
3071
|
+
0,
|
|
3072
|
+
1,
|
|
3073
|
+
1,
|
|
3074
|
+
18,
|
|
3075
|
+
0,
|
|
3076
|
+
3,
|
|
3077
|
+
0,
|
|
3078
|
+
0,
|
|
3079
|
+
0,
|
|
3080
|
+
1,
|
|
3081
|
+
0,
|
|
3082
|
+
0,
|
|
3083
|
+
0,
|
|
3084
|
+
0,
|
|
3085
|
+
0,
|
|
3086
|
+
0,
|
|
3087
|
+
0,
|
|
3088
|
+
0
|
|
3089
|
+
]);
|
|
3090
|
+
block[19] = orientation;
|
|
3091
|
+
return block;
|
|
3092
|
+
}
|
|
3093
|
+
function crc32(bytes) {
|
|
3094
|
+
let crc = 4294967295;
|
|
3095
|
+
for (const byte of bytes) {
|
|
3096
|
+
crc = (crcTable()[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
|
|
3097
|
+
}
|
|
3098
|
+
return (crc ^ 4294967295) >>> 0;
|
|
3099
|
+
}
|
|
3100
|
+
var crcEntries;
|
|
3101
|
+
function crcTable() {
|
|
3102
|
+
if (crcEntries === void 0) {
|
|
3103
|
+
crcEntries = new Uint32Array(256);
|
|
3104
|
+
for (let index = 0; index < 256; index += 1) {
|
|
3105
|
+
let crc = index;
|
|
3106
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
3107
|
+
crc = crc & 1 ? 3988292384 ^ crc >>> 1 : crc >>> 1;
|
|
3108
|
+
}
|
|
3109
|
+
crcEntries[index] = crc >>> 0;
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
3112
|
+
return crcEntries;
|
|
3113
|
+
}
|
|
3114
|
+
var ascii2 = (text) => new TextEncoder().encode(text);
|
|
3115
|
+
var EXIF_HEADER = Uint8Array.of(69, 120, 105, 102, 0, 0);
|
|
3116
|
+
function startsWith2(bytes, prefix, at = 0) {
|
|
3117
|
+
if (bytes.length - at < prefix.length) {
|
|
3118
|
+
return false;
|
|
3119
|
+
}
|
|
3120
|
+
for (let index = 0; index < prefix.length; index += 1) {
|
|
3121
|
+
if (bytes[at + index] !== prefix[index]) {
|
|
3122
|
+
return false;
|
|
3123
|
+
}
|
|
3124
|
+
}
|
|
3125
|
+
return true;
|
|
3126
|
+
}
|
|
3127
|
+
function typeAt(bytes, at) {
|
|
3128
|
+
return String.fromCharCode(bytes[at] ?? 0, bytes[at + 1] ?? 0, bytes[at + 2] ?? 0, bytes[at + 3] ?? 0);
|
|
3129
|
+
}
|
|
3130
|
+
function numberAt(bytes, at, size, little = false) {
|
|
3131
|
+
let value = 0;
|
|
3132
|
+
for (let index = 0; index < size; index += 1) {
|
|
3133
|
+
value = value * 256 + (bytes[at + (little ? size - 1 - index : index)] ?? 0);
|
|
3134
|
+
}
|
|
3135
|
+
return value;
|
|
3136
|
+
}
|
|
3137
|
+
function bigEndian(value, size) {
|
|
3138
|
+
return Array.from({ length: size }, (_, index) => value >>> (size - 1 - index) * 8 & 255);
|
|
3139
|
+
}
|
|
3140
|
+
function littleEndian(value, size) {
|
|
3141
|
+
return Array.from({ length: size }, (_, index) => value >>> index * 8 & 255);
|
|
3142
|
+
}
|
|
3143
|
+
var Kept = class {
|
|
3144
|
+
buffer;
|
|
3145
|
+
length = 0;
|
|
3146
|
+
constructor(capacity) {
|
|
3147
|
+
this.buffer = new Uint8Array(Math.max(capacity, 64));
|
|
3148
|
+
}
|
|
3149
|
+
add(piece) {
|
|
3150
|
+
if (this.length + piece.length > this.buffer.length) {
|
|
3151
|
+
const grown = new Uint8Array(Math.max(this.buffer.length * 2, this.length + piece.length));
|
|
3152
|
+
grown.set(this.buffer.subarray(0, this.length));
|
|
3153
|
+
this.buffer = grown;
|
|
3154
|
+
}
|
|
3155
|
+
this.buffer.set(piece, this.length);
|
|
3156
|
+
this.length += piece.length;
|
|
3157
|
+
}
|
|
3158
|
+
/** Writes `piece` over what was kept from `at` on, as a size once what it measures is kept. */
|
|
3159
|
+
set(at, piece) {
|
|
3160
|
+
this.buffer.set(piece, at);
|
|
3161
|
+
}
|
|
3162
|
+
get bytes() {
|
|
3163
|
+
return this.buffer.subarray(0, this.length);
|
|
3164
|
+
}
|
|
3165
|
+
};
|
|
3166
|
+
function jpegWithoutMetadata(bytes) {
|
|
3167
|
+
if (bytes[0] !== 255 || bytes[1] !== 216) {
|
|
3168
|
+
return null;
|
|
3169
|
+
}
|
|
3170
|
+
const kept = new Kept(bytes.length);
|
|
3171
|
+
kept.add([255, 216]);
|
|
3172
|
+
let at = 2;
|
|
3173
|
+
let orientationKept = false;
|
|
3174
|
+
for (; ; ) {
|
|
3175
|
+
if (at + 1 >= bytes.length || bytes[at] !== 255) {
|
|
3176
|
+
return null;
|
|
3177
|
+
}
|
|
3178
|
+
const marker = bytes[at + 1] ?? 0;
|
|
3179
|
+
if (marker === 255) {
|
|
3180
|
+
at += 1;
|
|
3181
|
+
continue;
|
|
3182
|
+
}
|
|
3183
|
+
if (marker === 0 || marker >= 2 && marker <= 191 || marker === 216 || marker === 217) {
|
|
3184
|
+
return null;
|
|
3185
|
+
}
|
|
3186
|
+
if (marker === 1 || marker >= 208 && marker <= 215) {
|
|
3187
|
+
kept.add([255, marker]);
|
|
3188
|
+
at += 2;
|
|
3189
|
+
continue;
|
|
3190
|
+
}
|
|
3191
|
+
if (at + 4 > bytes.length) {
|
|
3192
|
+
return null;
|
|
3193
|
+
}
|
|
3194
|
+
const length = numberAt(bytes, at + 2, 2);
|
|
3195
|
+
const end = at + 2 + length;
|
|
3196
|
+
if (length < 2 || end > bytes.length) {
|
|
3197
|
+
return null;
|
|
3198
|
+
}
|
|
3199
|
+
const payload = bytes.subarray(at + 4, end);
|
|
3200
|
+
if (marker === 224) {
|
|
3201
|
+
if (startsWith2(payload, JFIF) && payload.length >= 14) {
|
|
3202
|
+
kept.add([255, 224, 0, 16]);
|
|
3203
|
+
kept.add(payload.subarray(0, 12));
|
|
3204
|
+
kept.add([0, 0]);
|
|
3205
|
+
}
|
|
3206
|
+
} else if (marker === 225) {
|
|
3207
|
+
if (startsWith2(payload, EXIF_HEADER) && !orientationKept) {
|
|
3208
|
+
orientationKept = true;
|
|
3209
|
+
const orientation = exifOrientation(payload.subarray(EXIF_HEADER.length));
|
|
3210
|
+
if (orientation !== 1) {
|
|
3211
|
+
const exif = orientationOnly(orientation);
|
|
3212
|
+
kept.add([255, 225, ...bigEndian(EXIF_HEADER.length + exif.length + 2, 2)]);
|
|
3213
|
+
kept.add(EXIF_HEADER);
|
|
3214
|
+
kept.add(exif);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
} else if (marker === 226 && startsWith2(payload, ICC_PROFILE) || marker === 238 && startsWith2(payload, ADOBE) || // A frame, its tables, a scan, and their kin, JPEG-LS's frame and parameters among them.
|
|
3218
|
+
marker >= 192 && marker <= 207 && marker !== 200 || marker >= 218 && marker <= 223 || marker === 247 || marker === 248) {
|
|
3219
|
+
kept.add(bytes.subarray(at, end));
|
|
3220
|
+
}
|
|
3221
|
+
at = end;
|
|
3222
|
+
if (marker !== 218) {
|
|
3223
|
+
continue;
|
|
3224
|
+
}
|
|
3225
|
+
const scan = at;
|
|
3226
|
+
for (; ; ) {
|
|
3227
|
+
const next = bytes.indexOf(255, at);
|
|
3228
|
+
if (next === -1 || next + 1 >= bytes.length) {
|
|
3229
|
+
return null;
|
|
3230
|
+
}
|
|
3231
|
+
at = next;
|
|
3232
|
+
const after = bytes[at + 1] ?? 0;
|
|
3233
|
+
if (after !== 0 && after !== 255 && !(after >= 208 && after <= 215)) {
|
|
3234
|
+
break;
|
|
3235
|
+
}
|
|
3236
|
+
at += 1;
|
|
3237
|
+
}
|
|
3238
|
+
kept.add(bytes.subarray(scan, at));
|
|
3239
|
+
if (bytes[at + 1] === 217) {
|
|
3240
|
+
kept.add([255, 217]);
|
|
3241
|
+
return kept.bytes;
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
var JFIF = Uint8Array.of(74, 70, 73, 70, 0);
|
|
3246
|
+
var ICC_PROFILE = ascii2("ICC_PROFILE\0");
|
|
3247
|
+
var ADOBE = ascii2("Adobe");
|
|
3248
|
+
var PNG_DRAWING_CHUNKS = /* @__PURE__ */ new Set([
|
|
3249
|
+
"IHDR",
|
|
3250
|
+
"PLTE",
|
|
3251
|
+
"IDAT",
|
|
3252
|
+
"IEND",
|
|
3253
|
+
"tRNS",
|
|
3254
|
+
"cHRM",
|
|
3255
|
+
"gAMA",
|
|
3256
|
+
"iCCP",
|
|
3257
|
+
"sBIT",
|
|
3258
|
+
"sRGB",
|
|
3259
|
+
"cICP",
|
|
3260
|
+
"mDCV",
|
|
3261
|
+
"cLLI",
|
|
3262
|
+
"bKGD",
|
|
3263
|
+
"hIST",
|
|
3264
|
+
"pHYs",
|
|
3265
|
+
"sPLT",
|
|
3266
|
+
"acTL",
|
|
3267
|
+
"fcTL",
|
|
3268
|
+
"fdAT"
|
|
3269
|
+
]);
|
|
3270
|
+
function pngWithoutMetadata(bytes) {
|
|
3271
|
+
const kept = new Kept(bytes.length);
|
|
3272
|
+
kept.add(bytes.subarray(0, 8));
|
|
3273
|
+
let at = 8;
|
|
3274
|
+
let orientationKept = false;
|
|
3275
|
+
while (at + 12 <= bytes.length) {
|
|
3276
|
+
const length = numberAt(bytes, at, 4);
|
|
3277
|
+
const type = typeAt(bytes, at + 4);
|
|
3278
|
+
if (length > bytes.length - at - 12) {
|
|
3279
|
+
return null;
|
|
3280
|
+
}
|
|
3281
|
+
const end = at + 12 + length;
|
|
3282
|
+
if (PNG_DRAWING_CHUNKS.has(type)) {
|
|
3283
|
+
kept.add(bytes.subarray(at, end));
|
|
3284
|
+
} else if (type === "eXIf" && !orientationKept) {
|
|
3285
|
+
orientationKept = true;
|
|
3286
|
+
const orientation = exifOrientation(bytes.subarray(at + 8, at + 8 + length));
|
|
3287
|
+
if (orientation !== 1) {
|
|
3288
|
+
const data = new Uint8Array([...ascii2("eXIf"), ...orientationOnly(orientation)]);
|
|
3289
|
+
kept.add(bigEndian(data.length - 4, 4));
|
|
3290
|
+
kept.add(data);
|
|
3291
|
+
kept.add(bigEndian(crc32(data), 4));
|
|
3292
|
+
}
|
|
3293
|
+
}
|
|
3294
|
+
if (type === "IEND") {
|
|
3295
|
+
return kept.bytes;
|
|
3296
|
+
}
|
|
3297
|
+
at = end;
|
|
3298
|
+
}
|
|
3299
|
+
return null;
|
|
3300
|
+
}
|
|
3301
|
+
var GIF_PLAYING_APPLICATIONS = [
|
|
3302
|
+
"NETSCAPE2.0",
|
|
3303
|
+
"ANIMEXTS1.0",
|
|
3304
|
+
"ICCRGBG1012"
|
|
3305
|
+
].map(ascii2);
|
|
3306
|
+
function gifColourTable(packed) {
|
|
3307
|
+
return packed & 128 ? 3 << (packed & 7) + 1 : 0;
|
|
3308
|
+
}
|
|
3309
|
+
function gifWithoutMetadata(bytes) {
|
|
3310
|
+
const subBlocksEnd = (start) => {
|
|
3311
|
+
let at2 = start;
|
|
3312
|
+
while (at2 < bytes.length) {
|
|
3313
|
+
const size = bytes[at2] ?? 0;
|
|
3314
|
+
if (size === 0) {
|
|
3315
|
+
return at2 + 1;
|
|
3316
|
+
}
|
|
3317
|
+
at2 += 1 + size;
|
|
3318
|
+
}
|
|
3319
|
+
return null;
|
|
3320
|
+
};
|
|
3321
|
+
if (bytes.length < 13) {
|
|
3322
|
+
return null;
|
|
3323
|
+
}
|
|
3324
|
+
let at = 13 + gifColourTable(bytes[10] ?? 0);
|
|
3325
|
+
if (at > bytes.length) {
|
|
3326
|
+
return null;
|
|
3327
|
+
}
|
|
3328
|
+
const kept = new Kept(bytes.length);
|
|
3329
|
+
kept.add(bytes.subarray(0, at));
|
|
3330
|
+
while (at < bytes.length) {
|
|
3331
|
+
switch (bytes[at]) {
|
|
3332
|
+
case 44: {
|
|
3333
|
+
if (at + 10 > bytes.length) {
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
const data = at + 10 + gifColourTable(bytes[at + 9] ?? 0);
|
|
3337
|
+
const end = data < bytes.length ? subBlocksEnd(data + 1) : null;
|
|
3338
|
+
if (end === null) {
|
|
3339
|
+
return null;
|
|
3340
|
+
}
|
|
3341
|
+
kept.add(bytes.subarray(at, end));
|
|
3342
|
+
at = end;
|
|
3343
|
+
break;
|
|
3344
|
+
}
|
|
3345
|
+
case 33: {
|
|
3346
|
+
const end = at + 2 < bytes.length ? subBlocksEnd(at + 2) : null;
|
|
3347
|
+
if (end === null) {
|
|
3348
|
+
return null;
|
|
3349
|
+
}
|
|
3350
|
+
const label = bytes[at + 1];
|
|
3351
|
+
const plays = label === 255 && bytes[at + 2] === 11 && end >= at + 14 && GIF_PLAYING_APPLICATIONS.some((name) => startsWith2(bytes, name, at + 3));
|
|
3352
|
+
if (label === 249 || label === 1 || plays) {
|
|
3353
|
+
kept.add(bytes.subarray(at, end));
|
|
3354
|
+
}
|
|
3355
|
+
at = end;
|
|
3356
|
+
break;
|
|
3357
|
+
}
|
|
3358
|
+
case 59:
|
|
3359
|
+
kept.add([59]);
|
|
3360
|
+
return kept.bytes;
|
|
3361
|
+
default:
|
|
3362
|
+
return null;
|
|
3363
|
+
}
|
|
3364
|
+
}
|
|
3365
|
+
return null;
|
|
3366
|
+
}
|
|
3367
|
+
var WEBP_DRAWING_CHUNKS = /* @__PURE__ */ new Set([
|
|
3368
|
+
"VP8X",
|
|
3369
|
+
"ICCP",
|
|
3370
|
+
"ANIM",
|
|
3371
|
+
"ANMF",
|
|
3372
|
+
"ALPH",
|
|
3373
|
+
"VP8 ",
|
|
3374
|
+
"VP8L"
|
|
3375
|
+
]);
|
|
3376
|
+
function webpWithoutMetadata(bytes) {
|
|
3377
|
+
if (bytes.length < 12) {
|
|
3378
|
+
return null;
|
|
3379
|
+
}
|
|
3380
|
+
const end = 8 + numberAt(bytes, 4, 4, true);
|
|
3381
|
+
const chunks = end >= 12 && end <= bytes.length ? webpChunks(bytes.subarray(12, end)) : null;
|
|
3382
|
+
if (chunks === null || chunks.length === 0) {
|
|
3383
|
+
return null;
|
|
3384
|
+
}
|
|
3385
|
+
const kept = new Kept(chunks.length + 12);
|
|
3386
|
+
kept.add(ascii2("RIFF"));
|
|
3387
|
+
kept.add(littleEndian(chunks.length + 4, 4));
|
|
3388
|
+
kept.add(ascii2("WEBP"));
|
|
3389
|
+
kept.add(chunks);
|
|
3390
|
+
const image = kept.bytes;
|
|
3391
|
+
if (image.length > 20 && typeAt(image, 12) === "VP8X" && numberAt(image, 16, 4, true) > 0) {
|
|
3392
|
+
const exif = webpChunkTypes(image.subarray(12)).includes("EXIF");
|
|
3393
|
+
image[20] = (image[20] ?? 0) & ~12 | (exif ? 8 : 0);
|
|
3394
|
+
}
|
|
3395
|
+
return image;
|
|
3396
|
+
}
|
|
3397
|
+
function webpChunks(chunks) {
|
|
3398
|
+
const kept = new Kept(chunks.length);
|
|
3399
|
+
const frames = [];
|
|
3400
|
+
let end = chunks.length;
|
|
3401
|
+
let at = 0;
|
|
3402
|
+
let orientationKept = false;
|
|
3403
|
+
for (; ; ) {
|
|
3404
|
+
if (at >= end) {
|
|
3405
|
+
const frame = frames.pop();
|
|
3406
|
+
if (frame === void 0) {
|
|
3407
|
+
return kept.bytes;
|
|
3408
|
+
}
|
|
3409
|
+
kept.set(frame.size, littleEndian(kept.length - frame.size - 4, 4));
|
|
3410
|
+
at = frame.resume;
|
|
3411
|
+
end = frames.at(-1)?.end ?? chunks.length;
|
|
3412
|
+
continue;
|
|
3413
|
+
}
|
|
3414
|
+
if (end - at < 8) {
|
|
3415
|
+
return null;
|
|
3416
|
+
}
|
|
3417
|
+
const type = typeAt(chunks, at);
|
|
3418
|
+
const size = numberAt(chunks, at + 4, 4, true);
|
|
3419
|
+
if (size > end - at - 8) {
|
|
3420
|
+
return null;
|
|
3421
|
+
}
|
|
3422
|
+
const data = at + 8;
|
|
3423
|
+
at = Math.min(data + size + size % 2, end);
|
|
3424
|
+
if (type === "ANMF") {
|
|
3425
|
+
if (size < 16) {
|
|
3426
|
+
return null;
|
|
3427
|
+
}
|
|
3428
|
+
frames.push({ end: data + size, resume: at, size: kept.length + 4 });
|
|
3429
|
+
kept.add(chunks.subarray(data - 8, data + 16));
|
|
3430
|
+
at = data + 16;
|
|
3431
|
+
end = data + size;
|
|
3432
|
+
} else if (WEBP_DRAWING_CHUNKS.has(type)) {
|
|
3433
|
+
kept.add(chunks.subarray(data - 8, data + size));
|
|
3434
|
+
if (size % 2 === 1) {
|
|
3435
|
+
kept.add([0]);
|
|
3436
|
+
}
|
|
3437
|
+
} else if (type === "EXIF" && frames.length === 0 && !orientationKept) {
|
|
3438
|
+
orientationKept = true;
|
|
3439
|
+
const turned = exifOrientation(chunks.subarray(data, data + size));
|
|
3440
|
+
if (turned !== 1) {
|
|
3441
|
+
const exif = orientationOnly(turned);
|
|
3442
|
+
kept.add(ascii2(type));
|
|
3443
|
+
kept.add(littleEndian(exif.length, 4));
|
|
3444
|
+
kept.add(exif);
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
}
|
|
3448
|
+
}
|
|
3449
|
+
function webpChunkTypes(chunks) {
|
|
3450
|
+
const types = [];
|
|
3451
|
+
let at = 0;
|
|
3452
|
+
while (chunks.length - at >= 8) {
|
|
3453
|
+
types.push(typeAt(chunks, at));
|
|
3454
|
+
const size = numberAt(chunks, at + 4, 4, true);
|
|
3455
|
+
at += 8 + size + size % 2;
|
|
3456
|
+
}
|
|
3457
|
+
return types;
|
|
3458
|
+
}
|
|
3459
|
+
|
|
2979
3460
|
// packages/board-core/dist/moves.js
|
|
2980
3461
|
import { mkdir as mkdir4, rm as rm2 } from "node:fs/promises";
|
|
2981
3462
|
import path5 from "node:path";
|
|
@@ -3418,6 +3899,72 @@ function tokenUse(events, window, now) {
|
|
|
3418
3899
|
};
|
|
3419
3900
|
}
|
|
3420
3901
|
|
|
3902
|
+
// packages/board-core/dist/turn-counters.js
|
|
3903
|
+
var TOKEN_KINDS = ["input", "output", "cache_read", "cache_write"];
|
|
3904
|
+
var USAGE_FIELD = {
|
|
3905
|
+
input: "inputTokens",
|
|
3906
|
+
output: "outputTokens",
|
|
3907
|
+
cache_read: "cacheReadTokens",
|
|
3908
|
+
cache_write: "cacheWriteTokens"
|
|
3909
|
+
};
|
|
3910
|
+
var UNKNOWN_LABEL = "unknown";
|
|
3911
|
+
function byKey(entries) {
|
|
3912
|
+
return [...entries].toSorted(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([, series]) => series);
|
|
3913
|
+
}
|
|
3914
|
+
var TurnCounters = class {
|
|
3915
|
+
cliOf;
|
|
3916
|
+
tokens = /* @__PURE__ */ new Map();
|
|
3917
|
+
turns = /* @__PURE__ */ new Map();
|
|
3918
|
+
/**
|
|
3919
|
+
* `cliOf` names a citizen's CLI for an end logged before ends named theirs: a turn runs on the
|
|
3920
|
+
* CLI its citizen's record names, which nothing changes after the citizen is added.
|
|
3921
|
+
*/
|
|
3922
|
+
constructor(cliOf) {
|
|
3923
|
+
this.cliOf = cliOf;
|
|
3924
|
+
}
|
|
3925
|
+
/** Counts a turn's end, `turn.completed` or `turn.failed`, and passes over any other event. */
|
|
3926
|
+
add(event) {
|
|
3927
|
+
if (event.type !== "turn.completed" && event.type !== "turn.failed") {
|
|
3928
|
+
return;
|
|
3929
|
+
}
|
|
3930
|
+
const turn2 = TurnHistoryPayloadSchema.safeParse(event.payload);
|
|
3931
|
+
if (!turn2.success) {
|
|
3932
|
+
return;
|
|
3933
|
+
}
|
|
3934
|
+
const agent2 = event.actor;
|
|
3935
|
+
const outcome = event.type === "turn.failed" ? "failed" : "completed";
|
|
3936
|
+
const trigger = turn2.data.trigger;
|
|
3937
|
+
const counted = JSON.stringify([agent2, outcome, trigger]);
|
|
3938
|
+
this.turns.set(counted, {
|
|
3939
|
+
agent: agent2,
|
|
3940
|
+
outcome,
|
|
3941
|
+
trigger,
|
|
3942
|
+
turns: (this.turns.get(counted)?.turns ?? 0) + 1
|
|
3943
|
+
});
|
|
3944
|
+
const usage = turn2.data.usage;
|
|
3945
|
+
if (usage === void 0) {
|
|
3946
|
+
return;
|
|
3947
|
+
}
|
|
3948
|
+
const named = CliKindSchema.safeParse(event.payload["cli"]);
|
|
3949
|
+
const cli = (named.success ? named.data : this.cliOf(agent2)) ?? UNKNOWN_LABEL;
|
|
3950
|
+
const model = turn2.data.model ?? UNKNOWN_LABEL;
|
|
3951
|
+
for (const kind of TOKEN_KINDS) {
|
|
3952
|
+
const key = JSON.stringify([agent2, cli, model, kind]);
|
|
3953
|
+
this.tokens.set(key, {
|
|
3954
|
+
agent: agent2,
|
|
3955
|
+
cli,
|
|
3956
|
+
model,
|
|
3957
|
+
kind,
|
|
3958
|
+
tokens: (this.tokens.get(key)?.tokens ?? 0) + usage[USAGE_FIELD[kind]]
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3962
|
+
/** The counts so far, in an order that holds from one read to the next. */
|
|
3963
|
+
read() {
|
|
3964
|
+
return { tokens: byKey(this.tokens), turns: byKey(this.turns) };
|
|
3965
|
+
}
|
|
3966
|
+
};
|
|
3967
|
+
|
|
3421
3968
|
// packages/board-core/dist/mutex.js
|
|
3422
3969
|
var Mutex = class {
|
|
3423
3970
|
tail = Promise.resolve();
|
|
@@ -3777,6 +4324,7 @@ function hashToken(token) {
|
|
|
3777
4324
|
// packages/board-core/dist/board.js
|
|
3778
4325
|
var SYSTEM_ACTOR = { name: "board", role: USER_ROLE };
|
|
3779
4326
|
var CLOSING_ATTEMPTS = 3;
|
|
4327
|
+
var CHANNEL_POST_WAIT_MS = 24 * 36e5;
|
|
3780
4328
|
function ownTurn(actor, turn2) {
|
|
3781
4329
|
return turn2.agent === actor.name && turn2.scope === actor.scope && turn2.thread === actor.thread && turn2.channel === actor.channel && turn2.place === actor.place;
|
|
3782
4330
|
}
|
|
@@ -3900,8 +4448,10 @@ function plain(value) {
|
|
|
3900
4448
|
return "";
|
|
3901
4449
|
return JSON.stringify(value);
|
|
3902
4450
|
}
|
|
3903
|
-
|
|
3904
|
-
|
|
4451
|
+
var SENTENCE_END = /[.…?!]["'”’»)\]}*_]*$/u;
|
|
4452
|
+
function asSentence(text) {
|
|
4453
|
+
const trimmed = text.trim();
|
|
4454
|
+
return SENTENCE_END.test(trimmed) ? trimmed : `${trimmed}.`;
|
|
3905
4455
|
}
|
|
3906
4456
|
function skillSummary(data, body) {
|
|
3907
4457
|
const description = data["description"];
|
|
@@ -5089,10 +5639,13 @@ ${DASHBOARD_LINE}
|
|
|
5089
5639
|
* when it mentions the user, so the creator can put a wait on the user in; a post that asks the
|
|
5090
5640
|
* reader counts wherever it is. A closed thread counts for nothing: its conversation has ended,
|
|
5091
5641
|
* and a turn there could only read its posts and be refused a reply, while a wake queued before
|
|
5092
|
-
* it closed, as for a mention, still runs there.
|
|
5642
|
+
* it closed, as for a mention, still runs there. A top-level post in a project's channel, general
|
|
5643
|
+
* or a workstream's, counts only for a reader it asks until it is `channelPostWaitMs` old, and
|
|
5644
|
+
* then for every reader who has not read it, so a turn there for anything else reads it sooner.
|
|
5093
5645
|
*/
|
|
5094
|
-
async unreadByConversation(actor) {
|
|
5646
|
+
async unreadByConversation(actor, options = {}) {
|
|
5095
5647
|
const { cursors, upto } = await this.digestSnapshot(actor.name);
|
|
5648
|
+
const waited = this.now().getTime() - (options.channelPostWaitMs ?? CHANNEL_POST_WAIT_MS);
|
|
5096
5649
|
const counts = /* @__PURE__ */ new Map();
|
|
5097
5650
|
const threadCounts = /* @__PURE__ */ new Map();
|
|
5098
5651
|
const unscoped = { name: actor.name, role: actor.role };
|
|
@@ -5100,11 +5653,15 @@ ${DASHBOARD_LINE}
|
|
|
5100
5653
|
if (news === true || message.step !== void 0 || message.author === SYSTEM_ACTOR.name || message.notice?.kind === "knowledge") {
|
|
5101
5654
|
continue;
|
|
5102
5655
|
}
|
|
5103
|
-
const
|
|
5656
|
+
const project2 = parseChannelRef(message.channel).project;
|
|
5657
|
+
const posted = project2 ?? SOCIETY_SCOPE;
|
|
5104
5658
|
if (posted !== scope && scope !== SOCIETY_SCOPE) {
|
|
5105
5659
|
continue;
|
|
5106
5660
|
}
|
|
5107
5661
|
const thread2 = threadOfPart(part);
|
|
5662
|
+
if (thread2 === void 0 && project2 !== null && asked !== true && Date.parse(message.ts) > waited) {
|
|
5663
|
+
continue;
|
|
5664
|
+
}
|
|
5108
5665
|
if (thread2 !== void 0) {
|
|
5109
5666
|
let counted = threadCounts.get(thread2);
|
|
5110
5667
|
if (counted === void 0) {
|
|
@@ -5485,7 +6042,7 @@ ${current.body}`);
|
|
|
5485
6042
|
name: args.name,
|
|
5486
6043
|
reason: args.reason
|
|
5487
6044
|
});
|
|
5488
|
-
await this.appendMessage(SYSTEM_ACTOR.name, "general", `Skill ${args.name} removed from the society by ${actor.name}: ${
|
|
6045
|
+
await this.appendMessage(SYSTEM_ACTOR.name, "general", `Skill ${args.name} removed from the society by ${actor.name}: ${asSentence(withoutMentions(args.reason))} Every citizen's skills index stops listing it from its next turn.`);
|
|
5489
6046
|
return removed;
|
|
5490
6047
|
});
|
|
5491
6048
|
}
|
|
@@ -5528,9 +6085,9 @@ ${current.body}`);
|
|
|
5528
6085
|
/**
|
|
5529
6086
|
* Keeps an image a citizen's turn names by its path, read on the runner the turn runs on, which
|
|
5530
6087
|
* refuses a file outside the turn's worktree, the citizen's home, and the system temp folder.
|
|
5531
|
-
* Only
|
|
5532
|
-
*
|
|
5533
|
-
* mirrors
|
|
6088
|
+
* Only a PNG, JPEG, GIF, or WebP of at most `IMAGE_LIMIT_BYTES` is kept, checked here again
|
|
6089
|
+
* whatever the runner said, without its metadata, under a new id outside the projection, so no
|
|
6090
|
+
* runner mirrors it and no prompt carries it: a post shows the image by its `image:` address.
|
|
5534
6091
|
*/
|
|
5535
6092
|
async uploadImage(actor, input) {
|
|
5536
6093
|
const args = VerbInputs.upload_image.parse(input);
|
|
@@ -5556,8 +6113,13 @@ ${current.body}`);
|
|
|
5556
6113
|
}
|
|
5557
6114
|
/**
|
|
5558
6115
|
* Keeps `bytes` under a new id when they are a PNG, JPEG, GIF, or WebP of at most
|
|
5559
|
-
* `IMAGE_LIMIT_BYTES
|
|
5560
|
-
* names the image in a refusal.
|
|
6116
|
+
* `IMAGE_LIMIT_BYTES` that reads to its end, without its metadata (`withoutMetadata`), and
|
|
6117
|
+
* answers the markdown that shows it, described by `name`. `what` names the image in a refusal.
|
|
6118
|
+
* The limit is for the bytes as they came, as the route's body cap measures them, and bounds
|
|
6119
|
+
* what is read; what is kept is checked against it too, since an orientation written smaller
|
|
6120
|
+
* than the board writes it grows by a few bytes. The runner, the web's composer, and the app
|
|
6121
|
+
* strip an image before they send it, and stripping it again changes nothing, but an older
|
|
6122
|
+
* runner, page, or app sends one as it was.
|
|
5561
6123
|
*/
|
|
5562
6124
|
async keepImage(actor, bytes, what, name) {
|
|
5563
6125
|
const type = imageTypeOf(bytes);
|
|
@@ -5567,19 +6129,26 @@ ${current.body}`);
|
|
|
5567
6129
|
if (bytes.byteLength > IMAGE_LIMIT_BYTES) {
|
|
5568
6130
|
throw new BoardError("VALIDATION", `${what} is ${bytes.byteLength} bytes, over the ${IMAGE_LIMIT_BYTES} an image may be`);
|
|
5569
6131
|
}
|
|
6132
|
+
const kept = withoutMetadata(bytes);
|
|
6133
|
+
if (kept === null) {
|
|
6134
|
+
throw new BoardError("VALIDATION", `${what} does not read to its end as a ${IMAGE_KIND_NAMES[type]}, so its metadata cannot be told from its picture; save it again and send that copy`);
|
|
6135
|
+
}
|
|
6136
|
+
if (kept.byteLength > IMAGE_LIMIT_BYTES) {
|
|
6137
|
+
throw new BoardError("VALIDATION", `${what} is ${kept.byteLength} bytes without its metadata, over the ${IMAGE_LIMIT_BYTES} an image may be`);
|
|
6138
|
+
}
|
|
5570
6139
|
return this.mutex.run(async () => {
|
|
5571
6140
|
const id = this.newId();
|
|
5572
|
-
await writeFileAtomic(this.paths.image(id),
|
|
6141
|
+
await writeFileAtomic(this.paths.image(id), kept);
|
|
5573
6142
|
await this.events.append("image.uploaded", actor.name, {
|
|
5574
6143
|
id,
|
|
5575
6144
|
type,
|
|
5576
|
-
size:
|
|
6145
|
+
size: kept.byteLength
|
|
5577
6146
|
});
|
|
5578
6147
|
const description = imageDescription(name);
|
|
5579
6148
|
return {
|
|
5580
6149
|
id,
|
|
5581
6150
|
type,
|
|
5582
|
-
size:
|
|
6151
|
+
size: kept.byteLength,
|
|
5583
6152
|
markdown: ``
|
|
5584
6153
|
};
|
|
5585
6154
|
});
|
|
@@ -6555,7 +7124,7 @@ ${args.summary}`);
|
|
|
6555
7124
|
});
|
|
6556
7125
|
const thread2 = await this.openThreadUnlocked(actor.name, this.proposalThreadOpening(proposal2));
|
|
6557
7126
|
const rationale = args.rationale.trim();
|
|
6558
|
-
await this.appendThreadMessage(actor.name, thread2.id, `Proposal ${proposal2.id}: ${describeCharter(proposal2.kind, proposal2.charter)}
|
|
7127
|
+
await this.appendThreadMessage(actor.name, thread2.id, `Proposal ${proposal2.id}: ${asSentence(describeCharter(proposal2.kind, proposal2.charter))}${rationale.length === 0 ? "" : `
|
|
6559
7128
|
|
|
6560
7129
|
${rationale}`}`);
|
|
6561
7130
|
return proposal2;
|
|
@@ -6880,6 +7449,39 @@ ${rationale}`}`);
|
|
|
6880
7449
|
const events = await this.events.readSince(null, Number.MAX_SAFE_INTEGER);
|
|
6881
7450
|
return tokenUse(events, window, this.now());
|
|
6882
7451
|
}
|
|
7452
|
+
/**
|
|
7453
|
+
* Every finished turn counted for Prometheus: seeded once from the whole event log, then moved
|
|
7454
|
+
* by each turn's end this process appends, so reading the counts never reads the log. The server
|
|
7455
|
+
* logs every turn's end itself; one another process appended would count from the next seed.
|
|
7456
|
+
*/
|
|
7457
|
+
async countTurns() {
|
|
7458
|
+
const clis = /* @__PURE__ */ new Map();
|
|
7459
|
+
const counters = new TurnCounters((agent2) => clis.get(agent2) ?? null);
|
|
7460
|
+
let waiting = [];
|
|
7461
|
+
this.events.onAppend((event) => {
|
|
7462
|
+
if (waiting === null) {
|
|
7463
|
+
counters.add(event);
|
|
7464
|
+
} else {
|
|
7465
|
+
waiting.push(event);
|
|
7466
|
+
}
|
|
7467
|
+
});
|
|
7468
|
+
const events = await this.events.readSince(null, Number.MAX_SAFE_INTEGER);
|
|
7469
|
+
for (const agent2 of await this.listAgents()) {
|
|
7470
|
+
clis.set(agent2.name, agent2.cli);
|
|
7471
|
+
}
|
|
7472
|
+
const seen = /* @__PURE__ */ new Set();
|
|
7473
|
+
for (const event of events) {
|
|
7474
|
+
seen.add(event.id);
|
|
7475
|
+
counters.add(event);
|
|
7476
|
+
}
|
|
7477
|
+
for (const event of waiting) {
|
|
7478
|
+
if (!seen.has(event.id)) {
|
|
7479
|
+
counters.add(event);
|
|
7480
|
+
}
|
|
7481
|
+
}
|
|
7482
|
+
waiting = null;
|
|
7483
|
+
return counters;
|
|
7484
|
+
}
|
|
6883
7485
|
/** The board actions a finished turn took, from its transcript; null when it kept none. */
|
|
6884
7486
|
async turnActions(agent2, turnId) {
|
|
6885
7487
|
const known = this.actionCounts.get(turnId);
|
|
@@ -7077,6 +7679,7 @@ ${rationale}`}`);
|
|
|
7077
7679
|
trigger: parsed.trigger.kind,
|
|
7078
7680
|
...parsed.trigger.heartbeat === void 0 ? {} : { heartbeat: parsed.trigger.heartbeat },
|
|
7079
7681
|
session: parsed.session,
|
|
7682
|
+
cli: parsed.cli,
|
|
7080
7683
|
exitReason: parsed.exitReason,
|
|
7081
7684
|
costUsd: parsed.costUsd,
|
|
7082
7685
|
...parsed.usage === null ? {} : { usage: parsed.usage },
|
|
@@ -7259,7 +7862,7 @@ ${rationale}`}`);
|
|
|
7259
7862
|
const ts = this.now().toISOString();
|
|
7260
7863
|
const landed = current.onDone !== "none";
|
|
7261
7864
|
if (landed) {
|
|
7262
|
-
await this.postTaskNote(actor.name, current, input.ok ?
|
|
7865
|
+
await this.postTaskNote(actor.name, current, input.ok ? asSentence(input.detail) : `Landing failed: ${asSentence(input.detail)} The task waits at its last stage for its participants to reshape the plan.`, input.ok ? { action: "landed", stage: current.stage, to: null } : { action: "reopened", stage: current.stage, to: current.stage });
|
|
7263
7866
|
}
|
|
7264
7867
|
if (input.ok) {
|
|
7265
7868
|
const task3 = await this.writeEndedTask(actor.name, location.project, {
|
|
@@ -7279,7 +7882,7 @@ ${rationale}`}`);
|
|
|
7279
7882
|
await this.refreshMember(name);
|
|
7280
7883
|
}
|
|
7281
7884
|
if (landed) {
|
|
7282
|
-
await this.appendMessage(actor.name, channelRef(location.project, task3.channel), `Task ${task3.id} "${task3.title}" is done: ${
|
|
7885
|
+
await this.appendMessage(actor.name, channelRef(location.project, task3.channel), `Task ${task3.id} "${task3.title}" is done: ${asSentence(input.detail)}`);
|
|
7283
7886
|
}
|
|
7284
7887
|
return task3;
|
|
7285
7888
|
}
|
|
@@ -7990,7 +8593,7 @@ Short, curated, loaded on every turn. Keep entries that change future behavior a
|
|
|
7990
8593
|
files: taken.files.length,
|
|
7991
8594
|
...meta
|
|
7992
8595
|
});
|
|
7993
|
-
await this.appendMessage(SYSTEM_ACTOR.name, "general", `Skill ${skill2.name} ${replaced ? "updated in" : "promoted to"} the society: ${
|
|
8596
|
+
await this.appendMessage(SYSTEM_ACTOR.name, "general", `Skill ${skill2.name} ${replaced ? "updated in" : "promoted to"} the society: ${asSentence(skill2.summary)} Every citizen's skills index now lists it.`);
|
|
7994
8597
|
return replaced;
|
|
7995
8598
|
}
|
|
7996
8599
|
/**
|
|
@@ -8237,7 +8840,7 @@ Short, curated, loaded on every turn. Keep entries that change future behavior a
|
|
|
8237
8840
|
});
|
|
8238
8841
|
const purpose = withoutMentions(input.purpose);
|
|
8239
8842
|
await this.appendMessage(SYSTEM_ACTOR.name, ref, `Channel ${ref} opened: ${purpose}`);
|
|
8240
|
-
await this.appendMessage(SYSTEM_ACTOR.name, channelRef(input.project, "general"), `Channel ${ref} opened by ${by}: ${purpose}
|
|
8843
|
+
await this.appendMessage(SYSTEM_ACTOR.name, channelRef(input.project, "general"), `Channel ${ref} opened by ${by}: ${asSentence(purpose)} Subscribe to it to follow its posts; its tasks and mentions reach whoever they concern either way.`);
|
|
8241
8844
|
return ref;
|
|
8242
8845
|
}
|
|
8243
8846
|
/**
|
|
@@ -8660,17 +9263,18 @@ ${charter.purpose}
|
|
|
8660
9263
|
return kept > lease ? new Date(kept).toISOString() : null;
|
|
8661
9264
|
}
|
|
8662
9265
|
/**
|
|
8663
|
-
* The lease a holder keeps while the user's pause holds its turns in the
|
|
8664
|
-
* (`heldOn`), when later than the one it has, else null. It is renewed for a full
|
|
8665
|
-
* than half is left, as for a pending cron, so it never lapses while the holder
|
|
8666
|
-
* turn there, and after the resume the holder has at least half a
|
|
9266
|
+
* The lease a holder keeps while the user's pause, or its CLI's limit, holds its turns in the
|
|
9267
|
+
* task's project (`heldOn`), when later than the one it has, else null. It is renewed for a full
|
|
9268
|
+
* lease once less than half is left, as for a pending cron, so it never lapses while the holder
|
|
9269
|
+
* cannot take a turn there, and after the resume or the reset the holder has at least half a
|
|
9270
|
+
* lease to come back to it.
|
|
8667
9271
|
*/
|
|
8668
9272
|
async pausedLease(task2, runners, runner2, now) {
|
|
8669
9273
|
if (task2.claimedBy === void 0 || task2.leaseExpiresAt === void 0) {
|
|
8670
9274
|
return null;
|
|
8671
9275
|
}
|
|
8672
9276
|
const holder = await this.readAgent(task2.claimedBy).catch(() => null);
|
|
8673
|
-
if (holder === null || !heldOn(runners, runner2, holder.cli)) {
|
|
9277
|
+
if (holder === null || !heldOn(runners, runner2, holder.cli, now)) {
|
|
8674
9278
|
return null;
|
|
8675
9279
|
}
|
|
8676
9280
|
const lease = Date.parse(task2.leaseExpiresAt);
|
|
@@ -8761,9 +9365,9 @@ ${charter.purpose}
|
|
|
8761
9365
|
});
|
|
8762
9366
|
}
|
|
8763
9367
|
const verdict = outcome === "approved" ? "Approved" : "Rejected";
|
|
8764
|
-
const why = reason === void 0 ? "" : ` Reason: ${reason}
|
|
9368
|
+
const why = reason === void 0 ? "" : ` Reason: ${asSentence(reason)}`;
|
|
8765
9369
|
const result = provision === void 0 ? "" : ` Provisioned: ${Object.entries(provision).map(([key, value]) => `${key} ${plain(value)}`).join(", ")}.`;
|
|
8766
|
-
const post = `${verdict}: ${describeCharter(proposal2.kind, proposal2.charter)}
|
|
9370
|
+
const post = `${verdict}: ${asSentence(describeCharter(proposal2.kind, proposal2.charter))}${why}${result}`;
|
|
8767
9371
|
await this.appendThreadMessage(actor.name, thread2.id, actor.name === SYSTEM_ACTOR.name ? withoutMentions(post) : post, { step: { action: outcome } });
|
|
8768
9372
|
await this.endThreadOf(proposalId, actor.name, outcome);
|
|
8769
9373
|
return decision;
|
|
@@ -9040,7 +9644,11 @@ runner.command("add <name>").description("Register a runner and print its token
|
|
|
9040
9644
|
runner.command("list").description("List runners and what they offer").action(async () => {
|
|
9041
9645
|
const board = await open3();
|
|
9042
9646
|
const runners = await board.listRunners();
|
|
9043
|
-
|
|
9647
|
+
const now = /* @__PURE__ */ new Date();
|
|
9648
|
+
print(runners, () => runners.length === 0 ? "No runners yet; add one with `runner add <name>`." : runners.map((each) => `${each.name} ${each.status}${each.paused === void 0 ? "" : " paused"} ${each.os}${each.version === void 0 ? "" : ` v${each.version}`} ${each.clis.join(",") || "no CLIs yet"}${each.capabilities.length === 0 ? "" : ` ${each.capabilities.join(",")}`}${Object.keys(each.pausedClis ?? {}).map((cli) => ` ${cli} paused`).join("")}${each.clis.map((cli) => {
|
|
9649
|
+
const hold = runnerLimitHold(each, cli, now);
|
|
9650
|
+
return hold === null ? "" : ` ${cli} held until ${hold.until}`;
|
|
9651
|
+
}).join("")}`).join("\n"));
|
|
9044
9652
|
});
|
|
9045
9653
|
for (const [verb, paused] of [
|
|
9046
9654
|
["pause", true],
|