@rness/cli 0.21.0 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +161 -95
- package/dist/bin/rness.js +2 -2
- package/dist/{chunk-D3D2WCGW.js → chunk-OUZQGG6V.js} +464 -399
- package/dist/chunk-OUZQGG6V.js.map +1 -0
- package/dist/{chunk-4BM4FUWO.js → chunk-PW5RMU2G.js} +8 -8
- package/dist/chunk-PW5RMU2G.js.map +1 -0
- package/dist/{chunk-T5PINUCP.js → chunk-SX7D5W43.js} +131 -114
- package/dist/chunk-SX7D5W43.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/{note-RBG7OXVI.js → note-MKUG7GOT.js} +5 -5
- package/dist/{summary-UCMFESSA.js → summary-5DVUIOJM.js} +4 -4
- package/dist/summary-5DVUIOJM.js.map +1 -0
- package/package.json +1 -1
- package/scaffold/README.md +3 -3
- package/scaffold/WORKSPACE.md +2 -2
- package/scaffold/adr/0000-template.md +5 -5
- package/dist/chunk-4BM4FUWO.js.map +0 -1
- package/dist/chunk-D3D2WCGW.js.map +0 -1
- package/dist/chunk-T5PINUCP.js.map +0 -1
- package/dist/summary-UCMFESSA.js.map +0 -1
- /package/dist/{note-RBG7OXVI.js.map → note-MKUG7GOT.js.map} +0 -0
|
@@ -217,7 +217,9 @@ function documentNumber(rel) {
|
|
|
217
217
|
}
|
|
218
218
|
function documentTitle(heading, number) {
|
|
219
219
|
if (number === null) return heading;
|
|
220
|
-
const rest = new RegExp(`^${number}\\s*[\u2014\u2013:-]\\s*(.+)$`).exec(
|
|
220
|
+
const rest = new RegExp(`^${number}\\s*[\u2014\u2013:-]\\s*(.+)$`).exec(
|
|
221
|
+
heading
|
|
222
|
+
)?.[1];
|
|
221
223
|
return rest ?? heading;
|
|
222
224
|
}
|
|
223
225
|
|
|
@@ -288,7 +290,7 @@ async function checkContract(rnessDir, override) {
|
|
|
288
290
|
for (const key of PLACEMENT_KEYS) {
|
|
289
291
|
if (Object.hasOwn(item.fields, key)) {
|
|
290
292
|
problems.push(
|
|
291
|
-
`${where}: front matter "${key}" is not supported
|
|
293
|
+
`${where}: front matter "${key}" is not supported: the directory decides the scope; move the file`
|
|
292
294
|
);
|
|
293
295
|
}
|
|
294
296
|
}
|
|
@@ -856,16 +858,33 @@ function readHooks(value, at, fields2, holdsPlans) {
|
|
|
856
858
|
).withColon();
|
|
857
859
|
return hooks;
|
|
858
860
|
}
|
|
861
|
+
var PULSE = "pulse";
|
|
862
|
+
var presetFor = (name) => name === PULSE ? "agent-pulse" : "collection";
|
|
863
|
+
var PRESET_NAME = /^[a-z][a-z0-9-]*(?:\/[1-9][0-9]*)?$/;
|
|
864
|
+
function readPresetEntry(name, value, knows = isPresetRevision) {
|
|
865
|
+
const at = `boards.${name}`;
|
|
866
|
+
const preset = presetFor(name);
|
|
867
|
+
if (!PRESET_NAME.test(value))
|
|
868
|
+
throw new BoardRefused(at, `must name a preset, as "${preset}"`);
|
|
869
|
+
if (presetNameOf(value) !== preset)
|
|
870
|
+
throw new BoardRefused(
|
|
871
|
+
at,
|
|
872
|
+
name === PULSE ? `names ${value}: ${PULSE} is made from ${preset}` : `names ${value}: a collection's board is made from ${preset}`
|
|
873
|
+
);
|
|
874
|
+
if (value.includes("/") && !knows(value))
|
|
875
|
+
throw new BoardRefused(at, `names ${value}, which this rness does not have`);
|
|
876
|
+
return value;
|
|
877
|
+
}
|
|
859
878
|
function parseBoard(name, value, knows = isPresetRevision) {
|
|
860
|
-
const at = `
|
|
879
|
+
const at = `boards.${name}`;
|
|
861
880
|
if (!isRecord(value))
|
|
862
881
|
throw new BoardRefused(
|
|
863
882
|
at,
|
|
864
|
-
'must be an object, as { "
|
|
883
|
+
'must be an object, as { "collections": \u2026, "views": \u2026 }'
|
|
865
884
|
);
|
|
866
885
|
unknownKeys(value, BOARD_KEYS, at, "a board");
|
|
867
|
-
const number = value["number"];
|
|
868
|
-
if (typeof number !== "number" || !Number.isInteger(number) || number < 1)
|
|
886
|
+
const number = value["number"] ?? null;
|
|
887
|
+
if (number !== null && (typeof number !== "number" || !Number.isInteger(number) || number < 1))
|
|
869
888
|
throw new BoardRefused(`${at}.number`, "must be a project number");
|
|
870
889
|
const preset = value["preset"];
|
|
871
890
|
if (preset !== void 0 && (typeof preset !== "string" || !PRESET.test(preset)))
|
|
@@ -1230,8 +1249,10 @@ var KEYS = [
|
|
|
1230
1249
|
"provider",
|
|
1231
1250
|
"org",
|
|
1232
1251
|
"agents",
|
|
1233
|
-
"
|
|
1252
|
+
"boards",
|
|
1253
|
+
// Former names of `boards`, still read: `sync` renames them (spec 0033 §3).
|
|
1234
1254
|
"projects",
|
|
1255
|
+
"pulse",
|
|
1235
1256
|
"repos",
|
|
1236
1257
|
"scopes"
|
|
1237
1258
|
];
|
|
@@ -1287,52 +1308,57 @@ function readProvider(value) {
|
|
|
1287
1308
|
return name;
|
|
1288
1309
|
}
|
|
1289
1310
|
function readPulse(value) {
|
|
1290
|
-
if (value === void 0) return null;
|
|
1291
1311
|
if (!isRecord2(value) || Object.keys(value).length !== 1 || typeof value.project !== "number" || !Number.isInteger(value.project) || value.project < 1)
|
|
1292
1312
|
fail2(
|
|
1293
1313
|
`"pulse" must be { "project": <number> } (got ${JSON.stringify(value)})`
|
|
1294
1314
|
);
|
|
1295
1315
|
return { [PULSE]: value.project };
|
|
1296
1316
|
}
|
|
1297
|
-
var
|
|
1298
|
-
var PULSE = "pulse";
|
|
1299
|
-
var PROJECT_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
1317
|
+
var BOARD_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
1300
1318
|
var isProjectNumber = (n) => typeof n === "number" && Number.isInteger(n) && n >= 1;
|
|
1301
|
-
function
|
|
1302
|
-
if (value === void 0) return { projects: null, refused: [] };
|
|
1319
|
+
function readBoardEntries(value) {
|
|
1303
1320
|
const entries = isRecord2(value) ? Object.entries(value) : [];
|
|
1304
|
-
const numbers = entries.
|
|
1305
|
-
([, n]) => isRecord2(n)
|
|
1321
|
+
const numbers = entries.flatMap(
|
|
1322
|
+
([, n]) => isRecord2(n) ? isProjectNumber(n["number"]) ? [n["number"]] : [] : [n]
|
|
1306
1323
|
);
|
|
1307
1324
|
if (entries.length === 0 || !entries.every(
|
|
1308
|
-
([name, n]) =>
|
|
1325
|
+
([name, n]) => BOARD_NAME.test(name) && (isProjectNumber(n) || typeof n === "string" || isRecord2(n))
|
|
1309
1326
|
) || new Set(numbers).size !== numbers.length)
|
|
1310
1327
|
fail2(
|
|
1311
|
-
`"
|
|
1328
|
+
`"boards" must map names to boards on distinct projects, as { "pulse": "agent-pulse", "marketing": 5 } (got ${JSON.stringify(value)})`
|
|
1312
1329
|
);
|
|
1313
|
-
const
|
|
1330
|
+
const boards = {};
|
|
1314
1331
|
const refused = [];
|
|
1315
1332
|
for (const [name, entry] of entries) {
|
|
1316
1333
|
if (isProjectNumber(entry)) {
|
|
1317
|
-
|
|
1334
|
+
boards[name] = entry;
|
|
1318
1335
|
continue;
|
|
1319
1336
|
}
|
|
1320
1337
|
try {
|
|
1321
|
-
|
|
1338
|
+
boards[name] = typeof entry === "string" ? readPresetEntry(name, entry) : parseBoard(name, entry);
|
|
1322
1339
|
} catch (e) {
|
|
1323
1340
|
if (!(e instanceof BoardRefused)) throw e;
|
|
1324
1341
|
refused.push({ name, reason: e.message, source: entry });
|
|
1325
1342
|
}
|
|
1326
1343
|
}
|
|
1327
1344
|
return {
|
|
1328
|
-
|
|
1345
|
+
boards: Object.keys(boards).length === 0 ? null : boards,
|
|
1329
1346
|
refused
|
|
1330
1347
|
};
|
|
1331
1348
|
}
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1349
|
+
var HOLDERS = ["boards", "projects", "pulse"];
|
|
1350
|
+
function readBoardsOrFormer(data) {
|
|
1351
|
+
const present = HOLDERS.filter((k) => data[k] !== void 0);
|
|
1352
|
+
if (present.length > 1)
|
|
1353
|
+
fail2(
|
|
1354
|
+
`${present.map((k) => JSON.stringify(k)).join(" and ")} at once: keep "boards" only`
|
|
1355
|
+
);
|
|
1356
|
+
const key = present[0];
|
|
1357
|
+
if (key === void 0) return { boards: null, refused: [] };
|
|
1358
|
+
if (key === "pulse")
|
|
1359
|
+
return { boards: readPulse(data.pulse), refused: [], formerKey: key };
|
|
1360
|
+
const read = readBoardEntries(data[key]);
|
|
1361
|
+
return key === "boards" ? read : { ...read, formerKey: key };
|
|
1336
1362
|
}
|
|
1337
1363
|
function providerOf(manifest) {
|
|
1338
1364
|
if (manifest.provider !== null) return manifest.provider;
|
|
@@ -1399,34 +1425,36 @@ function parseManifest(raw) {
|
|
|
1399
1425
|
for (const key of Object.keys(data)) {
|
|
1400
1426
|
if (!KEYS.includes(key)) fail2(`unknown key ${JSON.stringify(key)}`);
|
|
1401
1427
|
}
|
|
1402
|
-
const {
|
|
1428
|
+
const { boards, refused, formerKey } = readBoardsOrFormer(data);
|
|
1403
1429
|
return {
|
|
1404
1430
|
contract: 1,
|
|
1405
1431
|
provider: readProvider(data.provider),
|
|
1406
1432
|
org: readOrg(data.org),
|
|
1407
1433
|
agents: readAgents(data.agents),
|
|
1408
|
-
|
|
1434
|
+
boards,
|
|
1409
1435
|
...refused.length === 0 ? {} : { refused },
|
|
1436
|
+
...formerKey === void 0 ? {} : { formerKey },
|
|
1410
1437
|
repos: readRepos(data.repos),
|
|
1411
1438
|
scopes: readScopes(data.scopes)
|
|
1412
1439
|
};
|
|
1413
1440
|
}
|
|
1414
|
-
var
|
|
1415
|
-
|
|
1441
|
+
var boardEntry = (name, value) => ` ${JSON.stringify(name)}: ${JSON.stringify(value, null, 2).replaceAll("\n", "\n ")}`;
|
|
1442
|
+
var isScalar = (v) => typeof v === "number" || typeof v === "string";
|
|
1443
|
+
function boardsLines(manifest) {
|
|
1416
1444
|
const entries = [
|
|
1417
|
-
...Object.entries(manifest.
|
|
1418
|
-
([name,
|
|
1445
|
+
...Object.entries(manifest.boards ?? {}).map(
|
|
1446
|
+
([name, b]) => [name, isScalar(b) ? b : b.source]
|
|
1419
1447
|
),
|
|
1420
1448
|
...(manifest.refused ?? []).map((r) => [r.name, r.source])
|
|
1421
1449
|
];
|
|
1422
1450
|
if (entries.length === 0) return [];
|
|
1423
|
-
if (entries.every(([, v]) =>
|
|
1451
|
+
if (entries.every(([, v]) => isScalar(v)))
|
|
1424
1452
|
return [
|
|
1425
|
-
` "
|
|
1453
|
+
` "boards": { ${entries.map(([name, v]) => `${JSON.stringify(name)}: ${JSON.stringify(v)}`).join(", ")} },`
|
|
1426
1454
|
];
|
|
1427
1455
|
return [
|
|
1428
|
-
' "
|
|
1429
|
-
entries.map(([name, v]) =>
|
|
1456
|
+
' "boards": {',
|
|
1457
|
+
entries.map(([name, v]) => boardEntry(name, v)).join(",\n"),
|
|
1430
1458
|
" },"
|
|
1431
1459
|
];
|
|
1432
1460
|
}
|
|
@@ -1447,7 +1475,7 @@ async function writeManifest(rnessDir, manifest) {
|
|
|
1447
1475
|
lines.push(
|
|
1448
1476
|
` "agents": [${manifest.agents.map((a) => JSON.stringify(a)).join(", ")}],`
|
|
1449
1477
|
);
|
|
1450
|
-
lines.push(...
|
|
1478
|
+
lines.push(...boardsLines(manifest));
|
|
1451
1479
|
lines.push(
|
|
1452
1480
|
' "repos": {',
|
|
1453
1481
|
repos.join(",\n"),
|
|
@@ -1489,7 +1517,7 @@ function parseRepoSpec(spec, org, host) {
|
|
|
1489
1517
|
}
|
|
1490
1518
|
|
|
1491
1519
|
// src/version.ts
|
|
1492
|
-
var VERSION = "0.
|
|
1520
|
+
var VERSION = "0.22.1";
|
|
1493
1521
|
|
|
1494
1522
|
// src/core/pm.ts
|
|
1495
1523
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -1715,7 +1743,7 @@ async function documentsIn(ws, manifest, scope, collections, statuses) {
|
|
|
1715
1743
|
return paths;
|
|
1716
1744
|
}
|
|
1717
1745
|
|
|
1718
|
-
// src/
|
|
1746
|
+
// src/board/urls.ts
|
|
1719
1747
|
var boardUrl = (org, project) => `https://github.com/orgs/${org}/projects/${project}`;
|
|
1720
1748
|
var itemUrl = (org, project, path) => `${boardUrl(org, project)}?filterQuery=${encodeURIComponent(`path:"${path}"`)}`;
|
|
1721
1749
|
var blobUrl = (org, path) => `https://github.com/${org}/.rness/blob/main/${encodeURI(path)}`;
|
|
@@ -3053,7 +3081,7 @@ import { join as join8 } from "path";
|
|
|
3053
3081
|
var GITHUB_CLIENT_ID = "Ov23liv1ia2UWeWttsOK";
|
|
3054
3082
|
var GITHUB_WEB = "https://github.com";
|
|
3055
3083
|
var SCOPES = "repo read:org";
|
|
3056
|
-
var
|
|
3084
|
+
var BOARD_SCOPE = "project";
|
|
3057
3085
|
function clientId() {
|
|
3058
3086
|
return process.env["RNESS_GITHUB_CLIENT_ID"] ?? GITHUB_CLIENT_ID;
|
|
3059
3087
|
}
|
|
@@ -3312,7 +3340,7 @@ async function resolveToken(deps = {}) {
|
|
|
3312
3340
|
return refreshed === null ? null : answer(refreshed);
|
|
3313
3341
|
}
|
|
3314
3342
|
|
|
3315
|
-
// src/
|
|
3343
|
+
// src/board/body.ts
|
|
3316
3344
|
import { createHash } from "crypto";
|
|
3317
3345
|
import { posix as posix4 } from "path";
|
|
3318
3346
|
var BODY_LIMIT = 65536;
|
|
@@ -3462,7 +3490,7 @@ ${content}`;
|
|
|
3462
3490
|
${comment2(digest(text))}`;
|
|
3463
3491
|
}
|
|
3464
3492
|
|
|
3465
|
-
// src/
|
|
3493
|
+
// src/board/collection.ts
|
|
3466
3494
|
import { readFile as readFile5, readdir as readdir2 } from "fs/promises";
|
|
3467
3495
|
import { join as join9 } from "path";
|
|
3468
3496
|
var FIELD_TYPES2 = ["text", "date", "select", "number"];
|
|
@@ -3654,7 +3682,7 @@ async function readUpdates(rnessDir, dir) {
|
|
|
3654
3682
|
return updates;
|
|
3655
3683
|
}
|
|
3656
3684
|
|
|
3657
|
-
// src/
|
|
3685
|
+
// src/board/layout.ts
|
|
3658
3686
|
var statusOf2 = (status2) => status2 === null || status2 === "?" ? null : status2;
|
|
3659
3687
|
var LIFECYCLE = [
|
|
3660
3688
|
"Draft",
|
|
@@ -3852,7 +3880,7 @@ function desiredOf(board, collections, org, fronts = /* @__PURE__ */ new Map(),
|
|
|
3852
3880
|
}
|
|
3853
3881
|
return {
|
|
3854
3882
|
path: row.path,
|
|
3855
|
-
title: `${row.id}
|
|
3883
|
+
title: `${row.id} - ${row.title}`,
|
|
3856
3884
|
body: headerOf(row.path, org),
|
|
3857
3885
|
status: status2,
|
|
3858
3886
|
statusField: c.field,
|
|
@@ -3873,7 +3901,7 @@ function desiredOf(board, collections, org, fronts = /* @__PURE__ */ new Map(),
|
|
|
3873
3901
|
}));
|
|
3874
3902
|
}
|
|
3875
3903
|
|
|
3876
|
-
// src/
|
|
3904
|
+
// src/board/plan.ts
|
|
3877
3905
|
var lower = (labels) => new Set(labels.map((l) => l.toLowerCase()));
|
|
3878
3906
|
function labelsDiffer(item, w) {
|
|
3879
3907
|
if (w.labels.length === 0 && w.unlabels.length === 0) return false;
|
|
@@ -4093,7 +4121,7 @@ var GitHubBoards = class {
|
|
|
4093
4121
|
const found = await repository(org, MEMORY, LABEL, this.#o);
|
|
4094
4122
|
if (found === null)
|
|
4095
4123
|
throw new Error(
|
|
4096
|
-
`
|
|
4124
|
+
`boards need ${org}/${MEMORY} on GitHub: it is not there, or this login cannot see it`
|
|
4097
4125
|
);
|
|
4098
4126
|
this.#memories.set(org, found);
|
|
4099
4127
|
return found;
|
|
@@ -4101,7 +4129,7 @@ var GitHubBoards = class {
|
|
|
4101
4129
|
async checkIssues(org) {
|
|
4102
4130
|
if (!(await this.#memory(org)).issues)
|
|
4103
4131
|
throw new Error(
|
|
4104
|
-
`
|
|
4132
|
+
`boards need Issues on ${org}/${MEMORY}: turn them on in its Settings`
|
|
4105
4133
|
);
|
|
4106
4134
|
}
|
|
4107
4135
|
/** The project only: the caller declares it before `ensureLayout` builds it. */
|
|
@@ -4271,7 +4299,7 @@ var GitHubBoards = class {
|
|
|
4271
4299
|
if (there.layout !== LAYOUTS[view.layout] || view.layout === "board" && there.columnField !== view.columns) {
|
|
4272
4300
|
await deleteView(there.id, this.#o);
|
|
4273
4301
|
added.push(
|
|
4274
|
-
`view ${view.name} remade${view.layout === "board" ?
|
|
4302
|
+
`view ${view.name} remade${view.layout === "board" ? `, columns ${view.columns}` : ""}`
|
|
4275
4303
|
);
|
|
4276
4304
|
await create(view);
|
|
4277
4305
|
gone2(view.name);
|
|
@@ -4602,7 +4630,7 @@ var GitHubBoards = class {
|
|
|
4602
4630
|
const id = (await this.#memory(board.org)).labelId;
|
|
4603
4631
|
if (id === null)
|
|
4604
4632
|
throw new Error(
|
|
4605
|
-
`${board.org}/${MEMORY} has no label ${LABEL}: run rness
|
|
4633
|
+
`${board.org}/${MEMORY} has no label ${LABEL}: run rness board push`
|
|
4606
4634
|
);
|
|
4607
4635
|
return id;
|
|
4608
4636
|
}
|
|
@@ -4739,7 +4767,7 @@ var GitHubOAuthProvider = class {
|
|
|
4739
4767
|
}
|
|
4740
4768
|
#boards() {
|
|
4741
4769
|
if (this.#token === null)
|
|
4742
|
-
throw new Error("
|
|
4770
|
+
throw new Error("boards need a GitHub login: run rness login");
|
|
4743
4771
|
this.#boardClient ??= new GitHubBoards(this.#api(this.#token.token));
|
|
4744
4772
|
return this.#boardClient;
|
|
4745
4773
|
}
|
|
@@ -5117,7 +5145,7 @@ var PROVIDERS = {
|
|
|
5117
5145
|
gitlab: { name: "gitlab", label: "GitLab", available: false },
|
|
5118
5146
|
atlassian: {
|
|
5119
5147
|
name: "atlassian",
|
|
5120
|
-
label: "Atlassian
|
|
5148
|
+
label: "Atlassian (Bitbucket + Jira)",
|
|
5121
5149
|
available: false
|
|
5122
5150
|
}
|
|
5123
5151
|
};
|
|
@@ -5338,7 +5366,7 @@ function sessionUi(p) {
|
|
|
5338
5366
|
spin.stop(line === null ? label : label_(line));
|
|
5339
5367
|
return result;
|
|
5340
5368
|
} catch (e) {
|
|
5341
|
-
spin.error(`${label}
|
|
5369
|
+
spin.error(`${label}: failed`);
|
|
5342
5370
|
throw e;
|
|
5343
5371
|
}
|
|
5344
5372
|
}
|
|
@@ -5406,14 +5434,14 @@ async function loginCommand(opts, deps = {}) {
|
|
|
5406
5434
|
ui.error(unsupportedProviderMessage(manifest.provider));
|
|
5407
5435
|
return 1;
|
|
5408
5436
|
}
|
|
5409
|
-
const needsProject = opts.project === true || manifest?.
|
|
5437
|
+
const needsProject = opts.project === true || manifest?.boards != null;
|
|
5410
5438
|
const bin = deps.bin ?? await realpath2(process.argv[1] ?? "").catch(() => "");
|
|
5411
5439
|
const env = envToken();
|
|
5412
5440
|
if (env !== null)
|
|
5413
5441
|
ui.hint(`${env.source} is set and wins over a stored login`);
|
|
5414
5442
|
const stored = await readAuth();
|
|
5415
5443
|
const resolved = stored === null ? null : await resolveToken();
|
|
5416
|
-
const lacksProject = needsProject && resolved?.source === "login" && !splitScopes(stored?.tokens.scopes ?? "").includes(
|
|
5444
|
+
const lacksProject = needsProject && resolved?.source === "login" && !splitScopes(stored?.tokens.scopes ?? "").includes(BOARD_SCOPE);
|
|
5417
5445
|
if (stored !== null && resolved !== null && !lacksProject) {
|
|
5418
5446
|
ui.line(
|
|
5419
5447
|
"logged in",
|
|
@@ -5425,7 +5453,7 @@ async function loginCommand(opts, deps = {}) {
|
|
|
5425
5453
|
}
|
|
5426
5454
|
if (lacksProject) ui.line("login", "logging in again for the project scope");
|
|
5427
5455
|
const code = await requestDeviceCode(
|
|
5428
|
-
needsProject ? `${SCOPES} ${
|
|
5456
|
+
needsProject ? `${SCOPES} ${BOARD_SCOPE}` : SCOPES
|
|
5429
5457
|
);
|
|
5430
5458
|
if (ui.session)
|
|
5431
5459
|
ui.line(
|
|
@@ -5471,7 +5499,7 @@ async function loginCommand(opts, deps = {}) {
|
|
|
5471
5499
|
}
|
|
5472
5500
|
}
|
|
5473
5501
|
|
|
5474
|
-
// src/
|
|
5502
|
+
// src/board/journal-state.ts
|
|
5475
5503
|
import { mkdir as mkdir2, readFile as readFile7, rename as rename2, rm as rm4, writeFile as writeFile2 } from "fs/promises";
|
|
5476
5504
|
import { dirname as dirname4, join as join12 } from "path";
|
|
5477
5505
|
var notedOf = (value) => {
|
|
@@ -5583,13 +5611,182 @@ async function takeNotices() {
|
|
|
5583
5611
|
return Array.isArray(now) ? now.filter((l) => typeof l === "string") : [];
|
|
5584
5612
|
}
|
|
5585
5613
|
|
|
5586
|
-
// src/commands/
|
|
5614
|
+
// src/commands/board.ts
|
|
5587
5615
|
import { readFile as readFile12, readdir as readdir4 } from "fs/promises";
|
|
5588
5616
|
import { join as join15 } from "path";
|
|
5589
5617
|
import { setTimeout as delay3 } from "timers/promises";
|
|
5590
5618
|
|
|
5619
|
+
// src/board/detached.ts
|
|
5620
|
+
import { spawn as nodeSpawn } from "child_process";
|
|
5621
|
+
import { mkdir as mkdir3, open as open2, readFile as readFile8, rm as rm5, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
5622
|
+
import { join as join13 } from "path";
|
|
5623
|
+
import { setTimeout as delay2 } from "timers/promises";
|
|
5624
|
+
var detached = (args, cwd) => {
|
|
5625
|
+
const bin = process.argv[1];
|
|
5626
|
+
if (bin === void 0) return;
|
|
5627
|
+
const child = nodeSpawn(process.execPath, [bin, ...args], {
|
|
5628
|
+
detached: true,
|
|
5629
|
+
stdio: "ignore",
|
|
5630
|
+
cwd,
|
|
5631
|
+
env: { ...process.env, RNESS_NO_DELEGATE: "1" }
|
|
5632
|
+
});
|
|
5633
|
+
child.on("error", () => void 0);
|
|
5634
|
+
child.unref();
|
|
5635
|
+
};
|
|
5636
|
+
var failureFile = () => join13(configDir(), "board.json");
|
|
5637
|
+
var formerFailureFile = () => join13(configDir(), "pulse.json");
|
|
5638
|
+
async function recordFailure(reason3) {
|
|
5639
|
+
try {
|
|
5640
|
+
await mkdir3(configDir(), { recursive: true, mode: 448 });
|
|
5641
|
+
await writeFile3(
|
|
5642
|
+
failureFile(),
|
|
5643
|
+
`${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), reason: reason3 })}
|
|
5644
|
+
`
|
|
5645
|
+
);
|
|
5646
|
+
} catch {
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
async function takeFailure() {
|
|
5650
|
+
return await takeFrom(failureFile()) ?? await takeFrom(formerFailureFile());
|
|
5651
|
+
}
|
|
5652
|
+
async function takeFrom(file) {
|
|
5653
|
+
try {
|
|
5654
|
+
const data = JSON.parse(await readFile8(file, "utf8"));
|
|
5655
|
+
await rm5(file, { force: true });
|
|
5656
|
+
const reason3 = data !== null && typeof data === "object" ? data["reason"] : void 0;
|
|
5657
|
+
return typeof reason3 === "string" && reason3 !== "" ? reason3 : null;
|
|
5658
|
+
} catch {
|
|
5659
|
+
return null;
|
|
5660
|
+
}
|
|
5661
|
+
}
|
|
5662
|
+
var LOCK_STALE_MS2 = 15 * 6e4;
|
|
5663
|
+
async function oneSyncAtATime(key, work, options = {}) {
|
|
5664
|
+
await mkdir3(configDir(), { recursive: true, mode: 448 });
|
|
5665
|
+
const file = join13(configDir(), `board-${key}.lock`);
|
|
5666
|
+
for (; ; ) {
|
|
5667
|
+
try {
|
|
5668
|
+
const handle = await open2(file, "wx");
|
|
5669
|
+
await handle.close();
|
|
5670
|
+
break;
|
|
5671
|
+
} catch (e) {
|
|
5672
|
+
if (e.code !== "EEXIST") throw e;
|
|
5673
|
+
const age = await stat2(file).then(
|
|
5674
|
+
(s) => Date.now() - s.mtimeMs,
|
|
5675
|
+
() => 0
|
|
5676
|
+
);
|
|
5677
|
+
if (age > LOCK_STALE_MS2) await rm5(file, { force: true });
|
|
5678
|
+
else if (options.wait !== true) return false;
|
|
5679
|
+
else await (options.sleep ?? ((ms) => delay2(ms)))(1e3);
|
|
5680
|
+
}
|
|
5681
|
+
}
|
|
5682
|
+
try {
|
|
5683
|
+
await work();
|
|
5684
|
+
return true;
|
|
5685
|
+
} finally {
|
|
5686
|
+
await rm5(file, { force: true });
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
|
|
5690
|
+
// src/board/noted.ts
|
|
5691
|
+
import { mkdir as mkdir4, readFile as readFile9, rename as rename3, rm as rm6, writeFile as writeFile4 } from "fs/promises";
|
|
5692
|
+
import { dirname as dirname5 } from "path";
|
|
5693
|
+
var NAME2 = "rness/noted";
|
|
5694
|
+
function notedFile(rnessDir) {
|
|
5695
|
+
return gitPath(rnessDir, NAME2);
|
|
5696
|
+
}
|
|
5697
|
+
async function readNoted(file) {
|
|
5698
|
+
if (file === null) return /* @__PURE__ */ new Set();
|
|
5699
|
+
try {
|
|
5700
|
+
const data = JSON.parse(await readFile9(file, "utf8"));
|
|
5701
|
+
return new Set(
|
|
5702
|
+
Array.isArray(data) ? data.filter((l) => typeof l === "string") : []
|
|
5703
|
+
);
|
|
5704
|
+
} catch {
|
|
5705
|
+
return /* @__PURE__ */ new Set();
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
async function writeNoted(file, noted) {
|
|
5709
|
+
if (file === null) return;
|
|
5710
|
+
try {
|
|
5711
|
+
if (noted.size === 0) {
|
|
5712
|
+
await rm6(file, { force: true });
|
|
5713
|
+
return;
|
|
5714
|
+
}
|
|
5715
|
+
await mkdir4(dirname5(file), { recursive: true });
|
|
5716
|
+
const temporary = `${file}.${process.pid}`;
|
|
5717
|
+
await writeFile4(
|
|
5718
|
+
temporary,
|
|
5719
|
+
`${JSON.stringify([...noted].sort(), null, 2)}
|
|
5720
|
+
`
|
|
5721
|
+
);
|
|
5722
|
+
await rename3(temporary, file);
|
|
5723
|
+
} catch {
|
|
5724
|
+
}
|
|
5725
|
+
}
|
|
5726
|
+
async function onceSaid(rnessDir, board, lines) {
|
|
5727
|
+
const file = await notedFile(rnessDir);
|
|
5728
|
+
const noted = await readNoted(file);
|
|
5729
|
+
const prefix = `${board}: `;
|
|
5730
|
+
const notes = lines.filter((l) => l.startsWith("note "));
|
|
5731
|
+
const now = new Set(notes.map((l) => `${prefix}${l}`));
|
|
5732
|
+
const said = lines.filter(
|
|
5733
|
+
(l) => !l.startsWith("note ") || !noted.has(`${prefix}${l}`)
|
|
5734
|
+
);
|
|
5735
|
+
const next = /* @__PURE__ */ new Set([
|
|
5736
|
+
...[...noted].filter((l) => !l.startsWith(prefix)),
|
|
5737
|
+
...now
|
|
5738
|
+
]);
|
|
5739
|
+
if (next.size !== noted.size || [...next].some((l) => !noted.has(l)))
|
|
5740
|
+
await writeNoted(file, next);
|
|
5741
|
+
return said;
|
|
5742
|
+
}
|
|
5743
|
+
|
|
5744
|
+
// src/board/opened.ts
|
|
5745
|
+
import { mkdir as mkdir5, readFile as readFile10, rename as rename4, rm as rm7, writeFile as writeFile5 } from "fs/promises";
|
|
5746
|
+
import { dirname as dirname6 } from "path";
|
|
5747
|
+
var NAME3 = "rness/opened";
|
|
5748
|
+
function openedFile(rnessDir) {
|
|
5749
|
+
return gitPath(rnessDir, NAME3);
|
|
5750
|
+
}
|
|
5751
|
+
var NUMBER = /^[1-9][0-9]*$/;
|
|
5752
|
+
async function readOpened(file) {
|
|
5753
|
+
const opened = /* @__PURE__ */ new Map();
|
|
5754
|
+
if (file === null) return opened;
|
|
5755
|
+
let data;
|
|
5756
|
+
try {
|
|
5757
|
+
data = JSON.parse(await readFile10(file, "utf8"));
|
|
5758
|
+
} catch {
|
|
5759
|
+
return opened;
|
|
5760
|
+
}
|
|
5761
|
+
if (data === null || typeof data !== "object" || Array.isArray(data))
|
|
5762
|
+
return opened;
|
|
5763
|
+
for (const [key, path] of Object.entries(data))
|
|
5764
|
+
if (NUMBER.test(key) && typeof path === "string" && path !== "")
|
|
5765
|
+
opened.set(Number(key), path);
|
|
5766
|
+
return opened;
|
|
5767
|
+
}
|
|
5768
|
+
async function writeOpened(file, opened) {
|
|
5769
|
+
if (file === null) return;
|
|
5770
|
+
try {
|
|
5771
|
+
if (opened.size === 0) {
|
|
5772
|
+
await rm7(file, { force: true });
|
|
5773
|
+
return;
|
|
5774
|
+
}
|
|
5775
|
+
const entries = [...opened].sort(([a], [b]) => a - b);
|
|
5776
|
+
await mkdir5(dirname6(file), { recursive: true });
|
|
5777
|
+
const temporary = `${file}.${process.pid}`;
|
|
5778
|
+
await writeFile5(
|
|
5779
|
+
temporary,
|
|
5780
|
+
`${JSON.stringify(Object.fromEntries(entries), null, 2)}
|
|
5781
|
+
`
|
|
5782
|
+
);
|
|
5783
|
+
await rename4(temporary, file);
|
|
5784
|
+
} catch {
|
|
5785
|
+
}
|
|
5786
|
+
}
|
|
5787
|
+
|
|
5591
5788
|
// src/core/board-migration.ts
|
|
5592
|
-
import { readFile as
|
|
5789
|
+
import { readFile as readFile11 } from "fs/promises";
|
|
5593
5790
|
import { parseDocument } from "yaml";
|
|
5594
5791
|
|
|
5595
5792
|
// src/core/board-merge.ts
|
|
@@ -5667,7 +5864,7 @@ function mergeViews(at, base, ours, theirs, ref, kept) {
|
|
|
5667
5864
|
return merged;
|
|
5668
5865
|
}
|
|
5669
5866
|
function mergeBoard(name, base, ours, theirs, ref) {
|
|
5670
|
-
const at = `
|
|
5867
|
+
const at = `boards.${name}`;
|
|
5671
5868
|
const kept = [];
|
|
5672
5869
|
const { number, preset: _, ...team } = ours;
|
|
5673
5870
|
const keys = [
|
|
@@ -5699,8 +5896,8 @@ function mergeBoard(name, base, ours, theirs, ref) {
|
|
|
5699
5896
|
}
|
|
5700
5897
|
|
|
5701
5898
|
// src/core/preset-board.ts
|
|
5702
|
-
import { stat as
|
|
5703
|
-
import { join as
|
|
5899
|
+
import { stat as stat3 } from "fs/promises";
|
|
5900
|
+
import { join as join14 } from "path";
|
|
5704
5901
|
var ORDER = [
|
|
5705
5902
|
"number",
|
|
5706
5903
|
"preset",
|
|
@@ -5722,30 +5919,30 @@ var ordered = (board) => Object.fromEntries(
|
|
|
5722
5919
|
);
|
|
5723
5920
|
async function exists2(path) {
|
|
5724
5921
|
try {
|
|
5725
|
-
await
|
|
5922
|
+
await stat3(path);
|
|
5726
5923
|
return true;
|
|
5727
5924
|
} catch {
|
|
5728
5925
|
return false;
|
|
5729
5926
|
}
|
|
5730
5927
|
}
|
|
5731
|
-
async function presetSource(name, rnessDir, number) {
|
|
5732
|
-
|
|
5733
|
-
|
|
5928
|
+
async function presetSource(name, rnessDir, number, ref) {
|
|
5929
|
+
const kind = presetFor(name);
|
|
5930
|
+
const preset = ref?.includes("/") === true ? ref : currentPreset(kind);
|
|
5931
|
+
const numbered = number === null ? {} : { number };
|
|
5932
|
+
if (name === PULSE)
|
|
5734
5933
|
return ordered({
|
|
5735
|
-
|
|
5736
|
-
preset
|
|
5737
|
-
...presetTemplate(
|
|
5934
|
+
...numbered,
|
|
5935
|
+
preset,
|
|
5936
|
+
...presetTemplate(preset, { collection: name })
|
|
5738
5937
|
});
|
|
5739
|
-
}
|
|
5740
|
-
const preset = currentPreset("collection");
|
|
5741
5938
|
const board = {
|
|
5742
|
-
|
|
5939
|
+
...numbered,
|
|
5743
5940
|
preset,
|
|
5744
5941
|
...presetTemplate(preset, { collection: name })
|
|
5745
5942
|
};
|
|
5746
|
-
if (await exists2(
|
|
5943
|
+
if (await exists2(join14(rnessDir, name, "README.md")))
|
|
5747
5944
|
board["readme"] = `${name}/README.md`;
|
|
5748
|
-
if (await exists2(
|
|
5945
|
+
if (await exists2(join14(rnessDir, name, "updates")))
|
|
5749
5946
|
board["updates"] = `${name}/updates`;
|
|
5750
5947
|
const shape = await readShape(rnessDir, name);
|
|
5751
5948
|
if (shape.description !== null) board["description"] = shape.description;
|
|
@@ -5777,23 +5974,24 @@ async function presetSource(name, rnessDir, number) {
|
|
|
5777
5974
|
return ordered(board);
|
|
5778
5975
|
}
|
|
5779
5976
|
async function declaredBoard(name, entry, rnessDir) {
|
|
5780
|
-
if (typeof entry
|
|
5781
|
-
|
|
5977
|
+
if (typeof entry === "number")
|
|
5978
|
+
return parseBoard(name, await presetSource(name, rnessDir, entry));
|
|
5979
|
+
if (typeof entry === "string")
|
|
5980
|
+
return parseBoard(name, await presetSource(name, rnessDir, null, entry));
|
|
5981
|
+
return entry;
|
|
5782
5982
|
}
|
|
5783
5983
|
async function readBoards(rnessDir) {
|
|
5784
|
-
let
|
|
5984
|
+
let declared;
|
|
5785
5985
|
try {
|
|
5786
|
-
|
|
5986
|
+
declared = (await loadManifest(rnessDir)).boards ?? {};
|
|
5787
5987
|
} catch {
|
|
5788
5988
|
return [];
|
|
5789
5989
|
}
|
|
5790
5990
|
const boards = [];
|
|
5791
|
-
for (const [name, entry] of Object.entries(
|
|
5991
|
+
for (const [name, entry] of Object.entries(declared))
|
|
5792
5992
|
try {
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
declaration: await declaredBoard(name, entry, rnessDir)
|
|
5796
|
-
});
|
|
5993
|
+
const declaration = await declaredBoard(name, entry, rnessDir);
|
|
5994
|
+
if (declaration.number !== null) boards.push({ name, declaration });
|
|
5797
5995
|
} catch {
|
|
5798
5996
|
}
|
|
5799
5997
|
return boards;
|
|
@@ -5814,7 +6012,7 @@ var BUNDLED = {
|
|
|
5814
6012
|
var README = (collection) => `${collection}/README.md`;
|
|
5815
6013
|
async function readmeOf(rnessDir, collection) {
|
|
5816
6014
|
try {
|
|
5817
|
-
return await
|
|
6015
|
+
return await readFile11(
|
|
5818
6016
|
await containedPath(rnessDir, README(collection)),
|
|
5819
6017
|
"utf8"
|
|
5820
6018
|
);
|
|
@@ -5887,20 +6085,31 @@ function moveInto(name, collection, source, declared) {
|
|
|
5887
6085
|
conflicts.push(`fields.${field}`);
|
|
5888
6086
|
}
|
|
5889
6087
|
if (conflicts.length > 0)
|
|
5890
|
-
return `${README(collection)} declares ${conflicts.join(", ")} otherwise than
|
|
6088
|
+
return `${README(collection)} declares ${conflicts.join(", ")} otherwise than boards.${name}: keep one, in rness.json`;
|
|
5891
6089
|
source["fields"] = fields2;
|
|
5892
6090
|
return null;
|
|
5893
6091
|
}
|
|
5894
6092
|
async function migrateBoards(rnessDir, manifest, presets = BUNDLED) {
|
|
5895
6093
|
const migration = {
|
|
5896
6094
|
changed: false,
|
|
5897
|
-
|
|
6095
|
+
boards: manifest.boards,
|
|
5898
6096
|
readmes: /* @__PURE__ */ new Map(),
|
|
5899
6097
|
lines: []
|
|
5900
6098
|
};
|
|
5901
|
-
if (manifest.
|
|
5902
|
-
|
|
5903
|
-
|
|
6099
|
+
if (manifest.formerKey !== void 0) {
|
|
6100
|
+
migration.lines.push([
|
|
6101
|
+
"renamed",
|
|
6102
|
+
`${manifest.formerKey} to boards in .rness/rness.json`
|
|
6103
|
+
]);
|
|
6104
|
+
migration.changed = true;
|
|
6105
|
+
}
|
|
6106
|
+
if (manifest.boards === null) return migration;
|
|
6107
|
+
const boards = {};
|
|
6108
|
+
for (const [name, entry] of Object.entries(manifest.boards)) {
|
|
6109
|
+
if (typeof entry === "string") {
|
|
6110
|
+
boards[name] = entry;
|
|
6111
|
+
continue;
|
|
6112
|
+
}
|
|
5904
6113
|
let source;
|
|
5905
6114
|
if (typeof entry === "number") {
|
|
5906
6115
|
source = await presetSource(name, rnessDir, entry);
|
|
@@ -5950,186 +6159,21 @@ async function migrateBoards(rnessDir, manifest, presets = BUNDLED) {
|
|
|
5950
6159
|
}
|
|
5951
6160
|
}
|
|
5952
6161
|
try {
|
|
5953
|
-
|
|
6162
|
+
boards[name] = typeof entry === "number" || migration.changed ? parseBoard(name, source, presets.knows) : entry;
|
|
5954
6163
|
} catch (e) {
|
|
5955
6164
|
if (!(e instanceof BoardRefused)) throw e;
|
|
5956
6165
|
migration.lines.push(["refused", e.message]);
|
|
5957
|
-
|
|
6166
|
+
boards[name] = entry;
|
|
5958
6167
|
}
|
|
5959
6168
|
}
|
|
5960
|
-
migration.
|
|
6169
|
+
migration.boards = boards;
|
|
5961
6170
|
return migration;
|
|
5962
6171
|
}
|
|
5963
6172
|
|
|
5964
|
-
// src/
|
|
5965
|
-
import { spawn as nodeSpawn } from "child_process";
|
|
5966
|
-
import { mkdir as mkdir3, open as open2, readFile as readFile9, rm as rm5, stat as stat3, writeFile as writeFile3 } from "fs/promises";
|
|
5967
|
-
import { join as join14 } from "path";
|
|
5968
|
-
import { setTimeout as delay2 } from "timers/promises";
|
|
5969
|
-
var detached = (args, cwd) => {
|
|
5970
|
-
const bin = process.argv[1];
|
|
5971
|
-
if (bin === void 0) return;
|
|
5972
|
-
const child = nodeSpawn(process.execPath, [bin, ...args], {
|
|
5973
|
-
detached: true,
|
|
5974
|
-
stdio: "ignore",
|
|
5975
|
-
cwd,
|
|
5976
|
-
env: { ...process.env, RNESS_NO_DELEGATE: "1" }
|
|
5977
|
-
});
|
|
5978
|
-
child.on("error", () => void 0);
|
|
5979
|
-
child.unref();
|
|
5980
|
-
};
|
|
5981
|
-
var failureFile = () => join14(configDir(), "pulse.json");
|
|
5982
|
-
async function recordFailure(reason3) {
|
|
5983
|
-
try {
|
|
5984
|
-
await mkdir3(configDir(), { recursive: true, mode: 448 });
|
|
5985
|
-
await writeFile3(
|
|
5986
|
-
failureFile(),
|
|
5987
|
-
`${JSON.stringify({ at: (/* @__PURE__ */ new Date()).toISOString(), reason: reason3 })}
|
|
5988
|
-
`
|
|
5989
|
-
);
|
|
5990
|
-
} catch {
|
|
5991
|
-
}
|
|
5992
|
-
}
|
|
5993
|
-
async function takeFailure() {
|
|
5994
|
-
try {
|
|
5995
|
-
const data = JSON.parse(await readFile9(failureFile(), "utf8"));
|
|
5996
|
-
await rm5(failureFile(), { force: true });
|
|
5997
|
-
const reason3 = data !== null && typeof data === "object" ? data["reason"] : void 0;
|
|
5998
|
-
return typeof reason3 === "string" && reason3 !== "" ? reason3 : null;
|
|
5999
|
-
} catch {
|
|
6000
|
-
return null;
|
|
6001
|
-
}
|
|
6002
|
-
}
|
|
6003
|
-
var PULSE_LOCK_STALE_MS = 15 * 6e4;
|
|
6004
|
-
async function oneSyncAtATime(key, work, options = {}) {
|
|
6005
|
-
await mkdir3(configDir(), { recursive: true, mode: 448 });
|
|
6006
|
-
const file = join14(configDir(), `pulse-${key}.lock`);
|
|
6007
|
-
for (; ; ) {
|
|
6008
|
-
try {
|
|
6009
|
-
const handle = await open2(file, "wx");
|
|
6010
|
-
await handle.close();
|
|
6011
|
-
break;
|
|
6012
|
-
} catch (e) {
|
|
6013
|
-
if (e.code !== "EEXIST") throw e;
|
|
6014
|
-
const age = await stat3(file).then(
|
|
6015
|
-
(s) => Date.now() - s.mtimeMs,
|
|
6016
|
-
() => 0
|
|
6017
|
-
);
|
|
6018
|
-
if (age > PULSE_LOCK_STALE_MS) await rm5(file, { force: true });
|
|
6019
|
-
else if (options.wait !== true) return false;
|
|
6020
|
-
else await (options.sleep ?? ((ms) => delay2(ms)))(1e3);
|
|
6021
|
-
}
|
|
6022
|
-
}
|
|
6023
|
-
try {
|
|
6024
|
-
await work();
|
|
6025
|
-
return true;
|
|
6026
|
-
} finally {
|
|
6027
|
-
await rm5(file, { force: true });
|
|
6028
|
-
}
|
|
6029
|
-
}
|
|
6030
|
-
|
|
6031
|
-
// src/pulse/noted.ts
|
|
6032
|
-
import { mkdir as mkdir4, readFile as readFile10, rename as rename3, rm as rm6, writeFile as writeFile4 } from "fs/promises";
|
|
6033
|
-
import { dirname as dirname5 } from "path";
|
|
6034
|
-
var NAME2 = "rness/noted";
|
|
6035
|
-
function notedFile(rnessDir) {
|
|
6036
|
-
return gitPath(rnessDir, NAME2);
|
|
6037
|
-
}
|
|
6038
|
-
async function readNoted(file) {
|
|
6039
|
-
if (file === null) return /* @__PURE__ */ new Set();
|
|
6040
|
-
try {
|
|
6041
|
-
const data = JSON.parse(await readFile10(file, "utf8"));
|
|
6042
|
-
return new Set(
|
|
6043
|
-
Array.isArray(data) ? data.filter((l) => typeof l === "string") : []
|
|
6044
|
-
);
|
|
6045
|
-
} catch {
|
|
6046
|
-
return /* @__PURE__ */ new Set();
|
|
6047
|
-
}
|
|
6048
|
-
}
|
|
6049
|
-
async function writeNoted(file, noted) {
|
|
6050
|
-
if (file === null) return;
|
|
6051
|
-
try {
|
|
6052
|
-
if (noted.size === 0) {
|
|
6053
|
-
await rm6(file, { force: true });
|
|
6054
|
-
return;
|
|
6055
|
-
}
|
|
6056
|
-
await mkdir4(dirname5(file), { recursive: true });
|
|
6057
|
-
const temporary = `${file}.${process.pid}`;
|
|
6058
|
-
await writeFile4(
|
|
6059
|
-
temporary,
|
|
6060
|
-
`${JSON.stringify([...noted].sort(), null, 2)}
|
|
6061
|
-
`
|
|
6062
|
-
);
|
|
6063
|
-
await rename3(temporary, file);
|
|
6064
|
-
} catch {
|
|
6065
|
-
}
|
|
6066
|
-
}
|
|
6067
|
-
async function onceSaid(rnessDir, board, lines) {
|
|
6068
|
-
const file = await notedFile(rnessDir);
|
|
6069
|
-
const noted = await readNoted(file);
|
|
6070
|
-
const prefix = `${board}: `;
|
|
6071
|
-
const notes = lines.filter((l) => l.startsWith("note "));
|
|
6072
|
-
const now = new Set(notes.map((l) => `${prefix}${l}`));
|
|
6073
|
-
const said = lines.filter(
|
|
6074
|
-
(l) => !l.startsWith("note ") || !noted.has(`${prefix}${l}`)
|
|
6075
|
-
);
|
|
6076
|
-
const next = /* @__PURE__ */ new Set([
|
|
6077
|
-
...[...noted].filter((l) => !l.startsWith(prefix)),
|
|
6078
|
-
...now
|
|
6079
|
-
]);
|
|
6080
|
-
if (next.size !== noted.size || [...next].some((l) => !noted.has(l)))
|
|
6081
|
-
await writeNoted(file, next);
|
|
6082
|
-
return said;
|
|
6083
|
-
}
|
|
6084
|
-
|
|
6085
|
-
// src/pulse/opened.ts
|
|
6086
|
-
import { mkdir as mkdir5, readFile as readFile11, rename as rename4, rm as rm7, writeFile as writeFile5 } from "fs/promises";
|
|
6087
|
-
import { dirname as dirname6 } from "path";
|
|
6088
|
-
var NAME3 = "rness/opened";
|
|
6089
|
-
function openedFile(rnessDir) {
|
|
6090
|
-
return gitPath(rnessDir, NAME3);
|
|
6091
|
-
}
|
|
6092
|
-
var NUMBER = /^[1-9][0-9]*$/;
|
|
6093
|
-
async function readOpened(file) {
|
|
6094
|
-
const opened = /* @__PURE__ */ new Map();
|
|
6095
|
-
if (file === null) return opened;
|
|
6096
|
-
let data;
|
|
6097
|
-
try {
|
|
6098
|
-
data = JSON.parse(await readFile11(file, "utf8"));
|
|
6099
|
-
} catch {
|
|
6100
|
-
return opened;
|
|
6101
|
-
}
|
|
6102
|
-
if (data === null || typeof data !== "object" || Array.isArray(data))
|
|
6103
|
-
return opened;
|
|
6104
|
-
for (const [key, path] of Object.entries(data))
|
|
6105
|
-
if (NUMBER.test(key) && typeof path === "string" && path !== "")
|
|
6106
|
-
opened.set(Number(key), path);
|
|
6107
|
-
return opened;
|
|
6108
|
-
}
|
|
6109
|
-
async function writeOpened(file, opened) {
|
|
6110
|
-
if (file === null) return;
|
|
6111
|
-
try {
|
|
6112
|
-
if (opened.size === 0) {
|
|
6113
|
-
await rm7(file, { force: true });
|
|
6114
|
-
return;
|
|
6115
|
-
}
|
|
6116
|
-
const entries = [...opened].sort(([a], [b]) => a - b);
|
|
6117
|
-
await mkdir5(dirname6(file), { recursive: true });
|
|
6118
|
-
const temporary = `${file}.${process.pid}`;
|
|
6119
|
-
await writeFile5(
|
|
6120
|
-
temporary,
|
|
6121
|
-
`${JSON.stringify(Object.fromEntries(entries), null, 2)}
|
|
6122
|
-
`
|
|
6123
|
-
);
|
|
6124
|
-
await rename4(temporary, file);
|
|
6125
|
-
} catch {
|
|
6126
|
-
}
|
|
6127
|
-
}
|
|
6128
|
-
|
|
6129
|
-
// src/commands/pulse.ts
|
|
6173
|
+
// src/commands/board.ts
|
|
6130
6174
|
var PROJECT_SCOPE = "project";
|
|
6131
|
-
var NEEDS_LOGIN = "
|
|
6132
|
-
var NEEDS_SCOPE = "
|
|
6175
|
+
var NEEDS_LOGIN = "boards need a GitHub login: run rness login";
|
|
6176
|
+
var NEEDS_SCOPE = "boards need the project scope: run rness login";
|
|
6133
6177
|
async function fromGithub(work) {
|
|
6134
6178
|
try {
|
|
6135
6179
|
return await work;
|
|
@@ -6149,7 +6193,7 @@ async function context(opts, wait) {
|
|
|
6149
6193
|
const manifest = await loadManifest(ws.rnessDir);
|
|
6150
6194
|
const provider = await openProvider(manifest, providerOptions(opts, wait));
|
|
6151
6195
|
if (manifest.org === null)
|
|
6152
|
-
throw new Error('
|
|
6196
|
+
throw new Error('boards need an organization: rness.json has no "org"');
|
|
6153
6197
|
return {
|
|
6154
6198
|
root: ws.root,
|
|
6155
6199
|
rnessDir: ws.rnessDir,
|
|
@@ -6159,7 +6203,7 @@ async function context(opts, wait) {
|
|
|
6159
6203
|
};
|
|
6160
6204
|
}
|
|
6161
6205
|
var waitSaid = (opts, ui) => rateWait(async (ms) => {
|
|
6162
|
-
ui.line("waiting", `${Math.round(ms / 1e3)} s
|
|
6206
|
+
ui.line("waiting", `${Math.round(ms / 1e3)} s: GitHub's rate limit`);
|
|
6163
6207
|
await (opts.sleep ?? ((n) => delay3(n)))(ms);
|
|
6164
6208
|
});
|
|
6165
6209
|
async function missingAccess(provider) {
|
|
@@ -6167,17 +6211,19 @@ async function missingAccess(provider) {
|
|
|
6167
6211
|
const scopes = await fromGithub(provider.scopes());
|
|
6168
6212
|
return scopes?.includes(PROJECT_SCOPE) === true ? null : NEEDS_SCOPE;
|
|
6169
6213
|
}
|
|
6214
|
+
var isCreated = (d) => d.number !== null;
|
|
6170
6215
|
var takesAll = (d) => d.declaration.collections === "all";
|
|
6171
6216
|
var namedCollections = (d) => d.collections === "all" ? [] : Object.keys(d.collections);
|
|
6172
6217
|
async function declarations(c, ui) {
|
|
6173
|
-
const
|
|
6218
|
+
const boards = c.manifest.boards ?? {};
|
|
6174
6219
|
for (const r of c.manifest.refused ?? [])
|
|
6175
6220
|
ui?.line("skipped", `${r.name}: ${r.reason}`);
|
|
6176
6221
|
const all = [];
|
|
6177
|
-
|
|
6222
|
+
const notCreated = [];
|
|
6223
|
+
for (const [name, entry] of Object.entries(boards)) {
|
|
6178
6224
|
const declaration = await declaredBoard(name, entry, c.rnessDir);
|
|
6179
6225
|
const still = [];
|
|
6180
|
-
if (typeof entry
|
|
6226
|
+
if (typeof entry === "object")
|
|
6181
6227
|
for (const collection of namedCollections(declaration)) {
|
|
6182
6228
|
const keys = Object.keys(
|
|
6183
6229
|
await readmeDeclarations(c.rnessDir, collection)
|
|
@@ -6188,23 +6234,32 @@ async function declarations(c, ui) {
|
|
|
6188
6234
|
if (still.length > 0) {
|
|
6189
6235
|
ui?.line(
|
|
6190
6236
|
"skipped",
|
|
6191
|
-
`${name}: ${still.join(", ")}, which rness.json declares now
|
|
6237
|
+
`${name}: ${still.join(", ")}, which rness.json declares now: rness sync moves it`
|
|
6192
6238
|
);
|
|
6193
6239
|
continue;
|
|
6194
6240
|
}
|
|
6195
|
-
all.push({ name, declaration });
|
|
6241
|
+
if (isCreated(declaration)) all.push({ name, declaration });
|
|
6242
|
+
else if (typeof entry !== "number")
|
|
6243
|
+
notCreated.push({ name, entry, declaration });
|
|
6196
6244
|
}
|
|
6197
|
-
return
|
|
6245
|
+
return {
|
|
6246
|
+
created: all.sort((a, b) => Number(takesAll(a)) - Number(takesAll(b))),
|
|
6247
|
+
notCreated
|
|
6248
|
+
};
|
|
6249
|
+
}
|
|
6250
|
+
function noBoard(c) {
|
|
6251
|
+
return new Error(
|
|
6252
|
+
c.manifest.refused === void 0 ? 'no board declared: declare one in .rness/rness.json, as "boards": { "pulse": "agent-pulse" }, then rness board push' : `no board rness.json declares is valid: ${c.manifest.refused.map((r) => r.reason).join("; ")}`
|
|
6253
|
+
);
|
|
6198
6254
|
}
|
|
6199
6255
|
async function declaredBoards(c, ui) {
|
|
6200
|
-
if (c.manifest.
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
);
|
|
6256
|
+
if (c.manifest.boards === null) throw noBoard(c);
|
|
6257
|
+
const { created } = await declarations(c, ui);
|
|
6258
|
+
if (created.length === 0) return [];
|
|
6204
6259
|
const missing = await missingAccess(c.provider);
|
|
6205
6260
|
if (missing !== null) throw new Error(missing);
|
|
6206
6261
|
const declared = [];
|
|
6207
|
-
for (const { name, declaration } of
|
|
6262
|
+
for (const { name, declaration } of created) {
|
|
6208
6263
|
const board = await fromGithub(c.provider.board(c.org, declaration.number));
|
|
6209
6264
|
if (board === null)
|
|
6210
6265
|
throw new Error(`GitHub has no project ${declaration.number} in ${c.org}`);
|
|
@@ -6442,7 +6497,7 @@ async function syncBoard(c, board, ui, sayLayout, scope) {
|
|
|
6442
6497
|
if (!(e instanceof RateLimitError)) throw e;
|
|
6443
6498
|
const total = changes + writes.length;
|
|
6444
6499
|
throw new Error(
|
|
6445
|
-
`${e.message}: ${total - made} of ${total} changes not made
|
|
6500
|
+
`${e.message}: ${total - made} of ${total} changes not made: the next rness board push makes them`,
|
|
6446
6501
|
{ cause: e }
|
|
6447
6502
|
);
|
|
6448
6503
|
}
|
|
@@ -6470,125 +6525,131 @@ async function syncAll(c, declared, ui, sayLayout) {
|
|
|
6470
6525
|
);
|
|
6471
6526
|
}
|
|
6472
6527
|
}
|
|
6473
|
-
async function
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
if (refused !== void 0)
|
|
6489
|
-
throw new Error(`already declared, and refused: ${refused.reason}`);
|
|
6490
|
-
const tab = opts.collection === void 0 ? null : (await statusTabs(c.rnessDir)).find(
|
|
6491
|
-
(t) => t.name === opts.collection
|
|
6492
|
-
) ?? null;
|
|
6493
|
-
if (opts.collection !== void 0 && tab === null)
|
|
6494
|
-
throw new Error(
|
|
6495
|
-
`${opts.collection} is no collection of .rness: none of its documents carries a status`
|
|
6496
|
-
);
|
|
6497
|
-
const detected = providerOf(c.manifest);
|
|
6498
|
-
if (!PROVIDERS[detected].available)
|
|
6499
|
-
throw new Error(
|
|
6500
|
-
`the pulse needs a GitHub organization, and this workspace's repositories look like ${detected} (detected): write "provider": "github" in rness.json if the organization is on GitHub`
|
|
6501
|
-
);
|
|
6502
|
-
const missing = await missingAccess(c.provider);
|
|
6503
|
-
if (missing !== null) {
|
|
6504
|
-
if (opts.yes === true || !terminal.isTty()) throw new Error(missing);
|
|
6505
|
-
const p = await terminal.prompts();
|
|
6506
|
-
const ok = await p.confirm({
|
|
6507
|
-
message: missing === NEEDS_LOGIN ? "The pulse needs a GitHub login with the project scope. Log in now?" : "The pulse needs the project scope of your GitHub login. Log in again to grant it?"
|
|
6508
|
-
});
|
|
6509
|
-
if (p.isCancel(ok) || ok !== true) throw new Error(missing);
|
|
6510
|
-
const code = await loginCommand(
|
|
6511
|
-
{
|
|
6512
|
-
project: true,
|
|
6513
|
-
// The git question is `rness login`'s own, not the pulse's to ask.
|
|
6514
|
-
setupGit: false,
|
|
6515
|
-
...opts.githubApi === void 0 ? {} : { githubApi: opts.githubApi }
|
|
6516
|
-
},
|
|
6517
|
-
{ terminal, ui, ...opts.cwd === void 0 ? {} : { cwd: opts.cwd } }
|
|
6518
|
-
);
|
|
6519
|
-
if (code !== 0) return code;
|
|
6520
|
-
c = {
|
|
6521
|
-
...c,
|
|
6522
|
-
provider: await openProvider(c.manifest, providerOptions(opts, wait))
|
|
6523
|
-
};
|
|
6524
|
-
const still = await missingAccess(c.provider);
|
|
6525
|
-
if (still !== null) throw new Error(still);
|
|
6526
|
-
}
|
|
6527
|
-
await fromGithub(c.provider.checkIssues(c.org));
|
|
6528
|
-
const login = (await c.provider.identity())?.login ?? "unknown";
|
|
6529
|
-
ui.line(
|
|
6530
|
-
"checked",
|
|
6531
|
-
`${detected}, logged in as ${login}, scope ${PROJECT_SCOPE}`
|
|
6528
|
+
async function checkBoardName(rnessDir, name) {
|
|
6529
|
+
if (name === PULSE) return;
|
|
6530
|
+
const tabs = await statusTabs(rnessDir);
|
|
6531
|
+
if (!tabs.some((t) => t.name === name))
|
|
6532
|
+
throw new Error(
|
|
6533
|
+
`"boards.${name}": ${name} is no collection of .rness: none of its documents carries a status`
|
|
6534
|
+
);
|
|
6535
|
+
}
|
|
6536
|
+
var titleOf = (b) => b.declaration.title ?? labelOf(b.name);
|
|
6537
|
+
async function createBoards(c, boards, opts, terminal, ui, wait) {
|
|
6538
|
+
for (const b of boards) await checkBoardName(c.rnessDir, b.name);
|
|
6539
|
+
const detected = providerOf(c.manifest);
|
|
6540
|
+
if (!PROVIDERS[detected].available)
|
|
6541
|
+
throw new Error(
|
|
6542
|
+
`boards need a GitHub organization, and this workspace's repositories look like ${detected} (detected): write "provider": "github" in rness.json if the organization is on GitHub`
|
|
6532
6543
|
);
|
|
6533
|
-
|
|
6534
|
-
|
|
6535
|
-
|
|
6544
|
+
const names = boards.map((b) => b.name);
|
|
6545
|
+
if (opts.confirmed !== true && opts.yes !== true) {
|
|
6546
|
+
if (!terminal.isTty()) return { c, made: [], left: names };
|
|
6547
|
+
const p = await terminal.prompts();
|
|
6548
|
+
const ok = await p.confirm({
|
|
6549
|
+
message: `Create ${boards.map((b) => `${titleOf(b)} (${b.name})`).join(", ")} on GitHub, in ${c.org}?`
|
|
6550
|
+
});
|
|
6551
|
+
if (p.isCancel(ok) || ok !== true) return { c, made: [], left: names };
|
|
6552
|
+
}
|
|
6553
|
+
const missing = await missingAccess(c.provider);
|
|
6554
|
+
if (missing !== null) {
|
|
6555
|
+
if (opts.yes === true || !terminal.isTty()) throw new Error(missing);
|
|
6556
|
+
const p = await terminal.prompts();
|
|
6557
|
+
const ok = await p.confirm({
|
|
6558
|
+
message: missing === NEEDS_LOGIN ? "Boards need a GitHub login with the project scope. Log in now?" : "Boards need the project scope of your GitHub login. Log in again to grant it?"
|
|
6559
|
+
});
|
|
6560
|
+
if (p.isCancel(ok) || ok !== true) throw new Error(missing);
|
|
6561
|
+
const code = await loginCommand(
|
|
6562
|
+
{
|
|
6563
|
+
project: true,
|
|
6564
|
+
// The git question is `rness login`'s own, not the board's to ask.
|
|
6565
|
+
setupGit: false,
|
|
6566
|
+
...opts.githubApi === void 0 ? {} : { githubApi: opts.githubApi }
|
|
6567
|
+
},
|
|
6568
|
+
{ terminal, ui, ...opts.cwd === void 0 ? {} : { cwd: opts.cwd } }
|
|
6569
|
+
);
|
|
6570
|
+
if (code !== 0) throw new Error(missing);
|
|
6571
|
+
c = {
|
|
6572
|
+
...c,
|
|
6573
|
+
provider: await openProvider(c.manifest, providerOptions(opts, wait))
|
|
6574
|
+
};
|
|
6575
|
+
const still = await missingAccess(c.provider);
|
|
6576
|
+
if (still !== null) throw new Error(still);
|
|
6577
|
+
}
|
|
6578
|
+
await fromGithub(c.provider.checkIssues(c.org));
|
|
6579
|
+
const login = (await c.provider.identity())?.login ?? "unknown";
|
|
6580
|
+
ui.line(
|
|
6581
|
+
"checked",
|
|
6582
|
+
`${detected}, logged in as ${login}, scope ${PROJECT_SCOPE}`
|
|
6583
|
+
);
|
|
6584
|
+
const made = [];
|
|
6585
|
+
for (const b of boards) {
|
|
6586
|
+
const source = typeof b.entry === "string" ? await presetSource(b.name, c.rnessDir, null, b.entry) : b.declaration.source;
|
|
6587
|
+
const readme = typeof b.entry === "string" && b.name !== PULSE ? await readmeText(c.rnessDir, b.name) : null;
|
|
6588
|
+
const title = titleOf(b);
|
|
6536
6589
|
const board = await fromGithub(c.provider.createBoard(c.org, title));
|
|
6537
6590
|
const manifest = {
|
|
6538
6591
|
...c.manifest,
|
|
6539
6592
|
provider: detected,
|
|
6540
|
-
|
|
6541
|
-
...c.manifest.
|
|
6542
|
-
[name]: parseBoard(name, {
|
|
6593
|
+
boards: {
|
|
6594
|
+
...c.manifest.boards,
|
|
6595
|
+
[b.name]: parseBoard(b.name, { number: board.number, ...source })
|
|
6543
6596
|
}
|
|
6544
6597
|
};
|
|
6545
6598
|
await writeManifest(c.rnessDir, manifest);
|
|
6546
|
-
if (readme !== null
|
|
6599
|
+
if (readme !== null) {
|
|
6547
6600
|
const cleaned = withoutDeclarations(readme);
|
|
6548
6601
|
if (cleaned !== readme)
|
|
6549
|
-
await writeFileAtomic(
|
|
6550
|
-
join15(c.rnessDir, opts.collection, "README.md"),
|
|
6551
|
-
cleaned
|
|
6552
|
-
);
|
|
6602
|
+
await writeFileAtomic(join15(c.rnessDir, b.name, "README.md"), cleaned);
|
|
6553
6603
|
}
|
|
6554
6604
|
c = { ...c, manifest };
|
|
6555
|
-
|
|
6605
|
+
made.push(b.name);
|
|
6606
|
+
ui.line("created", `${title} - ${board.url}`);
|
|
6607
|
+
}
|
|
6608
|
+
return { c, made, left: [] };
|
|
6609
|
+
}
|
|
6610
|
+
async function boardPushCommand(opts, deps = {}) {
|
|
6611
|
+
try {
|
|
6612
|
+
const terminal = deps.terminal ?? defaultTerminal;
|
|
6613
|
+
const ui = deps.ui ?? await makeUi(terminal);
|
|
6614
|
+
const wait = waitSaid(opts, ui);
|
|
6615
|
+
let c = await context(opts, wait);
|
|
6616
|
+
if (c.manifest.boards === null) throw noBoard(c);
|
|
6617
|
+
const { notCreated } = await declarations(c, ui);
|
|
6618
|
+
let made = [];
|
|
6619
|
+
let left = [];
|
|
6620
|
+
if (notCreated.length > 0)
|
|
6621
|
+
({ c, made, left } = await createBoards(
|
|
6622
|
+
c,
|
|
6623
|
+
notCreated,
|
|
6624
|
+
opts,
|
|
6625
|
+
terminal,
|
|
6626
|
+
ui,
|
|
6627
|
+
wait
|
|
6628
|
+
));
|
|
6556
6629
|
try {
|
|
6630
|
+
const declared = await declaredBoards(c);
|
|
6557
6631
|
await syncAll(
|
|
6558
6632
|
c,
|
|
6559
|
-
|
|
6633
|
+
declared,
|
|
6560
6634
|
ui,
|
|
6561
|
-
(n) => n
|
|
6635
|
+
(n) => made.includes(n) ? createdByKind : eachAdded
|
|
6562
6636
|
);
|
|
6563
6637
|
} finally {
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6638
|
+
if (made.length > 0)
|
|
6639
|
+
ui.line(
|
|
6640
|
+
"declared",
|
|
6641
|
+
`${made.join(", ")} in .rness/rness.json - commit it: git -C .rness commit -am "chore: board ${made.join(", ")}"`
|
|
6642
|
+
);
|
|
6568
6643
|
}
|
|
6644
|
+
if (left.length > 0)
|
|
6645
|
+
throw new Error(
|
|
6646
|
+
`not created: ${left.join(", ")} - rness board push in a terminal, or with --yes, creates ${left.length === 1 ? "it" : "them"}`
|
|
6647
|
+
);
|
|
6569
6648
|
return 0;
|
|
6570
6649
|
} catch (e) {
|
|
6571
6650
|
return reportError(e);
|
|
6572
6651
|
}
|
|
6573
6652
|
}
|
|
6574
|
-
async function pulseSyncCommand(opts, deps = {}) {
|
|
6575
|
-
try {
|
|
6576
|
-
const ui = deps.ui ?? await makeUi(deps.terminal ?? defaultTerminal);
|
|
6577
|
-
const c = await context(opts, waitSaid(opts, ui));
|
|
6578
|
-
await syncAll(c, await declaredBoards(c, ui), ui, () => eachAdded);
|
|
6579
|
-
return 0;
|
|
6580
|
-
} catch (e) {
|
|
6581
|
-
return reportError(e);
|
|
6582
|
-
}
|
|
6583
|
-
}
|
|
6584
|
-
async function pulseMarkCommand(opts) {
|
|
6585
|
-
try {
|
|
6586
|
-
return await mark(opts);
|
|
6587
|
-
} catch (e) {
|
|
6588
|
-
await recordFailure(e instanceof Error ? e.message : String(e));
|
|
6589
|
-
return 0;
|
|
6590
|
-
}
|
|
6591
|
-
}
|
|
6592
6653
|
function markFields(d) {
|
|
6593
6654
|
const fields2 = Object.entries(d.fields);
|
|
6594
6655
|
const agent = fields2.find(
|
|
@@ -6658,29 +6719,7 @@ async function clearOn(c, d, session) {
|
|
|
6658
6719
|
}).map((i) => i.id);
|
|
6659
6720
|
await fromGithub(c.provider.mark(d.board, ids, null, fields2));
|
|
6660
6721
|
}
|
|
6661
|
-
async function
|
|
6662
|
-
const c = await context(opts);
|
|
6663
|
-
const declared = await declaredBoards(c);
|
|
6664
|
-
const lock = opts.sleep === void 0 ? {} : { sleep: opts.sleep };
|
|
6665
|
-
if (opts.end === true) {
|
|
6666
|
-
for (const d of declared) await clearOn(c, d, opts.session);
|
|
6667
|
-
await oneSyncAtATime(
|
|
6668
|
-
lockKey(c, declared),
|
|
6669
|
-
() => syncAll(c, declared, plainUi, () => eachAdded),
|
|
6670
|
-
{ ...lock, wait: true }
|
|
6671
|
-
);
|
|
6672
|
-
return 0;
|
|
6673
|
-
}
|
|
6674
|
-
const wanted = /* @__PURE__ */ new Map();
|
|
6675
|
-
for (const d of declared) {
|
|
6676
|
-
const paths = opts.paths.filter((p) => holds(d, p));
|
|
6677
|
-
if (paths.length > 0) wanted.set(d, new Set(paths));
|
|
6678
|
-
}
|
|
6679
|
-
if (wanted.size === 0) return 0;
|
|
6680
|
-
await markOn(c, declared, wanted, opts.session, lock);
|
|
6681
|
-
return 0;
|
|
6682
|
-
}
|
|
6683
|
-
async function pulseRunCommand(opts) {
|
|
6722
|
+
async function boardRunCommand(opts) {
|
|
6684
6723
|
const failures = [];
|
|
6685
6724
|
try {
|
|
6686
6725
|
await run(opts, failures);
|
|
@@ -6703,7 +6742,7 @@ async function run(opts, failures) {
|
|
|
6703
6742
|
if (event === "session-end") {
|
|
6704
6743
|
for (const d of acting("journal-summary"))
|
|
6705
6744
|
try {
|
|
6706
|
-
const { postSummary } = await import("./summary-
|
|
6745
|
+
const { postSummary } = await import("./summary-5DVUIOJM.js");
|
|
6707
6746
|
await postSummary({
|
|
6708
6747
|
c,
|
|
6709
6748
|
board: d,
|
|
@@ -6764,6 +6803,33 @@ async function run(opts, failures) {
|
|
|
6764
6803
|
)
|
|
6765
6804
|
);
|
|
6766
6805
|
}
|
|
6806
|
+
async function pulseCreateCommand(collection, opts, deps = {}) {
|
|
6807
|
+
try {
|
|
6808
|
+
const name = collection ?? PULSE;
|
|
6809
|
+
const ws = await findWorkspace(opts.cwd ?? process.cwd());
|
|
6810
|
+
const manifest = await loadManifest(ws.rnessDir);
|
|
6811
|
+
if (manifest.org === null)
|
|
6812
|
+
throw new Error('boards need an organization: rness.json has no "org"');
|
|
6813
|
+
const refused = manifest.refused?.find((r) => r.name === name);
|
|
6814
|
+
if (refused !== void 0)
|
|
6815
|
+
throw new Error(`already declared, and refused: ${refused.reason}`);
|
|
6816
|
+
let said = "rness pulse create is now rness board push";
|
|
6817
|
+
if (manifest.boards?.[name] === void 0) {
|
|
6818
|
+
await checkBoardName(ws.rnessDir, name);
|
|
6819
|
+
const preset = presetFor(name);
|
|
6820
|
+
await writeManifest(ws.rnessDir, {
|
|
6821
|
+
...manifest,
|
|
6822
|
+
boards: { ...manifest.boards, [name]: preset }
|
|
6823
|
+
});
|
|
6824
|
+
said = `boards are declared in rness.json now: added "${name}": "${preset}", then rness board push`;
|
|
6825
|
+
}
|
|
6826
|
+
process.stderr.write(`${said}
|
|
6827
|
+
`);
|
|
6828
|
+
return await boardPushCommand({ ...opts, confirmed: true }, deps);
|
|
6829
|
+
} catch (e) {
|
|
6830
|
+
return reportError(e);
|
|
6831
|
+
}
|
|
6832
|
+
}
|
|
6767
6833
|
|
|
6768
6834
|
export {
|
|
6769
6835
|
exists,
|
|
@@ -6787,6 +6853,7 @@ export {
|
|
|
6787
6853
|
presetTemplate,
|
|
6788
6854
|
BoardRefused,
|
|
6789
6855
|
contractOf,
|
|
6856
|
+
PULSE,
|
|
6790
6857
|
parseBoard,
|
|
6791
6858
|
clone,
|
|
6792
6859
|
isClean,
|
|
@@ -6809,7 +6876,6 @@ export {
|
|
|
6809
6876
|
NAME_RULE,
|
|
6810
6877
|
ORG_NAME,
|
|
6811
6878
|
workspaceName,
|
|
6812
|
-
PULSE,
|
|
6813
6879
|
loadManifest,
|
|
6814
6880
|
parseManifest,
|
|
6815
6881
|
writeManifest,
|
|
@@ -6871,12 +6937,12 @@ export {
|
|
|
6871
6937
|
readBoards,
|
|
6872
6938
|
readmeDeclarations,
|
|
6873
6939
|
migrateBoards,
|
|
6940
|
+
detached,
|
|
6941
|
+
takeFailure,
|
|
6874
6942
|
openInBrowser,
|
|
6875
6943
|
canOpenBrowser,
|
|
6876
6944
|
removeGitSetup,
|
|
6877
6945
|
loginCommand,
|
|
6878
|
-
detached,
|
|
6879
|
-
takeFailure,
|
|
6880
6946
|
notesPosted,
|
|
6881
6947
|
notePosted,
|
|
6882
6948
|
issuesNoted,
|
|
@@ -6889,9 +6955,8 @@ export {
|
|
|
6889
6955
|
fromGithub,
|
|
6890
6956
|
context,
|
|
6891
6957
|
declaredBoards,
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
pulseRunCommand
|
|
6958
|
+
boardPushCommand,
|
|
6959
|
+
boardRunCommand,
|
|
6960
|
+
pulseCreateCommand
|
|
6896
6961
|
};
|
|
6897
|
-
//# sourceMappingURL=chunk-
|
|
6962
|
+
//# sourceMappingURL=chunk-OUZQGG6V.js.map
|