svamp-cli 0.2.8 → 0.2.9

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.
@@ -148,7 +148,7 @@ async function sessionBroadcast(action, args) {
148
148
  console.log(`Broadcast sent: ${action}`);
149
149
  }
150
150
  async function connectToMachineService() {
151
- const { connectAndGetMachine } = await import('./commands-DXaH6BQg.mjs');
151
+ const { connectAndGetMachine } = await import('./commands-h1lFrJKK.mjs');
152
152
  return connectAndGetMachine();
153
153
  }
154
154
  async function inboxSend(targetSessionId, opts) {
@@ -165,7 +165,7 @@ async function inboxSend(targetSessionId, opts) {
165
165
  }
166
166
  const { server, machine } = await connectToMachineService();
167
167
  try {
168
- const { resolveSessionId } = await import('./commands-DXaH6BQg.mjs');
168
+ const { resolveSessionId } = await import('./commands-h1lFrJKK.mjs');
169
169
  const sessions = await machine.listSessions();
170
170
  const match = resolveSessionId(sessions, targetSessionId);
171
171
  const fullTargetId = match.sessionId;
package/dist/cli.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-CAcScbEG.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-IDo93bqK.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -231,7 +231,7 @@ async function main() {
231
231
  console.error("svamp serve: Serve commands are not available in sandboxed sessions.");
232
232
  process.exit(1);
233
233
  }
234
- const { handleServeCommand } = await import('./serveCommands-Dr9CAgHo.mjs');
234
+ const { handleServeCommand } = await import('./serveCommands-BguUrQAM.mjs');
235
235
  await handleServeCommand();
236
236
  process.exit(0);
237
237
  } else if (subcommand === "process" || subcommand === "proc") {
@@ -240,7 +240,7 @@ async function main() {
240
240
  console.error("svamp process: Process commands are not available in sandboxed sessions.");
241
241
  process.exit(1);
242
242
  }
243
- const { processCommand } = await import('./commands-CAGeQm5f.mjs');
243
+ const { processCommand } = await import('./commands-C1xgznG4.mjs');
244
244
  let machineId;
245
245
  const processArgs = args.slice(1);
246
246
  const mIdx = processArgs.findIndex((a) => a === "--machine" || a === "-m");
@@ -258,7 +258,7 @@ async function main() {
258
258
  } else if (!subcommand || subcommand === "start") {
259
259
  await handleInteractiveCommand();
260
260
  } else if (subcommand === "--version" || subcommand === "-v") {
261
- const pkg = await import('./package-BMEGmZWU.mjs').catch(() => ({ default: { version: "unknown" } }));
261
+ const pkg = await import('./package-Bx_FLMjC.mjs').catch(() => ({ default: { version: "unknown" } }));
262
262
  console.log(`svamp version: ${pkg.default.version}`);
263
263
  } else {
264
264
  console.error(`Unknown command: ${subcommand}`);
@@ -267,7 +267,7 @@ async function main() {
267
267
  }
268
268
  }
269
269
  async function handleInteractiveCommand() {
270
- const { runInteractive } = await import('./run-B3G5eZmn.mjs');
270
+ const { runInteractive } = await import('./run-wHgMyNHQ.mjs');
271
271
  const interactiveArgs = subcommand === "start" ? args.slice(1) : args;
272
272
  let directory = process.cwd();
273
273
  let resumeSessionId;
@@ -312,7 +312,7 @@ async function handleAgentCommand() {
312
312
  return;
313
313
  }
314
314
  if (agentArgs[0] === "list") {
315
- const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.i; });
315
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.i; });
316
316
  console.log("Known agents:");
317
317
  for (const [name, config2] of Object.entries(KNOWN_ACP_AGENTS)) {
318
318
  console.log(` ${name.padEnd(12)} ${config2.command} ${config2.args.join(" ")} (ACP)`);
@@ -324,7 +324,7 @@ async function handleAgentCommand() {
324
324
  console.log('Use "svamp agent -- <command> [args]" for a custom ACP agent.');
325
325
  return;
326
326
  }
327
- const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.i; });
327
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.i; });
328
328
  let cwd = process.cwd();
