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 CHANGED
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { G as parseRef, K as parseUntil, N as UNTIL_FORMS, et as stampMs, n as CLOSED_STATUS, q as refExample } from "./dist-ud09dzZo.js";
3
- import { $ as nowMinute, B as applyOperation, C as readSession, Ct as WriteError, H as HubError, Q as unavailableHubs, S as loadSessions, St as DATA_DIR, V as checkHubName, W as loadHub, Y as memberOfGroup, Z as remoteMembers, _ as initHub, _t as requireSlug, at as MAX_FILE_BYTES, b as sessionBriefing, d as retroReport, f as retroReportFromReceiver, gt as TASK_FILE, ht as MAINLINE_FILE, m as RETRY_RULES, p as receiverFromEnv, tt as nodeStorage, u as migrateHub, v as untilState, y as duplicateClaimLines, yt as findHubRoot } from "./host-lY8ytTbw.js";
2
+ import { $ as stampMs, G as parseUntil, K as refExample, M as UNTIL_FORMS, W as parseRef, n as CLOSED_STATUS } from "./dist-zSabglPq.js";
3
+ import { $ as unavailableHubs, C as loadSessions, Ct as DATA_DIR, G as loadHub, H as checkHubName, K as sectionText, Q as remoteMembers, U as HubError, V as applyOperation, X as memberOfGroup, _t as TASK_FILE, b as duplicateClaimLines, bt as findHubRoot, d as migrateHub, et as nowMinute, f as retroReport, gt as MAINLINE_FILE, h as RETRY_RULES, m as receiverFromEnv, nt as nodeStorage, ot as MAX_FILE_BYTES, p as retroReportFromReceiver, u as groupPlan, v as initHub, vt as requireSlug, w as readSession, wt as WriteError, x as sessionBriefing, y as untilState } from "./host-CIOd2WSh.js";
4
4
  import { t as listProgress } from "./progress-1BfPg2zN.js";
5
- import { C as ServerError, D as syncSettings, E as hubName, O as SETTINGS_FILE, S as ServerApi, T as earlierToken, _ as readDaemon, a as remoteMode, b as readRemote, c as planAnnounce, d as toolCallOf, f as startDaemon, g as probeDaemon, h as callDaemon, i as queuedCount, j as syncPaths, l as planFetch, m as DaemonUnavailable, n as hubWriter, o as fetchDenial, p as DaemonRunning, r as writtenLines, s as hookAnswer, t as CONFIRM_MS, u as planFlush, v as silentHint, w as ENV, x as oversizedFiles } from "./operation-BZ7CHB6J.js";
5
+ import { C as ServerError, D as syncSettings, E as hubName, O as SETTINGS_FILE, S as ServerApi, T as earlierToken, _ as readDaemon, a as remoteMode, b as readRemote, c as planAnnounce, d as toolCallOf, f as startDaemon, g as probeDaemon, h as callDaemon, i as queuedCount, j as syncPaths, l as planFetch, m as DaemonUnavailable, n as hubWriter, o as fetchDenial, p as DaemonRunning, r as writtenLines, s as hookAnswer, t as CONFIRM_MS, u as planFlush, v as silentHint, w as ENV, x as oversizedFiles } from "./operation-DJARDCM0.js";
6
6
  import { COMMAND_SPECS, OPTIONS } from "./facts.js";
7
7
  import { hookFallback, parsePayload, runHook } from "./hooks.js";
8
- import { f as CLI_VERSION, i as launchUi, l as startUiInBackground, r as exitCodeFor, u as watchHubGone } from "./launch-3HLHjQF0.js";
8
+ import { f as CLI_VERSION, i as launchUi, l as startUiInBackground, r as exitCodeFor, u as watchHubGone } from "./launch-DJ944-bI.js";
9
9
  import { randomBytes } from "node:crypto";
10
10
  import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
11
11
  import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -669,7 +669,6 @@ const WRITES = {
669
669
  slug: args[0],
670
670
  title: required(opts, "title", "--title \"重建 mainline 任務管理\""),
671
671
  group: opts.group,
672
- role: opts.role,
673
672
  priority: opts.priority
674
673
  }),
675
674
  print: (_, { id, dir }) => done(`created ${id} ${inData(dir, MAINLINE_FILE)}`)
@@ -754,14 +753,9 @@ const WRITES = {
754
753
  id: args[0],
755
754
  status: opts.status,
756
755
  group: opts.group,
757
- role: opts.role,
758
756
  priority: opts.priority
759
757
  }),
760
- print: (_, m) => done(`updated ${m.id} (${[
761
- m.status,
762
- m.group,
763
- m.role
764
- ].filter(Boolean).join(", ")})`)
758
+ print: (_, m) => done(`updated ${m.id} (${[m.status, m.group].filter(Boolean).join(", ")})`)
765
759
  }),
