@slock-ai/daemon 0.55.2-alpha.0 → 0.55.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.
@@ -142,6 +142,10 @@ async function executeResponseRequest(url, init, {
142
142
  import { HttpsProxyAgent } from "https-proxy-agent";
143
143
  import { ProxyAgent } from "undici";
144
144
  var fetchDispatcherCache = /* @__PURE__ */ new Map();
145
+ function getFetchPreResponseTimeoutMs(env) {
146
+ const parsed = Number.parseInt(env.SLOCK_DAEMON_FETCH_PRE_RESPONSE_TIMEOUT_MS || "", 10);
147
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 3e4;
148
+ }
145
149
  function getDefaultPort(protocol) {
146
150
  switch (protocol) {
147
151
  case "https:":
@@ -196,24 +200,53 @@ function buildWebSocketOptions(wsUrl, env) {
196
200
  agent: new HttpsProxyAgent(proxyUrl)
197
201
  };
198
202
  }
199
- function buildFetchDispatcher(targetUrl, env) {
203
+ function resolveProxyUrl(targetUrl, env) {
200
204
  const proxyUrl = getProxyUrlForTarget(targetUrl, env);
201
205
  if (!proxyUrl) return void 0;
202
206
  if (shouldBypassProxy(targetUrl, env)) return void 0;
207
+ return proxyUrl;
208
+ }
209
+ function buildFetchDispatcher(targetUrl, env) {
210
+ const proxyUrl = resolveProxyUrl(targetUrl, env);
211
+ if (!proxyUrl) return void 0;
203
212
  const cached = fetchDispatcherCache.get(proxyUrl);
204
213
  if (cached) return cached;
205
- const dispatcher = new ProxyAgent(proxyUrl);
214
+ const timeoutMs = getFetchPreResponseTimeoutMs(env);
215
+ const dispatcher = new ProxyAgent({
216
+ uri: proxyUrl,
217
+ // All three are pre-response and body-agnostic (see getFetchPreResponseTimeoutMs):
218
+ // headersTimeout = headers-hang leg; requestTls.timeout = CONNECT-tunnel
219
+ // establish leg; connect.timeout = socket to the proxy itself (defensive).
220
+ connect: { timeout: timeoutMs },
221
+ requestTls: { timeout: timeoutMs },
222
+ headersTimeout: timeoutMs
223
+ });
206
224
  fetchDispatcherCache.set(proxyUrl, dispatcher);
207
225
  return dispatcher;
208
226
  }
227
+ function evictFetchDispatcher(targetUrl, env) {
228
+ const proxyUrl = resolveProxyUrl(targetUrl, env);
229
+ if (!proxyUrl) return false;
230
+ const cached = fetchDispatcherCache.get(proxyUrl);
231
+ if (!cached) return false;
232
+ fetchDispatcherCache.delete(proxyUrl);
233
+ void Promise.resolve().then(() => cached.close()).catch(() => cached.destroy?.(new Error("evicted"))).catch(() => {
234
+ });
235
+ return true;
236
+ }
209
237
 
210
238
  // src/daemonFetch.ts
211
239
  function withDaemonFetchProxy(input, init = {}, env = process.env) {
212
240
  const dispatcher = buildFetchDispatcher(input.toString(), env);
213
241
  return dispatcher ? { ...init, dispatcher } : init;
214
242
  }
215
- function daemonFetch(input, init, env = process.env) {
216
- return fetch(input, withDaemonFetchProxy(input, init, env));
243
+ async function daemonFetch(input, init, env = process.env) {
244
+ try {
245
+ return await fetch(input, withDaemonFetchProxy(input, init, env));
246
+ } catch (err) {
247
+ evictFetchDispatcher(input.toString(), env);
248
+ throw err;
249
+ }
217
250
  }
218
251
 
219
252
  export {
package/dist/cli/index.js CHANGED
@@ -1183,6 +1183,17 @@ var CHANNEL_MESSAGE_RE = new RegExp(
1183
1183
  "iu"
1184
1184
  );
1185
1185
 
1186
+ // ../shared/src/producerFactLineage.ts
1187
+ var PRODUCER_FACT_TEXT_LABEL = "producerFactId";
1188
+ function formatProducerFactLineageNote(producerFactId) {
1189
+ const id = normalizeProducerFactId(producerFactId);
1190
+ return id ? `
1191
+ Lineage: ${PRODUCER_FACT_TEXT_LABEL}=${id}.` : "";
1192
+ }
1193
+ function normalizeProducerFactId(producerFactId) {
1194
+ return typeof producerFactId === "string" ? producerFactId.trim() : "";
1195
+ }
1196
+
1186
1197
  // ../shared/src/tracing/index.ts
1187
1198
  var DEFAULT_TRACE_FLAGS = "00";
1188
1199
  var TRACE_ID_HEX_LENGTH2 = 32;
@@ -15904,37 +15915,148 @@ Your last read position: seq ${data.last_read_seq}. Use slock message read --cha
15904
15915
 
15905
15916
  ${formatted}${footer}`;
15906
15917
  }
15907
- function formatSearchTarget(result) {
15918
+ function renderSearchSource(result) {
15908
15919
  if (result.channelType === "thread") {
15909
15920
  const shortId = typeof result.channelName === "string" && result.channelName.startsWith("thread-") ? result.channelName.slice(7) : typeof result.threadId === "string" && result.threadId ? result.threadId.slice(0, 8) : result.channelName;
15910
15921
  if (result.parentChannelType === "dm") {
15911
- return `dm:@${result.parentChannelName}:${shortId}`;
15922
+ return `dm:${neutralizeSlockRefLiterals(result.parentChannelName ?? "unknown")}:${shortId}`;
15912
15923
  }
15913
- return `#${result.parentChannelName}:${shortId}`;
15924
+ return `thread:${neutralizeSlockRefLiterals(result.parentChannelName ?? "unknown")}:${shortId}`;
15914
15925
  }
15915
15926
  if (result.channelType === "dm") {
15916
- return `dm:@${result.channelName}`;
15927
+ return `dm:${neutralizeSlockRefLiterals(result.channelName ?? "unknown")}`;
15928
+ }
15929
+ return `channel:${neutralizeSlockRefLiterals(result.channelName ?? "unknown")}`;
15930
+ }
15931
+ var PREVIEW_BEFORE_CHARS = 80;
15932
+ var PREVIEW_AFTER_CHARS = 120;
15933
+ var PREVIEW_FALLBACK_CHARS = PREVIEW_BEFORE_CHARS + PREVIEW_AFTER_CHARS;
15934
+ function escapeRegExp(value) {
15935
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
15936
+ }
15937
+ function findSearchMatch(content, query) {
15938
+ const normalizedQuery = query.trim();
15939
+ if (!normalizedQuery) return null;
15940
+ const exactIndex = content.toLowerCase().indexOf(normalizedQuery.toLowerCase());
15941
+ if (exactIndex >= 0) {
15942
+ return { start: exactIndex, end: exactIndex + normalizedQuery.length };
15943
+ }
15944
+ const terms = normalizedQuery.match(/"([^"]+)"|\S+/g) ?? [];
15945
+ for (const rawTerm of terms) {
15946
+ const term = rawTerm.replace(/^"|"$/g, "").trim();
15947
+ if (!term) continue;
15948
+ const match = new RegExp(escapeRegExp(term), "i").exec(content);
15949
+ if (match?.index !== void 0) {
15950
+ return { start: match.index, end: match.index + match[0].length };
15951
+ }
15952
+ }
15953
+ return null;
15954
+ }
15955
+ function* findSlockRefLiteralRanges(content) {
15956
+ for (const match of content.matchAll(/\bdm:@[A-Za-z0-9][A-Za-z0-9_-]*/g)) {
15957
+ if (match.index !== void 0) yield { start: match.index, end: match.index + match[0].length };
15958
+ }
15959
+ for (const match of content.matchAll(/\btask #[0-9]+\b/g)) {
15960
+ if (match.index !== void 0) yield { start: match.index, end: match.index + match[0].length };
15961
+ }
15962
+ for (const match of content.matchAll(/(^|[\n\s([{"'`;])(@[A-Za-z0-9][A-Za-z0-9_-]*)/g)) {
15963
+ if (match.index === void 0) continue;
15964
+ const prefix = match[1] ?? "";
15965
+ const ref = match[2] ?? "";
15966
+ yield { start: match.index + prefix.length, end: match.index + prefix.length + ref.length };
15967
+ }
15968
+ for (const match of content.matchAll(/(^|[\n\s([{"'`;])(#[A-Za-z][A-Za-z0-9_-]*)/g)) {
15969
+ if (match.index === void 0) continue;
15970
+ const prefix = match[1] ?? "";
15971
+ const ref = match[2] ?? "";
15972
+ yield { start: match.index + prefix.length, end: match.index + prefix.length + ref.length };
15973
+ }
15974
+ }
15975
+ function expandSearchMatchToRefLiteral(content, match) {
15976
+ for (const refRange of findSlockRefLiteralRanges(content)) {
15977
+ if (match.start < refRange.end && match.end > refRange.start) {
15978
+ return {
15979
+ start: Math.min(match.start, refRange.start),
15980
+ end: Math.max(match.end, refRange.end)
15981
+ };
15982
+ }
15917
15983
  }
15918
- return `#${result.channelName}`;
15984
+ return match;
15985
+ }
15986
+ function trimPreviewWindow(content, start, end) {
15987
+ let trimmedStart = start;
15988
+ let trimmedEnd = end;
15989
+ while (trimmedStart > 0 && /\s/.test(content[trimmedStart] ?? "")) trimmedStart += 1;
15990
+ while (trimmedEnd < content.length && /\s/.test(content[trimmedEnd - 1] ?? "")) trimmedEnd -= 1;
15991
+ return {
15992
+ start: Math.max(0, Math.min(trimmedStart, content.length)),
15993
+ end: Math.max(0, Math.min(trimmedEnd, content.length))
15994
+ };
15995
+ }
15996
+ function escapeSearchComponentLiterals(text) {
15997
+ return text.replace(/<\/?(?:result|preview|match)\b[^>]*>|<omit\s*\/>/gi, (tag) => tag.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;"));
15998
+ }
15999
+ function neutralizeSlockRefLiterals(text) {
16000
+ return text.replace(/\bdm:@([A-Za-z0-9][A-Za-z0-9_-]*)/g, "dm:user:$1").replace(/\btask #([0-9]+)\b/g, "task:$1").replace(/(^|[\n\s([{"'`;])@([A-Za-z0-9][A-Za-z0-9_-]*)/g, "$1user:$2").replace(/(^|[\n\s([{"'`;])#([A-Za-z][A-Za-z0-9_-]*)/g, "$1channel:$2");
16001
+ }
16002
+ function renderPreviewText(text) {
16003
+ return neutralizeSlockRefLiterals(escapeSearchComponentLiterals(text));
16004
+ }
16005
+ function renderSearchPreview(content, query) {
16006
+ const foundMatch = findSearchMatch(content, query);
16007
+ const match = foundMatch ? expandSearchMatchToRefLiteral(content, foundMatch) : null;
16008
+ let start = 0;
16009
+ let end = Math.min(content.length, PREVIEW_FALLBACK_CHARS);
16010
+ if (match) {
16011
+ start = Math.max(0, match.start - PREVIEW_BEFORE_CHARS);
16012
+ end = Math.min(content.length, match.end + PREVIEW_AFTER_CHARS);
16013
+ }
16014
+ ({ start, end } = trimPreviewWindow(content, start, end));
16015
+ const leadingOmit = start > 0 ? "<omit />" : "";
16016
+ const trailingOmit = end < content.length ? "<omit />" : "";
16017
+ if (!match || match.end <= start || match.start >= end) {
16018
+ return `${leadingOmit}${renderPreviewText(content.slice(start, end))}${trailingOmit}`;
16019
+ }
16020
+ const before = content.slice(start, match.start);
16021
+ const matched = content.slice(match.start, match.end);
16022
+ const after = content.slice(match.end, end);
16023
+ return [
16024
+ leadingOmit,
16025
+ renderPreviewText(before),
16026
+ "<match>",
16027
+ renderPreviewText(matched),
16028
+ "</match>",
16029
+ renderPreviewText(after),
16030
+ trailingOmit
16031
+ ].join("");
15919
16032
  }
15920
16033
  function formatSearchResults(query, data) {
15921
16034
  if (!data.results || data.results.length === 0) return "No search results.";
15922
16035
  const formatted = data.results.map((result, index) => {
15923
- const target = formatSearchTarget(result);
15924
- const threadInfo = result.channelType === "thread" ? `
15925
- thread: ${result.parentChannelName} -> ${target}` : "";
16036
+ const ref = `msg:${result.id}`;
16037
+ const content = result.content ?? result.snippet ?? "";
16038
+ const sender = neutralizeSlockRefLiterals(result.senderName ?? "unknown");
16039
+ const senderType = result.senderType ? ` (${result.senderType})` : "";
15926
16040
  return [
15927
- `[${index + 1}] msg=${result.id} seq=${result.seq} time=${result.createdAt ? toLocalTime(result.createdAt) : "-"}`,
15928
- `target: ${target}${threadInfo}`,
15929
- `sender: @${result.senderName} (${result.senderType})`,
15930
- `content: ${result.content}`,
15931
- `match: ${result.snippet}`,
15932
- `next: slock message read --channel "${target}" --around "${result.id}" --limit 20`
16041
+ `<result ref="${ref}">`,
16042
+ `Source: ${renderSearchSource(result)}`,
16043
+ `Sender: ${sender}${senderType}`,
16044
+ `Time: ${result.createdAt ? toLocalTime(result.createdAt) : "-"}`,
16045
+ "",
16046
+ "<preview>",
16047
+ renderSearchPreview(content, query),
16048
+ "</preview>",
16049
+ "</result>"
15933
16050
  ].join("\n");
15934
16051
  }).join("\n\n");
15935
- return `## Search Results for "${query}" (${data.results.length} results)
15936
-
15937
- ${formatted}`;
16052
+ const resultLabel = data.results.length === 1 ? "result" : "results";
16053
+ return [
16054
+ `Search results for: "${query}" (${data.results.length} ${resultLabel})`,
16055
+ "",
16056
+ formatted,
16057
+ "",
16058
+ "If a result may be relevant but its preview is not enough, read the surrounding context for that result before answering."
16059
+ ].join("\n");
15938
16060
  }
15939
16061
 
15940
16062
  // src/commands/freshnessHold.ts
@@ -15952,9 +16074,10 @@ ${formatHistory(target, { messages: data.heldMessages })}` : "";
15952
16074
 
15953
16075
  Note: ${data.mentionAnnotation.formalMentionCount} of these messages formally @mention you.` : "";
15954
16076
  const omittedNote = omittedMessageCount > 0 ? ` ${omittedMessageCount} earlier same-target message${omittedMessageCount === 1 ? "" : "s"} omitted from this notice and no longer block this action; use slock message read explicitly if you need earlier context.` : "";
16077
+ const lineageNote = formatProducerFactLineageNote(data.producerFactId);
15955
16078
  const continueAnyway = data.continueAnywaySuggested && opts.continueAnywayInstruction ? opts.continueAnywayInstruction : "";
15956
16079
  return `Freshness hold: showing latest ${shownMessageCount} of ${newMessageCount} newer message${newMessageCount === 1 ? "" : "s"}.${omittedNote}
15957
- ${opts.heldAction} Review the bounded context shown here, then choose one path.${mentionNote}${heldHistory}
16080
+ ${opts.heldAction} Review the bounded context shown here, then choose one path.${lineageNote}${mentionNote}${heldHistory}
15958
16081
 
15959
16082
  ` + (opts.draftInstructions ?? "") + continueAnyway;
15960
16083
  }
@@ -17436,27 +17559,39 @@ function buildAgentAppUrl(returnUrl, requestId) {
17436
17559
  return null;
17437
17560
  }
17438
17561
  }
17562
+ function pushServiceBlock(lines, service, active) {
17563
+ lines.push(`- ${service.name}`);
17564
+ lines.push(` service: ${service.clientId}`);
17565
+ lines.push(` id: ${service.id}`);
17566
+ if (service.appType === "slock_builtin") lines.push(" type: built-in Slock app");
17567
+ lines.push(` status: ${active ? "active login" : "not logged in"}`);
17568
+ lines.push(` return URL: ${formatMaybe(service.returnUrl)}`);
17569
+ if (service.agentManifestUrl) {
17570
+ lines.push(` agent behavior manifest: ${service.agentManifestUrl}`);
17571
+ lines.push(` local CLI env: slock integration env --service ${JSON.stringify(service.clientId)}`);
17572
+ }
17573
+ if (service.homepageUrl) lines.push(` homepage: ${service.homepageUrl}`);
17574
+ if (service.description) lines.push(` description: ${service.description}`);
17575
+ if (!active) lines.push(` next: slock integration login --service ${JSON.stringify(service.clientId)}`);
17576
+ }
17439
17577
  function formatIntegrationList(data) {
17440
17578
  const activeByServiceId = new Map(data.activeLogins.map((login) => [login.serviceId, login]));
17579
+ const builtInServices = data.services.filter((service) => service.appType === "slock_builtin");
17580
+ const registeredServices = data.services.filter((service) => service.appType !== "slock_builtin");
17441
17581
  const lines = [];
17582
+ if (builtInServices.length > 0) {
17583
+ lines.push("Built-in Slock apps:");
17584
+ for (const service of builtInServices) {
17585
+ pushServiceBlock(lines, service, activeByServiceId.get(service.id));
17586
+ }
17587
+ lines.push("");
17588
+ }
17442
17589
  lines.push("Registered services:");
17443
- if (data.services.length === 0) {
17590
+ if (registeredServices.length === 0) {
17444
17591
  lines.push("- none");
17445
17592
  } else {
17446
- for (const service of data.services) {
17447
- const active = activeByServiceId.get(service.id);
17448
- lines.push(`- ${service.name}`);
17449
- lines.push(` service: ${service.clientId}`);
17450
- lines.push(` id: ${service.id}`);
17451
- lines.push(` status: ${active ? "active login" : "not logged in"}`);
17452
- lines.push(` return URL: ${formatMaybe(service.returnUrl)}`);
17453
- if (service.agentManifestUrl) {
17454
- lines.push(` agent behavior manifest: ${service.agentManifestUrl}`);
17455
- lines.push(` local CLI env: slock integration env --service ${JSON.stringify(service.clientId)}`);
17456
- }
17457
- if (service.homepageUrl) lines.push(` homepage: ${service.homepageUrl}`);
17458
- if (service.description) lines.push(` description: ${service.description}`);
17459
- if (!active) lines.push(` next: slock integration login --service ${JSON.stringify(service.clientId)}`);
17593
+ for (const service of registeredServices) {
17594
+ pushServiceBlock(lines, service, activeByServiceId.get(service.id));
17460
17595
  }
17461
17596
  }
17462
17597
  lines.push("");
@@ -17497,9 +17632,9 @@ function formatIntegrationLogin(data) {
17497
17632
  const agentAppUrl = buildAgentAppUrl(data.service.returnUrl, data.requestId);
17498
17633
  if (agentAppUrl) {
17499
17634
  lines.push(`app URL: ${agentAppUrl}`);
17500
- lines.push("next: open the app URL if you need the third-party app surface, or run `slock integration list` to confirm active login");
17635
+ lines.push("next: open the app URL if you need the service app surface, or run `slock integration list` to confirm active login");
17501
17636
  } else {
17502
- lines.push("next: use the registered service, or run `slock integration list` to confirm active login");
17637
+ lines.push("next: use the service, or run `slock integration list` to confirm active login");
17503
17638
  }
17504
17639
  return lines.join("\n");
17505
17640
  }
@@ -17508,7 +17643,7 @@ function formatIntegrationLogin(data) {
17508
17643
  var integrationListCommand = defineCommand(
17509
17644
  {
17510
17645
  name: "list",
17511
- description: "List registered third-party services and this agent's active logins",
17646
+ description: "List built-in Slock apps, registered services, and this agent's active logins",
17512
17647
  options: [{ flags: "--json", description: "Emit machine-readable JSON" }]
17513
17648
  },
17514
17649
  async (ctx, opts) => {
@@ -17548,7 +17683,7 @@ function normalizeScopes(raw) {
17548
17683
  var integrationLoginCommand = defineCommand(
17549
17684
  {
17550
17685
  name: "login",
17551
- description: "Provision or reuse this agent's login for a registered service",
17686
+ description: "Provision or reuse this agent's login for a built-in Slock app or registered service",
17552
17687
  options: [
17553
17688
  { flags: "--service <id>", description: "Registered service id, client id, or exact service name" },
17554
17689
  {
package/dist/core.js CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  resolveSlockCliPath,
10
10
  resolveWorkspaceDirectoryPath,
11
11
  scanWorkspaceDirectories
12
- } from "./chunk-QQRU3GA6.js";
12
+ } from "./chunk-DLB2KVD7.js";
13
13
  import {
14
14
  subscribeDaemonLogs
15
- } from "./chunk-VOZJ2ELH.js";
15
+ } from "./chunk-M2KQBJR3.js";
16
16
  export {
17
17
  DAEMON_CLI_USAGE,
18
18
  DaemonCore,
package/dist/index.js CHANGED
@@ -3,8 +3,8 @@ import {
3
3
  DAEMON_CLI_USAGE,
4
4
  DaemonCore,
5
5
  parseDaemonCliArgs
6
- } from "./chunk-QQRU3GA6.js";
7
- import "./chunk-VOZJ2ELH.js";
6
+ } from "./chunk-DLB2KVD7.js";
7
+ import "./chunk-M2KQBJR3.js";
8
8
 
9
9
  // src/index.ts
10
10
  var parsedArgs = parseDaemonCliArgs(process.argv.slice(2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slock-ai/daemon",
3
- "version": "0.55.2-alpha.0",
3
+ "version": "0.55.3",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "slock-daemon": "dist/index.js"