mainflow 0.37.0 → 0.39.0
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.js +41 -22
- package/dist/{dist-ud09dzZo.js → dist-zSabglPq.js} +33 -18
- package/dist/facts.d.ts +31 -31
- package/dist/facts.js +37 -30
- package/dist/grant-commands.d.ts +1 -1
- package/dist/grant-commands.js +1 -1
- package/dist/hooks.d.ts +5 -8
- package/dist/hooks.js +6 -6
- package/dist/{host-lY8ytTbw.js → host-CIOd2WSh.js} +251 -60
- package/dist/host.js +1 -1
- package/dist/{index-B32s8PHu.d.ts → index-Dk4fCI7q.d.ts} +31 -7
- package/dist/{launch-3HLHjQF0.js → launch-DJ944-bI.js} +2 -2
- package/dist/launch.js +1 -1
- package/dist/native/mainflow-swap-darwin-arm64 +0 -0
- package/dist/native/mainflow-swap-darwin-x64 +0 -0
- package/dist/{operation-BZ7CHB6J.js → operation-DJARDCM0.js} +1 -1
- package/dist/{ui-AhBsqtZe.js → ui-BhwCZPJR.js} +9 -9
- package/dist/web/assets/{index-8SRwJNYs.js → index-BrA-csjk.js} +30 -30
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
package/dist/hooks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _ as Task, a as Decision, c as Group, d as Mainline, f as OpsEntry, h as Session, i as ChecklistItem, n as ActionBlock, s as Finding, t as Action, u as Issue } from "./index-
|
|
1
|
+
import { _ as Task, a as Decision, c as Group, d as Mainline, f as OpsEntry, h as Session, i as ChecklistItem, n as ActionBlock, s as Finding, t as Action, u as Issue } from "./index-Dk4fCI7q.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region ../core/dist/ids/allocators.d.ts
|
|
4
4
|
/** The letters ids start with. */
|
|
@@ -123,8 +123,6 @@ interface MainlineInput {
|
|
|
123
123
|
title: string;
|
|
124
124
|
/** A group of this hub the mainline belongs to */
|
|
125
125
|
group?: string;
|
|
126
|
-
/** plan or impl; without one the mainline is an impl one */
|
|
127
|
-
role?: string;
|
|
128
126
|
priority?: string;
|
|
129
127
|
}
|
|
130
128
|
declare function createMainline(hub: HubReader, input: MainlineInput, ctx: OpContext): OpResult<{
|
|
@@ -137,12 +135,11 @@ interface MainlinePatch {
|
|
|
137
135
|
status?: string;
|
|
138
136
|
/** A group of this hub, or `none` (null) to leave every group */
|
|
139
137
|
group?: string | null;
|
|
140
|
-
role?: string;
|
|
141
138
|
priority?: string;
|
|
142
139
|
expectedVersion?: string;
|
|
143
140
|
}
|
|
144
141
|
/**
|
|
145
|
-
* Change a mainline's status, group
|
|
142
|
+
* Change a mainline's status, group or priority. Done is refused while criteria are open or decisions are
|
|
146
143
|
* proposed; the other fields change without conditions, in the same write.
|
|
147
144
|
*/
|
|
148
145
|
declare function setMainline(hub: HubReader, input: MainlinePatch, ctx: OpContext): OpResult<Mainline>;
|
|
@@ -157,7 +154,7 @@ declare function setMainlineArchived(hub: HubReader, input: {
|
|
|
157
154
|
archived: boolean;
|
|
158
155
|
expectedVersion?: string;
|
|
159
156
|
}, ctx: OpContext): OpResult<Mainline>;
|
|
160
|
-
/** Add an open criterion at the end of the mainline
|
|
157
|
+
/** Add an open criterion at the end of the list of the mainline or group in `mainline`, numbered by the context's allocator. */
|
|
161
158
|
declare function addCriterion(hub: HubReader, input: ListItemInput & {
|
|
162
159
|
mainline: string;
|
|
163
160
|
}, ctx: OpContext): OpResult<{
|
|
@@ -168,7 +165,7 @@ declare function setCriterion(hub: HubReader, input: {
|
|
|
168
165
|
done: boolean;
|
|
169
166
|
evidence?: string;
|
|
170
167
|
expectedVersion?: string;
|
|
171
|
-
}, ctx: OpContext): OpResult<Mainline>;
|
|
168
|
+
}, ctx: OpContext): OpResult<Mainline | Group>;
|
|
172
169
|
/** What `criterion set` rewrites; at least one must be given. `done` stays as it is; use criterion check/uncheck for that. */
|
|
173
170
|
interface CriterionTextPatch {
|
|
174
171
|
text?: string;
|
|
@@ -179,7 +176,7 @@ declare function setCriterionText(hub: HubReader, input: {
|
|
|
179
176
|
ref: string;
|
|
180
177
|
patch: CriterionTextPatch;
|
|
181
178
|
expectedVersion?: string;
|
|
182
|
-
}): OpResult<Mainline>;
|
|
179
|
+
}): OpResult<Mainline | Group>;
|
|
183
180
|
//#endregion
|
|
184
181
|
//#region ../core/dist/ops/tasks.d.ts
|
|
185
182
|
interface TaskInput {
|
package/dist/hooks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { A as
|
|
3
|
-
import { n as hubWriter, r as writtenLines } from "./operation-
|
|
1
|
+
import { P as configSchema, rt as describeRequest } from "./dist-zSabglPq.js";
|
|
2
|
+
import { A as headerLine, C as loadSessions, Ct as DATA_DIR, D as matchGrants, E as grantScope, G as loadHub, O as decorateReply, S as turnReminder, U as HubError, bt as findHubRoot, ht as hubFormatVersion, i as hostName, j as mayDecorate, k as endsWithMarker, mt as formatMismatch, nt as nodeStorage, tt as readYaml, w as readSession, x as sessionBriefing, xt as worktreesOf, yt as currentBranch } from "./host-CIOd2WSh.js";
|
|
3
|
+
import { n as hubWriter, r as writtenLines } from "./operation-DJARDCM0.js";
|
|
4
4
|
import { resolveFixed, scanCommand, scopedCwd } from "./grant-commands.js";
|
|
5
5
|
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
6
6
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -301,7 +301,7 @@ function grantableCall(payload) {
|
|
|
301
301
|
}
|
|
302
302
|
/** Outside a hub, or when deciding failed: ask for a grantable call, stay silent for any other. */
|
|
303
303
|
function askWhenGrantable({ payload }, failure) {
|
|
304
|
-
const reason = failure.kind === "outside-hub" ? "不在 mainflow hub
|
|
304
|
+
const reason = failure.kind === "outside-hub" ? "不在 mainflow hub 裡,沒有授權可用" : failure.kind === "error" ? `判斷授權時出錯:${failure.message}` : "hook 讀不到 PreToolUse 的輸入";
|
|
305
305
|
if (failure.kind === "unreadable-input") return askBecause(reason);
|
|
306
306
|
try {
|
|
307
307
|
return grantableCall(payload) ? askBecause(reason) : null;
|
|
@@ -318,7 +318,7 @@ async function logGranted(write, scope, call, request, grant, warn) {
|
|
|
318
318
|
target: request.action === "publish" ? `npm ${request.name}` : `github release ${request.repos.join("/")}`,
|
|
319
319
|
operation: opsText(call.text),
|
|
320
320
|
result: `授權放行 ${grant.ref}(${describeRequest(request)})`,
|
|
321
|
-
ref: scope.served[grant.
|
|
321
|
+
ref: scope.served[grant.owner]
|
|
322
322
|
});
|
|
323
323
|
} catch (error) {
|
|
324
324
|
warn?.(`mainflow hook claude-code pre-tool-use: allowed by ${grant.ref} but could not write the ops log: ${error.message}`);
|
|
@@ -353,7 +353,7 @@ async function decideByGrants(root, { payload, warn, write }) {
|
|
|
353
353
|
if (!match.ok) return askBecause(match.reason);
|
|
354
354
|
const { grant } = match.matches[0];
|
|
355
355
|
await logGranted(write, scoped.scope, scan.call, resolved.request, grant, warn);
|
|
356
|
-
return permission("allow",
|
|
356
|
+
return permission("allow", `授權 ${grant.ref} 涵蓋 ${describeRequest(resolved.request)}`);
|
|
357
357
|
}
|
|
358
358
|
/** How many problems outside the written file the reminder lists before it only gives the count. */
|
|
359
359
|
const OTHER_PROBLEMS_SHOWN = 5;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as
|
|
1
|
+
import { $ as stampMs, A as TASK_REQUIRED_SECTIONS, B as mainlineSchema, C as RESERVED_HUB_NAMES, D as SLUG, E as SESSION_STATUS, F as decisionSchema, G as parseUntil, H as parseActionRef, I as findingSchema, J as sessionSchema, K as refExample, L as formatOpsEntry, M as UNTIL_FORMS, N as WORK_STATUS, O as SURVEY_LINES, P as configSchema, Q as OFFSET, R as groupSchema, S as REF_EXAMPLES, T as SESSION_ID, U as parseOpsLine, V as opsEntrySchema, W as parseRef, X as waitingForAction, Y as taskSchema, Z as waitingForRef, a as DECISION_SECTIONS, at as grantForm, b as MERGE_STATES, c as FINDING_SECTIONS, d as GROUP_SECTIONS, f as GROUP_STATUS, h as ISSUE_SECTIONS, i as DECISION_BASES, it as grantCovers, j as TASK_SECTIONS, k as SURVEY_SECTION, l as FINDING_STATUS, n as CLOSED_STATUS, ot as grantRepo, q as refMainline, r as DECIDERS, rt as describeRequest, s as DEFAULT_CATEGORIES, st as parseGrantTarget, v as MAINLINE_SECTIONS, w as SERVES_REF, x as PRIORITIES, y as MAINLINE_STATUS, z as issueSchema } from "./dist-zSabglPq.js";
|
|
2
2
|
import { a as LABEL_ROLES, i as FINDING_SEVERITIES, n as FINDING_CLASSES, r as FINDING_FIELDS, t as FINDINGS_FENCE } from "./retro-formats-ECy0gGOL.js";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
4
|
import { appendFileSync, closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, symlinkSync, writeFileSync, writeSync } from "node:fs";
|
|
@@ -459,6 +459,11 @@ function decisionFileIn(hub, mainline, decision) {
|
|
|
459
459
|
return file;
|
|
460
460
|
}
|
|
461
461
|
const sessionFileIn = (id) => `${SESSIONS_DIR}/${id}.yaml`;
|
|
462
|
+
function groupFileIn(hub, id) {
|
|
463
|
+
const file = entryFileIn(hub, GROUPS_DIR, id);
|
|
464
|
+
if (!file) throw new WriteError(`group ${id} not found`);
|
|
465
|
+
return file;
|
|
466
|
+
}
|
|
462
467
|
//#endregion
|
|
463
468
|
//#region ../core/dist/ops/format.js
|
|
464
469
|
/** Why a hub whose data format is `found` cannot be written by this CLI; null when it can. */
|
|
@@ -751,6 +756,7 @@ const mainlineDir = (root, id) => onDisk(root, mainlineDirIn(nodeStorage(root),
|
|
|
751
756
|
const taskDir = (root, mainline, task) => onDisk(root, taskDirIn(nodeStorage(root), mainline, task));
|
|
752
757
|
const mainlineFile = (root, id) => join(mainlineDir(root, id), MAINLINE_FILE);
|
|
753
758
|
const taskFile = (root, mainline, task) => join(taskDir(root, mainline, task), TASK_FILE);
|
|
759
|
+
const groupFile = (root, id) => onDisk(root, groupFileIn(nodeStorage(root), id));
|
|
754
760
|
const readConfig = (root) => readConfigIn(nodeStorage(root));
|
|
755
761
|
//#endregion
|
|
756
762
|
//#region ../core/dist/refs.js
|
|
@@ -802,11 +808,18 @@ function refIndex(hub) {
|
|
|
802
808
|
title: f.title,
|
|
803
809
|
status: f.status
|
|
804
810
|
});
|
|
805
|
-
for (const g of hub.groups ?? [])
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
811
|
+
for (const g of hub.groups ?? []) {
|
|
812
|
+
index.set(g.id, {
|
|
813
|
+
kind: "group",
|
|
814
|
+
title: g.title,
|
|
815
|
+
status: g.status
|
|
816
|
+
});
|
|
817
|
+
for (const r of g.criteria ?? []) index.set(`${g.id}#${r.id}`, {
|
|
818
|
+
kind: "groupCriterion",
|
|
819
|
+
title: r.text,
|
|
820
|
+
status: itemStatus(r)
|
|
821
|
+
});
|
|
822
|
+
}
|
|
810
823
|
return index;
|
|
811
824
|
}
|
|
812
825
|
const isHubRoot = (dir) => existsSync(join(dir, DATA_DIR, "config.yaml"));
|
|
@@ -880,7 +893,6 @@ function remoteMembers(remotes, hubName) {
|
|
|
880
893
|
kind: "mainline",
|
|
881
894
|
title: m.title,
|
|
882
895
|
status: m.status,
|
|
883
|
-
role: m.role ?? "impl",
|
|
884
896
|
archived: Boolean(m.archivedAt),
|
|
885
897
|
open: !CLOSED_STATUS.mainline.includes(m.status)
|
|
886
898
|
});
|
|
@@ -1359,6 +1371,7 @@ function loadHub(root, options = {}) {
|
|
|
1359
1371
|
const findings = hubDocs(join(dataDir, "findings"), findingSchema);
|
|
1360
1372
|
const groups = hubDocs(join(dataDir, "groups"), groupSchema);
|
|
1361
1373
|
problems.push(...groupProblems(config.hub, groups, mainlines, hubIssues, unreadable));
|
|
1374
|
+
for (const g of groups) problems.push(...grantProblems(g, config), ...listGaps(g.file, "criteria", g.criteria ?? [], g.status === "open"));
|
|
1362
1375
|
const ops = [];
|
|
1363
1376
|
const opsPath = join(dataDir, "ops");
|
|
1364
1377
|
for (const name of existsSync(opsPath) ? readdirSync(opsPath).filter((n) => n.endsWith(".log")).sort() : []) readFileSync(join(opsPath, name), "utf8").split("\n").forEach((line, index) => {
|
|
@@ -1601,7 +1614,10 @@ function checkReferences(input) {
|
|
|
1601
1614
|
}
|
|
1602
1615
|
for (const i of issues) add(i.file, i, i.id);
|
|
1603
1616
|
for (const f of findings) add(f.file, f, f.id);
|
|
1604
|
-
for (const g of groups)
|
|
1617
|
+
for (const g of groups) {
|
|
1618
|
+
add(g.file, g, g.id);
|
|
1619
|
+
items(g.file, "criteria", g.criteria ?? []);
|
|
1620
|
+
}
|
|
1605
1621
|
for (const p of pending) {
|
|
1606
1622
|
const parsed = parseRef(p.ref);
|
|
1607
1623
|
if (!parsed) continue;
|
|
@@ -1658,7 +1674,7 @@ function repoPathProblems(root, config) {
|
|
|
1658
1674
|
});
|
|
1659
1675
|
}
|
|
1660
1676
|
/**
|
|
1661
|
-
* What the schema cannot see about a mainline's grants: ids must be unique, since the file is edited directly,
|
|
1677
|
+
* What the schema cannot see about a mainline's or a group's grants: ids must be unique, since the file is edited directly,
|
|
1662
1678
|
* and a target that names a repository must name one listed in config.yaml.
|
|
1663
1679
|
*/
|
|
1664
1680
|
function grantProblems(mainline, config) {
|
|
@@ -1689,24 +1705,28 @@ const isOpen$2 = (kind, status) => !CLOSED_STATUS[kind].includes(status);
|
|
|
1689
1705
|
* entries are skipped, because their evidence already says what was done. Ids must also be unique within
|
|
1690
1706
|
* a list, since the files are edited directly and nothing else allocates them.
|
|
1691
1707
|
*/
|
|
1692
|
-
|
|
1708
|
+
/** Ids unique within a list, and every open item saying what has to be true to check it. */
|
|
1709
|
+
function listGaps(file, field, items, open) {
|
|
1693
1710
|
const gaps = [];
|
|
1694
|
-
const
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
message: `${item.id} is used twice; give it the next free id`
|
|
1701
|
-
});
|
|
1702
|
-
seen.add(item.id);
|
|
1703
|
-
if (open && !item.done && !item.dropped && !item.doneWhen?.trim()) gaps.push({
|
|
1704
|
-
file,
|
|
1705
|
-
field: `${field}.${i}.doneWhen`,
|
|
1706
|
-
message: `${item.id} is open and needs doneWhen: what has to be true to check it`
|
|
1707
|
-
});
|
|
1711
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1712
|
+
items.forEach((item, i) => {
|
|
1713
|
+
if (seen.has(item.id)) gaps.push({
|
|
1714
|
+
file,
|
|
1715
|
+
field: `${field}.${i}.id`,
|
|
1716
|
+
message: `${item.id} is used twice; give it the next free id`
|
|
1708
1717
|
});
|
|
1709
|
-
|
|
1718
|
+
seen.add(item.id);
|
|
1719
|
+
if (open && !item.done && !item.dropped && !item.doneWhen?.trim()) gaps.push({
|
|
1720
|
+
file,
|
|
1721
|
+
field: `${field}.${i}.doneWhen`,
|
|
1722
|
+
message: `${item.id} is open and needs doneWhen: what has to be true to check it`
|
|
1723
|
+
});
|
|
1724
|
+
});
|
|
1725
|
+
return gaps;
|
|
1726
|
+
}
|
|
1727
|
+
function contentGaps(mainline, tasks) {
|
|
1728
|
+
const gaps = [];
|
|
1729
|
+
const list = (file, field, items, open) => gaps.push(...listGaps(file, field, items, open));
|
|
1710
1730
|
const mainlineOpen = isOpen$2("mainline", mainline.status);
|
|
1711
1731
|
list(mainline.file, "criteria", mainline.criteria, mainlineOpen);
|
|
1712
1732
|
if (mainlineOpen && tasks.length > 0) for (const message of surveyGaps(mainline.body)) gaps.push({
|
|
@@ -1847,6 +1867,7 @@ function requireExisting(hub, ref) {
|
|
|
1847
1867
|
entryFile(hub, FINDINGS_DIR, parsed.finding, "finding");
|
|
1848
1868
|
return;
|
|
1849
1869
|
case "group":
|
|
1870
|
+
case "groupCriterion":
|
|
1850
1871
|
entryFile(hub, GROUPS_DIR, parsed.group, "group");
|
|
1851
1872
|
return;
|
|
1852
1873
|
default:
|
|
@@ -2030,6 +2051,26 @@ function createGroup(hub, input, ctx) {
|
|
|
2030
2051
|
file
|
|
2031
2052
|
});
|
|
2032
2053
|
}
|
|
2054
|
+
/** The mainlines and issues of this hub that are members of group `id` and not yet settled, by id. */
|
|
2055
|
+
function openMembers(hub, id) {
|
|
2056
|
+
const own = readConfigIn(hub).hub;
|
|
2057
|
+
const isMember = (value) => value === id || value === `${own}:${id}`;
|
|
2058
|
+
const read = (path) => splitFrontMatter(hub.read(path) ?? "").data ?? {};
|
|
2059
|
+
const mainlines = hub.list(MAINLINES_DIR).filter((e) => e.dir).map((e) => read(`${MAINLINES_DIR}/${e.name}/${MAINLINE_FILE}`));
|
|
2060
|
+
const issues = hub.list(ISSUES_DIR).filter((e) => !e.dir && e.name.endsWith(".md")).map((e) => read(`${ISSUES_DIR}/${e.name}`));
|
|
2061
|
+
return [...mainlines.filter((m) => isMember(m.group) && !closes("mainline", m.status ?? "")), ...issues.filter((i) => isMember(i.group) && i.status !== "closed")].map((d) => d.id ?? "?");
|
|
2062
|
+
}
|
|
2063
|
+
/**
|
|
2064
|
+
* Marking a group done is a claim that its goal is reached and its work is settled, so it is refused while a
|
|
2065
|
+
* criterion is still open or a mainline or issue of this hub in the group is not finished. The message names each one.
|
|
2066
|
+
* Members in other hubs are not read here, since the writer only sees this hub.
|
|
2067
|
+
*/
|
|
2068
|
+
function requireGroupDone(hub, id, g) {
|
|
2069
|
+
const open = (g.criteria ?? []).filter((c) => !c.done && !c.dropped).map((c) => `${id}#${c.id}`);
|
|
2070
|
+
const members = openMembers(hub, id);
|
|
2071
|
+
if (!open.length && !members.length) return;
|
|
2072
|
+
throw new WriteError(`${id} cannot be marked done: ${[open.length ? `unmet criteria ${open.join(", ")} (check each with evidence, e.g. criterion check ${open[0]} --evidence <commit>, or reword or drop it in the group file)` : "", members.length ? `unfinished members ${members.join(", ")} (finish them, or move them out with mainline set or issue set --group none)` : ""].filter(Boolean).join("; ")}`);
|
|
2073
|
+
}
|
|
2033
2074
|
function setGroup(hub, input, ctx) {
|
|
2034
2075
|
const { patch } = input;
|
|
2035
2076
|
requireRef(input.id, "group");
|
|
@@ -2042,6 +2083,7 @@ function setGroup(hub, input, ctx) {
|
|
|
2042
2083
|
const draft = new Draft(hub);
|
|
2043
2084
|
return draft.result(editFrontMatter(draft, entryFile(draft, GROUPS_DIR, input.id, "group"), groupSchema, (g) => {
|
|
2044
2085
|
if (status) {
|
|
2086
|
+
if (status === "done" && g.status !== "done") requireGroupDone(draft, input.id, g);
|
|
2045
2087
|
g.status = status;
|
|
2046
2088
|
stampClosed(g, closes("group", status), day);
|
|
2047
2089
|
}
|
|
@@ -2078,7 +2120,6 @@ function listFilesIn(hub, dir) {
|
|
|
2078
2120
|
function createMainline(hub, input, ctx) {
|
|
2079
2121
|
requireSlug(input.slug);
|
|
2080
2122
|
const group = input.group ? requireGroup(hub, input.group) : void 0;
|
|
2081
|
-
const role = input.role ? requireOneOf(input.role, MAINLINE_ROLES, "mainline role") : void 0;
|
|
2082
2123
|
const priority = input.priority ? requirePriority(input.priority) : void 0;
|
|
2083
2124
|
const { day } = stamps(ctx);
|
|
2084
2125
|
const draft = new Draft(hub);
|
|
@@ -2095,7 +2136,6 @@ function createMainline(hub, input, ctx) {
|
|
|
2095
2136
|
...priority ? { priority } : {},
|
|
2096
2137
|
created: day,
|
|
2097
2138
|
...group ? { group } : {},
|
|
2098
|
-
...role ? { role } : {},
|
|
2099
2139
|
criteria: []
|
|
2100
2140
|
}, MAINLINE_FILE);
|
|
2101
2141
|
draft.makeDir(`${dir}/tasks`);
|
|
@@ -2137,7 +2177,7 @@ function activatePlanning(draft, id) {
|
|
|
2137
2177
|
editFrontMatter(draft, path, mainlineSchema, (m) => void (m.status = "active"));
|
|
2138
2178
|
}
|
|
2139
2179
|
/**
|
|
2140
|
-
* Change a mainline's status, group
|
|
2180
|
+
* Change a mainline's status, group or priority. Done is refused while criteria are open or decisions are
|
|
2141
2181
|
* proposed; the other fields change without conditions, in the same write.
|
|
2142
2182
|
*/
|
|
2143
2183
|
function setMainline(hub, input, ctx) {
|
|
@@ -2145,11 +2185,9 @@ function setMainline(hub, input, ctx) {
|
|
|
2145
2185
|
if ([
|
|
2146
2186
|
input.status,
|
|
2147
2187
|
input.group,
|
|
2148
|
-
input.role,
|
|
2149
2188
|
input.priority
|
|
2150
|
-
].every((v) => v === void 0)) throw new WriteError(`${input.id} needs --status, --group
|
|
2189
|
+
].every((v) => v === void 0)) throw new WriteError(`${input.id} needs --status, --group or --priority, e.g. --status paused`);
|
|
2151
2190
|
const next = input.status === void 0 ? void 0 : requireOneOf(input.status, MAINLINE_STATUS, "mainline status");
|
|
2152
|
-
const role = input.role === void 0 ? void 0 : requireOneOf(input.role, MAINLINE_ROLES, "mainline role");
|
|
2153
2191
|
const priority = input.priority === void 0 ? void 0 : requirePriority(input.priority);
|
|
2154
2192
|
const { day } = stamps(ctx);
|
|
2155
2193
|
const draft = new Draft(hub);
|
|
@@ -2162,7 +2200,6 @@ function setMainline(hub, input, ctx) {
|
|
|
2162
2200
|
}
|
|
2163
2201
|
if (group) m.group = group;
|
|
2164
2202
|
else if (clearsGroup(input.group)) delete m.group;
|
|
2165
|
-
if (role) m.role = role;
|
|
2166
2203
|
if (priority) m.priority = priority;
|
|
2167
2204
|
}, input.expectedVersion));
|
|
2168
2205
|
}
|
|
@@ -2185,45 +2222,69 @@ function setMainlineArchived(hub, input, ctx) {
|
|
|
2185
2222
|
else delete m.archivedAt;
|
|
2186
2223
|
}, input.expectedVersion));
|
|
2187
2224
|
}
|
|
2188
|
-
/**
|
|
2225
|
+
/** The mainline or group a criterion list belongs to, from `m001` or `w001`. */
|
|
2226
|
+
function requireOwner(input) {
|
|
2227
|
+
const ref = parseRef(input);
|
|
2228
|
+
if (ref?.kind !== "mainline" && ref?.kind !== "group") throw new WriteError(`expected a mainline or group reference like ${refExample("mainline")} or ${refExample("group")}, got "${input}"`);
|
|
2229
|
+
return input;
|
|
2230
|
+
}
|
|
2231
|
+
/** The owner and criterion ids of `m001#r001` or `w001#r001`. */
|
|
2232
|
+
function requireCriterionRef(input) {
|
|
2233
|
+
const ref = parseRef(input);
|
|
2234
|
+
if (ref?.kind === "criterion") return {
|
|
2235
|
+
owner: ref.mainline,
|
|
2236
|
+
criterion: ref.criterion
|
|
2237
|
+
};
|
|
2238
|
+
if (ref?.kind === "groupCriterion") return {
|
|
2239
|
+
owner: ref.group,
|
|
2240
|
+
criterion: ref.criterion
|
|
2241
|
+
};
|
|
2242
|
+
throw new WriteError(`expected a criterion reference like ${refExample("criterion")} or ${refExample("groupCriterion")}, got "${input}"`);
|
|
2243
|
+
}
|
|
2244
|
+
/** Edit the criteria of the mainline or group `owner`; a group written before criteria existed gets an empty list first. */
|
|
2245
|
+
function editCriteria(draft, owner, mutate, expectedVersion) {
|
|
2246
|
+
if (parseRef(owner)?.kind === "group") return editFrontMatter(draft, groupFileIn(draft, owner), groupSchema, (g) => mutate(g.criteria ??= []), expectedVersion);
|
|
2247
|
+
return editFrontMatter(draft, mainlineFileIn(draft, owner), mainlineSchema, (m) => mutate(m.criteria), expectedVersion);
|
|
2248
|
+
}
|
|
2249
|
+
/** Add an open criterion at the end of the list of the mainline or group in `mainline`, numbered by the context's allocator. */
|
|
2189
2250
|
function addCriterion(hub, input, ctx) {
|
|
2190
|
-
|
|
2191
|
-
const fields = newListItem(input, `criterion add ${
|
|
2251
|
+
const owner = requireOwner(input.mainline);
|
|
2252
|
+
const fields = newListItem(input, `criterion add ${owner}`);
|
|
2192
2253
|
const draft = new Draft(hub);
|
|
2193
2254
|
let ref = "";
|
|
2194
|
-
|
|
2255
|
+
editCriteria(draft, owner, (criteria) => {
|
|
2195
2256
|
const id = draft.number(ctx, {
|
|
2196
2257
|
prefix: "r",
|
|
2197
|
-
taken:
|
|
2198
|
-
ref: (id) => `${
|
|
2258
|
+
taken: criteria.map((c) => c.id),
|
|
2259
|
+
ref: (id) => `${owner}#${id}`
|
|
2199
2260
|
});
|
|
2200
|
-
|
|
2261
|
+
criteria.push({
|
|
2201
2262
|
id,
|
|
2202
2263
|
...fields
|
|
2203
2264
|
});
|
|
2204
|
-
ref = `${
|
|
2265
|
+
ref = `${owner}#${id}`;
|
|
2205
2266
|
});
|
|
2206
2267
|
return draft.result({ ref });
|
|
2207
2268
|
}
|
|
2208
2269
|
function setCriterion(hub, input, ctx) {
|
|
2209
|
-
const
|
|
2270
|
+
const { owner, criterion: id } = requireCriterionRef(input.ref);
|
|
2210
2271
|
if (input.done && !input.evidence) throw new WriteError(`marking ${input.ref} as met needs evidence, e.g. --evidence mainflow@25e4165`);
|
|
2211
2272
|
const { day } = stamps(ctx);
|
|
2212
2273
|
const draft = new Draft(hub);
|
|
2213
|
-
return draft.result(
|
|
2214
|
-
const criterion =
|
|
2274
|
+
return draft.result(editCriteria(draft, owner, (criteria) => {
|
|
2275
|
+
const criterion = criteria.find((c) => c.id === id);
|
|
2215
2276
|
if (!criterion) throw new WriteError(`criterion ${input.ref} not found`);
|
|
2216
|
-
setListItem(criterion, input.done, input.evidence, `${input.ref} is dropped; remove dropped and supersededBy in ${MAINLINE_FILE} to bring it back before checking it`, day);
|
|
2277
|
+
setListItem(criterion, input.done, input.evidence, `${input.ref} is dropped; remove dropped and supersededBy in ${parseRef(owner)?.kind === "group" ? "the group file" : MAINLINE_FILE} to bring it back before checking it`, day);
|
|
2217
2278
|
}, input.expectedVersion));
|
|
2218
2279
|
}
|
|
2219
2280
|
/** Rewrite a criterion's text or doneWhen, leaving done and evidence as they are. */
|
|
2220
2281
|
function setCriterionText(hub, input) {
|
|
2221
|
-
const
|
|
2282
|
+
const { owner, criterion: id } = requireCriterionRef(input.ref);
|
|
2222
2283
|
const { patch } = input;
|
|
2223
2284
|
if (patch.text === void 0 && patch.doneWhen === void 0) throw new WriteError(`${input.ref} needs --text or --done-when, e.g. --text "CLI can create mainlines"`);
|
|
2224
2285
|
const draft = new Draft(hub);
|
|
2225
|
-
return draft.result(
|
|
2226
|
-
const criterion =
|
|
2286
|
+
return draft.result(editCriteria(draft, owner, (criteria) => {
|
|
2287
|
+
const criterion = criteria.find((c) => c.id === id);
|
|
2227
2288
|
if (!criterion) throw new WriteError(`criterion ${input.ref} not found`);
|
|
2228
2289
|
if (patch.text !== void 0) criterion.text = patch.text;
|
|
2229
2290
|
if (patch.doneWhen !== void 0) criterion.doneWhen = patch.doneWhen;
|
|
@@ -2674,14 +2735,21 @@ function resolveActionIn(hub, ref) {
|
|
|
2674
2735
|
}
|
|
2675
2736
|
/**
|
|
2676
2737
|
* Every served checklist item or criterion must exist, so a session never points at work that is not in a
|
|
2677
|
-
* mainline. A criterion stands in while the mainline has no task for it yet, as when it is still being
|
|
2678
|
-
* and planned
|
|
2738
|
+
* mainline or a group. A criterion stands in while the mainline has no task for it yet, as when it is still being
|
|
2739
|
+
* surveyed and planned; a group's criterion (w001#r001) stands for work that belongs to the group as a whole. Its
|
|
2740
|
+
* mainline or group must still be open: follow-up work on an ended one either reopens it with a criterion
|
|
2679
2741
|
* or task for the follow-up, or starts a new mainline, so the follow-up is tracked instead of hanging off finished work.
|
|
2680
2742
|
*/
|
|
2681
2743
|
function requireServes(hub, serves) {
|
|
2682
2744
|
for (const ref of serves) {
|
|
2683
2745
|
const parsed = parseRef(ref);
|
|
2684
|
-
if (!SERVES_REF.test(ref) || parsed?.kind !== "checklistItem" && parsed?.kind !== "criterion") throw new WriteError(`--serves takes checklist items like m001/t002#c003 or criteria like m001#r001, got "${ref}"`);
|
|
2746
|
+
if (!SERVES_REF.test(ref) || parsed?.kind !== "checklistItem" && parsed?.kind !== "criterion" && parsed?.kind !== "groupCriterion") throw new WriteError(`--serves takes checklist items like m001/t002#c003 or criteria like m001#r001 or w001#r001, got "${ref}"`);
|
|
2747
|
+
if (parsed.kind === "groupCriterion") {
|
|
2748
|
+
const group = readFrontMatterIn(hub, groupFileIn(hub, parsed.group), groupSchema);
|
|
2749
|
+
if (group.status !== "open") throw new WriteError(`${parsed.group} is ${group.status}; to continue it, run "group set ${parsed.group} --status open" and add a criterion for the follow-up`);
|
|
2750
|
+
if (!(group.criteria ?? []).some((r) => r.id === parsed.criterion)) throw new WriteError(`criterion ${ref} not found`);
|
|
2751
|
+
continue;
|
|
2752
|
+
}
|
|
2685
2753
|
const mainline = readFrontMatterIn(hub, mainlineFileIn(hub, parsed.mainline), mainlineSchema);
|
|
2686
2754
|
if (CLOSED_STATUS.mainline.includes(mainline.status)) throw new WriteError(`${parsed.mainline} is ${mainline.status}; to continue it, run "mainline set ${parsed.mainline} --status active" and add a criterion or task for the follow-up, or start a new mainline with "new mainline"`);
|
|
2687
2755
|
if (parsed.kind === "criterion") {
|
|
@@ -3237,6 +3305,7 @@ const rewriteOf = ({ from, to }) => {
|
|
|
3237
3305
|
case "task":
|
|
3238
3306
|
case "decision":
|
|
3239
3307
|
case "criterion": return short((s) => s.mainline === ref.mainline);
|
|
3308
|
+
case "groupCriterion": return short((s) => s.group === ref.group);
|
|
3240
3309
|
case "checklistItem": return short((s) => s.mainline === ref.mainline && s.task === ref.task);
|
|
3241
3310
|
default: return {
|
|
3242
3311
|
full: from,
|
|
@@ -3266,6 +3335,10 @@ const ENTRY = /^([mtdifw]\d{3})(-.+)$/;
|
|
|
3266
3335
|
function scopeOfPath(path) {
|
|
3267
3336
|
const [top, second, third, fourth] = path.split("/");
|
|
3268
3337
|
if (top === "local" && second === "sessions" && third?.endsWith(".yaml") && fourth === void 0) return { session: third.slice(0, -5) };
|
|
3338
|
+
if (top === "groups" && second && third === void 0) {
|
|
3339
|
+
const group = ENTRY.exec(second)?.[1];
|
|
3340
|
+
return group ? { group } : {};
|
|
3341
|
+
}
|
|
3269
3342
|
if (top !== "mainlines" || !second) return {};
|
|
3270
3343
|
const mainline = ENTRY.exec(second)?.[1];
|
|
3271
3344
|
const task = third === "tasks" && fourth ? ENTRY.exec(fourth)?.[1] : void 0;
|
|
@@ -3684,6 +3757,8 @@ const mayDecorate = (text) => /m\d{3}|[ifw]\d{3}|\.mainflow\/mainlines/.test(tex
|
|
|
3684
3757
|
//#region ../core/dist/grants.js
|
|
3685
3758
|
/** Mainline statuses whose grants apply. */
|
|
3686
3759
|
const GRANTING_STATUS = ["active", "planning"];
|
|
3760
|
+
/** Group statuses whose grants apply. */
|
|
3761
|
+
const GRANTING_GROUP_STATUS = ["open"];
|
|
3687
3762
|
/**
|
|
3688
3763
|
* The grants in effect for a session. Reading a mainline that is missing or invalid throws, so a caller that
|
|
3689
3764
|
* must fail closed catches it and asks.
|
|
@@ -3708,13 +3783,21 @@ function grantScope(root, session) {
|
|
|
3708
3783
|
return parsed ? refMainline(parsed) : void 0;
|
|
3709
3784
|
};
|
|
3710
3785
|
const mainlines = [...new Set(action.serves.flatMap((ref) => mainlineOf(ref) ?? []))];
|
|
3711
|
-
|
|
3786
|
+
const direct = /* @__PURE__ */ new Map();
|
|
3787
|
+
for (const ref of action.serves) {
|
|
3788
|
+
const parsed = parseRef(ref);
|
|
3789
|
+
if (parsed?.kind === "groupCriterion" && !direct.has(parsed.group)) direct.set(parsed.group, ref);
|
|
3790
|
+
}
|
|
3791
|
+
if (mainlines.length === 0 && direct.size === 0) return {
|
|
3712
3792
|
ok: false,
|
|
3713
3793
|
reason: `${action.id} 沒有服務任何 checklist 項目或解決條件`
|
|
3714
3794
|
};
|
|
3715
3795
|
const grants = [];
|
|
3716
3796
|
const served = {};
|
|
3717
3797
|
const closed = [];
|
|
3798
|
+
const hubName = readConfig(root).hub;
|
|
3799
|
+
const groups = new Map(direct);
|
|
3800
|
+
const reachedByMainline = /* @__PURE__ */ new Set();
|
|
3718
3801
|
for (const id of mainlines) {
|
|
3719
3802
|
const mainline = readFrontMatter(mainlineFile(root, id), mainlineSchema).data;
|
|
3720
3803
|
if (!GRANTING_STATUS.includes(mainline.status)) {
|
|
@@ -3723,15 +3806,42 @@ function grantScope(root, session) {
|
|
|
3723
3806
|
}
|
|
3724
3807
|
served[id] = action.serves.find((ref) => mainlineOf(ref) === id);
|
|
3725
3808
|
for (const grant of mainline.grants ?? []) grants.push({
|
|
3726
|
-
|
|
3809
|
+
owner: id,
|
|
3727
3810
|
grant,
|
|
3728
3811
|
ref: `${id}#${grant.id}`
|
|
3729
3812
|
});
|
|
3813
|
+
const own = mainline.group ? splitGroup(mainline.group, hubName) : void 0;
|
|
3814
|
+
if (own && own.hub === void 0 && !groups.has(own.id)) {
|
|
3815
|
+
groups.set(own.id, served[id]);
|
|
3816
|
+
reachedByMainline.add(own.id);
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
for (const [id, via] of groups) {
|
|
3820
|
+
let group;
|
|
3821
|
+
try {
|
|
3822
|
+
group = readFrontMatter(groupFile(root, id), groupSchema).data;
|
|
3823
|
+
} catch (error) {
|
|
3824
|
+
if (reachedByMainline.has(id)) continue;
|
|
3825
|
+
throw error;
|
|
3826
|
+
}
|
|
3827
|
+
if (!GRANTING_GROUP_STATUS.includes(group.status)) {
|
|
3828
|
+
closed.push(`${id} 是 ${group.status}`);
|
|
3829
|
+
continue;
|
|
3830
|
+
}
|
|
3831
|
+
served[id] = via;
|
|
3832
|
+
for (const grant of group.grants ?? []) grants.push({
|
|
3833
|
+
owner: id,
|
|
3834
|
+
grant,
|
|
3835
|
+
ref: `${id}#${grant.id}`
|
|
3836
|
+
});
|
|
3837
|
+
}
|
|
3838
|
+
if (Object.keys(served).length === 0) {
|
|
3839
|
+
const what = [closed.some((c) => c.startsWith("m")) ? "主脈絡" : "", closed.some((c) => c.startsWith("w")) ? "組" : ""].filter(Boolean).join("或");
|
|
3840
|
+
return {
|
|
3841
|
+
ok: false,
|
|
3842
|
+
reason: `${action.id} 服務的${what}已不在進行中(${closed.join("、")}),授權不再生效`
|
|
3843
|
+
};
|
|
3730
3844
|
}
|
|
3731
|
-
if (Object.keys(served).length === 0) return {
|
|
3732
|
-
ok: false,
|
|
3733
|
-
reason: `${action.id} 服務的主脈絡已不在進行中(${closed.join("、")}),授權不再生效`
|
|
3734
|
-
};
|
|
3735
3845
|
return {
|
|
3736
3846
|
ok: true,
|
|
3737
3847
|
scope: {
|
|
@@ -3812,8 +3922,18 @@ function setReminderDigest(root, id, digest) {
|
|
|
3812
3922
|
//#region ../core/dist/briefing.js
|
|
3813
3923
|
function describe(root, ref) {
|
|
3814
3924
|
const parsed = parseRef(ref);
|
|
3815
|
-
if (parsed?.kind !== "checklistItem" && parsed?.kind !== "criterion") return null;
|
|
3925
|
+
if (parsed?.kind !== "checklistItem" && parsed?.kind !== "criterion" && parsed?.kind !== "groupCriterion") return null;
|
|
3816
3926
|
try {
|
|
3927
|
+
if (parsed.kind === "groupCriterion") {
|
|
3928
|
+
const group = readFrontMatter(groupFile(root, parsed.group), groupSchema).data;
|
|
3929
|
+
const criterion = group.criteria?.find((r) => r.id === parsed.criterion);
|
|
3930
|
+
return criterion ? {
|
|
3931
|
+
ref,
|
|
3932
|
+
text: criterion.text,
|
|
3933
|
+
checked: criterion.done,
|
|
3934
|
+
where: `${group.id} ${group.title} › 解決條件`
|
|
3935
|
+
} : null;
|
|
3936
|
+
}
|
|
3817
3937
|
const mainline = readFrontMatter(mainlineFile(root, parsed.mainline), mainlineSchema).data;
|
|
3818
3938
|
if (parsed.kind === "criterion") {
|
|
3819
3939
|
const criterion = mainline.criteria.find((r) => r.id === parsed.criterion);
|
|
@@ -4016,7 +4136,7 @@ function sessionBriefing(root, session, options) {
|
|
|
4016
4136
|
lines.push(doing ? `目前行動:${doing.id} ${doing.do}` : "目前沒有進行中的行動。");
|
|
4017
4137
|
if (doing) lines.push(`服務:${servedLine(root, doing)}`);
|
|
4018
4138
|
const grants = grantLines(root, session);
|
|
4019
|
-
if (grants.length > 0) lines.push("
|
|
4139
|
+
if (grants.length > 0) lines.push("目前行動服務的主脈絡與所屬的組預先授權了這些動作:", ...grants);
|
|
4020
4140
|
if (upcoming.length > 0) lines.push(`接下來:${upcoming.map((a) => `${a.id} ${a.do}`).join("、")}`);
|
|
4021
4141
|
const blocked = session.actions.filter((a) => a.status === "blocked");
|
|
4022
4142
|
if (blocked.length > 0) lines.push(`等外部條件:${blocked.map(waitingLine).join(";")}`);
|
|
@@ -4058,7 +4178,7 @@ function turnReminder(root, session, options) {
|
|
|
4058
4178
|
else setReminderDigest(root, session.id, digest);
|
|
4059
4179
|
} catch {}
|
|
4060
4180
|
const once = (lines, summary, full) => lines.length === 0 ? [] : repeated ? [summary] : full;
|
|
4061
|
-
const granted = once(grants, `- 預先授權同上一輪,共 ${grants.length} 條。`, ["-
|
|
4181
|
+
const granted = once(grants, `- 預先授權同上一輪,共 ${grants.length} 條。`, ["- 目前行動服務的主脈絡與所屬的組預先授權了這些動作:", ...grants.map((g) => ` ${g}`)]);
|
|
4062
4182
|
const waiting = once(waiters, `- 等待行同上一輪,共 ${waiters.length} 條。`, waiters.map((w) => `- ${w}`));
|
|
4063
4183
|
const warned = once(warnings, `- 佇列提醒同上一輪,共 ${warnings.length} 條。`, warnings.map((w) => `- ${w}`));
|
|
4064
4184
|
return [
|
|
@@ -8041,6 +8161,77 @@ function migrateHub(root, options = {}) {
|
|
|
8041
8161
|
}).value;
|
|
8042
8162
|
}
|
|
8043
8163
|
//#endregion
|
|
8164
|
+
//#region ../core/dist/group-plan.js
|
|
8165
|
+
/** Sessions that can still hold work: not archived, and active or paused. */
|
|
8166
|
+
const live = (s) => !s.archivedAt && (s.status === "active" || s.status === "paused");
|
|
8167
|
+
/** Order `refs` so each comes after the ones it depends on; members in a dependency loop keep their given order at the end. */
|
|
8168
|
+
function ordered(refs, dependsOn) {
|
|
8169
|
+
const done = /* @__PURE__ */ new Set();
|
|
8170
|
+
const out = [];
|
|
8171
|
+
for (let progressed = true; progressed && out.length < refs.length;) {
|
|
8172
|
+
progressed = false;
|
|
8173
|
+
for (const ref of refs) {
|
|
8174
|
+
if (done.has(ref) || !(dependsOn.get(ref) ?? []).every((d) => done.has(d))) continue;
|
|
8175
|
+
done.add(ref);
|
|
8176
|
+
out.push(ref);
|
|
8177
|
+
progressed = true;
|
|
8178
|
+
break;
|
|
8179
|
+
}
|
|
8180
|
+
}
|
|
8181
|
+
return [...out, ...refs.filter((r) => !done.has(r))];
|
|
8182
|
+
}
|
|
8183
|
+
function groupPlan(hub, sessions, groupId) {
|
|
8184
|
+
const own = hub.config.hub;
|
|
8185
|
+
const mainlines = hub.mainlines.filter((m) => memberOfGroup(m.group, groupId, own));
|
|
8186
|
+
const issues = hub.issues.filter((i) => memberOfGroup(i.group, groupId, own));
|
|
8187
|
+
const docs = [...mainlines.map((m) => ({
|
|
8188
|
+
ref: m.id,
|
|
8189
|
+
kind: "mainline",
|
|
8190
|
+
title: m.title,
|
|
8191
|
+
status: m.status,
|
|
8192
|
+
open: !CLOSED_STATUS.mainline.includes(m.status),
|
|
8193
|
+
links: m.links
|
|
8194
|
+
})), ...issues.map((i) => ({
|
|
8195
|
+
ref: i.id,
|
|
8196
|
+
kind: "issue",
|
|
8197
|
+
title: i.title,
|
|
8198
|
+
status: i.status,
|
|
8199
|
+
open: i.status !== "closed",
|
|
8200
|
+
links: i.links
|
|
8201
|
+
}))];
|
|
8202
|
+
const refs = docs.map((d) => d.ref);
|
|
8203
|
+
const dependsOn = new Map(docs.map((d) => [d.ref, (d.links ?? []).filter((l) => l.rel === "depends-on").map((l) => parseRef(l.to)?.hub === own ? l.to.slice(l.to.indexOf(":") + 1) : l.to).filter((to) => refs.includes(to) && to !== d.ref)]));
|
|
8204
|
+
const active = (matches) => sessions.filter(live).flatMap((s) => s.actions.flatMap((a) => (a.status === "doing" || a.status === "blocked") && a.serves.some(matches) ? [{
|
|
8205
|
+
session: s.id,
|
|
8206
|
+
action: a.id,
|
|
8207
|
+
status: a.status,
|
|
8208
|
+
do: a.do
|
|
8209
|
+
}] : []));
|
|
8210
|
+
const mainlineOf = (served) => {
|
|
8211
|
+
const parsed = parseRef(served);
|
|
8212
|
+
return parsed ? refMainline(parsed) : void 0;
|
|
8213
|
+
};
|
|
8214
|
+
const byRef = new Map(docs.map((d) => [d.ref, d]));
|
|
8215
|
+
return {
|
|
8216
|
+
members: ordered(refs, dependsOn).map((ref) => {
|
|
8217
|
+
const d = byRef.get(ref);
|
|
8218
|
+
return {
|
|
8219
|
+
ref,
|
|
8220
|
+
kind: d.kind,
|
|
8221
|
+
title: d.title,
|
|
8222
|
+
status: d.status,
|
|
8223
|
+
open: d.open,
|
|
8224
|
+
dependsOn: dependsOn.get(ref) ?? [],
|
|
8225
|
+
active: d.kind === "mainline" ? active((s) => mainlineOf(s) === ref) : []
|
|
8226
|
+
};
|
|
8227
|
+
}),
|
|
8228
|
+
active: active((s) => {
|
|
8229
|
+
const parsed = parseRef(s);
|
|
8230
|
+
return parsed?.kind === "groupCriterion" && parsed.group === groupId;
|
|
8231
|
+
})
|
|
8232
|
+
};
|
|
8233
|
+
}
|
|
8234
|
+
//#endregion
|
|
8044
8235
|
//#region src/host.ts
|
|
8045
8236
|
const DEFAULT_UI_PORT = 4320;
|
|
8046
8237
|
const hostName = (hub) => `${hub}.mainflow.localhost`;
|
|
@@ -8239,4 +8430,4 @@ function openInApp(hub, target, closeAfterMs = 150) {
|
|
|
8239
8430
|
return true;
|
|
8240
8431
|
}
|
|
8241
8432
|
//#endregion
|
|
8242
|
-
export {
|
|
8433
|
+
export { unavailableHubs as $, headerLine as A, scopeOfPath as B, loadSessions as C, DATA_DIR as Ct, matchGrants as D, grantScope as E, splitFrontMatter as Et, applyOffline as F, loadHub as G, checkHubName as H, renumberRequest as I, mainlineEdges as J, sectionText as K, renumberFiles as L, attributeTrace as M, traceTranscript as N, decorateReply as O, transcriptTitle as P, remoteMembers as Q, renumberPath as R, turnReminder as S, ConflictError as St, transcriptPath as T, contentHash as Tt, HubError as U, applyOperation as V, loadConfig as W, memberOfGroup as X, linksInto as Y, refIndex as Z, setArchivedMany as _, TASK_FILE as _t, openInApp as a, MAX_BLOB_BYTES as at, duplicateClaimLines as b, findHubRoot as bt, siteBlock as c, SOCKET_MAX_AGE_CLOSE as ct, migrateHub as d, readsAsText as dt, nowMinute as et, retroReport as f, requestTime as ft, ARCHIVE_KINDS as g, MAINLINE_FILE as gt, RETRY_RULES as h, hubFormatVersion as ht, hostName as i, BLOB_HASH as it, mayDecorate as j, endsWithMarker as k, syncHost as l, comparePaths as lt, receiverFromEnv as m, formatMismatch as mt, DEFAULT_UI_PORT as n, nodeStorage as nt, removeDanglingLinks as o, MAX_FILE_BYTES as ot, retroReportFromReceiver as p, textBytes as pt, dependencyGraph as q, caddySites as r, ACCESS_HEADERS as rt, removeHostLink as s, ROUTES as st, APP_BUNDLE_ID as t, readYaml as tt, groupPlan as u, exceedsFileLimit as ut, initHub as v, requireSlug as vt, readSession as w, WriteError as wt, sessionBriefing as x, worktreesOf as xt, untilState as y, currentBranch as yt, renumberText as z };
|
package/dist/host.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as openInApp, c as siteBlock, i as hostName, l as syncHost, n as DEFAULT_UI_PORT, o as removeDanglingLinks, r as caddySites, s as removeHostLink, t as APP_BUNDLE_ID } from "./host-
|
|
1
|
+
import { a as openInApp, c as siteBlock, i as hostName, l as syncHost, n as DEFAULT_UI_PORT, o as removeDanglingLinks, r as caddySites, s as removeHostLink, t as APP_BUNDLE_ID } from "./host-CIOd2WSh.js";
|
|
2
2
|
export { APP_BUNDLE_ID, DEFAULT_UI_PORT, caddySites, hostName, openInApp, removeDanglingLinks, removeHostLink, siteBlock, syncHost };
|