@agentdocumentformat/cli 0.7.2 → 0.7.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.
@@ -29,10 +29,10 @@ import {
29
29
  TriggersConfigV3Schema,
30
30
  UmbilicalFilterSchema,
31
31
  WsConnectionConfigSchema
32
- } from "./chunk-HWLWPXQ7.mjs";
32
+ } from "./chunk-HDBPBORT.mjs";
33
33
  import "./chunk-ZJKXHM4Q.mjs";
34
34
  import "./chunk-RIX34QHC.mjs";
35
- import "./chunk-WFQUVXML.mjs";
35
+ import "./chunk-CD3ATSXE.mjs";
36
36
  import "./chunk-M2RX3S2T.mjs";
37
37
  export {
38
38
  AdapterInstanceConfigSchema,
@@ -7,7 +7,7 @@ const __dirname = __adfDirname(__filename);
7
7
  import {
8
8
  AGENT_DEFAULTS,
9
9
  DEFAULT_TOOLS
10
- } from "./chunk-WFQUVXML.mjs";
10
+ } from "./chunk-CD3ATSXE.mjs";
11
11
  import {
12
12
  __export
13
13
  } from "./chunk-M2RX3S2T.mjs";
@@ -13,7 +13,7 @@ import {
13
13
  } from "./chunk-SGUTYISF.mjs";
14
14
  import {
15
15
  daemon_url_exports
16
- } from "./chunk-G426FACA.mjs";
16
+ } from "./chunk-GKKCMXIZ.mjs";
17
17
 
18
18
  // src/main/tui/api/sse.ts
