mainflow 0.39.0 → 0.40.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
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";
3
+ import { $ as unavailableHubs, C as loadSessions, Et as WriteError, G as loadHub, H as checkHubName, K as sectionText, Q as remoteMembers, St as findHubRoot, Tt as DATA_DIR, U as HubError, V as applyOperation, X as memberOfGroup, b as duplicateClaimLines, bt as requireSlug, ct as MAX_FILE_BYTES, d as migrateHub, f as retroReport, h as RETRY_RULES, it as nodeStorage, m as receiverFromEnv, p as retroReportFromReceiver, tt as nowMinute, u as groupPlan, v as initHub, vt as MAINLINE_FILE, w as readSession, x as sessionBriefing, y as untilState, yt as TASK_FILE } from "./host-erQ_Sr8U.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-DJARDCM0.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-Bf6DtnfD.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-DJ944-bI.js";
8
+ import { f as CLI_VERSION, i as launchUi, l as startUiInBackground, r as exitCodeFor, u as watchHubGone } from "./launch-I_JDTAtU.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";
package/dist/hooks.d.ts CHANGED
@@ -574,6 +574,7 @@ export interface ClaudeCodePayload {
574
574
  tool_name?: string;
575
575
  tool_input?: {
576
576
  file_path?: string;
577
+ notebook_path?: string;
577
578
  command?: string;
578
579
  };
579
580
  }
@@ -617,6 +618,23 @@ export type HookFailure = {
617
618
  } | {
618
619
  kind: 'unreadable-input';
619
620
  };
621
+ /** The first day the start gate applies; a task created earlier began before the lines below existed. */
622
+ export declare const START_GATE_FROM = "2026-10-19";
623
+ /** The kinds of change that need no acceptance scenarios, as a skip line names them. */
624
+ export declare const SCENARIO_SKIP_KINDS: readonly ['措辭或格式', '照抄或同步版號', '單一設定值', '一句話說得完'];
625
+ /** The two lines under a task's 紀錄 that let writing start: the scenarios were confirmed, or the change needs none. */
626
+ export declare const SCENARIO_LINES: {
627
+ readonly confirmed: {
628
+ readonly form: '- 驗收情境確認:{使用者怎麼回覆}';
629
+ readonly pattern: RegExp;
630
+ };
631
+ readonly skipped: {
632
+ readonly form: `- 驗收情境略過({${string} 之一}):{理由}`;
633
+ readonly pattern: RegExp;
634
+ };
635
+ };
636
+ /** Whether a task's 紀錄 holds a confirmation or a skip line as a top-level item; its lines are read untrimmed, so an indented one does not count. */
637
+ export declare function hasScenarioLine(body: string): boolean;
620
638
  export declare const HOOK_PLATFORMS: Record<string, Record<string, Handler>>;
621
639
  /** What an event prints when it cannot run its handler; null for the events that stay silent. */
622
640
  export declare function hookFallback(platform: string, event: string, ctx: HookContext, failure: HookFailure): string | null;
package/dist/hooks.js CHANGED
@@ -1,6 +1,6 @@
1
- import { P as configSchema, rt as describeRequest } from "./dist-zSabglPq.js";
2
- import { A as headerLine, C as loadSessions, Ct as DATA_DIR, D as matchGrants, E as grantScope, G as loadHub, O as decorateReply, S as turnReminder, U as HubError, bt as findHubRoot, ht as hubFormatVersion, i as hostName, j as mayDecorate, k as endsWithMarker, mt as formatMismatch, nt as nodeStorage, tt as readYaml, w as readSession, x as sessionBriefing, xt as worktreesOf, yt as currentBranch } from "./host-CIOd2WSh.js";
3
- import { n as hubWriter, r as writtenLines } from "./operation-DJARDCM0.js";
1
+ import { P as configSchema, W as parseRef, Y as taskSchema, rt as describeRequest } from "./dist-zSabglPq.js";
2
+ import { A as headerLine, C as loadSessions, Ct as worktreesOf, D as matchGrants, E as grantScope, G as loadHub, O as decorateReply, S as turnReminder, St as findHubRoot, Tt as DATA_DIR, U as HubError, _t as hubFormatVersion, et as taskFile, gt as formatMismatch, i as hostName, it as nodeStorage, j as mayDecorate, k as endsWithMarker, nt as readFrontMatter, rt as readYaml, w as readSession, x as sessionBriefing, xt as currentBranch } from "./host-erQ_Sr8U.js";
3
+ import { n as hubWriter, r as writtenLines } from "./operation-Bf6DtnfD.js";
4
4
  import { resolveFixed, scanCommand, scopedCwd } from "./grant-commands.js";
