mainflow 0.11.2 → 0.13.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,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { C as supersedeDecision, F as updateAction, G as createIssue, H as appendOps, I as sessionBriefing, J as setFindingArchived, K as planIssue, N as startSession, O as readSession, Q as loadHub, T as addAction, U as closeIssue, W as createFinding, X as setIssueArchived, Y as setFindingStatus, Z as HubError, _ as initHub, b as setCriterion, d as addHub, f as addRepo, g as dropChecklistItem, h as createTask, it as WriteError, j as setSessionStatus, k as setSessionArchived, l as migrateHub, m as createMainline, nt as TASK_FILE, p as createDecision, q as reopenIssue, st as findHubRoot, tt as MAINLINE_FILE, u as acceptDecision, v as setArchived, w as updateTask, x as setMainlineStatus, y as setChecklistItem } from "./host-C3MyDGB_.js";
2
+ import { $ as setFindingStatus, A as addAction, C as setCriterionText, D as updateTask, E as supersedeDecision, F as setSessionArchived, J as createFinding, K as appendOps, L as setSessionStatus, M as handoffSession, O as sessionBriefing, P as readSession, Q as setFindingArchived, S as setCriterion, V as updateAction, X as planIssue, Y as createIssue, Z as reopenIssue, _ as createTask, b as setArchived, ct as TASK_FILE, et as setIssueArchived, f as acceptDecision, g as createMainline, h as createDecision, l as migrateHub, m as addRepo, nt as loadHub, p as addHub, pt as findHubRoot, q as closeIssue, st as MAINLINE_FILE, tt as HubError, ut as WriteError, v as dropChecklistItem, w as setMainlineStatus, x as setChecklistItem, y as initHub, z as startSession } from "./host-daQGe7no.js";
3
+ import { N as parseRef, P as refExample } from "./dist-BQmXEfAf.js";
3
4
  import { t as listProgress } from "./progress-1BfPg2zN.js";
4
5
  import { COMMAND_SPECS, OPTIONS } from "./facts.js";
5
6
  import { runHook } from "./hooks.js";
6
- import { l as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-T0sXbTgT.js";
7
+ import { l as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-JK8l8BYu.js";
7
8
  import { readFileSync, realpathSync } from "node:fs";
8
9
  import { join, relative } from "node:path";
9
10
  import { fileURLToPath } from "node:url";
@@ -54,6 +55,10 @@ const RUNS = {
54
55
  });
55
56
  return done(`started ${session.id}${session.actions.length ? ` with ${session.actions.length} carried actions` : ""}`);
56
57
  },