19
19
  var EventStream = class {
@@ -25,6 +25,10 @@ var EventStream = class {
25
25
  attempt = 0;
26
26
  hasOpened = !1;
27
27
  lastCursor;
28
+ /** Daemon run the cursor belongs to (`stream.hello`). */
29
+ epoch = null;
30
+ /** This connection resumes a dropped one and has not reported how yet. */
31
+ resumePending = !1;
28
32
  seen = /* @__PURE__ */ new Set();
29
33
  seenOrder = [];
30
34
  idleTimer = null;
@@ -64,7 +68,7 @@ var EventStream = class {
64
68
  }
65
69
  buildUrl() {
66
70
  let params = new URLSearchParams();
67
- this.options.agentId && params.set("agentId", this.options.agentId), this.lastCursor >= 0 ? params.set("since", String(this.lastCursor)) : this.options.replay || params.set("since", String(Number.MAX_SAFE_INTEGER));
71
+ this.options.agentId && params.set("agentId", this.options.agentId), this.lastCursor >= 0 ? (params.set("since", String(this.lastCursor)), this.epoch && params.set("epoch", this.epoch)) : this.options.replay || params.set("since", String(Number.MAX_SAFE_INTEGER));
68
72
  let qs = params.toString();
69
73
  return `${this.options.baseUrl}/events${qs ? `?${qs}` : ""}`;
70
74
  }
@@ -83,7 +87,7 @@ var EventStream = class {
83
87
  });
84
88
  if (!response.ok || !response.body)
85
89
  throw new Error(`HTTP ${response.status} ${response.statusText}`.trim());
86
- this.attempt = 0, this.hasOpened = !0, this.setState({ state: "open", attempt: 0, resumed }), this.armIdle(), await this.read(response.body, controller), failure = "stream ended";
90
+ this.attempt = 0, this.resumePending = resumed, this.hasOpened = !0, this.setState({ state: "open", attempt: 0, resumed }), this.armIdle(), await this.read(response.body, controller), failure = "stream ended";
87
91
  } catch (err) {
88
92
  failure = controller.signal.aborted && this.closed ? void 0 : errorMessage(err);
89
93
  } finally {
@@ -136,14 +140,19 @@ var EventStream = class {
136
140
  if (controller.signal.aborted) throw controller.signal.reason instanceof Error ? controller.signal.reason : new Error("aborted");
137
141
  }
138
142
  handleBlock(block) {
139
- let data = [];
143
+ let data = [], name = "";
140
144
  for (let line of block.split(`
141
145
  `)) {
142
146
  if (!line || line.startsWith(":")) continue;
143
147
  let colon = line.indexOf(":"), field = colon < 0 ? line : line.slice(0, colon), value = colon < 0 ? "" : line.slice(colon + 1).replace(/^ /, "");
144
- field === "data" && data.push(value);
148
+ field === "data" ? data.push(value) : field === "event" && (name = value);
145
149
  }
146
150
  if (data.length === 0) return;
151
+ if (name === "stream.hello" || name === "stream.gap") {
152
+ this.handleControl(name, data.join(`
153
+ `));
154
+ return;
155
+ }
147
156
  let frame;
148
157
  try {
149
158
  frame = JSON.parse(data.join(`
@@ -163,6 +172,41 @@ var EventStream = class {
163
172
  } catch {
164
173
  }
165
174
  }
175
+ /**
176
+ * `stream.hello` carries enough to judge the resume on its own (so a quiet
177
+ * stream reports at once); `stream.gap` confirms a loss the hello missed.
178
+ */
179
+ handleControl(name, raw) {
180
+ let data;
181
+ try {
182
+ data = JSON.parse(raw);
183
+ } catch {
184
+ return;
185
+ }
186
+ let epoch = typeof data.epoch == "string" ? data.epoch : null;
187
+ if (!epoch) return;
188
+ let previous = this.epoch;
189
+ if (this.epoch = epoch, name === "stream.hello") {
190
+ if (previous && previous !== epoch) {
191
+ this.forgetCursorKeys(), this.lastCursor = -1, this.reportResume({ exact: !1, reason: "epoch_changed", epoch });
192
+ return;
193
+ }
194
+ let oldest = typeof data.oldestCursor == "number" ? data.oldestCursor : null, latest = typeof data.latestCursor == "number" ? data.latestCursor : 0, since = this.lastCursor, lost = since >= 0 && since < latest && (oldest === null || since < oldest - 1);
195
+ this.reportResume(lost ? { exact: !1, reason: "evicted", epoch } : { exact: !0, epoch });
196
+ return;
197
+ }
198
+ let reason = data.reason === "epoch_changed" ? "epoch_changed" : "evicted";
199
+ reason === "epoch_changed" && (this.forgetCursorKeys(), this.lastCursor = -1), this.reportResume({ exact: !1, reason, epoch });
200
+ }
201
+ reportResume(info) {
202
+ if (this.resumePending) {
203
+ this.resumePending = !1;
204
+ try {
205
+ this.options.onResume?.(info);
206
+ } catch {
207
+ }
208
+ }
209
+ }
166
210
  remember(key) {
167
211
  this.seen.add(key), this.seenOrder.push(key);
168
212
  let cap = this.options.dedupeWindow ?? 5e3;
@@ -209,7 +253,7 @@ function normalizeRuntime(raw) {
209
253
  }
210
254
 
211
255
  // src/main/tui/api/client.ts
212
- var { localDaemonToken, resolveDaemonToken, resolveDaemonUrl } = cjs(daemon_url_exports), enc = encodeURIComponent;
256
+ var { localDaemonToken, localProofHeaders, resolveDaemonToken, resolveDaemonUrl } = cjs(daemon_url_exports), enc = encodeURIComponent;
213
257
  function sameOrigin(a, b) {
214
258
  try {
215
259
  return new URL(a).origin === new URL(b).origin;
@@ -270,7 +314,11 @@ var DaemonClient = class _DaemonClient {
270
314
  try {
271
315
  response = await this.fetchImpl(this.url(path, options.query), {
272
316
  method,
273
- headers: this.headers(options.body !== void 0 ? { "Content-Type": "application/json" } : {}),
317
+ headers: this.headers({
318
+ ...options.body !== void 0 ? { "Content-Type": "application/json" } : {},
319
+ // Proxy-mode daemons (ADF_DAEMON_BEHIND_PROXY) need this machine's proof on local-only routes.
320
+ ...this.options.localToken ? localProofHeaders(this.baseUrl, path, this.options.env ?? process.env) : {}
321
+ }),
274
322
  body: options.body !== void 0 ? JSON.stringify(options.body) : void 0,
275
323
  signal: controller.signal
276
324
  });
@@ -33,7 +33,11 @@ var CODE_EXECUTION_DEFAULTS = {
33
33
  }, COMPUTE_DEFAULTS = {
34
34
  enabled: !1
35
35
  };
36
- var START_IN_STATES = ["active", "idle", "hibernate"], DEFAULT_NEW_LOOP_TOOLS = ["loop_send", "loop_list", "sys_set_state"], LOOP_PROHIBITED_TOOLS = ["sys_update_config", "loop_manage", "sys_create_adf"];
36
+ var START_IN_STATES = ["active", "idle", "hibernate"];
37
+ function resolveStartInState(config) {
38
+ return config.start_in_state ?? "active";
39
+ }
40
+ var DEFAULT_NEW_LOOP_TOOLS = ["loop_send", "loop_list", "sys_set_state"], LOOP_PROHIBITED_TOOLS = ["sys_update_config", "loop_manage", "sys_create_adf"];
37
41
  var META_PROTECTION_LEVELS = ["none", "readonly", "increment"], FILE_PROTECTION_LEVELS = ["read_only", "no_delete", "none"];
38
42
  var DEFAULT_TOOLS = [
39
43
  { name: "fs_read", enabled: !0, visible: !0 },
@@ -282,6 +286,7 @@ export {
282
286
  RECOVERY_DEFAULTS,
283
287
  CODE_EXECUTION_DEFAULTS,
284
288
  START_IN_STATES,
289
+ resolveStartInState,
285
290
  DEFAULT_NEW_LOOP_TOOLS,
286
291
  LOOP_PROHIBITED_TOOLS,
287
292
  META_PROTECTION_LEVELS,
@@ -0,0 +1,94 @@
1
+ import { createRequire as __adfCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __adfFileURLToPath } from 'node:url';
3
+ import { dirname as __adfDirname } from 'node:path';
4
+ const require = __adfCreateRequire(import.meta.url);
5
+ const __filename = __adfFileURLToPath(import.meta.url);
6
+ const __dirname = __adfDirname(__filename);
7
+ import {
8
+ readLocalProof
9
+ } from "./chunk-UEZR2CNS.mjs";
10
+ import {
11
+ daemonSettingsDir,
12
+ readDaemonToken
13
+ } from "./chunk-IHDDCZBS.mjs";
14
+ import {
15
+ __export
16
+ } from "./chunk-M2RX3S2T.mjs";
17
+
18
+ // src/main/cli/daemon-url.ts
19
+ var daemon_url_exports = {};
20
+ __export(daemon_url_exports, {
21
+ DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
22
+ DEFAULT_DAEMON_URL: () => DEFAULT_DAEMON_URL,
23
+ isLocalDaemonUrl: () => isLocalDaemonUrl,
24
+ isLocalOnlyRoute: () => isLocalOnlyRoute,
25
+ localDaemonToken: () => localDaemonToken,
26
+ localProofHeaders: () => localProofHeaders,
27
+ loopbackPort: () => loopbackPort,
28
+ resolveDaemonToken: () => resolveDaemonToken,
29
+ resolveDaemonUrl: () => resolveDaemonUrl,
30
+ tunnelTokenHint: () => tunnelTokenHint
31
+ });
32
+ import { readFileSync } from "node:fs";
33
+ import { join } from "node:path";
34
+ var DEFAULT_DAEMON_PORT = 7385, DEFAULT_DAEMON_URL = `http://127.0.0.1:${DEFAULT_DAEMON_PORT}`;
35
+ function resolveDaemonUrl(explicit, env = process.env) {
36
+ return (explicit ?? env.ADF_DAEMON_URL ?? DEFAULT_DAEMON_URL).replace(/\/+$/, "");
37
+ }
38
+ function loopbackPort(url) {
39
+ try {
40
+ let parsed = new URL(url), host = parsed.hostname.replace(/^\[|\]$/g, "").toLowerCase();
41
+ return host === "localhost" || host === "::1" || /^127\./.test(host) ? parsed.port ? Number(parsed.port) : parsed.protocol === "https:" ? 443 : 80 : null;
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+ function pidFileAlive(file) {
47
+ try {
48
+ let raw = readFileSync(file, "utf-8").trim(), pid = raw.startsWith("{") ? JSON.parse(raw).pid : Number.parseInt(raw, 10);
49
+ if (typeof pid != "number" || !Number.isFinite(pid) || pid <= 0) return !1;
50
+ try {
51
+ return process.kill(pid, 0), !0;
52
+ } catch (err) {
53
+ return err?.code === "EPERM";
54
+ }
55
+ } catch {
56
+ return !1;
57
+ }
58
+ }
59
+ function isLocalDaemonUrl(url, env = process.env) {
60
+ let port = loopbackPort(url);
61
+ return port === null ? !1 : port === DEFAULT_DAEMON_PORT || port === Number(env.ADF_DAEMON_PORT) ? !0 : pidFileAlive(join(daemonSettingsDir(env), `adf-daemon-${port}.pid`));
62
+ }
63
+ function localDaemonToken(url, env = process.env) {
64
+ if (isLocalDaemonUrl(url, env))
65
+ return readDaemonToken(daemonSettingsDir(env)) ?? void 0;
66
+ }
67
+ function tunnelTokenHint(url, explicit, env = process.env) {
68
+ return explicit || env.ADF_DAEMON_TOKEN || loopbackPort(url) === null || isLocalDaemonUrl(url, env) ? null : `${url} is not this machine's daemon port (${Number(env.ADF_DAEMON_PORT) || DEFAULT_DAEMON_PORT}; e.g. an SSH tunnel), so the local token is not sent there. Pass --token or set ADF_DAEMON_TOKEN to the remote daemon's token (print it on that host with: adf daemon token).`;
69
+ }
70
+ function resolveDaemonToken(explicit, env = process.env, url) {
71
+ let token = explicit ?? env.ADF_DAEMON_TOKEN;
72
+ return token || (url ? localDaemonToken(url, env) : void 0);
73
+ }
74
+ function isLocalOnlyRoute(path) {
75
+ let p = path.split("?")[0];
76
+ return p === "/daemon/shutdown" || /^\/identity\/(create|restore|unlock|lock|confirm-backup)$/.test(p);
77
+ }
78
+ function localProofHeaders(url, path, env = process.env) {
79
+ if (!isLocalOnlyRoute(path) || !isLocalDaemonUrl(url, env)) return {};
80
+ let proof = readLocalProof(daemonSettingsDir(env), loopbackPort(url) ?? DEFAULT_DAEMON_PORT);
81
+ return proof ? { "X-ADF-Local-Proof": proof } : {};
82
+ }
83
+
84
+ export {
85
+ DEFAULT_DAEMON_PORT,
86
+ DEFAULT_DAEMON_URL,
87
+ resolveDaemonUrl,
88
+ loopbackPort,
89
+ isLocalDaemonUrl,
90
+ tunnelTokenHint,
91
+ resolveDaemonToken,
92
+ localProofHeaders,
93
+ daemon_url_exports
94
+ };
@@ -13,7 +13,7 @@ import {
13
13
  MESSAGING_MODES,
14
14
  RESERVED_AGENT_PATH_SEGMENTS,
15
15
  START_IN_STATES
16
- } from "./chunk-WFQUVXML.mjs";
16
+ } from "./chunk-CD3ATSXE.mjs";
17
17
 
18
18
  // src/shared/types/umbilical-events.ts
19
19
  var UMBILICAL_EVENT_TYPES = [
@@ -30,6 +30,11 @@ var UMBILICAL_EVENT_TYPES = [
30
30
  "agent.credentials.unlocked",
31
31
  // --- turn --------------------------------------------------------------
32
32
  "turn.completed",
33
+ // --- owner chats queued behind a running turn ---------------------------
34
+ // delivered → put into a running turn (their ids complete with it);
35
+ // discarded → dropped undelivered by stop/unload/off (never silently).
36
+ "chat.delivered",
37
+ "chat.discarded",
33
38
  // --- tools -------------------------------------------------------------
34
39
  "tool.started",
35
40
  "tool.completed",
@@ -491,7 +496,7 @@ var StreamBindEndpointSchema = external_exports.union([
491
496
  }).optional(),
492
497
  fetch_middleware: external_exports.array(MiddlewareRefSchema).optional(),
493
498
  require_middleware_authorization: external_exports.boolean().default(!0),
494
- allow_local_fetch: external_exports.boolean().optional().describe("Opt out of the sys_fetch SSRF guard. When false/absent, sys_fetch refuses loopback, link-local and RFC1918/CGNAT destinations (including after DNS resolution and across redirects)."),
499
+ allow_local_fetch: external_exports.boolean().optional().describe("Allow sys_fetch/ws_connect to reach private (RFC1918) and CGNAT destinations. When false/absent those are refused, including after DNS resolution and across redirects. Loopback is allowed either way, except the local daemon control API; link-local and cloud-metadata addresses are always refused."),
495
500
  table_protections: external_exports.record(external_exports.enum(["none", "append_only", "authorized"])).optional()
496
501
  }),
497
502
  limits: external_exports.object({
@@ -268,7 +268,20 @@ function resultText(value) {
268
268
  }
269
269
  return value === void 0 ? void 0 : JSON.stringify(value);
270
270
  }
271
+ function markOwnTurns(items, event) {
272
+ let p = event.payload ?? {}, ids = (value) => Array.isArray(value) ? value.filter((id) => typeof id == "string") : [], terminal = event.event_type === "turn.completed" || event.event_type === "agent.error", absorbed = terminal ? ids(p.absorbed_turn_ids) : [], delivered = event.event_type === "chat.delivered" ? ids(p.turn_ids) : [], discarded = event.event_type === "chat.discarded" ? ids(p.turn_ids) : [], cutOff = event.event_type === "chat.discarded" ? ids(p.unanswered_turn_ids) : [];
273
+ if (!event.turn_id && absorbed.length + delivered.length + discarded.length + cutOff.length === 0) return items;
274
+ let answeredNow = event.event_type === "turn.completed" && p.interrupted !== !0, next = null;
275
+ for (let i = items.length - 1; i >= 0; i--) {
276
+ let item = items[i];
277
+ if (item.kind !== "user" || !item.turnId || item.answered) continue;
278
+ let patch = null;
279
+ absorbed.includes(item.turnId) ? patch = { taken: !0, answered: !0, pending: !1 } : discarded.includes(item.turnId) ? patch = { taken: !0, pending: !1, discarded: !0 } : cutOff.includes(item.turnId) ? patch = { taken: !0, pending: !1 } : delivered.includes(item.turnId) ? patch = item.taken ? null : { taken: !0 } : item.turnId === event.turn_id && (terminal ? patch = answeredNow ? { taken: !0, answered: !0, pending: !1 } : event.event_type === "agent.error" ? { taken: !0, pending: !1 } : null : item.taken || (patch = { taken: !0 })), patch && (next ??= items.slice(), next[i] = { ...item, ...patch });
280
+ }
281
+ return next ?? items;
282
+ }
271
283
  function applyEventToItems(items, event) {
284
+ items = markOwnTurns(items, event);
272
285
  let p = event.payload ?? {}, at = event.timestamp || Date.now();
273
286
  switch (event.event_type) {
274
287
  case "turn.delta": {
@@ -388,6 +401,10 @@ function noticeFor(event) {
388
401
  return { text: `Model call failed${p.model ? ` (${String(p.model)})` : ""}`, level: "warn" };
389
402
  case "error.recovery_suppressed":
390
403
  return { text: "Error recovery suppressed \u2014 triggers are being dropped", level: "warn" };
404
+ case "chat.discarded": {
405
+ let count = typeof p.count == "number" ? p.count : 0;
406
+ return count === 0 ? null : { text: `${count} queued message${count === 1 ? "" : "s"} discarded undelivered (${p.reason === "off" ? "agent turned off" : "agent stopped"})`, level: "warn" };
407
+ }
391
408
  default:
392
409
  return null;
393
410
  }
@@ -669,7 +686,9 @@ var TRANSCRIPT_EVENTS = /* @__PURE__ */ new Set([
669
686
  "provider.retry_scheduled",
670
687
  "provider.retry_cancelled",
671
688
  "llm.failed",
672
- "error.recovery_suppressed"
689
+ "error.recovery_suppressed",
690
+ "chat.delivered",
691
+ "chat.discarded"
673
692
  ]);
674
693
  function applyEvent(state, event) {
675
694
  let agentId = event.agent_id ?? null, loop = eventLoop(event), next = {
@@ -873,9 +892,9 @@ function serverText(server) {
873
892
  }
874
893
 
875
894
  // src/main/tui/state/store.tsx
876
- var import_jsx_runtime = __toESM(require_jsx_runtime(), 1), REFRESH_DEBOUNCE_MS = 120, WEB_EVENT_DEBOUNCE_MS = 900, WEB_POLL_MS = 2e4, TRACKED_POLL_MS = 15e3, FOLDER_OVERLAY = "fleet.track", PROMPT_PREFILL_KEY = "shell.prompt.prefill", CHAT_VIEW_ID = "chat";
895
+ var import_jsx_runtime = __toESM(require_jsx_runtime(), 1), REFRESH_DEBOUNCE_MS = 120, WEB_EVENT_DEBOUNCE_MS = 900, RESUME_VERDICT_MS = 1500, WEB_POLL_MS = 2e4, TRACKED_POLL_MS = 15e3, FOLDER_OVERLAY = "fleet.track", PROMPT_PREFILL_KEY = "shell.prompt.prefill", CHAT_VIEW_ID = "chat";
877
896
  function createTuiStore(options) {
878
- let client = options.client, pageSize = options.pageSize ?? 100, state = initialState(client.baseUrl, options.initialView), listeners = /* @__PURE__ */ new Set(), confirmResolvers = /* @__PURE__ */ new Map(), toastTimers = /* @__PURE__ */ new Map(), debounced = /* @__PURE__ */ new Map(), stream = null, webTick = null, trackedTick = null, stopped = !1, needsResync = !1, getState = () => state, dispatch = (action) => {
897
+ let client = options.client, pageSize = options.pageSize ?? 100, state = initialState(client.baseUrl, options.initialView), listeners = /* @__PURE__ */ new Set(), confirmResolvers = /* @__PURE__ */ new Map(), toastTimers = /* @__PURE__ */ new Map(), debounced = /* @__PURE__ */ new Map(), stream = null, webTick = null, trackedTick = null, stopped = !1, needsResync = !1, resumeFallback = null, getState = () => state, dispatch = (action) => {
879
898
  let next = tuiReducer(state, action);
880
899
  if (next !== state) {
881
900
  state = next;
@@ -1138,7 +1157,8 @@ function createTuiStore(options) {
1138
1157
  let loop = target.loop ?? selectedLoopOf(agentId), key = transcriptKey(agentId, loop), item = { id: localId(), at: Date.now(), local: !0, kind: "user", text: trimmed, origin: "owner", pending: !0 };
1139
1158
  dispatch({ type: "transcript/append", key, item });
1140
1159
  try {
1141
- return await client.chat(agentId, trimmed, loop), dispatch({ type: "transcript/update", key, id: item.id, patch: { accepted: !0 } }), !0;
1160
+ let accepted = await client.chat(agentId, trimmed, loop);
1161
+ return dispatch({ type: "transcript/update", key, id: item.id, patch: { accepted: !0, ...accepted?.turnId ? { turnId: accepted.turnId } : {} } }), !0;
1142
1162
  } catch (err) {
1143
1163
  return dispatch({ type: "transcript/update", key, id: item.id, patch: { pending: !1 } }), dispatch({ type: "transcript/append", key, item: { id: localId(), at: Date.now(), local: !0, kind: "error", text: `Not sent: ${describe(err)}` } }), !1;
1144
1164
  }
@@ -1369,7 +1389,16 @@ function createTuiStore(options) {
1369
1389
  options.live !== !1 && (stream = client.events({
1370
1390
  onEvent: onFrame,
1371
1391
  onState: (info) => {
1372
- dispatch({ type: "connection", info }), info.state === "reconnecting" && (needsResync = !0, info.error && dispatch({ type: "daemon/reachable", reachable: !1 })), info.state === "open" && (info.resumed || needsResync) && (needsResync = !1, toast(info.resumed ? "Reconnected to daemon \u2014 resyncing" : "Connected to daemon", "info", 2500), resync());
1392
+ dispatch({ type: "connection", info }), info.state === "reconnecting" && (needsResync = !0, info.error && dispatch({ type: "daemon/reachable", reachable: !1 })), info.state === "open" && info.resumed ? (needsResync = !1, resumeFallback && clearTimeout(resumeFallback), resumeFallback = setTimeout(() => {
1393
+ resumeFallback = null, toast("Reconnected to daemon \u2014 resyncing", "info", 2500), resync();
1394
+ }, RESUME_VERDICT_MS)) : info.state === "open" && needsResync && (needsResync = !1, toast("Connected to daemon", "info", 2500), resync());
1395
+ },
1396
+ onResume: (info) => {
1397
+ if (resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), info.exact) {
1398
+ toast("Reconnected to daemon \u2014 no events missed", "info", 2500), Promise.all([actions.refreshIdentity(), actions.refreshAuth(), actions.refreshAgents(), actions.refreshWeb()]);
1399
+ return;
1400
+ }
1401
+ toast(info.reason === "epoch_changed" ? "The daemon restarted \u2014 reloading" : "Events were missed while disconnected \u2014 reloading", "warn", 4e3), resync();
1373
1402
  }
1374
1403
  }).start(), webTick && clearInterval(webTick), webTick = setInterval(() => {
1375
1404
  stopped || actions.refreshWeb();
@@ -1385,7 +1414,7 @@ function createTuiStore(options) {
1385
1414
  }
1386
1415
  }
1387
1416
  function stop() {
1388
- stopped = !0, stream?.close(), stream = null, webTick && (clearInterval(webTick), webTick = null), trackedTick && (clearInterval(trackedTick), trackedTick = null), pendingFrames = [];
1417
+ stopped = !0, stream?.close(), stream = null, resumeFallback && (clearTimeout(resumeFallback), resumeFallback = null), webTick && (clearInterval(webTick), webTick = null), trackedTick && (clearInterval(trackedTick), trackedTick = null), pendingFrames = [];
1389
1418
  for (let timer of toastTimers.values()) clearTimeout(timer);
1390
1419
  for (let timer of debounced.values()) clearTimeout(timer);
1391
1420
  toastTimers.clear(), debounced.clear();
@@ -21,7 +21,7 @@ import {
21
21
  getCommand,
22
22
  notifyToolCallObservers,
23
23
  shellReadFile
24
- } from "./chunk-7MTRVW2U.mjs";
24
+ } from "./chunk-ZROSGV65.mjs";
25
25
 
26
26
  // src/main/tools/shell/executor/pipeline-executor.ts
27
27
  function vfsPath(p) {
@@ -0,0 +1,65 @@
1
+ import { createRequire as __adfCreateRequire } from 'node:module';
2
+ import { fileURLToPath as __adfFileURLToPath } from 'node:url';
3
+ import { dirname as __adfDirname } from 'node:path';
4
+ const require = __adfCreateRequire(import.meta.url);
5
+ const __filename = __adfFileURLToPath(import.meta.url);
6
+ const __dirname = __adfDirname(__filename);
7
+ import {
8
+ tokensEqual
9
+ } from "./chunk-IHDDCZBS.mjs";
10
+
11
+ // src/main/daemon/local-access.ts
12
+ import { chmodSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
13
+ import { join } from "node:path";
14
+ import { randomBytes } from "node:crypto";
15
+ var LOCAL_PROOF_FILENAME = "daemon-local-proof", LOCAL_PROOF_HEADER = "x-adf-local-proof", BEHIND_PROXY_ENV = "ADF_DAEMON_BEHIND_PROXY", PROXY_HEADERS = ["forwarded", "x-forwarded-for", "x-forwarded-host", "x-forwarded-proto", "x-real-ip", "via"];
16
+ function isLoopbackAddress(address) {
17
+ return address ? address === "::1" || address.startsWith("127.") || address.startsWith("::ffff:127.") : !1;
18
+ }
19
+ function hasProxyHeaders(headers) {
20
+ return PROXY_HEADERS.some((name) => headers[name] !== void 0);
21
+ }
22
+ function behindProxyFromEnv(env = process.env) {
23
+ return /^(1|true|yes|on)$/i.test((env[BEHIND_PROXY_ENV] ?? "").trim());
24
+ }
25
+ var DEFAULT_PORT = 7385;
26
+ function localProofPath(settingsDir, port = DEFAULT_PORT) {
27
+ return join(settingsDir, port === DEFAULT_PORT ? LOCAL_PROOF_FILENAME : `${LOCAL_PROOF_FILENAME}-${port}`);
28
+ }
29
+ function mintLocalProof(settingsDir, port = DEFAULT_PORT) {
30
+ mkdirSync(settingsDir, { recursive: !0 });
31
+ let proof = randomBytes(32).toString("base64url"), path = localProofPath(settingsDir, port);
32
+ writeFileSync(path, `${proof}
33
+ `, { mode: 384 });
34
+ try {
35
+ chmodSync(path, 384);
36
+ } catch {
37
+ }
38
+ return { proof, path };
39
+ }
40
+ function readLocalProof(settingsDir, port = DEFAULT_PORT) {
41
+ try {
42
+ let proof = readFileSync(localProofPath(settingsDir, port), "utf-8").trim();
43
+ return /^[A-Za-z0-9_-]{32,}$/.test(proof) ? proof : null;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+ function localAccessRefusal(request, opts) {
49
+ if (!isLoopbackAddress(request.remoteAddress)) return "the request did not come from this machine";
50
+ if (hasProxyHeaders(request.headers)) return "the request came through a proxy (forwarded headers)";
51
+ if (opts.behindProxy) {
52
+ let raw = request.headers[LOCAL_PROOF_HEADER], presented = (Array.isArray(raw) ? raw[0] : raw)?.trim();
53
+ if (!presented || !opts.localProof || !tokensEqual(presented, opts.localProof))
54
+ return `the daemon runs behind a proxy (${BEHIND_PROXY_ENV}) and the request lacks this machine's local proof`;
55
+ }
56
+ return null;
57
+ }
58
+
59
+ export {
60
+ BEHIND_PROXY_ENV,
61
+ behindProxyFromEnv,
62
+ mintLocalProof,
63
+ readLocalProof,
64
+ localAccessRefusal
65
+ };
@@ -7,7 +7,7 @@ const __dirname = __adfDirname(__filename);
7
7
  import {
8
8
  META_PROTECTION_LEVELS,
9
9
  SETTABLE_STATES
10
- } from "./chunk-WFQUVXML.mjs";
10
+ } from "./chunk-CD3ATSXE.mjs";
11
11
  import {
12
12
  __esm
13
13
  } from "./chunk-M2RX3S2T.mjs";
@@ -15,12 +15,19 @@ import {
15
15
  // src/main/runtime/execution-context.ts
16
16
  import { AsyncLocalStorage } from "node:async_hooks";
17
17
  function withSource(source, agentIdOrFn, maybeFn) {
18
- let agentId = typeof agentIdOrFn == "function" ? void 0 : agentIdOrFn, fn = typeof agentIdOrFn == "function" ? agentIdOrFn : maybeFn, parent = store.getStore(), loop = parent?.loop && (agentId === void 0 || agentId === parent.agentId) ? parent.loop : void 0;
19
- return store.run(loop ? { source, agentId, loop } : { source, agentId }, fn);
18
+ let agentId = typeof agentIdOrFn == "function" ? void 0 : agentIdOrFn, fn = typeof agentIdOrFn == "function" ? agentIdOrFn : maybeFn, parent = store.getStore(), sameAgent = agentId === void 0 || agentId === parent?.agentId, loop = parent?.loop && sameAgent ? parent.loop : void 0, turnId = parent?.turnId && sameAgent ? parent.turnId : void 0;
19
+ return store.run({ source, agentId, ...loop ? { loop } : {}, ...turnId ? { turnId } : {} }, fn);
20
20
  }
21
21
  function withLoop(loop, fn) {
22
22
  let parent = store.getStore();
23
- return store.run({ source: parent?.source ?? "system:unknown", agentId: parent?.agentId, loop }, fn);
23
+ return store.run({ ...parent, source: parent?.source ?? "system:unknown", agentId: parent?.agentId, loop }, fn);
24
+ }
25
+ function withTurn(turnId, fn) {
26
+ let parent = store.getStore();
27
+ return store.run({ ...parent, source: parent?.source ?? "system:unknown", turnId }, fn);
28
+ }
29
+ function currentTurnId() {
30
+ return store.getStore()?.turnId;
24
31
  }
25
32
  function currentLoop() {
26
33
  return store.getStore()?.loop;
@@ -1455,7 +1462,7 @@ var xargsHandler = {
1455
1462
  batchSize = n;
1456
1463
  }
1457
1464
  if (!text) return ok("");
1458
- let { parse } = await import("./parser-JVY2PWSM.mjs"), { executeNode } = await import("./pipeline-executor-BHBSJX2K.mjs"), subCtx = {
1465
+ let { parse } = await import("./parser-JVY2PWSM.mjs"), { executeNode } = await import("./pipeline-executor-U6IMCCP3.mjs"), subCtx = {
1459
1466
  workspace: ctx.workspace,
1460
1467
  toolRegistry: ctx.toolRegistry,
1461
1468
  config: ctx.config,
@@ -2275,7 +2282,7 @@ async function executeShellScript(path, ctx) {
2275
2282
  authorized = ctx.workspace.isFileAuthorized(path);
2276
2283
  } catch {
2277
2284
  }
2278
- let gate = { ...ctx.gate ?? {}, authorized }, base = baseRegistry(ctx.toolRegistry), toolRegistry = gate.authorized ? authorizedRegistry(base) : base, { parse } = await import("./parser-JVY2PWSM.mjs"), { executeNode, MAX_SHELL_DEPTH } = await import("./pipeline-executor-BHBSJX2K.mjs"), depth = (ctx.depth ?? 0) + 1;
2285
+ let gate = { ...ctx.gate ?? {}, authorized }, base = baseRegistry(ctx.toolRegistry), toolRegistry = gate.authorized ? authorizedRegistry(base) : base, { parse } = await import("./parser-JVY2PWSM.mjs"), { executeNode, MAX_SHELL_DEPTH } = await import("./pipeline-executor-U6IMCCP3.mjs"), depth = (ctx.depth ?? 0) + 1;
2279
2286
  if (depth > MAX_SHELL_DEPTH)
2280
2287
  return err(`./${path}: script nesting too deep (${MAX_SHELL_DEPTH}) \u2014 possible infinite recursion`);
2281
2288
  try {
@@ -3016,7 +3023,7 @@ var CATEGORY_ORDER = [
3016
3023
  resolvedTools: [],
3017
3024
  async execute(ctx) {
3018
3025
  if (ctx.args.length > 0) {
3019
- let { getCommand: getCommand2 } = await import("./commands-DTEKM4ZL.mjs"), handler = getCommand2(ctx.args[0]);
3026
+ let { getCommand: getCommand2 } = await import("./commands-XNJMCD5L.mjs"), handler = getCommand2(ctx.args[0]);
3020
3027
  return handler ? ok(handler.helpText) : ok(`Unknown command: ${ctx.args[0]}`);
3021
3028
  }
3022
3029
  let commands = getAllCommands(), grouped = /* @__PURE__ */ new Map();
@@ -3076,6 +3083,8 @@ function hasCommand(name) {
3076
3083
  export {
3077
3084
  withSource,
3078
3085
  withLoop,
3086
+ withTurn,
3087
+ currentTurnId,
3079
3088
  currentLoop,
3080
3089
  currentAgentId,
3081
3090
  currentSourceOrUnknown,