5
5
  import { appendFileSync, existsSync, readFileSync } from "node:fs";
6
6
  import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
@@ -269,7 +269,7 @@ const CLAUDE_CODE_EVENTS = {
269
269
  });
270
270
  return null;
271
271
  },
272
- "pre-tool-use": decideByGrants,
272
+ "pre-tool-use": (root, context) => typeof context.payload.tool_name === "string" && WRITE_TOOLS.has(context.payload.tool_name) ? decideStartGate(root, context) : decideByGrants(root, context),
273
273
  "post-tool-use": checkAfterWrite,
274
274
  "message-display": displayReply
275
275
  };
@@ -355,6 +355,90 @@ async function decideByGrants(root, { payload, warn, write }) {
355
355
  await logGranted(write, scoped.scope, scan.call, resolved.request, grant, warn);
356
356
  return permission("allow", `授權 ${grant.ref} 涵蓋 ${describeRequest(resolved.request)}`);
357
357
  }
358
+ /** The first day the start gate applies; a task created earlier began before the lines below existed. */
359
+ const START_GATE_FROM = "2026-10-19";
360
+ /** The kinds of change that need no acceptance scenarios, as a skip line names them. */
361
+ const SCENARIO_SKIP_KINDS = [
362
+ "措辭或格式",
363
+ "照抄或同步版號",
364
+ "單一設定值",
365
+ "一句話說得完"
366
+ ];
367
+ /** The two lines under a task's 紀錄 that let writing start: the scenarios were confirmed, or the change needs none. */
368
+ const SCENARIO_LINES = {
369
+ confirmed: {
370
+ form: "- 驗收情境確認:{使用者怎麼回覆}",
371
+ pattern: /^- 驗收情境確認:\S/
372
+ },
373
+ skipped: {
374
+ form: `- 驗收情境略過({${SCENARIO_SKIP_KINDS.join("、")} 之一}):{理由}`,
375
+ pattern: new RegExp(`^- 驗收情境略過((?:${SCENARIO_SKIP_KINDS.join("|")})):\\S`)
376
+ }
377
+ };
378
+ /** Whether a task's 紀錄 holds a confirmation or a skip line as a top-level item; its lines are read untrimmed, so an indented one does not count. */
379
+ function hasScenarioLine(body) {
380
+ const lines = body.split("\n");
381
+ const start = lines.findIndex((l) => l.trim() === "## 紀錄");
382
+ if (start === -1) return false;
383
+ const end = lines.findIndex((l, i) => i > start && l.startsWith("## "));
384
+ return lines.slice(start + 1, end === -1 ? void 0 : end).some((line) => SCENARIO_LINES.confirmed.pattern.test(line) || SCENARIO_LINES.skipped.pattern.test(line));
385
+ }
386
+ /** Whether a path lies under `tmp/` at the root of the hub or of a repository config.yaml lists. */
387
+ function inProjectTmp(file, root) {
388
+ const repos = readYaml(join(root, DATA_DIR, "config.yaml"), configSchema).data.repos;
389
+ return [root, ...Object.values(repos).map((path) => resolve(root, path))].some((dir) => relative(dir, file).startsWith(`tmp/`));
390
+ }
391
+ /**
392
+ * The open tasks of this hub that the session's actions in progress serve, created on or after START_GATE_FROM,
393
+ * whose 紀錄 has neither line. A task that cannot be read is left out: the gate only stops what it can show is missing.
394
+ */
395
+ function unconfirmedTasks(root, session) {
396
+ const tasks = /* @__PURE__ */ new Set();
397
+ for (const action of session.actions) {
398
+ if (action.status !== "doing") continue;
399
+ for (const ref of action.serves) {
400
+ const parsed = parseRef(ref);
401
+ if ((parsed?.kind === "task" || parsed?.kind === "checklistItem") && parsed.hub === void 0) tasks.add(`${parsed.mainline}/${parsed.task}`);
402
+ }
403
+ }
404
+ return [...tasks].filter((ref) => {
405
+ const [mainline, task] = ref.split("/");
406
+ try {
407
+ const { data, body } = readFrontMatter(taskFile(root, mainline, task), taskSchema);
408
+ return data.created >= "2026-10-19" && data.status !== "done" && data.status !== "dropped" && !hasScenarioLine(body);
409
+ } catch {
410
+ return false;
411
+ }
412
+ });
413
+ }
414
+ /**
415
+ * PreToolUse for the tools that write a file: deny the write while a task the session's action in progress
416
+ * serves has neither a confirmation nor a skip line under 紀錄, so code waits for its acceptance scenarios.
417
+ * Writes under `.mainflow/` or a project's `tmp/`, a session with no record or no such task, print nothing. A
418
+ * subagent's call carries the main session's session_id, so it is judged by the main session's action. Any failure
419
+ * stays silent, since the fallback only answers Bash, and the write goes on.
420
+ */
421
+ function decideStartGate(root, { payload, cli }) {
422
+ const path = payload.tool_input?.file_path ?? payload.tool_input?.notebook_path;
423
+ const sessionId = payload.session_id;
424
+ if (typeof path !== "string" || !path || typeof sessionId !== "string" || !sessionId) return null;
425
+ const file = isAbsolute(path) ? path : resolve(typeof payload.cwd === "string" ? payload.cwd : root, path);
426
+ if (inMainflowData(file) || inProjectTmp(file, root)) return null;
427
+ const session = readSession(root, claudeCodeSessionId(sessionId));
428
+ if (!session) return null;
429
+ const missing = unconfirmedTasks(root, session);
430
+ if (missing.length === 0) return null;
431
+ const reason = [
432
+ `${missing.join("、")} 的「紀錄」沒有驗收情境的確認行,也沒有略過行,所以先不寫檔。`,
433
+ `使用者確認「完成定義」的驗收情境後,用 ${cli} section append <m/t> 紀錄 加一行「${SCENARIO_LINES.confirmed.form}」。`,
434
+ `改動屬於 ${SCENARIO_SKIP_KINDS.join("、")} 這四類時,改加「${SCENARIO_LINES.skipped.form}」。`
435
+ ].join("");
436
+ return JSON.stringify({ hookSpecificOutput: {
437
+ hookEventName: "PreToolUse",
438
+ permissionDecision: "deny",
439
+ permissionDecisionReason: `[mainflow] ${reason}`
440
+ } });
441
+ }
358
442
  /** How many problems outside the written file the reminder lists before it only gives the count. */
