svamp-cli 0.2.10 → 0.2.11

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-BjLVgTDn.mjs');
151
+ const { connectAndGetMachine } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
168
+ const { resolveSessionId } = await import('./commands-DsBtNTwb.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-w_M8ajhF.mjs';
1
+ import { b as stopDaemon, s as startDaemon, d as daemonStatus } from './run-BRElsMCe.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-KG7QRNTH.mjs');
234
+ const { handleServeCommand } = await import('./serveCommands-B3lrLh1f.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-CAfSJwcS.mjs');
243
+ const { processCommand } = await import('./commands-DC-GHo_-.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-Bf0XCjn8.mjs').catch(() => ({ default: { version: "unknown" } }));
261
+ const pkg = await import('./package-O_s35H8q.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-oyFHdge9.mjs');
270
+ const { runInteractive } = await import('./run-sFMF1JIF.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-w_M8ajhF.mjs').then(function (n) { return n.i; });
315
+ const { KNOWN_ACP_AGENTS, KNOWN_MCP_AGENTS: KNOWN_MCP_AGENTS2 } = await import('./run-BRElsMCe.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-w_M8ajhF.mjs').then(function (n) { return n.i; });
327
+ const { resolveAcpAgentConfig, KNOWN_MCP_AGENTS } = await import('./run-BRElsMCe.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-w_M8ajhF.mjs').then(function (n) { return n.j; });
351
+ const { CodexMcpBackend } = await import('./run-BRElsMCe.mjs').then(function (n) { return n.j; });
352
352
  backend = new CodexMcpBackend({ cwd, log: logFn });
353
353
  } else {
354
- const { AcpBackend } = await import('./run-w_M8ajhF.mjs').then(function (n) { return n.h; });
355
- const { GeminiTransport } = await import('./run-w_M8ajhF.mjs').then(function (n) { return n.G; });
356
- const { DefaultTransport } = await import('./run-w_M8ajhF.mjs').then(function (n) { return n.D; });
354
+ const { AcpBackend } = await import('./run-BRElsMCe.mjs').then(function (n) { return n.h; });
355
+ const { GeminiTransport } = await import('./run-BRElsMCe.mjs').then(function (n) { return n.G; });
356
+ const { DefaultTransport } = await import('./run-BRElsMCe.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-BjLVgTDn.mjs');
483
+ const { sessionList, sessionSpawn, sessionStop, sessionInfo, sessionMessages, sessionAttach, sessionMachines, sessionSend, sessionWait, sessionShare, sessionRalphStart, sessionRalphCancel, sessionRalphStatus, sessionInboxSend, sessionInboxList, sessionInboxRead, sessionInboxReply, sessionInboxClear } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
543
+ const { parseShareArg } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
629
+ const { sessionApprove } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
639
+ const { sessionDeny } = await import('./commands-DsBtNTwb.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-DNFlwUrE.mjs');
675
+ const { sessionSetTitle } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
684
+ const { sessionSetLink } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
693
+ const { sessionNotify } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
701
+ const { sessionBroadcast } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
712
+ const { inboxSend } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
727
+ const { inboxList } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
749
+ const { inboxList } = await import('./agentCommands-CUCjwaSG.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-DNFlwUrE.mjs');
759
+ const { inboxReply } = await import('./agentCommands-CUCjwaSG.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-BjLVgTDn.mjs');
795
+ const { machineShare } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
825
+ const { machineExec } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
845
+ const { machineInfo } = await import('./commands-DsBtNTwb.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-DNFlwUrE.mjs');
865
+ const { machineNotify } = await import('./agentCommands-CUCjwaSG.mjs');
866
866
  await machineNotify(message, level);
867
867
  } else if (machineSubcommand === "ls") {
868
- const { machineLs } = await import('./commands-BjLVgTDn.mjs');
868
+ const { machineLs } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs';
3
+ import { connectAndGetMachine } from './commands-DsBtNTwb.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-w_M8ajhF.mjs';
8
+ import './run-BRElsMCe.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-w_M8ajhF.mjs';
5
+ import { l as loadSecurityContextConfig, e as resolveSecurityContext, f as buildSecurityContextFromFlags, m as mergeSecurityContexts, c as connectToHypha } from './run-BRElsMCe.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-w_M8ajhF.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-BRElsMCe.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.10";
2
+ var version = "0.2.11";
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";
@@ -2028,7 +2028,7 @@ async function registerDebugService(server, machineId, deps) {
2028
2028
  };
2029
2029
  }
