@kubitnodes/stellaris 0.3.9 → 0.3.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/index.js +27 -11
- package/dist/server/index.js +100 -69
- package/package.json +1 -1
- package/web/dist/assets/{BackLink-1EUHNOu3.js → BackLink-B3tz8OFm.js} +1 -1
- package/web/dist/assets/{ChannelView-A47Rvstg.js → ChannelView-Dkzr1zkF.js} +1 -1
- package/web/dist/assets/{CitizenView-B_jG9N5w.js → CitizenView-BLgyEvYz.js} +1 -1
- package/web/dist/assets/{CitizensView-DdIHzcx3.js → CitizensView-DttP5FqR.js} +1 -1
- package/web/dist/assets/{KnowledgeView-CXRQ4igk.js → KnowledgeView-DFAC95aF.js} +1 -1
- package/web/dist/assets/{Markdown-B2tp7ki-.js → Markdown-4W4xjIq7.js} +1 -1
- package/web/dist/assets/{MessageItem-CWZ0X2Vr.js → MessageItem-Bfpve1_Y.js} +1 -1
- package/web/dist/assets/{MetricsView-7X3Cmybh.js → MetricsView-Bp486U0v.js} +1 -1
- package/web/dist/assets/{NeedsYouView-Pi1jBF8V.js → NeedsYouView-CJ4COcNn.js} +1 -1
- package/web/dist/assets/{Overview-C1leALP3.js → Overview-BnO1K52h.js} +1 -1
- package/web/dist/assets/{Pane-DxXjKLAj.js → Pane-xzIpwnBD.js} +1 -1
- package/web/dist/assets/{ProjectView-DFReelVz.js → ProjectView-w0mcF0KW.js} +1 -1
- package/web/dist/assets/{ProposalView-3L5osVUL.js → ProposalView-CyJCwUYK.js} +1 -1
- package/web/dist/assets/{ProposalsView-Uc6fp4bD.js → ProposalsView-XrraDhwt.js} +1 -1
- package/web/dist/assets/{RunnersView-D4pd3ArT.js → RunnersView-H3kCdSQB.js} +1 -1
- package/web/dist/assets/{SocietyView--buUCciX.js → SocietyView-Cf8ENDAw.js} +1 -1
- package/web/dist/assets/{SubjectThread-C811fit3.js → SubjectThread-ClMmgVVd.js} +1 -1
- package/web/dist/assets/{TaskFileView-dvFssKHp.js → TaskFileView-CRwwL5K8.js} +1 -1
- package/web/dist/assets/{TaskView-C-VIKoFp.js → TaskView-A9IgTxQ0.js} +1 -1
- package/web/dist/assets/{TasksView-BXqfwU5R.js → TasksView-CnhTIldG.js} +1 -1
- package/web/dist/assets/{ThreadCard-Bn7HfgDI.js → ThreadCard-fvf8cY_l.js} +1 -1
- package/web/dist/assets/{ThreadForms-CzYPjU1-.js → ThreadForms-D09Ykgj9.js} +1 -1
- package/web/dist/assets/{ThreadView-BioBQeqV.js → ThreadView-BqNSssCf.js} +1 -1
- package/web/dist/assets/{citizen-BqHxQY9q.js → citizen-C27Wvimj.js} +1 -1
- package/web/dist/assets/{format-Cc6KjiYZ.js → format-lz-5NQWT.js} +1 -1
- package/web/dist/assets/{index-WB0PqHlY.js → index-CoKyPk79.js} +3 -3
- package/web/dist/assets/{tasks-CbQrkZ1C.js → tasks-DK1cnXqs.js} +1 -1
- package/web/dist/assets/{useStickyScroll-NvlGfk6Z.js → useStickyScroll-CfP3Yl_4.js} +1 -1
- package/web/dist/index.html +3 -3
package/dist/cli/index.js
CHANGED
|
@@ -866,11 +866,12 @@ var ProjectRepoSchema = z6.object({
|
|
|
866
866
|
defaultBranch: z6.string().min(1)
|
|
867
867
|
});
|
|
868
868
|
var TurnWorkspaceSchema = z6.discriminatedUnion("kind", [
|
|
869
|
-
z6.object({ kind: z6.literal("home") }),
|
|
869
|
+
z6.object({ kind: z6.literal("home"), thread: UlidSchema.optional() }),
|
|
870
870
|
z6.object({
|
|
871
871
|
kind: z6.literal("project"),
|
|
872
872
|
repo: ProjectRepoSchema,
|
|
873
|
-
branches: z6.array(z6.string().min(1))
|
|
873
|
+
branches: z6.array(z6.string().min(1)),
|
|
874
|
+
thread: UlidSchema.optional()
|
|
874
875
|
}),
|
|
875
876
|
z6.object({ kind: z6.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
876
877
|
]);
|
|
@@ -921,7 +922,7 @@ var TurnOutcomeSchema = z6.object({
|
|
|
921
922
|
model: z6.string().nullable(),
|
|
922
923
|
work: TurnWorkSchema.nullable()
|
|
923
924
|
});
|
|
924
|
-
var TurnAckSchema = z6.object({
|
|
925
|
+
var TurnAckSchema = z6.object({ dropWorkspace: z6.boolean() });
|
|
925
926
|
var LandRequestSchema = z6.object({
|
|
926
927
|
repo: ProjectRepoSchema,
|
|
927
928
|
branch: z6.string().min(1)
|
|
@@ -1300,7 +1301,7 @@ var RunnerConfigSchema = z10.object({
|
|
|
1300
1301
|
});
|
|
1301
1302
|
|
|
1302
1303
|
// packages/shared/dist/version.js
|
|
1303
|
-
var STELLARIS_VERSION = "0.3.
|
|
1304
|
+
var STELLARIS_VERSION = "0.3.10";
|
|
1304
1305
|
|
|
1305
1306
|
// packages/board-core/dist/errors.js
|
|
1306
1307
|
var BoardError = class extends Error {
|
|
@@ -1345,15 +1346,28 @@ async function writeJson(file, value) {
|
|
|
1345
1346
|
await writeFileAtomic(file, `${JSON.stringify(value, null, 2)}
|
|
1346
1347
|
`);
|
|
1347
1348
|
}
|
|
1349
|
+
function parseMatter(raw) {
|
|
1350
|
+
return matter(raw, {});
|
|
1351
|
+
}
|
|
1348
1352
|
async function readMarkdown(file, schema) {
|
|
1349
1353
|
const raw = await readFile(file, "utf8");
|
|
1350
|
-
const parsed =
|
|
1354
|
+
const parsed = parseMatter(raw);
|
|
1351
1355
|
return { data: schema.parse(parsed.data), body: parsed.content.replace(/^\n/, "") };
|
|
1352
1356
|
}
|
|
1357
|
+
async function readLooseMarkdown(file) {
|
|
1358
|
+
const raw = await readFile(file, "utf8");
|
|
1359
|
+
try {
|
|
1360
|
+
const parsed = parseMatter(raw);
|
|
1361
|
+
return { data: parsed.data, body: parsed.content.replace(/^\n/, ""), error: null };
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
const reason = (error instanceof Error ? error.message : String(error)).split("\n")[0] ?? "";
|
|
1364
|
+
return { data: {}, body: raw, error: reason.replace(/:$/, "") };
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1353
1367
|
async function writeMarkdown(file, data, body) {
|
|
1354
1368
|
const normalized = body.endsWith("\n") || body.length === 0 ? body : `${body}
|
|
1355
1369
|
`;
|
|
1356
|
-
await writeFileAtomic(file, matter.stringify(normalized, data));
|
|
1370
|
+
await writeFileAtomic(file, matter.stringify({ content: normalized }, data, {}));
|
|
1357
1371
|
}
|
|
1358
1372
|
function isMissing(error) {
|
|
1359
1373
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
@@ -3205,7 +3219,7 @@ ${charter.purpose}
|
|
|
3205
3219
|
}
|
|
3206
3220
|
async readProfile(name) {
|
|
3207
3221
|
const file = this.paths.agentProfile(name);
|
|
3208
|
-
return await exists(file) ? (await
|
|
3222
|
+
return await exists(file) ? (await readLooseMarkdown(file)).body : "";
|
|
3209
3223
|
}
|
|
3210
3224
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
3211
3225
|
async readSocietyNorms() {
|
|
@@ -3252,10 +3266,11 @@ ${charter.purpose}
|
|
|
3252
3266
|
if (!name.success) {
|
|
3253
3267
|
continue;
|
|
3254
3268
|
}
|
|
3255
|
-
const doc = await
|
|
3269
|
+
const doc = await readLooseMarkdown(file);
|
|
3256
3270
|
skills.push({
|
|
3257
3271
|
name: name.data,
|
|
3258
|
-
|
|
3272
|
+
// The index is where its writer sees that the file needs fixing.
|
|
3273
|
+
summary: doc.error === null ? skillSummary(doc.data, doc.body) : `its frontmatter does not parse (${doc.error}), so fix the file`,
|
|
3259
3274
|
scope,
|
|
3260
3275
|
path: file
|
|
3261
3276
|
});
|
|
@@ -4917,7 +4932,7 @@ ${rationale}`}`);
|
|
|
4917
4932
|
}
|
|
4918
4933
|
async readMemoryCore(agent2) {
|
|
4919
4934
|
const file = this.paths.agentMemoryCore(agent2);
|
|
4920
|
-
return await exists(file) ? (await
|
|
4935
|
+
return await exists(file) ? (await readLooseMarkdown(file)).body : "";
|
|
4921
4936
|
}
|
|
4922
4937
|
/**
|
|
4923
4938
|
* Moves a conversation's cursor forward to `cursor` once a turn there has delivered up to it. It
|
|
@@ -5132,7 +5147,8 @@ ${rationale}`}`);
|
|
|
5132
5147
|
if (!await exists(file)) {
|
|
5133
5148
|
return { data: { project: slug }, body: "" };
|
|
5134
5149
|
}
|
|
5135
|
-
|
|
5150
|
+
const { data, body } = await readLooseMarkdown(file);
|
|
5151
|
+
return { data, body };
|
|
5136
5152
|
}
|
|
5137
5153
|
async listRunners() {
|
|
5138
5154
|
const runners = [];
|
package/dist/server/index.js
CHANGED
|
@@ -899,11 +899,12 @@ var ProjectRepoSchema = z6.object({
|
|
|
899
899
|
defaultBranch: z6.string().min(1)
|
|
900
900
|
});
|
|
901
901
|
var TurnWorkspaceSchema = z6.discriminatedUnion("kind", [
|
|
902
|
-
z6.object({ kind: z6.literal("home") }),
|
|
902
|
+
z6.object({ kind: z6.literal("home"), thread: UlidSchema.optional() }),
|
|
903
903
|
z6.object({
|
|
904
904
|
kind: z6.literal("project"),
|
|
905
905
|
repo: ProjectRepoSchema,
|
|
906
|
-
branches: z6.array(z6.string().min(1))
|
|
906
|
+
branches: z6.array(z6.string().min(1)),
|
|
907
|
+
thread: UlidSchema.optional()
|
|
907
908
|
}),
|
|
908
909
|
z6.object({ kind: z6.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
909
910
|
]);
|
|
@@ -954,7 +955,7 @@ var TurnOutcomeSchema = z6.object({
|
|
|
954
955
|
model: z6.string().nullable(),
|
|
955
956
|
work: TurnWorkSchema.nullable()
|
|
956
957
|
});
|
|
957
|
-
var TurnAckSchema = z6.object({
|
|
958
|
+
var TurnAckSchema = z6.object({ dropWorkspace: z6.boolean() });
|
|
958
959
|
var LandRequestSchema = z6.object({
|
|
959
960
|
repo: ProjectRepoSchema,
|
|
960
961
|
branch: z6.string().min(1)
|
|
@@ -1381,7 +1382,7 @@ var RunnerConfigSchema = z10.object({
|
|
|
1381
1382
|
});
|
|
1382
1383
|
|
|
1383
1384
|
// packages/shared/dist/version.js
|
|
1384
|
-
var STELLARIS_VERSION = "0.3.
|
|
1385
|
+
var STELLARIS_VERSION = "0.3.10";
|
|
1385
1386
|
|
|
1386
1387
|
// packages/board-core/dist/errors.js
|
|
1387
1388
|
var BoardError = class extends Error {
|
|
@@ -1429,15 +1430,28 @@ async function writeJson(file, value) {
|
|
|
1429
1430
|
await writeFileAtomic(file, `${JSON.stringify(value, null, 2)}
|
|
1430
1431
|
`);
|
|
1431
1432
|
}
|
|
1433
|
+
function parseMatter(raw) {
|
|
1434
|
+
return matter(raw, {});
|
|
1435
|
+
}
|
|
1432
1436
|
async function readMarkdown(file, schema) {
|
|
1433
1437
|
const raw = await readFile(file, "utf8");
|
|
1434
|
-
const parsed =
|
|
1438
|
+
const parsed = parseMatter(raw);
|
|
1435
1439
|
return { data: schema.parse(parsed.data), body: parsed.content.replace(/^\n/, "") };
|
|
1436
1440
|
}
|
|
1441
|
+
async function readLooseMarkdown(file) {
|
|
1442
|
+
const raw = await readFile(file, "utf8");
|
|
1443
|
+
try {
|
|
1444
|
+
const parsed = parseMatter(raw);
|
|
1445
|
+
return { data: parsed.data, body: parsed.content.replace(/^\n/, ""), error: null };
|
|
1446
|
+
} catch (error) {
|
|
1447
|
+
const reason = (error instanceof Error ? error.message : String(error)).split("\n")[0] ?? "";
|
|
1448
|
+
return { data: {}, body: raw, error: reason.replace(/:$/, "") };
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1437
1451
|
async function writeMarkdown(file, data, body) {
|
|
1438
1452
|
const normalized2 = body.endsWith("\n") || body.length === 0 ? body : `${body}
|
|
1439
1453
|
`;
|
|
1440
|
-
await writeFileAtomic(file, matter.stringify(normalized2, data));
|
|
1454
|
+
await writeFileAtomic(file, matter.stringify({ content: normalized2 }, data, {}));
|
|
1441
1455
|
}
|
|
1442
1456
|
function isMissing(error) {
|
|
1443
1457
|
return typeof error === "object" && error !== null && error.code === "ENOENT";
|
|
@@ -3289,7 +3303,7 @@ ${charter.purpose}
|
|
|
3289
3303
|
}
|
|
3290
3304
|
async readProfile(name) {
|
|
3291
3305
|
const file = this.paths.agentProfile(name);
|
|
3292
|
-
return await exists(file) ? (await
|
|
3306
|
+
return await exists(file) ? (await readLooseMarkdown(file)).body : "";
|
|
3293
3307
|
}
|
|
3294
3308
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
3295
3309
|
async readSocietyNorms() {
|
|
@@ -3336,10 +3350,11 @@ ${charter.purpose}
|
|
|
3336
3350
|
if (!name.success) {
|
|
3337
3351
|
continue;
|
|
3338
3352
|
}
|
|
3339
|
-
const doc = await
|
|
3353
|
+
const doc = await readLooseMarkdown(file);
|
|
3340
3354
|
skills.push({
|
|
3341
3355
|
name: name.data,
|
|
3342
|
-
|
|
3356
|
+
// The index is where its writer sees that the file needs fixing.
|
|
3357
|
+
summary: doc.error === null ? skillSummary(doc.data, doc.body) : `its frontmatter does not parse (${doc.error}), so fix the file`,
|
|
3343
3358
|
scope,
|
|
3344
3359
|
path: file
|
|
3345
3360
|
});
|
|
@@ -5001,7 +5016,7 @@ ${rationale}`}`);
|
|
|
5001
5016
|
}
|
|
5002
5017
|
async readMemoryCore(agent) {
|
|
5003
5018
|
const file = this.paths.agentMemoryCore(agent);
|
|
5004
|
-
return await exists(file) ? (await
|
|
5019
|
+
return await exists(file) ? (await readLooseMarkdown(file)).body : "";
|
|
5005
5020
|
}
|
|
5006
5021
|
/**
|
|
5007
5022
|
* Moves a conversation's cursor forward to `cursor` once a turn there has delivered up to it. It
|
|
@@ -5216,7 +5231,8 @@ ${rationale}`}`);
|
|
|
5216
5231
|
if (!await exists(file)) {
|
|
5217
5232
|
return { data: { project: slug }, body: "" };
|
|
5218
5233
|
}
|
|
5219
|
-
|
|
5234
|
+
const { data, body } = await readLooseMarkdown(file);
|
|
5235
|
+
return { data, body };
|
|
5220
5236
|
}
|
|
5221
5237
|
async listRunners() {
|
|
5222
5238
|
const runners2 = [];
|
|
@@ -6503,7 +6519,10 @@ var Scheduler = class {
|
|
|
6503
6519
|
now;
|
|
6504
6520
|
log;
|
|
6505
6521
|
pending = /* @__PURE__ */ new Map();
|
|
6506
|
-
/**
|
|
6522
|
+
/**
|
|
6523
|
+
* Turns in flight by session key. A conversation runs one turn at a time, and different
|
|
6524
|
+
* conversations side by side, since each thread's works in a place of its own.
|
|
6525
|
+
*/
|
|
6507
6526
|
running = /* @__PURE__ */ new Map();
|
|
6508
6527
|
/** Steers under way, by session key; a pass does not wait for a runner to answer one. */
|
|
6509
6528
|
steering = /* @__PURE__ */ new Map();
|
|
@@ -6560,7 +6579,7 @@ var Scheduler = class {
|
|
|
6560
6579
|
}
|
|
6561
6580
|
await this.passing?.catch(() => void 0);
|
|
6562
6581
|
await Promise.allSettled([
|
|
6563
|
-
...
|
|
6582
|
+
...this.running.values(),
|
|
6564
6583
|
...this.completing,
|
|
6565
6584
|
...this.steering.values()
|
|
6566
6585
|
]);
|
|
@@ -6610,7 +6629,7 @@ var Scheduler = class {
|
|
|
6610
6629
|
async drain() {
|
|
6611
6630
|
await Promise.allSettled([
|
|
6612
6631
|
...this.steering.values(),
|
|
6613
|
-
...
|
|
6632
|
+
...this.running.values(),
|
|
6614
6633
|
...this.completing
|
|
6615
6634
|
]);
|
|
6616
6635
|
}
|
|
@@ -7228,7 +7247,7 @@ var Scheduler = class {
|
|
|
7228
7247
|
continue;
|
|
7229
7248
|
}
|
|
7230
7249
|
const key = sessionKey(agent.name, latest.scope);
|
|
7231
|
-
if (this.pending.has(key) || this.
|
|
7250
|
+
if (this.pending.has(key) || this.running.has(key)) {
|
|
7232
7251
|
continue;
|
|
7233
7252
|
}
|
|
7234
7253
|
this.state.lastReflection[agent.name] = iso(now);
|
|
@@ -7526,22 +7545,6 @@ var Scheduler = class {
|
|
|
7526
7545
|
this.state.costSinceReport = 0;
|
|
7527
7546
|
this.state.turnsSinceReport = 0;
|
|
7528
7547
|
}
|
|
7529
|
-
/**
|
|
7530
|
-
* The lane a turn runs in: a task's conversation has its own, with a worktree of its own; a
|
|
7531
|
-
* member's home conversation and its proposal and topic threads in a scope share the scope's
|
|
7532
|
-
* worktree, and so one lane, one turn at a time.
|
|
7533
|
-
*/
|
|
7534
|
-
laneOf(dispatch) {
|
|
7535
|
-
return dispatch.thread?.task === true ? sessionKey(dispatch.agent, dispatch.project, dispatch.thread.id) : sessionKey(dispatch.agent, dispatch.project);
|
|
7536
|
-
}
|
|
7537
|
-
laneBusy(lane) {
|
|
7538
|
-
for (const turn of this.running.values()) {
|
|
7539
|
-
if (turn.lane === lane) {
|
|
7540
|
-
return true;
|
|
7541
|
-
}
|
|
7542
|
-
}
|
|
7543
|
-
return false;
|
|
7544
|
-
}
|
|
7545
7548
|
/**
|
|
7546
7549
|
* Delivers ready message wakes into the turn already running in their conversation, rather than
|
|
7547
7550
|
* keeping them for a turn of their own. Each stays queued until that turn ends and is checked
|
|
@@ -7592,10 +7595,6 @@ var Scheduler = class {
|
|
|
7592
7595
|
if (this.running.size >= this.concurrency) {
|
|
7593
7596
|
break;
|
|
7594
7597
|
}
|
|
7595
|
-
const lane = this.laneOf(item.dispatch);
|
|
7596
|
-
if (this.laneBusy(lane)) {
|
|
7597
|
-
continue;
|
|
7598
|
-
}
|
|
7599
7598
|
this.pending.delete(key);
|
|
7600
7599
|
if (await this.alreadyRead(item)) {
|
|
7601
7600
|
this.log.info({ agent: item.dispatch.agent, project: item.dispatch.project }, "dropping message wake, its conversation has read the message");
|
|
@@ -7636,7 +7635,7 @@ var Scheduler = class {
|
|
|
7636
7635
|
this.running.delete(key);
|
|
7637
7636
|
}
|
|
7638
7637
|
})();
|
|
7639
|
-
this.running.set(key,
|
|
7638
|
+
this.running.set(key, promise);
|
|
7640
7639
|
}
|
|
7641
7640
|
}
|
|
7642
7641
|
/** Starts each queued completion once the turn that finished the task's last stage has ended. */
|
|
@@ -7669,7 +7668,7 @@ import { randomUUID } from "node:crypto";
|
|
|
7669
7668
|
var TURN_CONTRACT = [
|
|
7670
7669
|
"- Every turn belongs to one conversation, named at the top of your prompt: your home conversation in a project or the society, for its channels and for work tied to no thread, or the conversation of one thread you take part in, a task's, a proposal's, or a topic's. Each has its own session and its own turns, which may run while this one does. The prompt carries this conversation only: in a thread, its new messages, or the whole thread when the conversation is new, and in a task's thread the task and its stage; at home, the channel messages that concern you. Read anything else you need with get_task, search, and the board's files, and leave other threads' and other projects' work to their own turns.",
|
|
7671
7670
|
"- Act through the board tools (the `board` MCP server). Holding a stage is a lease; every turn that touches the task renews it.",
|
|
7672
|
-
"- Work only inside your worktree. In a task's conversation it is a worktree of its own on the task's branch `task/<id>`: commit your work there. After each turn the runner commits what you left on the branch and lets it go for the next holder. Your home worktree is on your own branch, `agent/<name>`, for work tied to no task.",
|
|
7671
|
+
"- Work only inside your worktree. In a task's conversation it is a worktree of its own on the task's branch `task/<id>`: commit your work there. After each turn the runner commits what you left on the branch and lets it go for the next holder. Your home worktree is on your own branch, `agent/<name>`, for work tied to no task. In a proposal's or a topic's conversation it is a worktree of its own, detached at your own branch's tip, which goes when the thread closes, so work that should last goes on a task's branch.",
|
|
7673
7672
|
"- Posts that would wake this conversation may arrive while you work, delivered into the turn under a heading that says so and formatted like the digest. They are part of this turn: act on them now, after the step in hand, or not at all, as with the digest. The user may also stop a turn; the next turn is told.",
|
|
7674
7673
|
"- Silence is allowed. If the digest needs no reply, post nothing.",
|
|
7675
7674
|
"- 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. @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.",
|
|
@@ -7734,7 +7733,7 @@ function renderInstructions(input) {
|
|
|
7734
7733
|
if (norms.length > 0) {
|
|
7735
7734
|
sections.push("", "## Society norms", "", norms);
|
|
7736
7735
|
}
|
|
7737
|
-
sections.push("", "## Core memory", "", memory.length === 0 ? "(empty)" : memory, "", "## Skills", "", ...renderSkillsIndex(input.skills ?? []), "", "## Where things are", "", `- Your home directory: ${input.homeDir}. memory/core.md is loaded every turn; memory/<topic>.md is your archive; skills/<name>/SKILL.md are your skills; projects/<slug>/notes.md are your notes. You may read and write all of it, and the board's search covers your archive and skills for you alone. The runner keeps it in git and shares it with the board after every turn, so whatever machine your next turn runs on has it; leave git there to the runner. Files over ${HOME_FILE_LIMIT_BYTES / (1024 * 1024)} MB are not kept.`, `- ${HOME_SCRATCH}/ in your home is your working folder in turns outside any project: it is
|
|
7736
|
+
sections.push("", "## Core memory", "", memory.length === 0 ? "(empty)" : memory, "", "## Skills", "", ...renderSkillsIndex(input.skills ?? []), "", "## Where things are", "", `- Your home directory: ${input.homeDir}. memory/core.md is loaded every turn; memory/<topic>.md is your archive; skills/<name>/SKILL.md are your skills; projects/<slug>/notes.md are your notes. You may read and write all of it, and the board's search covers your archive and skills for you alone. The runner keeps it in git and shares it with the board after every turn, so whatever machine your next turn runs on has it; leave git there to the runner. Files over ${HOME_FILE_LIMIT_BYTES / (1024 * 1024)} MB are not kept.`, `- ${HOME_SCRATCH}/ in your home is your working folder in turns outside any project, and a thread's conversation there works in a folder of its own inside it, which goes when the thread closes: none of it is kept or shared, so put downloads, environments, and other working files there, and keep the rest of your home for what you mean to remember.`, `- The board projection: ${input.boardDir} (read-only markdown: society and project channels, tasks, threads; shared knowledge under projects/<slug>/knowledge/ and society/knowledge/; the society's skills under society/skills/). Search it with your file tools; act through the board tools.`, "", "## Turn contract", "", TURN_CONTRACT, "", "## Planning", "", PLANNING, "", "## Governance", "", GOVERNANCE);
|
|
7738
7737
|
if (input.onboarding !== void 0) {
|
|
7739
7738
|
sections.push("", "## First turn", "", renderOnboardingPreamble(input.onboarding));
|
|
7740
7739
|
}
|
|
@@ -8066,7 +8065,7 @@ var TurnHost = class {
|
|
|
8066
8065
|
const societyScope = dispatch.project === SOCIETY_SCOPE;
|
|
8067
8066
|
const taskId = thread?.task === true ? thread.id : void 0;
|
|
8068
8067
|
const project = societyScope ? null : await this.board.readProject(dispatch.project);
|
|
8069
|
-
const workspace = await this.workspaceOf(project,
|
|
8068
|
+
const workspace = await this.workspaceOf(project, thread);
|
|
8070
8069
|
const sessions = await this.board.readSessions(agent.name, dispatch.project, thread?.id);
|
|
8071
8070
|
const recorded = sessions.runner === runner.name ? sessions[agent.cli] : void 0;
|
|
8072
8071
|
const newSession = recorded === void 0;
|
|
@@ -8178,7 +8177,8 @@ var TurnHost = class {
|
|
|
8178
8177
|
void this.board.heldClaims(agent.name).then((claims) => this.renewLeases(actor, claims.filter((each) => each.project === dispatch.project).map((each) => each.id))).catch(() => void 0);
|
|
8179
8178
|
}, LEASE_RENEW_MS);
|
|
8180
8179
|
keepLeases.unref?.();
|
|
8181
|
-
const { promise: ended, resolve: done } = Promise.withResolvers();
|
|
8180
|
+
const { promise: ended, resolve: done, reject: fail } = Promise.withResolvers();
|
|
8181
|
+
ended.catch(() => void 0);
|
|
8182
8182
|
this.open.set(record.id, {
|
|
8183
8183
|
job,
|
|
8184
8184
|
runner: runner.name,
|
|
@@ -8189,14 +8189,14 @@ var TurnHost = class {
|
|
|
8189
8189
|
outstanding: null,
|
|
8190
8190
|
stopRequestedBy: null,
|
|
8191
8191
|
held: held.map((each) => each.id),
|
|
8192
|
-
taskId,
|
|
8193
8192
|
costSoFarUsd,
|
|
8194
8193
|
configuredModel: agent.model ?? null,
|
|
8195
8194
|
transcript: [],
|
|
8196
8195
|
coldToken: residentKey === null ? token : null,
|
|
8197
8196
|
residentKey: residentKey === null ? null : `${runner.name}|${residentKey}`,
|
|
8198
8197
|
keepLeases,
|
|
8199
|
-
done
|
|
8198
|
+
done,
|
|
8199
|
+
fail
|
|
8200
8200
|
});
|
|
8201
8201
|
this.log.info({
|
|
8202
8202
|
agent: agent.name,
|
|
@@ -8335,7 +8335,7 @@ var TurnHost = class {
|
|
|
8335
8335
|
}
|
|
8336
8336
|
/**
|
|
8337
8337
|
* Records a turn's end from its outcome. Returns null for a turn the host does not know, else
|
|
8338
|
-
* whether the task the turn worked
|
|
8338
|
+
* whether the task or thread the turn worked in has ended, so the runner may drop its workspace.
|
|
8339
8339
|
*/
|
|
8340
8340
|
async closeTurn(turnId, outcome) {
|
|
8341
8341
|
const turn = this.open.get(turnId);
|
|
@@ -8348,9 +8348,6 @@ var TurnHost = class {
|
|
|
8348
8348
|
this.board.revokeTurnToken(turn.coldToken);
|
|
8349
8349
|
}
|
|
8350
8350
|
const { job } = turn;
|
|
8351
|
-
if (outcome.session !== job.session) {
|
|
8352
|
-
await this.board.writeSession(job.agent, job.scope, job.cli, outcome.session, turn.runner, job.thread);
|
|
8353
|
-
}
|
|
8354
8351
|
const finished = {
|
|
8355
8352
|
...turn.record,
|
|
8356
8353
|
session: outcome.session,
|
|
@@ -8366,17 +8363,29 @@ var TurnHost = class {
|
|
|
8366
8363
|
...outcome.work === null ? {} : { work: outcome.work },
|
|
8367
8364
|
...outcome.exitReason === "stopped" ? { stoppedBy: turn.stopRequestedBy ?? USER_NAME } : {}
|
|
8368
8365
|
};
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8366
|
+
const recorded = await this.recorded(turn, async () => {
|
|
8367
|
+
if (outcome.session !== job.session) {
|
|
8368
|
+
await this.board.writeSession(job.agent, job.scope, job.cli, outcome.session, turn.runner, job.thread);
|
|
8369
|
+
}
|
|
8370
|
+
if (outcome.exitReason === "completed" || outcome.exitReason === "blocked" || outcome.exitReason === "stopped") {
|
|
8371
|
+
await this.board.setDigestCursor(job.agent, job.scope, turn.delivered, job.thread);
|
|
8372
|
+
await this.renewLeases(turn.actor, turn.held);
|
|
8373
|
+
if (outcome.status?.needsUserDecision === true) {
|
|
8374
|
+
await this.askUser(turn.actor, job.scope, job.thread, turn.record.startedAt, outcome.status.summary);
|
|
8375
|
+
}
|
|
8374
8376
|
}
|
|
8377
|
+
await this.board.finishTurn(finished, turn.transcript);
|
|
8378
|
+
});
|
|
8379
|
+
if (recorded) {
|
|
8380
|
+
this.log.info({
|
|
8381
|
+
agent: job.agent,
|
|
8382
|
+
project: job.scope,
|
|
8383
|
+
thread: job.thread,
|
|
8384
|
+
exitReason: finished.exitReason
|
|
8385
|
+
}, "turn finished");
|
|
8386
|
+
turn.done(finished);
|
|
8375
8387
|
}
|
|
8376
|
-
await this.
|
|
8377
|
-
this.log.info({ agent: job.agent, project: job.scope, thread: job.thread, exitReason: finished.exitReason }, "turn finished");
|
|
8378
|
-
turn.done(finished);
|
|
8379
|
-
return { dropWorktree: await this.taskEnded(turn.taskId) };
|
|
8388
|
+
return { dropWorkspace: await this.conversationEnded(job) };
|
|
8380
8389
|
}
|
|
8381
8390
|
/** Ends a turn whose outcome will never come, as when its runner went away, as failed. */
|
|
8382
8391
|
async abortTurn(turnId, reason) {
|
|
@@ -8396,9 +8405,26 @@ var TurnHost = class {
|
|
|
8396
8405
|
error: reason,
|
|
8397
8406
|
toolCalls: turn.transcript.filter((entry) => entry.event.type === "tool_call").length
|
|
8398
8407
|
};
|
|
8399
|
-
await this.board.finishTurn(finished, turn.transcript)
|
|
8400
|
-
|
|
8401
|
-
|
|
8408
|
+
if (await this.recorded(turn, () => this.board.finishTurn(finished, turn.transcript))) {
|
|
8409
|
+
this.log.warn({ agent: turn.job.agent, project: turn.job.scope, reason }, "turn aborted");
|
|
8410
|
+
turn.done(finished);
|
|
8411
|
+
}
|
|
8412
|
+
}
|
|
8413
|
+
/**
|
|
8414
|
+
* Records the end of a turn already taken out of `open`, and says whether it could. The scheduler
|
|
8415
|
+
* holds the turn's conversation until the turn ends, and nothing would end it once it has left
|
|
8416
|
+
* `open`, so a turn whose end could not be recorded ends with the error rather than holding its
|
|
8417
|
+
* conversation for good.
|
|
8418
|
+
*/
|
|
8419
|
+
async recorded(turn, record) {
|
|
8420
|
+
try {
|
|
8421
|
+
await record();
|
|
8422
|
+
return true;
|
|
8423
|
+
} catch (error) {
|
|
8424
|
+
this.log.error({ agent: turn.job.agent, project: turn.job.scope, error: String(error) }, "could not record the end of a turn");
|
|
8425
|
+
turn.fail(error);
|
|
8426
|
+
return false;
|
|
8427
|
+
}
|
|
8402
8428
|
}
|
|
8403
8429
|
/** Records a turn that could never start, as when no runner could take its agent's CLI. */
|
|
8404
8430
|
async refuseTurn(dispatch, runner, reason) {
|
|
@@ -8451,29 +8477,34 @@ var TurnHost = class {
|
|
|
8451
8477
|
this.residentTokens.set(slot, token);
|
|
8452
8478
|
return token;
|
|
8453
8479
|
}
|
|
8454
|
-
|
|
8480
|
+
/** Where a conversation works: a task's on its branch, any other thread's in a place of its own. */
|
|
8481
|
+
async workspaceOf(project, thread) {
|
|
8482
|
+
const own = thread === void 0 || thread.task ? {} : { thread: thread.id };
|
|
8455
8483
|
if (project === null) {
|
|
8456
|
-
return { kind: "home" };
|
|
8484
|
+
return { kind: "home", ...own };
|
|
8457
8485
|
}
|
|
8458
8486
|
const repo = {
|
|
8459
8487
|
slug: project.slug,
|
|
8460
8488
|
origin: project.repo,
|
|
8461
8489
|
defaultBranch: project.defaultBranch
|
|
8462
8490
|
};
|
|
8463
|
-
if (
|
|
8464
|
-
return { kind: "task", repo, taskId };
|
|
8491
|
+
if (thread?.task === true) {
|
|
8492
|
+
return { kind: "task", repo, taskId: thread.id };
|
|
8465
8493
|
}
|
|
8466
8494
|
const branches = (await this.board.listTasks(project.slug)).filter((task) => task.status === "open" || task.status === "claimed").map((task) => `task/${task.id}`);
|
|
8467
|
-
return { kind: "project", repo, branches };
|
|
8495
|
+
return { kind: "project", repo, branches, ...own };
|
|
8468
8496
|
}
|
|
8469
|
-
/** Whether a
|
|
8470
|
-
async
|
|
8471
|
-
if (
|
|
8497
|
+
/** Whether a thread conversation's task or thread has ended, which frees its workspace. */
|
|
8498
|
+
async conversationEnded(job) {
|
|
8499
|
+
if (job.thread === void 0) {
|
|
8472
8500
|
return false;
|
|
8473
8501
|
}
|
|
8474
8502
|
try {
|
|
8475
|
-
|
|
8476
|
-
|
|
8503
|
+
if (job.workspace.kind === "task") {
|
|
8504
|
+
const { task } = await this.board.findTask(job.thread);
|
|
8505
|
+
return task.status === "done" || task.status === "abandoned";
|
|
8506
|
+
}
|
|
8507
|
+
return (await this.board.readThread(job.thread)).state === "closed";
|
|
8477
8508
|
} catch {
|
|
8478
8509
|
return false;
|
|
8479
8510
|
}
|
|
@@ -8676,7 +8707,7 @@ var RunnerHub = class {
|
|
|
8676
8707
|
async turnOutcome(runner, turnId, outcome) {
|
|
8677
8708
|
this.assertOwns(runner, turnId);
|
|
8678
8709
|
const ack = await this.host.closeTurn(turnId, outcome);
|
|
8679
|
-
return ack ?? {
|
|
8710
|
+
return ack ?? { dropWorkspace: false };
|
|
8680
8711
|
}
|
|
8681
8712
|
answer(runner, request, answer) {
|
|
8682
8713
|
const pending = this.pending.get(request);
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{b as e,ln as t,wt as n}from"./format-
|
|
1
|
+
import{b as e,ln as t,wt as n}from"./format-lz-5NQWT.js";import{L as r,S as i,n as a,r as o,t as s}from"./index-CoKyPk79.js";var c=t(),l=`grid size-7 shrink-0 place-items-center rounded-lg text-fg-tertiary hover:bg-surface-2/70 hover:text-fg-primary`;function u({fallback:t}){let u=n(),d=r({select:e=>e.location.state.__TSR_index}),f=o(),p=i(),m=e(),h=a(f,d);if(h===null)return t;let g=s(h,{entity:e=>p.get(e)?.title,project:e=>m.data?.find(t=>t.slug===e)?.name});return(0,c.jsx)(`button`,{type:`button`,onClick:()=>u.history.back(),"aria-label":`Back to ${g}`,title:`Back to ${g}`,className:l,children:`←`})}export{u as t};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{D as e,F as t,Ht as n,R as r,b as i,g as a,ln as o,pn as s,un as c,y as l}from"./format-
|
|
1
|
+
import{D as e,F as t,Ht as n,R as r,b as i,g as a,ln as o,pn as s,un as c,y as l}from"./format-lz-5NQWT.js";import{I as u,V as d,c as f,i as p}from"./index-CoKyPk79.js";import{t as m}from"./MessageItem-Bfpve1_Y.js";import{n as h,t as g}from"./Pane-xzIpwnBD.js";import{n as _}from"./ThreadCard-fvf8cY_l.js";import{i as v}from"./ThreadForms-D09Ykgj9.js";import{t as y}from"./useStickyScroll-CfP3Yl_4.js";var b=s(c(),1),x=o();function S(){let{_splat:e=`general`}=d({from:`/c/$`});return(0,x.jsx)(C,{channel:e},e)}function C({channel:o}){let{api:s}=e(),c=n({queryKey:[`channel`,o],queryFn:()=>s.channel(o)}),d=t(),S=a(),C=i(),w=l(3e4),[T,E]=(0,b.useState)(!1),D=(0,b.useMemo)(()=>{let e=(c.data??[]).map(e=>({kind:`message`,at:e.ts,id:e.id,message:e})),t=(d.data??[]).filter(e=>e.channel===o).map(e=>({kind:`thread`,at:e.openedAt,id:e.id,thread:e}));return[...e,...t].toSorted((e,t)=>e.at.localeCompare(t.at)||e.id.localeCompare(t.id))},[c.data,d.data,o]),O=c.data?.at(-1)?.id??null;(0,b.useEffect)(()=>u(o,O),[o,O]);let{ref:k,onScroll:A}=y(),[j,M]=o.split(`/`),N=M??j??o,P=M===void 0?void 0:C.data?.find(e=>e.slug===j),F=M===void 0?`society`:P?.name??j,I=P?.archived!==void 0,L=D.filter(e=>e.kind===`thread`&&e.thread.state===`open`);return(0,x.jsxs)(x.Fragment,{children:[(0,x.jsx)(g,{title:`# ${N}`,subtitle:`${F} · ${c.data?.length??0} messages${L.length>0?` · ${L.length} open threads`:``}`,trailing:T||I?null:(0,x.jsx)(f,{onClick:()=>E(!0),children:`New thread`})}),T?(0,x.jsx)(v,{channel:o,onDone:()=>E(!1)}):null,(0,x.jsx)(`div`,{ref:k,onScroll:A,className:`flex-1 overflow-y-auto py-2`,children:c.error instanceof r&&c.error.status===404?(0,x.jsxs)(h,{children:[`There is no channel `,o,`.`]}):c.data===void 0?(0,x.jsx)(h,{children:`Reading the channel…`}):D.length===0?(0,x.jsx)(h,{children:`Nothing has been said here yet.`}):D.map(e=>e.kind===`message`?(0,x.jsx)(m,{message:e.message,members:S.data,now:w},e.id):(0,x.jsx)(_,{thread:e.thread,now:w},e.id))}),c.data===void 0?null:I?(0,x.jsxs)(`p`,{className:`border-t border-line px-4 py-3 text-meta`,children:[F,` is archived, so its channels are read-only.`]}):(0,x.jsx)(p,{target:{channel:o},placeholder:`Message #${N}`})]})}export{S as ChannelView};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{D as e,E as t,H as n,I as r,L as i,P as a,R as o,T as s,_ as c,a as l,cn as u,ct as d,d as f,f as p,g as m,ln as h,o as g,p as _,pn as v,t as y,un as b,w as x,y as S}from"./format-
|
|
1
|
+
import{D as e,E as t,H as n,I as r,L as i,P as a,R as o,T as s,_ as c,a as l,cn as u,ct as d,d as f,f as p,g as m,ln as h,o as g,p as _,pn as v,t as y,un as b,w as x,y as S}from"./format-lz-5NQWT.js";import{B as C,H as w,R as T,S as E,T as D,V as ee,_ as te,c as O,f as k,g as ne,h as re,i as ie,m as A,p as j,v as M,x as N,y as P}from"./index-CoKyPk79.js";import{t as F}from"./Markdown-4W4xjIq7.js";import{n as I,t as ae}from"./Pane-xzIpwnBD.js";import{n as oe,r as L}from"./ThreadForms-D09Ykgj9.js";import{t as se}from"./useStickyScroll-CfP3Yl_4.js";import{a as R,c as ce,i as z,l as B,n as le,o as V,s as ue,t as de}from"./citizen-C27Wvimj.js";var H=v(b(),1),U=h(),fe={completed:`completed`,timeout:`timed out`,error:`failed`,interrupted:`was interrupted`,blocked:`was blocked`,stopped:`was stopped by you`};function W(e){return new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`,second:`2-digit`,hour12:!1})}function G({label:e,tone:t,children:n}){return(0,U.jsxs)(`div`,{children:[(0,U.jsx)(`p`,{className:`px-0.5 pb-0.5 text-[10px] tracking-wider text-fg-muted uppercase`,children:e}),(0,U.jsx)(`pre`,{className:`max-h-72 overflow-auto rounded-md bg-surface-0/60 p-2 font-mono text-[11px] leading-relaxed whitespace-pre-wrap break-words ${t}`,children:n})]})}function pe({step:e,open:t}){if(e.kind===`say`)return(0,U.jsx)(`li`,{className:`py-1.5 text-sm`,title:W(e.at),children:(0,U.jsx)(F,{text:e.text})});if(e.kind===`error`)return(0,U.jsx)(`li`,{className:`py-1 font-mono text-xs break-words text-red-400`,title:W(e.at),children:e.message});if(e.kind===`steer`)return(0,U.jsx)(`li`,{children:(0,U.jsxs)(`details`,{open:t,className:`group rounded-md open:bg-surface-2/30`,children:[(0,U.jsxs)(`summary`,{className:`flex cursor-pointer list-none items-center gap-2 rounded-md px-1.5 py-1 text-xs hover:bg-surface-2/40`,children:[(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`grid w-3 shrink-0 place-items-center text-sky-300`,children:`↳`}),(0,U.jsxs)(`span`,{className:`shrink-0 text-fg-tertiary`,children:[`Took `,re(e.posts.length)]}),(0,U.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-fg-secondary`,children:e.from.length===0?``:`from ${e.from.join(`, `)}, delivered mid-turn`}),(0,U.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-fg-muted`,children:W(e.at)})]}),(0,U.jsx)(`ul`,{className:`space-y-1.5 px-1.5 pb-1.5`,children:e.posts.map(e=>(0,U.jsxs)(`li`,{className:`rounded-md bg-surface-0/40 px-2.5 py-2`,children:[(0,U.jsxs)(`p`,{className:`flex gap-1.5 text-meta`,children:[(0,U.jsx)(`span`,{className:`text-fg-secondary`,children:e.author}),(0,U.jsxs)(`span`,{className:`min-w-0 truncate`,children:[`in `,e.where]}),e.at===``?null:(0,U.jsx)(`span`,{className:`ml-auto shrink-0 font-mono`,children:W(e.at)})]}),(0,U.jsx)(`div`,{className:`mt-1 text-sm`,children:(0,U.jsx)(F,{text:e.body})})]},`${e.at}-${e.author}`))})]})});let n=e.ok===null?(0,U.jsx)(`span`,{"aria-label":`running`,className:`size-1.5 animate-pulse rounded-full bg-amber-300`}):e.ok?(0,U.jsx)(`span`,{"aria-label":`succeeded`,className:`text-[11px] text-emerald-400`,children:`✓`}):(0,U.jsx)(`span`,{"aria-label":`failed`,className:`text-[11px] text-red-400`,children:`✕`});return(0,U.jsx)(`li`,{children:(0,U.jsxs)(`details`,{open:t,className:`group rounded-md open:bg-surface-2/30`,children:[(0,U.jsxs)(`summary`,{className:`flex cursor-pointer list-none items-center gap-2 rounded-md px-1.5 py-1 text-xs hover:bg-surface-2/40`,children:[(0,U.jsx)(`span`,{className:`grid w-3 shrink-0 place-items-center`,children:n}),(0,U.jsx)(`span`,{className:`shrink-0 font-mono text-fg-tertiary`,children:ne(e.name)}),(0,U.jsx)(`span`,{className:`min-w-0 flex-1 truncate font-mono text-fg-secondary`,children:e.summary}),(0,U.jsx)(`span`,{className:`shrink-0 font-mono text-[10px] text-fg-muted`,children:W(e.at)})]}),(0,U.jsxs)(`div`,{className:`space-y-1.5 px-1.5 pb-1.5`,children:[(0,U.jsx)(G,{label:`Input`,tone:`text-fg-secondary`,children:e.detail}),e.output===null?null:(0,U.jsx)(G,{label:e.ok===!1?`Returned an error`:`Returned`,tone:e.ok===!1?`text-red-300`:`text-fg-tertiary`,children:e.output})]})]})})}function K({steps:e}){let[t,n]=(0,H.useState)(!1),r=e.filter(e=>e.kind===`tool`).length;return e.length===0?(0,U.jsx)(`p`,{className:`mt-2 text-meta`,children:`No steps yet.`}):(0,U.jsxs)(U.Fragment,{children:[r===0?null:(0,U.jsxs)(`p`,{className:`mt-2 flex items-center gap-2 text-meta`,children:[r===1?`1 tool call`:`${r} tool calls`,(0,U.jsx)(`button`,{type:`button`,onClick:()=>n(!t),className:`rounded-md px-1.5 py-0.5 text-fg-tertiary transition-colors hover:bg-surface-2/60 hover:text-fg-primary`,children:t?`Collapse all`:`Expand all`})]}),(0,U.jsx)(`ol`,{className:`mt-1 space-y-0.5`,children:e.map(e=>(0,U.jsx)(pe,{step:e,open:t},e.seq))})]})}function me({turn:e,running:t,now:n}){return e.end===null?t?(0,U.jsxs)(`p`,{className:`mt-3 flex items-center gap-2 text-meta`,"aria-live":`polite`,children:[(0,U.jsx)(`span`,{className:`size-1.5 animate-pulse rounded-full bg-emerald-400`}),`Working · last step `,y(e.lastAt,n)]}):(0,U.jsx)(`p`,{className:`mt-3 text-meta`,children:`The turn ended without a report.`}):(0,U.jsxs)(`section`,{className:`mt-3 rounded-xl bg-surface-2/40 px-3.5 py-3 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.06)]`,children:[(0,U.jsxs)(`p`,{className:`text-caps`,children:[`The turn `,fe[e.end.exitReason],` `,y(e.end.at,n),e.fromStart?` · ${j(e.startedAt,Date.parse(e.end.at))}`:``]}),e.end.summary===null?null:(0,U.jsx)(`p`,{className:`mt-1 text-sm text-fg-secondary`,children:e.end.summary})]})}var q=30,he={turn:`turn`,board:`board`,merge:`both kept`},ge={turn:`Changed by a turn`,board:`Written by the board`,merge:`Both versions kept`};function _e(e){return e.status===`added`?`new`:e.status===`deleted`?`deleted`:e.added===null||e.removed===null?`binary`:`+${e.added} −${e.removed}`}function ve(e){return e.files.map(e=>`${e.path} ${_e(e)}`).join(`, `)}function ye(e){return e.startsWith(`@@`)||e.startsWith(`\\`)?`text-fg-muted`:e.startsWith(`+`)?`text-emerald-300`:e.startsWith(`-`)?`text-red-300`:`text-fg-tertiary`}function be({file:e}){return(0,U.jsxs)(`div`,{children:[(0,U.jsxs)(`p`,{className:`text-xs text-fg-secondary`,children:[e.path,e.status===`modified`?``:(0,U.jsxs)(`span`,{className:`text-fg-muted`,children:[` · `,e.status]})]}),e.patch===null?(0,U.jsx)(`p`,{className:`mt-1 text-meta`,children:`A binary file; its contents are not shown.`}):e.patch===``?(0,U.jsx)(`p`,{className:`mt-1 text-meta`,children:`Empty.`}):(0,U.jsx)(`pre`,{className:`mt-1 max-h-96 overflow-auto rounded-md bg-surface-0/60 p-2 font-mono text-[11px] leading-relaxed`,children:e.patch.split(`
|
|
2
2
|
`).map((e,t)=>(0,U.jsx)(`span`,{className:`block whitespace-pre-wrap break-words ${ye(e)}`,children:e===``?` `:e},t))}),e.truncated?(0,U.jsx)(`p`,{className:`mt-1 text-meta`,children:`The rest of this file's change is cut.`}):null]})}function xe({name:e,change:t}){let n=f(e,t.commit,!0);return(0,U.jsxs)(`div`,{className:`space-y-3 px-4 pt-1 pb-3`,children:[(0,U.jsxs)(`p`,{className:`text-xs text-fg-secondary`,children:[t.kind===`merge`?`Two turns on different runners changed the same lines at once. The file kept one turn's version, and this copy holds the other's until the citizen reconciles them.`:t.kind===`board`?`Written by the board: ${t.subject.replace(/^home: /,``)}.`:t.turnId===void 0?t.subject:(0,U.jsx)(T,{to:`/citizen/$name`,params:{name:e},search:{tab:`turns`,turn:t.turnId},className:`text-fg-secondary underline decoration-line underline-offset-2 hover:text-fg-primary`,children:`Open the turn that made it`}),(0,U.jsxs)(`span`,{className:`text-fg-muted`,children:[` · `,W(t.at)]})]}),n.data===void 0?(0,U.jsx)(`p`,{className:`text-meta`,children:n.isError?`Could not read the change.`:`Reading the change…`}):n.data.map(e=>(0,U.jsx)(be,{file:e},e.path))]})}function Se({name:e,change:t,now:n}){let[r,i]=(0,H.useState)(!1),a=t.files.length===0?t.subject:ve(t);return(0,U.jsx)(`li`,{className:`border-b border-line/60 last:border-b-0`,children:(0,U.jsxs)(`details`,{className:`group`,onToggle:e=>i(e.currentTarget.open),children:[(0,U.jsx)(`summary`,{"aria-label":`${ge[t.kind]} ${y(t.at,n)}: ${a}`,className:`block cursor-pointer list-none px-4 py-2.5 transition-colors hover:bg-surface-2/30 group-open:bg-surface-2/20`,children:(0,U.jsxs)(`span`,{className:`flex items-center gap-2 text-xs`,children:[(0,U.jsx)(`span`,{className:`shrink-0 text-fg-muted`,children:he[t.kind]}),(0,U.jsx)(`span`,{className:`min-w-0 flex-1 truncate text-fg-secondary`,children:a}),(0,U.jsx)(`span`,{className:`shrink-0 text-fg-muted`,children:y(t.at,n)}),(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`shrink-0 text-[10px] text-fg-muted transition-transform group-open:rotate-90`,children:`▸`})]})}),r?(0,U.jsx)(xe,{name:e,change:t}):null]})})}function Ce({name:e}){let[t,n]=(0,H.useState)(q),r=_(e,t),i=S(3e4);if(r.data===void 0)return(0,U.jsx)(I,{children:r.isError?`Could not read the home's history.`:`Reading the history…`});let{changes:a,more:o}=r.data;return a.length===0?(0,U.jsxs)(I,{children:[e,`'s home has no history yet; it starts with the citizen's first turn.`]}):(0,U.jsxs)(`div`,{className:`flex-1 overflow-y-auto`,children:[(0,U.jsxs)(`p`,{className:`px-4 pt-3 pb-1 text-meta`,children:[`What `,e,`'s turns changed in its memory, skills, and profile, newest first.`]}),(0,U.jsx)(`ol`,{children:a.map(t=>(0,U.jsx)(Se,{name:e,change:t,now:i},t.commit))}),o?(0,U.jsx)(`button`,{type:`button`,onClick:()=>n(t+q),className:`px-4 py-3 text-xs text-fg-tertiary hover:text-fg-primary`,children:`Show earlier changes`}):null]})}function J({title:e,children:t}){return(0,U.jsxs)(`section`,{className:`border-t border-line pt-4 first:border-t-0 first:pt-0`,children:[(0,U.jsx)(`h3`,{className:`text-section`,children:e}),(0,U.jsx)(`div`,{className:`mt-2`,children:t})]})}function we({member:e,charter:t}){let n=c(e.name),r=g(e.name),i=p(e.name),a=S(3e4);return(0,U.jsxs)(`div`,{className:`flex-1 space-y-5 overflow-y-auto px-4 py-4`,children:[i.data===void 0||i.data.length===0?null:(0,U.jsxs)(J,{title:`Edits to reconcile`,children:[(0,U.jsxs)(`p`,{className:`text-sm text-fg-secondary`,children:[`Two turns on different runners changed these files at once. Each file kept one version; the other waits beside it until `,e.name,` merges it in and deletes the copy.`]}),(0,U.jsx)(`ul`,{className:`mt-2 space-y-1.5`,children:i.data.map(e=>(0,U.jsxs)(`li`,{className:`text-sm`,children:[(0,U.jsx)(`span`,{className:`text-fg-primary`,children:e.file}),(0,U.jsxs)(`span`,{className:`text-meta`,children:[` `,`· `,e.path.slice(e.path.lastIndexOf(`/`)+1),` · left`,` `,y(e.since,a)]})]},e.path))})]}),(0,U.jsx)(J,{title:`Profile`,children:e.profile.trim()===``?(0,U.jsx)(`p`,{className:`text-meta`,children:`No profile yet. The citizen writes its own profile.md.`}):(0,U.jsx)(F,{text:B(e.profile,`Profile`)})}),(0,U.jsx)(J,{title:`Core memory`,children:n.data===void 0?(0,U.jsx)(`p`,{className:`text-meta`,children:`Reading…`}):n.data.body.trim()===``?(0,U.jsx)(`p`,{className:`text-meta`,children:`Empty. Every turn loads this file in full.`}):(0,U.jsx)(F,{text:B(n.data.body,`Core memory`)})}),(0,U.jsx)(J,{title:`Own skills`,children:r.data===void 0?(0,U.jsx)(`p`,{className:`text-meta`,children:`Reading…`}):r.data.length===0?(0,U.jsx)(`p`,{className:`text-meta`,children:`None yet.`}):(0,U.jsx)(`ul`,{className:`space-y-1.5`,children:r.data.map(e=>(0,U.jsxs)(`li`,{className:`text-sm`,children:[(0,U.jsx)(`span`,{className:`text-fg-primary`,children:e.name}),e.summary===``?null:(0,U.jsxs)(`span`,{className:`text-fg-secondary`,children:[` · `,e.summary]})]},e.name))})}),t===void 0?null:(0,U.jsxs)(J,{title:`Charter of ${t.name}`,children:[(0,U.jsx)(`p`,{className:`text-sm text-fg-secondary`,children:t.purpose}),(0,U.jsxs)(`p`,{className:`mt-2 text-meta`,children:[`Wakes on mentions, stages, and `,t.wakeTriggers.join(`, `)||`nothing else`,t.resident?` · keeps a warm session`:``,t.reflects?` · reflects`:``]}),(0,U.jsx)(`p`,{className:`mt-2 flex flex-wrap gap-1`,children:t.verbs.map(e=>(0,U.jsx)(`span`,{className:`rounded-md bg-surface-2/70 px-1.5 py-px font-mono text-[11px] text-fg-tertiary`,children:e},e))})]})]})}function Te(e,t){let n=r(e,t?.turnId??null);return{turn:(0,H.useMemo)(()=>t===void 0||n.data===void 0?void 0:te(n.data,e,t.project,t.thread),[t,n.data,e]),loading:t?.turnId!==void 0&&n.isPending,missing:t!==void 0&&(t.turnId===void 0||n.isError)}}var Y=50;function Ee({name:e,entry:t,now:n,opened:r}){let[i,a]=(0,H.useState)(r),o=(0,H.useRef)(null);(0,H.useEffect)(()=>{r&&o.current?.scrollIntoView({block:`start`})},[r]);let s=E(),c=ue(t),l=t.thread===void 0?null:s.get(t.thread)?.title??`a thread`,u=t.error??t.summary??``,d=t.error===null?`text-fg-secondary`:`text-red-300`;return(0,U.jsx)(`li`,{ref:o,className:`border-b border-line/60 last:border-b-0`,children:(0,U.jsxs)(`details`,{className:`group`,open:i,onToggle:e=>a(e.currentTarget.open),children:[(0,U.jsxs)(`summary`,{className:`block cursor-pointer list-none px-4 py-2.5 transition-colors hover:bg-surface-2/30 group-open:bg-surface-2/20`,children:[(0,U.jsxs)(`span`,{className:`flex items-center gap-2 text-xs`,children:[(0,U.jsxs)(`span`,{className:`min-w-0 truncate text-fg-secondary`,children:[z(t.project),l===null?``:` · ${l}`]}),(0,U.jsx)(`span`,{className:`text-fg-muted`,children:t.trigger}),(0,U.jsxs)(`span`,{className:`min-w-0 flex-1 truncate text-fg-muted`,children:[de(t),` `,y(t.ts,n)]}),(0,U.jsx)(`span`,{className:`shrink-0 font-mono text-[11px] text-fg-tertiary`,title:t.usage===void 0?void 0:R(t.usage),children:[c,t.toolCalls===void 0?null:`${t.toolCalls} tools`,t.usage===void 0?null:V(t.usage)].filter(e=>e!==null).join(` · `)}),(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`shrink-0 text-[10px] text-fg-muted transition-transform group-open:rotate-90`,children:`▸`})]}),u.trim()===``?null:(0,U.jsx)(`span`,{className:`mt-1 line-clamp-2 block text-xs leading-relaxed group-open:hidden ${d}`,children:(0,U.jsx)(N,{text:u,links:!1})})]}),i?(0,U.jsx)(De,{name:e,entry:t,text:u,tone:d}):null]})})}function De({name:e,entry:t,text:n,tone:r}){let i=Te(e,t);return(0,U.jsxs)(`div`,{className:`px-4 pt-1 pb-3`,children:[n.trim()===``?null:(0,U.jsx)(`p`,{className:`text-xs leading-relaxed whitespace-pre-wrap ${r}`,children:(0,U.jsx)(N,{text:n})}),(0,U.jsx)(`div`,{className:`mt-2`,children:t.turnId===void 0?(0,U.jsx)(`p`,{className:`text-meta`,children:`This turn ran before turns kept their steps.`}):i.loading?(0,U.jsx)(`p`,{className:`text-meta`,children:`Reading the steps…`}):i.turn===void 0?(0,U.jsx)(`p`,{className:`text-meta`,children:`No steps were kept for this turn.`}):(0,U.jsxs)(U.Fragment,{children:[t.startedAt===void 0?null:(0,U.jsxs)(`p`,{className:`text-caps`,children:[`Started `,W(t.startedAt)]}),(0,U.jsx)(K,{steps:i.turn.steps})]})})]})}function Oe({name:e,opened:t}){let[n,r]=(0,H.useState)(Y),a=i(e,n),o=S(3e4);if(a.data===void 0)return(0,U.jsx)(I,{children:`Reading the turns…`});let s=a.data.toReversed();if(s.length===0)return(0,U.jsxs)(I,{children:[e,` has not finished a turn yet.`]});let c=le(s),l=c.usage===null?``:` · ${V(c.usage)}${c.withUsage<c.turns?` over ${c.withUsage} of them`:``}`;return(0,U.jsxs)(`div`,{className:`flex-1 overflow-y-auto`,children:[(0,U.jsxs)(`p`,{className:`px-4 pt-3 pb-1 text-meta`,title:c.usage===null?void 0:R(c.usage),children:[c.turns===1?`1 turn`:`${c.turns} turns`,c.failed===0?``:`, ${c.failed} not completed`,l]}),t!==null&&!s.some(e=>e.turnId===t)?(0,U.jsx)(`p`,{className:`px-4 pb-1 text-meta`,children:a.data.length===n?`The turn this address opens is further back; show earlier turns to reach it.`:`The turn this address opens is not in this citizen's history.`}):null,(0,U.jsx)(`ol`,{children:s.map(n=>(0,U.jsx)(Ee,{name:e,entry:n,now:o,opened:t!==null&&n.turnId===t},n.id))}),a.data.length===n?(0,U.jsxs)(`button`,{type:`button`,onClick:()=>r(n+Y),className:`px-4 py-3 text-xs text-fg-tertiary hover:text-fg-primary`,children:[`Show `,Y,` earlier turns`]}):null]})}function ke(e){return e===void 0?``:`${e.name}${e.id===null?``:` · ${e.id}`}`}function X({label:e,choices:t,value:n,onChange:r,listClassName:i=`inset-x-0`}){let[a,o]=(0,H.useState)(!1),s=(0,H.useRef)(null),c=(0,H.useRef)(null),l=(0,H.useRef)([]),u=t.findIndex(e=>e.value===n);(0,H.useEffect)(()=>{if(!a)return;l.current[Math.max(u,0)]?.focus();let e=e=>{e.target instanceof Node&&s.current?.contains(e.target)===!0||o(!1)};return window.addEventListener(`pointerdown`,e),()=>window.removeEventListener(`pointerdown`,e)},[a,u]);let d=e=>{if(e.key===`Escape`){e.stopPropagation(),o(!1),c.current?.focus();return}if(e.key!==`ArrowDown`&&e.key!==`ArrowUp`)return;e.preventDefault();let n=(l.current.findIndex(e=>e===document.activeElement)+(e.key===`ArrowDown`?1:-1)+t.length)%t.length;l.current[n]?.focus()},f=t[u];return(0,U.jsxs)(`div`,{ref:s,className:`relative min-w-0 flex-1`,children:[(0,U.jsxs)(`button`,{ref:c,type:`button`,"aria-label":`${e}: ${ke(f)}`,"aria-expanded":a,onClick:()=>o(!a),onKeyDown:a?d:void 0,className:`flex h-7 w-full items-center gap-1.5 rounded-md bg-surface-2/60 px-2.5 text-xs text-fg-secondary transition-colors hover:bg-surface-2 focus-visible:ring-2 focus-visible:ring-fg-primary/30 focus-visible:outline-none`,children:[(0,U.jsxs)(`span`,{className:`min-w-0 flex-1 truncate text-left`,children:[f?.name,f?.id===null||f===void 0?null:(0,U.jsxs)(`span`,{className:`text-fg-tertiary`,children:[` · `,f.id]})]}),(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`text-[10px] text-fg-muted transition-transform ${a?`rotate-180`:``}`,children:`▾`})]}),a?(0,U.jsx)(`div`,{className:`absolute ${i} top-full z-20 mt-1 max-h-80 overflow-y-auto rounded-xl bg-surface-1/95 p-1 shadow-[inset_0_0_0_1px_rgba(255,255,255,0.08),0_16px_32px_-12px_rgba(0,0,0,0.8)] backdrop-blur-xl`,children:t.map((e,t)=>{let i=e.value===n;return(0,U.jsxs)(`button`,{ref:e=>{l.current[t]=e},type:`button`,"aria-current":i?`true`:void 0,onKeyDown:d,onClick:()=>{r(e.value),o(!1),c.current?.focus()},className:`flex w-full items-start gap-2 rounded-lg px-2.5 py-1.5 text-left transition-colors focus-visible:outline-none ${i?`bg-surface-2/80`:`hover:bg-surface-2/50 focus-visible:bg-surface-2/50`}`,children:[(0,U.jsxs)(`span`,{className:`min-w-0 flex-1`,children:[(0,U.jsxs)(`span`,{className:`block truncate text-xs text-fg-secondary`,children:[e.name,e.id===null?null:(0,U.jsxs)(`span`,{className:`text-fg-tertiary`,children:[` · `,e.id]})]}),e.description===``?null:(0,U.jsx)(`span`,{className:`block truncate text-[11px] text-fg-muted`,children:e.description})]}),(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`w-3 shrink-0 pt-px text-[11px] text-fg-primary`,children:i?`✓`:``})]},e.value)})}):null]})}var Z=``,Q=``;function Ae(e,t){return[{value:Z,name:`CLI default`,id:e.find(e=>e.isDefault)?.name??null,description:`Whatever the CLI runs when no model is set.`},...e.map(e=>({value:e.id,name:e.name,id:e.name===e.id?null:e.id,description:e.description})),...t===null?[]:[{value:t,name:t,id:null,description:`Not in the CLI's list.`}]]}function je(e,t){return[{value:Q,name:`Default`,id:e?.defaultEffort??null,description:`Whatever the model runs unset.`},...(e?.efforts??[]).map(e=>({value:e.id,name:e.id,id:null,description:e.description})),...t===null?[]:[{value:t,name:t,id:null,description:`Not in the model's list.`}]]}function Me({member:t,onDone:n}){let{api:r}=e(),i=u(),a=l(t.name),s=t.model??Z,c=t.effort??Q,[d,f]=(0,H.useState)(s),[p,m]=(0,H.useState)(c),h=w({mutationFn:async()=>{d!==s&&await r.setModel(t.name,d===Z?null:d),p!==c&&await r.setEffort(t.name,p===Q?null:p)},onSettled:()=>void i.invalidateQueries({queryKey:[`members`]}),onSuccess:n}),g=a.data?.models??[],_=t.model!==void 0&&!g.some(e=>e.id===t.model)?t.model:null,v=e=>g.find(t=>e===Z?t.isDefault:t.id===e),y=v(d)?.efforts??[],b=p!==Q&&!y.some(e=>e.id===p)?p:null,x=e=>{f(e);let t=v(e)?.efforts??[];p!==Q&&!t.some(e=>e.id===p)&&m(Q)},S=d!==s||p!==c;return(0,U.jsxs)(`form`,{"aria-label":`Model of ${t.name}`,className:`space-y-2 border-b border-line bg-surface-2/20 p-3`,onSubmit:e=>{e.preventDefault(),h.mutate()},children:[(0,U.jsxs)(`div`,{className:`flex items-center gap-2`,children:[a.isPending?(0,U.jsxs)(`p`,{className:`min-w-0 flex-1 truncate text-meta`,children:[`Asking `,t.cli,` for its models…`]}):a.error===null?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(X,{label:`Model`,choices:Ae(g,_),value:d,onChange:x}),y.length===0&&b===null?null:(0,U.jsx)(`div`,{className:`flex w-32 shrink-0`,children:(0,U.jsx)(X,{label:`Effort`,choices:je(v(d),b),value:p,onChange:m,listClassName:`right-0 w-64`})})]}):(0,U.jsxs)(`p`,{role:`alert`,className:`min-w-0 flex-1 truncate text-xs text-red-400`,children:[t.cli,` did not list its models:`,` `,a.error instanceof o?a.error.message:`the board server did not answer`]}),(0,U.jsx)(O,{onClick:n,children:`Cancel`}),(0,U.jsx)(O,{variant:`primary`,type:`submit`,disabled:h.isPending||!S||a.error!==null,children:h.isPending?`Saving…`:`Save`})]}),a.data===void 0?null:(0,U.jsxs)(`p`,{className:`text-meta`,children:[`As `,a.data.cli,` on `,a.data.runner,` lists them, where this citizen's turns run.`]}),(0,U.jsx)(L,{error:h.error})]})}var $=``;function Ne(e,t){let n=t.cli;return[e.status,e.clis.length===0?`offers no CLI yet`:e.clis.join(`, `),n!==null&&e.clis.length>0&&!e.clis.includes(n)?`has no ${n}`:``,e.capabilities.length===0?``:e.capabilities.join(`, `)].filter(e=>e!==``).join(` · `)}function Pe(e,t){return[{value:$,name:`Any runner`,id:null,description:`Pinned to the least busy runner on its next turn outside a project.`},...e.map(e=>({value:e.name,name:e.name,id:e.os,description:Ne(e,t)}))]}function Fe({member:t,onDone:n}){let{api:r}=e(),i=u(),a=s(),o=t.homeRunner??$,[c,l]=(0,H.useState)(o),d=w({mutationFn:()=>r.setRunner(t.name,c===$?null:c),onSuccess:()=>{i.invalidateQueries({queryKey:[`members`]}),n()}});return(0,U.jsxs)(`form`,{"aria-label":`Runner of ${t.name}`,className:`space-y-2 border-b border-line bg-surface-2/20 p-3`,onSubmit:e=>{e.preventDefault(),d.mutate()},children:[(0,U.jsxs)(`div`,{className:`flex items-center gap-2`,children:[a.data===void 0?(0,U.jsx)(`p`,{className:`min-w-0 flex-1 truncate text-meta`,children:`Reading the runners…`}):(0,U.jsx)(X,{label:`Runner`,choices:Pe(a.data,t),value:c,onChange:l}),(0,U.jsx)(O,{onClick:n,children:`Cancel`}),(0,U.jsx)(O,{variant:`primary`,type:`submit`,disabled:d.isPending||c===o,children:d.isPending?`Saving…`:`Run here`})]}),(0,U.jsx)(`p`,{className:`text-meta`,children:`Its conversations outside projects start afresh there from its next turn; its memory and skills follow it. Project work runs where each project lives.`}),(0,U.jsx)(L,{error:d.error})]})}function Ie(e){return e.thread===void 0?{channel:e.channel??(e.scope===`society`?`general`:`${e.scope}/general`)}:{threadId:e.thread}}function Le({name:t,turn:n}){let{api:r}=e(),i=u(),[a,o]=(0,H.useState)(!1),s=w({mutationFn:()=>r.stopTurn(n.turnId),onSuccess:()=>{o(!1),i.invalidateQueries({queryKey:[`scheduler`]})}});return(0,U.jsxs)(`div`,{className:`border-t border-line`,children:[(0,U.jsx)(ie,{target:Ie(n),initialText:`@${t} `,placeholder:n.steerable?`Message ${t} while it works`:`Message ${t} for its next turn`,className:`px-3 pt-3 pb-2`},n.turnId),n.stoppable?(0,U.jsxs)(`div`,{className:`flex items-center gap-2 px-3 pb-3`,children:[(0,U.jsx)(`p`,{className:`min-w-0 flex-1 text-[11px] leading-snug text-fg-muted`,children:a?`Ends the turn now. What it was shown counts as read; its stages stay held.`:n.steerable?`Posts reach the turn at its next step.`:`This runner delivers posts after the turn ends.`}),a?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(O,{onClick:()=>{o(!1),s.reset()},children:`Keep it running`}),(0,U.jsx)(O,{variant:`primary`,disabled:s.isPending,onClick:()=>{s.mutate()},children:s.isPending?`Stopping…`:`Stop the turn`})]}):(0,U.jsx)(O,{onClick:()=>o(!0),children:`Stop…`})]}):null,s.error===null?null:(0,U.jsx)(`div`,{className:`px-3 pb-3`,children:(0,U.jsx)(L,{error:s.error})})]})}function Re({member:t,scopes:n,preferred:r,running:i,paused:a,onDone:o}){let{api:s}=e(),c=u(),[l,d]=(0,H.useState)(`manual`),[f,p]=(0,H.useState)(r!==null&&n.includes(r)?r:n[0]??``),[m,h]=(0,H.useState)(``),g=(0,H.useRef)(null);(0,H.useEffect)(()=>g.current?.focus(),[]);let _=w({mutationFn:()=>s.wake({agent:t.name,project:f,kind:l,...m.trim()===``?{}:{reason:m.trim()}}),onSuccess:()=>{c.invalidateQueries({queryKey:[`scheduler`]}),o()}}),v=z(f),y=l===`reflection`?`Asks ${t.name} to reflect at ${v}: consolidate its memory, skills, and profile, and take no new work. It restarts the reflection clock.`:`Starts a turn for ${t.name} at ${v} as soon as the scheduler takes it.`,b=a?` The society is paused, so it waits until you resume.`:i.includes(f)?` ${t.name} is in a turn there now; this one follows it.`:``;return(0,U.jsxs)(`form`,{"aria-label":`Wake ${t.name}`,className:`space-y-2 border-b border-line bg-surface-2/20 p-3`,onSubmit:e=>{e.preventDefault(),_.mutate()},children:[(0,U.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,U.jsxs)(`fieldset`,{className:`flex gap-1`,children:[(0,U.jsx)(`legend`,{className:`sr-only`,children:`Kind of turn`}),[`manual`,`reflection`].map(e=>(0,U.jsxs)(`label`,{className:`cursor-pointer rounded-md px-2.5 py-1 text-xs transition-colors has-focus-visible:ring-2 has-focus-visible:ring-fg-primary/30 ${l===e?`bg-surface-2 text-fg-primary`:`text-fg-tertiary hover:bg-surface-2/60 hover:text-fg-primary`}`,children:[(0,U.jsx)(`input`,{type:`radio`,name:`kind`,value:e,checked:l===e,onChange:()=>d(e),className:`sr-only`}),e===`manual`?`A turn`:`A reflection`]},e))]}),(0,U.jsxs)(`label`,{className:`ml-auto flex items-center gap-2 text-xs text-fg-tertiary`,children:[`at`,(0,U.jsx)(`select`,{value:f,onChange:e=>p(e.target.value),"aria-label":`Where`,className:`rounded-md bg-surface-2/60 px-2 py-1 text-xs text-fg-primary outline-none`,children:n.map(e=>(0,U.jsx)(`option`,{value:e,children:z(e)},e))})]})]}),(0,U.jsx)(`textarea`,{ref:g,value:m,rows:2,placeholder:l===`reflection`?`Anything to reflect on in particular? Optional.`:`What should it look at? It reads this as the reason it was woken.`,"aria-label":`Reason`,onChange:e=>h(e.target.value),className:`${oe} resize-none`}),(0,U.jsxs)(`p`,{className:`text-[11px] leading-relaxed text-fg-muted`,children:[y,b,` Each turn costs money.`]}),(0,U.jsxs)(`div`,{className:`flex items-center justify-end gap-2`,children:[(0,U.jsx)(O,{onClick:o,children:`Cancel`}),(0,U.jsx)(O,{variant:`primary`,type:`submit`,disabled:_.isPending||f===``,children:_.isPending?`Waking…`:l===`reflection`?`Ask for a reflection`:`Wake ${t.name}`})]}),(0,U.jsx)(L,{error:_.error})]})}var ze={working:`bg-emerald-500/15 text-emerald-300`,queued:`bg-amber-500/15 text-amber-300`,idle:`bg-surface-2 text-fg-tertiary`};function Be({project:e,name:t}){let n=(a(e).data??[]).filter(e=>e.status===`claimed`&&e.claimedBy===t);return n.length===0?null:(0,U.jsx)(`ul`,{className:`mt-1.5 space-y-1`,children:n.map(e=>(0,U.jsx)(`li`,{children:(0,U.jsxs)(T,{to:`/task/$taskId`,params:{taskId:e.id},className:`flex items-center gap-2 rounded-md text-xs text-fg-secondary hover:text-fg-primary`,children:[(0,U.jsx)(`span`,{"aria-hidden":`true`,className:`text-fg-muted`,children:`◇`}),(0,U.jsx)(`span`,{className:`min-w-0 flex-1 truncate`,children:e.title}),(0,U.jsx)(`span`,{className:`max-w-[40%] shrink-0 truncate font-mono text-[11px] text-fg-muted`,children:d(e)?.name??e.stage})]})},e.id))})}function Ve(){let{name:e}=ee({from:`/citizen/$name`}),{scope:t,tab:n,turn:r}=C({from:`/citizen/$name`});return(0,U.jsx)(Ue,{name:e,chosen:t??null,tab:n??`now`,turn:r??null},e)}var He=[{tab:`now`,label:`Now`},{tab:`turns`,label:`Turns`},{tab:`memory`,label:`Memory`},{tab:`history`,label:`History`}];function Ue({name:e,chosen:r,tab:i,turn:a}){let o=m(),s=x(),c=t(),l=P(),[u,d]=(0,H.useState)(null),f=o.data?.find(t=>t.name===e);if(f===void 0)return(0,U.jsx)(I,{children:o.data===void 0?`Reading the roster…`:`There is no citizen ${e}.`});let p=n(c.data?.running??[]).filter(t=>t.agent===e),h=[...new Set(p.map(e=>e.scope))],g=p.map(e=>A(e.agent,e.scope,e.thread)),_=n(c.data?.pending??[]).find(t=>t.agent===e),v=h.length>0?`working`:_===void 0?`idle`:`queued`,y=M(l,e)[0],b=y?.model??f.lastModel,S=b??f.model??`CLI default`,C=f.model!==void 0&&f.model!==b?f.model:null,w=s.data?.find(e=>e.name===f.role),E=ce(f),ee=f.status===`active`&&f.cli!==null;return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(ae,{leading:f.cli===null?null:(0,U.jsx)(`span`,{className:`grid size-9 shrink-0 place-items-center rounded-lg bg-surface-2/70`,children:(0,U.jsx)(D,{cli:f.cli,size:20})}),title:e,subtitle:(0,U.jsxs)(U.Fragment,{children:[f.role,` · `,S,C===null?``:` · set to ${C}`,f.effort===void 0?``:` · ${f.effort} effort`,f.homeRunner===void 0?``:` · on ${f.homeRunner}`,f.status===`retired`?` · retired`:``]}),trailing:(0,U.jsxs)(U.Fragment,{children:[ee&&u===null?(0,U.jsxs)(U.Fragment,{children:[(0,U.jsx)(O,{onClick:()=>d(`model`),children:`Model…`}),(0,U.jsx)(O,{onClick:()=>d(`runner`),children:`Runner…`}),(0,U.jsx)(O,{onClick:()=>d(`wake`),children:`Wake…`})]}):null,(0,U.jsx)(`span`,{className:`shrink-0 rounded-full px-2 py-0.5 text-[11px] font-medium ${ze[v]}`,children:v})]})}),u===`wake`?(0,U.jsx)(Re,{member:f,scopes:E,preferred:r?.split(`/`)[0]??y?.scope??null,running:h,paused:c.data?.paused??!1,onDone:()=>d(null)}):u===`model`?(0,U.jsx)(Me,{member:f,onDone:()=>d(null)}):u===`runner`?(0,U.jsx)(Fe,{member:f,onDone:()=>d(null)}):null,(0,U.jsx)(`nav`,{"aria-label":`Citizen views`,className:`flex gap-1 border-b border-line px-3 py-2`,children:He.map(t=>(0,U.jsx)(T,{to:`/citizen/$name`,params:{name:e},search:{...r===null?{}:{scope:r},...t.tab===`now`?{}:{tab:t.tab}},replace:!0,"aria-current":t.tab===i?`page`:void 0,className:`rounded-md px-2.5 py-1 text-xs transition-colors ${t.tab===i?`bg-surface-2 text-fg-primary`:`text-fg-tertiary hover:bg-surface-2/60 hover:text-fg-primary`}`,children:t.label},t.tab))}),i===`turns`?(0,U.jsx)(Oe,{name:e,opened:a},a):i===`memory`?(0,U.jsx)(we,{member:f,charter:w}):i===`history`?(0,U.jsx)(Ce,{name:e}):(0,U.jsx)(Ge,{name:e,chosen:r,lastTurnAt:f.lastTurnAt,state:v,runningScopes:h,runningKeys:g,runningTurns:(c.data?.turns??[]).filter(t=>t.agent===e),queuedScope:_?.scope??null})]})}function We(e){return e.toSorted((e,t)=>e.startedAt.localeCompare(t.startedAt))[0]}function Ge({name:e,chosen:t,lastTurnAt:n,state:r,runningScopes:a,runningKeys:o,runningTurns:s,queuedScope:c}){let l=P(),u=S(5e3),{ref:d,onScroll:f}=se(),p=M(l,e),m=i(e,1),h=Te(e,p.length===0?m.data?.at(-1):void 0),g=E(),_=e=>e.end===null&&o.includes(A(e.agent,e.scope,e.thread)),v=t?.split(`/`)[0]??null,b=(t?.includes(`/`)===!0?p.find(e=>k(e)===t):void 0)??We(p.filter(e=>e.scope===v&&_(e)))??p.find(e=>k(e)===t)??We(p.filter(_))??p[0]??h.turn,x=e=>e.thread===void 0?z(e.scope):`${z(e.scope)} · ${g.get(e.thread)?.title??`a thread`}`,C=b!==void 0&&_(b),w=b?.scope??a[0]??c,D=(b===void 0?void 0:s.find(e=>e.scope===b.scope&&e.thread===b.thread))??(C?void 0:s[0]);return(0,U.jsxs)(U.Fragment,{children:[(0,U.jsxs)(`section`,{className:`border-b border-line px-4 py-3 text-xs text-fg-tertiary`,children:[(0,U.jsx)(`p`,{children:C?`In a turn at ${z(b.scope)} for ${b.fromStart?``:`at least `}${j(b.startedAt,u)}`:a.length>0?`In a turn at ${a.map(z).join(` and `)}`:c===null?n===void 0?`No turns yet`:`Last turn ${y(n,u)}`:`Queued for a turn at ${z(c)}`}),w===null||w===`society`?null:(0,U.jsx)(Be,{project:w,name:e})]}),(0,U.jsx)(`div`,{ref:d,onScroll:f,className:`flex-1 overflow-y-auto px-4 py-3`,children:b===void 0?(0,U.jsx)(I,{children:r===`working`?`The turn has not reported a step yet.`:h.loading?`Reading the last turn…`:n===void 0?`${e} has not taken a turn yet.`:`${e}'s last turn kept no steps; Turns lists every finished one.`}):(0,U.jsxs)(U.Fragment,{children:[p.length>1?(0,U.jsx)(`div`,{className:`mb-3 flex flex-wrap gap-1.5`,"aria-label":`Turns by conversation`,children:p.toSorted((e,t)=>k(e).localeCompare(k(t))).map(t=>(0,U.jsxs)(T,{to:`/citizen/$name`,params:{name:e},search:{scope:k(t)},replace:!0,"aria-current":t===b?`true`:void 0,className:`inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-[11px] transition-colors ${t===b?`bg-surface-2 text-fg-primary`:`text-fg-tertiary hover:bg-surface-2/60 hover:text-fg-primary`}`,children:[_(t)?(0,U.jsx)(`span`,{className:`size-1.5 animate-pulse rounded-full bg-emerald-400`}):null,x(t)]},k(t)))}):null,(0,U.jsxs)(`p`,{className:`text-caps`,children:[C?`This turn`:`Last turn`,` · `,x(b),` · started`,` `,b.fromStart?W(b.startedAt):`before the earliest step shown`]}),b.fromStart?null:(0,U.jsxs)(`p`,{className:`mt-1 text-meta`,children:[`Earlier steps of this turn are no longer in the server's live buffer`,C?``:`; Turns has the whole turn`,`.`]}),(0,U.jsx)(K,{steps:b.steps}),(0,U.jsx)(me,{turn:b,running:C,now:u})]})}),D===void 0?null:(0,U.jsx)(Le,{name:e,turn:D})]})}export{Ve as CitizenView};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{E as e,H as t,b as n,g as r,ln as i}from"./format-
|
|
1
|
+
import{E as e,H as t,b as n,g as r,ln as i}from"./format-lz-5NQWT.js";import{R as a,T as o}from"./index-CoKyPk79.js";import{n as s,t as c}from"./Pane-xzIpwnBD.js";import{i as l,r as u}from"./citizen-C27Wvimj.js";var d=i();function f(e){let t=e.lastModel??e.model??`CLI default`,n=e.model!==void 0&&e.model!==t?`${t} · set to ${e.model}`:t;return e.effort===void 0?n:`${n} · ${e.effort}`}function p(e,t){return e.name.localeCompare(t.name)}function m(e,t){return e.role.localeCompare(t.role)||p(e,t)}function h(){let i=r(),h=e(),g=n();if(i.data===void 0)return(0,d.jsx)(s,{children:`Reading the roster…`});let _=i.data.filter(e=>e.cli!==null),v=_.filter(e=>e.status===`active`).toSorted(m),y=_.filter(e=>e.status!==`active`).toSorted(p),b=new Set(v.map(e=>e.role)).size,x=t(h.data?.running??[]),S=t(h.data?.pending??[]),C=new Map((g.data??[]).flatMap(e=>e.runner===void 0?[]:[[e.slug,e.runner]])),w=e=>{let t=[...new Set(x.filter(t=>t.agent===e.name).map(e=>e.scope))];return t.length>0?{label:`working`,detail:`in a turn at ${t.map(l).join(` and `)}`,tone:`text-emerald-300`}:S.some(t=>t.agent===e.name)?{label:`queued`,detail:`queued for a turn`,tone:`text-amber-300`}:{label:`resting`,detail:`resting`,tone:`text-fg-muted`}};return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(c,{title:`Citizens`,subtitle:`${v.length} active in ${b===1?`1 role`:`${b} roles`}${y.length===0?``:` · ${y.length} retired`}`}),(0,d.jsxs)(`div`,{className:`flex-1 overflow-y-auto px-2 py-2`,children:[v.length===0?(0,d.jsx)(`p`,{className:`px-2 py-2 text-meta`,children:`No citizens yet. Ask the concierge for one.`}):null,(0,d.jsx)(`ul`,{className:`grid grid-cols-[auto_auto_auto_minmax(0,max-content)_auto_minmax(3rem,1fr)_auto] gap-x-3`,children:v.map(e=>{let t=w(e),n=f(e),r=e.memberships.length===0?`no projects`:e.memberships.join(`, `),i=u(e,C);return(0,d.jsx)(`li`,{className:`col-span-full grid grid-cols-subgrid`,children:(0,d.jsxs)(a,{to:`/citizen/$name`,params:{name:e.name},className:`col-span-full grid grid-cols-subgrid items-center rounded-lg px-2 py-1.5 text-sm transition-colors hover:bg-surface-2/50`,children:[(0,d.jsx)(`span`,{className:`grid size-4 place-items-center`,children:e.cli===null?null:(0,d.jsx)(o,{cli:e.cli,size:13})}),(0,d.jsx)(`span`,{className:`text-fg-primary`,children:e.name}),(0,d.jsx)(`span`,{className:`text-fg-secondary`,children:e.role}),(0,d.jsx)(`span`,{className:`truncate text-xs text-fg-muted`,title:n,children:n}),(0,d.jsx)(`span`,{className:`text-xs text-fg-muted`,title:i.detail,children:i.label}),(0,d.jsx)(`span`,{className:`truncate text-xs text-fg-muted`,title:r,children:r}),(0,d.jsx)(`span`,{className:`text-right text-xs ${t.tone}`,title:t.detail,children:t.label})]})},e.name)})}),y.length===0?null:(0,d.jsxs)(`p`,{className:`mt-2 border-t border-line px-2 pt-2 text-meta`,children:[`Retired: `,y.map(e=>`${e.name} (${e.role})`).join(`, `)]})]})]})}export{h as CitizensView};
|