359
443
  const OTHER_PROBLEMS_SHOWN = 5;
360
444
  const problemLine = (p) => `- ${p.file}${p.field ? ` › ${p.field}` : ""}:${p.message}`;
@@ -498,4 +582,4 @@ async function runHook(platform, event, ctx) {
498
582
  }
499
583
  }
500
584
  //#endregion
501
- export { HOOK_PLATFORMS, claudeCodeSessionId, hookFallback, openLink, parsePayload, runHook, subagentTranscript };
585
+ export { HOOK_PLATFORMS, SCENARIO_LINES, SCENARIO_SKIP_KINDS, START_GATE_FROM, claudeCodeSessionId, hasScenarioLine, hookFallback, openLink, parsePayload, runHook, subagentTranscript };
@@ -8430,4 +8430,4 @@ function openInApp(hub, target, closeAfterMs = 150) {
8430
8430
  return true;
8431
8431
  }
8432
8432
  //#endregion
8433
- export { unavailableHubs as $, headerLine as A, scopeOfPath as B, loadSessions as C, DATA_DIR as Ct, matchGrants as D, grantScope as E, splitFrontMatter as Et, applyOffline as F, loadHub as G, checkHubName as H, renumberRequest as I, mainlineEdges as J, sectionText as K, renumberFiles as L, attributeTrace as M, traceTranscript as N, decorateReply as O, transcriptTitle as P, remoteMembers as Q, renumberPath as R, turnReminder as S, ConflictError as St, transcriptPath as T, contentHash as Tt, HubError as U, applyOperation as V, loadConfig as W, memberOfGroup as X, linksInto as Y, refIndex as Z, setArchivedMany as _, TASK_FILE as _t, openInApp as a, MAX_BLOB_BYTES as at, duplicateClaimLines as b, findHubRoot as bt, siteBlock as c, SOCKET_MAX_AGE_CLOSE as ct, migrateHub as d, readsAsText as dt, nowMinute as et, retroReport as f, requestTime as ft, ARCHIVE_KINDS as g, MAINLINE_FILE as gt, RETRY_RULES as h, hubFormatVersion as ht, hostName as i, BLOB_HASH as it, mayDecorate as j, endsWithMarker as k, syncHost as l, comparePaths as lt, receiverFromEnv as m, formatMismatch as mt, DEFAULT_UI_PORT as n, nodeStorage as nt, removeDanglingLinks as o, MAX_FILE_BYTES as ot, retroReportFromReceiver as p, textBytes as pt, dependencyGraph as q, caddySites as r, ACCESS_HEADERS as rt, removeHostLink as s, ROUTES as st, APP_BUNDLE_ID as t, readYaml as tt, groupPlan as u, exceedsFileLimit as ut, initHub as v, requireSlug as vt, readSession as w, WriteError as wt, sessionBriefing as x, worktreesOf as xt, untilState as y, currentBranch as yt, renumberText as z };
8433
+ export { unavailableHubs as $, headerLine as A, scopeOfPath as B, loadSessions as C, worktreesOf as Ct, matchGrants as D, contentHash as Dt, grantScope as E, WriteError as Et, applyOffline as F, loadHub as G, checkHubName as H, renumberRequest as I, mainlineEdges as J, sectionText as K, renumberFiles as L, attributeTrace as M, traceTranscript as N, decorateReply as O, splitFrontMatter as Ot, transcriptTitle as P, remoteMembers as Q, renumberPath as R, turnReminder as S, findHubRoot as St, transcriptPath as T, DATA_DIR as Tt, HubError as U, applyOperation as V, loadConfig as W, memberOfGroup as X, linksInto as Y, refIndex as Z, setArchivedMany as _, hubFormatVersion as _t, openInApp as a, ACCESS_HEADERS as at, duplicateClaimLines as b, requireSlug as bt, siteBlock as c, MAX_FILE_BYTES as ct, migrateHub as d, comparePaths as dt, taskFile as et, retroReport as f, exceedsFileLimit as ft, ARCHIVE_KINDS as g, formatMismatch as gt, RETRY_RULES as h, textBytes as ht, hostName as i, nodeStorage as it, mayDecorate as j, endsWithMarker as k, syncHost as l, ROUTES as lt, receiverFromEnv as m, requestTime as mt, DEFAULT_UI_PORT as n, readFrontMatter as nt, removeDanglingLinks as o, BLOB_HASH as ot, retroReportFromReceiver as p, readsAsText as pt, dependencyGraph as q, caddySites as r, readYaml as rt, removeHostLink as s, MAX_BLOB_BYTES as st, APP_BUNDLE_ID as t, nowMinute as tt, groupPlan as u, SOCKET_MAX_AGE_CLOSE as ut, initHub as v, MAINLINE_FILE as vt, readSession as w, ConflictError as wt, sessionBriefing as x, currentBranch as xt, untilState as y, TASK_FILE as yt, renumberText as z };
package/dist/host.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as openInApp, c as siteBlock, i as hostName, l as syncHost, n as DEFAULT_UI_PORT, o as removeDanglingLinks, r as caddySites, s as removeHostLink, t as APP_BUNDLE_ID } from "./host-CIOd2WSh.js";
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-erQ_Sr8U.js";
2
2
  export { APP_BUNDLE_ID, DEFAULT_UI_PORT, caddySites, hostName, openInApp, removeDanglingLinks, removeHostLink, siteBlock, syncHost };