766
760
  "mainline archive": write({
767
761
  op: "mainline.archive",
@@ -1104,6 +1098,7 @@ const RUNS = {
1104
1098
  return done(`${shown.length} issues`);
1105
1099
  },
1106
1100
  "group list": ({ root, opts }) => printGroups(loadHub(root), opts.all ?? false),
1101
+ "group show": ({ root, args }) => printGroup(loadHub(root), loadSessions(root).sessions, args[0]),
1107
1102
  "finding list": ({ root, opts }) => {
1108
1103
  const shown = loadHub(root).findings.filter((f) => opts.all || f.status === "valid");
1109
1104
  for (const f of shown) console.log(` ${f.id} ${f.created} ${f.title}${f.labels?.length ? ` [${f.labels.join(", ")}]` : ""}`);
@@ -1346,10 +1341,9 @@ function required(opts, name, example) {
1346
1341
  if (!value) throw new WriteError(`--${name} is required, e.g. ${example}`);
1347
1342
  return value;
1348
1343
  }
1349
- /** The group and role a mainline line ends with, like ` [w001, plan]`; nothing for an impl mainline outside a group. */
1344
+ /** The group a mainline line ends with, like ` [w001]`; nothing for a mainline outside a group. */
1350
1345
  const membership = (m) => {
1351
- const tags = [m.group, m.role === "plan" ? "plan" : void 0].filter(Boolean);
1352
- return tags.length ? ` [${tags.join(", ")}]` : "";
1346
+ return m.group ? ` [${m.group}]` : "";
1353
1347
  };
1354
1348
  function printStatus(hub, all) {
1355
1349
  const shown = hub.mainlines.filter((m) => all || !m.archivedAt);
@@ -1365,7 +1359,7 @@ function printStatus(hub, all) {
1365
1359
  }
1366
1360
  /**
1367
1361
  * Open groups by priority, P0 first and a group without one as P2, then by id; each with its trigger and its members:
1368
- * plan mainlines first, then impl mainlines, then issues. Archived and closed members are left out unless --all.
1362
+ * mainlines first, then issues. Archived and closed members are left out unless --all.
1369
1363
  */
1370
1364
  function printGroups(hub, all) {
1371
1365
  const rank = (p) => (p ?? "P2").slice(1);
@@ -1375,19 +1369,44 @@ function printGroups(hub, all) {
1375
1369
  console.log(` ${g.id} ${g.status.padEnd(4)} ${g.priority ?? "P2"} ${g.title}${g.trigger ? ` (時機:${g.trigger})` : ""}`);
1376
1370
  const mainlines = hub.mainlines.filter((m) => memberOfGroup(m.group, g.id, hub.config.hub) && (all || !m.archivedAt && !CLOSED_STATUS.mainline.includes(m.status)));
1377
1371
  const issues = hub.issues.filter((i) => memberOfGroup(i.group, g.id, hub.config.hub) && (all || !i.archivedAt && i.status !== "closed"));
1378
- for (const m of [...mainlines.filter((m) => m.role === "plan"), ...mainlines.filter((m) => m.role !== "plan")]) console.log(` ${m.id} ${(m.role ?? "impl").padEnd(4)} ${m.status.padEnd(8)} ${m.title}`);
1379
- for (const i of issues) console.log(` ${i.id} issue ${i.status.padEnd(8)} ${i.title}`);
1372
+ for (const m of mainlines) console.log(` ${m.id} mainline ${m.status.padEnd(8)} ${m.title}`);
1373
+ for (const i of issues) console.log(` ${i.id} issue ${i.status.padEnd(8)} ${i.title}`);
1380
1374
  const remote = (remoteByGroup.get(g.id) ?? []).filter((m) => all || !m.archived && m.open);
1381
- for (const m of [
1382
- ...remote.filter((m) => m.role === "plan"),
1383
- ...remote.filter((m) => m.kind === "mainline" && m.role !== "plan"),
1384
- ...remote.filter((m) => m.kind === "issue")
1385
- ]) console.log(` ${m.ref} ${(m.kind === "issue" ? "issue" : m.role).padEnd(4)} ${m.status.padEnd(8)} ${m.title}`);
1375
+ for (const m of [...remote.filter((m) => m.kind === "mainline"), ...remote.filter((m) => m.kind === "issue")]) console.log(` ${m.ref} ${(m.kind === "issue" ? "issue" : "mainline").padEnd(8)} ${m.status.padEnd(8)} ${m.title}`);
1386
1376
  }
1387
1377
  const missing = unavailableHubs(hub.remotes);
1388
1378
  if (missing.length) console.log(` note: hub ${missing.join(", ")} not loaded, so their members are not listed`);
1389
1379
  return done(`${shown.length} groups`);
1390
1380
  }
1381
+ /**
1382
+ * One group: goal, criteria, grants, then its members of this hub in the order their depends-on links give, each
1383
+ * with the actions in progress or blocked that serve it. Members in other hubs are listed by `group list`.
1384
+ */
1385
+ function printGroup(hub, sessions, idInput) {
1386
+ const ref = parseRef(idInput);
1387
+ if (ref?.kind !== "group") throw new WriteError(`expected a group reference like ${refExample("group")}, got "${idInput}"`);
1388
+ const g = hub.groups.find((x) => x.id === ref.group);
1389
+ if (!g) throw new WriteError(`group ${ref.group} not found; run "mainflow group list --all" to list groups`);
1390
+ console.log(`${g.id} ${g.status.padEnd(4)} ${g.priority ?? "P2"} ${g.title}${g.trigger ? ` (時機:${g.trigger})` : ""}`);
1391
+ const goal = sectionText(g.body, "目標");
1392
+ console.log(` 目標:${goal ? goal.replace(/\s+/g, " ") : "(未填)"}`);
1393
+ const criteria = g.criteria ?? [];
1394
+ console.log(` 條件:${criteria.length ? "" : "(無)"}`);
1395
+ for (const c of criteria) console.log(` ${c.dropped ? "[-]" : c.done ? "[x]" : "[ ]"} ${g.id}#${c.id} ${c.text}${c.dropped ? " (dropped)" : ""}`);
1396
+ const grants = g.grants ?? [];
1397
+ console.log(` 授權:${grants.length ? "" : "(無)"}`);
1398
+ for (const x of grants) console.log(` ${g.id}#${x.id} ${x.action} ${x.target}`);
1399
+ const plan = groupPlan(hub, sessions, g.id);
1400
+ const work = (list) => list.map((a) => `${a.session}#${a.action}(${a.status})`).join("、");
1401
+ console.log(` 成員:${plan.members.length ? "(依 depends-on 排序)" : "(無)"}`);
1402
+ plan.members.forEach((m, i) => {
1403
+ const waits = m.dependsOn.length ? ` 依賴 ${m.dependsOn.join("、")}` : "";
1404
+ const active = m.active.length ? ` 進行中:${work(m.active)}` : "";
1405
+ console.log(` ${i + 1}. ${m.ref} ${m.kind.padEnd(8)} ${m.status.padEnd(8)} ${m.title}${waits}${active}`);
1406
+ });
1407
+ if (plan.active.length) console.log(` 服務組條件的行動:${work(plan.active)}`);
1408
+ return done(`${plan.members.length} members`);
1409
+ }
1391
1410
  function printProblems(problems, mark = "✗") {
1392
1411
  for (const problem of problems) console.error(`${mark} ${problem.file}${problem.field ? ` › ${problem.field}` : ""}: ${problem.message}`);
1393
1412
  }
@@ -381,8 +381,11 @@ const ID_PATTERNS = {
381
381
  grant: /^g\d{3}$/
382
382
  };
383
383
  const CHECKLIST_REF = /^m\d{3}\/t\d{3}#c\d{3}$/;
384
- /** What an action may serve: a checklist item, or a mainline's criterion while the mainline has no task for it yet. */
385
- const SERVES_REF = /^m\d{3}(?:\/t\d{3}#c\d{3}|#r\d{3})$/;
384
+ /**
385
+ * What an action may serve: a checklist item, or a mainline's criterion while the mainline has no task for it yet,
386
+ * or a group's criterion (`w017#r001`).
387
+ */
388
+ const SERVES_REF = /^(?:m\d{3}(?:\/t\d{3}#c\d{3}|#r\d{3})|w\d{3}#r\d{3})$/;
386
389
  const SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
387
390
  const DATE = /^\d{4}-\d{2}-\d{2}$/;
388
391
  /** A hub name: kebab-case, also the first label of {hub}.mainflow.localhost and the prefix of a cross-hub reference. */
@@ -410,6 +413,11 @@ const REF_FORMS = [
410
413
  pattern: /^(m\d{3})#(r\d{3})$/,
411
414
  example: "m001#r001"
412
415
  },
416
+ {
417
+ kind: "groupCriterion",
418
+ pattern: /^(w\d{3})#(r\d{3})$/,
419
+ example: "w001#r001"
420
+ },
413
421
  {
414
422
  kind: "decision",
415
423
  pattern: /^(m\d{3})\/(d\d{3})$/,
@@ -482,6 +490,11 @@ function parseLocal(input) {
482
490
  mainline: a,
483
491
  criterion: b
484
492
  };
493
+ case "groupCriterion": return {
494
+ kind: "groupCriterion",
495
+ group: a,
496
+ criterion: b
497
+ };
485
498
  case "decision": return {
486
499
  kind: "decision",
487
500
  mainline: a,
@@ -623,8 +636,13 @@ const FINDING_SECTIONS = [
623
636
  "影響",
624
637
  "做法"
625
638
  ];
626
- /** 說明 says what the group gathers and why; its first paragraph is the summary the interface shows on the group's heading. */
627
- const GROUP_SECTIONS = ["說明"];
639
+ /**
640
+ * 目標 says what the group's work is meant to achieve; 說明 says what the group gathers and its scope, and its first
641
+ * paragraph is the summary the interface shows on the group's heading.
642
+ */
643
+ const GROUP_SECTIONS = ["目標", "說明"];
644
+ /** The group section whose first paragraph is the summary. */
645
+ const GROUP_SUMMARY_SECTION = "說明";
628
646
  const SURVEY_SECTION = "現況查核";
629
647
  const SURVEY_LINES = [
630
648
  {
@@ -749,8 +767,9 @@ const costSchema = z.object({
749
767
  note: text.optional()
750
768
  });
751
769
  /**
752
- * One thing the mainline authorizes ahead of time: an action plus the target it covers. It applies only while
753
- * a session's action in progress serves this mainline and the mainline is still open.
770
+ * One thing a mainline or a group authorizes ahead of time: an action plus the target it covers. It applies only while
771
+ * a session's action in progress serves this mainline (or a mainline of this group, or the group's own criterion)
772
+ * and the mainline or group is still open.
754
773
  */
755
774
  const grantSchema = z.object({
756
775
  id: id("grant"),
@@ -765,13 +784,6 @@ const grantSchema = z.object({
765
784
  message: parsed.message
766
785
  });
767
786
  });
768
- /**
769
- * What a mainline is for. A plan mainline sizes the work, splits it into impl mainlines, coordinates them and makes
770
- * the final check; an impl mainline carries a piece of the work out. A mainline without a role is an impl one, and
771
- * a group may hold no plan mainline at all: a small piece of work needs none.
772
- */
773
- const MAINLINE_ROLES = ["plan", "impl"];
774
- const DEFAULT_ROLE = "impl";
775
787
  const mainlineSchema = z.object({
776
788
  id: id("mainline"),
777
789
  title: text,
@@ -779,7 +791,6 @@ const mainlineSchema = z.object({
779
791
  priority,
780
792
  ...documentShape,
781
793
  group,
782
- role: z.enum(MAINLINE_ROLES).optional(),
783
794
  due: date.optional(),
784
795
  /** Hidden from the default listings; independent of status, a done mainline may stay visible */
785
796
  archivedAt: date.optional(),
@@ -1051,8 +1062,8 @@ const findingSchema = z.object({
1051
1062
  archivedAt: date.optional()
1052
1063
  });
1053
1064
  /**
1054
- * Front matter of groups/w{NNN}-{slug}.md: mainlines and issues that belong together, such as a plan mainline with the
1055
- * impl mainlines it split off, or the issues to take up together when a measurement is fixed. Membership is written
1065
+ * Front matter of groups/w{NNN}-{slug}.md: mainlines and issues that belong together, such as the mainlines that split one
1066
+ * piece of work, or the issues to take up together when a measurement is fixed. Membership is written
1056
1067
  * on each member (`group`), so a group file never lists its members and the two cannot disagree. A group is apart
1057
1068
  * from dependencies: depends-on between groups orders them, and priority and trigger say how urgent and when.
1058
1069
  */
@@ -1063,7 +1074,11 @@ const groupSchema = z.object({
1063
1074
  priority,
1064
1075
  ...documentShape,
1065
1076
  /** When to take the group's work up, in a phrase, e.g. 量測修正時 */
1066
- trigger: text.optional()
1077
+ trigger: text.optional(),
1078
+ /** What has to be true for the group's work as a whole to be done; the same shape as a mainline's, referenced as w001#r001 */
1079
+ criteria: z.array(criterionSchema).optional(),
1080
+ /** Granted ahead of time to the work of every member mainline, and to actions serving the group's own criteria; referenced as w001#g001 */
1081
+ grants: z.array(grantSchema).optional()
1067
1082
  });
1068
1083
  /** One line of ops/{YYYY-MM}.log: an external operation, append-only. */
1069
1084
  const opsEntrySchema = z.object({
@@ -1095,4 +1110,4 @@ function parseOpsLine(line) {
1095
1110
  return parsed.success ? parsed.data : null;
1096
1111
  }
1097
1112
  //#endregion
1098
- export { OFFSET as $, SURVEY_SECTION as A, issueSchema as B, REF_EXAMPLES as C, SESSION_STATUS as D, SESSION_ID as E, configSchema as F, parseRef as G, opsEntrySchema as H, decisionSchema as I, refMainline as J, parseUntil as K, findingSchema as L, TASK_SECTIONS as M, UNTIL_FORMS as N, SLUG as O, WORK_STATUS as P, waitingForRef as Q, formatOpsEntry as R, PRIORITIES as S, SERVES_REF as T, parseActionRef as U, mainlineSchema as V, parseOpsLine as W, taskSchema as X, sessionSchema as Y, waitingForAction as Z, LINK_RELS as _, DECISION_SECTIONS as a, grantCovers as at, MAINLINE_STATUS as b, DEFAULT_ROLE as c, parseGrantTarget as ct, FORMAT_VERSION as d, stampMs as et, GROUP_SECTIONS as f, ISSUE_STATUS as g, ISSUE_SECTIONS as h, DECISION_BASES as i, describeRequest as it, TASK_REQUIRED_SECTIONS as j, SURVEY_LINES as k, FINDING_SECTIONS as l, ID_PATTERNS as m, CLOSED_STATUS as n, GRANT_FORMS as nt, DECISION_STATUS as o, grantForm as ot, GROUP_STATUS as p, refExample as q, DECIDERS as r, GRANT_TARGET_FORMS as rt, DEFAULT_CATEGORIES as s, grantRepo as st, CHECKLIST_REF as t, GRANT_ACTIONS as tt, FINDING_STATUS as u, MAINLINE_ROLES as v, RESERVED_HUB_NAMES as w, MERGE_STATES as x, MAINLINE_SECTIONS as y, groupSchema as z };
1113
+ export { stampMs as $, TASK_REQUIRED_SECTIONS as A, mainlineSchema as B, RESERVED_HUB_NAMES as C, SLUG as D, SESSION_STATUS as E, decisionSchema as F, parseUntil as G, parseActionRef as H, findingSchema as I, sessionSchema as J, refExample as K, formatOpsEntry as L, UNTIL_FORMS as M, WORK_STATUS as N, SURVEY_LINES as O, configSchema as P, OFFSET as Q, groupSchema as R, REF_EXAMPLES as S, SESSION_ID as T, parseOpsLine as U, opsEntrySchema as V, parseRef as W, waitingForAction as X, taskSchema as Y, waitingForRef as Z, LINK_RELS as _, DECISION_SECTIONS as a, grantForm as at, MERGE_STATES as b, FINDING_SECTIONS as c, GROUP_SECTIONS as d, GRANT_ACTIONS as et, GROUP_STATUS as f, ISSUE_STATUS as g, ISSUE_SECTIONS as h, DECISION_BASES as i, grantCovers as it, TASK_SECTIONS as j, SURVEY_SECTION as k, FINDING_STATUS as l, ID_PATTERNS as m, CLOSED_STATUS as n, GRANT_TARGET_FORMS as nt, DECISION_STATUS as o, grantRepo as ot, GROUP_SUMMARY_SECTION as p, refMainline as q, DECIDERS as r, describeRequest as rt, DEFAULT_CATEGORIES as s, parseGrantTarget as st, CHECKLIST_REF as t, GRANT_FORMS as tt, FORMAT_VERSION as u, MAINLINE_SECTIONS as v, SERVES_REF as w, PRIORITIES as x, MAINLINE_STATUS as y, issueSchema as z };
package/dist/facts.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { g as SurveyLine, l as ID_PATTERNS, m as SLUG, o as FORMAT_VERSION, p as SERVES_REF, r as CHECKLIST_REF, v as Until } from "./index-B32s8PHu.js";
1
+ import { g as SurveyLine, l as ID_PATTERNS, m as SLUG, o as FORMAT_VERSION, p as SERVES_REF, r as CHECKLIST_REF, v as Until } from "./index-Dk4fCI7q.js";
2
2
  //#region src/facts.d.ts
3
3
  export interface CommandSpec {
4
4
  usage: string;
@@ -99,8 +99,8 @@ export declare const COMMAND_SPECS: {
99
99
  readonly needsHub: true;
100
100
  };
101
101
  readonly 'action add': {
102
- readonly usage: 'action add <text> --serves <m/t#c|m#r>[,...] [--before <a>] [--session <session>]';
103
- readonly summary: 'Add an action to the session queue; --serves names checklist items, or criteria while the mainline has no task for them. Prints a reminder when another session active in the last 15 minutes is doing what it serves';
102
+ readonly usage: 'action add <text> --serves <m/t#c|m#r|w#r>[,...] [--before <a>] [--session <session>]';
103
+ readonly summary: 'Add an action to the session queue; --serves names checklist items, or criteria while the mainline has no task for them, or a group\'s criterion (w#r) for work that belongs to the group as a whole. Prints a reminder when another session active in the last 15 minutes is doing what it serves';
104
104
  readonly args: 1;
105
105
  readonly needsHub: true;
106
106
  };
@@ -124,8 +124,8 @@ export declare const COMMAND_SPECS: {
124
124
  readonly needsHub: false;
125
125
  };
126
126
  readonly 'new mainline': {
127
- readonly usage: 'new mainline <slug> --title <title> [--group <w>] [--role plan|impl] [--priority P0|P1|P2|P3]';
128
- readonly summary: 'Create mainline.md with the next id and the section template; write the rest in the file. --group puts it in an existing group, or in one of another registered hub as {hub}:w001; --role plan makes it the mainline that splits the work, coordinates it and makes the final check (without --role it is an impl mainline)';
127
+ readonly usage: 'new mainline <slug> --title <title> [--group <w>] [--priority P0|P1|P2|P3]';
128
+ readonly summary: 'Create mainline.md with the next id and the section template; write the rest in the file. --group puts it in an existing group, or in one of another registered hub as {hub}:w001';
129
129
  readonly args: 1;
130
130
  readonly needsHub: true;
131
131
  };
@@ -161,19 +161,25 @@ export declare const COMMAND_SPECS: {
161
161
  };
162
162
  readonly 'group set': {
163
163
  readonly usage: 'group set <w> [--status open|done] [--priority P0|P1|P2|P3] [--trigger <when>] [--title <title>]';
164
- readonly summary: 'Change a group\'s status, priority, trigger or title; an empty --trigger "" removes it. Relations between groups go in links in the file';
164
+ readonly summary: 'Change a group\'s status, priority, trigger or title; an empty --trigger "" removes it. --status done needs every criterion met or dropped and every mainline and issue of this hub in the group finished. Relations between groups go in links in the file';
165
+ readonly args: 1;
166
+ readonly needsHub: true;
167
+ };
168
+ readonly 'group show': {
169
+ readonly usage: 'group show <w>';
170
+ readonly summary: 'Print a group: goal, criteria, grants, and its members in the order their depends-on links give, each with the sessions whose actions in progress or blocked serve it';
165
171
  readonly args: 1;
166
172
  readonly needsHub: true;
167
173
  };
168
174
  readonly 'group list': {
169
175
  readonly usage: 'group list [--all]';
170
- readonly summary: 'List open groups by priority with their trigger and members, plan mainlines first; members in other hubs read {hub}:{id}, and a registered hub that is not loaded is noted (--all includes done groups)';
176
+ readonly summary: 'List open groups by priority with their trigger and members, mainlines before issues; members in other hubs read {hub}:{id}, and a registered hub that is not loaded is noted (--all includes done groups)';
171
177
  readonly args: 0;
172
178
  readonly needsHub: true;
173
179
  };
174
180
  readonly 'mainline set': {
175
- readonly usage: 'mainline set <m> [--status <status>] [--group <w|none>] [--role plan|impl] [--priority P0|P1|P2|P3]';
176
- readonly summary: 'Change status, group, role or priority; done needs every criterion met and no proposed decision. A planning mainline becomes active by itself when work on it starts, so use --status for paused, done and dropped. --group none leaves the group; {hub}:w001 joins a group of another registered hub';
181
+ readonly usage: 'mainline set <m> [--status <status>] [--group <w|none>] [--priority P0|P1|P2|P3]';
182
+ readonly summary: 'Change status, group or priority; done needs every criterion met and no proposed decision. A planning mainline becomes active by itself when work on it starts, so use --status for paused, done and dropped. --group none leaves the group; {hub}:w001 joins a group of another registered hub';
177
183
  readonly args: 1;
178
184
  readonly needsHub: true;
179
185
  };
@@ -190,25 +196,25 @@ export declare const COMMAND_SPECS: {
190
196
  readonly needsHub: true;
191
197
  };
192
198
  readonly 'criterion add': {
193
- readonly usage: 'criterion add <m> <text> --done-when <text>';
194
- readonly summary: 'Add an open criterion at the end of the mainline\'s criteria with the next r id';
199
+ readonly usage: 'criterion add <m|w> <text> --done-when <text>';
200
+ readonly summary: 'Add an open criterion at the end of the mainline\'s or group\'s criteria with the next r id';
195
201
  readonly args: 2;
196
202
  readonly needsHub: true;
197
203
  };
198
204
  readonly 'criterion check': {
199
- readonly usage: 'criterion check <m#r> --evidence <evidence>';
205
+ readonly usage: 'criterion check <m#r|w#r> --evidence <evidence>';
200
206
  readonly summary: 'Mark a criterion as met';
201
207
  readonly args: 1;
202
208
  readonly needsHub: true;
203
209
  };
204
210
  readonly 'criterion uncheck': {
205
- readonly usage: 'criterion uncheck <m#r>';
211
+ readonly usage: 'criterion uncheck <m#r|w#r>';
206
212
  readonly summary: 'Mark a criterion as not met';
207
213
  readonly args: 1;
208
214
  readonly needsHub: true;
209
215
  };
210
216
  readonly 'criterion set': {
211
- readonly usage: 'criterion set <m#r> [--text <text>] [--done-when <text>]';
217
+ readonly usage: 'criterion set <m#r|w#r> [--text <text>] [--done-when <text>]';
212
218
  readonly summary: 'Rewrite a criterion\'s text or doneWhen; done stays as it is (use criterion check/uncheck)';
213
219
  readonly args: 1;
214
220
  readonly needsHub: true;
@@ -495,9 +501,6 @@ export declare const OPTIONS: {
495
501
  readonly group: {
496
502
  readonly type: 'string';
497
503
  };
498
- readonly role: {
499
- readonly type: 'string';
500
- };
501
504
  readonly priority: {
502
505
  readonly type: 'string';
503
506
  };
@@ -574,6 +577,10 @@ export declare const REFERENCES: readonly [{
574
577
  readonly target: 'criterion';
575
578
  readonly format: 'm{NNN}#r{NNN}';
576
579
  readonly example: 'm001#r001';
580
+ }, {
581
+ readonly target: 'group criterion';
582
+ readonly format: 'w{NNN}#r{NNN}';
583
+ readonly example: 'w001#r001';
577
584
  }, {
578
585
  readonly target: 'decision';
579
586
  readonly format: 'm{NNN}/d{NNN}';
@@ -632,8 +639,10 @@ export declare const LINKS: {
632
639
  readonly rels: readonly ["depends-on", "relates", "split-from"];
633
640
  };
634
641
  /**
635
- * What a mainline's grants authorize: each action with the form of its target. A grant applies only while the
636
- * session's action in progress serves the mainline and the mainline is active or planning. The PreToolUse hook
642
+ * What a mainline's or group's grants authorize: each action with the form of its target. A mainline's grant applies
643
+ * only while the session's action in progress serves the mainline and the mainline is active or planning. A group's
644
+ * grant applies while the group is open and the action serves one of the group's mainlines (of this hub) or the
645
+ * group's own criterion. The PreToolUse hook
637
646
  * allows `publish` and `release` only when the command is written in the fixed form in `forms`; the other
638
647
  * actions are for the executor to read.
639
648
  */
@@ -676,15 +685,6 @@ export declare const CLASSIFICATION: {
676
685
  readonly priorities: readonly ["P0", "P1", "P2", "P3"];
677
686
  readonly defaultPriority: "P2";
678
687
  };
679
- /**
680
- * What a mainline is for: a plan mainline sizes the work, splits it into impl mainlines, coordinates them and makes
681
- * the final check; an impl mainline carries a piece out. Without a role a mainline is `default`. A group needs no plan
682
- * mainline: whether to open one, and how many impl mainlines, follows from how big the work is.
683
- */
684
- export declare const ROLES: {
685
- readonly values: readonly ["plan", "impl"];
686
- readonly default: "impl";
687
- };
688
688
  /** Body sections each document is created with; the task sections in `taskRequired` must be filled while it is open. */
689
689
  export declare const SECTIONS: {
690
690
  readonly mainline: readonly ["概述", "背景與前置", "現況查核", "範圍與不做", "限制"];
@@ -693,7 +693,7 @@ export declare const SECTIONS: {
693
693
  readonly decision: readonly ["背景", "選項", "建議", "決定", "理由"];
694
694
  readonly issue: readonly ["背景", "要做的事", "完成條件"];
695
695
  readonly finding: readonly ["發現", "影響", "做法"];
696
- readonly group: readonly ["說明"];
696
+ readonly group: readonly ["目標", "說明"];
697
697
  };
698
698
  /**
699
699
  * The mainline section that records what was checked before tasks were written, one `- {label}:{text}`
@@ -712,12 +712,12 @@ export interface FieldSpec {
712
712
  }
713
713
  /** Every front matter field of each document and list entry; facts.test keeps it equal to the schema. */
714
714
  export declare const FIELDS: {
715
- readonly mainline: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec];
715
+ readonly mainline: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec];
716
716
  readonly task: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec];
717
717
  readonly decision: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec];
718
718
  readonly issue: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec, FieldSpec, FieldSpec];
719
719
  readonly finding: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec];
720
- readonly group: readonly [...FieldSpec[], FieldSpec];
720
+ readonly group: readonly [...FieldSpec[], FieldSpec, FieldSpec, FieldSpec];
721
721
  readonly criterion: FieldSpec[];
722
722
  readonly checklistItem: readonly [...FieldSpec[], FieldSpec];
723
723
  readonly grant: readonly [FieldSpec, FieldSpec, FieldSpec, FieldSpec];
package/dist/facts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as SURVEY_SECTION, D as SESSION_STATUS, M as TASK_SECTIONS, N as UNTIL_FORMS, O as SLUG, P as WORK_STATUS, S as PRIORITIES, T as SERVES_REF, _ as LINK_RELS, a as DECISION_SECTIONS, b as MAINLINE_STATUS, c as DEFAULT_ROLE, d as FORMAT_VERSION, f as GROUP_SECTIONS, g as ISSUE_STATUS, h as ISSUE_SECTIONS, i as DECISION_BASES, j as TASK_REQUIRED_SECTIONS, k as SURVEY_LINES, l as FINDING_SECTIONS, m as ID_PATTERNS, n as CLOSED_STATUS, nt as GRANT_FORMS, o as DECISION_STATUS, p as GROUP_STATUS, r as DECIDERS, rt as GRANT_TARGET_FORMS, s as DEFAULT_CATEGORIES, t as CHECKLIST_REF, tt as GRANT_ACTIONS, u as FINDING_STATUS, v as MAINLINE_ROLES, x as MERGE_STATES, y as MAINLINE_SECTIONS } from "./dist-ud09dzZo.js";
1
+ import { A as TASK_REQUIRED_SECTIONS, D as SLUG, E as SESSION_STATUS, M as UNTIL_FORMS, N as WORK_STATUS, O as SURVEY_LINES, _ as LINK_RELS, a as DECISION_SECTIONS, b as MERGE_STATES, c as FINDING_SECTIONS, d as GROUP_SECTIONS, et as GRANT_ACTIONS, f as GROUP_STATUS, g as ISSUE_STATUS, h as ISSUE_SECTIONS, i as DECISION_BASES, j as TASK_SECTIONS, k as SURVEY_SECTION, l as FINDING_STATUS, m as ID_PATTERNS, n as CLOSED_STATUS, nt as GRANT_TARGET_FORMS, o as DECISION_STATUS, r as DECIDERS, s as DEFAULT_CATEGORIES, t as CHECKLIST_REF, tt as GRANT_FORMS, u as FORMAT_VERSION, v as MAINLINE_SECTIONS, w as SERVES_REF, x as PRIORITIES, y as MAINLINE_STATUS } 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
  //#region src/facts.ts
4
4
  const COMMAND_SPECS = {
@@ -89,8 +89,8 @@ const COMMAND_SPECS = {
89
89
  needsHub: true
90
90
  },
91
91
  "action add": {
92
- usage: "action add <text> --serves <m/t#c|m#r>[,...] [--before <a>] [--session <session>]",
93
- summary: "Add an action to the session queue; --serves names checklist items, or criteria while the mainline has no task for them. Prints a reminder when another session active in the last 15 minutes is doing what it serves",
92
+ usage: "action add <text> --serves <m/t#c|m#r|w#r>[,...] [--before <a>] [--session <session>]",
93
+ summary: "Add an action to the session queue; --serves names checklist items, or criteria while the mainline has no task for them, or a group's criterion (w#r) for work that belongs to the group as a whole. Prints a reminder when another session active in the last 15 minutes is doing what it serves",
94
94
  args: 1,
95
95
  needsHub: true
96
96
  },
@@ -114,8 +114,8 @@ const COMMAND_SPECS = {
114
114
  needsHub: false
115
115
  },
116
116
  "new mainline": {
117
- usage: "new mainline <slug> --title <title> [--group <w>] [--role plan|impl] [--priority P0|P1|P2|P3]",
118
- summary: "Create mainline.md with the next id and the section template; write the rest in the file. --group puts it in an existing group, or in one of another registered hub as {hub}:w001; --role plan makes it the mainline that splits the work, coordinates it and makes the final check (without --role it is an impl mainline)",
117
+ usage: "new mainline <slug> --title <title> [--group <w>] [--priority P0|P1|P2|P3]",
118
+ summary: "Create mainline.md with the next id and the section template; write the rest in the file. --group puts it in an existing group, or in one of another registered hub as {hub}:w001",
119
119
  args: 1,
120
120
  needsHub: true
121
121
  },
@@ -151,19 +151,25 @@ const COMMAND_SPECS = {
151
151
  },
152
152
  "group set": {
153
153
  usage: "group set <w> [--status open|done] [--priority P0|P1|P2|P3] [--trigger <when>] [--title <title>]",
154
- summary: "Change a group's status, priority, trigger or title; an empty --trigger \"\" removes it. Relations between groups go in links in the file",
154
+ summary: "Change a group's status, priority, trigger or title; an empty --trigger \"\" removes it. --status done needs every criterion met or dropped and every mainline and issue of this hub in the group finished. Relations between groups go in links in the file",
155
+ args: 1,
156
+ needsHub: true
157
+ },
158
+ "group show": {
159
+ usage: "group show <w>",
160
+ summary: "Print a group: goal, criteria, grants, and its members in the order their depends-on links give, each with the sessions whose actions in progress or blocked serve it",
155
161
  args: 1,
156
162
  needsHub: true
157
163
  },
158
164
  "group list": {
159
165
  usage: "group list [--all]",
160
- summary: "List open groups by priority with their trigger and members, plan mainlines first; members in other hubs read {hub}:{id}, and a registered hub that is not loaded is noted (--all includes done groups)",
166
+ summary: "List open groups by priority with their trigger and members, mainlines before issues; members in other hubs read {hub}:{id}, and a registered hub that is not loaded is noted (--all includes done groups)",
161
167
  args: 0,
162
168
  needsHub: true
163
169
  },
164
170
  "mainline set": {
165
- usage: "mainline set <m> [--status <status>] [--group <w|none>] [--role plan|impl] [--priority P0|P1|P2|P3]",
166
- summary: "Change status, group, role or priority; done needs every criterion met and no proposed decision. A planning mainline becomes active by itself when work on it starts, so use --status for paused, done and dropped. --group none leaves the group; {hub}:w001 joins a group of another registered hub",
171
+ usage: "mainline set <m> [--status <status>] [--group <w|none>] [--priority P0|P1|P2|P3]",
172
+ summary: "Change status, group or priority; done needs every criterion met and no proposed decision. A planning mainline becomes active by itself when work on it starts, so use --status for paused, done and dropped. --group none leaves the group; {hub}:w001 joins a group of another registered hub",
167
173
  args: 1,
168
174
  needsHub: true
169
175
  },
@@ -180,25 +186,25 @@ const COMMAND_SPECS = {
180
186
  needsHub: true
181
187
  },
182
188
  "criterion add": {
183
- usage: "criterion add <m> <text> --done-when <text>",
184
- summary: "Add an open criterion at the end of the mainline's criteria with the next r id",
189
+ usage: "criterion add <m|w> <text> --done-when <text>",
190
+ summary: "Add an open criterion at the end of the mainline's or group's criteria with the next r id",
185
191
  args: 2,
186
192
  needsHub: true
187
193
  },
188
194
  "criterion check": {
189
- usage: "criterion check <m#r> --evidence <evidence>",
195
+ usage: "criterion check <m#r|w#r> --evidence <evidence>",
190
196
  summary: "Mark a criterion as met",
191
197
  args: 1,
192
198
  needsHub: true
193
199
  },
194
200
  "criterion uncheck": {
195
- usage: "criterion uncheck <m#r>",
201
+ usage: "criterion uncheck <m#r|w#r>",
196
202
  summary: "Mark a criterion as not met",
197
203
  args: 1,
198
204
  needsHub: true
199
205
  },
200
206
  "criterion set": {
201
- usage: "criterion set <m#r> [--text <text>] [--done-when <text>]",
207
+ usage: "criterion set <m#r|w#r> [--text <text>] [--done-when <text>]",
202
208
  summary: "Rewrite a criterion's text or doneWhen; done stays as it is (use criterion check/uncheck)",
203
209
  args: 1,
204
210
  needsHub: true
@@ -418,7 +424,6 @@ const OPTIONS = {
418
424
  origin: { type: "string" },
419
425
  labels: { type: "string" },
420
426
  group: { type: "string" },
421
- role: { type: "string" },
422
427
  priority: { type: "string" },
423
428
  trigger: { type: "string" },
424
429
  target: { type: "string" },
@@ -486,6 +491,11 @@ const REFERENCES = [
486
491
  format: "m{NNN}#r{NNN}",
487
492
  example: "m001#r001"
488
493
  },
494
+ {
495
+ target: "group criterion",
496
+ format: "w{NNN}#r{NNN}",
497
+ example: "w001#r001"
498
+ },
489
499
  {
490
500
  target: "decision",
491
501
  format: "m{NNN}/d{NNN}",
@@ -544,8 +554,10 @@ const UNTIL = UNTIL_FORMS;
544
554
  /** Relation types a document's links take; readers derive the reverse direction. */
545
555
  const LINKS = { rels: LINK_RELS };
546
556
  /**
547
- * What a mainline's grants authorize: each action with the form of its target. A grant applies only while the
548
- * session's action in progress serves the mainline and the mainline is active or planning. The PreToolUse hook
557
+ * What a mainline's or group's grants authorize: each action with the form of its target. A mainline's grant applies
558
+ * only while the session's action in progress serves the mainline and the mainline is active or planning. A group's
559
+ * grant applies while the group is open and the action serves one of the group's mainlines (of this hub) or the
560
+ * group's own criterion. The PreToolUse hook
549
561
  * allows `publish` and `release` only when the command is written in the fixed form in `forms`; the other
550
562
  * actions are for the executor to read.
551
563
  */
@@ -575,15 +587,6 @@ const CLASSIFICATION = {
575
587
  priorities: PRIORITIES,
576
588
  defaultPriority: "P2"
577
589
  };
578
- /**
579
- * What a mainline is for: a plan mainline sizes the work, splits it into impl mainlines, coordinates them and makes
580
- * the final check; an impl mainline carries a piece out. Without a role a mainline is `default`. A group needs no plan
581
- * mainline: whether to open one, and how many impl mainlines, follows from how big the work is.
582
- */
583
- const ROLES = {
584
- values: MAINLINE_ROLES,
585
- default: DEFAULT_ROLE
586
- };
587
590
  /** Body sections each document is created with; the task sections in `taskRequired` must be filled while it is open. */
588
591
  const SECTIONS = {
589
592
  mainline: MAINLINE_SECTIONS,
@@ -655,7 +658,6 @@ const FIELDS = {
655
658
  mainline: [
656
659
  ...shared(...EVERY),
657
660
  field("group", false, "所屬的組 w{NNN},或其他 hub 的組 {hub}:w{NNN},一條主脈絡最多一組;組和依賴無關"),
658
- field("role", false, "plan 是拆分顆粒、整合調度與最終確認的規劃型,impl 是執行的實作型;沒填視為 impl"),
659
661
  field("due", false, "預計完成的日期"),
660
662
  field("archivedAt", false, "封存的日期,和狀態分開"),
661
663
  field("criteria", true, "解決條件清單,每條的欄位見 criterion"),
@@ -702,7 +704,12 @@ const FIELDS = {
702
704
  field("reviewAfter", false, "到這天要重新確認它還成立"),
703
705
  field("archivedAt", false, "封存的日期,和狀態分開")
704
706
  ],
705
- group: [...shared(...EVERY), field("trigger", false, "什麼時機做這組的事,一句話,例如「量測修正時」")],
707
+ group: [
708
+ ...shared(...EVERY),
709
+ field("trigger", false, "什麼時機做這組的事,一句話,例如「量測修正時」"),
710
+ field("criteria", false, "這組的解決條件清單,每條的欄位見 criterion,參照寫 w{NNN}#r{NNN};組改成 done 前要全部已勾或已放棄"),
711
+ field("grants", false, "預先授權清單,每條的欄位見 grant,參照寫 w{NNN}#g{NNN};組是 open 時,對成員主脈絡的行動和服務這組解決條件的行動生效")
712
+ ],
706
713
  criterion: LIST_ITEM,
707
714
  checklistItem: [...LIST_ITEM, field("serves", false, "這個項目推進的解決條件,r{NNN} 清單")],
708
715
  grant: [
@@ -715,7 +722,7 @@ const FIELDS = {
715
722
  field("id", true, "會話內不重複的編號 a{NNN},由 action add 配發"),
716
723
  field("do", true, "要做的事,一句話"),
717
724
  field("status", true, "狀態值見 STATUSES,用 action set 改"),
718
- field("serves", true, "推進的 checklist 項目(m{NNN}/t{NNN}#c{NNN})或解決條件(m{NNN}#r{NNN})參照清單,可以是空的;主脈絡還沒拆任務時指向解決條件"),
725
+ field("serves", true, "推進的 checklist 項目(m{NNN}/t{NNN}#c{NNN})或解決條件(主脈絡 m{NNN}#r{NNN}、組 w{NNN}#r{NNN})參照清單,可以是空的;主脈絡還沒拆任務時指向解決條件"),
719
726
  field("note", false, "一句備註"),
720
727
  field("blockedBy", false, "卡住時的原因 reason、等待對象 waitingFor 與程式可判斷的條件 until,blocked 時必填,其他狀態不得有;等待對象整串是其他會話的行動(例如 claude-code-1a2b3c4d#a003)時,對方的簡報會列出有人在等它;條件格式見 UNTIL"),
721
728
  field("startedAt", false, "轉為 doing 時由 CLI 寫入"),
@@ -728,4 +735,4 @@ const FIELDS = {
728
735
  ]
729
736
  };
730
737
  //#endregion
731
- export { CHECKLIST_REF, CLASSIFICATION, CLOSED_STATUSES, COMMAND_SPECS, FIELDS, FORMAT_VERSION, GRANTS, ID_PATTERNS, LAYOUT, LINKS, OPTIONS, REFERENCES, RETRO_FORMATS, ROLES, SECTIONS, SERVES_REF, SLUG, STATUSES, SURVEY, UNTIL };
738
+ export { CHECKLIST_REF, CLASSIFICATION, CLOSED_STATUSES, COMMAND_SPECS, FIELDS, FORMAT_VERSION, GRANTS, ID_PATTERNS, LAYOUT, LINKS, OPTIONS, REFERENCES, RETRO_FORMATS, SECTIONS, SERVES_REF, SLUG, STATUSES, SURVEY, UNTIL };
@@ -1,4 +1,4 @@
1
- import "./index-B32s8PHu.js";
1
+ import "./index-Dk4fCI7q.js";
2
2
  //#region ../schema/dist/grants.d.ts
3
3
  /** An operation about to run, resolved to what a grant is written against. */
4
4
  type GrantRequest = {
@@ -1,4 +1,4 @@
1
- import { nt as GRANT_FORMS } from "./dist-ud09dzZo.js";
1
+ import { tt as GRANT_FORMS } from "./dist-zSabglPq.js";
2
2
  import { closeSync, constants, fstatSync, openSync, readFileSync, realpathSync } from "node:fs";
3
3
  import { isAbsolute, join, relative, resolve } from "node:path";
4
4
  import { spawnSync } from "node:child_process";