mainflow 0.30.0-alpha.1 → 0.31.0-alpha.1

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,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import { B as parseRef, H as refExample, V as parseUntil, Y as stampMs, k as UNTIL_FORMS } from "./dist-IdbnCDqM.js";
3
- import { B as checkHubName, H as loadHub, J as TASK_FILE, Q as nodeStorage, S as readSession, V as HubError, X as nowMinute, Y as requireSlug, _ as untilState, d as retroReportFromReceiver, f as receiverFromEnv, g as initHub, l as migrateHub, ot as DATA_DIR, p as RETRY_RULES, q as MAINLINE_FILE, rt as findHubRoot, st as WriteError, u as retroReport, v as duplicateClaimLines, x as loadSessions, y as sessionBriefing, z as applyOperation } from "./host-DmVNYRql.js";
3
+ import { B as checkHubName, H as loadHub, J as TASK_FILE, Q as nodeStorage, S as readSession, V as HubError, X as nowMinute, Y as requireSlug, _ as untilState, at as findHubRoot, ct as DATA_DIR, d as retroReportFromReceiver, f as receiverFromEnv, g as initHub, l as migrateHub, lt as WriteError, p as RETRY_RULES, q as MAINLINE_FILE, u as retroReport, v as duplicateClaimLines, x as loadSessions, y as sessionBriefing, z as applyOperation } from "./host-CdB_vDY_.js";
4
4
  import { t as listProgress } from "./progress-1BfPg2zN.js";
5
- import { C as ServerError, S as ServerApi, _ as silentHint, a as remoteMode, c as syncSettings, d as startDaemon, f as DaemonRunning, g as readDaemon, h as probeDaemon, i as queuedCount, l as hookAnswer, m as callDaemon, n as hubWriter, o as ENV, p as DaemonUnavailable, r as writtenLines, s as hubName, t as CONFIRM_MS, u as planFlush, v as SETTINGS_FILE, x as syncPaths } from "./operation-BQiUL0eq.js";
5
+ import { C as syncSettings, D as syncPaths, S as hubName, _ as readRemote, a as remoteMode, b as ENV, c as planFetch, d as DaemonRunning, f as DaemonUnavailable, g as silentHint, h as readDaemon, i as queuedCount, l as planFlush, m as probeDaemon, n as hubWriter, o as fetchDenial, p as callDaemon, r as writtenLines, s as hookAnswer, t as CONFIRM_MS, u as startDaemon, v as ServerApi, w as SETTINGS_FILE, x as earlierToken, y as ServerError } from "./operation-BmysMg4R.js";
6
6
  import { COMMAND_SPECS, OPTIONS } from "./facts.js";
7
7
  import { hookFallback, parsePayload, runHook } from "./hooks.js";