@@ -1,4 +1,4 @@
1
- import { Ct as DATA_DIR, i as hostName, l as syncHost, n as DEFAULT_UI_PORT, s as removeHostLink, wt as WriteError } from "./host-CIOd2WSh.js";
1
+ import { Et as WriteError, Tt as DATA_DIR, i as hostName, l as syncHost, n as DEFAULT_UI_PORT, s as removeHostLink } from "./host-erQ_Sr8U.js";
2
2
  import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
4
  import { spawn, spawnSync } from "node:child_process";
@@ -276,7 +276,7 @@ async function launchUi(root, hub, configured, options) {
276
276
  }
277
277
  let server;
278
278
  if (!reuse) {
279
- const { serveUi } = await import("./ui-BhwCZPJR.js");
279
+ const { serveUi } = await import("./ui-CFtibt8x.js");
280
280
  server = await serveUi(root, choice.port);
281
281
  writeUiRecord(root, {
282
282
  port: choice.port,
package/dist/launch.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as networkProbe, c as realRoot, d as withUiLock, i as launchUi, l as startUiInBackground, n as choosePort, o as portCandidates, r as exitCodeFor, s as readUiRecord, t as PORT_SPAN, u as watchHubGone } from "./launch-DJ944-bI.js";
1
+ import { a as networkProbe, c as realRoot, d as withUiLock, i as launchUi, l as startUiInBackground, n as choosePort, o as portCandidates, r as exitCodeFor, s as readUiRecord, t as PORT_SPAN, u as watchHubGone } from "./launch-I_JDTAtU.js";
2
2
  export { PORT_SPAN, choosePort, exitCodeFor, launchUi, networkProbe, portCandidates, readUiRecord, realRoot, startUiInBackground, watchHubGone, withUiLock };
@@ -1,4 +1,4 @@
1
- import { B as scopeOfPath, Ct as DATA_DIR, Et as splitFrontMatter, F as applyOffline, I as renumberRequest, L as renumberFiles, R as renumberPath, St as ConflictError, Tt as contentHash, V as applyOperation, at as MAX_BLOB_BYTES, ct as SOCKET_MAX_AGE_CLOSE, dt as readsAsText, et as nowMinute, ft as requestTime, it as BLOB_HASH, lt as comparePaths, nt as nodeStorage, ot as MAX_FILE_BYTES, pt as textBytes, rt as ACCESS_HEADERS, st as ROUTES, ut as exceedsFileLimit, wt as WriteError, z as renumberText } from "./host-CIOd2WSh.js";
1
+ import { B as scopeOfPath, Dt as contentHash, Et as WriteError, F as applyOffline, I as renumberRequest, L as renumberFiles, Ot as splitFrontMatter, R as renumberPath, Tt as DATA_DIR, V as applyOperation, at as ACCESS_HEADERS, ct as MAX_FILE_BYTES, dt as comparePaths, ft as exceedsFileLimit, ht as textBytes, it as nodeStorage, lt as ROUTES, mt as requestTime, ot as BLOB_HASH, pt as readsAsText, st as MAX_BLOB_BYTES, tt as nowMinute, ut as SOCKET_MAX_AGE_CLOSE, wt as ConflictError, z as renumberText } from "./host-erQ_Sr8U.js";
2
2
  import { createHash, randomBytes } from "node:crypto";
3
3
  import { accessSync, appendFileSync, chmodSync, closeSync, constants, copyFileSync, createReadStream, createWriteStream, existsSync, linkSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, statSync, watch, writeFileSync } from "node:fs";
4
4
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
@@ -1,8 +1,8 @@
1
1
  import { P as configSchema } from "./dist-zSabglPq.js";
2
- import { C as loadSessions, Ct as DATA_DIR, G as loadHub, J as mainlineEdges, K as sectionText, M as attributeTrace, N as traceTranscript, P as transcriptTitle, Q as remoteMembers, St as ConflictError, T as transcriptPath, U as HubError, W as loadConfig, Y as linksInto, Z as refIndex, _ as setArchivedMany, a as openInApp, g as ARCHIVE_KINDS, q as dependencyGraph, tt as readYaml, u as groupPlan, w as readSession, wt as WriteError } from "./host-CIOd2WSh.js";
2
+ import { C as loadSessions, Et as WriteError, G as loadHub, J as mainlineEdges, K as sectionText, M as attributeTrace, N as traceTranscript, P as transcriptTitle, Q as remoteMembers, T as transcriptPath, Tt as DATA_DIR, U as HubError, W as loadConfig, Y as linksInto, Z as refIndex, _ as setArchivedMany, a as openInApp, g as ARCHIVE_KINDS, q as dependencyGraph, rt as readYaml, u as groupPlan, w as readSession, wt as ConflictError } from "./host-erQ_Sr8U.js";
3
3
  import { t as listProgress } from "./progress-1BfPg2zN.js";
4
- import { A as isSynced, _ as readDaemon, a as remoteMode, b as readRemote, h as callDaemon, j as syncPaths, k as SYNC_DIR, m as DaemonUnavailable, n as hubWriter, r as writtenLines, y as watchTree } from "./operation-DJARDCM0.js";
5
- import { c as realRoot, f as CLI_VERSION, s as readUiRecord } from "./launch-DJ944-bI.js";
4
+ import { A as isSynced, _ as readDaemon, a as remoteMode, b as readRemote, h as callDaemon, j as syncPaths, k as SYNC_DIR, m as DaemonUnavailable, n as hubWriter, r as writtenLines, y as watchTree } from "./operation-Bf6DtnfD.js";
5
+ import { c as realRoot, f as CLI_VERSION, s as readUiRecord } from "./launch-I_JDTAtU.js";
6
6
  import { createRequire } from "node:module";
7
7
  import { closeSync, existsSync, lstatSync, openSync, readFileSync, readSync, realpathSync, statSync } from "node:fs";
8
8
  import { basename, dirname, extname, join, normalize, relative, resolve, sep } from "node:path";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mainflow",
3
- "version": "0.39.0",
3
+ "version": "0.40.0",
4
4
  "description": "本機多 AI 協作的主脈絡任務管理:CLI 與介面",
5
5
  "license": "MIT",
6
6
  "type": "module",