@kubitnodes/stellaris 0.3.19 → 0.3.20
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 +213 -105
- package/dist/server/index.js +201 -63
- package/package.json +1 -1
- package/web/dist/assets/BackLink-BjfX2KZl.js +1 -0
- package/web/dist/assets/{ChannelForms-BjD5Lp_u.js → ChannelForms-BYrcUldk.js} +1 -1
- package/web/dist/assets/ChannelView-GJ_DusLQ.js +2 -0
- package/web/dist/assets/{CitizenView-tvC6dNUB.js → CitizenView-Cx7IYSRr.js} +2 -2
- package/web/dist/assets/{CitizensView-DsUhIYtl.js → CitizensView-IKH7_yNQ.js} +1 -1
- package/web/dist/assets/{CliIcon-TlyIqh7V.js → CliIcon-vSuwLv2K.js} +1 -1
- package/web/dist/assets/CronsView-DJbi8Qhx.js +1 -0
- package/web/dist/assets/KnowledgeView-CoYOG9tI.js +1 -0
- package/web/dist/assets/{Markdown-CePsfcUS.js → Markdown-YC-fbHiE.js} +4 -4
- package/web/dist/assets/MessageItem-D7MUCA_T.js +1 -0
- package/web/dist/assets/MetricsView-CE94VW0I.js +1 -0
- package/web/dist/assets/NeedsYouView-Otnm3lcG.js +1 -0
- package/web/dist/assets/Overview-B8f6rLb2.js +1 -0
- package/web/dist/assets/{Pane-DGtHsANK.js → Pane-_D7n5uKH.js} +1 -1
- package/web/dist/assets/{Picker-Dq5Vvxod.js → Picker-DUiiQMFN.js} +1 -1
- package/web/dist/assets/ProjectView-D_ACOmEd.js +1 -0
- package/web/dist/assets/ProposalView-4d0U3nEb.js +2 -0
- package/web/dist/assets/{ProposalsView-BjEfHBtx.js → ProposalsView-BovF6CMD.js} +1 -1
- package/web/dist/assets/{RunnersView-CM-q_AX9.js → RunnersView-B2_uCVHC.js} +1 -1
- package/web/dist/assets/SocietyView-Bf0iX8AY.js +1 -0
- package/web/dist/assets/SubjectThread-B_Vmgs3d.js +1 -0
- package/web/dist/assets/{TaskFileView-BMAkbh-e.js → TaskFileView-BzO0gjE6.js} +2 -2
- package/web/dist/assets/{TaskView-HDwqXuYy.js → TaskView-DB_Nji99.js} +2 -2
- package/web/dist/assets/{TasksView-Dt8M_z96.js → TasksView-Bz36YYWq.js} +1 -1
- package/web/dist/assets/{ThreadForms-DbV3kPCi.js → ThreadForms-1mbMZsbv.js} +1 -1
- package/web/dist/assets/ThreadItem-QJSA92C4.js +1 -0
- package/web/dist/assets/ThreadView-BECLqt5B.js +1 -0
- package/web/dist/assets/{citizen-DQ0Bmk-r.js → citizen-DVFr5T6R.js} +1 -1
- package/web/dist/assets/{compose-Cx9c9k90.js → compose-_6feqP1t.js} +1 -1
- package/web/dist/assets/{format-SP8GnzAX.js → format-DxXtbdNM.js} +1 -1
- package/web/dist/assets/{governance-DX2ph-qr.js → governance-C9xH4QTm.js} +1 -1
- package/web/dist/assets/index-BEVCPm4C.js +23 -0
- package/web/dist/assets/index-BkOq4PSU.css +2 -0
- package/web/dist/assets/{link-DxSeFzFf.js → link-CTjFMNoY.js} +1 -1
- package/web/dist/assets/{tasks-BeWF0Xy2.js → tasks-B6I9DJ8O.js} +1 -1
- package/web/dist/assets/useMatch-B3RzAe8y.js +1 -0
- package/web/dist/assets/useStickyScroll-Ca7sWbGH.js +1 -0
- package/web/dist/index.html +9 -9
- package/web/dist/assets/BackLink-CDrsO9Ls.js +0 -1
- package/web/dist/assets/ChannelView-dI5EHpof.js +0 -2
- package/web/dist/assets/CronsView-BPlSyoAe.js +0 -1
- package/web/dist/assets/KnowledgeView-CgRGZrOK.js +0 -1
- package/web/dist/assets/MessageItem-kg5zWMDe.js +0 -1
- package/web/dist/assets/MetricsView-cJeDTfBE.js +0 -1
- package/web/dist/assets/NeedsYouView-Cd1TnY7W.js +0 -1
- package/web/dist/assets/Overview-B6aBmove.js +0 -1
- package/web/dist/assets/ProjectView-uskZHP8l.js +0 -1
- package/web/dist/assets/ProposalView-DmjIL53_.js +0 -2
- package/web/dist/assets/SocietyView-DZuGEqIl.js +0 -1
- package/web/dist/assets/SubjectThread-pCRDn42X.js +0 -1
- package/web/dist/assets/ThreadItem-BVlz2w6q.js +0 -1
- package/web/dist/assets/ThreadView-CpBytSH7.js +0 -1
- package/web/dist/assets/index-BDKI0Rje.js +0 -23
- package/web/dist/assets/index-BPVeX6tV.css +0 -2
- package/web/dist/assets/useMatch-HNekgJrF.js +0 -1
- package/web/dist/assets/useStickyScroll-BmqddNx5.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// apps/cli/dist/index.js
|
|
4
|
-
import { readFile as
|
|
4
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
5
5
|
import path7 from "node:path";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
|
|
8
8
|
// packages/board-core/dist/board.js
|
|
9
|
-
import { chmod as chmod2, cp, mkdir as mkdir4, readdir as readdir3, readFile as
|
|
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
12
|
import { z as z13 } from "zod";
|
|
@@ -422,6 +422,13 @@ var MessageFrontmatterSchema = z4.object({
|
|
|
422
422
|
ts: IsoDateTimeSchema,
|
|
423
423
|
mentions: z4.array(NameSchema)
|
|
424
424
|
});
|
|
425
|
+
var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
426
|
+
id: true,
|
|
427
|
+
author: true,
|
|
428
|
+
channel: true,
|
|
429
|
+
thread: true,
|
|
430
|
+
ts: true
|
|
431
|
+
});
|
|
425
432
|
var TaskStatusSchema = z4.enum(["open", "claimed", "done", "abandoned"]);
|
|
426
433
|
var ThreadStateSchema = z4.enum(["open", "closed"]);
|
|
427
434
|
var ThreadSubjectSchema = z4.object({
|
|
@@ -1733,7 +1740,7 @@ var RunnerConfigSchema = z11.object({
|
|
|
1733
1740
|
});
|
|
1734
1741
|
|
|
1735
1742
|
// packages/shared/dist/version.js
|
|
1736
|
-
var STELLARIS_VERSION = "0.3.
|
|
1743
|
+
var STELLARIS_VERSION = "0.3.20";
|
|
1737
1744
|
|
|
1738
1745
|
// packages/board-core/dist/errors.js
|
|
1739
1746
|
var BoardError = class extends Error {
|
|
@@ -1746,7 +1753,7 @@ var BoardError = class extends Error {
|
|
|
1746
1753
|
};
|
|
1747
1754
|
|
|
1748
1755
|
// packages/board-core/dist/events.js
|
|
1749
|
-
import { appendFile,
|
|
1756
|
+
import { appendFile, open, stat } from "node:fs/promises";
|
|
1750
1757
|
import path2 from "node:path";
|
|
1751
1758
|
|
|
1752
1759
|
// packages/board-core/dist/fs.js
|
|
@@ -1831,10 +1838,19 @@ async function listDirs(dir) {
|
|
|
1831
1838
|
|
|
1832
1839
|
// packages/board-core/dist/events.js
|
|
1833
1840
|
var LEADING_ID = /^\{"id":"([0-9A-HJKMNP-TV-Z]{26})"/;
|
|
1841
|
+
var ID_PREFIX_BYTES = 64;
|
|
1842
|
+
var NEWLINE = 10;
|
|
1834
1843
|
var EventLog = class {
|
|
1835
1844
|
file;
|
|
1836
1845
|
newId;
|
|
1837
1846
|
now;
|
|
1847
|
+
lines = [];
|
|
1848
|
+
/** Bytes the index covers: always the end of a complete line. */
|
|
1849
|
+
indexed = 0;
|
|
1850
|
+
/** The indexed file, to tell a replaced log from a grown one. */
|
|
1851
|
+
inode = null;
|
|
1852
|
+
scanning = Promise.resolve();
|
|
1853
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1838
1854
|
constructor(file, newId, now) {
|
|
1839
1855
|
this.file = file;
|
|
1840
1856
|
this.newId = newId;
|
|
@@ -1851,48 +1867,97 @@ var EventLog = class {
|
|
|
1851
1867
|
await ensureDir(path2.dirname(this.file));
|
|
1852
1868
|
await appendFile(this.file, `${JSON.stringify(event)}
|
|
1853
1869
|
`, "utf8");
|
|
1870
|
+
for (const listener of this.listeners) {
|
|
1871
|
+
try {
|
|
1872
|
+
listener(event);
|
|
1873
|
+
} catch {
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1854
1876
|
return event;
|
|
1855
1877
|
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Calls `listener` after each event this process appends, until the returned function is
|
|
1880
|
+
* called. Another process's appends, such as the admin CLI's, are seen only by the next read.
|
|
1881
|
+
*/
|
|
1882
|
+
onAppend(listener) {
|
|
1883
|
+
this.listeners.add(listener);
|
|
1884
|
+
return () => {
|
|
1885
|
+
this.listeners.delete(listener);
|
|
1886
|
+
};
|
|
1887
|
+
}
|
|
1856
1888
|
/** Events with an id greater than `since`, oldest first. `null` reads from the beginning. */
|
|
1857
1889
|
async readSince(since, limit = 1e3) {
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
const events = [];
|
|
1863
|
-
for (const line of raw.split("\n")) {
|
|
1864
|
-
if (line.trim().length === 0) {
|
|
1890
|
+
await this.refresh();
|
|
1891
|
+
const chosen = [];
|
|
1892
|
+
for (const line of this.lines) {
|
|
1893
|
+
if (since !== null && line.id <= since) {
|
|
1865
1894
|
continue;
|
|
1866
1895
|
}
|
|
1867
|
-
|
|
1868
|
-
if (
|
|
1869
|
-
continue;
|
|
1870
|
-
}
|
|
1871
|
-
const event = BoardEventSchema.parse(JSON.parse(line));
|
|
1872
|
-
if (since !== null && event.id <= since) {
|
|
1873
|
-
continue;
|
|
1874
|
-
}
|
|
1875
|
-
events.push(event);
|
|
1876
|
-
if (events.length >= limit) {
|
|
1896
|
+
chosen.push(line);
|
|
1897
|
+
if (chosen.length >= limit) {
|
|
1877
1898
|
break;
|
|
1878
1899
|
}
|
|
1879
1900
|
}
|
|
1880
|
-
|
|
1901
|
+
const first = chosen[0];
|
|
1902
|
+
const last = chosen.at(-1);
|
|
1903
|
+
if (first === void 0 || last === void 0) {
|
|
1904
|
+
return [];
|
|
1905
|
+
}
|
|
1906
|
+
const span = await this.readBytes(first.start, last.end);
|
|
1907
|
+
return chosen.map((line) => BoardEventSchema.parse(JSON.parse(span.toString("utf8", line.start - first.start, line.end - first.start))));
|
|
1881
1908
|
}
|
|
1882
1909
|
/** The id of the newest event, or null for an empty log. */
|
|
1883
1910
|
async lastId() {
|
|
1884
|
-
|
|
1885
|
-
|
|
1911
|
+
await this.refresh();
|
|
1912
|
+
return this.lines.at(-1)?.id ?? null;
|
|
1913
|
+
}
|
|
1914
|
+
/** Brings the index up to the file's end, one scan at a time. */
|
|
1915
|
+
refresh() {
|
|
1916
|
+
this.scanning = this.scanning.then(() => this.scan(), () => this.scan());
|
|
1917
|
+
return this.scanning;
|
|
1918
|
+
}
|
|
1919
|
+
async scan() {
|
|
1920
|
+
const info = await stat(this.file).catch((error) => {
|
|
1921
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
1922
|
+
return null;
|
|
1923
|
+
}
|
|
1924
|
+
throw error;
|
|
1925
|
+
});
|
|
1926
|
+
if (info === null || info.ino !== this.inode || info.size < this.indexed) {
|
|
1927
|
+
this.lines = [];
|
|
1928
|
+
this.indexed = 0;
|
|
1929
|
+
this.inode = info?.ino ?? null;
|
|
1930
|
+
}
|
|
1931
|
+
if (info === null || info.size === this.indexed) {
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
const added = await this.readBytes(this.indexed, info.size);
|
|
1935
|
+
let start = 0;
|
|
1936
|
+
for (let at = added.indexOf(NEWLINE); at >= 0; at = added.indexOf(NEWLINE, start)) {
|
|
1937
|
+
const prefix = added.toString("utf8", start, Math.min(at, start + ID_PREFIX_BYTES));
|
|
1938
|
+
if (prefix.trim().length > 0) {
|
|
1939
|
+
const id = LEADING_ID.exec(prefix)?.[1] ?? BoardEventSchema.parse(JSON.parse(added.toString("utf8", start, at))).id;
|
|
1940
|
+
this.lines.push({ id, start: this.indexed + start, end: this.indexed + at });
|
|
1941
|
+
}
|
|
1942
|
+
start = at + 1;
|
|
1943
|
+
}
|
|
1944
|
+
this.indexed += start;
|
|
1945
|
+
}
|
|
1946
|
+
async readBytes(from, to) {
|
|
1947
|
+
const handle = await open(this.file, "r");
|
|
1948
|
+
try {
|
|
1949
|
+
const buffer = Buffer.alloc(to - from);
|
|
1950
|
+
const { bytesRead } = await handle.read(buffer, 0, buffer.length, from);
|
|
1951
|
+
return buffer.subarray(0, bytesRead);
|
|
1952
|
+
} finally {
|
|
1953
|
+
await handle.close();
|
|
1886
1954
|
}
|
|
1887
|
-
const lines = (await readFile2(this.file, "utf8")).trimEnd().split("\n");
|
|
1888
|
-
const last = lines.at(-1) ?? "";
|
|
1889
|
-
return last.length === 0 ? null : BoardEventSchema.parse(JSON.parse(last)).id;
|
|
1890
1955
|
}
|
|
1891
1956
|
};
|
|
1892
1957
|
|
|
1893
1958
|
// packages/board-core/dist/files.js
|
|
1894
1959
|
import { createHash } from "node:crypto";
|
|
1895
|
-
import { mkdir as mkdir2, readdir as readdir2, readFile as
|
|
1960
|
+
import { mkdir as mkdir2, readdir as readdir2, readFile as readFile2, rename as rename2, rm, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
1896
1961
|
import path3 from "node:path";
|
|
1897
1962
|
var MAX_FILE_BYTES = 8 * 1024 * 1024;
|
|
1898
1963
|
function isMissing2(error) {
|
|
@@ -1914,9 +1979,9 @@ var FileTree = class {
|
|
|
1914
1979
|
}
|
|
1915
1980
|
try {
|
|
1916
1981
|
const absolute = path3.join(root, ...relative.split("/"));
|
|
1917
|
-
const info = await
|
|
1982
|
+
const info = await stat2(absolute);
|
|
1918
1983
|
if (info.isFile() && info.size <= MAX_FILE_BYTES) {
|
|
1919
|
-
files[relative] = (await
|
|
1984
|
+
files[relative] = (await readFile2(absolute)).toString("base64");
|
|
1920
1985
|
}
|
|
1921
1986
|
} catch (error) {
|
|
1922
1987
|
if (!isMissing2(error)) {
|
|
@@ -1972,7 +2037,7 @@ var FileTree = class {
|
|
|
1972
2037
|
}
|
|
1973
2038
|
async hash(absolute) {
|
|
1974
2039
|
try {
|
|
1975
|
-
const info = await
|
|
2040
|
+
const info = await stat2(absolute);
|
|
1976
2041
|
if (info.size > MAX_FILE_BYTES) {
|
|
1977
2042
|
return null;
|
|
1978
2043
|
}
|
|
@@ -1981,7 +2046,7 @@ var FileTree = class {
|
|
|
1981
2046
|
if (known !== void 0 && known.mtimeMs === info.mtimeMs && known.size === info.size) {
|
|
1982
2047
|
return fileVersion(known.sha, executable);
|
|
1983
2048
|
}
|
|
1984
|
-
const sha = createHash("sha256").update(await
|
|
2049
|
+
const sha = createHash("sha256").update(await readFile2(absolute)).digest("hex");
|
|
1985
2050
|
this.hashes.set(absolute, { mtimeMs: info.mtimeMs, size: info.size, sha });
|
|
1986
2051
|
return fileVersion(sha, executable);
|
|
1987
2052
|
} catch (error) {
|
|
@@ -1994,7 +2059,7 @@ var FileTree = class {
|
|
|
1994
2059
|
};
|
|
1995
2060
|
|
|
1996
2061
|
// packages/board-core/dist/homes.js
|
|
1997
|
-
import { chmod, mkdir as mkdir3, readFile as
|
|
2062
|
+
import { chmod, mkdir as mkdir3, readFile as readFile3, writeFile as writeFile3 } from "node:fs/promises";
|
|
1998
2063
|
import path4 from "node:path";
|
|
1999
2064
|
import { execa } from "execa";
|
|
2000
2065
|
var HOME_GITIGNORE = [
|
|
@@ -2138,7 +2203,7 @@ var HomeRepos = class {
|
|
|
2138
2203
|
await writeFile3(ignore, IGNORE_FILE, "utf8");
|
|
2139
2204
|
await git(["add", "--all"], home);
|
|
2140
2205
|
await git(["commit", "--quiet", "--allow-empty", "-m", "home: created by the board"], home);
|
|
2141
|
-
} else if (await
|
|
2206
|
+
} else if (await readFile3(ignore, "utf8").catch(() => "") !== IGNORE_FILE) {
|
|
2142
2207
|
await writeFile3(ignore, IGNORE_FILE, "utf8");
|
|
2143
2208
|
await git(["add", ".gitignore"], home);
|
|
2144
2209
|
await git(["commit", "--quiet", "-m", "home: the board's ignore file"], home);
|
|
@@ -3057,8 +3122,8 @@ function restage(existing, edit) {
|
|
|
3057
3122
|
};
|
|
3058
3123
|
}
|
|
3059
3124
|
function reopenStage(stage) {
|
|
3060
|
-
const { completedBy: _by, completedAt: _at, ...
|
|
3061
|
-
return
|
|
3125
|
+
const { completedBy: _by, completedAt: _at, ...open3 } = stage;
|
|
3126
|
+
return open3;
|
|
3062
3127
|
}
|
|
3063
3128
|
function gateChanges(before, after) {
|
|
3064
3129
|
const changes = [];
|
|
@@ -3453,7 +3518,7 @@ var Board = class _Board {
|
|
|
3453
3518
|
const task2 = { ...TaskFrontmatterSchema.parse(raw.data), body: raw.body };
|
|
3454
3519
|
if ((legacy === "open" || legacy === "closed") && !await exists(this.paths.threadFile(threads, task2.id))) {
|
|
3455
3520
|
const ended = task2.status === "done" || task2.status === "abandoned";
|
|
3456
|
-
const
|
|
3521
|
+
const open3 = legacy === "open" && !ended;
|
|
3457
3522
|
const openedBy = opened.get(task2.id);
|
|
3458
3523
|
const closedBy = closed.get(task2.id);
|
|
3459
3524
|
await this.writeThread(threads, {
|
|
@@ -3461,10 +3526,10 @@ var Board = class _Board {
|
|
|
3461
3526
|
channel: channelRef(slug, "general"),
|
|
3462
3527
|
title: task2.title,
|
|
3463
3528
|
subject: { kind: "task", id: task2.id },
|
|
3464
|
-
state:
|
|
3529
|
+
state: open3 ? "open" : "closed",
|
|
3465
3530
|
openedBy: openedBy?.actor ?? task2.createdBy,
|
|
3466
3531
|
openedAt: openedBy?.ts ?? task2.createdAt,
|
|
3467
|
-
...
|
|
3532
|
+
...open3 ? {} : {
|
|
3468
3533
|
closedBy: closedBy?.actor ?? SYSTEM_ACTOR.name,
|
|
3469
3534
|
closedAt: closedBy?.ts ?? this.now().toISOString()
|
|
3470
3535
|
},
|
|
@@ -3527,7 +3592,7 @@ var Board = class _Board {
|
|
|
3527
3592
|
for (const agent2 of await this.listAgents()) {
|
|
3528
3593
|
const file = this.paths.agentCursors(agent2.name);
|
|
3529
3594
|
if (await exists(file)) {
|
|
3530
|
-
const legacy = Legacy.safeParse(JSON.parse(await
|
|
3595
|
+
const legacy = Legacy.safeParse(JSON.parse(await readFile4(file, "utf8")));
|
|
3531
3596
|
if (legacy.success) {
|
|
3532
3597
|
await writeJson(file, { digest: legacy.data.inbox });
|
|
3533
3598
|
}
|
|
@@ -3866,6 +3931,10 @@ ${charter.purpose}
|
|
|
3866
3931
|
async latestEventId() {
|
|
3867
3932
|
return this.events.lastId();
|
|
3868
3933
|
}
|
|
3934
|
+
/** Calls `listener` after each event the board appends, until the returned function is called. */
|
|
3935
|
+
onEventAppended(listener) {
|
|
3936
|
+
return this.events.onAppend(listener);
|
|
3937
|
+
}
|
|
3869
3938
|
/** The roster as projected: every citizen with identity, reach, availability, and profile. */
|
|
3870
3939
|
async listMembers() {
|
|
3871
3940
|
const members = [];
|
|
@@ -3910,7 +3979,7 @@ ${charter.purpose}
|
|
|
3910
3979
|
project: project2,
|
|
3911
3980
|
revision: revision.success ? revision.data : 0,
|
|
3912
3981
|
updatedBy: updatedBy.success ? updatedBy.data : SYSTEM_ACTOR.name,
|
|
3913
|
-
updatedAt: updatedAt.success ? updatedAt.data : (await
|
|
3982
|
+
updatedAt: updatedAt.success ? updatedAt.data : (await stat3(file)).mtime.toISOString(),
|
|
3914
3983
|
body
|
|
3915
3984
|
};
|
|
3916
3985
|
}
|
|
@@ -4012,6 +4081,28 @@ ${charter.purpose}
|
|
|
4012
4081
|
async readThread(id) {
|
|
4013
4082
|
return (await this.findThread(id)).thread;
|
|
4014
4083
|
}
|
|
4084
|
+
/**
|
|
4085
|
+
* Where each of the messages named is and who wrote it, for text that names them by id; an id
|
|
4086
|
+
* that names no message is left out. Message files start with their ids, so only the files
|
|
4087
|
+
* asked for are read.
|
|
4088
|
+
*/
|
|
4089
|
+
async findMessages(ids) {
|
|
4090
|
+
const wanted = new Set(ids);
|
|
4091
|
+
const found = [];
|
|
4092
|
+
for await (const dir of this.messageDirs()) {
|
|
4093
|
+
for (const file of await listFiles(dir)) {
|
|
4094
|
+
if (!wanted.delete(file.slice(0, 26))) {
|
|
4095
|
+
continue;
|
|
4096
|
+
}
|
|
4097
|
+
const { data } = await readMarkdown(path6.join(dir, file), MessageFrontmatterSchema);
|
|
4098
|
+
found.push(MessageRefSchema.parse(data));
|
|
4099
|
+
}
|
|
4100
|
+
if (wanted.size === 0) {
|
|
4101
|
+
break;
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
return found;
|
|
4105
|
+
}
|
|
4015
4106
|
/**
|
|
4016
4107
|
* What citizens have asked the user and the user has not answered, oldest first: every message
|
|
4017
4108
|
* by someone else that mentions the user, in an open thread or a channel the society or an
|
|
@@ -4513,12 +4604,12 @@ ${DASHBOARD_LINE}
|
|
|
4513
4604
|
continue;
|
|
4514
4605
|
}
|
|
4515
4606
|
const named = thread2 === null ? channelConversation(filedIn, message.channel) : void 0;
|
|
4516
|
-
let
|
|
4517
|
-
if (named !== void 0 &&
|
|
4518
|
-
|
|
4519
|
-
openChannels.set(message.channel,
|
|
4607
|
+
let open3 = named === void 0 ? void 0 : openChannels.get(message.channel);
|
|
4608
|
+
if (named !== void 0 && open3 === void 0) {
|
|
4609
|
+
open3 = await this.channelOpen(message.channel);
|
|
4610
|
+
openChannels.set(message.channel, open3);
|
|
4520
4611
|
}
|
|
4521
|
-
const part = thread2 ?? (
|
|
4612
|
+
const part = thread2 ?? (open3 === true ? `#${named}` : null);
|
|
4522
4613
|
if (conversation !== void 0 && (filedIn !== conversation.scope || part !== conversation.part)) {
|
|
4523
4614
|
continue;
|
|
4524
4615
|
}
|
|
@@ -4583,7 +4674,7 @@ ${task2.body}`;
|
|
|
4583
4674
|
}
|
|
4584
4675
|
}
|
|
4585
4676
|
for (const file of await listFiles(this.paths.projectKnowledge(project2))) {
|
|
4586
|
-
const content = await
|
|
4677
|
+
const content = await readFile4(path6.join(this.paths.projectKnowledge(project2), file), "utf8");
|
|
4587
4678
|
if (content.toLowerCase().includes(needle)) {
|
|
4588
4679
|
hits.push({
|
|
4589
4680
|
kind: "knowledge",
|
|
@@ -4621,7 +4712,7 @@ ${task2.body}`;
|
|
|
4621
4712
|
});
|
|
4622
4713
|
}
|
|
4623
4714
|
for (const entry of shared) {
|
|
4624
|
-
const content = await
|
|
4715
|
+
const content = await readFile4(entry.file, "utf8");
|
|
4625
4716
|
if (content.toLowerCase().includes(needle)) {
|
|
4626
4717
|
hits.push({
|
|
4627
4718
|
kind: entry.kind,
|
|
@@ -6110,7 +6201,7 @@ ${rationale}`}`);
|
|
|
6110
6201
|
throw new BoardError("NOT_FOUND", `no transcript of turn ${turnId} for ${agent2}`);
|
|
6111
6202
|
}
|
|
6112
6203
|
const entries = [];
|
|
6113
|
-
for (const line of (await
|
|
6204
|
+
for (const line of (await readFile4(file, "utf8")).split("\n")) {
|
|
6114
6205
|
if (line.trim() === "")
|
|
6115
6206
|
continue;
|
|
6116
6207
|
const parsed = TranscriptEntrySchema.safeParse(JSON.parse(line));
|
|
@@ -6589,7 +6680,7 @@ ${rationale}`}`);
|
|
|
6589
6680
|
}
|
|
6590
6681
|
const file = entry.isFile() ? conflictCopyOf(relative) : null;
|
|
6591
6682
|
if (file !== null) {
|
|
6592
|
-
const since = await this.homes.changedAt(home, relative) ?? (await
|
|
6683
|
+
const since = await this.homes.changedAt(home, relative) ?? (await stat3(path6.join(home, relative)).catch(() => null))?.mtime.toISOString();
|
|
6593
6684
|
if (since !== void 0) {
|
|
6594
6685
|
found.push({ path: relative, file, since });
|
|
6595
6686
|
}
|
|
@@ -7167,7 +7258,7 @@ Short, curated, loaded on every turn. Keep entries that change future behavior a
|
|
|
7167
7258
|
if (!isSafeRelativePath(entry.path)) {
|
|
7168
7259
|
continue;
|
|
7169
7260
|
}
|
|
7170
|
-
const bytes = await
|
|
7261
|
+
const bytes = await readFile4(path6.join(dir, ...entry.path.split("/"))).catch(() => null);
|
|
7171
7262
|
const text = bytes === null || bytes.includes(0) ? null : bytes.toString("utf8");
|
|
7172
7263
|
files.push({
|
|
7173
7264
|
...entry,
|
|
@@ -7866,6 +7957,23 @@ ${charter.purpose}
|
|
|
7866
7957
|
yield* this.threadMessagesIn(this.paths.threads(slug), since);
|
|
7867
7958
|
}
|
|
7868
7959
|
}
|
|
7960
|
+
/** Every folder that holds messages: each channel's and each thread's, in the society and every project. */
|
|
7961
|
+
async *messageDirs() {
|
|
7962
|
+
for (const channel of await listDirs(this.paths.societyChannels())) {
|
|
7963
|
+
yield this.paths.societyChannel(channel);
|
|
7964
|
+
}
|
|
7965
|
+
for (const id of await listDirs(this.paths.societyThreads())) {
|
|
7966
|
+
yield this.paths.threadMessages(this.paths.societyThreads(), id);
|
|
7967
|
+
}
|
|
7968
|
+
for (const slug of await listDirs(this.paths.projects())) {
|
|
7969
|
+
for (const channel of await listDirs(this.paths.projectChannels(slug))) {
|
|
7970
|
+
yield this.paths.projectChannel(slug, channel);
|
|
7971
|
+
}
|
|
7972
|
+
for (const id of await listDirs(this.paths.threads(slug))) {
|
|
7973
|
+
yield this.paths.threadMessages(this.paths.threads(slug), id);
|
|
7974
|
+
}
|
|
7975
|
+
}
|
|
7976
|
+
}
|
|
7869
7977
|
async *threadMessagesIn(threads, since) {
|
|
7870
7978
|
for (const id of await listDirs(threads)) {
|
|
7871
7979
|
yield* await this.readMessagesIn(this.paths.threadMessages(threads, id), since);
|
|
@@ -7882,7 +7990,7 @@ function globals() {
|
|
|
7882
7990
|
function print(value, human) {
|
|
7883
7991
|
console.log(globals().json ? JSON.stringify(value, null, 2) : human());
|
|
7884
7992
|
}
|
|
7885
|
-
async function
|
|
7993
|
+
async function open2() {
|
|
7886
7994
|
return Board.open(globals().data);
|
|
7887
7995
|
}
|
|
7888
7996
|
async function actorFor(board, as) {
|
|
@@ -7928,7 +8036,7 @@ user.command("token").description("Issue the user a new token and print it once;
|
|
|
7928
8036
|
if (!opts.rotate) {
|
|
7929
8037
|
throw new BoardError("VALIDATION", "the board keeps only a hash of the user token, so it cannot show it again; `user token --rotate` issues a new one");
|
|
7930
8038
|
}
|
|
7931
|
-
const board = await
|
|
8039
|
+
const board = await open2();
|
|
7932
8040
|
const userToken = await board.rotateUserToken();
|
|
7933
8041
|
print({ userToken }, () => [
|
|
7934
8042
|
`User token (shown once): ${userToken}`,
|
|
@@ -7937,7 +8045,7 @@ user.command("token").description("Issue the user a new token and print it once;
|
|
|
7937
8045
|
});
|
|
7938
8046
|
var project = program.command("project").description("Manage projects");
|
|
7939
8047
|
project.command("add <slug>").description("Add a project with its default channels").option("--name <name>", "display name").option("--repo <url>", "git remote").option("--on-done <effect>", "what finishing a task does: none, or merge its branch").action(async (slug, opts) => {
|
|
7940
|
-
const board = await
|
|
8048
|
+
const board = await open2();
|
|
7941
8049
|
const added = await board.addProject(board.userActor(), {
|
|
7942
8050
|
slug,
|
|
7943
8051
|
name: opts.name,
|
|
@@ -7947,7 +8055,7 @@ project.command("add <slug>").description("Add a project with its default channe
|
|
|
7947
8055
|
print(added, () => `Project ${added.slug} added with channels ${added.channels.join(", ")}`);
|
|
7948
8056
|
});
|
|
7949
8057
|
project.command("configure <slug>").description("Set a project's completion effect").requiredOption("--on-done <effect>", "none, or merge").option("--as <agent>", "act as this agent instead of the user").action(async (slug, opts) => {
|
|
7950
|
-
const board = await
|
|
8058
|
+
const board = await open2();
|
|
7951
8059
|
const configured = await board.configureProject(await actorFor(board, opts.as), {
|
|
7952
8060
|
project: slug,
|
|
7953
8061
|
on_done: CompletionEffectSchema.parse(opts.onDone)
|
|
@@ -7955,7 +8063,7 @@ project.command("configure <slug>").description("Set a project's completion effe
|
|
|
7955
8063
|
print(configured, () => `Project ${configured.slug}: on done ${configured.onDone}`);
|
|
7956
8064
|
});
|
|
7957
8065
|
project.command("archive <slug>").description("Archive a project with no task in play: its members leave and its threads close").requiredOption("--reason <text>", "why the project is archived").action(async (slug, opts) => {
|
|
7958
|
-
const board = await
|
|
8066
|
+
const board = await open2();
|
|
7959
8067
|
const archived = await board.archiveProject(board.userActor(), {
|
|
7960
8068
|
project: slug,
|
|
7961
8069
|
reason: opts.reason
|
|
@@ -7963,13 +8071,13 @@ project.command("archive <slug>").description("Archive a project with no task in
|
|
|
7963
8071
|
print(archived, () => `Project ${archived.slug} archived`);
|
|
7964
8072
|
});
|
|
7965
8073
|
project.command("list").description("List projects").action(async () => {
|
|
7966
|
-
const board = await
|
|
8074
|
+
const board = await open2();
|
|
7967
8075
|
const projects = await board.listProjects();
|
|
7968
8076
|
print(projects, () => projects.map((p) => p.archived === void 0 ? `${p.slug} ${p.name} members: ${p.members.join(", ") || "none"}` : `${p.slug} ${p.name} archived ${p.archived.at} by ${p.archived.by}`).join("\n"));
|
|
7969
8077
|
});
|
|
7970
8078
|
var runner = program.command("runner").description("Manage runners");
|
|
7971
8079
|
runner.command("add <name>").description("Register a runner and print its token once").action(async (name) => {
|
|
7972
|
-
const board = await
|
|
8080
|
+
const board = await open2();
|
|
7973
8081
|
const { runner: added, token } = await board.addRunner(board.userActor(), name);
|
|
7974
8082
|
print({ runner: added, token }, () => [
|
|
7975
8083
|
`Runner ${added.name} added`,
|
|
@@ -7978,13 +8086,13 @@ runner.command("add <name>").description("Register a runner and print its token
|
|
|
7978
8086
|
].join("\n"));
|
|
7979
8087
|
});
|
|
7980
8088
|
runner.command("list").description("List runners and what they offer").action(async () => {
|
|
7981
|
-
const board = await
|
|
8089
|
+
const board = await open2();
|
|
7982
8090
|
const runners = await board.listRunners();
|
|
7983
8091
|
print(runners, () => runners.length === 0 ? "No runners yet; add one with `runner add <name>`." : runners.map((each) => `${each.name} ${each.status} ${each.os}${each.version === void 0 ? "" : ` v${each.version}`} ${each.clis.join(",") || "no CLIs yet"}${each.capabilities.length === 0 ? "" : ` ${each.capabilities.join(",")}`}`).join("\n"));
|
|
7984
8092
|
});
|
|
7985
8093
|
var agent = program.command("agent").description("Manage agents");
|
|
7986
8094
|
agent.command("add <name>").description("Add an agent and print its board token once").requiredOption("--role <role>", "role charter name").option("--cli <cli>", "claude or codex").option("--model <model>", "model to run the CLI with; the CLI's own default otherwise").option("--runner <name>", "runner preferred for its turns; any with its CLI otherwise").option("-p, --project <slug...>", "project memberships").action(async (name, opts) => {
|
|
7987
|
-
const board = await
|
|
8095
|
+
const board = await open2();
|
|
7988
8096
|
const cli = opts.cli === void 0 ? null : CliKindSchema.parse(opts.cli);
|
|
7989
8097
|
const { agent: added, token } = await board.addAgent(board.userActor(), {
|
|
7990
8098
|
name,
|
|
@@ -7997,7 +8105,7 @@ agent.command("add <name>").description("Add an agent and print its board token
|
|
|
7997
8105
|
print({ agent: added, token }, () => [`Agent ${added.name} added as ${added.role}`, `Token (shown once): ${token}`].join("\n"));
|
|
7998
8106
|
});
|
|
7999
8107
|
agent.command("runner <name> [runner]").description("Show or set the runner a citizen's work outside any project runs on; `none` pins it again on its next turn").action(async (name, chosen) => {
|
|
8000
|
-
const board = await
|
|
8108
|
+
const board = await open2();
|
|
8001
8109
|
if (chosen === void 0) {
|
|
8002
8110
|
const current = await board.readAgent(name);
|
|
8003
8111
|
print({ agent: name, homeRunner: current.homeRunner ?? null }, () => current.homeRunner === void 0 ? `${name} is not pinned; its next turn outside a project pins it` : `${name} runs on ${current.homeRunner}`);
|
|
@@ -8007,7 +8115,7 @@ agent.command("runner <name> [runner]").description("Show or set the runner a ci
|
|
|
8007
8115
|
print({ agent: name, homeRunner: updated.homeRunner ?? null }, () => updated.homeRunner === void 0 ? `${name} will be pinned on its next turn` : `${name} runs on ${updated.homeRunner} from its next turn`);
|
|
8008
8116
|
});
|
|
8009
8117
|
agent.command("list").description("List agents").action(async () => {
|
|
8010
|
-
const board = await
|
|
8118
|
+
const board = await open2();
|
|
8011
8119
|
const agents = await board.listAgents();
|
|
8012
8120
|
const members = await board.listMembers();
|
|
8013
8121
|
print(agents, () => agents.map((a) => {
|
|
@@ -8016,28 +8124,28 @@ agent.command("list").description("List agents").action(async () => {
|
|
|
8016
8124
|
}).join("\n"));
|
|
8017
8125
|
});
|
|
8018
8126
|
agent.command("model <name> [model]").description("Set the model a member's turns run with, from its next turn; no model means the CLI's default").action(async (name, model) => {
|
|
8019
|
-
const board = await
|
|
8127
|
+
const board = await open2();
|
|
8020
8128
|
const updated = await board.setAgentModel(board.userActor(), name, model ?? null);
|
|
8021
8129
|
print(updated, () => `${updated.name} runs with ${updated.model ?? "its CLI's default model"} from its next turn`);
|
|
8022
8130
|
});
|
|
8023
8131
|
agent.command("effort <name> [effort]").description("Set the reasoning effort a member's turns run with, from its next turn, such as high; no effort means the model's default").action(async (name, effort) => {
|
|
8024
|
-
const board = await
|
|
8132
|
+
const board = await open2();
|
|
8025
8133
|
const updated = await board.setAgentEffort(board.userActor(), name, effort ?? null);
|
|
8026
8134
|
print(updated, () => `${updated.name} runs with ${updated.effort === void 0 ? "its model's default effort" : `${updated.effort} effort`} from its next turn`);
|
|
8027
8135
|
});
|
|
8028
8136
|
agent.command("retire <name>").description("Retire a member: no more wakes, claims released, token revoked, sessions archived").requiredOption("--reason <text>", "why").action(async (name, opts) => {
|
|
8029
|
-
const board = await
|
|
8137
|
+
const board = await open2();
|
|
8030
8138
|
const retired = await board.retireAgent(board.userActor(), { name, reason: opts.reason });
|
|
8031
8139
|
print(retired, () => `Agent ${retired.name} retired: ${opts.reason}`);
|
|
8032
8140
|
});
|
|
8033
8141
|
var proposal = program.command("proposal").description("Governance proposals");
|
|
8034
8142
|
proposal.command("list").description("List proposals").action(async () => {
|
|
8035
|
-
const board = await
|
|
8143
|
+
const board = await open2();
|
|
8036
8144
|
const proposals = await board.listProposals();
|
|
8037
8145
|
print(proposals, () => proposals.length === 0 ? "No proposals." : proposals.map((p) => `${p.id} ${p.kind} ${p.status} by ${p.proposedBy}`).join("\n"));
|
|
8038
8146
|
});
|
|
8039
8147
|
proposal.command("show <id>").description("Show a proposal with its charter and rationale").action(async (id) => {
|
|
8040
|
-
const board = await
|
|
8148
|
+
const board = await open2();
|
|
8041
8149
|
const found = await board.readProposal(id);
|
|
8042
8150
|
print(found, () => [
|
|
8043
8151
|
`${found.id} ${found.kind} ${found.status} by ${found.proposedBy}`,
|
|
@@ -8047,7 +8155,7 @@ proposal.command("show <id>").description("Show a proposal with its charter and
|
|
|
8047
8155
|
].filter((line) => line.length > 0).join("\n"));
|
|
8048
8156
|
});
|
|
8049
8157
|
proposal.command("create").description("Propose a member, role, channel, reallocation, or retirement").requiredOption("--kind <kind>", "member, role, channel, reallocation, or retirement").requiredOption("--charter <json>", "the charter as a JSON object").option("--rationale <text>", "why", "").option("--as <agent>", "act as this agent instead of the user").action(async (opts) => {
|
|
8050
|
-
const board = await
|
|
8158
|
+
const board = await open2();
|
|
8051
8159
|
const created = await board.propose(await actorFor(board, opts.as), {
|
|
8052
8160
|
kind: ProposalKindSchema.parse(opts.kind),
|
|
8053
8161
|
charter: parseCharter(opts.charter),
|
|
@@ -8056,7 +8164,7 @@ proposal.command("create").description("Propose a member, role, channel, realloc
|
|
|
8056
8164
|
print(created, () => `Proposal ${created.id} (${created.kind}) is ${created.status}`);
|
|
8057
8165
|
});
|
|
8058
8166
|
proposal.command("approve <id>").description("Approve a proposal; the board provisions it").option("--reason <text>", "a note for the record").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8059
|
-
const board = await
|
|
8167
|
+
const board = await open2();
|
|
8060
8168
|
const decision = await board.approve(await actorFor(board, opts.as), {
|
|
8061
8169
|
proposal_id: id,
|
|
8062
8170
|
...opts.reason === void 0 ? {} : { reason: opts.reason }
|
|
@@ -8065,7 +8173,7 @@ proposal.command("approve <id>").description("Approve a proposal; the board prov
|
|
|
8065
8173
|
print({ decision, proposal: after }, () => `Proposal ${id} approved; it is now ${after.status}`);
|
|
8066
8174
|
});
|
|
8067
8175
|
proposal.command("reject <id>").description("Reject a proposal with a reason").requiredOption("--reason <text>", "why").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8068
|
-
const board = await
|
|
8176
|
+
const board = await open2();
|
|
8069
8177
|
const decision = await board.reject(await actorFor(board, opts.as), {
|
|
8070
8178
|
proposal_id: id,
|
|
8071
8179
|
reason: opts.reason
|
|
@@ -8074,14 +8182,14 @@ proposal.command("reject <id>").description("Reject a proposal with a reason").r
|
|
|
8074
8182
|
});
|
|
8075
8183
|
var role = program.command("role").description("Role charters");
|
|
8076
8184
|
role.command("list").description("List role charters").action(async () => {
|
|
8077
|
-
const board = await
|
|
8185
|
+
const board = await open2();
|
|
8078
8186
|
const roles = await board.listRoles();
|
|
8079
8187
|
print(roles, () => roles.map((r) => `${r.name} replicas up to ${r.maxReplicas} backlog threshold ${r.backlogThreshold} wakes on ${r.wakeTriggers.join(", ") || "direct wakes only"}`).join("\n"));
|
|
8080
8188
|
});
|
|
8081
8189
|
role.command("add <name>").description("Write a new role charter directly as the user").requiredOption("--purpose <text>", "what the role is for; its members read this every turn").option("--verbs <verbs...>", "board verbs granted; the member verbs by default").option("--triggers <triggers...>", "wakes it opts into: user_post, ops_event, heartbeat", [
|
|
8082
8190
|
"heartbeat"
|
|
8083
8191
|
]).action(async (name, opts) => {
|
|
8084
|
-
const board = await
|
|
8192
|
+
const board = await open2();
|
|
8085
8193
|
const added = await board.setRoleCharter(board.userActor(), {
|
|
8086
8194
|
name,
|
|
8087
8195
|
purpose: opts.purpose,
|
|
@@ -8091,7 +8199,7 @@ role.command("add <name>").description("Write a new role charter directly as the
|
|
|
8091
8199
|
print(added, () => `Role ${added.name} written with ${added.verbs.length} verbs`);
|
|
8092
8200
|
});
|
|
8093
8201
|
role.command("set <name>").description("Change a charter directly as the user: scaling cap, threshold, or purpose").option("--max-replicas <n>", "active members of the role per project the scheduler may reach").option("--backlog-threshold <n>", "load per member that adds a replica").option("--purpose <text>", "the charter's purpose").action(async (name, opts) => {
|
|
8094
|
-
const board = await
|
|
8202
|
+
const board = await open2();
|
|
8095
8203
|
const current = await board.readRole(name);
|
|
8096
8204
|
const updated = await board.setRoleCharter(board.userActor(), {
|
|
8097
8205
|
...current,
|
|
@@ -8103,7 +8211,7 @@ role.command("set <name>").description("Change a charter directly as the user: s
|
|
|
8103
8211
|
});
|
|
8104
8212
|
var channelCommand = program.command("channel").description("Channels");
|
|
8105
8213
|
channelCommand.command("add <ref>").description("Open a channel: <name> for the society or <project>/<name>").requiredOption("--purpose <text>", "what the channel is for").option("--as <agent>", "act as this agent instead of the user").action(async (ref, opts) => {
|
|
8106
|
-
const board = await
|
|
8214
|
+
const board = await open2();
|
|
8107
8215
|
const parsed = parseChannelRef(ref);
|
|
8108
8216
|
const added = await board.addChannel(await actorFor(board, opts.as), {
|
|
8109
8217
|
project: parsed.project,
|
|
@@ -8113,7 +8221,7 @@ channelCommand.command("add <ref>").description("Open a channel: <name> for the
|
|
|
8113
8221
|
print({ channel: added }, () => `Channel ${added} opened`);
|
|
8114
8222
|
});
|
|
8115
8223
|
channelCommand.command("archive <ref>").description("Archive a channel whose workstream is done, once no task filed there is in play").requiredOption("--reason <text>", "why its work is done").option("--as <agent>", "act as this agent instead of the user").action(async (ref, opts) => {
|
|
8116
|
-
const board = await
|
|
8224
|
+
const board = await open2();
|
|
8117
8225
|
const archived = await board.archiveChannel(await actorFor(board, opts.as), {
|
|
8118
8226
|
channel: ref,
|
|
8119
8227
|
reason: opts.reason
|
|
@@ -8121,12 +8229,12 @@ channelCommand.command("archive <ref>").description("Archive a channel whose wor
|
|
|
8121
8229
|
print(archived, () => `Channel ${ref} archived: ${archived.reason}`);
|
|
8122
8230
|
});
|
|
8123
8231
|
program.command("signals").description("Recent operations signals, oldest first").option("--limit <n>", "how many", "50").action(async (opts) => {
|
|
8124
|
-
const board = await
|
|
8232
|
+
const board = await open2();
|
|
8125
8233
|
const signals = await board.listSignals(Number(opts.limit));
|
|
8126
8234
|
print(signals, () => signals.length === 0 ? "No signals yet." : signals.map((s) => `[${s.ts}] ${s.signal.kind} ${s.signal.summary}`).join("\n"));
|
|
8127
8235
|
});
|
|
8128
8236
|
program.command("post <channel> <body>").description("Post a message to a channel, or into one of its threads").option("--as <agent>", "act as this agent instead of the user").option("--thread <threadId>", "post into the thread, which must hang off the channel").action(async (channel, body, opts) => {
|
|
8129
|
-
const board = await
|
|
8237
|
+
const board = await open2();
|
|
8130
8238
|
const who = await actorFor(board, opts.as);
|
|
8131
8239
|
const message = await board.postMessage(who, {
|
|
8132
8240
|
channel,
|
|
@@ -8136,13 +8244,13 @@ program.command("post <channel> <body>").description("Post a message to a channe
|
|
|
8136
8244
|
print(message, () => `Posted ${message.id} to ${message.channel}${message.thread === void 0 ? "" : ` (thread ${message.thread})`}`);
|
|
8137
8245
|
});
|
|
8138
8246
|
program.command("ask <text>").description("Post to the society's general channel as the user; the front desk routes it").action(async (text) => {
|
|
8139
|
-
const board = await
|
|
8247
|
+
const board = await open2();
|
|
8140
8248
|
const message = await board.postMessage(board.userActor(), { channel: "general", body: text });
|
|
8141
8249
|
print(message, () => `Posted ${message.id} to general; the concierge wakes on it`);
|
|
8142
8250
|
});
|
|
8143
8251
|
var task = program.command("task").description("Manage tasks");
|
|
8144
8252
|
task.command("create <project> <title>").description("Create a task with a plan, or with one stage anyone in the project may take").option("--body <text>", "task body", "").option("--parent <id>", "parent task id").option("--plan <json>", `stages, for example '[{"name":"analysis","role":"analyst"}]'`).option("--channel <name>", "the project's channel to file it in, such as a release's", "general").option("--as <agent>", "act as this agent instead of the user").action(async (projectSlug, title, opts) => {
|
|
8145
|
-
const board = await
|
|
8253
|
+
const board = await open2();
|
|
8146
8254
|
const who = await actorFor(board, opts.as);
|
|
8147
8255
|
const created = await board.createTask(who, {
|
|
8148
8256
|
project: projectSlug,
|
|
@@ -8158,17 +8266,17 @@ task.command("create <project> <title>").description("Create a task with a plan,
|
|
|
8158
8266
|
].join("\n"));
|
|
8159
8267
|
});
|
|
8160
8268
|
task.command("claim <id>").description("Hold the task's current stage").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8161
|
-
const board = await
|
|
8269
|
+
const board = await open2();
|
|
8162
8270
|
const claimed = await board.claimTask(await actorFor(board, opts.as), { task_id: id });
|
|
8163
8271
|
print(claimed, () => `Stage ${claimed.stage} of task ${claimed.id} held by ${claimed.claimedBy ?? "?"} until ${claimed.leaseExpiresAt ?? "?"}`);
|
|
8164
8272
|
});
|
|
8165
8273
|
task.command("release <id>").description("Let go of the stage held on a task").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8166
|
-
const board = await
|
|
8274
|
+
const board = await open2();
|
|
8167
8275
|
const released = await board.releaseTask(await actorFor(board, opts.as), { task_id: id });
|
|
8168
8276
|
print(released, () => `Stage ${released.stage} of task ${released.id} released`);
|
|
8169
8277
|
});
|
|
8170
8278
|
task.command("advance <id>").description("Finish the current stage; past the last one the task is done").option("--note <text>", "what was done, posted to the task's thread").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8171
|
-
const board = await
|
|
8279
|
+
const board = await open2();
|
|
8172
8280
|
const advanced = await board.advanceTask(await actorFor(board, opts.as), {
|
|
8173
8281
|
task_id: id,
|
|
8174
8282
|
...opts.note === void 0 ? {} : { note: opts.note }
|
|
@@ -8177,7 +8285,7 @@ task.command("advance <id>").description("Finish the current stage; past the las
|
|
|
8177
8285
|
${describePlan(advanced)}`);
|
|
8178
8286
|
});
|
|
8179
8287
|
task.command("plan <id> <stages>").description("Reshape the stages ahead: pass existing stages with their id to keep them, new ones without").option("--on-done <effect>", "override the completion effect for this task").option("--as <agent>", "act as this agent instead of the user").action(async (id, stages, opts) => {
|
|
8180
|
-
const board = await
|
|
8288
|
+
const board = await open2();
|
|
8181
8289
|
const planned = await board.planTask(await actorFor(board, opts.as), {
|
|
8182
8290
|
task_id: id,
|
|
8183
8291
|
stages: PlanEditSchema.parse(JSON.parse(stages)),
|
|
@@ -8186,7 +8294,7 @@ task.command("plan <id> <stages>").description("Reshape the stages ahead: pass e
|
|
|
8186
8294
|
print(planned, () => describePlan(planned));
|
|
8187
8295
|
});
|
|
8188
8296
|
task.command("update <id>").description("Send a task back to an earlier stage, abandon it, or set blockers, with a note for its thread").option("--stage <stageId>", "move back to this earlier stage").option("--abandon", "abandon the task", false).option("--note <text>", "a note, posted to the task's thread").option("--blocked-by <ids...>", "task ids this task waits on").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8189
|
-
const board = await
|
|
8297
|
+
const board = await open2();
|
|
8190
8298
|
const updated = await board.updateTask(await actorFor(board, opts.as), {
|
|
8191
8299
|
task_id: id,
|
|
8192
8300
|
...opts.stage === void 0 ? {} : { stage: opts.stage },
|
|
@@ -8197,7 +8305,7 @@ task.command("update <id>").description("Send a task back to an earlier stage, a
|
|
|
8197
8305
|
print(updated, () => `Task ${updated.id} is ${updated.status} at ${updated.stage}`);
|
|
8198
8306
|
});
|
|
8199
8307
|
task.command("show <id>").description("Show a task with its plan and its thread").action(async (id) => {
|
|
8200
|
-
const board = await
|
|
8308
|
+
const board = await open2();
|
|
8201
8309
|
const found = await board.getTask(board.userActor(), { task_id: id });
|
|
8202
8310
|
const threadState = await board.readThread(id).then((t) => t.state).catch(() => "none");
|
|
8203
8311
|
const said = found.messages.map((message) => {
|
|
@@ -8217,7 +8325,7 @@ ${message.body.trim()}
|
|
|
8217
8325
|
].join("\n"));
|
|
8218
8326
|
});
|
|
8219
8327
|
task.command("list <project>").description("List a project's tasks with their current stage").action(async (projectSlug) => {
|
|
8220
|
-
const board = await
|
|
8328
|
+
const board = await open2();
|
|
8221
8329
|
const tasks = await board.listTasks(projectSlug);
|
|
8222
8330
|
print(tasks, () => tasks.length === 0 ? "No tasks." : tasks.map((t) => {
|
|
8223
8331
|
const stage = t.stages[stageIndex(t, t.stage)];
|
|
@@ -8226,7 +8334,7 @@ task.command("list <project>").description("List a project's tasks with their cu
|
|
|
8226
8334
|
});
|
|
8227
8335
|
var thread = program.command("thread").description("Manage threads");
|
|
8228
8336
|
thread.command("open [taskId]").description("Open a thread on a task, on a proposal, or on a channel with a title").option("--proposal <id>", "open the proposal's thread").option("--channel <ref>", "the channel it hangs off; required for a topic").option("--title <text>", "the thread's title; required for a topic").option("--as <agent>", "act as this agent instead of the user").action(async (taskId, opts) => {
|
|
8229
|
-
const board = await
|
|
8337
|
+
const board = await open2();
|
|
8230
8338
|
const opened = await board.openThread(await actorFor(board, opts.as), {
|
|
8231
8339
|
...taskId === void 0 ? {} : { task_id: taskId },
|
|
8232
8340
|
...opts.proposal === void 0 ? {} : { proposal_id: opts.proposal },
|
|
@@ -8236,7 +8344,7 @@ thread.command("open [taskId]").description("Open a thread on a task, on a propo
|
|
|
8236
8344
|
print(opened, () => `Thread ${opened.id} opened on ${opened.channel}: ${opened.title}`);
|
|
8237
8345
|
});
|
|
8238
8346
|
thread.command("close <threadId>").description("Close a thread with a summary posted to its channel").requiredOption("--summary <text>", "closure summary").option("--as <agent>", "act as this agent instead of the user").action(async (threadId, opts) => {
|
|
8239
|
-
const board = await
|
|
8347
|
+
const board = await open2();
|
|
8240
8348
|
const summary = await board.closeThread(await actorFor(board, opts.as), {
|
|
8241
8349
|
thread_id: threadId,
|
|
8242
8350
|
summary: opts.summary
|
|
@@ -8244,7 +8352,7 @@ thread.command("close <threadId>").description("Close a thread with a summary po
|
|
|
8244
8352
|
print(summary, () => `Thread closed; summary posted as ${summary.id} to ${summary.channel}`);
|
|
8245
8353
|
});
|
|
8246
8354
|
thread.command("list").description("List threads, the society's first, then each project's").option("--open", "only open threads", false).action(async (opts) => {
|
|
8247
|
-
const board = await
|
|
8355
|
+
const board = await open2();
|
|
8248
8356
|
const threads = (await board.listThreads()).filter((t) => !opts.open || t.state === "open");
|
|
8249
8357
|
print(threads, () => threads.length === 0 ? "No threads." : threads.map((t) => {
|
|
8250
8358
|
const about = t.subject === void 0 ? "topic" : t.subject.kind;
|
|
@@ -8252,7 +8360,7 @@ thread.command("list").description("List threads, the society's first, then each
|
|
|
8252
8360
|
}).join("\n"));
|
|
8253
8361
|
});
|
|
8254
8362
|
thread.command("show <threadId>").description("Show a thread and its messages").action(async (threadId) => {
|
|
8255
|
-
const board = await
|
|
8363
|
+
const board = await open2();
|
|
8256
8364
|
const found = await board.readThread(threadId);
|
|
8257
8365
|
const messages = await board.listThread(threadId);
|
|
8258
8366
|
print({ thread: found, messages }, () => [
|
|
@@ -8263,17 +8371,17 @@ thread.command("show <threadId>").description("Show a thread and its messages").
|
|
|
8263
8371
|
].join("\n"));
|
|
8264
8372
|
});
|
|
8265
8373
|
program.command("pause").description("Stop all wakeups; turns in flight finish").action(async () => {
|
|
8266
|
-
const board = await
|
|
8374
|
+
const board = await open2();
|
|
8267
8375
|
await board.setPaused(board.userActor(), true);
|
|
8268
8376
|
print({ paused: true }, () => "Society paused");
|
|
8269
8377
|
});
|
|
8270
8378
|
program.command("resume").description("Allow wakeups again").action(async () => {
|
|
8271
|
-
const board = await
|
|
8379
|
+
const board = await open2();
|
|
8272
8380
|
await board.setPaused(board.userActor(), false);
|
|
8273
8381
|
print({ paused: false }, () => "Society resumed");
|
|
8274
8382
|
});
|
|
8275
8383
|
program.command("society").description("The society's settings").command("timezone [zone]").description("Show the society's time zone, or set it: crons that name none are read in it").action(async (zone) => {
|
|
8276
|
-
const board = await
|
|
8384
|
+
const board = await open2();
|
|
8277
8385
|
const society = zone === void 0 ? await board.society() : await board.setTimezone(board.userActor(), zone);
|
|
8278
8386
|
print({ timezone: society.timezone }, () => `Time zone: ${society.timezone}`);
|
|
8279
8387
|
});
|
|
@@ -8289,13 +8397,13 @@ function describeCron(cron2, timeZone) {
|
|
|
8289
8397
|
}
|
|
8290
8398
|
var cron = program.command("cron").description("Crons that wake citizens on a clock");
|
|
8291
8399
|
cron.command("list").description("List crons, ended ones too with --all").option("--all", "include ended crons", false).action(async (opts) => {
|
|
8292
|
-
const board = await
|
|
8400
|
+
const board = await open2();
|
|
8293
8401
|
const { timezone } = await board.society();
|
|
8294
8402
|
const crons = (await board.listCrons()).filter((each) => opts.all || each.ended === void 0);
|
|
8295
8403
|
print(crons, () => crons.length === 0 ? "No crons." : crons.map((each) => describeCron(each, timezone)).join("\n"));
|
|
8296
8404
|
});
|
|
8297
8405
|
cron.command("add <agent> <title>").description("Set a cron that wakes a citizen, with a note on what to do then").requiredOption("--note <text>", "what the citizen does when it fires").option("--cron <expression>", "five fields: minute hour day-of-month month day-of-week").option("--timezone <zone>", "the zone the expression is read in; the society's otherwise").option("--at <time>", "one time to fire, with its offset, instead of --cron").option("--project <slug>", "where it fires: a project the citizen is in, or society").option("--thread <id>", "an open thread there whose conversation it fires in").option("--channel <name>", "an open channel there, other than general, whose conversation it fires in").option("--as <agent>", "act as this agent instead of the user").action(async (agentName, title, opts) => {
|
|
8298
|
-
const board = await
|
|
8406
|
+
const board = await open2();
|
|
8299
8407
|
const created = await board.createCron(await actorFor(board, opts.as), {
|
|
8300
8408
|
title,
|
|
8301
8409
|
note: opts.note,
|
|
@@ -8315,7 +8423,7 @@ for (const [name, paused] of [
|
|
|
8315
8423
|
["resume", false]
|
|
8316
8424
|
]) {
|
|
8317
8425
|
cron.command(`${name} <id>`).description(paused ? "Pause a cron" : "Resume a paused cron from its next time").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8318
|
-
const board = await
|
|
8426
|
+
const board = await open2();
|
|
8319
8427
|
const updated = await board.updateCron(await actorFor(board, opts.as), {
|
|
8320
8428
|
cron_id: id,
|
|
8321
8429
|
paused
|
|
@@ -8325,7 +8433,7 @@ for (const [name, paused] of [
|
|
|
8325
8433
|
});
|
|
8326
8434
|
}
|
|
8327
8435
|
cron.command("remove <id>").description("End a cron for good").requiredOption("--reason <text>", "why it ends").option("--as <agent>", "act as this agent instead of the user").action(async (id, opts) => {
|
|
8328
|
-
const board = await
|
|
8436
|
+
const board = await open2();
|
|
8329
8437
|
const removed = await board.removeCron(await actorFor(board, opts.as), {
|
|
8330
8438
|
cron_id: id,
|
|
8331
8439
|
reason: opts.reason
|
|
@@ -8334,12 +8442,12 @@ cron.command("remove <id>").description("End a cron for good").requiredOption("-
|
|
|
8334
8442
|
});
|
|
8335
8443
|
var knowledge = program.command("knowledge").description("Shared knowledge, by project or society");
|
|
8336
8444
|
knowledge.command("list [project]").description("List knowledge topics of a project, or of the society when no project is given").action(async (projectSlug) => {
|
|
8337
|
-
const board = await
|
|
8445
|
+
const board = await open2();
|
|
8338
8446
|
const topics = await board.listKnowledge(projectSlug ?? null);
|
|
8339
8447
|
print(topics, () => topics.length === 0 ? "No knowledge yet." : topics.map((t) => `${t.topic} revision ${t.revision}, updated by ${t.updatedBy} at ${t.updatedAt}`).join("\n"));
|
|
8340
8448
|
});
|
|
8341
8449
|
knowledge.command("show <topic>").description("Print a knowledge topic").option("--project <slug>", "the project's topic instead of the society's").action(async (topic, opts) => {
|
|
8342
|
-
const board = await
|
|
8450
|
+
const board = await open2();
|
|
8343
8451
|
const found = (await board.listKnowledge(opts.project ?? null)).find((t) => t.topic === topic);
|
|
8344
8452
|
if (found === void 0) {
|
|
8345
8453
|
throw new BoardError("NOT_FOUND", `no knowledge topic ${topic}`);
|
|
@@ -8347,8 +8455,8 @@ knowledge.command("show <topic>").description("Print a knowledge topic").option(
|
|
|
8347
8455
|
print(found, () => found.body);
|
|
8348
8456
|
});
|
|
8349
8457
|
knowledge.command("write <topic>").description("Write a knowledge topic as the user, from a file or standard input").requiredOption("--revision <n>", "the revision it replaces, as knowledge list shows it; 0 for a new topic").option("--project <slug>", "the project's topic instead of the society's").option("--file <path>", "read the body from this file instead of standard input").option("--as <agent>", "act as this agent instead of the user").action(async (topic, opts) => {
|
|
8350
|
-
const board = await
|
|
8351
|
-
const body = opts.file === void 0 ? await readStdin() : await
|
|
8458
|
+
const board = await open2();
|
|
8459
|
+
const body = opts.file === void 0 ? await readStdin() : await readFile5(path7.resolve(opts.file), "utf8");
|
|
8352
8460
|
const written = await board.writeKnowledge(await actorFor(board, opts.as), {
|
|
8353
8461
|
project: opts.project ?? null,
|
|
8354
8462
|
topic,
|
|
@@ -8359,7 +8467,7 @@ knowledge.command("write <topic>").description("Write a knowledge topic as the u
|
|
|
8359
8467
|
});
|
|
8360
8468
|
var skill = program.command("skill").description("Skills promoted to the society");
|
|
8361
8469
|
skill.command("list").description("List the society's skills, and each member's own").action(async () => {
|
|
8362
|
-
const board = await
|
|
8470
|
+
const board = await open2();
|
|
8363
8471
|
const society = await board.listSocietySkills();
|
|
8364
8472
|
const own = [];
|
|
8365
8473
|
for (const member of await board.listAgents()) {
|
|
@@ -8374,7 +8482,7 @@ skill.command("list").description("List the society's skills, and each member's
|
|
|
8374
8482
|
].join("\n") || "No skills yet.");
|
|
8375
8483
|
});
|
|
8376
8484
|
skill.command("remove <name>").description("Remove a skill from the society's skills; its text is set aside, not destroyed").requiredOption("--reason <text>", "why it is wrong, superseded, or no longer used").option("--as <agent>", "act as this agent instead of the user").action(async (name, opts) => {
|
|
8377
|
-
const board = await
|
|
8485
|
+
const board = await open2();
|
|
8378
8486
|
const removed = await board.removeSkill(await actorFor(board, opts.as), {
|
|
8379
8487
|
name,
|
|
8380
8488
|
reason: opts.reason
|
|
@@ -8383,13 +8491,13 @@ skill.command("remove <name>").description("Remove a skill from the society's sk
|
|
|
8383
8491
|
});
|
|
8384
8492
|
var turn = program.command("turn").description("Turn operations");
|
|
8385
8493
|
turn.command("digest <agent>").description("Show the unread messages the agent's next turn opens with, in one scope or all; the cursors stay put").option("--limit <n>", "maximum messages", "50").option("--project <slug>", "the scope whose turn to show: a project, or society").action(async (agentName, opts) => {
|
|
8386
|
-
const board = await
|
|
8494
|
+
const board = await open2();
|
|
8387
8495
|
const actor = await board.actorFor(agentName);
|
|
8388
8496
|
const digest = await board.readDigest(opts.project === void 0 ? actor : { ...actor, scope: opts.project }, { advance: false, limit: Number(opts.limit) });
|
|
8389
8497
|
print(digest, () => digest.messages.length === 0 ? "No unread messages." : digest.messages.map((m) => `[${m.ts}] ${m.channel}${m.thread === void 0 ? "" : ` (thread ${m.thread})`} @${m.author}: ${m.body.trim()}`).join("\n"));
|
|
8390
8498
|
});
|
|
8391
8499
|
turn.command("run <agent>").description("Enqueue a manual wake for an agent on a project, or a reflection turn").requiredOption("--project <slug>", "project to act on, or society for a society-scope turn").option("--reason <text>", "why", "manual wake from the admin CLI").option("--reflect", "a reflection turn instead of a working turn", false).action(async (agentName, opts) => {
|
|
8392
|
-
const board = await
|
|
8500
|
+
const board = await open2();
|
|
8393
8501
|
const event = await board.requestWake(board.userActor(), {
|
|
8394
8502
|
agent: agentName,
|
|
8395
8503
|
project: opts.project,
|