mainflow 0.44.0-alpha.2 → 0.44.0-alpha.3
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 +35 -6
- package/dist/facts.d.ts +2 -2
- package/dist/facts.js +2 -2
- package/dist/grant-check.js +2 -2
- package/dist/hooks.js +17 -8
- package/dist/{host-C74j2Qox.js → host-CsZY5trM.js} +107 -5
- package/dist/host.js +1 -1
- package/dist/launch.js +2 -2
- package/dist/{operation-CUeOFEaf.js → operation-MKNwQkAY.js} +1 -1
- package/dist/{ui-qqVCewFz.js → ui-Bv29R0WG.js} +2 -3
- package/package.json +1 -1
- package/dist/progress-1BfPg2zN.js +0 -10
package/dist/cli.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { P as UNTIL_FORMS, X as parseUntil, Y as parseRef, Z as refExample, ct as stampMs, it as untilProblem, n as CLOSED_STATUS } from "./dist-CXrUfRQp.js";
|
|
3
|
-
import { $t as
|
|
4
|
-
import { t as
|
|
5
|
-
import { A as hubName, C as readRemote, D as Unreachable, E as ServerError, F as syncPaths, M as SETTINGS_FILE, O as ENV, T as ServerApi, _ as DaemonUnavailable, a as versionGate, b as readDaemon, c as oversizedFiles, d as planAnnounce, f as planFetch, g as DaemonRunning, h as startDaemon, i as requireWritableVersion, j as syncSettings, k as earlierToken, l as fetchDenial, m as toolCallOf, n as hubWriter, o as queuedCount, p as planFlush, r as writtenLines, s as remoteMode, t as CONFIRM_MS, u as hookAnswer, v as callDaemon, w as HubRewritingError, x as silentHint, y as probeDaemon } from "./operation-CUeOFEaf.js";
|
|
2
|
+
import { D as SESSION_ID, P as UNTIL_FORMS, X as parseUntil, Y as parseRef, Z as refExample, ct as stampMs, it as untilProblem, n as CLOSED_STATUS } from "./dist-CXrUfRQp.js";
|
|
3
|
+
import { $ as applyOperation, $t as dataFile, A as unhandledNotices, Bt as hubHoldingFile, C as duplicateClaimLines, Ft as MAINLINE_FILE, Gt as registerHub, Ht as listHubs, Jt as resolveHub, Kt as registeredName, Lt as TASK_FILE, M as readSession, Rt as requireSlug, S as untilState, St as MAX_FILE_BYTES, Ut as notRegisteredMessage, Wt as readRegistry, Xt as userDataDir, Yt as unregisterHub, Zt as nodeStorage, _ as receiverFromEnv, an as DATA_DIR, d as groupPlan, et as checkHubName, f as listProgress, ft as remoteMembers, g as retroReportFromReceiver, h as retroReport, ht as nowMinute, i as hostName, it as loadHub, j as loadSessions, m as migrateHub, nn as realPath, on as WriteError, ot as sectionText, p as migrateHubData, pt as unavailableHubs, qt as registryFile, tt as HubError, u as sessionView, ut as memberOfGroup, v as RETRY_RULES, w as sessionBriefing, x as initHub, xt as MAX_CHANGE_PAGE, yt as BLOB_HASH, zt as hubAtRoot } from "./host-CsZY5trM.js";
|
|
4
|
+
import { A as hubName, C as readRemote, D as Unreachable, E as ServerError, F as syncPaths, M as SETTINGS_FILE, O as ENV, T as ServerApi, _ as DaemonUnavailable, a as versionGate, b as readDaemon, c as oversizedFiles, d as planAnnounce, f as planFetch, g as DaemonRunning, h as startDaemon, i as requireWritableVersion, j as syncSettings, k as earlierToken, l as fetchDenial, m as toolCallOf, n as hubWriter, o as queuedCount, p as planFlush, r as writtenLines, s as remoteMode, t as CONFIRM_MS, u as hookAnswer, v as callDaemon, w as HubRewritingError, x as silentHint, y as probeDaemon } from "./operation-MKNwQkAY.js";
|
|
6
5
|
import { COMMAND_SPECS, OPTIONS } from "./facts.js";
|
|
7
6
|
import { t as CLI_VERSION } from "./version-Dvv4jwF1.js";
|
|
8
|
-
import { hookFallback, parsePayload, runHook } from "./hooks.js";
|
|
7
|
+
import { claudeCodeSessionId, hookFallback, openLink, parsePayload, runHook } from "./hooks.js";
|
|
9
8
|
import { runGrantCheck } from "./grant-check.js";
|
|
10
9
|
import { exitCodeFor, launchUi, networkProbe, readUiRecord, startUiInBackground, watchHubGone } from "./launch.js";
|
|
11
10
|
import { randomBytes } from "node:crypto";
|
|
@@ -13,6 +12,35 @@ import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync }
|
|
|
13
12
|
import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
14
13
|
import { fileURLToPath } from "node:url";
|
|
15
14
|
import { parseArgs } from "node:util";
|
|
15
|
+
//#region src/session-json.ts
|
|
16
|
+
/** The mainflow session a host's session id stands for: the id itself when such a session exists, else Claude Code's. */
|
|
17
|
+
function sessionIdOf(dirs, raw) {
|
|
18
|
+
return SESSION_ID.test(raw) && readSession(dirs, raw) ? raw : claudeCodeSessionId(raw);
|
|
19
|
+
}
|
|
20
|
+
/** The sync client's state; null when the hub is not synced, that is no client runs and writes go to the files. */
|
|
21
|
+
async function syncState(dirs) {
|
|
22
|
+
const probe = await probeDaemon(dirs);
|
|
23
|
+
if (!probe && !remoteMode(dirs)) return null;
|
|
24
|
+
const running = probe?.state === "running";
|
|
25
|
+
return {
|
|
26
|
+
running,
|
|
27
|
+
caughtUp: running && probe.status?.caughtUp === true,
|
|
28
|
+
queued: queuedCount(dirs),
|
|
29
|
+
notices: unhandledNotices(dirs).length
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** What `session show --json` prints for a mainflow or host session id; a missing session gives `session: null`. */
|
|
33
|
+
async function sessionJson(dirs, raw) {
|
|
34
|
+
const hub = loadHub(dirs, { remotes: false });
|
|
35
|
+
return sessionView({
|
|
36
|
+
hub,
|
|
37
|
+
session: readSession(dirs, sessionIdOf(dirs, raw)),
|
|
38
|
+
url: `https://${hostName(hub.config.hub)}`,
|
|
39
|
+
link: openLink(hub.config.hub),
|
|
40
|
+
sync: await syncState(dirs)
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
16
44
|
//#region src/migration.ts
|
|
17
45
|
/**
|
|
18
46
|
* What `mainflow migrate` prints of a migration's report, the same whether the hub's files are here or on the sync
|
|
@@ -1604,8 +1632,9 @@ const RUNS = {
|
|
|
1604
1632
|
});
|
|
1605
1633
|
return 0;
|
|
1606
1634
|
},
|
|
1607
|
-
"session show": ({ dirs, args, opts }) => {
|
|
1635
|
+
"session show": async ({ dirs, args, opts }) => {
|
|
1608
1636
|
const id = sessionOf(opts, args[0]);
|
|
1637
|
+
if (opts.json) return done(JSON.stringify(await sessionJson(dirs, id)));
|
|
1609
1638
|
const session = readSession(dirs, id);
|
|
1610
1639
|
if (!session) throw new WriteError(`session ${id} not found; start one with "mainflow session start"`);
|
|
1611
1640
|
return done(sessionBriefing(dirs, session, { cli: CLI }));
|
package/dist/facts.d.ts
CHANGED
|
@@ -97,8 +97,8 @@ export declare const COMMAND_SPECS: {
|
|
|
97
97
|
readonly needsHub: true;
|
|
98
98
|
};
|
|
99
99
|
readonly 'session show': {
|
|
100
|
-
readonly usage: 'session show [session]';
|
|
101
|
-
readonly summary: 'Print the briefing a hook would give this session';
|
|
100
|
+
readonly usage: 'session show [session] [--json]';
|
|
101
|
+
readonly summary: 'Print the briefing a hook would give this session. --json prints one object for a host to read: {"hub","session","focus","tasks","mainlines","sync"}; session is null, and the exit code 0, when the session does not exist. The session is a mainflow session id or the host\'s own (a Claude Code UUID)';
|
|
102
102
|
readonly args: 0;
|
|
103
103
|
readonly optionalArgs: 1;
|
|
104
104
|
readonly needsHub: true;
|
package/dist/facts.js
CHANGED
|
@@ -87,8 +87,8 @@ const COMMAND_SPECS = {
|
|
|
87
87
|
needsHub: true
|
|
88
88
|
},
|
|
89
89
|
"session show": {
|
|
90
|
-
usage: "session show [session]",
|
|
91
|
-
summary: "Print the briefing a hook would give this session",
|
|
90
|
+
usage: "session show [session] [--json]",
|
|
91
|
+
summary: "Print the briefing a hook would give this session. --json prints one object for a host to read: {\"hub\",\"session\",\"focus\",\"tasks\",\"mainlines\",\"sync\"}; session is null, and the exit code 0, when the session does not exist. The session is a mainflow session id or the host's own (a Claude Code UUID)",
|
|
92
92
|
args: 0,
|
|
93
93
|
optionalArgs: 1,
|
|
94
94
|
needsHub: true
|
package/dist/grant-check.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { D as SESSION_ID, I as configSchema, ft as describeRequest, gt as hasControl, tt as repoPaths } from "./dist-CXrUfRQp.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as hubWriter, r as writtenLines } from "./operation-
|
|
2
|
+
import { F as matchGrants, Jt as resolveHub, M as readSession, Mt as hubFormatVersion, P as grantScope, Qt as currentBranch, Zt as nodeStorage, _t as readYaml, en as gitCheckout, jt as formatMismatch, nn as realPath } from "./host-CsZY5trM.js";
|
|
3
|
+
import { n as hubWriter, r as writtenLines } from "./operation-MKNwQkAY.js";
|
|
4
4
|
import { OWNER_REPO, githubOrigin, quote, readManifest, resolveFixed, scanCommand, scopedCwd } from "./grant-commands.js";
|
|
5
5
|
import { claudeCodeSessionId, parsePayload } from "./hooks.js";
|
|
6
6
|
import { readFileSync } from "node:fs";
|
package/dist/hooks.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { I as configSchema, Y as parseRef, ft as describeRequest, rt as taskSchema, tt as repoPaths } from "./dist-CXrUfRQp.js";
|
|
2
|
-
import { $ as
|
|
3
|
-
import { n as hubWriter, r as writtenLines } from "./operation-
|
|
2
|
+
import { $t as dataFile, Bt as hubHoldingFile, F as matchGrants, I as decorateReply, It as SESSIONS_DIR, Jt as resolveHub, L as endsWithMarker, M as readSession, Mt as hubFormatVersion, P as grantScope, Qt as currentBranch, R as headerLine, T as turnReminder, Ut as notRegisteredMessage, Vt as inRepositoryHubAt, Zt as nodeStorage, _t as readYaml, an as DATA_DIR, at as loadMainlines, gt as readFrontMatter, i as hostName, it as loadHub, j as loadSessions, jt as formatMismatch, mt as taskFile, nn as realPath, nt as isOpenMainline, rn as worktreesOf, tn as hubPath, tt as HubError, w as sessionBriefing, z as mayDecorate } from "./host-CsZY5trM.js";
|
|
3
|
+
import { n as hubWriter, r as writtenLines } from "./operation-MKNwQkAY.js";
|
|
4
4
|
import { SCENARIO_LINES, SCENARIO_SKIP_KINDS } from "./facts.js";
|
|
5
5
|
import { resolveFixed, scanCommand, scopedCwd } from "./grant-commands.js";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
@@ -102,13 +102,17 @@ const settleOnEnd = async (_root, { payload, write }) => {
|
|
|
102
102
|
};
|
|
103
103
|
/** How a hub's interface is linked from a reply: through its /open route, which shows the address in the app. */
|
|
104
104
|
const openLink = (hub) => (path) => `https://${hostName(hub)}/open${path}`;
|
|
105
|
+
/** Whether a host's display mod is loaded, which it says by setting MAINFLOW_DISPLAY_MOD; it then shows the current action itself. */
|
|
106
|
+
const displayModOn = (env = process.env) => !!env.MAINFLOW_DISPLAY_MOD;
|
|
105
107
|
/**
|
|
106
108
|
* MessageDisplay: link the references in the lines about to be shown and expand the trailing header line into
|
|
107
109
|
* the mainline › task › action its ids name, titles included, whatever state that action is in now. Display
|
|
108
110
|
* only, so the model keeps reading what it wrote. Text with nothing to change
|
|
109
|
-
* returns before the hub is loaded, because Claude Code holds every batch until the hook answers.
|
|
111
|
+
* returns before the hub is loaded, because Claude Code holds every batch until the hook answers. With a display
|
|
112
|
+
* mod loaded it returns null at once.
|
|
110
113
|
*/
|
|
111
|
-
const displayReply = (dirs, { payload }) => {
|
|
114
|
+
const displayReply = (dirs, { payload, env }) => {
|
|
115
|
+
if (displayModOn(env)) return null;
|
|
112
116
|
const text = payload.delta;
|
|
113
117
|
if (!text || !mayDecorate(text)) return null;
|
|
114
118
|
const hub = loadHub(dirs, { remotes: false });
|
|
@@ -183,18 +187,22 @@ function turnTouchedMainflow(transcript, cli, env) {
|
|
|
183
187
|
* an action first when the queue is empty, the reply talks about an open mainline and the turn ran a mainflow
|
|
184
188
|
* command or wrote a file of the hub, since the header only names the session's own action in progress. A reply
|
|
185
189
|
* that only mentions a mainline, in a draft or a question, asks for nothing. Null when there is nothing to ask for.
|
|
190
|
+
* With a display mod loaded the mod shows the current action, so no header is asked for, but an empty queue
|
|
191
|
+
* still is: the action is what grants and the hub's tracking hang on.
|
|
186
192
|
*/
|
|
187
193
|
function missingHeaderRequest(dirs, { payload, cli, env }) {
|
|
188
194
|
if (!payload.session_id || payload.stop_hook_active) return null;
|
|
195
|
+
const displayMod = displayModOn(env);
|
|
189
196
|
const message = payload.last_assistant_message ?? "";
|
|
190
|
-
if (endsWithMarker(message)) return null;
|
|
197
|
+
if (!displayMod && endsWithMarker(message)) return null;
|
|
191
198
|
const session = readSession(dirs, claudeCodeSessionId(payload.session_id));
|
|
192
199
|
const header = headerLine(session);
|
|
193
|
-
if (header) return `[mainflow] 這一輪最後一則回覆的最後一行不是標頭。請只回一則內容為「${header}」的訊息,不加其他文字。`;
|
|
200
|
+
if (header) return displayMod ? null : `[mainflow] 這一輪最後一則回覆的最後一行不是標頭。請只回一則內容為「${header}」的訊息,不加其他文字。`;
|
|
194
201
|
if (session && session.actions.length > 0) return null;
|
|
195
202
|
const mainlines = openMainlinesIn(dirs, message);
|
|
196
203
|
if (mainlines.length === 0 || !turnTouchedMainflow(payload.transcript_path, cli, env)) return null;
|
|
197
|
-
|
|
204
|
+
const list = `先用 ${cli} action add "<做法>" --serves <m/t#c>(還沒拆任務時用解決條件 <m#r>)列出行動並用 ${cli} action set <a編號> --status doing 標為進行中,或用 ${cli} session handoff <會話> 接手上一場沒做完的行動`;
|
|
205
|
+
return displayMod ? `[mainflow] 這一輪的回覆提到 ${mainlines.join("、")},也執行了 mainflow 指令或寫入 hub 的資料目錄,但這場會話沒有行動。這一輪若在推進它,${list}。只是提到、沒有推進時,不必處理。` : `[mainflow] 這一輪的回覆提到 ${mainlines.join("、")},也執行了 mainflow 指令或寫入 hub 的資料目錄,但這場會話沒有行動,所以回覆結尾沒有標頭。這一輪若在推進它,${list};再只回一則內容為「▸ <m/t> · <a編號>」的訊息,不加其他文字。只是提到、沒有推進時,不必處理。`;
|
|
198
206
|
}
|
|
199
207
|
/**
|
|
200
208
|
* Stop: ask for what the turn's header needs, then settle the session. Only the model knows which message closes a
|
|
@@ -231,12 +239,13 @@ const CLAUDE_CODE_EVENTS = {
|
|
|
231
239
|
envNote: envFile ? "已設定環境變數 MAINFLOW_SESSION,指令不必再帶 --session" : `執行指令時帶 --session ${id}`
|
|
232
240
|
});
|
|
233
241
|
},
|
|
234
|
-
"user-prompt-submit": async (dirs, { payload, cli, write }) => {
|
|
242
|
+
"user-prompt-submit": async (dirs, { payload, cli, write, env }) => {
|
|
235
243
|
if (!payload.session_id) return null;
|
|
236
244
|
const session = await recordSession(write, dirs, payload, claudeCodeSessionId(payload.session_id), false);
|
|
237
245
|
const saved = [];
|
|
238
246
|
const text = turnReminder(dirs, session, {
|
|
239
247
|
cli,
|
|
248
|
+
displayMod: displayModOn(env),
|
|
240
249
|
saveDigest: (digest) => saved.push(write("session.reminder", {
|
|
241
250
|
id: session.id,
|
|
242
251
|
digest
|
|
@@ -4435,6 +4435,17 @@ function pathOf(ref, target) {
|
|
|
4435
4435
|
}
|
|
4436
4436
|
}
|
|
4437
4437
|
const sessionPath = (id) => `/sessions/${id}`;
|
|
4438
|
+
/** Where a mainline's file shows on the hub's interface, under the mainline's own address. */
|
|
4439
|
+
const mainlineFilePath = (mainline, file) => `/mainlines/${mainline}/files/${file}`;
|
|
4440
|
+
/** The interface address of every reference the hub has a page or panel for, keyed by the reference. */
|
|
4441
|
+
function refPaths(hub) {
|
|
4442
|
+
const paths = {};
|
|
4443
|
+
for (const [ref, target] of refIndex(hub)) {
|
|
4444
|
+
const path = pathOf(ref, target);
|
|
4445
|
+
if (path) paths[ref] = path;
|
|
4446
|
+
}
|
|
4447
|
+
return paths;
|
|
4448
|
+
}
|
|
4438
4449
|
/** Fenced blocks, inline code, markdown links and bare URLs: text inside them is left as written. */
|
|
4439
4450
|
const PROTECTED = /(```[\s\S]*?(?:```|$)|`[^`\n]*`|\[[^\]\n]*\]\([^)\n]*\)|https?:\/\/\S+)/;
|
|
4440
4451
|
/** A file under a mainline directory, or a reference to a mainline, task, decision, issue, finding or group. */
|
|
@@ -4443,7 +4454,7 @@ const MENTION = /\.mainflow\/(?:[a-z0-9-]+\/)?mainlines\/(m\d{3})-[\w-]+\/([^\s`
|
|
|
4443
4454
|
function linkMentions(text, context) {
|
|
4444
4455
|
const index = refIndex(context.hub);
|
|
4445
4456
|
return text.split(PROTECTED).map((part, i) => i % 2 === 1 ? part : part.replace(MENTION, (all, m, file, ref) => {
|
|
4446
|
-
if (m && file) return index.has(m) ? `[${m}/${file}](${context.link(
|
|
4457
|
+
if (m && file) return index.has(m) ? `[${m}/${file}](${context.link(mainlineFilePath(m, file))})` : all;
|
|
4447
4458
|
const target = ref ? index.get(ref) : void 0;
|
|
4448
4459
|
const path = ref && target ? pathOf(ref, target) : null;
|
|
4449
4460
|
return path ? `[${ref}](${context.link(path)})` : all;
|
|
@@ -5145,9 +5156,10 @@ function sessionBriefing(dirs, session, options) {
|
|
|
5145
5156
|
* The reminder for every user turn; null when there is nothing to say, or when it would be the same text as the
|
|
5146
5157
|
* reminder the model was last given. Records a digest of the whole text in the session file, only when it changes;
|
|
5147
5158
|
* `saveDigest` records it instead of writing the file here, as a host hook in remote mode sends it to the sync server.
|
|
5159
|
+
* `displayMod` leaves out the sentence that asks for the header line, for a host whose mod shows the current action.
|
|
5148
5160
|
*/
|
|
5149
5161
|
function turnReminder(dirs, session, options) {
|
|
5150
|
-
const text = reminderText(dirs, session, options.cli);
|
|
5162
|
+
const text = reminderText(dirs, session, options.cli, options.displayMod === true);
|
|
5151
5163
|
if (text === null) return null;
|
|
5152
5164
|
const digest = contentHash(text);
|
|
5153
5165
|
if (session.reminderDigest === digest) return null;
|
|
@@ -5157,13 +5169,13 @@ function turnReminder(dirs, session, options) {
|
|
|
5157
5169
|
} catch {}
|
|
5158
5170
|
return text;
|
|
5159
5171
|
}
|
|
5160
|
-
function reminderText(dirs, session, cli) {
|
|
5172
|
+
function reminderText(dirs, session, cli, displayMod) {
|
|
5161
5173
|
if (session.actions.length === 0) return openMainlines(dirs).length > 0 ? `[mainflow] ${session.id} 還沒有行動。這一輪要推進主脈絡時,先用 ${cli} action add 列出行動並標為 doing,或用 ${cli} session handoff <會話> 接手上一場沒做完的行動,再開始做。回覆結尾的標頭只看這場會話進行中的行動。` : null;
|
|
5162
5174
|
const doing = current(session);
|
|
5163
5175
|
const open = session.actions.filter(isOpen);
|
|
5164
5176
|
const blocked = session.actions.filter((a) => a.status === "blocked");
|
|
5165
5177
|
const head = doing ? `[mainflow] 目前行動 ${doing.id} ${doing.do},服務 ${doing.serves.join("、") || "(未指定)"}。這一輪的工作若不屬於它,先調整佇列再做。` : open.length > 0 ? `[mainflow] ${session.id} 目前沒有進行中的行動。` : blocked.length > 0 ? `[mainflow] ${session.id} 的行動在等外部條件:${blocked.map(waitingLine).join(";")}。有條件(until)的可以在背景執行 ${cli} wait <a編號> 等它成立。條件出現後用 ${cli} action set <a編號> --status doing 繼續;要先做別的事,用 ${cli} action add 列出行動。` : `[mainflow] ${session.id} 的行動都已結束。繼續工作前先用 ${cli} action add 列出下一個行動。`;
|
|
5166
|
-
const header = headerLine(session);
|
|
5178
|
+
const header = displayMod ? null : headerLine(session);
|
|
5167
5179
|
const marker = header ? [`- 這一輪最後一則回覆的最後一行寫「${header}」,回覆範例等其他內容都放在它前面。有顯示 hook 時,它會換成標題與連結。`] : [];
|
|
5168
5180
|
const grants = grantLines(dirs, session);
|
|
5169
5181
|
const granted = grants.length > 0 ? ["- 目前行動服務的主脈絡與所屬的組預先授權了這些動作:", ...grants.map((g) => ` ${g}`)] : [];
|
|
@@ -9330,6 +9342,15 @@ function copyData(source, target) {
|
|
|
9330
9342
|
return target;
|
|
9331
9343
|
}
|
|
9332
9344
|
//#endregion
|
|
9345
|
+
//#region ../core/dist/progress.js
|
|
9346
|
+
function listProgress(items) {
|
|
9347
|
+
const counted = items.filter((item) => !item.dropped);
|
|
9348
|
+
return {
|
|
9349
|
+
done: counted.filter((item) => item.done).length,
|
|
9350
|
+
total: counted.length
|
|
9351
|
+
};
|
|
9352
|
+
}
|
|
9353
|
+
//#endregion
|
|
9333
9354
|
//#region ../core/dist/group-plan.js
|
|
9334
9355
|
/** Sessions that can still hold work: not archived, and active or paused. */
|
|
9335
9356
|
const live = (s) => !s.archivedAt && (s.status === "active" || s.status === "paused");
|
|
@@ -9401,6 +9422,87 @@ function groupPlan(hub, sessions, groupId) {
|
|
|
9401
9422
|
};
|
|
9402
9423
|
}
|
|
9403
9424
|
//#endregion
|
|
9425
|
+
//#region ../core/dist/session-view.js
|
|
9426
|
+
const unfinished = (a) => a.status === "todo" || a.status === "doing" || a.status === "blocked";
|
|
9427
|
+
/** The mainline and task a served reference points into; criteria of a group name neither. */
|
|
9428
|
+
function targetOf(ref) {
|
|
9429
|
+
const parsed = parseRef(ref);
|
|
9430
|
+
if (parsed?.kind === "checklistItem") return {
|
|
9431
|
+
mainline: parsed.mainline,
|
|
9432
|
+
task: parsed.task
|
|
9433
|
+
};
|
|
9434
|
+
if (parsed?.kind === "criterion") return { mainline: parsed.mainline };
|
|
9435
|
+
return null;
|
|
9436
|
+
}
|
|
9437
|
+
const taskProgress = (m) => {
|
|
9438
|
+
const parts = m.tasks.map((t) => listProgress(t.checklist));
|
|
9439
|
+
return {
|
|
9440
|
+
done: parts.reduce((n, p) => n + p.done, 0),
|
|
9441
|
+
total: parts.reduce((n, p) => n + p.total, 0)
|
|
9442
|
+
};
|
|
9443
|
+
};
|
|
9444
|
+
function sessionView({ hub, session, url, link, sync }) {
|
|
9445
|
+
const actions = session?.actions ?? [];
|
|
9446
|
+
const lead = actions.find((a) => a.status === "doing") ?? actions.find(unfinished);
|
|
9447
|
+
const doing = actions.find((a) => a.status === "doing");
|
|
9448
|
+
const focusTarget = lead?.serves.map(targetOf).find((t) => t !== null) ?? null;
|
|
9449
|
+
const focusMainline = focusTarget ? hub.mainlines.find((m) => m.id === focusTarget.mainline) : void 0;
|
|
9450
|
+
const serving = new Set((doing?.serves ?? []).flatMap((s) => targetOf(s) ?? []).filter((t) => t.task).map((t) => `${t.mainline}/${t.task}`));
|
|
9451
|
+
const mainlinePath = (id) => `/mainlines/${id}`;
|
|
9452
|
+
return {
|
|
9453
|
+
hub: {
|
|
9454
|
+
name: hub.config.hub,
|
|
9455
|
+
url,
|
|
9456
|
+
open: link("")
|
|
9457
|
+
},
|
|
9458
|
+
refs: refPaths(hub),
|
|
9459
|
+
session: session ? {
|
|
9460
|
+
id: session.id,
|
|
9461
|
+
actions: actions.map((a) => ({
|
|
9462
|
+
id: a.id,
|
|
9463
|
+
do: a.do,
|
|
9464
|
+
status: a.status,
|
|
9465
|
+
serves: a.serves,
|
|
9466
|
+
waiting: a.blockedBy ? {
|
|
9467
|
+
reason: a.blockedBy.reason,
|
|
9468
|
+
waitingFor: a.blockedBy.waitingFor ?? null,
|
|
9469
|
+
until: a.blockedBy.until ?? null
|
|
9470
|
+
} : null
|
|
9471
|
+
})),
|
|
9472
|
+
progress: {
|
|
9473
|
+
done: actions.filter((a) => a.status === "done").length,
|
|
9474
|
+
total: actions.filter((a) => a.status !== "dropped").length
|
|
9475
|
+
}
|
|
9476
|
+
} : null,
|
|
9477
|
+
focus: focusMainline ? {
|
|
9478
|
+
id: focusMainline.id,
|
|
9479
|
+
title: focusMainline.title,
|
|
9480
|
+
status: focusMainline.status,
|
|
9481
|
+
criteria: listProgress(focusMainline.criteria),
|
|
9482
|
+
checklist: taskProgress(focusMainline),
|
|
9483
|
+
link: link(mainlinePath(focusMainline.id))
|
|
9484
|
+
} : null,
|
|
9485
|
+
tasks: (focusMainline?.tasks ?? []).map((t) => ({
|
|
9486
|
+
mainline: focusMainline.id,
|
|
9487
|
+
id: t.id,
|
|
9488
|
+
title: t.title,
|
|
9489
|
+
status: t.status,
|
|
9490
|
+
checklist: listProgress(t.checklist),
|
|
9491
|
+
link: link(`${mainlinePath(focusMainline.id)}/tasks/${t.id}`),
|
|
9492
|
+
serving: serving.has(`${focusMainline.id}/${t.id}`)
|
|
9493
|
+
})),
|
|
9494
|
+
mainlines: hub.mainlines.filter(isOpenMainline).map((m) => ({
|
|
9495
|
+
id: m.id,
|
|
9496
|
+
title: m.title,
|
|
9497
|
+
status: m.status,
|
|
9498
|
+
group: m.group ?? null,
|
|
9499
|
+
checklist: taskProgress(m),
|
|
9500
|
+
link: link(mainlinePath(m.id))
|
|
9501
|
+
})),
|
|
9502
|
+
sync
|
|
9503
|
+
};
|
|
9504
|
+
}
|
|
9505
|
+
//#endregion
|
|
9404
9506
|
//#region src/host.ts
|
|
9405
9507
|
const DEFAULT_UI_PORT = 4320;
|
|
9406
9508
|
const hostName = (hub) => `${hub}.mainflow.localhost`;
|
|
@@ -9599,4 +9701,4 @@ function openInApp(hub, target, closeAfterMs = 150) {
|
|
|
9599
9701
|
return true;
|
|
9600
9702
|
}
|
|
9601
9703
|
//#endregion
|
|
9602
|
-
export {
|
|
9704
|
+
export { applyOperation as $, dataFile as $t, unhandledNotices as A, textBytes as At, attributeTrace as B, hubHoldingFile as Bt, duplicateClaimLines as C, ROUTES as Ct, markNoticesHandled as D, exceedsFileLimit as Dt, HANDLED_FILE as E, comparePaths as Et, matchGrants as F, MAINLINE_FILE as Ft, renumberFiles as G, registerHub as Gt, transcriptTitle as H, listHubs as Ht, decorateReply as I, SESSIONS_DIR as It, scopeOfPath as J, resolveHub as Jt, renumberPath as K, registeredName as Kt, endsWithMarker as L, TASK_FILE as Lt, readSession as M, hubFormatVersion as Mt, transcriptPath as N, hubRequirements as Nt, parseWarn as O, readsAsText as Ot, grantScope as P, versionMismatch as Pt, syncedPath as Q, currentBranch as Qt, headerLine as R, requireSlug as Rt, untilState as S, MAX_FILE_BYTES as St, turnReminder as T, VERSION_HEADER as Tt, applyOffline as U, notRegisteredMessage as Ut, traceTranscript as V, inRepositoryHubAt as Vt, renumberRequest as W, readRegistry as Wt, mayHoldSynced as X, userDataDir as Xt, hubDigest as Y, unregisterHub as Yt, syncedDir as Z, nodeStorage as Zt, receiverFromEnv as _, readYaml as _t, openInApp as a, DATA_DIR as an, loadMainlines as at, setArchivedMany as b, MAX_BLOB_BYTES as bt, siteBlock as c, splitFrontMatter as cn, mainlineEdges as ct, groupPlan as d, refIndex as dt, gitCheckout as en, checkHubName as et, listProgress as f, remoteMembers as ft, retroReportFromReceiver as g, readFrontMatter as gt, retroReport as h, nowMinute as ht, hostName as i, ConflictError as in, loadHub as it, loadSessions as j, formatMismatch as jt, readNotices as k, requestTime as kt, syncHost as l, linksInto as lt, migrateHub as m, taskFile as mt, DEFAULT_UI_PORT as n, realPath as nn, isOpenMainline as nt, removeDanglingLinks as o, WriteError as on, sectionText as ot, migrateHubData as p, unavailableHubs as pt, renumberText as q, registryFile as qt, caddySites as r, worktreesOf as rn, loadConfig as rt, removeHostLink as s, contentHash as sn, dependencyGraph as st, APP_BUNDLE_ID as t, hubPath as tn, HubError as tt, sessionView as u, memberOfGroup as ut, RETRY_RULES as v, ACCESS_HEADERS as vt, sessionBriefing as w, SOCKET_MAX_AGE_CLOSE as wt, initHub as x, MAX_CHANGE_PAGE as xt, ARCHIVE_KINDS as y, BLOB_HASH as yt, mayDecorate as z, hubAtRoot as zt };
|
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-CsZY5trM.js";
|
|
2
2
|
export { APP_BUNDLE_ID, DEFAULT_UI_PORT, caddySites, hostName, openInApp, removeDanglingLinks, removeHostLink, siteBlock, syncHost };
|
package/dist/launch.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as hostName, l as syncHost, n as DEFAULT_UI_PORT,
|
|
1
|
+
import { i as hostName, l as syncHost, n as DEFAULT_UI_PORT, on as WriteError, s as removeHostLink } from "./host-CsZY5trM.js";
|
|
2
2
|
import { t as CLI_VERSION } from "./version-Dvv4jwF1.js";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { join, resolve } from "node:path";
|
|
@@ -273,7 +273,7 @@ async function launchUi(dirs, hub, configured, options) {
|
|
|
273
273
|
}
|
|
274
274
|
let server;
|
|
275
275
|
if (!reuse) {
|
|
276
|
-
const { serveUi } = await import("./ui-
|
|
276
|
+
const { serveUi } = await import("./ui-Bv29R0WG.js");
|
|
277
277
|
server = await serveUi(dirs, choice.port);
|
|
278
278
|
writeUiRecord(dirs, {
|
|
279
279
|
port: choice.port,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { $ as applyOperation, At as textBytes, Ct as ROUTES, Dt as exceedsFileLimit, Et as comparePaths, G as renumberFiles, J as scopeOfPath, K as renumberPath, Kt as registeredName, Nt as hubRequirements, Ot as readsAsText, Pt as versionMismatch, Q as syncedPath, St as MAX_FILE_BYTES, Tt as VERSION_HEADER, U as applyOffline, W as renumberRequest, X as mayHoldSynced, Y as hubDigest, Z as syncedDir, Zt as nodeStorage, bt as MAX_BLOB_BYTES, cn as splitFrontMatter, ht as nowMinute, in as ConflictError, kt as requestTime, on as WriteError, q as renumberText, sn as contentHash, vt as ACCESS_HEADERS, wt as SOCKET_MAX_AGE_CLOSE, yt as BLOB_HASH } from "./host-CsZY5trM.js";
|
|
2
2
|
import { t as CLI_VERSION } from "./version-Dvv4jwF1.js";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, watch, writeFileSync } from "node:fs";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { I as configSchema, tt as repoPaths } from "./dist-CXrUfRQp.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { C as readRemote, F as syncPaths, N as SYNC_DIR, P as isSynced, S as watchTree, _ as DaemonUnavailable, b as readDaemon, n as hubWriter, r as writtenLines, s as remoteMode, v as callDaemon } from "./operation-CUeOFEaf.js";
|
|
2
|
+
import { $t as dataFile, B as attributeTrace, D as markNoticesHandled, E as HANDLED_FILE, H as transcriptTitle, M as readSession, N as transcriptPath, O as parseWarn, V as traceTranscript, _t as readYaml, a as openInApp, an as DATA_DIR, b as setArchivedMany, ct as mainlineEdges, d as groupPlan, dt as refIndex, f as listProgress, ft as remoteMembers, in as ConflictError, it as loadHub, j as loadSessions, k as readNotices$1, lt as linksInto, on as WriteError, ot as sectionText, rt as loadConfig, st as dependencyGraph, tn as hubPath, tt as HubError, y as ARCHIVE_KINDS, zt as hubAtRoot } from "./host-CsZY5trM.js";
|
|
3
|
+
import { C as readRemote, F as syncPaths, N as SYNC_DIR, P as isSynced, S as watchTree, _ as DaemonUnavailable, b as readDaemon, n as hubWriter, r as writtenLines, s as remoteMode, v as callDaemon } from "./operation-MKNwQkAY.js";
|
|
5
4
|
import { t as CLI_VERSION } from "./version-Dvv4jwF1.js";
|
|
6
5
|
import { readUiRecord, realRoot } from "./launch.js";
|
|
7
6
|
import { createRequire } from "node:module";
|
package/package.json
CHANGED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
//#region ../core/dist/progress.js
|
|
2
|
-
function listProgress(items) {
|
|
3
|
-
const counted = items.filter((item) => !item.dropped);
|
|
4
|
-
return {
|
|
5
|
-
done: counted.filter((item) => item.done).length,
|
|
6
|
-
total: counted.length
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { listProgress as t };
|