@slock-ai/daemon 0.48.0 → 0.49.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/index.js CHANGED
@@ -947,10 +947,10 @@ function mergeDefs(...defs) {
947
947
  function cloneDef(schema) {
948
948
  return mergeDefs(schema._zod.def);
949
949
  }
950
- function getElementAtPath(obj, path) {
951
- if (!path)
950
+ function getElementAtPath(obj, path2) {
951
+ if (!path2)
952
952
  return obj;
953
- return path.reduce((acc, key) => acc?.[key], obj);
953
+ return path2.reduce((acc, key) => acc?.[key], obj);
954
954
  }
955
955
  function promiseAllObject(promisesObj) {
956
956
  const keys = Object.keys(promisesObj);
@@ -1333,11 +1333,11 @@ function aborted(x, startIndex = 0) {
1333
1333
  }
1334
1334
  return false;
1335
1335
  }
1336
- function prefixIssues(path, issues) {
1336
+ function prefixIssues(path2, issues) {
1337
1337
  return issues.map((iss) => {
1338
1338
  var _a2;
1339
1339
  (_a2 = iss).path ?? (_a2.path = []);
1340
- iss.path.unshift(path);
1340
+ iss.path.unshift(path2);
1341
1341
  return iss;
1342
1342
  });
1343
1343
  }
@@ -1520,7 +1520,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
1520
1520
  }
1521
1521
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
1522
1522
  const result = { errors: [] };
1523
- const processError = (error49, path = []) => {
1523
+ const processError = (error49, path2 = []) => {
1524
1524
  var _a2, _b;
1525
1525
  for (const issue2 of error49.issues) {
1526
1526
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -1530,7 +1530,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1530
1530
  } else if (issue2.code === "invalid_element") {
1531
1531
  processError({ issues: issue2.issues }, issue2.path);
1532
1532
  } else {
1533
- const fullpath = [...path, ...issue2.path];
1533
+ const fullpath = [...path2, ...issue2.path];
1534
1534
  if (fullpath.length === 0) {
1535
1535
  result.errors.push(mapper(issue2));
1536
1536
  continue;
@@ -1562,8 +1562,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
1562
1562
  }
1563
1563
  function toDotPath(_path) {
1564
1564
  const segs = [];
1565
- const path = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1566
- for (const seg of path) {
1565
+ const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
1566
+ for (const seg of path2) {
1567
1567
  if (typeof seg === "number")
1568
1568
  segs.push(`[${seg}]`);
1569
1569
  else if (typeof seg === "symbol")
@@ -13540,13 +13540,13 @@ function resolveRef(ref, ctx) {
13540
13540
  if (!ref.startsWith("#")) {
13541
13541
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
13542
13542
  }
13543
- const path = ref.slice(1).split("/").filter(Boolean);
13544
- if (path.length === 0) {
13543
+ const path2 = ref.slice(1).split("/").filter(Boolean);
13544
+ if (path2.length === 0) {
13545
13545
  return ctx.rootSchema;
13546
13546
  }
13547
13547
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
13548
- if (path[0] === defsKey) {
13549
- const key = path[1];
13548
+ if (path2[0] === defsKey) {
13549
+ const key = path2[1];
13550
13550
  if (!key || !ctx.defs[key]) {
13551
13551
  throw new Error(`Reference not found: ${ref}`);
13552
13552
  }
@@ -14410,7 +14410,7 @@ function formatServerInfo(data) {
14410
14410
  const humans = data.humans ?? [];
14411
14411
  text += formatRuntimeContext(data.runtimeContext);
14412
14412
  text += "### Channels\n";
14413
- text += 'Visible public channels may appear even when `joined=false`. Private channels are shown only when you are a member; do not disclose private-channel names, membership, or content outside that channel. Use `slock message read --channel "#name"` to inspect visible channels. When a channel is not joined, you cannot send messages there or receive ordinary channel delivery until a human adds you to the channel. To leave a channel you have joined, use `slock channel leave --target "#name"`. To stop following a thread, use `slock thread unfollow --target "#name:shortid"`.\n';
14413
+ text += 'Visible public channels may appear even when `joined=false`. Private channels are shown only when you are a member; do not disclose private-channel names, membership, or content outside that channel. Use `slock message read --channel "#name"` to inspect visible channels. When a public channel is not joined, you can join it with `slock channel join --target "#name"` before sending messages or receiving ordinary channel delivery. Private channels require a human with access to add you. To leave a channel you have joined, use `slock channel leave --target "#name"`. To stop following a thread, use `slock thread unfollow --target "#name:shortid"`.\n';
14414
14414
  if (channels.length > 0) {
14415
14415
  for (const t of channels) {
14416
14416
  const visibility = t.type === "private" ? "private" : "public";
@@ -14507,36 +14507,6 @@ function registerChannelMembersCommand(parent) {
14507
14507
  });
14508
14508
  }
14509
14509
 
14510
- // src/commands/server/info.ts
14511
- function registerServerInfoCommand(parent) {
14512
- parent.command("info").description("List channels, agents, and humans on the current server").action(async () => {
14513
- let ctx;
14514
- try {
14515
- ctx = loadAgentContext();
14516
- } catch (err) {
14517
- if (err instanceof AgentBootstrapError) fail(err.code, err.message);
14518
- throw err;
14519
- }
14520
- const client = new ApiClient(ctx);
14521
- const res = await client.request(
14522
- "GET",
14523
- `/internal/agent/${encodeURIComponent(ctx.agentId)}/server`
14524
- );
14525
- if (!res.ok) {
14526
- const code = res.status >= 500 ? "SERVER_5XX" : "INFO_FAILED";
14527
- fail(code, res.error ?? `HTTP ${res.status}`);
14528
- }
14529
- const data = res.data;
14530
- if (data?.runtimeContext) {
14531
- data.runtimeContext = {
14532
- ...data.runtimeContext,
14533
- workspacePath: data.runtimeContext.workspacePath ?? process.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
14534
- };
14535
- }
14536
- process.stdout.write(formatServerInfo(data));
14537
- });
14538
- }
14539
-
14540
14510
  // src/commands/channel/leave.ts
14541
14511
  function parseRegularChannelTarget(target) {
14542
14512
  if (!target.startsWith("#")) return null;
@@ -14545,7 +14515,7 @@ function parseRegularChannelTarget(target) {
14545
14515
  return name.length > 0 ? name : null;
14546
14516
  }
14547
14517
  function formatLeaveChannelResult(target) {
14548
- return `Left ${target}. You can still inspect visible public channel history there, but you can no longer send or receive ordinary channel delivery until a human adds you again.`;
14518
+ return `Left ${target}. You can still inspect visible public channel history there, but you can no longer send or receive ordinary channel delivery until you join the public channel again or a human re-adds you to a private channel.`;
14549
14519
  }
14550
14520
  function formatAlreadyNotJoined(target) {
14551
14521
  return `Already not joined in ${target}.`;
@@ -14592,6 +14562,85 @@ function registerChannelLeaveCommand(parent) {
14592
14562
  });
14593
14563
  }
14594
14564
 
14565
+ // src/commands/channel/join.ts
14566
+ function formatJoinChannelResult(target) {
14567
+ return `Joined ${target}. You can now send messages there and receive ordinary channel delivery.`;
14568
+ }
14569
+ function formatAlreadyJoined(target) {
14570
+ return `Already joined ${target}.`;
14571
+ }
14572
+ function registerChannelJoinCommand(parent) {
14573
+ parent.command("join").description("Join a visible public channel").requiredOption("--target <target>", "Regular channel to join, e.g. '#engineering'").action(async (opts) => {
14574
+ const channelName = parseRegularChannelTarget(opts.target);
14575
+ if (!channelName) {
14576
+ fail("INVALID_TARGET", "Target must be a regular channel in the form '#channel-name'. DMs and thread targets are not supported.");
14577
+ }
14578
+ let ctx;
14579
+ try {
14580
+ ctx = loadAgentContext();
14581
+ } catch (err) {
14582
+ if (err instanceof AgentBootstrapError) fail(err.code, err.message);
14583
+ throw err;
14584
+ }
14585
+ const client = new ApiClient(ctx);
14586
+ const infoRes = await client.request(
14587
+ "GET",
14588
+ `/internal/agent/${encodeURIComponent(ctx.agentId)}/server`
14589
+ );
14590
+ if (!infoRes.ok) {
14591
+ const code = infoRes.status >= 500 ? "SERVER_5XX" : "INFO_FAILED";
14592
+ fail(code, infoRes.error ?? `HTTP ${infoRes.status}`);
14593
+ }
14594
+ const channel = (infoRes.data?.channels ?? []).find((candidate) => candidate.name === channelName);
14595
+ if (!channel) {
14596
+ fail("NOT_FOUND", `Channel not found: ${opts.target}`);
14597
+ }
14598
+ if (channel.joined) {
14599
+ process.stdout.write(formatAlreadyJoined(opts.target) + "\n");
14600
+ return;
14601
+ }
14602
+ const joinRes = await client.request(
14603
+ "POST",
14604
+ `/internal/agent/${encodeURIComponent(ctx.agentId)}/channels/${encodeURIComponent(channel.id)}/join`
14605
+ );
14606
+ if (!joinRes.ok) {
14607
+ const code = joinRes.status >= 500 ? "SERVER_5XX" : "JOIN_FAILED";
14608
+ fail(code, joinRes.error ?? `HTTP ${joinRes.status}`);
14609
+ }
14610
+ process.stdout.write(formatJoinChannelResult(opts.target) + "\n");
14611
+ });
14612
+ }
14613
+
14614
+ // src/commands/server/info.ts
14615
+ function registerServerInfoCommand(parent) {
14616
+ parent.command("info").description("List channels, agents, and humans on the current server").action(async () => {
14617
+ let ctx;
14618
+ try {
14619
+ ctx = loadAgentContext();
14620
+ } catch (err) {
14621
+ if (err instanceof AgentBootstrapError) fail(err.code, err.message);
14622
+ throw err;
14623
+ }
14624
+ const client = new ApiClient(ctx);
14625
+ const res = await client.request(
14626
+ "GET",
14627
+ `/internal/agent/${encodeURIComponent(ctx.agentId)}/server`
14628
+ );
14629
+ if (!res.ok) {
14630
+ const code = res.status >= 500 ? "SERVER_5XX" : "INFO_FAILED";
14631
+ fail(code, res.error ?? `HTTP ${res.status}`);
14632
+ }
14633
+ const data = res.data;
14634
+ if (data?.runtimeContext) {
14635
+ data.runtimeContext = {
14636
+ ...data.runtimeContext,
14637
+ workspacePath: data.runtimeContext.workspacePath ?? process.env.SLOCK_CURRENT_WORKSPACE_PATH ?? null
14638
+ };
14639
+ }
14640
+ process.stdout.write(formatServerInfo(data));
14641
+ });
14642
+ }
14643
+
14595
14644
  // src/commands/thread/unfollow.ts
14596
14645
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
14597
14646
  var SHORT_ID_RE = /^[0-9a-f]{8}$/i;
@@ -14644,6 +14693,69 @@ function registerThreadUnfollowCommand(parent) {
14644
14693
  });
14645
14694
  }
14646
14695
 
14696
+ // src/commands/message/_continueDraftState.ts
14697
+ import fs2 from "fs";
14698
+ import os from "os";
14699
+ import path from "path";
14700
+ var DEFAULT_LOCAL_DRAFT_TTL_MS = 10 * 60 * 1e3;
14701
+ function stateFilePath(agentId) {
14702
+ return path.join(process.env.SLOCK_CLI_DRAFT_STATE_DIR ?? os.tmpdir(), "slock-cli-attested-send", agentId, "continue-state.json");
14703
+ }
14704
+ function readState(agentId) {
14705
+ const filePath = stateFilePath(agentId);
14706
+ try {
14707
+ const raw = fs2.readFileSync(filePath, "utf8");
14708
+ const parsed = JSON.parse(raw);
14709
+ return typeof parsed === "object" && parsed ? parsed : {};
14710
+ } catch {
14711
+ return {};
14712
+ }
14713
+ }
14714
+ function writeState(agentId, state) {
14715
+ const filePath = stateFilePath(agentId);
14716
+ fs2.mkdirSync(path.dirname(filePath), { recursive: true });
14717
+ fs2.writeFileSync(filePath, JSON.stringify(state), "utf8");
14718
+ }
14719
+ function getSavedDraft(agentId, target) {
14720
+ const state = readState(agentId);
14721
+ const draft = state.targets?.[target];
14722
+ if (!draft || typeof draft === "string") return null;
14723
+ if (typeof draft.content !== "string") return null;
14724
+ const attachmentIds = Array.isArray(draft.attachmentIds) ? draft.attachmentIds.filter((item) => typeof item === "string") : [];
14725
+ const savedAt = Number.isFinite(draft.savedAt) ? draft.savedAt : Date.now();
14726
+ const reholdCount = Number.isFinite(draft.reholdCount) ? draft.reholdCount : 0;
14727
+ const seenUpToSeq = Number.isFinite(draft.seenUpToSeq) ? draft.seenUpToSeq : void 0;
14728
+ if (Date.now() - savedAt > DEFAULT_LOCAL_DRAFT_TTL_MS) {
14729
+ clearSavedDraft(agentId, target);
14730
+ return null;
14731
+ }
14732
+ return {
14733
+ content: draft.content,
14734
+ attachmentIds,
14735
+ savedAt,
14736
+ reholdCount,
14737
+ seenUpToSeq
14738
+ };
14739
+ }
14740
+ function setSavedDraft(agentId, target, draft) {
14741
+ const state = readState(agentId);
14742
+ const targets = state.targets ?? {};
14743
+ targets[target] = {
14744
+ content: draft.content,
14745
+ attachmentIds: draft.attachmentIds,
14746
+ savedAt: draft.savedAt,
14747
+ reholdCount: draft.reholdCount,
14748
+ ...draft.seenUpToSeq !== void 0 ? { seenUpToSeq: draft.seenUpToSeq } : {}
14749
+ };
14750
+ writeState(agentId, { targets });
14751
+ }
14752
+ function clearSavedDraft(agentId, target) {
14753
+ const state = readState(agentId);
14754
+ if (!state.targets || !(target in state.targets)) return;
14755
+ delete state.targets[target];
14756
+ writeState(agentId, state);
14757
+ }
14758
+
14647
14759
  // src/commands/message/_format.ts
14648
14760
  function toLocalTime(iso) {
14649
14761
  const d = new Date(iso);
@@ -14811,6 +14923,13 @@ async function resolveSendContent(input = process.stdin) {
14811
14923
  }
14812
14924
  return content;
14813
14925
  }
14926
+ async function resolveOptionalSendContent(input = process.stdin) {
14927
+ if (input.isTTY) {
14928
+ return void 0;
14929
+ }
14930
+ const content = await readStream2(input);
14931
+ return content.trim().length > 0 ? content : void 0;
14932
+ }
14814
14933
  function rejectArgContent(positionalContent, opts) {
14815
14934
  if (positionalContent.length > 0) {
14816
14935
  throw new SendContentError(
@@ -14835,8 +14954,35 @@ function rejectArgContent(positionalContent, opts) {
14835
14954
  );
14836
14955
  }
14837
14956
  }
14957
+ function validateDraftSendFlags(opts) {
14958
+ if (opts.anyway && !opts.sendDraft) {
14959
+ throw new SendContentError(
14960
+ "SEND_DRAFT_ANYWAY_REQUIRES_SEND_DRAFT",
14961
+ "--anyway can only be used together with --send-draft."
14962
+ );
14963
+ }
14964
+ if (opts.sendDraft && opts.attachmentId && opts.attachmentId.length > 0) {
14965
+ throw new SendContentError(
14966
+ "SEND_DRAFT_ATTACHMENTS_UNSUPPORTED",
14967
+ "--attachment-id cannot be used with --send-draft. Use a normal send to replace the draft."
14968
+ );
14969
+ }
14970
+ }
14971
+ function rejectSendDraftStdin(content, target) {
14972
+ if (content === void 0) return;
14973
+ throw new SendContentError(
14974
+ "SEND_DRAFT_STDIN_UNSUPPORTED",
14975
+ [
14976
+ "--send-draft sends the current saved draft and does not accept stdin.",
14977
+ "To update the draft, send the revised content normally without --send-draft:",
14978
+ ` slock message send --target "${target}" <<'EOF'`,
14979
+ " revised message",
14980
+ " EOF"
14981
+ ].join("\n")
14982
+ );
14983
+ }
14838
14984
  function registerSendCommand(parent) {
14839
- parent.command("send").description("Send a message to a channel, DM, or thread").argument("[content...]", "Unsupported positional message content. Pipe content to stdin instead.").requiredOption("--target <target>", "Target: '#channel', 'dm:@peer', '#channel:threadId', 'dm:@peer:threadId'").option("--content <content>", "Unsupported. Pipe message content to stdin instead.").option(
14985
+ parent.command("send").description("Send a message to a channel, DM, or thread").argument("[content...]", "Unsupported positional message content. Pipe content to stdin instead.").requiredOption("--target <target>", "Target: '#channel', 'dm:@peer', '#channel:threadId', 'dm:@peer:threadId'").option("--send-draft", "Send the current saved draft after reviewing newer messages").option("--anyway", "Escape hatch: send a saved draft even if freshness re-check is still stale").option("--content <content>", "Unsupported. Pipe message content to stdin instead.").option(
14840
14986
  "--attachment-id <id>",
14841
14987
  "Attachment id to link (repeatable). Get one from `slock attachment upload`.",
14842
14988
  (value, prev = []) => prev.concat(value)
@@ -14855,16 +15001,72 @@ function registerSendCommand(parent) {
14855
15001
  throw err;
14856
15002
  }
14857
15003
  const client = new ApiClient(ctx);
14858
- let content;
14859
15004
  try {
14860
- content = await resolveSendContent();
15005
+ validateDraftSendFlags(opts);
14861
15006
  } catch (err) {
14862
15007
  if (err instanceof SendContentError) fail(err.code, err.message);
14863
15008
  throw err;
14864
15009
  }
14865
- const body = { target: opts.target, content };
14866
- if (opts.attachmentId && opts.attachmentId.length > 0) {
14867
- body.attachmentIds = opts.attachmentId;
15010
+ let content;
15011
+ let outgoingContent;
15012
+ let outgoingAttachmentIds = [];
15013
+ let previousDraftReholdCount = 0;
15014
+ let seenUpToSeq;
15015
+ if (opts.sendDraft) {
15016
+ content = await resolveOptionalSendContent();
15017
+ try {
15018
+ rejectSendDraftStdin(content, opts.target);
15019
+ } catch (err) {
15020
+ if (err instanceof SendContentError) fail(err.code, err.message);
15021
+ throw err;
15022
+ }
15023
+ const savedDraft = getSavedDraft(ctx.agentId, opts.target);
15024
+ if (!savedDraft) {
15025
+ fail(
15026
+ "SEND_DRAFT_NOT_FOUND",
15027
+ [
15028
+ "No saved draft exists for this target.",
15029
+ "To create or update a draft, send message content normally:",
15030
+ ` slock message send --target "${opts.target}" <<'EOF'`,
15031
+ " message body",
15032
+ " EOF"
15033
+ ].join("\n")
15034
+ );
15035
+ return;
15036
+ }
15037
+ outgoingContent = savedDraft.content;
15038
+ outgoingAttachmentIds = savedDraft.attachmentIds;
15039
+ previousDraftReholdCount = savedDraft.reholdCount;
15040
+ seenUpToSeq = savedDraft.seenUpToSeq;
15041
+ } else {
15042
+ try {
15043
+ content = await resolveSendContent();
15044
+ } catch (err) {
15045
+ if (err instanceof SendContentError) fail(err.code, err.message);
15046
+ throw err;
15047
+ }
15048
+ outgoingContent = content;
15049
+ outgoingAttachmentIds = opts.attachmentId && opts.attachmentId.length > 0 ? opts.attachmentId : [];
15050
+ const previousDraft = getSavedDraft(ctx.agentId, opts.target);
15051
+ previousDraftReholdCount = previousDraft?.reholdCount ?? 0;
15052
+ seenUpToSeq = previousDraft?.seenUpToSeq;
15053
+ }
15054
+ const body = {
15055
+ target: opts.target,
15056
+ content: outgoingContent,
15057
+ draftReholdCount: previousDraftReholdCount
15058
+ };
15059
+ if (seenUpToSeq !== void 0) {
15060
+ body.seenUpToSeq = seenUpToSeq;
15061
+ }
15062
+ if (opts.sendDraft) {
15063
+ body.sendDraft = true;
15064
+ if (opts.anyway) body.continueAnyway = true;
15065
+ } else {
15066
+ body.draftReplacedExisting = previousDraftReholdCount > 0;
15067
+ }
15068
+ if (outgoingAttachmentIds.length > 0) {
15069
+ body.attachmentIds = outgoingAttachmentIds;
14868
15070
  }
14869
15071
  const res = await client.request(
14870
15072
  "POST",
@@ -14876,6 +15078,37 @@ function registerSendCommand(parent) {
14876
15078
  fail(code, res.error ?? `HTTP ${res.status}`);
14877
15079
  }
14878
15080
  const data = res.data;
15081
+ if (data.state === "held") {
15082
+ setSavedDraft(ctx.agentId, opts.target, {
15083
+ content: outgoingContent,
15084
+ attachmentIds: outgoingAttachmentIds,
15085
+ savedAt: Date.now(),
15086
+ reholdCount: previousDraftReholdCount + 1,
15087
+ seenUpToSeq: data.seenUpToSeq
15088
+ });
15089
+ const heldHistory = data.heldMessages && data.heldMessages.length > 0 ? `
15090
+
15091
+ ${formatHistory(opts.target, { messages: data.heldMessages })}` : "";
15092
+ const mentionNote = (data.mentionAnnotation?.formalMentionCount ?? 0) > 0 ? `
15093
+
15094
+ Note: ${data.mentionAnnotation.formalMentionCount} of these messages formally @mention you.` : "";
15095
+ process.stdout.write(
15096
+ `Not sent yet \u2014 ${data.newMessageCount ?? 0} newer message(s) arrived.
15097
+ Your message has been saved as a draft. Read the new messages below, then choose one path.${mentionNote}${heldHistory}
15098
+
15099
+ To update the draft, send revised content normally:
15100
+ slock message send --target "${opts.target}" <<'EOF'
15101
+ revised message
15102
+ EOF
15103
+ To send the current draft unchanged:
15104
+ slock message send --send-draft --target "${opts.target}"
15105
+ ` + (data.continueAnywaySuggested ? `If repeated updates keep blocking the same draft and this is still the right reply, you may use:
15106
+ slock message send --send-draft --anyway --target "${opts.target}"
15107
+ ` : "")
15108
+ );
15109
+ return;
15110
+ }
15111
+ clearSavedDraft(ctx.agentId, opts.target);
14879
15112
  const shortId = data.messageId ? data.messageId.slice(0, 8) : null;
14880
15113
  const replyHint = shortId ? ` (to reply in this message's thread, use target "${opts.target.includes(":") ? opts.target : opts.target + ":" + shortId}")` : "";
14881
15114
  let unreadSection = "";
@@ -14898,8 +15131,8 @@ async function drainInbox(ctx, opts) {
14898
15131
  const query = [];
14899
15132
  if (opts.block) query.push("block=true");
14900
15133
  if (opts.block && opts.timeoutMs !== void 0) query.push(`timeout=${opts.timeoutMs}`);
14901
- const path = query.length > 0 ? `${agentPath}/receive?${query.join("&")}` : `${agentPath}/receive`;
14902
- const res = await client.request("GET", path);
15134
+ const path2 = query.length > 0 ? `${agentPath}/receive?${query.join("&")}` : `${agentPath}/receive`;
15135
+ const res = await client.request("GET", path2);
14903
15136
  if (!res.ok) {
14904
15137
  const code = res.status >= 500 ? "SERVER_5XX" : failCode;
14905
15138
  fail(code, res.error ?? `HTTP ${res.status}`);
@@ -16097,6 +16330,7 @@ var authCmd = program.command("auth").description("Auth introspection");
16097
16330
  registerWhoamiCommand(authCmd);
16098
16331
  var channelCmd = program.command("channel").description("Channel membership operations");
16099
16332
  registerChannelMembersCommand(channelCmd);
16333
+ registerChannelJoinCommand(channelCmd);
16100
16334
  registerChannelLeaveCommand(channelCmd);
16101
16335
  var threadCmd = program.command("thread").description("Thread attention operations");
16102
16336
  registerThreadUnfollowCommand(threadCmd);
package/dist/core.js CHANGED
@@ -9,10 +9,10 @@ import {
9
9
  resolveSlockCliPath,
10
10
  resolveWorkspaceDirectoryPath,
11
11
  scanWorkspaceDirectories
12
- } from "./chunk-EDE2E6QR.js";
12
+ } from "./chunk-M4A5QPUN.js";
13
13
  import {
14
14
  subscribeDaemonLogs
15
- } from "./chunk-B7XIMLOT.js";
15
+ } from "./chunk-KNMCE6WB.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-EDE2E6QR.js";
7
- import "./chunk-B7XIMLOT.js";
6
+ } from "./chunk-M4A5QPUN.js";
7
+ import "./chunk-KNMCE6WB.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.48.0",
3
+ "version": "0.49.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "slock-daemon": "dist/index.js"