mainflow 0.10.0 → 0.11.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 +2 -2
- package/dist/hooks.js +6 -5
- package/dist/{host-BFGfpTDq.js → host-iTpj7MPD.js} +30 -14
- package/dist/host.js +1 -1
- package/dist/{launch-D5uHpqkh.js → launch-BMuk7UvN.js} +2 -2
- package/dist/launch.js +1 -1
- package/dist/{ui-DbEmJiwO.js → ui-DNLdjWwd.js} +2 -2
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { A as setSessionStatus, C as updateTask, D as readSession, F as sessionBriefing, G as planIssue, H as closeIssue, J as setFindingStatus, K as reopenIssue, M as startSession, O as setSessionArchived, P as updateAction, S as supersedeDecision, U as createFinding, V as appendOps, W as createIssue, X as HubError, Y as setIssueArchived, Z as loadHub, _ as setArchived, b as setMainlineStatus, c as migrateHub, d as addRepo, et as MAINLINE_FILE, f as createDecision, g as initHub, h as dropChecklistItem, l as acceptDecision, m as createTask, ot as findHubRoot, p as createMainline, q as setFindingArchived, rt as WriteError, tt as TASK_FILE, u as addHub, v as setChecklistItem, w as addAction, y as setCriterion } from "./host-iTpj7MPD.js";
|
|
3
3
|
import { t as listProgress } from "./progress-1BfPg2zN.js";
|
|
4
4
|
import { COMMAND_SPECS, OPTIONS } from "./facts.js";
|
|
5
5
|
import { runHook } from "./hooks.js";
|
|
6
|
-
import { c as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-
|
|
6
|
+
import { c as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-BMuk7UvN.js";
|
|
7
7
|
import { readFileSync, realpathSync } from "node:fs";
|
|
8
8
|
import { join, relative } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
package/dist/hooks.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as setSessionStatus, D as readSession, F as sessionBriefing, I as turnReminder, L as decorateReply, R as endsWithMarker, T as ensureSession, X as
|
|
1
|
+
import { A as setSessionStatus, B as mayDecorate, D as readSession, F as sessionBriefing, I as turnReminder, L as decorateReply, R as endsWithMarker, T as ensureSession, X as HubError, Z as loadHub, at as currentBranch, i as hostName, it as DATA_DIR, j as settleSession, k as setSessionInfo, ot as findHubRoot, st as worktreesOf, z as headerLine } from "./host-iTpj7MPD.js";
|
|
2
2
|
import { appendFileSync, existsSync, readFileSync } from "node:fs";
|
|
3
3
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
//#region src/hooks.ts
|
|
@@ -75,18 +75,19 @@ const displayReply = (root, { payload }) => {
|
|
|
75
75
|
} });
|
|
76
76
|
};
|
|
77
77
|
/**
|
|
78
|
-
* Stop: settle the session, then ask for the
|
|
79
|
-
* turn without one. Only the model knows which message closes a turn, so the
|
|
78
|
+
* Stop: settle the session, then ask for the header line when a session with an action in progress ended its
|
|
79
|
+
* turn without one. Only the model knows which message closes a turn, so the header is its to write; this makes
|
|
80
80
|
* a forgotten one cost a single extra message. stop_hook_active stops it from asking twice in a row.
|
|
81
81
|
*/
|
|
82
82
|
const settleAndCheckMarker = (root, context) => {
|
|
83
83
|
settleOnEnd(root, context);
|
|
84
84
|
const { payload } = context;
|
|
85
85
|
if (!payload.session_id || payload.stop_hook_active || endsWithMarker(payload.last_assistant_message ?? "")) return null;
|
|
86
|
-
|
|
86
|
+
const header = headerLine(readSession(root, claudeCodeSessionId(payload.session_id)));
|
|
87
|
+
if (!header) return null;
|
|
87
88
|
return JSON.stringify({ hookSpecificOutput: {
|
|
88
89
|
hookEventName: "Stop",
|
|
89
|
-
additionalContext: `[mainflow]
|
|
90
|
+
additionalContext: `[mainflow] 這一輪最後一則回覆的最後一行不是標頭。請只回一則內容為「${header}」的訊息,不加其他文字。`
|
|
90
91
|
} });
|
|
91
92
|
};
|
|
92
93
|
const CLAUDE_CODE_EVENTS = {
|
|
@@ -954,20 +954,34 @@ function currentActionLine(context) {
|
|
|
954
954
|
parts.push(`[${action.id}](${context.link(sessionPath(context.session.id))}) ${action.do}`);
|
|
955
955
|
return `▸ ${parts.join(" › ")}`;
|
|
956
956
|
}
|
|
957
|
-
/**
|
|
958
|
-
|
|
957
|
+
/** The header line the model writes at the end of a turn, e.g. `▸ m001/t001 · a001`; null without an action in progress. */
|
|
958
|
+
function headerLine(session) {
|
|
959
|
+
const action = session?.actions.find((a) => a.status === "doing");
|
|
960
|
+
if (!action) return null;
|
|
961
|
+
const served = action.serves.map((s) => parseRef(s)).find((r) => r !== null);
|
|
962
|
+
const where = served && "mainline" in served ? "task" in served ? `${served.mainline}/${served.task}` : served.mainline : null;
|
|
963
|
+
return `▸ ${where ? `${where} · ` : ""}${action.id}`;
|
|
964
|
+
}
|
|
965
|
+
/** A line that is the header: the marker alone, or the marker followed by the ids the model copied. */
|
|
966
|
+
const HEADER = new RegExp(`^[ \\t]*▸(?:[ \\t].*)?$`);
|
|
967
|
+
/** The last non-empty line, if it is the header line. */
|
|
968
|
+
const lastHeader = (text) => {
|
|
969
|
+
const last = text.trimEnd().split("\n").at(-1) ?? "";
|
|
970
|
+
return HEADER.test(last) ? last : null;
|
|
971
|
+
};
|
|
972
|
+
/** Whether a message ends with the header line, as the turn's last message should. */
|
|
973
|
+
const endsWithMarker = (text) => lastHeader(text) !== null;
|
|
959
974
|
/**
|
|
960
|
-
* The text to display for a piece of a reply: mentions linked, and a trailing
|
|
961
|
-
* current action line
|
|
975
|
+
* The text to display for a piece of a reply: mentions linked, and a trailing header line replaced with the
|
|
976
|
+
* session's current action line, titles and links included. Without an action in progress the line the model
|
|
977
|
+
* wrote stays, its ids linked; a bare marker is dropped. Returns the input unchanged when there is nothing to do.
|
|
962
978
|
*/
|
|
963
979
|
function decorateReply(text, context) {
|
|
964
|
-
|
|
965
|
-
if (
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
}
|
|
970
|
-
return shown;
|
|
980
|
+
const header = lastHeader(text);
|
|
981
|
+
if (header === null) return linkMentions(text, context);
|
|
982
|
+
const body = linkMentions(text.trimEnd().slice(0, -header.length).trimEnd(), context);
|
|
983
|
+
const line = currentActionLine(context) ?? (header.trim() === "▸" ? null : linkMentions(header.trim(), context));
|
|
984
|
+
return line ? `${body}\n\n${line}\n` : `${body}\n`;
|
|
971
985
|
}
|
|
972
986
|
/** Cheap test for text that decorateReply could change, so a display hook can skip loading the hub. */
|
|
973
987
|
const mayDecorate = (text) => /m\d{3}|[if]\d{3}|\.mainflow\/mainlines/.test(text) || endsWithMarker(text);
|
|
@@ -1039,9 +1053,11 @@ function turnReminder(root, session, options) {
|
|
|
1039
1053
|
if (session.actions.length === 0) return null;
|
|
1040
1054
|
const doing = current(session);
|
|
1041
1055
|
const open = session.actions.filter((a) => a.status === "todo" || a.status === "doing");
|
|
1056
|
+
const head = doing ? `[mainflow] 目前行動 ${doing.id} ${doing.do},服務 ${doing.serves.join("、") || "(未指定)"}。這一輪的工作若不屬於它,先調整佇列再做。` : open.length === 0 ? `[mainflow] ${session.id} 的行動都已結束。繼續工作前先用 ${options.cli} action add 列出下一個行動。` : `[mainflow] ${session.id} 目前沒有進行中的行動。`;
|
|
1057
|
+
const header = headerLine(session);
|
|
1042
1058
|
return [
|
|
1043
|
-
|
|
1044
|
-
...
|
|
1059
|
+
head,
|
|
1060
|
+
...header ? [`- 這一輪最後一則回覆的最後一行寫「${header}」,回覆範例等其他內容都放在它前面。有顯示 hook 時,它會換成標題與連結。`] : [],
|
|
1045
1061
|
...queueWarnings(root, session, options.cli).map((w) => `- ${w}`)
|
|
1046
1062
|
].join("\n");
|
|
1047
1063
|
}
|
|
@@ -1834,4 +1850,4 @@ function openInApp(hub, target, closeAfterMs = 150) {
|
|
|
1834
1850
|
return true;
|
|
1835
1851
|
}
|
|
1836
1852
|
//#endregion
|
|
1837
|
-
export {
|
|
1853
|
+
export { refIndex as $, setSessionStatus as A, mayDecorate as B, updateTask as C, readSession as D, loadSessions as E, sessionBriefing as F, planIssue as G, closeIssue as H, turnReminder as I, setFindingStatus as J, reopenIssue as K, decorateReply as L, startSession as M, transcriptPath as N, setSessionArchived as O, updateAction as P, linksInto as Q, endsWithMarker as R, supersedeDecision as S, ensureSession as T, createFinding as U, appendOps as V, createIssue as W, HubError as X, setIssueArchived as Y, loadHub as Z, setArchived as _, openInApp as a, currentBranch as at, setMainlineStatus as b, migrateHub as c, addRepo as d, MAINLINE_FILE as et, createDecision as f, initHub as g, dropChecklistItem as h, hostName as i, DATA_DIR as it, settleSession as j, setSessionInfo as k, acceptDecision as l, createTask as m, DEFAULT_UI_PORT as n, ConflictError as nt, siteBlock as o, findHubRoot as ot, createMainline as p, setFindingArchived as q, caddySites as r, WriteError as rt, syncHost as s, worktreesOf as st, APP_BUNDLE_ID as t, TASK_FILE as tt, addHub as u, setChecklistItem as v, addAction as w, setMainlineTitle as x, setCriterion as y, headerLine as z };
|
package/dist/host.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as openInApp, i as hostName, n as DEFAULT_UI_PORT, o as siteBlock, r as caddySites, s as syncHost, t as APP_BUNDLE_ID } from "./host-
|
|
1
|
+
import { a as openInApp, i as hostName, n as DEFAULT_UI_PORT, o as siteBlock, r as caddySites, s as syncHost, t as APP_BUNDLE_ID } from "./host-iTpj7MPD.js";
|
|
2
2
|
export { APP_BUNDLE_ID, DEFAULT_UI_PORT, caddySites, hostName, openInApp, siteBlock, syncHost };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { it as DATA_DIR, n as DEFAULT_UI_PORT, rt as WriteError, s as syncHost } from "./host-iTpj7MPD.js";
|
|
2
2
|
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { spawn, spawnSync } from "node:child_process";
|
|
@@ -162,7 +162,7 @@ async function launchUi(root, hub, configured, options) {
|
|
|
162
162
|
}
|
|
163
163
|
let server;
|
|
164
164
|
if (!reuse) {
|
|
165
|
-
const { serveUi } = await import("./ui-
|
|
165
|
+
const { serveUi } = await import("./ui-DNLdjWwd.js");
|
|
166
166
|
server = await serveUi(root, choice.port);
|
|
167
167
|
writeUiRecord(root, {
|
|
168
168
|
port: choice.port,
|
package/dist/launch.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as portCandidates, i as networkProbe, n as choosePort, o as readUiRecord, r as launchUi, s as startUiInBackground, t as PORT_SPAN } from "./launch-
|
|
1
|
+
import { a as portCandidates, i as networkProbe, n as choosePort, o as readUiRecord, r as launchUi, s as startUiInBackground, t as PORT_SPAN } from "./launch-BMuk7UvN.js";
|
|
2
2
|
export { PORT_SPAN, choosePort, launchUi, networkProbe, portCandidates, readUiRecord, startUiInBackground };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as updateTask, D as readSession, E as loadSessions,
|
|
1
|
+
import { $ as refIndex, C as updateTask, D as readSession, E as loadSessions, N as transcriptPath, O as setSessionArchived, Q as linksInto, Y as setIssueArchived, Z as loadHub, _ as setArchived, a as openInApp, b as setMainlineStatus, it as DATA_DIR, nt as ConflictError, q as setFindingArchived, rt as WriteError, v as setChecklistItem, x as setMainlineTitle, y as setCriterion } from "./host-iTpj7MPD.js";
|
|
2
2
|
import { t as listProgress } from "./progress-1BfPg2zN.js";
|
|
3
|
-
import { c as CLI_VERSION } from "./launch-
|
|
3
|
+
import { c as CLI_VERSION } from "./launch-BMuk7UvN.js";
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import { closeSync, existsSync, openSync, readFileSync, readSync, statSync, watch } from "node:fs";
|
|
6
6
|
import { basename, dirname, extname, join, normalize, relative, sep } from "node:path";
|