8
- import { c as watchHubGone, l as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-DHug6eli.js";
8
+ import { c as watchHubGone, l as CLI_VERSION, r as launchUi, s as startUiInBackground } from "./launch-D1zaGo7W.js";
9
9
  import { randomBytes } from "node:crypto";
10
- import { existsSync, readFileSync, realpathSync, rmSync, statSync } from "node:fs";
11
- import { basename, join, relative, resolve } from "node:path";
10
+ import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
11
+ import { basename, isAbsolute, join, relative, resolve, sep } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { parseArgs } from "node:util";
14
14
  //#region src/remote/sync.ts
@@ -20,7 +20,8 @@ import { parseArgs } from "node:util";
20
20
  async function syncRun(root) {
21
21
  const settings = syncSettings(root);
22
22
  if (!settings) {
23
- console.error(`✗ no sync server: set ${ENV.url} and ${ENV.token}, or url and token in .mainflow/${SETTINGS_FILE}`);
23
+ const earlier = earlierToken(root);
24
+ console.error(earlier ? `✗ ${earlier}` : `✗ no sync server: set ${ENV.url}, ${ENV.clientId} and ${ENV.clientSecret}, or url, clientId and clientSecret in .mainflow/${SETTINGS_FILE}`);
24
25
  return 1;
25
26
  }
26
27
  const running = await probeDaemon(root);
@@ -28,13 +29,16 @@ async function syncRun(root) {
28
29
  console.error(`✗ mainflow sync already runs for this hub (pid ${running.daemon.pid})${running.state === "silent" ? `; ${silentHint(running.daemon)}` : ""}`);
29
30
  return 1;
30
31
  }
32
+ const api = new ServerApi(settings);
31
33
  try {
32
- await new ServerApi(settings).snapshot();
34
+ await api.check();
33
35
  } catch (error) {
34
36
  if (error instanceof ServerError) {
35
37
  console.error(`✗ ${error.message} (hub ${settings.hub} at ${settings.url})`);
36
38
  return 1;
37
39
  }
40
+ } finally {
41
+ api.close();
38
42
  }
39
43
  let daemon;
40
44
  try {
@@ -104,6 +108,96 @@ async function syncFlush(root, hook) {
104
108
  console.log(`${result.problems.length} problems, ${result.queued} queued, ${result.online ? "online" : "offline"}`);
105
109
  return result.problems.length > 0 ? 1 : 0;
106
110
  }
111
+ /** How long a download may take before the command or the hook gives up on the sync client's answer. */
112
+ const FETCH_MS = 3e4;
113
+ /**
114
+ * What `target` names, as the sync client takes it: a mainline (m001) or a task (m001/t002), as its directory with every
115
+ * file under it, or a path, from the current directory or from .mainflow/. Null when it names nothing of the hub.
116
+ */
117
+ function fetchSpec(root, target) {
118
+ const ref = /^(m\d{3})(?:\/(t\d{3}))?$/.exec(target);
119
+ if (ref) {
120
+ const dirOf = (parent, id) => existsSync(join(root, ".mainflow", parent)) ? readdirSync(join(root, DATA_DIR, parent)).find((name) => name.startsWith(`${id}-`)) : void 0;
121
+ const mainline = dirOf("mainlines", ref[1]);
122
+ if (!mainline) return null;
123
+ if (!ref[2]) return `mainlines/${mainline}/`;
124
+ const task = dirOf(`mainlines/${mainline}/tasks`, ref[2]);
125
+ return task ? `mainlines/${mainline}/tasks/${task}/` : null;
126
+ }
127
+ const inHub = (file) => {
128
+ const path = relative(join(root, DATA_DIR), file).split(sep).join("/");
129
+ return path === "" || path.startsWith("../") || path === ".." || isAbsolute(path) ? null : path;
130
+ };
131
+ return inHub(resolve(process.cwd(), target)) ?? (isAbsolute(target) ? null : inHub(join(root, ".mainflow", target)));
132
+ }
133
+ /**
134
+ * Download files only on the sync server, the artifacts of closed mainlines an environment with on-demand downloads
135
+ * left there: one file, a directory, or a mainline's or task's, by its ID. With `hook`, read the PreToolUse payload from
136
+ * stdin instead: a Read, Edit, Write or MultiEdit of an artifact that is not here downloads it first, when the host runs
137
+ * the hook for it (Claude Code answers an Edit of a missing file before its hooks). A Read then goes ahead; a write is
138
+ * stopped with the reason, so the agent reads the file before writing over it. When it cannot be
139
+ * downloaded, or no sync client runs, the tool is stopped with the reason, so the agent does not take the file for one
140
+ * that does not exist. Anything else answers nothing.
141
+ */
142
+ async function syncFetch(root, target, hook) {
143
+ if (hook) return syncFetchHook(root, readPayload());
144
+ if (target === void 0) {
145
+ console.error("✗ Usage: mainflow sync fetch <path|m|m/t> (or --hook for a PreToolUse hook)");
146
+ return 1;
147
+ }
148
+ const spec = fetchSpec(root, target);
149
+ if (spec === null) {
150
+ console.error(`✗ ${target} names no mainline, task or path in .mainflow/`);
151
+ return 1;
152
+ }
153
+ const daemon = readDaemon(root);
154
+ if (!daemon) {
155
+ console.error("✗ mainflow sync is not running for this hub; start it with mainflow sync, then fetch again");
156
+ return 1;
157
+ }
158
+ let result;
159
+ try {
160
+ result = await callDaemon(daemon, "/fetch", { paths: [spec] }, FETCH_MS);
161
+ } catch (error) {
162
+ if (!(error instanceof DaemonUnavailable)) throw error;
163
+ console.error(error.silent ? `✗ mainflow sync (pid ${daemon.pid}) did not answer within ${FETCH_MS / 1e3} s: it is busy, as with a large snapshot or a slow download; try again shortly` : `✗ ${error.message}; start mainflow sync, then fetch again`);
164
+ return 1;
165
+ }
166
+ if (result.error) {
167
+ console.error(`✗ could not download ${spec}: ${result.error}`);
168
+ return 1;
169
+ }
170
+ for (const path of result.fetched) console.log(` ${path}`);
171
+ for (const path of result.gone) console.log(`! ${path} is no longer on the sync server`);
172
+ if (result.fetched.length === 0 && result.gone.length === 0) console.log(`✓ nothing to download: no file under ${spec} is only on the sync server`);
173
+ else console.log(`✓ downloaded ${result.fetched.length} file${result.fetched.length === 1 ? "" : "s"}`);
174
+ return 0;
175
+ }
176
+ async function syncFetchHook(root, payload) {
177
+ const plan = planFetch(root, payload);
178
+ if (!plan) return 0;
179
+ const deny = (reason) => {
180
+ console.log(fetchDenial(reason));
181
+ return 0;
182
+ };
183
+ const daemon = readDaemon(root);
184
+ let result = null;
185
+ let busy = false;
186
+ if (daemon) try {
187
+ result = await callDaemon(daemon, "/fetch", { paths: [plan.path] }, FETCH_MS);
188
+ } catch (error) {
189
+ busy = error instanceof DaemonUnavailable && error.silent;
190
+ }
191
+ if (!result) {
192
+ if (!(plan.path in readRemote(root))) return 0;
193
+ if (busy) return deny(`.mainflow/${plan.path} is only on the sync server and is not downloaded yet: mainflow sync did not answer within ${FETCH_MS / 1e3} s, as it is busy, such as with a large snapshot. Try again shortly, or run mainflow sync fetch ${plan.path}; the file exists, do not take it for missing.`);
194
+ return deny(`.mainflow/${plan.path} is only on the sync server and is not downloaded here, and mainflow sync is not running, so it cannot be downloaded now. Start mainflow sync and run mainflow sync fetch ${plan.path}; the file exists, do not take it for missing.`);
195
+ }
196
+ if (result.error) return deny(`.mainflow/${plan.path} is only on the sync server and could not be downloaded (${result.error}). Try again once mainflow sync status says online; the file exists, do not take it for missing.`);
197
+ if (!result.fetched.includes(plan.path)) return 0;
198
+ if (plan.write) return deny(`.mainflow/${plan.path} was only on the sync server and is downloaded now. Read it before writing to it, so the write starts from what it holds.`);
199
+ return 0;
200
+ }
107
201
  async function syncStatus(root) {
108
202
  const probe = await probeDaemon(root);
109
203
  if (probe?.state === "silent") {
@@ -113,11 +207,14 @@ async function syncStatus(root) {
113
207
  if (probe?.state === "running") {
114
208
  const { status, daemon } = probe;
115
209
  if (!status) console.log(`mainflow sync runs for this hub (pid ${daemon.pid}); it did not give its status`);
116
- else console.log(`mainflow sync runs (pid ${daemon.pid}): ${status.online ? status.caughtUp ? "online, caught up" : "online, catching up" : "offline"}, ${status.queued} queued, atomic exchange ${status.swapping ? "on" : "off"}, ${status.problems} problems so far`);
210
+ else console.log(`mainflow sync runs (pid ${daemon.pid}): ${status.online ? status.caughtUp ? "online, caught up" : "online, catching up" : "offline"}, ${status.queued} queued, atomic exchange ${status.swapping ? "on" : "off"}, ${status.problems} problems so far${status.remote ? `, ${status.remote} file${status.remote === 1 ? "" : "s"} only on the server (mainflow sync fetch)` : ""}`);
211
+ if (status?.waitingForUpload) console.log("! the sync server has no copy of this hub, and this environment downloads on demand, so it does not upload its copy; run mainflow sync with on-demand downloads off in an environment that keeps every file of the hub to upload it");
117
212
  return 0;
118
213
  }
119
214
  const queue = queuedCount(root);
120
215
  console.log(`mainflow sync is not running; ${remoteMode(root) ? `${queue} write(s) wait in the outbox until it runs` : "writes go to the local files"}`);
216
+ const earlier = remoteMode(root) ? null : earlierToken(root);
217
+ if (earlier) console.error(`! ${earlier}`);
121
218
  return 0;
122
219
  }
123
220
  //#endregion
@@ -801,7 +898,12 @@ const WRITES = {
801
898
  function runWrite(ctx, spec) {
802
899
  spec.check?.(ctx);
803
900
  const input = spec.input(ctx);
804
- if (!remoteMode(ctx.root)) return spec.print(ctx, applyOperation(nodeStorage(ctx.root), spec.op, input, { now: nowMinute() }).value);
901
+ if (!remoteMode(ctx.root)) {
902
+ const code = spec.print(ctx, applyOperation(nodeStorage(ctx.root), spec.op, input, { now: nowMinute() }).value);
903
+ const earlier = earlierToken(ctx.root);
904
+ if (earlier) console.error(`! ${earlier}`);
905
+ return code;
906
+ }
805
907
  return hubWriter(ctx.root, process.env, { confirmMs: CONFIRM_MS })(spec.op, input).then((written) => {
806
908
  const code = spec.print(ctx, written.value);
807
909
  for (const line of writtenLines(written)) (line.startsWith("!") ? console.error : console.log)(line);
@@ -920,6 +1022,7 @@ const RUNS = {
920
1022
  },
921
1023
  sync: ({ root }) => syncRun(root),
922
1024
  "sync flush": ({ root, opts }) => syncFlush(root, opts.hook ?? false),
1025
+ "sync fetch": ({ root, args, opts }) => syncFetch(root, args[0], opts.hook ?? false),
923
1026
  "sync status": ({ root }) => syncStatus(root)
924
1027
  };
925
1028
  const COMMANDS = Object.fromEntries(Object.keys(COMMAND_SPECS).map((name) => [name, {
package/dist/facts.d.ts CHANGED
@@ -342,7 +342,7 @@ export declare const COMMAND_SPECS: {
342
342
  };
343
343
  readonly sync: {
344
344
  readonly usage: 'sync';
345
- readonly summary: `Keep .mainflow/ in step with the hub on the sync server until stopped: pull its changes, send every local change. The server and token come from MAINFLOW_SYNC_URL and MAINFLOW_SYNC_TOKEN, or url and token in .mainflow/local/sync.json. While it runs, or with a server and token set, every mainflow write is applied here and put in the outbox, which it sends in order; a writing command waits up to 15 s for the server's answer`;
345
+ readonly summary: `Keep .mainflow/ in step with the hub on the sync server until stopped: pull its changes, send every local change. The server and its Cloudflare Access service token come from MAINFLOW_SYNC_URL, MAINFLOW_SYNC_CLIENT_ID and MAINFLOW_SYNC_CLIENT_SECRET, or url, clientId and clientSecret in .mainflow/local/sync.json. On connecting it downloads only the files that differ from the versions it last synced; with MAINFLOW_SYNC_ON_DEMAND=1, or onDemand: true in sync.json, it leaves the artifacts of done and dropped mainlines on the server until they are used (sync fetch). While it runs, or with a server and token set, every mainflow write is applied here and put in the outbox, which it sends in order; a writing command waits up to 15 s for the server's answer`;
346
346
  readonly args: 0;
347
347
  readonly needsHub: true;
348
348
  };
@@ -352,6 +352,13 @@ export declare const COMMAND_SPECS: {
352
352
  readonly args: 0;
353
353
  readonly needsHub: true;
354
354
  };
355
+ readonly 'sync fetch': {
356
+ readonly usage: 'sync fetch [<path|m|m/t>] [--hook]';
357
+ readonly summary: 'Download files only on the sync server: with MAINFLOW_SYNC_ON_DEMAND, or onDemand in .mainflow/local/sync.json, the artifacts of done and dropped mainlines stay there until used. Give a file or directory (from here or from .mainflow/), or a mainline or task ID for all of its artifacts; mainflow sync must be running. Grep and Glob do not see a file that is not downloaded, so fetch the mainline before searching it. --hook reads a PreToolUse payload from stdin: a Read or Write of such a file downloads it first (Claude Code 2.1.285 answers an Edit of a missing file before any hook runs, so Read it or fetch it before editing); a Write, a failed download, or a mainflow sync that does not run or does not answer within 30 s answers deny with the reason';
358
+ readonly args: 0;
359
+ readonly optionalArgs: 1;
360
+ readonly needsHub: true;
361
+ };
355
362
  readonly 'sync status': {
356
363
  readonly usage: 'sync status';
357
364
  readonly summary: 'Say whether mainflow sync runs for this hub, whether it is online and caught up with the server, and how many writes wait to be sent';
package/dist/facts.js CHANGED
@@ -332,7 +332,7 @@ const COMMAND_SPECS = {
332
332
  },
333
333
  sync: {
334
334
  usage: "sync",
335
- summary: `Keep .mainflow/ in step with the hub on the sync server until stopped: pull its changes, send every local change. The server and token come from MAINFLOW_SYNC_URL and MAINFLOW_SYNC_TOKEN, or url and token in .mainflow/local/sync.json. While it runs, or with a server and token set, every mainflow write is applied here and put in the outbox, which it sends in order; a writing command waits up to 15 s for the server's answer`,
335
+ summary: `Keep .mainflow/ in step with the hub on the sync server until stopped: pull its changes, send every local change. The server and its Cloudflare Access service token come from MAINFLOW_SYNC_URL, MAINFLOW_SYNC_CLIENT_ID and MAINFLOW_SYNC_CLIENT_SECRET, or url, clientId and clientSecret in .mainflow/local/sync.json. On connecting it downloads only the files that differ from the versions it last synced; with MAINFLOW_SYNC_ON_DEMAND=1, or onDemand: true in sync.json, it leaves the artifacts of done and dropped mainlines on the server until they are used (sync fetch). While it runs, or with a server and token set, every mainflow write is applied here and put in the outbox, which it sends in order; a writing command waits up to 15 s for the server's answer`,
336
336
  args: 0,
337
337
  needsHub: true
338
338
  },
@@ -342,6 +342,13 @@ const COMMAND_SPECS = {
342
342
  args: 0,
343
343
  needsHub: true
344
344
  },
345
+ "sync fetch": {
346
+ usage: "sync fetch [<path|m|m/t>] [--hook]",
347
+ summary: "Download files only on the sync server: with MAINFLOW_SYNC_ON_DEMAND, or onDemand in .mainflow/local/sync.json, the artifacts of done and dropped mainlines stay there until used. Give a file or directory (from here or from .mainflow/), or a mainline or task ID for all of its artifacts; mainflow sync must be running. Grep and Glob do not see a file that is not downloaded, so fetch the mainline before searching it. --hook reads a PreToolUse payload from stdin: a Read or Write of such a file downloads it first (Claude Code 2.1.285 answers an Edit of a missing file before any hook runs, so Read it or fetch it before editing); a Write, a failed download, or a mainflow sync that does not run or does not answer within 30 s answers deny with the reason",
348
+ args: 0,
349
+ optionalArgs: 1,
350
+ needsHub: true
351
+ },
345
352
  "sync status": {
346
353
  usage: "sync status",
347
354
  summary: "Say whether mainflow sync runs for this hub, whether it is online and caught up with the server, and how many writes wait to be sent",
package/dist/hooks.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { $ as describeRequest, j as configSchema } from "./dist-IdbnCDqM.js";
2
- import { D as endsWithMarker, E as decorateReply, H as loadHub, O as headerLine, S as readSession, T as matchGrants, V as HubError, Z as readYaml, b as turnReminder, i as hostName, it as worktreesOf, k as mayDecorate, nt as currentBranch, ot as DATA_DIR, rt as findHubRoot, w as grantScope, x as loadSessions, y as sessionBriefing } from "./host-DmVNYRql.js";
3
- import { n as hubWriter, r as writtenLines } from "./operation-BQiUL0eq.js";
2
+ import { D as endsWithMarker, E as decorateReply, H as loadHub, O as headerLine, S as readSession, T as matchGrants, V as HubError, Z as readYaml, at as findHubRoot, b as turnReminder, ct as DATA_DIR, i as hostName, it as currentBranch, k as mayDecorate, ot as worktreesOf, w as grantScope, x as loadSessions, y as sessionBriefing } from "./host-CdB_vDY_.js";
3
+ import { n as hubWriter, r as writtenLines } from "./operation-BmysMg4R.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";
@@ -328,17 +328,54 @@ function requestTime(instant = /* @__PURE__ */ new Date()) {
328
328
  }
329
329
  /** The routes, below the server's origin. `{hub}` is the hub's name, like carlos-space. */
330
330
  const ROUTES = {
331
- /** GET, without a token: the protocol version this server speaks, `{ protocol }` */
331
+ /** GET: the protocol version this server speaks, `{ protocol }` */
332
332
  version: "/version",
333
333
  /** POST one request (SyncRequest), answered with its response and broadcast to the hub's connections when applied */
334
334
  request: (hub) => `/hub/${hub}/request`,
335
- /** GET `?protocol=2`: every file and directory of the hub (Snapshot). PUT: upload a whole hub (UploadRequest) */
335
+ /** POST: one batch of the hub's snapshot (SnapshotRequest, answered with SnapshotBatch). PUT: upload a whole hub (UploadRequest) */
336
336
  snapshot: (hub) => `/hub/${hub}/snapshot`,
337
- /** GET `?protocol=2` with `Upgrade: websocket`: receive every broadcast of the hub (ServerBroadcast) */
337
+ /** GET `?protocol=3` with `Upgrade: websocket`: receive every broadcast of the hub (ServerBroadcast) */
338
338
  socket: (hub) => `/hub/${hub}/ws`
339
339
  };
340
- /** Every route below /hub/ needs this header as `Bearer <token>`, with the token of that hub. */
341
- const AUTHORIZATION = "authorization";
340
+ /**
341
+ * The service token of Cloudflare Access, which stands in front of the sync server and lets through only the requests
342
+ * that carry a valid one: every request, the WebSocket's upgrade included, sends both headers. The sync server itself
343
+ * checks no credentials, so one deployed without Access in front serves anyone who knows its address.
344
+ */
345
+ const ACCESS_HEADERS = {
346
+ clientId: "CF-Access-Client-Id",
347
+ clientSecret: "CF-Access-Client-Secret"
348
+ };
349
+ /**
350
+ * The order of paths in a snapshot: by Unicode code point, which is the order of their UTF-8 bytes and so the order
351
+ * SQLite gives TEXT. JavaScript compares strings by UTF-16 code unit, which differs only where a character beyond
352
+ * U+FFFF meets one from U+E000 to U+FFFF.
353
+ */
354
+ function comparePaths(a, b) {
355
+ const length = Math.min(a.length, b.length);
356
+ for (let i = 0; i < length; i++) {
357
+ let x = a.charCodeAt(i);
358
+ let y = b.charCodeAt(i);
359
+ if (x === y) continue;
360
+ if (x >= 55296 && y >= 55296) {
361
+ x += x < 57344 ? 8192 : -2048;
362
+ y += y < 57344 ? 8192 : -2048;
363
+ }
364
+ return x - y;
365
+ }
366
+ return a.length - b.length;
367
+ }
368
+ /**
369
+ * The close the sync server ends a WebSocket with once the connection is older than the server lets one live, instead
370
+ * of sending it a broadcast. Cloudflare Access checks the service token only on the upgrade, so a connection opened
371
+ * before its token was revoked would otherwise go on receiving the hub; the client reconnects at once, through Access
372
+ * again, and the snapshot on the new connection brings what changed meanwhile. 4000 is the first of the codes RFC 6455
373
+ * leaves to applications.
374
+ */
375
+ const SOCKET_MAX_AGE_CLOSE = {
376
+ code: 4e3,
377
+ reason: "the connection reached its maximum age; reconnect"
378
+ };
342
379
  //#endregion
343
380
  //#region ../core/dist/storage/node.js
344
381
  const LOCK_WAIT_MS = 5e3;
@@ -7297,4 +7334,4 @@ function openInApp(hub, target, closeAfterMs = 150) {
7297
7334
  return true;
7298
7335
  }
7299
7336
  //#endregion
7300
- export { AUTHORIZATION as $, attributeTrace as A, checkHubName as B, transcriptPath as C, endsWithMarker as D, decorateReply as E, renumberFiles as F, linksInto as G, loadHub as H, renumberPath as I, TASK_FILE as J, refIndex as K, renumberText as L, transcriptTitle as M, applyOffline as N, headerLine as O, renumberRequest as P, nodeStorage as Q, scopeOfPath as R, readSession as S, matchGrants as T, dependencyGraph as U, HubError as V, mainlineEdges as W, nowMinute as X, requireSlug as Y, readYaml as Z, untilState as _, openInApp as a, ConflictError as at, turnReminder as b, syncHost as c, contentHash as ct, retroReportFromReceiver as d, ROUTES as et, receiverFromEnv as f, initHub as g, setArchivedMany as h, hostName as i, worktreesOf as it, traceTranscript as j, mayDecorate as k, migrateHub as l, ARCHIVE_KINDS as m, DEFAULT_UI_PORT as n, currentBranch as nt, removeHostLink as o, DATA_DIR as ot, RETRY_RULES as p, MAINLINE_FILE as q, caddySites as r, findHubRoot as rt, siteBlock as s, WriteError as st, APP_BUNDLE_ID as t, requestTime as tt, retroReport as u, duplicateClaimLines as v, grantScope as w, loadSessions as x, sessionBriefing as y, applyOperation as z };
7337
+ export { ACCESS_HEADERS as $, attributeTrace as A, checkHubName as B, transcriptPath as C, endsWithMarker as D, decorateReply as E, renumberFiles as F, linksInto as G, loadHub as H, renumberPath as I, TASK_FILE as J, refIndex as K, renumberText as L, transcriptTitle as M, applyOffline as N, headerLine as O, renumberRequest as P, nodeStorage as Q, scopeOfPath as R, readSession as S, matchGrants as T, dependencyGraph as U, HubError as V, mainlineEdges as W, nowMinute as X, requireSlug as Y, readYaml as Z, untilState as _, openInApp as a, findHubRoot as at, turnReminder as b, syncHost as c, DATA_DIR as ct, retroReportFromReceiver as d, splitFrontMatter as dt, ROUTES as et, receiverFromEnv as f, initHub as g, setArchivedMany as h, hostName as i, currentBranch as it, traceTranscript as j, mayDecorate as k, migrateHub as l, WriteError as lt, ARCHIVE_KINDS as m, DEFAULT_UI_PORT as n, comparePaths as nt, removeHostLink as o, worktreesOf as ot, RETRY_RULES as p, MAINLINE_FILE as q, caddySites as r, requestTime as rt, siteBlock as s, ConflictError as st, APP_BUNDLE_ID as t, SOCKET_MAX_AGE_CLOSE as tt, retroReport as u, contentHash as ut, duplicateClaimLines as v, grantScope as w, loadSessions as x, sessionBriefing as y, applyOperation as z };
package/dist/host.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as openInApp, c as syncHost, i as hostName, n as DEFAULT_UI_PORT, o as removeHostLink, r as caddySites, s as siteBlock, t as APP_BUNDLE_ID } from "./host-DmVNYRql.js";
1
+ import { a as openInApp, c as syncHost, i as hostName, n as DEFAULT_UI_PORT, o as removeHostLink, r as caddySites, s as siteBlock, t as APP_BUNDLE_ID } from "./host-CdB_vDY_.js";
2
2
  export { APP_BUNDLE_ID, DEFAULT_UI_PORT, caddySites, hostName, openInApp, removeHostLink, siteBlock, syncHost };
@@ -1,4 +1,4 @@
1
- import { c as syncHost, i as hostName, n as DEFAULT_UI_PORT, o as removeHostLink, ot as DATA_DIR, st as WriteError } from "./host-DmVNYRql.js";
1
+ import { c as syncHost, ct as DATA_DIR, i as hostName, lt as WriteError, n as DEFAULT_UI_PORT, o as removeHostLink } from "./host-CdB_vDY_.js";
2
2
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { spawn, spawnSync } from "node:child_process";
@@ -176,7 +176,7 @@ async function launchUi(root, hub, configured, options) {
176
176
  }
177
177
  let server;
178
178
  if (!reuse) {
179
- const { serveUi } = await import("./ui-BqRmaHXn.js");
179
+ const { serveUi } = await import("./ui-DlOY5qEU.js");
180
180
  server = await serveUi(root, choice.port);
181
181
  writeUiRecord(root, {
182
182
  port: choice.port,
package/dist/launch.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as portCandidates, c as watchHubGone, i as networkProbe, n as choosePort, o as readUiRecord, r as launchUi, s as startUiInBackground, t as PORT_SPAN } from "./launch-DHug6eli.js";
1
+ import { a as portCandidates, c as watchHubGone, i as networkProbe, n as choosePort, o as readUiRecord, r as launchUi, s as startUiInBackground, t as PORT_SPAN } from "./launch-D1zaGo7W.js";
2
2
  export { PORT_SPAN, choosePort, launchUi, networkProbe, portCandidates, readUiRecord, startUiInBackground, watchHubGone };