@kubitnodes/stellaris 0.3.22 → 0.3.23
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/README.md +4 -4
- package/dist/cli/index.js +556 -413
- package/dist/server/index.js +666 -473
- package/package.json +1 -1
- package/web/dist/assets/BackLink-DGYs80bb.js +1 -0
- package/web/dist/assets/{Button-Yoe21NQ2.js → Button-f4jgBZY1.js} +1 -1
- package/web/dist/assets/{ChannelForms-55otlg-m.js → ChannelForms-q9zdj4p2.js} +1 -1
- package/web/dist/assets/{ChannelView-DJvLzg0N.js → ChannelView-CGs_aWL3.js} +2 -2
- package/web/dist/assets/{CitizenView-m1K2aTvK.js → CitizenView-gcIo_sKt.js} +2 -2
- package/web/dist/assets/CitizensView-DZ7S8vnJ.js +1 -0
- package/web/dist/assets/{CliIcon-DbMYJdlU.js → CliIcon-CLHaA65A.js} +1 -1
- package/web/dist/assets/{CronsView-B4kXk5Ld.js → CronsView-1wns6Uwv.js} +1 -1
- package/web/dist/assets/{KnowledgeView-aSGxDDKy.js → KnowledgeView-Cxfi2-Pt.js} +1 -1
- package/web/dist/assets/Markdown-BhtIFcWc.js +30 -0
- package/web/dist/assets/MessageItem-Bk9eBp1U.js +1 -0
- package/web/dist/assets/MetricsView-CTEH6rJn.js +1 -0
- package/web/dist/assets/NeedsYouView-2VNqH2Sb.js +1 -0
- package/web/dist/assets/{Overview-BveU1yJj.js → Overview-CS9HCSmm.js} +1 -1
- package/web/dist/assets/{Pane-CLjdfBMM.js → Pane-CJYRVkwh.js} +1 -1
- package/web/dist/assets/{Picker-CXOe5Xdu.js → Picker-DoxCN6C7.js} +1 -1
- package/web/dist/assets/{ProjectView-oa4Z46ED.js → ProjectView-CJ3r4UdN.js} +1 -1
- package/web/dist/assets/ProposalView-DLn9dNPp.js +2 -0
- package/web/dist/assets/{ProposalsView-BZHivSEm.js → ProposalsView-B-cOxTsQ.js} +1 -1
- package/web/dist/assets/{Quota-BC7dpnwd.js → Quota-Bo7UdWTV.js} +1 -1
- package/web/dist/assets/{RunnersView-BrJF-aLU.js → RunnersView-DlQruhwp.js} +1 -1
- package/web/dist/assets/{SocietyView-C1yosPuf.js → SocietyView-Bl4ErnV8.js} +1 -1
- package/web/dist/assets/{StickyList-7tAlUDCN.js → StickyList-MVP34ytV.js} +1 -1
- package/web/dist/assets/{SubjectThread-CCq6ZAnR.js → SubjectThread-BFFnHxIF.js} +1 -1
- package/web/dist/assets/{TaskFileView-BEXQJQQ6.js → TaskFileView-GZ0eQFUb.js} +2 -2
- package/web/dist/assets/{TaskView-Cfhb7NuO.js → TaskView-DppFelLW.js} +2 -2
- package/web/dist/assets/{TasksView-3XljXcoi.js → TasksView-DDNXzeG4.js} +1 -1
- package/web/dist/assets/{ThreadForms-D2y5dXSC.js → ThreadForms-C846TvtS.js} +1 -1
- package/web/dist/assets/{ThreadItem-DeIhhmyu.js → ThreadItem-C8cou6wD.js} +1 -1
- package/web/dist/assets/{ThreadView-CbUnt9WL.js → ThreadView-DvSGDYoD.js} +1 -1
- package/web/dist/assets/{citizen--bqux6i_.js → citizen-B2Dlbcpe.js} +1 -1
- package/web/dist/assets/{compose-DNc3_c5x.js → compose-BmqQmcZH.js} +1 -1
- package/web/dist/assets/{format-B6fjC0_a.js → format-DT52SbbR.js} +1 -1
- package/web/dist/assets/{governance-RBQ4Lam0.js → governance-Cr5OlQnw.js} +1 -1
- package/web/dist/assets/index-BTVy_xFF.js +23 -0
- package/web/dist/assets/index-DzV6CCnG.css +2 -0
- package/web/dist/assets/{mentions-B2Qchd_6.js → mentions-D5hNgtg6.js} +1 -1
- package/web/dist/assets/{tasks-DCUj5w_d.js → tasks-R3YgpYTe.js} +1 -1
- package/web/dist/assets/useMatch-pEF6RJ6Q.js +1 -0
- package/web/dist/index.html +9 -9
- package/web/dist/assets/BackLink-CD-iuy-h.js +0 -1
- package/web/dist/assets/CitizensView-BeTgmrKE.js +0 -1
- package/web/dist/assets/Markdown-c9bCCLHg.js +0 -30
- package/web/dist/assets/MessageItem-DKJKMqs-.js +0 -1
- package/web/dist/assets/MetricsView-D2TTry5O.js +0 -1
- package/web/dist/assets/NeedsYouView-C3celRei.js +0 -1
- package/web/dist/assets/ProposalView-B4T-EoX9.js +0 -2
- package/web/dist/assets/index-CyCty7a2.js +0 -23
- package/web/dist/assets/index-GRqxKN35.css +0 -2
- package/web/dist/assets/useMatch-CfbBQirn.js +0 -1
package/dist/server/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { serve } from "@hono/node-server";
|
|
|
9
9
|
import { chmod as chmod2, cp, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, rename as rename3, rm as rm2, stat as stat3, writeFile as writeFile4 } from "node:fs/promises";
|
|
10
10
|
import path6 from "node:path";
|
|
11
11
|
import { decodeTime, monotonicFactory } from "ulid";
|
|
12
|
-
import { z as
|
|
12
|
+
import { z as z16 } from "zod";
|
|
13
13
|
|
|
14
14
|
// packages/shared/dist/ids.js
|
|
15
15
|
import { z } from "zod";
|
|
@@ -64,7 +64,8 @@ var VERB_NAMES = [
|
|
|
64
64
|
"create_cron",
|
|
65
65
|
"update_cron",
|
|
66
66
|
"remove_cron",
|
|
67
|
-
"remove_skill"
|
|
67
|
+
"remove_skill",
|
|
68
|
+
"upload_image"
|
|
68
69
|
];
|
|
69
70
|
var VerbNameSchema = z2.enum(VERB_NAMES);
|
|
70
71
|
var CharterTriggerSchema = z2.enum(["user_post", "ops_event", "heartbeat"]);
|
|
@@ -93,6 +94,7 @@ var USER_ROLE = "user";
|
|
|
93
94
|
var USER_NAME = "user";
|
|
94
95
|
var MEMBER_VERBS = [
|
|
95
96
|
"post_message",
|
|
97
|
+
"upload_image",
|
|
96
98
|
"read_inbox",
|
|
97
99
|
"search",
|
|
98
100
|
"open_thread",
|
|
@@ -1037,130 +1039,175 @@ var DecisionSchema = z5.object({
|
|
|
1037
1039
|
});
|
|
1038
1040
|
|
|
1039
1041
|
// packages/shared/dist/verbs.js
|
|
1042
|
+
import { z as z7 } from "zod";
|
|
1043
|
+
|
|
1044
|
+
// packages/shared/dist/images.js
|
|
1040
1045
|
import { z as z6 } from "zod";
|
|
1041
|
-
var
|
|
1042
|
-
var
|
|
1043
|
-
var
|
|
1046
|
+
var IMAGE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1047
|
+
var ImageTypeSchema = z6.enum(["png", "jpeg", "gif", "webp"]);
|
|
1048
|
+
var IMAGE_MEDIA_TYPES = {
|
|
1049
|
+
png: "image/png",
|
|
1050
|
+
jpeg: "image/jpeg",
|
|
1051
|
+
gif: "image/gif",
|
|
1052
|
+
webp: "image/webp"
|
|
1053
|
+
};
|
|
1054
|
+
function startsWith(bytes, prefix, at = 0) {
|
|
1055
|
+
for (let index = 0; index < prefix.length; index += 1) {
|
|
1056
|
+
if (bytes[at + index] !== prefix[index]) {
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
return true;
|
|
1061
|
+
}
|
|
1062
|
+
var ascii = (text) => new TextEncoder().encode(text);
|
|
1063
|
+
function imageTypeOf(bytes) {
|
|
1064
|
+
if (startsWith(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
1065
|
+
return "png";
|
|
1066
|
+
}
|
|
1067
|
+
if (startsWith(bytes, [255, 216, 255])) {
|
|
1068
|
+
return "jpeg";
|
|
1069
|
+
}
|
|
1070
|
+
if (startsWith(bytes, ascii("GIF87a")) || startsWith(bytes, ascii("GIF89a"))) {
|
|
1071
|
+
return "gif";
|
|
1072
|
+
}
|
|
1073
|
+
if (startsWith(bytes, ascii("RIFF")) && startsWith(bytes, ascii("WEBP"), 8)) {
|
|
1074
|
+
return "webp";
|
|
1075
|
+
}
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
var ImagePathSchema = z6.string().min(1).max(4096).refine((value) => !value.includes("\0"), { message: "a path with no NUL character" });
|
|
1079
|
+
var IMAGE_SCHEME = "image:";
|
|
1080
|
+
var UploadedImageSchema = z6.object({
|
|
1081
|
+
id: UlidSchema,
|
|
1082
|
+
type: ImageTypeSchema,
|
|
1083
|
+
size: z6.number().int().positive(),
|
|
1084
|
+
markdown: z6.string()
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
// packages/shared/dist/verbs.js
|
|
1088
|
+
var MomentSchema = z7.iso.datetime({ offset: true });
|
|
1089
|
+
var CronTitleSchema = z7.string().trim().min(1).max(120);
|
|
1090
|
+
var CronNoteSchema = z7.string().trim().min(1).max(4e3);
|
|
1044
1091
|
var VerbInputs = {
|
|
1045
|
-
post_message:
|
|
1092
|
+
post_message: z7.object({
|
|
1046
1093
|
/** Required outside a thread; in one it may be left out, and must otherwise be the thread's. */
|
|
1047
1094
|
channel: ChannelRefSchema.optional(),
|
|
1048
|
-
body:
|
|
1095
|
+
body: z7.string().min(1),
|
|
1049
1096
|
thread_id: UlidSchema.optional()
|
|
1050
1097
|
}),
|
|
1051
|
-
read_inbox:
|
|
1098
|
+
read_inbox: z7.object({
|
|
1052
1099
|
since_cursor: UlidSchema.nullable().optional(),
|
|
1053
|
-
limit:
|
|
1054
|
-
advance:
|
|
1100
|
+
limit: z7.number().int().positive().max(200).default(50),
|
|
1101
|
+
advance: z7.boolean().default(true)
|
|
1055
1102
|
}),
|
|
1056
|
-
search:
|
|
1057
|
-
query:
|
|
1103
|
+
search: z7.object({
|
|
1104
|
+
query: z7.string().min(1),
|
|
1058
1105
|
project: NameSchema.optional(),
|
|
1059
1106
|
channel: ChannelRefSchema.optional(),
|
|
1060
|
-
limit:
|
|
1107
|
+
limit: z7.number().int().positive().max(100).default(20)
|
|
1061
1108
|
}),
|
|
1062
1109
|
/** On a task or a proposal, whose id the thread takes, or on a channel with a title. */
|
|
1063
|
-
open_thread:
|
|
1110
|
+
open_thread: z7.object({
|
|
1064
1111
|
task_id: UlidSchema.optional(),
|
|
1065
1112
|
proposal_id: UlidSchema.optional(),
|
|
1066
1113
|
channel: ChannelRefSchema.optional(),
|
|
1067
|
-
title:
|
|
1114
|
+
title: z7.string().min(1).max(200).optional()
|
|
1068
1115
|
}),
|
|
1069
|
-
close_thread:
|
|
1070
|
-
create_task:
|
|
1116
|
+
close_thread: z7.object({ thread_id: UlidSchema, summary: z7.string().min(1) }),
|
|
1117
|
+
create_task: z7.object({
|
|
1071
1118
|
project: NameSchema,
|
|
1072
|
-
title:
|
|
1073
|
-
body:
|
|
1119
|
+
title: z7.string().min(1).max(200),
|
|
1120
|
+
body: z7.string().default(""),
|
|
1074
1121
|
parent_id: UlidSchema.optional(),
|
|
1075
|
-
required_capabilities:
|
|
1122
|
+
required_capabilities: z7.array(z7.string()).default([]),
|
|
1076
1123
|
/** The plan; without it the task gets one stage, work, that anyone in the project may take. */
|
|
1077
|
-
stages:
|
|
1124
|
+
stages: z7.array(PlanStageSchema).min(1).optional(),
|
|
1078
1125
|
/** A channel of the project the task belongs to, such as a release's; its thread opens there. */
|
|
1079
1126
|
channel: NameSchema.default("general")
|
|
1080
1127
|
}),
|
|
1081
|
-
claim_task:
|
|
1082
|
-
release_task:
|
|
1083
|
-
update_task:
|
|
1128
|
+
claim_task: z7.object({ task_id: UlidSchema }),
|
|
1129
|
+
release_task: z7.object({ task_id: UlidSchema }),
|
|
1130
|
+
update_task: z7.object({
|
|
1084
1131
|
task_id: UlidSchema,
|
|
1085
1132
|
/** Move the task back to this earlier stage. */
|
|
1086
1133
|
stage: StageIdSchema.optional(),
|
|
1087
|
-
status:
|
|
1134
|
+
status: z7.enum(["abandoned"]).optional(),
|
|
1088
1135
|
/** Posted to the task's thread as the caller, marked with the step when the task moved. */
|
|
1089
|
-
note:
|
|
1090
|
-
blocked_by:
|
|
1136
|
+
note: z7.string().min(1).optional(),
|
|
1137
|
+
blocked_by: z7.array(UlidSchema).optional(),
|
|
1091
1138
|
/**
|
|
1092
1139
|
* The pull request a `ghpr` task lands through, on its project's repository, with the merge
|
|
1093
1140
|
* commit's subject and body; null unlinks it.
|
|
1094
1141
|
*/
|
|
1095
|
-
pull_request:
|
|
1142
|
+
pull_request: z7.object({
|
|
1096
1143
|
url: PullRequestUrlSchema,
|
|
1097
1144
|
merge_subject: MergeSubjectSchema.optional(),
|
|
1098
|
-
merge_body:
|
|
1145
|
+
merge_body: z7.string().max(2e4).optional()
|
|
1099
1146
|
}).nullable().optional()
|
|
1100
1147
|
}),
|
|
1101
|
-
get_task:
|
|
1102
|
-
subscribe:
|
|
1103
|
-
unsubscribe:
|
|
1104
|
-
propose:
|
|
1148
|
+
get_task: z7.object({ task_id: UlidSchema }),
|
|
1149
|
+
subscribe: z7.object({ channel: ChannelRefSchema }),
|
|
1150
|
+
unsubscribe: z7.object({ channel: ChannelRefSchema }),
|
|
1151
|
+
propose: z7.object({
|
|
1105
1152
|
kind: ProposalKindSchema,
|
|
1106
|
-
charter:
|
|
1107
|
-
rationale:
|
|
1153
|
+
charter: z7.record(z7.string(), z7.unknown()),
|
|
1154
|
+
rationale: z7.string().default("")
|
|
1108
1155
|
}),
|
|
1109
|
-
approve:
|
|
1110
|
-
reject:
|
|
1111
|
-
create_project:
|
|
1156
|
+
approve: z7.object({ proposal_id: UlidSchema, reason: z7.string().optional() }),
|
|
1157
|
+
reject: z7.object({ proposal_id: UlidSchema, reason: z7.string().min(1) }),
|
|
1158
|
+
create_project: z7.object({
|
|
1112
1159
|
slug: NameSchema,
|
|
1113
|
-
name:
|
|
1114
|
-
repo:
|
|
1160
|
+
name: z7.string().min(1).optional(),
|
|
1161
|
+
repo: z7.string().min(1).nullable().default(null),
|
|
1115
1162
|
default_branch: DefaultBranchSchema.default("main"),
|
|
1116
1163
|
on_done: CompletionEffectSchema.optional()
|
|
1117
1164
|
}),
|
|
1118
|
-
join_project:
|
|
1119
|
-
leave_project:
|
|
1120
|
-
write_knowledge:
|
|
1165
|
+
join_project: z7.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1166
|
+
leave_project: z7.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1167
|
+
write_knowledge: z7.object({
|
|
1121
1168
|
/** A project you belong to, or null for society knowledge, which the steward and the user curate. */
|
|
1122
1169
|
project: NameSchema.nullable().default(null),
|
|
1123
1170
|
topic: NameSchema,
|
|
1124
|
-
body:
|
|
1171
|
+
body: z7.string().min(1),
|
|
1125
1172
|
/** The `revision` in the frontmatter of the topic you read, 0 when it names none or for a new topic. */
|
|
1126
|
-
revision:
|
|
1173
|
+
revision: z7.number().int().min(0)
|
|
1127
1174
|
}),
|
|
1128
|
-
remove_knowledge:
|
|
1175
|
+
remove_knowledge: z7.object({
|
|
1129
1176
|
/** As for write_knowledge: a project you belong to, or null for society knowledge. */
|
|
1130
1177
|
project: NameSchema.nullable().default(null),
|
|
1131
1178
|
topic: NameSchema
|
|
1132
1179
|
}),
|
|
1133
|
-
plan_task:
|
|
1180
|
+
plan_task: z7.object({
|
|
1134
1181
|
task_id: UlidSchema,
|
|
1135
|
-
stages:
|
|
1182
|
+
stages: z7.array(PlanEditStageSchema),
|
|
1136
1183
|
on_done: CompletionEffectSchema.optional()
|
|
1137
1184
|
}),
|
|
1138
1185
|
/** The note is posted to the task's thread as the caller, marked with the step. */
|
|
1139
|
-
advance_task:
|
|
1140
|
-
configure_project:
|
|
1186
|
+
advance_task: z7.object({ task_id: UlidSchema, note: z7.string().min(1).optional() }),
|
|
1187
|
+
configure_project: z7.object({
|
|
1141
1188
|
project: NameSchema,
|
|
1142
1189
|
on_done: CompletionEffectSchema.optional(),
|
|
1143
1190
|
/** A new display name; the slug, which everything refers to the project by, never changes. */
|
|
1144
|
-
name:
|
|
1191
|
+
name: z7.string().trim().min(1).max(120).optional(),
|
|
1145
1192
|
/** The branch tasks start from and land on from now; tasks in play keep their branches. */
|
|
1146
1193
|
default_branch: DefaultBranchSchema.optional()
|
|
1147
1194
|
}),
|
|
1148
|
-
archive_project:
|
|
1149
|
-
create_channel:
|
|
1195
|
+
archive_project: z7.object({ project: NameSchema, reason: z7.string().min(1) }),
|
|
1196
|
+
create_channel: z7.object({
|
|
1150
1197
|
/** A project, or null for a channel of the society. */
|
|
1151
1198
|
project: NameSchema.nullable().default(null),
|
|
1152
1199
|
name: NameSchema,
|
|
1153
|
-
purpose:
|
|
1200
|
+
purpose: z7.string().min(1)
|
|
1154
1201
|
}),
|
|
1155
|
-
archive_channel:
|
|
1156
|
-
update_dashboard:
|
|
1202
|
+
archive_channel: z7.object({ channel: ChannelRefSchema, reason: z7.string().min(1) }),
|
|
1203
|
+
update_dashboard: z7.object({
|
|
1157
1204
|
project: NameSchema,
|
|
1158
1205
|
/** The whole dashboard as markdown; the board keeps its frontmatter. */
|
|
1159
|
-
body:
|
|
1206
|
+
body: z7.string().min(1),
|
|
1160
1207
|
/** The `revision` in the frontmatter of the dashboard you read, 0 when it names none. */
|
|
1161
|
-
revision:
|
|
1208
|
+
revision: z7.number().int().min(0)
|
|
1162
1209
|
}),
|
|
1163
|
-
create_cron:
|
|
1210
|
+
create_cron: z7.object({
|
|
1164
1211
|
title: CronTitleSchema,
|
|
1165
1212
|
/** What to do when it fires; quoted in the prompt of every turn it starts. */
|
|
1166
1213
|
note: CronNoteSchema,
|
|
@@ -1179,10 +1226,10 @@ var VerbInputs = {
|
|
|
1179
1226
|
/** An open channel of that place other than general, whose conversation it fires in. */
|
|
1180
1227
|
channel: NameSchema.optional()
|
|
1181
1228
|
}),
|
|
1182
|
-
update_cron:
|
|
1229
|
+
update_cron: z7.object({
|
|
1183
1230
|
cron_id: UlidSchema,
|
|
1184
1231
|
/** Pause it, or resume it, which starts its schedule afresh from now. */
|
|
1185
|
-
paused:
|
|
1232
|
+
paused: z7.boolean().optional(),
|
|
1186
1233
|
title: CronTitleSchema.optional(),
|
|
1187
1234
|
note: CronNoteSchema.optional(),
|
|
1188
1235
|
/** A new expression, or `at` for one time; either starts the schedule afresh. */
|
|
@@ -1191,8 +1238,12 @@ var VerbInputs = {
|
|
|
1191
1238
|
timezone: TimeZoneSchema.nullable().optional(),
|
|
1192
1239
|
at: MomentSchema.optional()
|
|
1193
1240
|
}),
|
|
1194
|
-
remove_cron:
|
|
1195
|
-
remove_skill:
|
|
1241
|
+
remove_cron: z7.object({ cron_id: UlidSchema, reason: z7.string().trim().min(1) }),
|
|
1242
|
+
remove_skill: z7.object({ name: NameSchema, reason: z7.string().trim().min(1) }),
|
|
1243
|
+
upload_image: z7.object({
|
|
1244
|
+
/** The image file on the machine your turn runs on: absolute, or relative to your working directory. */
|
|
1245
|
+
path: ImagePathSchema
|
|
1246
|
+
})
|
|
1196
1247
|
};
|
|
1197
1248
|
var VERB_DESCRIPTIONS = {
|
|
1198
1249
|
post_message: "Post a markdown message to a channel, or into a thread when thread_id is given; a thread's message goes to the thread's channel.",
|
|
@@ -1203,7 +1254,7 @@ var VERB_DESCRIPTIONS = {
|
|
|
1203
1254
|
create_task: "Create a task in a project with its plan: stages of {name, role or agent, gate}. Without stages it gets one stage, work, that anyone in the project may take. File it in a channel of the project, such as a release's, or general by default; its thread opens there with it, under the task's id, for everything said about the work.",
|
|
1204
1255
|
claim_task: "Hold the task's current stage. Claims are leases renewed by every turn that touches the task.",
|
|
1205
1256
|
release_task: "Let go of the stage you hold so someone else can take it.",
|
|
1206
|
-
update_task: "Move a task back to an earlier stage, abandon it, set the tasks it is blocked by (blocked_by: its stage wakes nobody until they have all ended), or link its pull request (pull_request: url, with the merge commit's merge_subject and merge_body), which a ghpr task needs before its last stage completes. A note is posted to the task's thread.",
|
|
1257
|
+
update_task: "Move a task back to an earlier stage (the current stage's holder, the user, the steward, or the concierge; anyone else asks the concierge in the task's thread), abandon it, set the tasks it is blocked by (blocked_by: its stage wakes nobody until they have all ended), or link its pull request (pull_request: url, with the merge commit's merge_subject and merge_body), which a ghpr task needs before its last stage completes. A note is posted to the task's thread.",
|
|
1207
1258
|
get_task: "Read a task with its plan, its brief, and the messages of its thread.",
|
|
1208
1259
|
subscribe: "Subscribe to a channel. Subscriptions feed your digest; they never wake you.",
|
|
1209
1260
|
unsubscribe: "Unsubscribe from a channel.",
|
|
@@ -1225,11 +1276,12 @@ var VERB_DESCRIPTIONS = {
|
|
|
1225
1276
|
create_cron: "Set a cron that wakes you later: a title, a note on what to do then, and either cron, a five-field expression (minute hour day-of-month month day-of-week) read in timezone or the society's, or at, one time. It fires in this turn's conversation unless you name a project, thread_id, or channel, at most every 15 minutes, and every fire is a turn. Only the user, the steward, and the concierge set one that wakes another citizen (agent).",
|
|
1226
1277
|
update_cron: "Pause or resume a cron, or change its title, note, or schedule; resuming or rescheduling starts it afresh from now. Yours, or anyone's for the user, the steward, and the concierge.",
|
|
1227
1278
|
remove_cron: "End a cron for good, with a reason. Yours, or anyone's for the user, the steward, and the concierge. A cron also ends with its conversation, and a one-time cron once it fires.",
|
|
1228
|
-
remove_skill: "Remove a skill from the society's skills, with a reason, when it is wrong, superseded, or no longer used: no skills index lists it from the next turn, and a notice in general says so with the reason. Its proposer's own copy stays in its home. Steward and user only; the board keeps its text aside for the user to restore."
|
|
1279
|
+
remove_skill: "Remove a skill from the society's skills, with a reason, when it is wrong, superseded, or no longer used: no skills index lists it from the next turn, and a notice in general says so with the reason. Its proposer's own copy stays in its home. Steward and user only; the board keeps its text aside for the user to restore.",
|
|
1280
|
+
upload_image: "Upload an image file, such as a screenshot or a chart, from the machine your turn runs on: a PNG, JPEG, GIF, or WebP of at most 8 MB, in your worktree, your home, or the system temp folder. Returns its id and the markdown that shows it in a post, ``; write what it shows as the alt text."
|
|
1229
1281
|
};
|
|
1230
1282
|
|
|
1231
1283
|
// packages/shared/dist/events.js
|
|
1232
|
-
import { z as
|
|
1284
|
+
import { z as z8 } from "zod";
|
|
1233
1285
|
var BOARD_EVENT_TYPES = [
|
|
1234
1286
|
"society.initialized",
|
|
1235
1287
|
"project.added",
|
|
@@ -1293,21 +1345,22 @@ var BOARD_EVENT_TYPES = [
|
|
|
1293
1345
|
"cron.updated",
|
|
1294
1346
|
"cron.fired",
|
|
1295
1347
|
"cron.skipped",
|
|
1296
|
-
"cron.ended"
|
|
1348
|
+
"cron.ended",
|
|
1349
|
+
"image.uploaded"
|
|
1297
1350
|
];
|
|
1298
|
-
var BoardEventTypeSchema =
|
|
1299
|
-
var BoardEventSchema =
|
|
1351
|
+
var BoardEventTypeSchema = z8.enum(BOARD_EVENT_TYPES);
|
|
1352
|
+
var BoardEventSchema = z8.object({
|
|
1300
1353
|
id: UlidSchema,
|
|
1301
1354
|
ts: IsoDateTimeSchema,
|
|
1302
1355
|
type: BoardEventTypeSchema,
|
|
1303
1356
|
actor: NameSchema,
|
|
1304
|
-
payload:
|
|
1357
|
+
payload: z8.record(z8.string(), z8.unknown())
|
|
1305
1358
|
});
|
|
1306
|
-
var UsageSchema =
|
|
1307
|
-
inputTokens:
|
|
1308
|
-
outputTokens:
|
|
1309
|
-
cacheReadTokens:
|
|
1310
|
-
cacheWriteTokens:
|
|
1359
|
+
var UsageSchema = z8.object({
|
|
1360
|
+
inputTokens: z8.number().int().nonnegative(),
|
|
1361
|
+
outputTokens: z8.number().int().nonnegative(),
|
|
1362
|
+
cacheReadTokens: z8.number().int().nonnegative().default(0),
|
|
1363
|
+
cacheWriteTokens: z8.number().int().nonnegative().default(0)
|
|
1311
1364
|
});
|
|
1312
1365
|
function addUsage(a, b) {
|
|
1313
1366
|
return {
|
|
@@ -1317,14 +1370,14 @@ function addUsage(a, b) {
|
|
|
1317
1370
|
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens
|
|
1318
1371
|
};
|
|
1319
1372
|
}
|
|
1320
|
-
var TurnStatusSchema =
|
|
1321
|
-
summary:
|
|
1322
|
-
claimsHeld:
|
|
1323
|
-
blockedOn:
|
|
1324
|
-
needsUserDecision:
|
|
1325
|
-
memoryUpdated:
|
|
1373
|
+
var TurnStatusSchema = z8.object({
|
|
1374
|
+
summary: z8.string().min(1),
|
|
1375
|
+
claimsHeld: z8.array(UlidSchema).default([]),
|
|
1376
|
+
blockedOn: z8.array(z8.string()).default([]),
|
|
1377
|
+
needsUserDecision: z8.boolean().default(false),
|
|
1378
|
+
memoryUpdated: z8.boolean().default(false)
|
|
1326
1379
|
});
|
|
1327
|
-
var TurnExitReasonSchema =
|
|
1380
|
+
var TurnExitReasonSchema = z8.enum([
|
|
1328
1381
|
"completed",
|
|
1329
1382
|
"timeout",
|
|
1330
1383
|
"error",
|
|
@@ -1332,50 +1385,50 @@ var TurnExitReasonSchema = z7.enum([
|
|
|
1332
1385
|
"blocked",
|
|
1333
1386
|
"stopped"
|
|
1334
1387
|
]);
|
|
1335
|
-
var AgentEventSchema =
|
|
1336
|
-
|
|
1337
|
-
type:
|
|
1388
|
+
var AgentEventSchema = z8.discriminatedUnion("type", [
|
|
1389
|
+
z8.object({
|
|
1390
|
+
type: z8.literal("turn_started"),
|
|
1338
1391
|
agent: NameSchema,
|
|
1339
|
-
session:
|
|
1392
|
+
session: z8.string(),
|
|
1340
1393
|
runner: NameSchema,
|
|
1341
1394
|
/** The model the CLI reports running, when it reports one. */
|
|
1342
|
-
model:
|
|
1395
|
+
model: z8.string().optional()
|
|
1343
1396
|
}),
|
|
1344
1397
|
/**
|
|
1345
1398
|
* The CLI took a steer into the running turn. Adapters name the steer; the server adds the
|
|
1346
1399
|
* messages it delivered and the text the CLI was given.
|
|
1347
1400
|
*/
|
|
1348
|
-
|
|
1349
|
-
type:
|
|
1350
|
-
steer:
|
|
1351
|
-
messages:
|
|
1352
|
-
text:
|
|
1401
|
+
z8.object({
|
|
1402
|
+
type: z8.literal("steered"),
|
|
1403
|
+
steer: z8.string().min(1),
|
|
1404
|
+
messages: z8.array(UlidSchema).optional(),
|
|
1405
|
+
text: z8.string().optional()
|
|
1353
1406
|
}),
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
type:
|
|
1358
|
-
name:
|
|
1359
|
-
ok:
|
|
1407
|
+
z8.object({ type: z8.literal("text"), delta: z8.string() }),
|
|
1408
|
+
z8.object({ type: z8.literal("tool_call"), name: z8.string(), input: z8.unknown() }),
|
|
1409
|
+
z8.object({
|
|
1410
|
+
type: z8.literal("tool_result"),
|
|
1411
|
+
name: z8.string(),
|
|
1412
|
+
ok: z8.boolean(),
|
|
1360
1413
|
/** What the tool returned, cut to `OUTPUT_LIMIT` characters by `capOutput`. */
|
|
1361
|
-
output:
|
|
1414
|
+
output: z8.string().optional()
|
|
1362
1415
|
}),
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
type:
|
|
1416
|
+
z8.object({ type: z8.literal("approval_requested"), kind: z8.string(), detail: z8.unknown() }),
|
|
1417
|
+
z8.object({
|
|
1418
|
+
type: z8.literal("turn_completed"),
|
|
1366
1419
|
usage: UsageSchema,
|
|
1367
|
-
costUsd:
|
|
1420
|
+
costUsd: z8.number().nonnegative(),
|
|
1368
1421
|
status: TurnStatusSchema.nullable(),
|
|
1369
1422
|
exitReason: TurnExitReasonSchema
|
|
1370
1423
|
}),
|
|
1371
|
-
|
|
1424
|
+
z8.object({ type: z8.literal("error"), message: z8.string() })
|
|
1372
1425
|
]);
|
|
1373
|
-
var TranscriptEntrySchema =
|
|
1426
|
+
var TranscriptEntrySchema = z8.object({
|
|
1374
1427
|
ts: IsoDateTimeSchema,
|
|
1375
1428
|
event: AgentEventSchema
|
|
1376
1429
|
});
|
|
1377
|
-
var LiveTurnEventSchema =
|
|
1378
|
-
seq:
|
|
1430
|
+
var LiveTurnEventSchema = z8.object({
|
|
1431
|
+
seq: z8.number().int().positive(),
|
|
1379
1432
|
ts: IsoDateTimeSchema,
|
|
1380
1433
|
agent: NameSchema,
|
|
1381
1434
|
project: NameSchema,
|
|
@@ -1387,10 +1440,10 @@ var LiveTurnEventSchema = z7.object({
|
|
|
1387
1440
|
});
|
|
1388
1441
|
|
|
1389
1442
|
// packages/shared/dist/turns.js
|
|
1390
|
-
import { z as
|
|
1443
|
+
import { z as z10 } from "zod";
|
|
1391
1444
|
|
|
1392
1445
|
// packages/shared/dist/runner.js
|
|
1393
|
-
import { z as
|
|
1446
|
+
import { z as z9 } from "zod";
|
|
1394
1447
|
var RUNNER_PROTOCOL = 1;
|
|
1395
1448
|
var PATH_TOKENS = {
|
|
1396
1449
|
home: "{{stellaris:home}}",
|
|
@@ -1401,75 +1454,77 @@ var SERVER_TOKEN = "{{stellaris:server}}";
|
|
|
1401
1454
|
var WORKSPACE_TOKEN = "{{stellaris:workspace}}";
|
|
1402
1455
|
var HOME_SCRATCH = "scratch";
|
|
1403
1456
|
var HOME_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1404
|
-
var RunnerHelloSchema =
|
|
1405
|
-
protocol:
|
|
1406
|
-
version:
|
|
1457
|
+
var RunnerHelloSchema = z9.object({
|
|
1458
|
+
protocol: z9.number().int().positive(),
|
|
1459
|
+
version: z9.string().min(1),
|
|
1407
1460
|
os: RunnerOsSchema,
|
|
1408
|
-
clis:
|
|
1461
|
+
clis: z9.array(CliKindSchema),
|
|
1409
1462
|
/** The CLIs whose adapter can keep a session warm between turns. */
|
|
1410
|
-
residentClis:
|
|
1463
|
+
residentClis: z9.array(CliKindSchema).default([]),
|
|
1411
1464
|
/** The CLIs whose adapter can take input into a running turn; the server steers only these. */
|
|
1412
|
-
steerableClis:
|
|
1465
|
+
steerableClis: z9.array(CliKindSchema).default([]),
|
|
1413
1466
|
/** The CLIs whose adapter can stop a running turn; the server stops only these. */
|
|
1414
|
-
stoppableClis:
|
|
1467
|
+
stoppableClis: z9.array(CliKindSchema).default([]),
|
|
1415
1468
|
/** Whether the runner answers file reads on its projects' branches; one from before never does. */
|
|
1416
|
-
branchReads:
|
|
1469
|
+
branchReads: z9.boolean().default(false),
|
|
1417
1470
|
/** Whether the runner lists what a branch changed; one from before never does. */
|
|
1418
|
-
branchChanges:
|
|
1471
|
+
branchChanges: z9.boolean().default(false),
|
|
1419
1472
|
/** Whether the runner answers a read of a CLI's quota; one from before never does. */
|
|
1420
|
-
quotaReads:
|
|
1421
|
-
|
|
1473
|
+
quotaReads: z9.boolean().default(false),
|
|
1474
|
+
/** Whether the runner reads an image a turn running there uploads; one from before never does. */
|
|
1475
|
+
imageReads: z9.boolean().default(false),
|
|
1476
|
+
capabilities: z9.array(z9.string()).default([]),
|
|
1422
1477
|
/**
|
|
1423
1478
|
* What the runner's account lacks of the git identity citizens' own commits carry, checked
|
|
1424
1479
|
* before each hello outside any repository; empty when it has both. Absent from a runner from
|
|
1425
1480
|
* before the check, which no default fills in, so the board marks only what a runner reported.
|
|
1426
1481
|
*/
|
|
1427
|
-
gitIdentityMissing:
|
|
1482
|
+
gitIdentityMissing: z9.array(GitIdentityPartSchema).optional(),
|
|
1428
1483
|
/** Turns the runner runs at once, or null for no limit. */
|
|
1429
|
-
slots:
|
|
1484
|
+
slots: z9.number().int().positive().nullable(),
|
|
1430
1485
|
/** Turns the runner is still running, when it registers again; the server fails the rest of its turns. */
|
|
1431
|
-
turns:
|
|
1486
|
+
turns: z9.array(UlidSchema).default([])
|
|
1432
1487
|
});
|
|
1433
|
-
var RunnerWelcomeSchema =
|
|
1434
|
-
var RunnerEnrollRequestSchema =
|
|
1435
|
-
protocol:
|
|
1436
|
-
version:
|
|
1437
|
-
hostname:
|
|
1488
|
+
var RunnerWelcomeSchema = z9.object({ name: NameSchema, version: z9.string() });
|
|
1489
|
+
var RunnerEnrollRequestSchema = z9.object({
|
|
1490
|
+
protocol: z9.number().int().positive(),
|
|
1491
|
+
version: z9.string().min(1).max(64),
|
|
1492
|
+
hostname: z9.string().min(1).max(253),
|
|
1438
1493
|
os: RunnerOsSchema,
|
|
1439
|
-
clis:
|
|
1440
|
-
capabilities:
|
|
1494
|
+
clis: z9.array(CliKindSchema).max(8),
|
|
1495
|
+
capabilities: z9.array(z9.string().min(1).max(64)).max(32).default([])
|
|
1441
1496
|
});
|
|
1442
|
-
var RunnerEnrollmentSchema =
|
|
1443
|
-
deviceCode:
|
|
1444
|
-
userCode:
|
|
1497
|
+
var RunnerEnrollmentSchema = z9.object({
|
|
1498
|
+
deviceCode: z9.string().min(1),
|
|
1499
|
+
userCode: z9.string().min(1),
|
|
1445
1500
|
expiresAt: IsoDateTimeSchema,
|
|
1446
|
-
intervalMs:
|
|
1501
|
+
intervalMs: z9.number().int().positive()
|
|
1447
1502
|
});
|
|
1448
|
-
var RunnerEnrollPollSchema =
|
|
1449
|
-
var RunnerEnrollStatusSchema =
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1503
|
+
var RunnerEnrollPollSchema = z9.object({ deviceCode: z9.string().min(1) });
|
|
1504
|
+
var RunnerEnrollStatusSchema = z9.discriminatedUnion("status", [
|
|
1505
|
+
z9.object({ status: z9.literal("pending") }),
|
|
1506
|
+
z9.object({ status: z9.literal("approved"), name: NameSchema, token: z9.string().min(1) }),
|
|
1507
|
+
z9.object({ status: z9.literal("denied") })
|
|
1453
1508
|
]);
|
|
1454
|
-
var PendingEnrollmentSchema =
|
|
1455
|
-
userCode:
|
|
1456
|
-
hostname:
|
|
1509
|
+
var PendingEnrollmentSchema = z9.object({
|
|
1510
|
+
userCode: z9.string().min(1),
|
|
1511
|
+
hostname: z9.string(),
|
|
1457
1512
|
os: RunnerOsSchema,
|
|
1458
|
-
clis:
|
|
1459
|
-
capabilities:
|
|
1460
|
-
version:
|
|
1513
|
+
clis: z9.array(CliKindSchema),
|
|
1514
|
+
capabilities: z9.array(z9.string()),
|
|
1515
|
+
version: z9.string(),
|
|
1461
1516
|
requestedAt: IsoDateTimeSchema,
|
|
1462
1517
|
expiresAt: IsoDateTimeSchema
|
|
1463
1518
|
});
|
|
1464
|
-
var ProjectRepoSchema =
|
|
1519
|
+
var ProjectRepoSchema = z9.object({
|
|
1465
1520
|
slug: NameSchema,
|
|
1466
|
-
origin:
|
|
1467
|
-
defaultBranch:
|
|
1521
|
+
origin: z9.string().nullable(),
|
|
1522
|
+
defaultBranch: z9.string().min(1),
|
|
1468
1523
|
/**
|
|
1469
1524
|
* The board lands finished tasks on the default branch, itself or through their pull requests,
|
|
1470
1525
|
* so the runner lets nothing else move it.
|
|
1471
1526
|
*/
|
|
1472
|
-
boardLands:
|
|
1527
|
+
boardLands: z9.boolean()
|
|
1473
1528
|
});
|
|
1474
1529
|
function projectRepo(project) {
|
|
1475
1530
|
return {
|
|
@@ -1479,29 +1534,29 @@ function projectRepo(project) {
|
|
|
1479
1534
|
boardLands: project.onDone !== "none"
|
|
1480
1535
|
};
|
|
1481
1536
|
}
|
|
1482
|
-
var TurnWorkspaceSchema =
|
|
1483
|
-
|
|
1484
|
-
kind:
|
|
1537
|
+
var TurnWorkspaceSchema = z9.discriminatedUnion("kind", [
|
|
1538
|
+
z9.object({
|
|
1539
|
+
kind: z9.literal("home"),
|
|
1485
1540
|
thread: UlidSchema.optional(),
|
|
1486
1541
|
channel: NameSchema.optional()
|
|
1487
1542
|
}),
|
|
1488
|
-
|
|
1489
|
-
kind:
|
|
1543
|
+
z9.object({
|
|
1544
|
+
kind: z9.literal("project"),
|
|
1490
1545
|
repo: ProjectRepoSchema,
|
|
1491
|
-
branches:
|
|
1546
|
+
branches: z9.array(z9.string().min(1)),
|
|
1492
1547
|
thread: UlidSchema.optional(),
|
|
1493
1548
|
channel: NameSchema.optional()
|
|
1494
1549
|
}),
|
|
1495
|
-
|
|
1550
|
+
z9.object({ kind: z9.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
1496
1551
|
]);
|
|
1497
|
-
var TurnJobSchema =
|
|
1552
|
+
var TurnJobSchema = z9.object({
|
|
1498
1553
|
turnId: UlidSchema,
|
|
1499
1554
|
agent: NameSchema,
|
|
1500
1555
|
role: NameSchema,
|
|
1501
1556
|
cli: CliKindSchema,
|
|
1502
|
-
model:
|
|
1557
|
+
model: z9.string().optional(),
|
|
1503
1558
|
/** The reasoning effort set on the agent; absent for the model's own default. */
|
|
1504
|
-
effort:
|
|
1559
|
+
effort: z9.string().optional(),
|
|
1505
1560
|
/** A project slug, or the society scope. */
|
|
1506
1561
|
scope: NameSchema,
|
|
1507
1562
|
/** The thread whose conversation the turn is in; absent for the home conversation. */
|
|
@@ -1512,130 +1567,130 @@ var TurnJobSchema = z8.object({
|
|
|
1512
1567
|
* The session to resume, or null to start one: the CLI's adapter picks a fresh session's id, and
|
|
1513
1568
|
* the outcome reports it.
|
|
1514
1569
|
*/
|
|
1515
|
-
session:
|
|
1570
|
+
session: z9.string().min(1).nullable(),
|
|
1516
1571
|
/** The running total the session reported after its last turn, which a resumed session starts from. */
|
|
1517
|
-
costSoFarUsd:
|
|
1572
|
+
costSoFarUsd: z9.number().nonnegative(),
|
|
1518
1573
|
/** The rendered charter, norms, memory core, and skills index, with `PATH_TOKENS` for places. */
|
|
1519
|
-
instructions:
|
|
1520
|
-
prompt:
|
|
1521
|
-
mcp:
|
|
1522
|
-
limits:
|
|
1523
|
-
timeoutMs:
|
|
1524
|
-
maxTurns:
|
|
1574
|
+
instructions: z9.string(),
|
|
1575
|
+
prompt: z9.string(),
|
|
1576
|
+
mcp: z9.object({ url: z9.string().min(1), token: z9.string().min(1) }),
|
|
1577
|
+
limits: z9.object({
|
|
1578
|
+
timeoutMs: z9.number().int().positive().nullable(),
|
|
1579
|
+
maxTurns: z9.number().int().positive().nullable()
|
|
1525
1580
|
}),
|
|
1526
1581
|
/** Present when the runner keeps the conversation's session warm between turns, under `key`. */
|
|
1527
|
-
resident:
|
|
1582
|
+
resident: z9.object({ key: z9.string().min(1), idleMs: z9.number().int().positive() }).optional(),
|
|
1528
1583
|
workspace: TurnWorkspaceSchema
|
|
1529
1584
|
});
|
|
1530
|
-
var TurnWorkSchema =
|
|
1531
|
-
var TurnEventsSchema =
|
|
1532
|
-
var TurnOutcomeSchema =
|
|
1585
|
+
var TurnWorkSchema = z9.object({ branch: z9.string().min(1), head: z9.string().min(1) });
|
|
1586
|
+
var TurnEventsSchema = z9.object({ entries: z9.array(TranscriptEntrySchema) });
|
|
1587
|
+
var TurnOutcomeSchema = z9.object({
|
|
1533
1588
|
exitReason: TurnExitReasonSchema,
|
|
1534
1589
|
status: TurnStatusSchema.nullable(),
|
|
1535
|
-
error:
|
|
1590
|
+
error: z9.string().nullable(),
|
|
1536
1591
|
usage: UsageSchema,
|
|
1537
|
-
costUsd:
|
|
1592
|
+
costUsd: z9.number().nonnegative(),
|
|
1538
1593
|
/** The session's running total after this turn, for CLIs that report one. */
|
|
1539
|
-
sessionCostUsd:
|
|
1594
|
+
sessionCostUsd: z9.number().nonnegative().optional(),
|
|
1540
1595
|
/** The session the CLI used, which differs from the job's for CLIs that assign their own ids. */
|
|
1541
|
-
session:
|
|
1596
|
+
session: z9.string().min(1),
|
|
1542
1597
|
/** The model the CLI reported, when it reported one. */
|
|
1543
|
-
model:
|
|
1598
|
+
model: z9.string().nullable(),
|
|
1544
1599
|
work: TurnWorkSchema.nullable(),
|
|
1545
1600
|
/**
|
|
1546
1601
|
* Whether the turn's own workspace, a thread's, a channel's, or a task's, holds work on no
|
|
1547
1602
|
* branch after the hand-back: uncommitted changes, or commits no branch contains.
|
|
1548
1603
|
*/
|
|
1549
|
-
leftovers:
|
|
1604
|
+
leftovers: z9.boolean().default(false),
|
|
1550
1605
|
/**
|
|
1551
1606
|
* The CLI's plan quota as the turn's stream last reported it, when it reported any; a runner from
|
|
1552
1607
|
* before never sends it.
|
|
1553
1608
|
*/
|
|
1554
1609
|
quota: CliQuotaSchema.optional()
|
|
1555
1610
|
});
|
|
1556
|
-
var TurnAckSchema =
|
|
1557
|
-
var LandRequestSchema =
|
|
1611
|
+
var TurnAckSchema = z9.object({ dropWorkspace: z9.boolean() });
|
|
1612
|
+
var LandRequestSchema = z9.object({
|
|
1558
1613
|
repo: ProjectRepoSchema,
|
|
1559
|
-
branch:
|
|
1614
|
+
branch: z9.string().min(1),
|
|
1560
1615
|
/**
|
|
1561
1616
|
* For a `ghpr` task, the pull request to merge in place of the branch, which must hold the
|
|
1562
1617
|
* branch's files, and the merge commit's subject and body, the pull request's title and an
|
|
1563
1618
|
* empty body when left out.
|
|
1564
1619
|
*/
|
|
1565
|
-
pullRequest:
|
|
1566
|
-
url:
|
|
1567
|
-
subject:
|
|
1568
|
-
body:
|
|
1620
|
+
pullRequest: z9.object({
|
|
1621
|
+
url: z9.string().min(1),
|
|
1622
|
+
subject: z9.string().min(1).optional(),
|
|
1623
|
+
body: z9.string().optional()
|
|
1569
1624
|
}).optional()
|
|
1570
1625
|
});
|
|
1571
|
-
var CloseRequestSchema =
|
|
1626
|
+
var CloseRequestSchema = z9.object({
|
|
1572
1627
|
repo: ProjectRepoSchema,
|
|
1573
|
-
url:
|
|
1574
|
-
comment:
|
|
1628
|
+
url: z9.string().min(1),
|
|
1629
|
+
comment: z9.string().min(1)
|
|
1575
1630
|
});
|
|
1576
|
-
var MergeOutcomeSchema =
|
|
1577
|
-
var ModelListSchema =
|
|
1631
|
+
var MergeOutcomeSchema = z9.object({ ok: z9.boolean(), detail: z9.string() });
|
|
1632
|
+
var ModelListSchema = z9.array(ModelOptionSchema);
|
|
1578
1633
|
var BRANCH_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1579
|
-
var BranchPathSchema =
|
|
1580
|
-
var BranchNameSchema =
|
|
1581
|
-
var BranchReadSchema =
|
|
1634
|
+
var BranchPathSchema = z9.string().max(4096).refine((value) => value === "" || value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".." && !segment.includes("\0")), { message: "a path inside the branch, with no empty, `.`, or `..` segment" });
|
|
1635
|
+
var BranchNameSchema = z9.string().regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/);
|
|
1636
|
+
var BranchReadSchema = z9.object({
|
|
1582
1637
|
repo: ProjectRepoSchema,
|
|
1583
1638
|
branch: BranchNameSchema,
|
|
1584
1639
|
path: BranchPathSchema
|
|
1585
1640
|
});
|
|
1586
|
-
var BranchCommitSchema =
|
|
1587
|
-
id:
|
|
1641
|
+
var BranchCommitSchema = z9.object({
|
|
1642
|
+
id: z9.string().min(1),
|
|
1588
1643
|
at: IsoDateTimeSchema,
|
|
1589
|
-
author:
|
|
1644
|
+
author: z9.string()
|
|
1590
1645
|
});
|
|
1591
|
-
var BranchFileSchema =
|
|
1592
|
-
|
|
1593
|
-
kind:
|
|
1646
|
+
var BranchFileSchema = z9.discriminatedUnion("kind", [
|
|
1647
|
+
z9.object({
|
|
1648
|
+
kind: z9.literal("file"),
|
|
1594
1649
|
path: BranchPathSchema,
|
|
1595
1650
|
commit: BranchCommitSchema,
|
|
1596
|
-
size:
|
|
1597
|
-
content:
|
|
1651
|
+
size: z9.number().int().nonnegative(),
|
|
1652
|
+
content: z9.string().nullable()
|
|
1598
1653
|
}),
|
|
1599
|
-
|
|
1600
|
-
kind:
|
|
1654
|
+
z9.object({
|
|
1655
|
+
kind: z9.literal("dir"),
|
|
1601
1656
|
path: BranchPathSchema,
|
|
1602
1657
|
commit: BranchCommitSchema,
|
|
1603
|
-
entries:
|
|
1604
|
-
name:
|
|
1605
|
-
kind:
|
|
1606
|
-
size:
|
|
1658
|
+
entries: z9.array(z9.object({
|
|
1659
|
+
name: z9.string().min(1),
|
|
1660
|
+
kind: z9.enum(["file", "dir"]),
|
|
1661
|
+
size: z9.number().int().nonnegative().nullable()
|
|
1607
1662
|
}))
|
|
1608
1663
|
})
|
|
1609
1664
|
]);
|
|
1610
|
-
var BranchChangesReadSchema =
|
|
1665
|
+
var BranchChangesReadSchema = z9.object({
|
|
1611
1666
|
repo: ProjectRepoSchema,
|
|
1612
1667
|
branch: BranchNameSchema
|
|
1613
1668
|
});
|
|
1614
|
-
var BranchFileChangeSchema =
|
|
1615
|
-
path:
|
|
1616
|
-
status:
|
|
1669
|
+
var BranchFileChangeSchema = z9.object({
|
|
1670
|
+
path: z9.string().min(1),
|
|
1671
|
+
status: z9.enum(["added", "modified", "deleted"]),
|
|
1617
1672
|
/** Lines added and removed, or null for a binary file. */
|
|
1618
|
-
added:
|
|
1619
|
-
removed:
|
|
1673
|
+
added: z9.number().int().nonnegative().nullable(),
|
|
1674
|
+
removed: z9.number().int().nonnegative().nullable(),
|
|
1620
1675
|
/** Absent when the file changed only through a merge of another branch. */
|
|
1621
|
-
lastChange:
|
|
1676
|
+
lastChange: z9.object({ author: z9.string(), at: IsoDateTimeSchema }).optional()
|
|
1622
1677
|
});
|
|
1623
|
-
var BranchChangesSchema =
|
|
1678
|
+
var BranchChangesSchema = z9.object({
|
|
1624
1679
|
head: BranchCommitSchema,
|
|
1625
|
-
files:
|
|
1626
|
-
total:
|
|
1680
|
+
files: z9.array(BranchFileChangeSchema),
|
|
1681
|
+
total: z9.number().int().nonnegative()
|
|
1627
1682
|
});
|
|
1628
|
-
var BranchDiffReadSchema =
|
|
1683
|
+
var BranchDiffReadSchema = z9.object({
|
|
1629
1684
|
repo: ProjectRepoSchema,
|
|
1630
1685
|
branch: BranchNameSchema,
|
|
1631
1686
|
path: BranchPathSchema.min(1)
|
|
1632
1687
|
});
|
|
1633
|
-
var BranchFileDiffSchema =
|
|
1688
|
+
var BranchFileDiffSchema = z9.object({
|
|
1634
1689
|
head: BranchCommitSchema,
|
|
1635
1690
|
path: BranchPathSchema,
|
|
1636
1691
|
status: BranchFileChangeSchema.shape.status,
|
|
1637
|
-
patch:
|
|
1638
|
-
truncated:
|
|
1692
|
+
patch: z9.string().nullable(),
|
|
1693
|
+
truncated: z9.boolean()
|
|
1639
1694
|
});
|
|
1640
1695
|
function patchHunks(patch, limit2) {
|
|
1641
1696
|
if (/^Binary files .* differ$/m.test(patch)) {
|
|
@@ -1649,9 +1704,23 @@ function patchHunks(patch, limit2) {
|
|
|
1649
1704
|
const cut = hunks.lastIndexOf("\n", limit2);
|
|
1650
1705
|
return { patch: hunks.slice(0, cut === -1 ? limit2 : cut), truncated: true };
|
|
1651
1706
|
}
|
|
1652
|
-
var
|
|
1653
|
-
|
|
1654
|
-
|
|
1707
|
+
var TurnImageReadSchema = z9.object({
|
|
1708
|
+
turnId: UlidSchema,
|
|
1709
|
+
path: ImagePathSchema
|
|
1710
|
+
});
|
|
1711
|
+
var ImageRefusalSchema = z9.enum(["missing", "outside", "not_image", "too_big"]);
|
|
1712
|
+
var TurnImageSchema = z9.discriminatedUnion("kind", [
|
|
1713
|
+
z9.object({
|
|
1714
|
+
kind: z9.literal("image"),
|
|
1715
|
+
type: ImageTypeSchema,
|
|
1716
|
+
size: z9.number().int().positive(),
|
|
1717
|
+
content: z9.string()
|
|
1718
|
+
}),
|
|
1719
|
+
z9.object({ kind: z9.literal("refused"), why: ImageRefusalSchema, detail: z9.string() })
|
|
1720
|
+
]);
|
|
1721
|
+
var WorkspaceConversationSchema = z9.discriminatedUnion("kind", [
|
|
1722
|
+
z9.object({ kind: z9.literal("thread"), id: UlidSchema }),
|
|
1723
|
+
z9.object({ kind: z9.literal("channel"), scope: NameSchema, name: NameSchema })
|
|
1655
1724
|
]);
|
|
1656
1725
|
function workspaceConversationOf(turn) {
|
|
1657
1726
|
if (turn.thread !== void 0) {
|
|
@@ -1659,65 +1728,70 @@ function workspaceConversationOf(turn) {
|
|
|
1659
1728
|
}
|
|
1660
1729
|
return turn.channel === void 0 ? null : { kind: "channel", scope: turn.scope, name: turn.channel };
|
|
1661
1730
|
}
|
|
1662
|
-
var HeldWorkspaceSchema =
|
|
1731
|
+
var HeldWorkspaceSchema = z9.object({
|
|
1663
1732
|
agent: NameSchema,
|
|
1664
1733
|
scope: NameSchema,
|
|
1665
1734
|
conversation: WorkspaceConversationSchema
|
|
1666
1735
|
});
|
|
1667
|
-
var HeldWorkspacesSchema =
|
|
1668
|
-
var SweepResultSchema =
|
|
1669
|
-
var TurnSteerSchema =
|
|
1670
|
-
var RunnerMessageSchema =
|
|
1671
|
-
|
|
1672
|
-
|
|
1736
|
+
var HeldWorkspacesSchema = z9.object({ workspaces: z9.array(HeldWorkspaceSchema) });
|
|
1737
|
+
var SweepResultSchema = z9.object({ kept: z9.array(HeldWorkspaceSchema) });
|
|
1738
|
+
var TurnSteerSchema = z9.object({ id: z9.uuid(), text: z9.string().min(1) });
|
|
1739
|
+
var RunnerMessageSchema = z9.discriminatedUnion("type", [
|
|
1740
|
+
z9.object({ type: z9.literal("turn"), job: TurnJobSchema }),
|
|
1741
|
+
z9.object({ type: z9.literal("land"), request: z9.string().min(1), land: LandRequestSchema }),
|
|
1673
1742
|
/** Answered with a `MergeOutcome`. */
|
|
1674
|
-
|
|
1675
|
-
|
|
1743
|
+
z9.object({ type: z9.literal("close"), request: z9.string().min(1), close: CloseRequestSchema }),
|
|
1744
|
+
z9.object({ type: z9.literal("models"), request: z9.string().min(1), cli: CliKindSchema }),
|
|
1676
1745
|
/**
|
|
1677
1746
|
* Answered with a `CliQuota` read from the CLI without a turn, or null when its adapter cannot
|
|
1678
1747
|
* read one. Sent only to runners whose hello says `quotaReads`.
|
|
1679
1748
|
*/
|
|
1680
|
-
|
|
1749
|
+
z9.object({ type: z9.literal("quota"), request: z9.string().min(1), cli: CliKindSchema }),
|
|
1681
1750
|
/** Answered with a `BranchFile`, or null when the branch or the path does not exist. */
|
|
1682
|
-
|
|
1751
|
+
z9.object({ type: z9.literal("file"), request: z9.string().min(1), read: BranchReadSchema }),
|
|
1683
1752
|
/** Answered with `BranchChanges`, or null when the repository or the branch does not exist. */
|
|
1684
|
-
|
|
1685
|
-
type:
|
|
1686
|
-
request:
|
|
1753
|
+
z9.object({
|
|
1754
|
+
type: z9.literal("changes"),
|
|
1755
|
+
request: z9.string().min(1),
|
|
1687
1756
|
read: BranchChangesReadSchema
|
|
1688
1757
|
}),
|
|
1689
1758
|
/** Answered with a `BranchFileDiff`, or null when the branch does not exist or left the path alone. */
|
|
1690
|
-
|
|
1759
|
+
z9.object({ type: z9.literal("diff"), request: z9.string().min(1), read: BranchDiffReadSchema }),
|
|
1760
|
+
/**
|
|
1761
|
+
* Answered with a `TurnImage`, or null when the turn is not running there. Sent only to runners
|
|
1762
|
+
* whose hello says `imageReads`.
|
|
1763
|
+
*/
|
|
1764
|
+
z9.object({ type: z9.literal("image"), request: z9.string().min(1), read: TurnImageReadSchema }),
|
|
1691
1765
|
/** Answered with whether the CLI accepted it; that it took it comes as a `steered` event. */
|
|
1692
|
-
|
|
1693
|
-
type:
|
|
1694
|
-
request:
|
|
1766
|
+
z9.object({
|
|
1767
|
+
type: z9.literal("steer"),
|
|
1768
|
+
request: z9.string().min(1),
|
|
1695
1769
|
turnId: UlidSchema,
|
|
1696
1770
|
steer: TurnSteerSchema
|
|
1697
1771
|
}),
|
|
1698
1772
|
/** Answered with whether the turn was there to stop; it ends `stopped`. */
|
|
1699
|
-
|
|
1773
|
+
z9.object({ type: z9.literal("stop"), request: z9.string().min(1), turnId: UlidSchema }),
|
|
1700
1774
|
/**
|
|
1701
1775
|
* A conversation ended: the runner removes every citizen's workspace for it but those a turn
|
|
1702
1776
|
* still uses, and answers with a `SweepResult` naming those it kept for holding work on no branch.
|
|
1703
1777
|
*/
|
|
1704
|
-
|
|
1705
|
-
type:
|
|
1706
|
-
request:
|
|
1778
|
+
z9.object({
|
|
1779
|
+
type: z9.literal("sweep"),
|
|
1780
|
+
request: z9.string().min(1),
|
|
1707
1781
|
conversation: WorkspaceConversationSchema
|
|
1708
1782
|
})
|
|
1709
1783
|
]);
|
|
1710
|
-
var RunnerAnswerSchema =
|
|
1711
|
-
|
|
1712
|
-
|
|
1784
|
+
var RunnerAnswerSchema = z9.discriminatedUnion("ok", [
|
|
1785
|
+
z9.object({ ok: z9.literal(true), value: z9.unknown() }),
|
|
1786
|
+
z9.object({ ok: z9.literal(false), error: z9.string() })
|
|
1713
1787
|
]);
|
|
1714
|
-
var WarmSessionsSchema =
|
|
1715
|
-
var FileManifestSchema =
|
|
1788
|
+
var WarmSessionsSchema = z9.object({ warm: z9.array(z9.string()) });
|
|
1789
|
+
var FileManifestSchema = z9.object({ files: z9.record(z9.string(), z9.string()) });
|
|
1716
1790
|
function fileVersion(sha, executable) {
|
|
1717
1791
|
return executable ? `${sha}+x` : sha;
|
|
1718
1792
|
}
|
|
1719
|
-
var FileReadSchema =
|
|
1720
|
-
var FileContentsSchema =
|
|
1793
|
+
var FileReadSchema = z9.object({ paths: z9.array(z9.string()) });
|
|
1794
|
+
var FileContentsSchema = z9.object({ files: z9.record(z9.string(), z9.string()) });
|
|
1721
1795
|
function isSafeRelativePath(file) {
|
|
1722
1796
|
if (file.length === 0 || file.startsWith("/") || file.includes("\\") || file.includes("\0")) {
|
|
1723
1797
|
return false;
|
|
@@ -1726,7 +1800,7 @@ function isSafeRelativePath(file) {
|
|
|
1726
1800
|
}
|
|
1727
1801
|
|
|
1728
1802
|
// packages/shared/dist/turns.js
|
|
1729
|
-
var TriggerKindSchema =
|
|
1803
|
+
var TriggerKindSchema = z10.enum([
|
|
1730
1804
|
"mention",
|
|
1731
1805
|
"stage",
|
|
1732
1806
|
"task_done",
|
|
@@ -1740,11 +1814,11 @@ var TriggerKindSchema = z9.enum([
|
|
|
1740
1814
|
"closing",
|
|
1741
1815
|
"cron"
|
|
1742
1816
|
]);
|
|
1743
|
-
var TriggerSchema =
|
|
1817
|
+
var TriggerSchema = z10.object({
|
|
1744
1818
|
kind: TriggerKindSchema,
|
|
1745
1819
|
from: NameSchema.optional(),
|
|
1746
|
-
fromUser:
|
|
1747
|
-
reason:
|
|
1820
|
+
fromUser: z10.boolean().default(false),
|
|
1821
|
+
reason: z10.string().default(""),
|
|
1748
1822
|
taskId: UlidSchema.optional(),
|
|
1749
1823
|
messageId: UlidSchema.optional(),
|
|
1750
1824
|
/** The channel the waking message was posted in. */
|
|
@@ -1752,17 +1826,17 @@ var TriggerSchema = z9.object({
|
|
|
1752
1826
|
/** The cron that came due, for a `cron` wake. */
|
|
1753
1827
|
cronId: UlidSchema.optional()
|
|
1754
1828
|
});
|
|
1755
|
-
var TurnThreadSchema =
|
|
1756
|
-
var TurnDispatchSchema =
|
|
1829
|
+
var TurnThreadSchema = z10.object({ id: UlidSchema, task: z10.boolean() });
|
|
1830
|
+
var TurnDispatchSchema = z10.object({
|
|
1757
1831
|
agent: NameSchema,
|
|
1758
1832
|
project: NameSchema,
|
|
1759
1833
|
thread: TurnThreadSchema.optional(),
|
|
1760
1834
|
channel: NameSchema.optional(),
|
|
1761
1835
|
trigger: TriggerSchema,
|
|
1762
|
-
priority:
|
|
1763
|
-
onboarding:
|
|
1836
|
+
priority: z10.number().int().min(0).max(2),
|
|
1837
|
+
onboarding: z10.boolean().default(false),
|
|
1764
1838
|
/** Every cron that came due for this turn, whatever wake it merged into; its prompt quotes each. */
|
|
1765
|
-
crons:
|
|
1839
|
+
crons: z10.array(UlidSchema).optional()
|
|
1766
1840
|
});
|
|
1767
1841
|
function conversationPart(conversation) {
|
|
1768
1842
|
return conversation.thread ?? (conversation.channel === void 0 ? void 0 : `#${conversation.channel}`);
|
|
@@ -1786,7 +1860,7 @@ function channelConversation(scope, channel) {
|
|
|
1786
1860
|
const name = at < 0 ? channel : channel.slice(at + 1);
|
|
1787
1861
|
return place === scope && name !== "general" ? name : void 0;
|
|
1788
1862
|
}
|
|
1789
|
-
var TurnRecordSchema =
|
|
1863
|
+
var TurnRecordSchema = z10.object({
|
|
1790
1864
|
/** Assigned by the board when the turn begins; the turn's transcript is filed under it. */
|
|
1791
1865
|
id: UlidSchema.optional(),
|
|
1792
1866
|
agent: NameSchema,
|
|
@@ -1797,31 +1871,31 @@ var TurnRecordSchema = z9.object({
|
|
|
1797
1871
|
channel: NameSchema.optional(),
|
|
1798
1872
|
runner: NameSchema,
|
|
1799
1873
|
cli: CliKindSchema.nullable(),
|
|
1800
|
-
session:
|
|
1874
|
+
session: z10.string().nullable(),
|
|
1801
1875
|
trigger: TriggerSchema,
|
|
1802
1876
|
startedAt: IsoDateTimeSchema,
|
|
1803
1877
|
endedAt: IsoDateTimeSchema.nullable(),
|
|
1804
1878
|
exitReason: TurnExitReasonSchema.nullable(),
|
|
1805
1879
|
status: TurnStatusSchema.nullable(),
|
|
1806
|
-
error:
|
|
1880
|
+
error: z10.string().nullable(),
|
|
1807
1881
|
usage: UsageSchema.nullable(),
|
|
1808
|
-
costUsd:
|
|
1882
|
+
costUsd: z10.number().nonnegative().default(0),
|
|
1809
1883
|
/**
|
|
1810
1884
|
* The running total the CLI reported for the session after this turn, when it reports one. A
|
|
1811
1885
|
* resumed session starts from it, so the next turn's own cost is measured from here.
|
|
1812
1886
|
*/
|
|
1813
|
-
sessionCostUsd:
|
|
1814
|
-
toolCalls:
|
|
1887
|
+
sessionCostUsd: z10.number().nonnegative().optional(),
|
|
1888
|
+
toolCalls: z10.number().int().nonnegative().default(0),
|
|
1815
1889
|
/** The model the CLI reported for this turn, else the model configured for the agent, else null. */
|
|
1816
|
-
model:
|
|
1890
|
+
model: z10.string().nullable().default(null),
|
|
1817
1891
|
/** The task branch the turn left work on, with its commit, as the runner reported it. */
|
|
1818
1892
|
work: TurnWorkSchema.optional(),
|
|
1819
1893
|
/** Who stopped the turn, for one that ended `stopped`. */
|
|
1820
1894
|
stoppedBy: NameSchema.optional(),
|
|
1821
1895
|
/** The crons whose fire started the turn, which record how it ended. */
|
|
1822
|
-
crons:
|
|
1896
|
+
crons: z10.array(UlidSchema).optional()
|
|
1823
1897
|
});
|
|
1824
|
-
var RunningTurnSchema =
|
|
1898
|
+
var RunningTurnSchema = z10.object({
|
|
1825
1899
|
turnId: UlidSchema,
|
|
1826
1900
|
agent: NameSchema,
|
|
1827
1901
|
scope: NameSchema,
|
|
@@ -1829,49 +1903,49 @@ var RunningTurnSchema = z9.object({
|
|
|
1829
1903
|
channel: NameSchema.optional(),
|
|
1830
1904
|
cli: CliKindSchema,
|
|
1831
1905
|
askedIn: ChannelRefSchema.optional(),
|
|
1832
|
-
steerable:
|
|
1833
|
-
stoppable:
|
|
1906
|
+
steerable: z10.boolean(),
|
|
1907
|
+
stoppable: z10.boolean()
|
|
1834
1908
|
});
|
|
1835
|
-
var SessionsFileSchema =
|
|
1836
|
-
claude:
|
|
1837
|
-
codex:
|
|
1909
|
+
var SessionsFileSchema = z10.object({
|
|
1910
|
+
claude: z10.string().optional(),
|
|
1911
|
+
codex: z10.string().optional(),
|
|
1838
1912
|
runner: NameSchema.optional()
|
|
1839
1913
|
});
|
|
1840
|
-
var WakeRequestSchema =
|
|
1914
|
+
var WakeRequestSchema = z10.object({
|
|
1841
1915
|
agent: NameSchema,
|
|
1842
1916
|
project: NameSchema,
|
|
1843
|
-
reason:
|
|
1917
|
+
reason: z10.string().default("manual wake"),
|
|
1844
1918
|
/** A manual wake, or a reflection turn requested ahead of the cadence. */
|
|
1845
|
-
kind:
|
|
1919
|
+
kind: z10.enum(["manual", "reflection"]).default("manual")
|
|
1846
1920
|
});
|
|
1847
|
-
var TurnHistoryEntrySchema =
|
|
1921
|
+
var TurnHistoryEntrySchema = z10.object({
|
|
1848
1922
|
/** The id of the event that ended the turn. */
|
|
1849
1923
|
id: UlidSchema,
|
|
1850
1924
|
/** The turn's own id, when it has a transcript to open; turns before transcripts have none. */
|
|
1851
1925
|
turnId: UlidSchema.optional(),
|
|
1852
1926
|
ts: IsoDateTimeSchema,
|
|
1853
|
-
outcome:
|
|
1927
|
+
outcome: z10.enum(["completed", "failed"]),
|
|
1854
1928
|
/** A project slug, or the society scope. */
|
|
1855
1929
|
project: NameSchema,
|
|
1856
1930
|
/** The thread whose conversation the turn was in; absent for the home conversation. */
|
|
1857
1931
|
thread: UlidSchema.optional(),
|
|
1858
1932
|
/** The channel, never general, whose conversation the turn was in. */
|
|
1859
1933
|
channel: NameSchema.optional(),
|
|
1860
|
-
trigger:
|
|
1861
|
-
exitReason:
|
|
1862
|
-
costUsd:
|
|
1934
|
+
trigger: z10.string(),
|
|
1935
|
+
exitReason: z10.string().nullable(),
|
|
1936
|
+
costUsd: z10.number(),
|
|
1863
1937
|
/** The tokens the turn used; absent for turns logged before turns recorded them. */
|
|
1864
1938
|
usage: UsageSchema.optional(),
|
|
1865
|
-
model:
|
|
1866
|
-
summary:
|
|
1867
|
-
error:
|
|
1939
|
+
model: z10.string().nullable(),
|
|
1940
|
+
summary: z10.string().nullable(),
|
|
1941
|
+
error: z10.string().nullable(),
|
|
1868
1942
|
/** When the log recorded the turn's start; absent when the start is missing from the log. */
|
|
1869
1943
|
startedAt: IsoDateTimeSchema.optional(),
|
|
1870
|
-
toolCalls:
|
|
1944
|
+
toolCalls: z10.number().int().nonnegative().optional()
|
|
1871
1945
|
});
|
|
1872
1946
|
|
|
1873
1947
|
// packages/shared/dist/ops.js
|
|
1874
|
-
import { z as
|
|
1948
|
+
import { z as z11 } from "zod";
|
|
1875
1949
|
var OPS_SIGNAL_KINDS = [
|
|
1876
1950
|
"waiting_stage",
|
|
1877
1951
|
"backlog",
|
|
@@ -1887,7 +1961,7 @@ var OPS_SIGNAL_KINDS = [
|
|
|
1887
1961
|
"stuck_workspace",
|
|
1888
1962
|
"cron_failing"
|
|
1889
1963
|
];
|
|
1890
|
-
var OpsSignalKindSchema =
|
|
1964
|
+
var OpsSignalKindSchema = z11.enum(OPS_SIGNAL_KINDS);
|
|
1891
1965
|
var WAKING_SIGNAL_KINDS = [
|
|
1892
1966
|
"backlog",
|
|
1893
1967
|
"role_gap",
|
|
@@ -1897,15 +1971,15 @@ var WAKING_SIGNAL_KINDS = [
|
|
|
1897
1971
|
"blocked_capability",
|
|
1898
1972
|
"scaled"
|
|
1899
1973
|
];
|
|
1900
|
-
var OpsSignalSchema =
|
|
1974
|
+
var OpsSignalSchema = z11.object({
|
|
1901
1975
|
kind: OpsSignalKindSchema,
|
|
1902
1976
|
/** Identifies the condition, for example `backlog:demo:engineer`, so a persisting one is not logged again every pass. */
|
|
1903
|
-
key:
|
|
1977
|
+
key: z11.string().min(1),
|
|
1904
1978
|
/** One line a reader can act on. */
|
|
1905
|
-
summary:
|
|
1979
|
+
summary: z11.string().min(1),
|
|
1906
1980
|
/** The counter or timer value behind the signal. */
|
|
1907
|
-
value:
|
|
1908
|
-
threshold:
|
|
1981
|
+
value: z11.number(),
|
|
1982
|
+
threshold: z11.number().optional(),
|
|
1909
1983
|
project: NameSchema.optional(),
|
|
1910
1984
|
agent: NameSchema.optional(),
|
|
1911
1985
|
role: NameSchema.optional(),
|
|
@@ -1913,8 +1987,8 @@ var OpsSignalSchema = z10.object({
|
|
|
1913
1987
|
});
|
|
1914
1988
|
|
|
1915
1989
|
// packages/shared/dist/metrics.js
|
|
1916
|
-
import { z as
|
|
1917
|
-
var MetricsWindowSchema =
|
|
1990
|
+
import { z as z12 } from "zod";
|
|
1991
|
+
var MetricsWindowSchema = z12.enum(["24h", "7d", "all"]);
|
|
1918
1992
|
var METRICS_WINDOW_MS = {
|
|
1919
1993
|
"24h": 24 * 36e5,
|
|
1920
1994
|
"7d": 7 * 24 * 36e5,
|
|
@@ -1925,9 +1999,9 @@ function isBoardAction(tool) {
|
|
|
1925
1999
|
const verb = /^mcp__board__(.+)$/.exec(tool)?.[1];
|
|
1926
2000
|
return verb !== void 0 && !READ_VERBS.some((read2) => read2 === verb);
|
|
1927
2001
|
}
|
|
1928
|
-
var CountSchema =
|
|
1929
|
-
var MsSchema =
|
|
1930
|
-
var MetricsSchema =
|
|
2002
|
+
var CountSchema = z12.number().int().nonnegative();
|
|
2003
|
+
var MsSchema = z12.number().nonnegative();
|
|
2004
|
+
var MetricsSchema = z12.object({
|
|
1931
2005
|
window: MetricsWindowSchema,
|
|
1932
2006
|
since: IsoDateTimeSchema.nullable(),
|
|
1933
2007
|
until: IsoDateTimeSchema,
|
|
@@ -1935,12 +2009,12 @@ var MetricsSchema = z11.object({
|
|
|
1935
2009
|
* Finished turns that changed nothing on the board. Reflections are left out, since they write
|
|
1936
2010
|
* memory, not the board; turns without a transcript are counted apart, their actions unknown.
|
|
1937
2011
|
*/
|
|
1938
|
-
idle:
|
|
2012
|
+
idle: z12.object({
|
|
1939
2013
|
turns: CountSchema,
|
|
1940
2014
|
idle: CountSchema,
|
|
1941
2015
|
unknown: CountSchema,
|
|
1942
|
-
byTrigger:
|
|
1943
|
-
byAgent:
|
|
2016
|
+
byTrigger: z12.array(z12.object({ trigger: z12.string(), turns: CountSchema, idle: CountSchema })),
|
|
2017
|
+
byAgent: z12.array(z12.object({
|
|
1944
2018
|
agent: NameSchema,
|
|
1945
2019
|
role: NameSchema.nullable(),
|
|
1946
2020
|
turns: CountSchema,
|
|
@@ -1948,33 +2022,33 @@ var MetricsSchema = z11.object({
|
|
|
1948
2022
|
}))
|
|
1949
2023
|
}),
|
|
1950
2024
|
/** Work sent back to an earlier stage: over the tasks finished in the window, and by where. */
|
|
1951
|
-
sentBack:
|
|
2025
|
+
sentBack: z12.object({
|
|
1952
2026
|
finished: CountSchema,
|
|
1953
2027
|
sendBacks: CountSchema,
|
|
1954
2028
|
tasksSentBack: CountSchema,
|
|
1955
|
-
byStage:
|
|
1956
|
-
bySender:
|
|
2029
|
+
byStage: z12.array(z12.object({ project: NameSchema, stage: z12.string(), count: CountSchema })),
|
|
2030
|
+
bySender: z12.array(z12.object({ agent: NameSchema, count: CountSchema }))
|
|
1957
2031
|
}),
|
|
1958
2032
|
/** Posts in the threads of the tasks finished in the window, the board's own notices left out. */
|
|
1959
|
-
messages:
|
|
2033
|
+
messages: z12.object({
|
|
1960
2034
|
finished: CountSchema,
|
|
1961
2035
|
messages: CountSchema,
|
|
1962
|
-
byProject:
|
|
1963
|
-
busiest:
|
|
2036
|
+
byProject: z12.array(z12.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
|
|
2037
|
+
busiest: z12.array(z12.object({
|
|
1964
2038
|
taskId: UlidSchema,
|
|
1965
|
-
title:
|
|
2039
|
+
title: z12.string(),
|
|
1966
2040
|
project: NameSchema,
|
|
1967
2041
|
messages: CountSchema
|
|
1968
2042
|
}))
|
|
1969
2043
|
}),
|
|
1970
2044
|
/** Time from a mention to the start of the turn it woke, in the conversation it was made in. */
|
|
1971
|
-
latency:
|
|
2045
|
+
latency: z12.object({
|
|
1972
2046
|
mentions: CountSchema,
|
|
1973
2047
|
/** Mentions no turn has followed yet. */
|
|
1974
2048
|
unanswered: CountSchema,
|
|
1975
2049
|
medianMs: MsSchema.nullable(),
|
|
1976
2050
|
slowestMs: MsSchema.nullable(),
|
|
1977
|
-
byAgent:
|
|
2051
|
+
byAgent: z12.array(z12.object({
|
|
1978
2052
|
agent: NameSchema,
|
|
1979
2053
|
mentions: CountSchema,
|
|
1980
2054
|
medianMs: MsSchema,
|
|
@@ -1982,73 +2056,73 @@ var MetricsSchema = z11.object({
|
|
|
1982
2056
|
}))
|
|
1983
2057
|
}),
|
|
1984
2058
|
/** The user's decisions: proposals decided, questions answered, and stages passed or sent back. */
|
|
1985
|
-
decisions:
|
|
2059
|
+
decisions: z12.object({
|
|
1986
2060
|
total: CountSchema,
|
|
1987
|
-
byDay:
|
|
1988
|
-
day:
|
|
2061
|
+
byDay: z12.array(z12.object({
|
|
2062
|
+
day: z12.string(),
|
|
1989
2063
|
proposals: CountSchema,
|
|
1990
2064
|
answers: CountSchema,
|
|
1991
2065
|
stages: CountSchema
|
|
1992
2066
|
}))
|
|
1993
2067
|
}),
|
|
1994
2068
|
/** Tasks that needed a capability no connected runner offered, and whether they still do. */
|
|
1995
|
-
blocked:
|
|
2069
|
+
blocked: z12.array(z12.object({
|
|
1996
2070
|
taskId: UlidSchema,
|
|
1997
|
-
title:
|
|
2071
|
+
title: z12.string().nullable(),
|
|
1998
2072
|
project: NameSchema.nullable(),
|
|
1999
|
-
summary:
|
|
2073
|
+
summary: z12.string(),
|
|
2000
2074
|
firstAt: IsoDateTimeSchema,
|
|
2001
2075
|
lastAt: IsoDateTimeSchema,
|
|
2002
|
-
holds:
|
|
2076
|
+
holds: z12.boolean()
|
|
2003
2077
|
}))
|
|
2004
2078
|
});
|
|
2005
|
-
var CitizenTokensSchema =
|
|
2079
|
+
var CitizenTokensSchema = z12.object({
|
|
2006
2080
|
agent: NameSchema,
|
|
2007
2081
|
turns: CountSchema,
|
|
2008
2082
|
withUsage: CountSchema,
|
|
2009
2083
|
usage: UsageSchema.nullable()
|
|
2010
2084
|
});
|
|
2011
|
-
var TokenUseSchema =
|
|
2085
|
+
var TokenUseSchema = z12.object({
|
|
2012
2086
|
window: MetricsWindowSchema,
|
|
2013
2087
|
since: IsoDateTimeSchema.nullable(),
|
|
2014
2088
|
until: IsoDateTimeSchema,
|
|
2015
|
-
citizens:
|
|
2089
|
+
citizens: z12.array(CitizenTokensSchema)
|
|
2016
2090
|
});
|
|
2017
2091
|
|
|
2018
2092
|
// packages/shared/dist/config.js
|
|
2019
|
-
import { z as
|
|
2020
|
-
var LogLevelSchema =
|
|
2021
|
-
var GithubSignInSchema =
|
|
2022
|
-
clientId:
|
|
2023
|
-
clientSecret:
|
|
2093
|
+
import { z as z13 } from "zod";
|
|
2094
|
+
var LogLevelSchema = z13.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
|
|
2095
|
+
var GithubSignInSchema = z13.object({
|
|
2096
|
+
clientId: z13.string().min(1),
|
|
2097
|
+
clientSecret: z13.string().min(1),
|
|
2024
2098
|
/** Logins, lowercased; GitHub logins are case-insensitive. */
|
|
2025
|
-
users:
|
|
2099
|
+
users: z13.array(z13.string().min(1)).min(1)
|
|
2026
2100
|
});
|
|
2027
|
-
var ServerConfigSchema =
|
|
2028
|
-
dataDir:
|
|
2029
|
-
host:
|
|
2030
|
-
port:
|
|
2101
|
+
var ServerConfigSchema = z13.object({
|
|
2102
|
+
dataDir: z13.string().min(1),
|
|
2103
|
+
host: z13.string().min(1),
|
|
2104
|
+
port: z13.number().int().positive().max(65535),
|
|
2031
2105
|
/**
|
|
2032
2106
|
* An address every runner's agents reach this server at, for example https://board.example, or
|
|
2033
2107
|
* null for each runner to use the address it reaches the server at itself.
|
|
2034
2108
|
*/
|
|
2035
|
-
publicUrl:
|
|
2109
|
+
publicUrl: z13.string().min(1).nullable(),
|
|
2036
2110
|
logLevel: LogLevelSchema,
|
|
2037
2111
|
/** Turns running at once across every runner, or null for no limit beyond each runner's own. */
|
|
2038
|
-
concurrency:
|
|
2112
|
+
concurrency: z13.number().int().positive().nullable(),
|
|
2039
2113
|
/** How long one turn may run before it is stopped, or null for no limit. */
|
|
2040
|
-
turnTimeoutMs:
|
|
2114
|
+
turnTimeoutMs: z13.number().int().positive().nullable(),
|
|
2041
2115
|
/** Rounds of tool calls one Claude turn may take, or null for no limit. */
|
|
2042
|
-
toolRounds:
|
|
2116
|
+
toolRounds: z13.number().int().positive().nullable(),
|
|
2043
2117
|
/** How long a resident session stays warm after its last turn. */
|
|
2044
|
-
residentIdleMs:
|
|
2118
|
+
residentIdleMs: z13.number().int().positive(),
|
|
2045
2119
|
/** Signing in to the board with GitHub, or null when only a token lets anyone in. */
|
|
2046
2120
|
github: GithubSignInSchema.nullable(),
|
|
2047
2121
|
/**
|
|
2048
2122
|
* Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
|
|
2049
2123
|
* rate limits on what anyone may ask without a token: 0 when clients connect directly.
|
|
2050
2124
|
*/
|
|
2051
|
-
trustedProxies:
|
|
2125
|
+
trustedProxies: z13.number().int().min(0).max(16)
|
|
2052
2126
|
});
|
|
2053
2127
|
function limit(value, fallback) {
|
|
2054
2128
|
if (value === void 0 || value.trim() === "") {
|
|
@@ -2086,25 +2160,25 @@ function loadServerConfig(env) {
|
|
|
2086
2160
|
trustedProxies: Number(env["STELLARIS_TRUSTED_PROXIES"] ?? "0")
|
|
2087
2161
|
});
|
|
2088
2162
|
}
|
|
2089
|
-
var RunnerConfigSchema =
|
|
2163
|
+
var RunnerConfigSchema = z13.object({
|
|
2090
2164
|
/** The board server, for example http://127.0.0.1:4700. */
|
|
2091
|
-
serverUrl:
|
|
2165
|
+
serverUrl: z13.string().url(),
|
|
2092
2166
|
/**
|
|
2093
2167
|
* The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
|
|
2094
2168
|
* to enroll it.
|
|
2095
2169
|
*/
|
|
2096
|
-
token:
|
|
2170
|
+
token: z13.string().min(1).nullable(),
|
|
2097
2171
|
/** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
|
|
2098
|
-
dataDir:
|
|
2172
|
+
dataDir: z13.string().min(1),
|
|
2099
2173
|
logLevel: LogLevelSchema,
|
|
2100
2174
|
/** Turns this machine runs at once, or null for no limit. */
|
|
2101
|
-
slots:
|
|
2102
|
-
clis:
|
|
2103
|
-
capabilities:
|
|
2175
|
+
slots: z13.number().int().positive().nullable(),
|
|
2176
|
+
clis: z13.array(CliKindSchema).min(1),
|
|
2177
|
+
capabilities: z13.array(z13.string())
|
|
2104
2178
|
});
|
|
2105
2179
|
|
|
2106
2180
|
// packages/shared/dist/version.js
|
|
2107
|
-
var STELLARIS_VERSION = "0.3.
|
|
2181
|
+
var STELLARIS_VERSION = "0.3.23";
|
|
2108
2182
|
|
|
2109
2183
|
// packages/shared/dist/mentions.js
|
|
2110
2184
|
import { parse, postprocess, preprocess } from "micromark";
|
|
@@ -2825,32 +2899,32 @@ function postMentions(body) {
|
|
|
2825
2899
|
}
|
|
2826
2900
|
|
|
2827
2901
|
// packages/board-core/dist/metrics.js
|
|
2828
|
-
import { z as
|
|
2829
|
-
var TurnPayload =
|
|
2830
|
-
turnId:
|
|
2831
|
-
project:
|
|
2832
|
-
thread:
|
|
2833
|
-
channel:
|
|
2834
|
-
trigger:
|
|
2902
|
+
import { z as z14 } from "zod";
|
|
2903
|
+
var TurnPayload = z14.object({
|
|
2904
|
+
turnId: z14.string().optional(),
|
|
2905
|
+
project: z14.string(),
|
|
2906
|
+
thread: z14.string().optional(),
|
|
2907
|
+
channel: z14.string().optional(),
|
|
2908
|
+
trigger: z14.string()
|
|
2835
2909
|
});
|
|
2836
|
-
var TaskPayload =
|
|
2837
|
-
taskId:
|
|
2838
|
-
project:
|
|
2839
|
-
from:
|
|
2910
|
+
var TaskPayload = z14.object({
|
|
2911
|
+
taskId: z14.string(),
|
|
2912
|
+
project: z14.string(),
|
|
2913
|
+
from: z14.string().optional()
|
|
2840
2914
|
});
|
|
2841
|
-
var MessagePayload =
|
|
2842
|
-
id:
|
|
2843
|
-
channel:
|
|
2844
|
-
thread:
|
|
2845
|
-
mentions:
|
|
2915
|
+
var MessagePayload = z14.object({
|
|
2916
|
+
id: z14.string().optional(),
|
|
2917
|
+
channel: z14.string(),
|
|
2918
|
+
thread: z14.string().nullable().optional(),
|
|
2919
|
+
mentions: z14.array(z14.string()).default([])
|
|
2846
2920
|
});
|
|
2847
|
-
var SteeredPayload =
|
|
2848
|
-
var SignalPayload =
|
|
2849
|
-
kind:
|
|
2850
|
-
key:
|
|
2851
|
-
summary:
|
|
2852
|
-
taskId:
|
|
2853
|
-
project:
|
|
2921
|
+
var SteeredPayload = z14.object({ messages: z14.array(z14.string()) });
|
|
2922
|
+
var SignalPayload = z14.object({
|
|
2923
|
+
kind: z14.string(),
|
|
2924
|
+
key: z14.string(),
|
|
2925
|
+
summary: z14.string(),
|
|
2926
|
+
taskId: z14.string().optional(),
|
|
2927
|
+
project: z14.string().optional()
|
|
2854
2928
|
});
|
|
2855
2929
|
function median(values) {
|
|
2856
2930
|
const sorted = values.toSorted((a, b) => a - b);
|
|
@@ -3140,19 +3214,19 @@ function computeMetrics(input) {
|
|
|
3140
3214
|
}
|
|
3141
3215
|
|
|
3142
3216
|
// packages/board-core/dist/turn-history.js
|
|
3143
|
-
import { z as
|
|
3144
|
-
var TurnHistoryPayloadSchema =
|
|
3217
|
+
import { z as z15 } from "zod";
|
|
3218
|
+
var TurnHistoryPayloadSchema = z15.object({
|
|
3145
3219
|
project: NameSchema,
|
|
3146
3220
|
thread: UlidSchema.optional(),
|
|
3147
3221
|
channel: NameSchema.optional(),
|
|
3148
|
-
trigger:
|
|
3149
|
-
exitReason:
|
|
3150
|
-
costUsd:
|
|
3222
|
+
trigger: z15.string().default("manual"),
|
|
3223
|
+
exitReason: z15.string().nullable().default(null),
|
|
3224
|
+
costUsd: z15.number().default(0),
|
|
3151
3225
|
usage: UsageSchema.optional(),
|
|
3152
|
-
model:
|
|
3153
|
-
summary:
|
|
3154
|
-
error:
|
|
3155
|
-
toolCalls:
|
|
3226
|
+
model: z15.string().nullable().default(null),
|
|
3227
|
+
summary: z15.string().nullable().default(null),
|
|
3228
|
+
error: z15.string().nullable().default(null),
|
|
3229
|
+
toolCalls: z15.number().int().nonnegative().optional(),
|
|
3156
3230
|
turnId: UlidSchema.optional()
|
|
3157
3231
|
});
|
|
3158
3232
|
function tokenUse(events, window, now) {
|
|
@@ -3398,6 +3472,13 @@ var BoardPaths = class {
|
|
|
3398
3472
|
eventLog() {
|
|
3399
3473
|
return path5.join(this.events(), "log.jsonl");
|
|
3400
3474
|
}
|
|
3475
|
+
/** Images citizens uploaded, by id: outside the projection, which every runner mirrors. */
|
|
3476
|
+
images() {
|
|
3477
|
+
return path5.join(this.dataDir, "images");
|
|
3478
|
+
}
|
|
3479
|
+
image(id) {
|
|
3480
|
+
return path5.join(this.images(), id);
|
|
3481
|
+
}
|
|
3401
3482
|
state() {
|
|
3402
3483
|
return path5.join(this.dataDir, "state");
|
|
3403
3484
|
}
|
|
@@ -3433,27 +3514,27 @@ function namesList(names) {
|
|
|
3433
3514
|
return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
|
|
3434
3515
|
}
|
|
3435
3516
|
var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".codex"]);
|
|
3436
|
-
var RunnerTokensSchema =
|
|
3437
|
-
runners:
|
|
3517
|
+
var RunnerTokensSchema = z16.object({
|
|
3518
|
+
runners: z16.record(z16.string(), z16.object({ tokenHash: z16.string().min(1) }))
|
|
3438
3519
|
});
|
|
3439
|
-
var SignInsSchema =
|
|
3440
|
-
signIns:
|
|
3441
|
-
tokenHash:
|
|
3442
|
-
login:
|
|
3520
|
+
var SignInsSchema = z16.object({
|
|
3521
|
+
signIns: z16.array(z16.object({
|
|
3522
|
+
tokenHash: z16.string().min(1),
|
|
3523
|
+
login: z16.string().min(1),
|
|
3443
3524
|
/** The account's picture at the identity provider; sign-ins from before it have none. */
|
|
3444
|
-
avatarUrl:
|
|
3525
|
+
avatarUrl: z16.url().optional(),
|
|
3445
3526
|
createdAt: IsoDateTimeSchema,
|
|
3446
3527
|
expiresAt: IsoDateTimeSchema
|
|
3447
3528
|
})).default([])
|
|
3448
3529
|
});
|
|
3449
|
-
var TurnStartPayloadSchema =
|
|
3450
|
-
var CursorsSchema =
|
|
3451
|
-
digest:
|
|
3452
|
-
scopes:
|
|
3453
|
-
threadsFrom:
|
|
3454
|
-
channelsFrom:
|
|
3530
|
+
var TurnStartPayloadSchema = z16.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3531
|
+
var CursorsSchema = z16.object({
|
|
3532
|
+
digest: z16.string().nullable(),
|
|
3533
|
+
scopes: z16.record(z16.string(), z16.string()).default({}),
|
|
3534
|
+
threadsFrom: z16.record(z16.string(), z16.string().nullable()).default({}),
|
|
3535
|
+
channelsFrom: z16.record(z16.string(), z16.string().nullable()).default({}),
|
|
3455
3536
|
/** How far a work role has read news, which goes to whichever of its general conversations reads first. */
|
|
3456
|
-
news:
|
|
3537
|
+
news: z16.string().optional()
|
|
3457
3538
|
});
|
|
3458
3539
|
var NO_CURSORS = { digest: null, scopes: {}, threadsFrom: {}, channelsFrom: {} };
|
|
3459
3540
|
function conversationKey(scope, part) {
|
|
@@ -3492,7 +3573,7 @@ function byId(a, b) {
|
|
|
3492
3573
|
function turnTime(record) {
|
|
3493
3574
|
return record.endedAt ?? record.startedAt;
|
|
3494
3575
|
}
|
|
3495
|
-
var PausedSchema =
|
|
3576
|
+
var PausedSchema = z16.object({ paused: z16.boolean() });
|
|
3496
3577
|
var DEFAULT_LEASE_MS = 30 * 60 * 1e3;
|
|
3497
3578
|
function withoutMentions(text) {
|
|
3498
3579
|
return text.replaceAll(MENTION_PATTERN, "$1$2");
|
|
@@ -3517,7 +3598,7 @@ var OPS_WAKE_TRIGGER = "ops_event";
|
|
|
3517
3598
|
var FRONT_DESK_TRIGGER = "user_post";
|
|
3518
3599
|
var OPS_CHANNELS = ["governance"];
|
|
3519
3600
|
var FRONT_DESK_CHANNELS = [ASK_CHANNEL];
|
|
3520
|
-
var AlignmentsSchema =
|
|
3601
|
+
var AlignmentsSchema = z16.object({ applied: z16.array(z16.string()).default([]) });
|
|
3521
3602
|
var FOLLOW_DECISIONS = "ops-readers-follow-decisions";
|
|
3522
3603
|
var THREAD_RECORDS = "threads-as-records";
|
|
3523
3604
|
var DIGEST_CURSORS = "digest-replaces-inbox";
|
|
@@ -3531,10 +3612,11 @@ var CHANNEL_CONVERSATIONS = "channel-conversations";
|
|
|
3531
3612
|
var DASHBOARD_UPDATES = "dashboard-updates-granted";
|
|
3532
3613
|
var CRON_VERBS = "cron-verbs-granted";
|
|
3533
3614
|
var KNOWLEDGE_NOTICES = "knowledge-notices";
|
|
3534
|
-
var
|
|
3615
|
+
var IMAGE_UPLOADS = "image-uploads-granted";
|
|
3616
|
+
var KnowledgeEventSchema = z16.object({
|
|
3535
3617
|
topic: NameSchema,
|
|
3536
3618
|
project: NameSchema.nullable(),
|
|
3537
|
-
replaced:
|
|
3619
|
+
replaced: z16.boolean().optional()
|
|
3538
3620
|
});
|
|
3539
3621
|
var CRON_VERB_NAMES = ["create_cron", "update_cron", "remove_cron"];
|
|
3540
3622
|
var OLD_DASHBOARD_LINE = "Agents may edit this file. It is rendered by the board UI.";
|
|
@@ -3666,6 +3748,7 @@ var Board = class _Board {
|
|
|
3666
3748
|
mutex = new Mutex();
|
|
3667
3749
|
/** The turns in flight, which the server hosting them supplies; none until it does. */
|
|
3668
3750
|
turnsInFlight = () => [];
|
|
3751
|
+
imageSource = null;
|
|
3669
3752
|
newId = monotonicFactory();
|
|
3670
3753
|
events;
|
|
3671
3754
|
actionCounts = /* @__PURE__ */ new Map();
|
|
@@ -3730,7 +3813,8 @@ var Board = class _Board {
|
|
|
3730
3813
|
CHANNEL_CONVERSATIONS,
|
|
3731
3814
|
DASHBOARD_UPDATES,
|
|
3732
3815
|
CRON_VERBS,
|
|
3733
|
-
KNOWLEDGE_NOTICES
|
|
3816
|
+
KNOWLEDGE_NOTICES,
|
|
3817
|
+
IMAGE_UPLOADS
|
|
3734
3818
|
].filter((name) => !applied.includes(name));
|
|
3735
3819
|
if (pending.length === 0) {
|
|
3736
3820
|
return;
|
|
@@ -3760,13 +3844,13 @@ var Board = class _Board {
|
|
|
3760
3844
|
await this.openAsksChannel();
|
|
3761
3845
|
}
|
|
3762
3846
|
if (pending.includes(KNOWLEDGE_REMOVAL)) {
|
|
3763
|
-
await this.
|
|
3847
|
+
await this.grantBeside("write_knowledge", "remove_knowledge");
|
|
3764
3848
|
}
|
|
3765
3849
|
if (pending.includes(CHANNEL_CONVERSATIONS)) {
|
|
3766
3850
|
await this.startChannelCursors();
|
|
3767
3851
|
}
|
|
3768
3852
|
if (pending.includes(DASHBOARD_UPDATES)) {
|
|
3769
|
-
await this.
|
|
3853
|
+
await this.grantBeside("write_knowledge", "update_dashboard");
|
|
3770
3854
|
await this.rewordDashboards();
|
|
3771
3855
|
}
|
|
3772
3856
|
if (pending.includes(CRON_VERBS)) {
|
|
@@ -3775,6 +3859,9 @@ var Board = class _Board {
|
|
|
3775
3859
|
if (pending.includes(KNOWLEDGE_NOTICES)) {
|
|
3776
3860
|
await this.noticeKnowledgeNotes();
|
|
3777
3861
|
}
|
|
3862
|
+
if (pending.includes(IMAGE_UPLOADS)) {
|
|
3863
|
+
await this.grantBeside("post_message", "upload_image");
|
|
3864
|
+
}
|
|
3778
3865
|
await writeJson(file, { applied: [...applied, ...pending] });
|
|
3779
3866
|
}
|
|
3780
3867
|
/**
|
|
@@ -3816,12 +3903,12 @@ var Board = class _Board {
|
|
|
3816
3903
|
}
|
|
3817
3904
|
}
|
|
3818
3905
|
/**
|
|
3819
|
-
* Grants `verb` once to every charter granting `
|
|
3820
|
-
*
|
|
3906
|
+
* Grants `verb` once to every charter granting `beside`, the work roles' charters in practice;
|
|
3907
|
+
* seed roles have it from their seed.
|
|
3821
3908
|
*/
|
|
3822
|
-
async
|
|
3909
|
+
async grantBeside(beside, verb) {
|
|
3823
3910
|
for (const charter of await this.listRoles()) {
|
|
3824
|
-
if (charter.verbs.includes(
|
|
3911
|
+
if (charter.verbs.includes(beside) && !charter.verbs.includes(verb)) {
|
|
3825
3912
|
await this.writeRoleUnlocked(USER_NAME, { ...charter, verbs: [...charter.verbs, verb] }, { verbsAdded: [verb] });
|
|
3826
3913
|
}
|
|
3827
3914
|
}
|
|
@@ -3979,7 +4066,7 @@ var Board = class _Board {
|
|
|
3979
4066
|
}
|
|
3980
4067
|
}
|
|
3981
4068
|
for (const file of await listFiles(this.paths.tasks(slug))) {
|
|
3982
|
-
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file),
|
|
4069
|
+
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z16.record(z16.string(), z16.unknown()));
|
|
3983
4070
|
const legacy = raw.data["thread"];
|
|
3984
4071
|
if (legacy === void 0) {
|
|
3985
4072
|
continue;
|
|
@@ -4057,7 +4144,7 @@ var Board = class _Board {
|
|
|
4057
4144
|
* turns, so it follows nothing now.
|
|
4058
4145
|
*/
|
|
4059
4146
|
async renameInboxCursors() {
|
|
4060
|
-
const Legacy =
|
|
4147
|
+
const Legacy = z16.object({ inbox: z16.string().nullable() });
|
|
4061
4148
|
for (const agent of await this.listAgents()) {
|
|
4062
4149
|
const file = this.paths.agentCursors(agent.name);
|
|
4063
4150
|
if (await exists(file)) {
|
|
@@ -4103,7 +4190,7 @@ ${charter.purpose}
|
|
|
4103
4190
|
*/
|
|
4104
4191
|
async alignSeedRole(seed) {
|
|
4105
4192
|
const file = this.paths.role(seed.name);
|
|
4106
|
-
const raw = await readMarkdown(file,
|
|
4193
|
+
const raw = await readMarkdown(file, z16.record(z16.string(), z16.unknown()));
|
|
4107
4194
|
const current = RoleCharterSchema.parse(raw.data);
|
|
4108
4195
|
const verbsAdded = seed.verbs.filter((verb) => !current.verbs.includes(verb));
|
|
4109
4196
|
const fieldsAligned = RoleCharterSchema.keyof().options.filter((key) => key === "verbs" || seed[key] === void 0 ? false : seed.name === USER_ROLE ? JSON.stringify(seed[key]) !== JSON.stringify(current[key]) : !(key in raw.data));
|
|
@@ -4420,7 +4507,7 @@ ${charter.purpose}
|
|
|
4420
4507
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
4421
4508
|
async readSocietyNorms() {
|
|
4422
4509
|
const file = this.paths.societyKnowledgeFile("norms");
|
|
4423
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
4510
|
+
return await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
4424
4511
|
}
|
|
4425
4512
|
/** Knowledge topics of a project, or of the society when the project is null. */
|
|
4426
4513
|
async listKnowledge(project) {
|
|
@@ -4440,7 +4527,7 @@ ${charter.purpose}
|
|
|
4440
4527
|
*/
|
|
4441
4528
|
async knowledgeAt(file, project, topic) {
|
|
4442
4529
|
const { data, body } = await readLooseMarkdown(file);
|
|
4443
|
-
const revision =
|
|
4530
|
+
const revision = z16.number().int().min(0).safeParse(data["revision"]);
|
|
4444
4531
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
4445
4532
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
4446
4533
|
return {
|
|
@@ -5403,6 +5490,60 @@ ${current.body}`);
|
|
|
5403
5490
|
return updated;
|
|
5404
5491
|
});
|
|
5405
5492
|
}
|
|
5493
|
+
/**
|
|
5494
|
+
* Keeps an image a citizen's turn names by its path, read on the runner the turn runs on, which
|
|
5495
|
+
* refuses a file outside the turn's worktree, the citizen's home, and the system temp folder.
|
|
5496
|
+
* Only the bytes of a PNG, JPEG, GIF, or WebP of at most `IMAGE_LIMIT_BYTES` are kept, checked
|
|
5497
|
+
* here again whatever the runner said, under a new id outside the projection, so no runner
|
|
5498
|
+
* mirrors them and no prompt carries them: a post shows the image by its `image:` address.
|
|
5499
|
+
*/
|
|
5500
|
+
async uploadImage(actor, input) {
|
|
5501
|
+
const args = VerbInputs.upload_image.parse(input);
|
|
5502
|
+
await this.authorize(actor, "upload_image");
|
|
5503
|
+
if (actor.scope === void 0) {
|
|
5504
|
+
throw new BoardError("INVALID_STATE", "upload_image reads the file on the machine a turn runs on, so only a turn can call it");
|
|
5505
|
+
}
|
|
5506
|
+
if (this.imageSource === null) {
|
|
5507
|
+
throw new BoardError("NOT_FOUND", "this board has no runners to read an image from");
|
|
5508
|
+
}
|
|
5509
|
+
const bytes = await this.imageSource(actor, args.path);
|
|
5510
|
+
const type = imageTypeOf(bytes);
|
|
5511
|
+
if (type === null) {
|
|
5512
|
+
throw new BoardError("VALIDATION", `${args.path} is not a PNG, JPEG, GIF, or WebP image by its first bytes`);
|
|
5513
|
+
}
|
|
5514
|
+
if (bytes.byteLength > IMAGE_LIMIT_BYTES) {
|
|
5515
|
+
throw new BoardError("VALIDATION", `${args.path} is ${bytes.byteLength} bytes, over the ${IMAGE_LIMIT_BYTES} an image may be`);
|
|
5516
|
+
}
|
|
5517
|
+
return this.mutex.run(async () => {
|
|
5518
|
+
const id = this.newId();
|
|
5519
|
+
await writeFileAtomic(this.paths.image(id), bytes);
|
|
5520
|
+
await this.events.append("image.uploaded", actor.name, {
|
|
5521
|
+
id,
|
|
5522
|
+
type,
|
|
5523
|
+
size: bytes.byteLength
|
|
5524
|
+
});
|
|
5525
|
+
const name = path6.basename(args.path).replaceAll(/[[\]\\\r\n]/g, "");
|
|
5526
|
+
return {
|
|
5527
|
+
id,
|
|
5528
|
+
type,
|
|
5529
|
+
size: bytes.byteLength,
|
|
5530
|
+
markdown: ``
|
|
5531
|
+
};
|
|
5532
|
+
});
|
|
5533
|
+
}
|
|
5534
|
+
/** An uploaded image's bytes and kind, which its first bytes tell. */
|
|
5535
|
+
async readImage(id) {
|
|
5536
|
+
const file = this.paths.image(UlidSchema.parse(id));
|
|
5537
|
+
if (!await exists(file)) {
|
|
5538
|
+
throw new BoardError("NOT_FOUND", `image ${id} not found`);
|
|
5539
|
+
}
|
|
5540
|
+
const bytes = await readFile4(file);
|
|
5541
|
+
const type = imageTypeOf(bytes);
|
|
5542
|
+
if (type === null) {
|
|
5543
|
+
throw new BoardError("NOT_FOUND", `image ${id} is not an image the board shows`);
|
|
5544
|
+
}
|
|
5545
|
+
return { type, bytes };
|
|
5546
|
+
}
|
|
5406
5547
|
/** Every cron, ended ones included, oldest first. */
|
|
5407
5548
|
async listCrons() {
|
|
5408
5549
|
const crons = [];
|
|
@@ -5794,6 +5935,13 @@ ${current.body}`);
|
|
|
5794
5935
|
watchTurns(source) {
|
|
5795
5936
|
this.turnsInFlight = source;
|
|
5796
5937
|
}
|
|
5938
|
+
/**
|
|
5939
|
+
* Where `upload_image` reads a file from: the runner the calling turn runs on, through the server
|
|
5940
|
+
* that hosts the runners. Without one, as in the admin CLI, nothing can be uploaded.
|
|
5941
|
+
*/
|
|
5942
|
+
readImagesWith(source) {
|
|
5943
|
+
this.imageSource = source;
|
|
5944
|
+
}
|
|
5797
5945
|
/**
|
|
5798
5946
|
* Refuses to end conversations while another citizen's turn is in one of them: `cut` picks the
|
|
5799
5947
|
* turns that would lose theirs. The caller's own turn is exempt, since ending a conversation
|
|
@@ -6623,6 +6771,8 @@ ${rationale}`}`);
|
|
|
6623
6771
|
return this.updateCron(actor, VerbInputs.update_cron.parse(input));
|
|
6624
6772
|
case "remove_cron":
|
|
6625
6773
|
return this.removeCron(actor, VerbInputs.remove_cron.parse(input));
|
|
6774
|
+
case "upload_image":
|
|
6775
|
+
return this.uploadImage(actor, VerbInputs.upload_image.parse(input));
|
|
6626
6776
|
default:
|
|
6627
6777
|
throw new BoardError("VALIDATION", `unknown verb ${String(verb)}`);
|
|
6628
6778
|
}
|
|
@@ -6669,7 +6819,7 @@ ${rationale}`}`);
|
|
|
6669
6819
|
}
|
|
6670
6820
|
async readAgentRoleBody(agent) {
|
|
6671
6821
|
const file = this.paths.agentRole(agent);
|
|
6672
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
6822
|
+
return await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
6673
6823
|
}
|
|
6674
6824
|
/** The steps of one finished turn, as the runner handed them over when it ended. */
|
|
6675
6825
|
/**
|
|
@@ -7077,7 +7227,7 @@ ${rationale}`}`);
|
|
|
7077
7227
|
return { project: slug, revision: 0, body: "" };
|
|
7078
7228
|
}
|
|
7079
7229
|
const { data, body } = await readLooseMarkdown(file);
|
|
7080
|
-
const revision =
|
|
7230
|
+
const revision = z16.number().int().min(0).safeParse(data["revision"]);
|
|
7081
7231
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
7082
7232
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
7083
7233
|
return {
|
|
@@ -7351,7 +7501,7 @@ ${charter.purpose}
|
|
|
7351
7501
|
|
|
7352
7502
|
${charter.purpose}
|
|
7353
7503
|
|
|
7354
|
-
Route every lesson with one question: about me, my craft, or the user, it goes in memory/core.md; about this codebase, it goes in the project's knowledge
|
|
7504
|
+
Route every lesson with one question: about me, my craft, or the user, it goes in memory/core.md; about how this codebase behaves, it goes in the repo's AGENTS.md or README; about this project as a place (runners, access, flow, where results live), it goes in the project's knowledge; something everyone should know, post it.
|
|
7355
7505
|
` + (seed.length === 0 ? "" : `
|
|
7356
7506
|
${SEED_INSTRUCTIONS_HEADING}
|
|
7357
7507
|
|
|
@@ -7368,7 +7518,7 @@ ${seed}
|
|
|
7368
7518
|
continue;
|
|
7369
7519
|
}
|
|
7370
7520
|
const file = this.paths.agentRole(agent.name);
|
|
7371
|
-
const body = await exists(file) ? (await readMarkdown(file,
|
|
7521
|
+
const body = await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
7372
7522
|
const at = body.indexOf(`
|
|
7373
7523
|
${SEED_INSTRUCTIONS_HEADING}
|
|
7374
7524
|
`);
|
|
@@ -8584,7 +8734,7 @@ function decideWake(input) {
|
|
|
8584
8734
|
}
|
|
8585
8735
|
|
|
8586
8736
|
// packages/scheduler/dist/scheduler.js
|
|
8587
|
-
import { z as
|
|
8737
|
+
import { z as z17 } from "zod";
|
|
8588
8738
|
function besideFields(beside) {
|
|
8589
8739
|
if (beside === void 0) {
|
|
8590
8740
|
return {};
|
|
@@ -8611,21 +8761,21 @@ var DEFAULT_TIMINGS = Object.freeze({
|
|
|
8611
8761
|
scaleCooldownMs: 36e5,
|
|
8612
8762
|
reflectionMs: 24 * 36e5
|
|
8613
8763
|
});
|
|
8614
|
-
var SchedulerTimingsSchema =
|
|
8615
|
-
pollMs:
|
|
8616
|
-
debounceMs:
|
|
8617
|
-
userDebounceMs:
|
|
8618
|
-
heartbeatMs:
|
|
8619
|
-
waitingStageMs:
|
|
8620
|
-
leaseSweepMs:
|
|
8621
|
-
opsIntervalMs:
|
|
8622
|
-
signalRepeatMs:
|
|
8623
|
-
costReportMs:
|
|
8624
|
-
staleThreadMs:
|
|
8625
|
-
idleMemberMs:
|
|
8626
|
-
homeConflictMs:
|
|
8627
|
-
scaleCooldownMs:
|
|
8628
|
-
reflectionMs:
|
|
8764
|
+
var SchedulerTimingsSchema = z17.object({
|
|
8765
|
+
pollMs: z17.number().positive(),
|
|
8766
|
+
debounceMs: z17.number().nonnegative(),
|
|
8767
|
+
userDebounceMs: z17.number().nonnegative(),
|
|
8768
|
+
heartbeatMs: z17.number().positive(),
|
|
8769
|
+
waitingStageMs: z17.number().positive(),
|
|
8770
|
+
leaseSweepMs: z17.number().positive(),
|
|
8771
|
+
opsIntervalMs: z17.number().positive(),
|
|
8772
|
+
signalRepeatMs: z17.number().positive(),
|
|
8773
|
+
costReportMs: z17.number().positive(),
|
|
8774
|
+
staleThreadMs: z17.number().positive(),
|
|
8775
|
+
idleMemberMs: z17.number().positive(),
|
|
8776
|
+
homeConflictMs: z17.number().positive(),
|
|
8777
|
+
scaleCooldownMs: z17.number().positive(),
|
|
8778
|
+
reflectionMs: z17.number().positive()
|
|
8629
8779
|
}).partial();
|
|
8630
8780
|
function parseTimings(input) {
|
|
8631
8781
|
const parsed = SchedulerTimingsSchema.parse(input);
|
|
@@ -8637,32 +8787,32 @@ function parseTimings(input) {
|
|
|
8637
8787
|
}
|
|
8638
8788
|
return overrides;
|
|
8639
8789
|
}
|
|
8640
|
-
var PendingSchema =
|
|
8790
|
+
var PendingSchema = z17.object({
|
|
8641
8791
|
dispatch: TurnDispatchSchema,
|
|
8642
|
-
readyAt:
|
|
8643
|
-
stageWakes:
|
|
8644
|
-
holder:
|
|
8792
|
+
readyAt: z17.number(),
|
|
8793
|
+
stageWakes: z17.array(TriggerSchema).optional(),
|
|
8794
|
+
holder: z17.boolean().optional(),
|
|
8645
8795
|
newestMessage: UlidSchema.optional(),
|
|
8646
|
-
onlyMessages:
|
|
8796
|
+
onlyMessages: z17.boolean().optional(),
|
|
8647
8797
|
steeredThrough: UlidSchema.optional(),
|
|
8648
|
-
onlyCrons:
|
|
8798
|
+
onlyCrons: z17.boolean().optional()
|
|
8649
8799
|
});
|
|
8650
|
-
var StateSchema =
|
|
8651
|
-
cursor:
|
|
8652
|
-
lastHeartbeat:
|
|
8800
|
+
var StateSchema = z17.object({
|
|
8801
|
+
cursor: z17.string().nullable(),
|
|
8802
|
+
lastHeartbeat: z17.record(z17.string(), z17.string()),
|
|
8653
8803
|
/** Waiting stages already signalled, as `task:stage`, so each is logged once while it waits. */
|
|
8654
|
-
waitingSeen:
|
|
8804
|
+
waitingSeen: z17.record(z17.string(), z17.string()).default({}),
|
|
8655
8805
|
/** Queued dispatches survive a restart; the cursor has already moved past the events that made them. */
|
|
8656
|
-
pending:
|
|
8657
|
-
opsReported:
|
|
8658
|
-
releaseCounts:
|
|
8659
|
-
lastOps:
|
|
8660
|
-
lastScaled:
|
|
8661
|
-
lastCostReport:
|
|
8662
|
-
costSinceReport:
|
|
8663
|
-
turnsSinceReport:
|
|
8806
|
+
pending: z17.record(z17.string(), PendingSchema).default({}),
|
|
8807
|
+
opsReported: z17.record(z17.string(), z17.string()).default({}),
|
|
8808
|
+
releaseCounts: z17.record(z17.string(), z17.number().int().nonnegative()).default({}),
|
|
8809
|
+
lastOps: z17.string().nullable().default(null),
|
|
8810
|
+
lastScaled: z17.record(z17.string(), z17.string()).default({}),
|
|
8811
|
+
lastCostReport: z17.string().nullable().default(null),
|
|
8812
|
+
costSinceReport: z17.number().nonnegative().default(0),
|
|
8813
|
+
turnsSinceReport: z17.number().int().nonnegative().default(0),
|
|
8664
8814
|
/** When each member last reflected, or was first seen; the cadence counts from here. */
|
|
8665
|
-
lastReflection:
|
|
8815
|
+
lastReflection: z17.record(z17.string(), z17.string()).default({})
|
|
8666
8816
|
});
|
|
8667
8817
|
function messageOf(trigger) {
|
|
8668
8818
|
return trigger.kind === "mention" || trigger.kind === "user_post" ? trigger.messageId : void 0;
|
|
@@ -10237,9 +10387,9 @@ var TURN_CONTRACT = [
|
|
|
10237
10387
|
"- To come back to something later, set a cron with create_cron: a note on what to do then, and a five-field cron expression or one time with at. It wakes you in this conversation unless you name another, at most every fifteen minutes, and every fire is a paid turn, so end a cron with remove_cron once it has done its job. Never wait by holding a stage, sleeping, or leaving a process running: a turn's board token ends with the turn, so nothing it leaves behind can act on the board. The society's crons are under society/crons/ in the board projection.",
|
|
10238
10388
|
"- An @mention wakes the citizen named, and every wake costs a turn. Address someone with @ only when you need them to act; when you merely refer to citizens, write their names plainly. A name in a code span or a code block is no mention, so code keeps its @ as written. @user wakes nobody, since the user takes no turns; it is what puts a question before the user, so use it only when you need the user to answer or decide.",
|
|
10239
10389
|
"- A thread is a conversation off a channel that reaches only its participants and whoever is mentioned in it. Every task has one, opened with it under the task's id on the channel of its project it was filed in, general unless it was filed in another: talk about a task there, with post_message and its thread_id, and the notes you give advance_task and update_task are posted there as you. Its participants are the task's creator, its stage holders and assignees, whoever may take the stage that waits, and anyone who posted; it closes when the task ends. Every proposal has one too, in governance, opened with its pitch and closed by its decision. Open other threads with open_thread on a channel with a title, for any other topic; close_thread posts your summary to its channel.",
|
|
10240
|
-
"- To show an image in a post, such as a screenshot or a chart,
|
|
10241
|
-
"- Route every lesson: about you, your craft, or the user, write it to memory/core.md in your home directory, and keep that file short by moving detail to memory/<topic>.md, your archive; a durable fact about a project
|
|
10242
|
-
'- A procedure you have followed twice is a skill: write it to skills/<name>/SKILL.md in your home, frontmatter with `name` and a one-line `description` and then the steps, and your skills index lists it from the next turn. Files the steps use, such as scripts/ and references/, go in the same folder, named in SKILL.md by paths relative to it. Propose it with kind "skill" when
|
|
10390
|
+
"- To show an image in a post, such as a screenshot or a chart, save it anywhere you can read it, such as a folder from `mktemp -d`, call upload_image with its path, and put the markdown it returns in the post, ``, with what the image shows as its alt text: the board keeps the image, so it shows in any conversation after the file is gone. It takes a PNG, JPEG, GIF, or WebP of at most 8 MB from your worktree, your home, or the system temp folder. An image committed on a task's branch, linked by its path in the task's worktree, still shows in place, and so does one at an https address. Never put an image or any other file into a message as base64 or a data: URL: the board does not show it, and every reader of the conversation gets it in full in their prompt.",
|
|
10391
|
+
"- Route every lesson: about you, your craft, or the user, write it to memory/core.md in your home directory, and keep that file short by moving detail to memory/<topic>.md, your archive; how a codebase behaves (architecture, conventions, gotchas, how to build, test, and verify it) goes in its AGENTS.md or README, committed on a task's branch like any change to the code, or proposed in the task's thread or the project channel when it is outside the task at hand; a durable fact about a project as a place (runners, access, flow, where results live) goes through `write_knowledge` on that project; something the whole project should know now, post it to the project channel, and anything about one task, in the task's thread.",
|
|
10392
|
+
'- A procedure you have followed twice is a candidate for a skill, which it is when it makes a citizen better at a kind of work on any project: write it to skills/<name>/SKILL.md in your home, frontmatter with `name` and a one-line `description` and then the steps, and your skills index lists it from the next turn. Files the steps use, such as scripts/ and references/, go in the same folder, named in SKILL.md by paths relative to it. Propose it with kind "skill" when more than one citizen would use it and nothing in it is tied to one place; a skill only you use stays yours, however many projects you use it on.',
|
|
10243
10393
|
"- To take a published skill for yourself, install it in a temporary folder and copy it into your home: in a folder from `mktemp -d`, `npx -y skills add <source> --skill <name> -a universal --copy -y` writes `.agents/skills/<name>/` and a lock file there, and you copy that skill folder to skills/<name>/ in your home, named in lowercase letters, digits, and hyphens. Never install one inside a worktree, where it would be committed into the project, or with -g, which writes to the runner's own home, shared by every citizen on it and listed in no skills index.",
|
|
10244
10394
|
"- Report memoryUpdated: true in the status object whenever you changed memory/core.md or a skill, so a warm session restarts with the new instructions.",
|
|
10245
10395
|
"- Other turns of yours may be running at the same time and share your home. Change a file there with your edit tool, which refuses a file changed since you read it, and never rewrite one whole from an earlier read, with a shell redirect or a script, or you erase what another of your turns wrote.",
|
|
@@ -10250,7 +10400,7 @@ var PLANNING = [
|
|
|
10250
10400
|
"- A task is a plan of stages between open and done. Hold the current stage with claim_task and finish it with advance_task; the next stage becomes current, and past the last one the task is done.",
|
|
10251
10401
|
"- Name stages by what gets done. Plan the next few steps rather than everything, and reshape with plan_task as the work teaches you.",
|
|
10252
10402
|
"- Assign a stage to a role when anyone in it could do it, to a citizen only when it must be them, and to nobody when anyone in the project could. A citizen named on a stage must be a member of the task's project; add them first. A stage wakes everyone it is open to when it comes up, so the narrower the assignee, the fewer turns it costs.",
|
|
10253
|
-
"- Reshape rather than force: another round is an inserted stage, and a wait on something outside the society is a stage named for what it waits on. When a check finds work unfinished,
|
|
10403
|
+
"- Reshape rather than force: another round is an inserted stage, and a wait on something outside the society is a stage named for what it waits on. When a check finds work unfinished, the holder of the current stage sends the task back to an earlier stage with update_task, and so may the user, the steward, and the concierge; anyone else asks the concierge in the task's thread.",
|
|
10254
10404
|
"- A task that cannot start until other tasks finish names them with update_task blocked_by. While any of them is in play, its stage wakes nobody, neither when it comes up nor on a heartbeat; once the last has ended, done or abandoned, the stage wakes as if it had just come up, or wakes its holder. Nobody needs to clear the block or mention anyone when they end; change blocked_by only when the plan changes.",
|
|
10255
10405
|
"- A gated stage is an independent check: nobody who held an earlier stage of the task may hold it, and only the user, the steward, and the concierge may add, remove, move, reassign, or ungate it. Ask them in the task's thread when a gate should change.",
|
|
10256
10406
|
"- Commit your work on the task's branch before you advance, and say what you did in the advance note; it is the handover the next holder reads in the task's thread."
|
|
@@ -10288,7 +10438,7 @@ function renderOnboardingPreamble(context2) {
|
|
|
10288
10438
|
function renderSkillsIndex(skills) {
|
|
10289
10439
|
if (skills.length === 0) {
|
|
10290
10440
|
return [
|
|
10291
|
-
"None yet.
|
|
10441
|
+
"None yet. Something you have done the same way twice is a candidate for the first; the turn contract says when it is one."
|
|
10292
10442
|
];
|
|
10293
10443
|
}
|
|
10294
10444
|
return [
|
|
@@ -10317,9 +10467,9 @@ var REFLECTION_INTRO = "This turn is for your memory; take no new work, and answ
|
|
|
10317
10467
|
var RECONCILE = "- Reconcile first: merge each copy listed under Edits to reconcile in your home into the file beside it, then delete the copy.";
|
|
10318
10468
|
var REFLECTION_STEPS = [
|
|
10319
10469
|
"- Consolidate memory/core.md: keep it to lessons that still hold, about sixty lines at most, and move detail worth keeping to memory/<topic>.md in your home, which the board's search covers for you alone.",
|
|
10320
|
-
'- Extract a skill: a procedure you have followed twice goes to skills/<name>/SKILL.md, frontmatter with `name` and a one-line `description` and then the steps, with any script or reference it uses in the same folder. Propose it with kind "skill" when
|
|
10470
|
+
'- Extract a skill: a procedure you have followed twice is a candidate, and one that makes a citizen better at a kind of work on any project goes to skills/<name>/SKILL.md, frontmatter with `name` and a one-line `description` and then the steps, with any script or reference it uses in the same folder. Propose it with kind "skill" when more than one citizen would use it and nothing in it is tied to one place; one only you use stays yours.',
|
|
10321
10471
|
"- Refresh profile.md: one paragraph on what you do well and what to send your way; the roster the front desk routes with is built from it.",
|
|
10322
|
-
"- Share: a durable fact about this scope
|
|
10472
|
+
"- Share: how a codebase behaves goes in its AGENTS.md or README through a task like any change to the code, so propose it in that task's thread or the project channel; a durable fact about this scope as a place (runners, access, flow, where results live) goes through write_knowledge; a norm the whole society should follow goes to the steward as a plain post in general.",
|
|
10323
10473
|
"- Report memoryUpdated: true in the status object when core.md or a skill changed."
|
|
10324
10474
|
];
|
|
10325
10475
|
var MAX_BODY_CHARS = 1500;
|
|
@@ -10543,7 +10693,7 @@ function buildTurnPrompt(input) {
|
|
|
10543
10693
|
if (knowledge !== void 0 && knowledge !== null) {
|
|
10544
10694
|
lines.push("", `## Knowledge of ${dispatch.project}`, "");
|
|
10545
10695
|
if (knowledge.topics.length === 0) {
|
|
10546
|
-
lines.push("None yet. A durable fact about this
|
|
10696
|
+
lines.push("None yet. A durable fact about this place, such as its runners, access, flow, or where results live, is worth a write_knowledge call.");
|
|
10547
10697
|
} else {
|
|
10548
10698
|
lines.push(`Topics under ${knowledge.dir}; open one with your file tools when it is relevant.`, "");
|
|
10549
10699
|
for (const topic of knowledge.topics) {
|
|
@@ -11319,6 +11469,12 @@ var DEFAULT_GRACE_MS = 2 * 6e4;
|
|
|
11319
11469
|
var DEFAULT_REQUEST_TIMEOUT_MS = 10 * 6e4;
|
|
11320
11470
|
var CONTROL_TIMEOUT_MS = 15e3;
|
|
11321
11471
|
var FILE_TIMEOUT_MS = 6e4;
|
|
11472
|
+
var IMAGE_REFUSALS = {
|
|
11473
|
+
missing: "NOT_FOUND",
|
|
11474
|
+
outside: "FORBIDDEN",
|
|
11475
|
+
not_image: "VALIDATION",
|
|
11476
|
+
too_big: "VALIDATION"
|
|
11477
|
+
};
|
|
11322
11478
|
var SWEEP_TIMEOUT_MS = 2 * 6e4;
|
|
11323
11479
|
var DEFAULT_ACK_TIMEOUT_MS = 3e4;
|
|
11324
11480
|
var RunnerHub = class {
|
|
@@ -11827,6 +11983,33 @@ var RunnerHub = class {
|
|
|
11827
11983
|
}
|
|
11828
11984
|
return diff;
|
|
11829
11985
|
}
|
|
11986
|
+
/**
|
|
11987
|
+
* The image file a citizen's turn names for `upload_image`, read on the runner that turn runs on,
|
|
11988
|
+
* which refuses a file outside the turn's worktree, its citizen's home, and the system temp
|
|
11989
|
+
* folder, and anything but a PNG, JPEG, GIF, or WebP within the size limit; each refusal comes
|
|
11990
|
+
* back as a `BoardError` in the runner's words.
|
|
11991
|
+
*/
|
|
11992
|
+
async readTurnImage(actor, file) {
|
|
11993
|
+
const turn = this.host.runningTurns().find((each) => each.agent === actor.name && each.scope === actor.scope && each.thread === actor.thread && each.channel === actor.channel);
|
|
11994
|
+
if (turn === void 0) {
|
|
11995
|
+
throw new BoardError("INVALID_STATE", `${actor.name} has no turn running in this conversation to read ${file} from`);
|
|
11996
|
+
}
|
|
11997
|
+
const seat = this.seats.get(turn.runner);
|
|
11998
|
+
if (seat === void 0 || seat.send === null) {
|
|
11999
|
+
throw new RunnerAwayError(`runner ${turn.runner}, where the turn runs, is not connected`);
|
|
12000
|
+
}
|
|
12001
|
+
if (!seat.hello.imageReads) {
|
|
12002
|
+
throw new BoardError("INVALID_STATE", `runner ${seat.name}, where the turn runs, cannot read images yet; upgrade it`);
|
|
12003
|
+
}
|
|
12004
|
+
const image = TurnImageSchema.nullable().parse(await this.request(seat, (request) => ({ type: "image", request, read: { turnId: turn.turnId, path: file } }), FILE_TIMEOUT_MS));
|
|
12005
|
+
if (image === null) {
|
|
12006
|
+
throw new BoardError("INVALID_STATE", `the turn is no longer running on runner ${seat.name}`);
|
|
12007
|
+
}
|
|
12008
|
+
if (image.kind === "refused") {
|
|
12009
|
+
throw new BoardError(IMAGE_REFUSALS[image.why], image.detail);
|
|
12010
|
+
}
|
|
12011
|
+
return Buffer.from(image.content, "base64");
|
|
12012
|
+
}
|
|
11830
12013
|
/** The models a CLI offers, asked of a connected runner that has it; none when no runner has it. */
|
|
11831
12014
|
/**
|
|
11832
12015
|
* The connected runner a model list for `cli` comes from: the first of `prefer` that has the CLI,
|
|
@@ -12098,20 +12281,20 @@ async function handleMcpRequest(board2, actor, request, version) {
|
|
|
12098
12281
|
import { Hono as Hono3 } from "hono";
|
|
12099
12282
|
import { compress } from "hono/compress";
|
|
12100
12283
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
12101
|
-
import { z as
|
|
12284
|
+
import { z as z19, ZodError } from "zod";
|
|
12102
12285
|
|
|
12103
12286
|
// apps/server/dist/github-auth.js
|
|
12104
12287
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
12105
12288
|
import { Hono } from "hono";
|
|
12106
|
-
import { z as
|
|
12289
|
+
import { z as z18 } from "zod";
|
|
12107
12290
|
var SIGN_IN_TTL_MS = 30 * 24 * 36e5;
|
|
12108
12291
|
var STATE_TTL_MS = 10 * 6e4;
|
|
12109
12292
|
var MAX_STATES = 1e3;
|
|
12110
|
-
var TokenAnswerSchema =
|
|
12111
|
-
var GithubUserSchema =
|
|
12112
|
-
login:
|
|
12113
|
-
id:
|
|
12114
|
-
avatar_url:
|
|
12293
|
+
var TokenAnswerSchema = z18.object({ access_token: z18.string().min(1) });
|
|
12294
|
+
var GithubUserSchema = z18.object({
|
|
12295
|
+
login: z18.string().min(1),
|
|
12296
|
+
id: z18.number().int(),
|
|
12297
|
+
avatar_url: z18.string().optional()
|
|
12115
12298
|
});
|
|
12116
12299
|
function githubAvatar(url) {
|
|
12117
12300
|
try {
|
|
@@ -12586,19 +12769,19 @@ var ERROR_STATUS = {
|
|
|
12586
12769
|
INVALID_STATE: 409
|
|
12587
12770
|
};
|
|
12588
12771
|
var EVENT_PAGE = 100;
|
|
12589
|
-
var RetireBodySchema =
|
|
12590
|
-
var RunnerBodySchema =
|
|
12591
|
-
var EnrollmentApprovalSchema =
|
|
12592
|
-
var HomeRunnerBodySchema =
|
|
12593
|
-
var ModelBodySchema =
|
|
12594
|
-
var EffortBodySchema =
|
|
12595
|
-
var HistoryLimitSchema =
|
|
12596
|
-
var MessageIdsSchema =
|
|
12597
|
-
var TimezoneBodySchema =
|
|
12598
|
-
var ChannelBodySchema =
|
|
12772
|
+
var RetireBodySchema = z19.object({ reason: z19.string().min(1) });
|
|
12773
|
+
var RunnerBodySchema = z19.object({ name: NameSchema });
|
|
12774
|
+
var EnrollmentApprovalSchema = z19.object({ name: NameSchema });
|
|
12775
|
+
var HomeRunnerBodySchema = z19.object({ runner: NameSchema.nullable() });
|
|
12776
|
+
var ModelBodySchema = z19.object({ model: ModelNameSchema.nullable() });
|
|
12777
|
+
var EffortBodySchema = z19.object({ effort: EffortSchema.nullable() });
|
|
12778
|
+
var HistoryLimitSchema = z19.coerce.number().int().min(1).max(500);
|
|
12779
|
+
var MessageIdsSchema = z19.string().transform((ids) => ids.split(",").filter((id) => id !== "")).pipe(z19.array(UlidSchema).min(1).max(MESSAGE_LOOKUP_LIMIT));
|
|
12780
|
+
var TimezoneBodySchema = z19.object({ timezone: TimeZoneSchema });
|
|
12781
|
+
var ChannelBodySchema = z19.object({
|
|
12599
12782
|
project: NameSchema.nullable().default(null),
|
|
12600
12783
|
name: NameSchema,
|
|
12601
|
-
purpose:
|
|
12784
|
+
purpose: z19.string().min(1)
|
|
12602
12785
|
});
|
|
12603
12786
|
function bearer2(c) {
|
|
12604
12787
|
const header = c.req.header("authorization") ?? "";
|
|
@@ -12770,7 +12953,7 @@ function createApp(deps) {
|
|
|
12770
12953
|
});
|
|
12771
12954
|
api.put("/roles/:name", async (c) => {
|
|
12772
12955
|
const charter = RoleCharterSchema.parse({
|
|
12773
|
-
...
|
|
12956
|
+
...z19.record(z19.string(), z19.unknown()).parse(await c.req.json()),
|
|
12774
12957
|
name: c.req.param("name")
|
|
12775
12958
|
});
|
|
12776
12959
|
return c.json(await board2.setRoleCharter(c.get("actor"), charter));
|
|
@@ -12809,6 +12992,15 @@ function createApp(deps) {
|
|
|
12809
12992
|
return c.json(await deps.runners.branchDiff(task.project, `task/${task.id}`, BranchPathSchema.parse(c.req.param("path"))));
|
|
12810
12993
|
});
|
|
12811
12994
|
api.get("/tasks/:id/files/:path{.+}", (c) => taskFile(c, c.req.param("path")));
|
|
12995
|
+
api.get("/images/:id", async (c) => {
|
|
12996
|
+
const { type, bytes } = await board2.readImage(UlidSchema.parse(c.req.param("id")));
|
|
12997
|
+
return c.body(new Uint8Array(bytes), 200, {
|
|
12998
|
+
"content-type": IMAGE_MEDIA_TYPES[type],
|
|
12999
|
+
"cache-control": "private, max-age=31536000, immutable",
|
|
13000
|
+
"x-content-type-options": "nosniff",
|
|
13001
|
+
"content-security-policy": "default-src 'none'; sandbox"
|
|
13002
|
+
});
|
|
13003
|
+
});
|
|
12812
13004
|
api.get("/threads", async (c) => c.json(await board2.listThreads()));
|
|
12813
13005
|
api.get("/requests", async (c) => c.json(await board2.listRequests()));
|
|
12814
13006
|
api.get("/threads/:id", async (c) => {
|
|
@@ -13231,6 +13423,7 @@ var host = new TurnHost({
|
|
|
13231
13423
|
});
|
|
13232
13424
|
var runners = new RunnerHub({ board, host, version: VERSION, log });
|
|
13233
13425
|
board.watchTurns(() => host.inFlight());
|
|
13426
|
+
board.readImagesWith((actor, file) => runners.readTurnImage(actor, file));
|
|
13234
13427
|
var concurrency = config.concurrency ?? Number.POSITIVE_INFINITY;
|
|
13235
13428
|
var timings = parseTimings(JSON.parse(process.env["STELLARIS_TIMINGS"] ?? "{}"));
|
|
13236
13429
|
var scheduler = new Scheduler({ board, runner: runners, log, concurrency, timings });
|