58
+ "session handoff": ({ root, args, opts }) => {
59
+ const session = handoffSession(root, sessionOf(opts), args[0]);
60
+ return done(`${session.id} took over ${session.actions.filter((a) => a.status === "todo" || a.status === "doing").length} actions from ${args[0]}`);
61
+ },
57
62
  "session show": ({ root, args, opts }) => {
58
63
  const id = sessionOf(opts, args[0]);
59
64
  const session = readSession(root, id);
@@ -155,6 +160,13 @@ const RUNS = {
155
160
  setCriterion(root, args[0], false);
156
161
  return done(`unchecked ${args[0]}`);
157
162
  },
163
+ "criterion set": ({ root, args, opts }) => {
164
+ setCriterionText(root, args[0], {
165
+ text: opts.text,
166
+ doneWhen: opts["done-when"]
167
+ });
168
+ return done(`updated ${args[0]}`);
169
+ },
158
170
  "task set": ({ root, args, opts }) => {
159
171
  const blockedBy = opts.reason ? {
160
172
  reason: opts.reason,
@@ -172,6 +184,18 @@ const RUNS = {
172
184
  });
173
185
  return done(`updated ${args[0]} (${t.status})`);
174
186
  },
187
+ "task show": ({ root, args }) => {
188
+ const { mainline, task } = findTask(loadHub(root), args[0]);
189
+ console.log(`${mainline.id}/${task.id} ${task.status.padEnd(8)} ${task.kind} ${task.title}`);
190
+ if (task.checklist.length === 0) console.log(" (no checklist items)");
191
+ for (const c of task.checklist) {
192
+ const mark = c.done ? "[x]" : "[ ]";
193
+ const state = c.dropped ? " (dropped)" : "";
194
+ console.log(` ${mark} ${c.id} ${c.text}${state}`);
195
+ }
196
+ for (const link of task.links ?? []) console.log(` ${link.rel} → ${link.to}${link.note ? ` ${link.note}` : ""}`);
197
+ return done(`${task.checklist.length} checklist items`);
198
+ },
175
199
  "item check": ({ root, args, opts }) => {
176
200
  setChecklistItem(root, args[0], true, opts.evidence);
177
201
  return done(`checked ${args[0]}`);
@@ -216,13 +240,18 @@ const RUNS = {
216
240
  return done(`logged ${entry.at} ${entry.operation}`);
217
241
  },
218
242
  "ops list": ({ root, opts }) => {
219
- const shown = loadHub(root).ops.filter((o) => !opts.month || o.at.startsWith(opts.month));
243
+ const shown = loadHub(root).ops.filter((o) => (!opts.month || o.at.startsWith(opts.month)) && (!opts.ref || o.ref === opts.ref));
220
244
  for (const o of shown) console.log(` ${o.at} ${o.target} ${o.operation} ${o.result}${o.ref ? ` ${o.ref}` : ""}`);
221
245
  return done(`${shown.length} operations`);
222
246
  },
223
247
  "decision supersede": ({ root, args, opts }) => {
224
248
  const d = supersedeDecision(root, args[0], required(opts, "by", "--by d002"));
225
249
  return done(`superseded ${args[0]} by ${d.supersededBy}`);
250
+ },
251
+ "decision list": ({ root, args }) => {
252
+ const mainline = findMainline(loadHub(root), args[0]);
253
+ for (const d of mainline.decisions) console.log(` ${mainline.id}/${d.id} ${d.status.padEnd(10)} ${d.title}`);
254
+ return done(`${mainline.decisions.length} decisions`);
226
255
  }
227
256
  };
228
257
  const COMMANDS = Object.fromEntries(Object.keys(COMMAND_SPECS).map((name) => [name, {
@@ -300,6 +329,24 @@ function sessionOf(opts, arg) {
300
329
  return id;
301
330
  }
302
331
  const list = (value) => (value ?? "").split(",").map((v) => v.trim()).filter(Boolean);
332
+ /** The mainline a reference names; throws with the same message resolve.ts gives when it is missing. */
333
+ function findMainline(hub, id) {
334
+ const mainline = hub.mainlines.find((m) => m.id === id);
335
+ if (!mainline) throw new WriteError(`mainline ${id} not found; run "mainflow status --all" to list mainlines`);
336
+ return mainline;
337
+ }
338
+ /** The task a `m/t` reference names, with the mainline it sits in. */
339
+ function findTask(hub, refInput) {
340
+ const ref = parseRef(refInput);
341
+ if (ref?.kind !== "task") throw new WriteError(`expected a task reference like ${refExample("task")}, got "${refInput}"`);
342
+ const mainline = findMainline(hub, ref.mainline);
343
+ const task = mainline.tasks.find((t) => t.id === ref.task);
344
+ if (!task) throw new WriteError(`task ${refInput} not found`);
345
+ return {
346
+ mainline,
347
+ task
348
+ };
349
+ }
303
350
  function required(opts, name, example) {
304
351
  const value = opts[name];
305
352
  if (!value) throw new WriteError(`--${name} is required, e.g. ${example}`);
@@ -124,6 +124,8 @@ function parseLocal(input) {
124
124
  }
125
125
  return null;
126
126
  }
127
+ /** The reference a blocked task waits for, when its whole `waitingFor` text is one; free text such as 使用者 gives undefined. */
128
+ const waitingForRef = (waitingFor) => waitingFor && parseRef(waitingFor) ? waitingFor : void 0;
127
129
  /** The mainline a reference sits in, or undefined for hub-level issues and findings. */
128
130
  const refMainline = (ref) => "mainline" in ref ? ref.mainline : void 0;
129
131
  /** The example reference for a kind, used in error messages. */
@@ -382,7 +384,10 @@ const taskSchema = z.object({
382
384
  repo: z.string().min(1).nullable().optional(),
383
385
  startedAt: date.optional(),
384
386
  checklist: z.array(checklistItemSchema),
385
- /** Why a blocked task cannot move, what it waits for, and which signal says the wait is over */
387
+ /**
388
+ * Why a blocked task cannot move, what it waits for, and which signal says the wait is over. `waitingFor`
389
+ * is free text, or a reference such as m031/t002 when the whole text is one (see waitingForRef).
390
+ */
386
391
  blockedBy: z.object({
387
392
  reason: text,
388
393
  waitingFor: text.optional(),
@@ -508,4 +513,4 @@ function parseOpsLine(line) {
508
513
  return parsed.success ? parsed.data : null;
509
514
  }
510
515
  //#endregion
511
- export { mainlineSchema as A, TASK_SECTIONS as C, findingSchema as D, decisionSchema as E, refMainline as F, sessionSchema as I, taskSchema as L, parseOpsLine as M, parseRef as N, formatOpsEntry as O, refExample as P, TASK_REQUIRED_SECTIONS as S, configSchema as T, PRIORITIES as _, DECISION_STATUS as a, SESSION_STATUS as b, FINDING_STATUS as c, ISSUE_SECTIONS as d, ISSUE_STATUS as f, MERGE_STATES as g, MAINLINE_STATUS as h, DECISION_SECTIONS as i, opsEntrySchema as j, issueSchema as k, FORMAT_VERSION as l, MAINLINE_SECTIONS as m, CLOSED_STATUS as n, DEFAULT_CATEGORIES as o, LINK_RELS as p, DECIDERS as r, FINDING_SECTIONS as s, CHECKLIST_REF as t, ID_PATTERNS as u, REF_EXAMPLES as v, WORK_STATUS as w, SLUG as x, RESERVED_HUB_NAMES as y };
516
+ export { mainlineSchema as A, TASK_SECTIONS as C, findingSchema as D, decisionSchema as E, refMainline as F, sessionSchema as I, taskSchema as L, parseOpsLine as M, parseRef as N, formatOpsEntry as O, refExample as P, waitingForRef as R, TASK_REQUIRED_SECTIONS as S, configSchema as T, PRIORITIES as _, DECISION_STATUS as a, SESSION_STATUS as b, FINDING_STATUS as c, ISSUE_SECTIONS as d, ISSUE_STATUS as f, MERGE_STATES as g, MAINLINE_STATUS as h, DECISION_SECTIONS as i, opsEntrySchema as j, issueSchema as k, FORMAT_VERSION as l, MAINLINE_SECTIONS as m, CLOSED_STATUS as n, DEFAULT_CATEGORIES as o, LINK_RELS as p, DECIDERS as r, FINDING_SECTIONS as s, CHECKLIST_REF as t, ID_PATTERNS as u, REF_EXAMPLES as v, WORK_STATUS as w, SLUG as x, RESERVED_HUB_NAMES as y };
package/dist/facts.d.ts CHANGED
@@ -73,6 +73,12 @@ export declare const COMMAND_SPECS: {
73
73
  readonly args: 0;
74
74
  readonly needsHub: true;
75
75
  };
76
+ readonly 'session handoff': {
77
+ readonly usage: 'session handoff <session> [--session <session>]';
78
+ readonly summary: 'Take over the unfinished actions of another session into this one';
79
+ readonly args: 1;
80
+ readonly needsHub: true;
81
+ };
76
82
  readonly 'session show': {
77
83
  readonly usage: 'session show [session]';
78
84
  readonly summary: 'Print the briefing a hook would give this session';
@@ -183,12 +189,24 @@ export declare const COMMAND_SPECS: {
183
189
  readonly args: 1;
184
190
  readonly needsHub: true;
185
191
  };
192
+ readonly 'criterion set': {
193
+ readonly usage: 'criterion set <m#r> [--text <text>] [--done-when <text>]';
194
+ readonly summary: 'Rewrite a criterion\'s text or doneWhen; done stays as it is (use criterion check/uncheck)';
195
+ readonly args: 1;
196
+ readonly needsHub: true;
197
+ };
186
198
  readonly 'task set': {
187
199
  readonly usage: 'task set <m/t> [--status] [--reason --waiting-for --signal] [--repo] [--branch --worktree --base --merge]';
188
200
  readonly summary: 'Change status, repository or branch state; --status blocked needs --reason';
189
201
  readonly args: 1;
190
202
  readonly needsHub: true;
191
203
  };
204
+ readonly 'task show': {
205
+ readonly usage: 'task show <m/t>';
206
+ readonly summary: 'Print a task: status, kind, checklist and links';
207
+ readonly args: 1;
208
+ readonly needsHub: true;
209
+ };
192
210
  readonly 'item check': {
193
211
  readonly usage: 'item check <m/t#c> --evidence <evidence>';
194
212
  readonly summary: 'Check an item with evidence';
@@ -280,8 +298,8 @@ export declare const COMMAND_SPECS: {
280
298
  readonly needsHub: true;
281
299
  };
282
300
  readonly 'ops list': {
283
- readonly usage: 'ops list [--month YYYY-MM]';
284
- readonly summary: 'List logged external operations';
301
+ readonly usage: 'ops list [--month YYYY-MM] [--ref <ref>]';
302
+ readonly summary: 'List logged external operations, optionally filtered by month or by the exact ref that was logged';
285
303
  readonly args: 0;
286
304
  readonly needsHub: true;
287
305
  };
@@ -291,6 +309,12 @@ export declare const COMMAND_SPECS: {
291
309
  readonly args: 1;
292
310
  readonly needsHub: true;
293
311
  };
312
+ readonly 'decision list': {
313
+ readonly usage: 'decision list <m>';
314
+ readonly summary: 'List a mainline\'s decisions';
315
+ readonly args: 1;
316
+ readonly needsHub: true;
317
+ };
294
318
  };
295
319
  export type CommandName = keyof typeof COMMAND_SPECS;
296
320
  export declare const OPTIONS: {
@@ -340,6 +364,9 @@ export declare const OPTIONS: {
340
364
  readonly text: {
341
365
  readonly type: 'string';
342
366
  };
367
+ readonly 'done-when': {
368
+ readonly type: 'string';
369
+ };
343
370
  readonly serves: {
344
371
  readonly type: 'string';
345
372
  };
package/dist/facts.js CHANGED
@@ -1,4 +1,4 @@
1
- import { C as TASK_SECTIONS, S as TASK_REQUIRED_SECTIONS, _ as PRIORITIES, a as DECISION_STATUS, b as SESSION_STATUS, c as FINDING_STATUS, d as ISSUE_SECTIONS, f as ISSUE_STATUS, g as MERGE_STATES, h as MAINLINE_STATUS, i as DECISION_SECTIONS, l as FORMAT_VERSION, m as MAINLINE_SECTIONS, n as CLOSED_STATUS, o as DEFAULT_CATEGORIES, p as LINK_RELS, r as DECIDERS, s as FINDING_SECTIONS, t as CHECKLIST_REF, u as ID_PATTERNS, w as WORK_STATUS, x as SLUG } from "./dist-D2NK-QQP.js";
1
+ import { C as TASK_SECTIONS, S as TASK_REQUIRED_SECTIONS, _ as PRIORITIES, a as DECISION_STATUS, b as SESSION_STATUS, c as FINDING_STATUS, d as ISSUE_SECTIONS, f as ISSUE_STATUS, g as MERGE_STATES, h as MAINLINE_STATUS, i as DECISION_SECTIONS, l as FORMAT_VERSION, m as MAINLINE_SECTIONS, n as CLOSED_STATUS, o as DEFAULT_CATEGORIES, p as LINK_RELS, r as DECIDERS, s as FINDING_SECTIONS, t as CHECKLIST_REF, u as ID_PATTERNS, w as WORK_STATUS, x as SLUG } from "./dist-BQmXEfAf.js";
2
2
  //#region src/facts.ts
3
3
  const COMMAND_SPECS = {
4
4
  init: {
@@ -49,6 +49,12 @@ const COMMAND_SPECS = {
49
49
  args: 0,
50
50
  needsHub: true
51
51
  },
52
+ "session handoff": {
53
+ usage: "session handoff <session> [--session <session>]",
54
+ summary: "Take over the unfinished actions of another session into this one",
55
+ args: 1,
56
+ needsHub: true
57
+ },
52
58
  "session show": {
53
59
  usage: "session show [session]",
54
60
  summary: "Print the briefing a hook would give this session",
@@ -159,12 +165,24 @@ const COMMAND_SPECS = {
159
165
  args: 1,
160
166
  needsHub: true
161
167
  },
168
+ "criterion set": {
169
+ usage: "criterion set <m#r> [--text <text>] [--done-when <text>]",
170
+ summary: "Rewrite a criterion's text or doneWhen; done stays as it is (use criterion check/uncheck)",
171
+ args: 1,
172
+ needsHub: true
173
+ },
162
174
  "task set": {
163
175
  usage: "task set <m/t> [--status] [--reason --waiting-for --signal] [--repo] [--branch --worktree --base --merge]",
164
176
  summary: "Change status, repository or branch state; --status blocked needs --reason",
165
177
  args: 1,
166
178
  needsHub: true
167
179
  },
180
+ "task show": {
181
+ usage: "task show <m/t>",
182
+ summary: "Print a task: status, kind, checklist and links",
183
+ args: 1,
184
+ needsHub: true
185
+ },
168
186
  "item check": {
169
187
  usage: "item check <m/t#c> --evidence <evidence>",
170
188
  summary: "Check an item with evidence",
@@ -256,8 +274,8 @@ const COMMAND_SPECS = {
256
274
  needsHub: true
257
275
  },
258
276
  "ops list": {
259
- usage: "ops list [--month YYYY-MM]",
260
- summary: "List logged external operations",
277
+ usage: "ops list [--month YYYY-MM] [--ref <ref>]",
278
+ summary: "List logged external operations, optionally filtered by month or by the exact ref that was logged",
261
279
  args: 0,
262
280
  needsHub: true
263
281
  },
@@ -266,6 +284,12 @@ const COMMAND_SPECS = {
266
284
  summary: "Mark a decision as replaced by another",
267
285
  args: 1,
268
286
  needsHub: true
287
+ },
288
+ "decision list": {
289
+ usage: "decision list <m>",
290
+ summary: "List a mainline's decisions",
291
+ args: 1,
292
+ needsHub: true
269
293
  }
270
294
  };
271
295
  const OPTIONS = {
@@ -287,6 +311,7 @@ const OPTIONS = {
287
311
  "delegated-from": { type: "string" },
288
312
  "handoff-from": { type: "string" },
289
313
  text: { type: "string" },
314
+ "done-when": { type: "string" },
290
315
  serves: { type: "string" },
291
316
  before: { type: "string" },
292
317
  note: { type: "string" },
@@ -477,7 +502,7 @@ const FIELDS = {
477
502
  field("repo", false, "主要動到的倉庫,名稱需在 config.yaml 登記"),
478
503
  field("startedAt", false, "第一次轉為 doing 時由 CLI 寫入"),
479
504
  field("checklist", true, "checklist 項目清單,每項的欄位見 checklistItem"),
480
- field("blockedBy", false, "卡住時的原因、等待對象與繼續的訊號,blocked 時必填"),
505
+ field("blockedBy", false, "卡住時的原因、等待對象與繼續的訊號,blocked 時必填;等待對象整串是參照時(例如 m031/t002)會檢查它存在"),
481
506
  field("branch", false, "工作所在的分支"),
482
507
  field("worktree", false, "worktree 的路徑"),
483
508
  field("base", false, "分支基於哪個 commit"),
package/dist/hooks.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as setSessionInfo, B as headerLine, E as ensureSession, I as sessionBriefing, L as turnReminder, M as settleSession, O as readSession, Q as loadHub, R as decorateReply, V as mayDecorate, Z as HubError, at as DATA_DIR, ct as worktreesOf, i as hostName, j as setSessionStatus, ot as currentBranch, st as findHubRoot, z as endsWithMarker } from "./host-C3MyDGB_.js";
1
+ import { G as mayDecorate, H as decorateReply, I as setSessionInfo, L as setSessionStatus, O as sessionBriefing, P as readSession, R as settleSession, U as endsWithMarker, W as headerLine, dt as DATA_DIR, ft as currentBranch, i as hostName, j as ensureSession, k as turnReminder, mt as worktreesOf, nt as loadHub, pt as findHubRoot, tt as HubError } from "./host-daQGe7no.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,21 +75,45 @@ const displayReply = (root, { payload }) => {
75
75
  displayContent: shown
76
76
  } });
77
77
  };
78
+ /** Mainline ids a reply mentions, e.g. m001 in `m001/t003`; not inside a longer word or path. */
79
+ const MAINLINE_MENTION = /(?<![\w/#.[-])(m\d{3})(?![\w\]])/g;
80
+ /** The open mainlines the text mentions; loads the hub only when the text mentions one. */
81
+ function openMainlinesIn(root, text) {
82
+ const mentioned = new Set([...text.matchAll(MAINLINE_MENTION)].map((m) => m[1]));
83
+ if (mentioned.size === 0) return [];
84
+ return loadHub(root, { remotes: false }).mainlines.filter((m) => mentioned.has(m.id) && !m.archivedAt && (m.status === "active" || m.status === "planning")).map((m) => m.id);
85
+ }
86
+ /**
87
+ * What to ask for when a turn ends without its header line: the header itself when an action is in progress, or
88
+ * an action first when the queue is empty but the reply talks about an open mainline, since the header only names
89
+ * the session's own action in progress. Null when there is nothing to ask for.
90
+ */
91
+ function missingHeaderRequest(root, { payload, cli }) {
92
+ if (!payload.session_id || payload.stop_hook_active) return null;
93
+ const message = payload.last_assistant_message ?? "";
94
+ if (endsWithMarker(message)) return null;
95
+ const session = readSession(root, claudeCodeSessionId(payload.session_id));
96
+ const header = headerLine(session);
97
+ if (header) return `[mainflow] 這一輪最後一則回覆的最後一行不是標頭。請只回一則內容為「${header}」的訊息,不加其他文字。`;
98
+ if (session && session.actions.length > 0) return null;
99
+ const mainlines = openMainlinesIn(root, message);
100
+ if (mainlines.length === 0) return null;
101
+ return `[mainflow] 這一輪的回覆提到 ${mainlines.join("、")},但這場會話沒有行動,所以回覆結尾沒有標頭。這一輪若在推進它,先用 ${cli} action add "<做法>" --serves <m/t#c> 列出行動並用 ${cli} action set <a編號> --status doing 標為進行中,或用 ${cli} session handoff <會話> 接手上一場沒做完的行動;再只回一則內容為「▸ <m/t> · <a編號>」的訊息,不加其他文字。只是提到、沒有推進時,不必處理。`;
102
+ }
78
103
  /**
79
- * Stop: settle the session, then ask for the header line when a session with an action in progress ended its
80
- * turn without one. Only the model knows which message closes a turn, so the header is its to write; this makes
81
- * a forgotten one cost a single extra message. stop_hook_active stops it from asking twice in a row.
104
+ * Stop: ask for what the turn's header needs, then settle the session. Only the model knows which message closes a
105
+ * turn, so the header is its to write; this makes a forgotten one cost a single extra message. stop_hook_active
106
+ * stops it from asking twice in a row. A session asked to list an action is not settled yet: settling removes a
107
+ * session with no actions, and the action it is asked to add needs the session to exist.
82
108
  */
83
109
  const settleAndCheckMarker = (root, context) => {
84
- settleOnEnd(root, context);
85
- const { payload } = context;
86
- if (!payload.session_id || payload.stop_hook_active || endsWithMarker(payload.last_assistant_message ?? "")) return null;
87
- const header = headerLine(readSession(root, claudeCodeSessionId(payload.session_id)));
88
- if (!header) return null;
89
- return JSON.stringify({ hookSpecificOutput: {
110
+ const request = missingHeaderRequest(root, context);
111
+ const session = context.payload.session_id ? readSession(root, claudeCodeSessionId(context.payload.session_id)) : null;
112
+ if (!request || session && session.actions.length > 0) settleOnEnd(root, context);
113
+ return request ? JSON.stringify({ hookSpecificOutput: {
90
114
  hookEventName: "Stop",
91
- additionalContext: `[mainflow] 這一輪最後一則回覆的最後一行不是標頭。請只回一則內容為「${header}」的訊息,不加其他文字。`
92
- } });
115
+ additionalContext: request
116
+ } }) : null;
93
117
  };
94
118
  const CLAUDE_CODE_EVENTS = {
95
119
  "session-start": (root, { payload, envFile, cli, startUi }) => {