329
329
  const filteredArgs = [];
330
330
  for (let i = 0; i < agentArgs.length; i++) {
@@ -348,12 +348,12 @@ async function handleAgentCommand() {
348
348
  console.log(`Starting ${config.agentName} agent in ${cwd}...`);
349
349
  let backend;
350
350
  if (KNOWN_MCP_AGENTS[config.agentName]) {
351
- const { CodexMcpBackend } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.j; });
351
+ const { CodexMcpBackend } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.j; });
352
352
  backend = new CodexMcpBackend({ cwd, log: logFn });
353
353
  } else {
354
- const { AcpBackend } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.h; });
355
- const { GeminiTransport } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.G; });
356
- const { DefaultTransport } = await import('./run-CAcScbEG.mjs').then(function (n) { return n.D; });
354
+ const { AcpBackend } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.h; });
355
+ const { GeminiTransport } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.G; });
356
+ const { DefaultTransport } = await import('./run-IDo93bqK.mjs').then(function (n) { return n.D; });
357
357
  const transportHandler = config.agentName === "gemini" ? new GeminiTransport() : new DefaultTransport(config.agentName);
358
358
  backend = new AcpBackend({
359
359
  agentName: config.agentName,
@@ -480,7 +480,7 @@ async function handleSessionCommand() {
480
480
  process.exit(1);
481
481
  }
482
482
  }
483
- const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-DXaH6BQg.mjs');
483
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-h1lFrJKK.mjs');
484
484
  const parseFlagStr = (flag, shortFlag) => {
485
485
  for (let i = 1; i < sessionArgs.length; i++) {
486
486
  if ((sessionArgs[i] === flag || shortFlag) && i + 1 < sessionArgs.length) {
@@ -540,7 +540,7 @@ async function handleSessionCommand() {
540
540
  allowDomain.push(sessionArgs[++i]);
541
541
  }
542
542
  }
543
- const { parseShareArg } = await import('./commands-DXaH6BQg.mjs');
543
+ const { parseShareArg } = await import('./commands-h1lFrJKK.mjs');
544
544
  const shareEntries = share.map((s) => parseShareArg(s));
545
545
  await sessionSpawn(agent, dir, targetMachineId, {
546
546
  message,
@@ -626,7 +626,7 @@ async function handleSessionCommand() {
626
626
  console.error("Usage: svamp session approve <session-id> [request-id] [--json]");
627
627
  process.exit(1);
628
628
  }
629
- const { sessionApprove } = await import('./commands-DXaH6BQg.mjs');
629
+ const { sessionApprove } = await import('./commands-h1lFrJKK.mjs');
630
630
  const approveReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
631
631
  await sessionApprove(sessionArgs[1], approveReqId, targetMachineId, {
632
632
  json: hasFlag("--json")
@@ -636,7 +636,7 @@ async function handleSessionCommand() {
636
636
  console.error("Usage: svamp session deny <session-id> [request-id] [--json]");
637
637
  process.exit(1);
638
638
  }
639
- const { sessionDeny } = await import('./commands-DXaH6BQg.mjs');
639
+ const { sessionDeny } = await import('./commands-h1lFrJKK.mjs');
640
640
  const denyReqId = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
641
641
  await sessionDeny(sessionArgs[1], denyReqId, targetMachineId, {
642
642
  json: hasFlag("--json")
@@ -672,7 +672,7 @@ async function handleSessionCommand() {
672
672
  console.error("Usage: svamp session set-title <title>");
673
673
  process.exit(1);
674
674
  }
675
- const { sessionSetTitle } = await import('./agentCommands-BBTwxjv1.mjs');
675
+ const { sessionSetTitle } = await import('./agentCommands-CrfvZzCn.mjs');
676
676
  await sessionSetTitle(title);
677
677
  } else if (sessionSubcommand === "set-link") {
678
678
  const url = sessionArgs[1];
@@ -681,7 +681,7 @@ async function handleSessionCommand() {
681
681
  process.exit(1);
682
682
  }
683
683
  const label = sessionArgs[2] && !sessionArgs[2].startsWith("--") ? sessionArgs[2] : void 0;
684
- const { sessionSetLink } = await import('./agentCommands-BBTwxjv1.mjs');
684
+ const { sessionSetLink } = await import('./agentCommands-CrfvZzCn.mjs');
685
685
  await sessionSetLink(url, label);
686
686
  } else if (sessionSubcommand === "notify") {
687
687
  const message = sessionArgs[1];
@@ -690,7 +690,7 @@ async function handleSessionCommand() {
690
690
  process.exit(1);
691
691
  }
692
692
  const level = parseFlagStr("--level") || "info";
693
- const { sessionNotify } = await import('./agentCommands-BBTwxjv1.mjs');
693
+ const { sessionNotify } = await import('./agentCommands-CrfvZzCn.mjs');
694
694
  await sessionNotify(message, level);
695
695
  } else if (sessionSubcommand === "broadcast") {
696
696
  const action = sessionArgs[1];
@@ -698,7 +698,7 @@ async function handleSessionCommand() {
698
698
  console.error("Usage: svamp session broadcast <action> [args...]\nActions: open-canvas <url> [label], close-canvas, toast <message>");
699
699
  process.exit(1);
700
700
  }
701
- const { sessionBroadcast } = await import('./agentCommands-BBTwxjv1.mjs');
701
+ const { sessionBroadcast } = await import('./agentCommands-CrfvZzCn.mjs');
702
702
  await sessionBroadcast(action, sessionArgs.slice(2).filter((a) => !a.startsWith("--")));
703
703
  } else if (sessionSubcommand === "inbox") {
704
704
  const inboxSubcmd = sessionArgs[1];
@@ -709,7 +709,7 @@ async function handleSessionCommand() {
709
709
  process.exit(1);
710
710
  }
711
711
  if (agentSessionId) {
712
- const { inboxSend } = await import('./agentCommands-BBTwxjv1.mjs');
712
+ const { inboxSend } = await import('./agentCommands-CrfvZzCn.mjs');
713
713
  await inboxSend(sessionArgs[2], {
714
714
  body: sessionArgs[3],
715
715
  subject: parseFlagStr("--subject"),
@@ -724,7 +724,7 @@ async function handleSessionCommand() {
724
724
  }
725
725
  } else if (inboxSubcmd === "list" || inboxSubcmd === "ls") {
726
726
  if (agentSessionId && !sessionArgs[2]) {
727
- const { inboxList } = await import('./agentCommands-BBTwxjv1.mjs');
727
+ const { inboxList } = await import('./agentCommands-CrfvZzCn.mjs');
728
728
  await inboxList({
729
729
  unread: hasFlag("--unread"),
730
730
  limit: parseFlagInt("--limit"),
@@ -746,7 +746,7 @@ async function handleSessionCommand() {
746
746
  process.exit(1);
747
747
  }
748
748
  if (agentSessionId && !sessionArgs[3]) {
749
- const { inboxList } = await import('./agentCommands-BBTwxjv1.mjs');
749
+ const { inboxList } = await import('./agentCommands-CrfvZzCn.mjs');
750
750
  await sessionInboxRead(agentSessionId, sessionArgs[2], targetMachineId);
751
751
  } else if (sessionArgs[3]) {
752
752
  await sessionInboxRead(sessionArgs[2], sessionArgs[3], targetMachineId);
@@ -756,7 +756,7 @@ async function handleSessionCommand() {
756
756
  }
757
757
  } else if (inboxSubcmd === "reply") {
758
758
  if (agentSessionId && sessionArgs[2] && sessionArgs[3] && !sessionArgs[4]) {
759
- const { inboxReply } = await import('./agentCommands-BBTwxjv1.mjs');
759
+ const { inboxReply } = await import('./agentCommands-CrfvZzCn.mjs');
760
760
  await inboxReply(sessionArgs[2], sessionArgs[3]);
761
761
  } else if (sessionArgs[2] && sessionArgs[3] && sessionArgs[4]) {
762
762
  await sessionInboxReply(sessionArgs[2], sessionArgs[3], sessionArgs[4], targetMachineId);
@@ -792,7 +792,7 @@ async function handleMachineCommand() {
792
792
  return;
793
793
  }
794
794
  if (machineSubcommand === "share") {
795
- const { machineShare } = await import('./commands-DXaH6BQg.mjs');
795
+ const { machineShare } = await import('./commands-h1lFrJKK.mjs');
796
796
  let machineId;
797
797
  const shareArgs = [];
798
798
  for (let i = 1; i < machineArgs.length; i++) {
@@ -822,7 +822,7 @@ async function handleMachineCommand() {
822
822
  }
823
823
  await machineShare(machineId, { add, remove, list, configPath, showConfig });
824
824
  } else if (machineSubcommand === "exec") {
825
- const { machineExec } = await import('./commands-DXaH6BQg.mjs');
825
+ const { machineExec } = await import('./commands-h1lFrJKK.mjs');
826
826
  let machineId;
827
827
  let cwd;
828
828
  const cmdParts = [];
@@ -842,7 +842,7 @@ async function handleMachineCommand() {
842
842
  }
843
843
  await machineExec(machineId, command, cwd);
844
844
  } else if (machineSubcommand === "info") {
845
- const { machineInfo } = await import('./commands-DXaH6BQg.mjs');
845
+ const { machineInfo } = await import('./commands-h1lFrJKK.mjs');
846
846
  let machineId;
847
847
  for (let i = 1; i < machineArgs.length; i++) {
848
848
  if ((machineArgs[i] === "--machine" || machineArgs[i] === "-m") && i + 1 < machineArgs.length) {
@@ -862,10 +862,10 @@ async function handleMachineCommand() {
862
862
  level = machineArgs[++i];
863
863
  }
864
864
  }
865
- const { machineNotify } = await import('./agentCommands-BBTwxjv1.mjs');
865
+ const { machineNotify } = await import('./agentCommands-CrfvZzCn.mjs');
866
866
  await machineNotify(message, level);
867
867
  } else if (machineSubcommand === "ls") {
868
- const { machineLs } = await import('./commands-DXaH6BQg.mjs');
868
+ const { machineLs } = await import('./commands-h1lFrJKK.mjs');
869
869
  let machineId;
870
870
  let showHidden = false;
871
871
  let path;
@@ -1,11 +1,11 @@
1
1
  import { writeFileSync, readFileSync } from 'fs';
2
2
  import { resolve } from 'path';
3
- import { connectAndGetMachine } from './commands-DXaH6BQg.mjs';
3
+ import { connectAndGetMachine } from './commands-h1lFrJKK.mjs';
4
4
  import 'node:fs';
5
5
  import 'node:child_process';
6
6
  import 'node:path';
7
7
  import 'node:os';
8
- import './run-CAcScbEG.mjs';
8
+ import './run-IDo93bqK.mjs';
9
9
  import 'os';
10
10
  import 'fs/promises';
11
11
  import 'url';
@@ -2,7 +2,7 @@ import { existsSync, readFileSync } from 'node:fs';
2
2
  import { execSync } from 'node:child_process';
3
3
  import { resolve, join } from 'node:path';
4
4
  import os from 'node:os';
5
- import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-CAcScbEG.mjs';
5
+ import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-IDo93bqK.mjs';
6
6
  import 'os';
7
7
  import 'fs/promises';
8
8
  import 'fs';
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-CAcScbEG.mjs';
1
+ export { c as connectToHypha, d as daemonStatus, g as getHyphaServerUrl, r as registerMachineService, a as registerSessionService, s as startDaemon, b as stopDaemon } from './run-IDo93bqK.mjs';
2
2
  import 'os';
3
3
  import 'fs/promises';
4
4
  import 'fs';
@@ -1,5 +1,5 @@
1
1
  var name = "svamp-cli";
2
- var version = "0.2.8";
2
+ var version = "0.2.9";
3
3
  var description = "Svamp CLI — AI workspace daemon on Hypha Cloud";
4
4
  var author = "Amun AI AB";
5
5
  var license = "SEE LICENSE IN LICENSE";
@@ -6,7 +6,7 @@ import { fileURLToPath } from 'url';
6
6
  import { spawn as spawn$1 } from 'child_process';
7
7
  import { randomUUID as randomUUID$1 } from 'crypto';
8
8
  import { existsSync, readFileSync, writeFileSync as writeFileSync$1, mkdirSync as mkdirSync$1, appendFileSync } from 'node:fs';
9
- import { randomUUID } from 'node:crypto';
9
+ import { randomUUID, createHash } from 'node:crypto';
10
10
  import { join as join$1 } from 'node:path';
11
11
  import { spawn, execSync, execFile } from 'node:child_process';
12
12
  import { ndJsonStream, ClientSideConnection } from '@agentclientprotocol/sdk';
@@ -718,6 +718,7 @@ async function registerMachineService(server, machineId, metadata, daemonState,
718
718
  if (newSharing.enabled && !newSharing.owner && context?.user?.email) {
719
719
  newSharing = { ...newSharing, owner: context.user.email };
720
720
  }
721
+ const oldSharing = currentMetadata.sharing;
721
722
  currentMetadata = { ...currentMetadata, sharing: newSharing };
722
723
  metadataVersion++;
723
724
  savePersistedMachineMetadata(metadata.svampHomeDir, {
@@ -730,6 +731,20 @@ async function registerMachineService(server, machineId, metadata, daemonState,
730
731
  machineId,
731
732
  metadata: { value: currentMetadata, version: metadataVersion }
732
733
  });
734
+ handlers.sharingNotificationSync?.syncSharing(
735
+ `machine-${machineId}`,
736
+ oldSharing,
737
+ newSharing,
738
+ {
739
+ machineId,
740
+ machineServiceId: `${server.config.workspace}/${server.config.client_id}:default`,
741
+ ownerWorkspace: server.config.workspace,
742
+ ownerEmail: newSharing.owner || "",
743
+ label: currentMetadata.displayName || machineId,
744
+ shareType: "machine"
745
+ }
746
+ ).catch(() => {
747
+ });
733
748
  return { success: true, sharing: newSharing };
734
749
  },
735
750
  // Get security context config
@@ -2013,7 +2028,7 @@ async function registerDebugService(server, machineId, deps) {
2013
2028
  };
2014
2029
  }
2015
2030
 
2016
- const COLLECTION_ALIAS = "svamp-agent-sessions";
2031
+ const COLLECTION_ALIAS$1 = "svamp-agent-sessions";
2017
2032
  class SessionArtifactSync {
2018
2033
  server;
2019
2034
  artifactManager = null;
@@ -2048,14 +2063,14 @@ class SessionArtifactSync {
2048
2063
  async ensureCollection() {
2049
2064
  try {
2050
2065
  const existing = await this.artifactManager.read({
2051
- artifact_id: COLLECTION_ALIAS,
2066
+ artifact_id: COLLECTION_ALIAS$1,
2052
2067
  _rkwargs: true
2053
2068
  });
2054
2069
  this.collectionId = existing.id;
2055
2070
  this.log(`[ARTIFACT SYNC] Found existing collection: ${this.collectionId}`);
2056
2071
  } catch {
2057
2072
  const collection = await this.artifactManager.create({
2058
- alias: COLLECTION_ALIAS,
2073
+ alias: COLLECTION_ALIAS$1,
2059
2074
  type: "collection",
2060
2075
  manifest: {
2061
2076
  name: "Svamp Agent Sessions",
@@ -2334,6 +2349,170 @@ class SessionArtifactSync {
2334
2349
  }
2335
2350
  }
2336
2351
 
2352
+ const COLLECTION_ALIAS = "svamp-shared-sessions";
2353
+ function emailHash(email) {
2354
+ return createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 12);
2355
+ }
2356
+ function notificationAlias(sessionId, recipientEmail) {
2357
+ return `share-${sessionId.slice(0, 8)}-${emailHash(recipientEmail)}`;
2358
+ }
2359
+ class SharingNotificationSync {
2360
+ server;
2361
+ artifactManager = null;
2362
+ collectionId = null;
2363
+ initialized = false;
2364
+ log;
2365
+ constructor(server, log) {
2366
+ this.server = server;
2367
+ this.log = log;
2368
+ }
2369
+ async init() {
2370
+ try {
2371
+ this.artifactManager = await this.server.getService("public/artifact-manager");
2372
+ if (!this.artifactManager) {
2373
+ this.log("[SHARING NOTIFY] Artifact manager not available");
2374
+ return;
2375
+ }
2376
+ await this.ensureCollection();
2377
+ this.initialized = true;
2378
+ this.log("[SHARING NOTIFY] Initialized");
2379
+ } catch (err) {
2380
+ this.log(`[SHARING NOTIFY] Init failed: ${err.message}`);
2381
+ }
2382
+ }
2383
+ async ensureCollection() {
2384
+ try {
2385
+ const existing = await this.artifactManager.read({
2386
+ artifact_id: COLLECTION_ALIAS,
2387
+ _rkwargs: true
2388
+ });
2389
+ this.collectionId = existing.id;
2390
+ } catch {
2391
+ const collection = await this.artifactManager.create({
2392
+ alias: COLLECTION_ALIAS,
2393
+ type: "collection",
2394
+ manifest: {
2395
+ name: "Svamp Shared Sessions",
2396
+ description: "Cross-workspace share notifications for session/machine bookmarks"
2397
+ },
2398
+ config: {
2399
+ permissions: { "*": "r", "@": "rw+" }
2400
+ },
2401
+ _rkwargs: true
2402
+ });
2403
+ this.collectionId = collection.id;
2404
+ await this.artifactManager.commit({
2405
+ artifact_id: this.collectionId,
2406
+ _rkwargs: true
2407
+ });
2408
+ this.log(`[SHARING NOTIFY] Created collection: ${this.collectionId}`);
2409
+ }
2410
+ }
2411
+ /**
2412
+ * Publish a share notification for a recipient.
2413
+ * Idempotent — uses deterministic alias, so re-sharing updates the existing artifact.
2414
+ */
2415
+ async notifyShare(params) {
2416
+ if (!this.initialized || !this.collectionId) return;
2417
+ const alias = notificationAlias(params.sessionId, params.recipientEmail);
2418
+ const manifest = {
2419
+ recipientEmail: params.recipientEmail.toLowerCase(),
2420
+ sessionId: params.sessionId,
2421
+ machineId: params.machineId,
2422
+ machineServiceId: params.machineServiceId,
2423
+ ownerWorkspace: params.ownerWorkspace,
2424
+ ownerEmail: params.ownerEmail,
2425
+ label: params.label || "",
2426
+ role: params.role,
2427
+ sharedAt: Date.now(),
2428
+ shareType: params.shareType || "session"
2429
+ };
2430
+ try {
2431
+ const existing = await this.artifactManager.read({
2432
+ artifact_id: alias,
2433
+ parent_id: this.collectionId,
2434
+ _rkwargs: true
2435
+ });
2436
+ await this.artifactManager.edit({
2437
+ artifact_id: existing.id,
2438
+ manifest,
2439
+ _rkwargs: true
2440
+ });
2441
+ await this.artifactManager.commit({
2442
+ artifact_id: existing.id,
2443
+ _rkwargs: true
2444
+ });
2445
+ } catch {
2446
+ try {
2447
+ const artifact = await this.artifactManager.create({
2448
+ alias,
2449
+ parent_id: this.collectionId,
2450
+ type: "share-notification",
2451
+ manifest,
2452
+ _rkwargs: true
2453
+ });
2454
+ await this.artifactManager.commit({
2455
+ artifact_id: artifact.id,
2456
+ _rkwargs: true
2457
+ });
2458
+ } catch (createErr) {
2459
+ this.log(`[SHARING NOTIFY] Failed to create notification for ${params.recipientEmail}: ${createErr.message}`);
2460
+ return;
2461
+ }
2462
+ }
2463
+ this.log(`[SHARING NOTIFY] Notified ${params.recipientEmail} about ${params.shareType || "session"} ${params.sessionId.slice(0, 8)}`);
2464
+ }
2465
+ /**
2466
+ * Remove a share notification when a user is unshared.
2467
+ */
2468
+ async removeNotification(sessionId, recipientEmail) {
2469
+ if (!this.initialized || !this.collectionId) return;
2470
+ const alias = notificationAlias(sessionId, recipientEmail);
2471
+ try {
2472
+ const existing = await this.artifactManager.read({
2473
+ artifact_id: alias,
2474
+ parent_id: this.collectionId,
2475
+ _rkwargs: true
2476
+ });
2477
+ await this.artifactManager.delete({
2478
+ artifact_id: existing.id,
2479
+ _rkwargs: true
2480
+ });
2481
+ this.log(`[SHARING NOTIFY] Removed notification for ${recipientEmail} on ${sessionId.slice(0, 8)}`);
2482
+ } catch {
2483
+ }
2484
+ }
2485
+ /**
2486
+ * Sync all sharing notifications for a session based on its current sharing config.
2487
+ * Adds notifications for new users, removes for removed users.
2488
+ */
2489
+ async syncSharing(sessionId, oldSharing, newSharing, context) {
2490
+ if (!this.initialized) return;
2491
+ const oldEmails = new Set(
2492
+ (oldSharing?.allowedUsers || []).map((u) => u.email.toLowerCase())
2493
+ );
2494
+ const newUsers = newSharing.allowedUsers || [];
2495
+ const newEmails = new Set(newUsers.map((u) => u.email.toLowerCase()));
2496
+ for (const user of newUsers) {
2497
+ if (!oldEmails.has(user.email.toLowerCase())) {
2498
+ this.notifyShare({
2499
+ recipientEmail: user.email,
2500
+ sessionId,
2501
+ role: user.role,
2502
+ ...context
2503
+ }).catch(() => {
2504
+ });
2505
+ }
2506
+ }
2507
+ for (const email of oldEmails) {
2508
+ if (!newEmails.has(email)) {
2509
+ this.removeNotification(sessionId, email).catch(() => {
2510
+ });
2511
+ }
2512
+ }
2513
+ }
2514
+ }
2515
+
2337
2516
  const DEFAULT_TIMEOUTS = {
2338
2517
  init: 6e4,
2339
2518
  toolCall: 12e4,
@@ -7128,6 +7307,7 @@ The automated loop has finished. Review the progress above and let me know if yo
7128
7307
  },
7129
7308
  onSharingUpdate: (newSharing) => {
7130
7309
  logger.log(`[Session ${sessionId}] Sharing config updated \u2014 persisting to disk`);
7310
+ const oldSharing = sessionMetadata.sharing;
7131
7311
  sessionMetadata = { ...sessionMetadata, sharing: newSharing };
7132
7312
  if (!trackedSession.stopped) {
7133
7313
  saveSession({
@@ -7142,6 +7322,17 @@ The automated loop has finished. Review the progress above and let me know if yo
7142
7322
  wasProcessing: sessionWasProcessing
7143
7323
  });
7144
7324
  }
7325
+ const ownerWorkspace = server.config.workspace;
7326
+ const machineServiceId = `${ownerWorkspace}/${server.config.client_id}:default`;
7327
+ sharingNotificationSync.syncSharing(sessionId, oldSharing, newSharing, {
7328
+ machineId,
7329
+ machineServiceId,
7330
+ ownerWorkspace,
7331
+ ownerEmail: newSharing.owner || "",
7332
+ label: sessionMetadata.summary?.text || "",
7333
+ shareType: "session"
7334
+ }).catch(() => {
7335
+ });
7145
7336
  },
7146
7337
  onApplySystemPrompt: async (prompt) => {
7147
7338
  logger.log(`[Session ${sessionId}] System prompt update requested \u2014 restarting agent`);
@@ -8065,6 +8256,9 @@ The automated loop has finished. Review the progress above and let me know if yo
8065
8256
  pid: process.pid,
8066
8257
  startedAt: Date.now()
8067
8258
  };
8259
+ const sharingNotificationSync = new SharingNotificationSync(server, logger.log);
8260
+ sharingNotificationSync.init().catch(() => {
8261
+ });
8068
8262
  const machineService = await registerMachineService(
8069
8263
  server,
8070
8264
  machineId,
@@ -8097,7 +8291,8 @@ The automated loop has finished. Review the progress above and let me know if yo
8097
8291
  },
8098
8292
  supervisor,
8099
8293
  tunnels,
8100
- serveManager
8294
+ serveManager,
8295
+ sharingNotificationSync
8101
8296
  }
8102
8297
  );
8103
8298
  logger.log(`Machine service registered: svamp-machine-${machineId}`);
@@ -2,7 +2,7 @@ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(im
2
2
  import os from 'node:os';
3
3
  import { join, resolve } from 'node:path';
4
4
  import { mkdirSync, writeFileSync, existsSync, unlinkSync, readFileSync, watch } from 'node:fs';
5
- import { c as connectToHypha, a as registerSessionService } from './run-CAcScbEG.mjs';
5
+ import { c as connectToHypha, a as registerSessionService } from './run-IDo93bqK.mjs';
6
6
  import { createServer } from 'node:http';
7
7
  import { spawn } from 'node:child_process';
8
8
  import { createInterface } from 'node:readline';
@@ -52,7 +52,7 @@ async function handleServeCommand() {
52
52
  }
53
53
  }
54
54
  async function serveAdd(args, machineId) {
55
- const { connectAndGetMachine } = await import('./commands-DXaH6BQg.mjs');
55
+ const { connectAndGetMachine } = await import('./commands-h1lFrJKK.mjs');
56
56
  const pos = positionalArgs(args);
57
57
  const name = pos[0];
58
58
  if (!name) {
@@ -84,7 +84,7 @@ async function serveAdd(args, machineId) {
84
84
  }
85
85
  }
86
86
  async function serveRemove(args, machineId) {
87
- const { connectAndGetMachine } = await import('./commands-DXaH6BQg.mjs');
87
+ const { connectAndGetMachine } = await import('./commands-h1lFrJKK.mjs');
88
88
  const pos = positionalArgs(args);
89
89
  const name = pos[0];
90
90
  if (!name) {
@@ -104,7 +104,7 @@ async function serveRemove(args, machineId) {
104
104
  }
105
105
  }
106
106
  async function serveList(args, machineId) {
107
- const { connectAndGetMachine } = await import('./commands-DXaH6BQg.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-h1lFrJKK.mjs');
108
108
  const all = hasFlag(args, "--all", "-a");
109
109
  const json = hasFlag(args, "--json");
110
110
  const sessionId = getFlag(args, "--session");
@@ -137,7 +137,7 @@ async function serveList(args, machineId) {
137
137
  }
138
138
  }
139
139
  async function serveInfo(machineId) {
140
- const { connectAndGetMachine } = await import('./commands-DXaH6BQg.mjs');
140
+ const { connectAndGetMachine } = await import('./commands-h1lFrJKK.mjs');
141
141
  const { machine, server } = await connectAndGetMachine(machineId);
142
142
  try {
143
143
  const info = await machine.serveInfo({ _rkwargs: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svamp-cli",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",