2030
2030
 
2031
- const COLLECTION_ALIAS$1 = "svamp-agent-sessions";
2031
+ const COLLECTION_ALIAS = "svamp-agent-sessions";
2032
2032
  class SessionArtifactSync {
2033
2033
  server;
2034
2034
  artifactManager = null;
@@ -2063,14 +2063,14 @@ class SessionArtifactSync {
2063
2063
  async ensureCollection() {
2064
2064
  try {
2065
2065
  const existing = await this.artifactManager.read({
2066
- artifact_id: COLLECTION_ALIAS$1,
2066
+ artifact_id: COLLECTION_ALIAS,
2067
2067
  _rkwargs: true
2068
2068
  });
2069
2069
  this.collectionId = existing.id;
2070
2070
  this.log(`[ARTIFACT SYNC] Found existing collection: ${this.collectionId}`);
2071
2071
  } catch {
2072
2072
  const collection = await this.artifactManager.create({
2073
- alias: COLLECTION_ALIAS$1,
2073
+ alias: COLLECTION_ALIAS,
2074
2074
  type: "collection",
2075
2075
  manifest: {
2076
2076
  name: "Svamp Agent Sessions",
@@ -2349,17 +2349,22 @@ class SessionArtifactSync {
2349
2349
  }
2350
2350
  }
2351
2351
 
2352
- const COLLECTION_ALIAS = "svamp-shared-sessions";
2352
+ const SHARE_COLLECTION_ALIAS = "svamp-shared-sessions";
2353
+ const EVENT_COLLECTION_ALIAS = "svamp-user-events";
2353
2354
  function emailHash(email) {
2354
2355
  return createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 12);
2355
2356
  }
2356
- function notificationAlias(sessionId, recipientEmail) {
2357
+ function shareAlias(sessionId, recipientEmail) {
2357
2358
  return `share-${sessionId.slice(0, 8)}-${emailHash(recipientEmail)}`;
2358
2359
  }
2360
+ function eventAlias(eventId, recipientEmail) {
2361
+ return `evt-${emailHash(recipientEmail)}-${eventId.slice(0, 8)}`;
2362
+ }
2359
2363
  class SharingNotificationSync {
2360
2364
  server;
2361
2365
  artifactManager = null;
2362
- collectionId = null;
2366
+ shareCollectionId = null;
2367
+ eventCollectionId = null;
2363
2368
  initialized = false;
2364
2369
  log;
2365
2370
  constructor(server, log) {
@@ -2373,49 +2378,48 @@ class SharingNotificationSync {
2373
2378
  this.log("[SHARING NOTIFY] Artifact manager not available");
2374
2379
  return;
2375
2380
  }
2376
- await this.ensureCollection();
2381
+ await Promise.all([
2382
+ this.ensureCollection(SHARE_COLLECTION_ALIAS, "Svamp Shared Sessions", "Cross-workspace share notifications for session/machine bookmarks").then((id) => {
2383
+ this.shareCollectionId = id;
2384
+ }),
2385
+ this.ensureCollection(EVENT_COLLECTION_ALIAS, "Svamp User Events", "General-purpose user event inbox for bell notifications").then((id) => {
2386
+ this.eventCollectionId = id;
2387
+ })
2388
+ ]);
2377
2389
  this.initialized = true;
2378
- this.log("[SHARING NOTIFY] Initialized");
2390
+ this.log("[SHARING NOTIFY] Initialized (share + events collections)");
2379
2391
  } catch (err) {
2380
2392
  this.log(`[SHARING NOTIFY] Init failed: ${err.message}`);
2381
2393
  }
2382
2394
  }
2383
- async ensureCollection() {
2395
+ async ensureCollection(alias, name, description) {
2384
2396
  try {
2385
2397
  const existing = await this.artifactManager.read({
2386
- artifact_id: COLLECTION_ALIAS,
2398
+ artifact_id: alias,
2387
2399
  _rkwargs: true
2388
2400
  });
2389
- this.collectionId = existing.id;
2401
+ return existing.id;
2390
2402
  } catch {
2391
2403
  const collection = await this.artifactManager.create({
2392
- alias: COLLECTION_ALIAS,
2404
+ alias,
2393
2405
  type: "collection",
2394
2406
  stage: true,
2395
- manifest: {
2396
- name: "Svamp Shared Sessions",
2397
- description: "Cross-workspace share notifications for session/machine bookmarks"
2398
- },
2399
- config: {
2400
- permissions: { "*": "r", "@": "rw+" }
2401
- },
2407
+ manifest: { name, description },
2408
+ config: { permissions: { "*": "r", "@": "rw+" } },
2402
2409
  _rkwargs: true
2403
2410
  });
2404
- this.collectionId = collection.id;
2405
2411
  await this.artifactManager.commit({
2406
- artifact_id: this.collectionId,
2412
+ artifact_id: collection.id,
2407
2413
  _rkwargs: true
2408
2414
  });
2409
- this.log(`[SHARING NOTIFY] Created collection: ${this.collectionId}`);
2415
+ this.log(`[SHARING NOTIFY] Created collection: ${alias} (${collection.id})`);
2416
+ return collection.id;
2410
2417
  }
2411
2418
  }
2412
- /**
2413
- * Publish a share notification for a recipient.
2414
- * Idempotent — uses deterministic alias, so re-sharing updates the existing artifact.
2415
- */
2419
+ // ── Share bookmark artifacts (svamp-shared-sessions) ──────────────
2416
2420
  async notifyShare(params) {
2417
- if (!this.initialized || !this.collectionId) return;
2418
- const alias = notificationAlias(params.sessionId, params.recipientEmail);
2421
+ if (!this.initialized || !this.shareCollectionId) return;
2422
+ const alias = shareAlias(params.sessionId, params.recipientEmail);
2419
2423
  const manifest = {
2420
2424
  recipientEmail: params.recipientEmail.toLowerCase(),
2421
2425
  sessionId: params.sessionId,
@@ -2431,7 +2435,7 @@ class SharingNotificationSync {
2431
2435
  try {
2432
2436
  const existing = await this.artifactManager.read({
2433
2437
  artifact_id: alias,
2434
- parent_id: this.collectionId,
2438
+ parent_id: this.shareCollectionId,
2435
2439
  _rkwargs: true
2436
2440
  });
2437
2441
  await this.artifactManager.edit({
@@ -2447,7 +2451,7 @@ class SharingNotificationSync {
2447
2451
  try {
2448
2452
  const artifact = await this.artifactManager.create({
2449
2453
  alias,
2450
- parent_id: this.collectionId,
2454
+ parent_id: this.shareCollectionId,
2451
2455
  type: "share-notification",
2452
2456
  stage: true,
2453
2457
  manifest,
@@ -2458,36 +2462,110 @@ class SharingNotificationSync {
2458
2462
  _rkwargs: true
2459
2463
  });
2460
2464
  } catch (createErr) {
2461
- this.log(`[SHARING NOTIFY] Failed to create notification for ${params.recipientEmail}: ${createErr.message}`);
2465
+ this.log(`[SHARING NOTIFY] Failed to create share notification for ${params.recipientEmail}: ${createErr.message}`);
2462
2466
  return;
2463
2467
  }
2464
2468
  }
2465
- this.log(`[SHARING NOTIFY] Notified ${params.recipientEmail} about ${params.shareType || "session"} ${params.sessionId.slice(0, 8)}`);
2469
+ this.log(`[SHARING NOTIFY] Share notified ${params.recipientEmail} about ${params.shareType || "session"} ${params.sessionId.slice(0, 8)}`);
2470
+ const shareType = params.shareType || "session";
2471
+ const typeLabel = shareType === "machine" ? "Machine" : "Session";
2472
+ await this.publishUserEvent({
2473
+ id: randomUUID(),
2474
+ recipientEmail: params.recipientEmail.toLowerCase(),
2475
+ type: "sharing-invite",
2476
+ source: {
2477
+ service: "svamp-machine",
2478
+ workspace: params.ownerWorkspace,
2479
+ userEmail: params.ownerEmail
2480
+ },
2481
+ title: `${typeLabel} shared with you`,
2482
+ body: `${params.ownerEmail} shared "${params.label || "Untitled"}" with you as ${params.role}`,
2483
+ level: "info",
2484
+ action: shareType === "session" ? {
2485
+ type: "add-session-bookmark",
2486
+ sessionId: params.sessionId,
2487
+ workspace: params.ownerWorkspace,
2488
+ machineServiceId: params.machineServiceId,
2489
+ label: params.label || ""
2490
+ } : {
2491
+ type: "add-machine-bookmark",
2492
+ machineId: params.machineId,
2493
+ workspace: params.ownerWorkspace,
2494
+ label: params.label || ""
2495
+ },
2496
+ createdAt: Date.now(),
2497
+ expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1e3
2498
+ // 30 days
2499
+ });
2466
2500
  }
2467
- /**
2468
- * Remove a share notification when a user is unshared.
2469
- */
2470
2501
  async removeNotification(sessionId, recipientEmail) {
2471
- if (!this.initialized || !this.collectionId) return;
2472
- const alias = notificationAlias(sessionId, recipientEmail);
2502
+ if (!this.initialized || !this.shareCollectionId) return;
2503
+ const alias = shareAlias(sessionId, recipientEmail);
2473
2504
  try {
2474
2505
  const existing = await this.artifactManager.read({
2475
2506
  artifact_id: alias,
2476
- parent_id: this.collectionId,
2507
+ parent_id: this.shareCollectionId,
2477
2508
  _rkwargs: true
2478
2509
  });
2479
2510
  await this.artifactManager.delete({
2480
2511
  artifact_id: existing.id,
2481
2512
  _rkwargs: true
2482
2513
  });
2483
- this.log(`[SHARING NOTIFY] Removed notification for ${recipientEmail} on ${sessionId.slice(0, 8)}`);
2514
+ this.log(`[SHARING NOTIFY] Removed share notification for ${recipientEmail} on ${sessionId.slice(0, 8)}`);
2484
2515
  } catch {
2485
2516
  }
2517
+ await this.publishUserEvent({
2518
+ id: randomUUID(),
2519
+ recipientEmail: recipientEmail.toLowerCase(),
2520
+ type: "sharing-revoked",
2521
+ source: {
2522
+ service: "svamp-machine",
2523
+ workspace: this.server.config?.workspace || "",
2524
+ userEmail: ""
2525
+ },
2526
+ title: "Session access removed",
2527
+ body: `Your access to a shared session has been revoked`,
2528
+ level: "warning",
2529
+ createdAt: Date.now(),
2530
+ expiresAt: Date.now() + 7 * 24 * 60 * 60 * 1e3
2531
+ // 7 days
2532
+ });
2486
2533
  }
2534
+ // ── General user event artifacts (svamp-user-events) ─────────────
2487
2535
  /**
2488
- * Sync all sharing notifications for a session based on its current sharing config.
2489
- * Adds notifications for new users, removes for removed users.
2536
+ * Publish a general user event to the event inbox collection.
2537
+ * Any service can call this to deliver an event to any user's bell icon.
2490
2538
  */
2539
+ async publishUserEvent(event) {
2540
+ if (!this.initialized || !this.eventCollectionId) return;
2541
+ const alias = eventAlias(event.id, event.recipientEmail);
2542
+ try {
2543
+ const artifact = await this.artifactManager.create({
2544
+ alias,
2545
+ parent_id: this.eventCollectionId,
2546
+ type: "user-event",
2547
+ stage: true,
2548
+ manifest: event,
2549
+ _rkwargs: true
2550
+ });
2551
+ await this.artifactManager.commit({
2552
+ artifact_id: artifact.id,
2553
+ _rkwargs: true
2554
+ });
2555
+ this.log(`[USER EVENT] Published ${event.type} to ${event.recipientEmail}`);
2556
+ try {
2557
+ this.server.emit?.({
2558
+ type: "svamp:user-event",
2559
+ data: event,
2560
+ to: "*"
2561
+ });
2562
+ } catch {
2563
+ }
2564
+ } catch (err) {
2565
+ this.log(`[USER EVENT] Failed to publish ${event.type} for ${event.recipientEmail}: ${err.message}`);
2566
+ }
2567
+ }
2568
+ // ── Sharing config diff + sync ───────────────────────────────────
2491
2569
  async syncSharing(sessionId, oldSharing, newSharing, context) {
2492
2570
  if (!this.initialized) return;
2493
2571
  const oldEmails = new Set(
@@ -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-w_M8ajhF.mjs';
5
+ import { c as connectToHypha, a as registerSessionService } from './run-BRElsMCe.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-BjLVgTDn.mjs');
55
+ const { connectAndGetMachine } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
87
+ const { connectAndGetMachine } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
107
+ const { connectAndGetMachine } = await import('./commands-DsBtNTwb.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-BjLVgTDn.mjs');
140
+ const { connectAndGetMachine } = await import('./commands-DsBtNTwb.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.10",
3
+ "version": "0.2.11",
4
4
  "description": "Svamp CLI — AI workspace daemon on Hypha Cloud",
5
5
  "author": "Amun AI AB",
6
6
  "license": "SEE LICENSE IN LICENSE",