paperclip-plugin-supermemory-otomatik 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -13,7 +13,7 @@ The plugin uses Paperclip's standard plugin slots (`settingsPage`, `page`, `side
13
13
 
14
14
  ## Install from Paperclip
15
15
 
16
- Package: [`paperclip-plugin-supermemory-otomatik`](https://www.npmjs.com/package/paperclip-plugin-supermemory-otomatik) **0.2.0**.
16
+ Package: [`paperclip-plugin-supermemory-otomatik`](https://www.npmjs.com/package/paperclip-plugin-supermemory-otomatik) **0.2.2**.
17
17
 
18
18
  1. In Paperclip, open **Settings → Plugins → Install Plugin**.
19
19
  2. Enter `paperclip-plugin-supermemory-otomatik` and install it for the instance.
package/dist/manifest.js CHANGED
@@ -9,7 +9,7 @@ var MEMORY_ROUTE = "memory";
9
9
  var manifest = {
10
10
  id: PLUGIN_ID,
11
11
  apiVersion: 1,
12
- version: "0.2.0",
12
+ version: "0.2.2",
13
13
  minimumHostVersion: "2026.1023.0",
14
14
  displayName: "Supermemory (self-hosted)",
15
15
  description: "Memory tools and an Owner-managed memory library for self-hosted Supermemory, with company-, agent-, and project-scoped access.",
@@ -46,7 +46,9 @@ var manifest = {
46
46
  default: "http://127.0.0.1:6767"
47
47
  },
48
48
  adminApiKeyRef: {
49
- type: "string",
49
+ // Paperclip persists a secret-ref format as an object binding, even
50
+ // though the format marker historically describes a string picker.
51
+ type: ["string", "object"],
50
52
  format: "secret-ref",
51
53
  title: "Owner-only Supermemory Local API key",
52
54
  description: "Paperclip secret containing the Supermemory Local master API key. The plugin resolves it only for Owner-checked management actions and authorized agent searches; never paste it into instructions or agent prompts."
@@ -66,7 +68,7 @@ var manifest = {
66
68
  minLength: 1
67
69
  },
68
70
  tokenRef: {
69
- type: "string",
71
+ type: ["string", "object"],
70
72
  format: "secret-ref",
71
73
  title: "This agent's ACL token secret",
72
74
  description: "Select the Paperclip company secret containing only this agent's Supermemory ACL token."
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/manifest.ts"],
4
- "sourcesContent": ["import type { PaperclipPluginManifestV1 } from \"@paperclipai/plugin-sdk\";\n\nexport const PLUGIN_ID = \"paperclipai.supermemory\";\nexport const SEARCH_TOOL = \"search-approved-memory\";\nexport const SAVE_TOOL = \"submit-memory-candidate\";\nexport const MEMORY_SETTINGS_PAGE = \"supermemory-settings\";\nexport const MEMORY_PAGE = \"supermemory-memory\";\nexport const MEMORY_SIDEBAR = \"supermemory-sidebar\";\nexport const MEMORY_ROUTE = \"memory\";\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: PLUGIN_ID,\n apiVersion: 1,\n version: \"0.2.0\",\n minimumHostVersion: \"2026.1023.0\",\n displayName: \"Supermemory (self-hosted)\",\n description: \"Memory tools and an Owner-managed memory library for self-hosted Supermemory, with company-, agent-, and project-scoped access.\",\n author: \"Otomatik\",\n categories: [\"connector\", \"automation\", \"ui\"],\n capabilities: [\n \"agent.tools.register\",\n \"agents.read\",\n \"projects.read\",\n \"access.members.read\",\n \"http.outbound\",\n \"instance.settings.register\",\n \"secrets.read-ref\",\n \"ui.page.register\",\n \"ui.sidebar.register\",\n ],\n entrypoints: {\n worker: \"./dist/worker.js\",\n ui: \"./dist/ui\",\n },\n instanceConfigSchema: {\n type: \"object\",\n properties: {\n gatewayUrl: {\n type: \"string\",\n title: \"Self-hosted ACL gateway URL\",\n description: \"Private Paperclip ACL gateway used by legacy company/team memory and reviewed memory candidates. Defaults to the OTOMATIK loopback endpoint.\",\n default: \"http://127.0.0.1:6768/mcp\",\n },\n localApiUrl: {\n type: \"string\",\n title: \"Supermemory Local API URL\",\n description: \"Private Supermemory Local API used by Owner-managed namespace content and explicit agent/project memory. Defaults to the OTOMATIK loopback endpoint.\",\n default: \"http://127.0.0.1:6767\",\n },\n adminApiKeyRef: {\n type: \"string\",\n format: \"secret-ref\",\n title: \"Owner-only Supermemory Local API key\",\n description: \"Paperclip secret containing the Supermemory Local master API key. The plugin resolves it only for Owner-checked management actions and authorized agent searches; never paste it into instructions or agent prompts.\",\n },\n agentGrants: {\n type: \"array\",\n title: \"Authorized agents\",\n description: \"Only listed Paperclip agents can use the memory tools. Each one uses its own ACL gateway token secret, already bound to the same agent, company, and role.\",\n items: {\n type: \"object\",\n title: \"Agent grant\",\n required: [\"agentId\", \"tokenRef\"],\n properties: {\n agentId: {\n type: \"string\",\n title: \"Paperclip agent\",\n minLength: 1,\n },\n tokenRef: {\n type: \"string\",\n format: \"secret-ref\",\n title: \"This agent's ACL token secret\",\n description: \"Select the Paperclip company secret containing only this agent's Supermemory ACL token.\",\n },\n },\n },\n default: [],\n },\n },\n },\n tools: [\n {\n name: SEARCH_TOOL,\n displayName: \"Search approved Supermemory\",\n description: \"Search this agent's explicitly authorized company/team compartments and any assigned agent/project namespaces. Project memory is available only when the Paperclip run is in that project and the agent is on its explicit allowlist. Do not search for credentials or personal records.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", minLength: 1, maxLength: 300 },\n searchMode: { type: \"string\", enum: [\"hybrid\", \"memories\", \"chunks\"], default: \"hybrid\" },\n limit: { type: \"integer\", minimum: 1, maximum: 5, default: 3 },\n },\n required: [\"query\"],\n additionalProperties: false,\n },\n },\n {\n name: SAVE_TOOL,\n displayName: \"Submit a Supermemory candidate\",\n description: \"Submit one durable, non-sensitive fact or decision to this agent's role staging compartment for human review. This does not publish it to shared approved memory. Never submit credentials, personal data, customer cases, legal/health/workplace records, or full chat transcripts.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n content: { type: \"string\", minLength: 20, maxLength: 1200 },\n },\n required: [\"content\"],\n additionalProperties: false,\n },\n },\n ],\n ui: {\n slots: [\n {\n type: \"settingsPage\",\n id: MEMORY_SETTINGS_PAGE,\n displayName: \"Supermemory settings\",\n exportName: \"SupermemorySettingsPage\",\n },\n {\n type: \"page\",\n id: MEMORY_PAGE,\n displayName: \"Memory\",\n exportName: \"MemoryPage\",\n routePath: MEMORY_ROUTE,\n },\n {\n type: \"sidebar\",\n id: MEMORY_SIDEBAR,\n displayName: \"Memory\",\n exportName: \"MemorySidebarLink\",\n },\n ],\n },\n};\n\nexport default manifest;\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import type { PaperclipPluginManifestV1 } from \"@paperclipai/plugin-sdk\";\n\nexport const PLUGIN_ID = \"paperclipai.supermemory\";\nexport const SEARCH_TOOL = \"search-approved-memory\";\nexport const SAVE_TOOL = \"submit-memory-candidate\";\nexport const MEMORY_SETTINGS_PAGE = \"supermemory-settings\";\nexport const MEMORY_PAGE = \"supermemory-memory\";\nexport const MEMORY_SIDEBAR = \"supermemory-sidebar\";\nexport const MEMORY_ROUTE = \"memory\";\n\nconst manifest: PaperclipPluginManifestV1 = {\n id: PLUGIN_ID,\n apiVersion: 1,\n version: \"0.2.2\",\n minimumHostVersion: \"2026.1023.0\",\n displayName: \"Supermemory (self-hosted)\",\n description: \"Memory tools and an Owner-managed memory library for self-hosted Supermemory, with company-, agent-, and project-scoped access.\",\n author: \"Otomatik\",\n categories: [\"connector\", \"automation\", \"ui\"],\n capabilities: [\n \"agent.tools.register\",\n \"agents.read\",\n \"projects.read\",\n \"access.members.read\",\n \"http.outbound\",\n \"instance.settings.register\",\n \"secrets.read-ref\",\n \"ui.page.register\",\n \"ui.sidebar.register\",\n ],\n entrypoints: {\n worker: \"./dist/worker.js\",\n ui: \"./dist/ui\",\n },\n instanceConfigSchema: {\n type: \"object\",\n properties: {\n gatewayUrl: {\n type: \"string\",\n title: \"Self-hosted ACL gateway URL\",\n description: \"Private Paperclip ACL gateway used by legacy company/team memory and reviewed memory candidates. Defaults to the OTOMATIK loopback endpoint.\",\n default: \"http://127.0.0.1:6768/mcp\",\n },\n localApiUrl: {\n type: \"string\",\n title: \"Supermemory Local API URL\",\n description: \"Private Supermemory Local API used by Owner-managed namespace content and explicit agent/project memory. Defaults to the OTOMATIK loopback endpoint.\",\n default: \"http://127.0.0.1:6767\",\n },\n adminApiKeyRef: {\n // Paperclip persists a secret-ref format as an object binding, even\n // though the format marker historically describes a string picker.\n type: [\"string\", \"object\"],\n format: \"secret-ref\",\n title: \"Owner-only Supermemory Local API key\",\n description: \"Paperclip secret containing the Supermemory Local master API key. The plugin resolves it only for Owner-checked management actions and authorized agent searches; never paste it into instructions or agent prompts.\",\n },\n agentGrants: {\n type: \"array\",\n title: \"Authorized agents\",\n description: \"Only listed Paperclip agents can use the memory tools. Each one uses its own ACL gateway token secret, already bound to the same agent, company, and role.\",\n items: {\n type: \"object\",\n title: \"Agent grant\",\n required: [\"agentId\", \"tokenRef\"],\n properties: {\n agentId: {\n type: \"string\",\n title: \"Paperclip agent\",\n minLength: 1,\n },\n tokenRef: {\n type: [\"string\", \"object\"],\n format: \"secret-ref\",\n title: \"This agent's ACL token secret\",\n description: \"Select the Paperclip company secret containing only this agent's Supermemory ACL token.\",\n },\n },\n },\n default: [],\n },\n },\n },\n tools: [\n {\n name: SEARCH_TOOL,\n displayName: \"Search approved Supermemory\",\n description: \"Search this agent's explicitly authorized company/team compartments and any assigned agent/project namespaces. Project memory is available only when the Paperclip run is in that project and the agent is on its explicit allowlist. Do not search for credentials or personal records.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n query: { type: \"string\", minLength: 1, maxLength: 300 },\n searchMode: { type: \"string\", enum: [\"hybrid\", \"memories\", \"chunks\"], default: \"hybrid\" },\n limit: { type: \"integer\", minimum: 1, maximum: 5, default: 3 },\n },\n required: [\"query\"],\n additionalProperties: false,\n },\n },\n {\n name: SAVE_TOOL,\n displayName: \"Submit a Supermemory candidate\",\n description: \"Submit one durable, non-sensitive fact or decision to this agent's role staging compartment for human review. This does not publish it to shared approved memory. Never submit credentials, personal data, customer cases, legal/health/workplace records, or full chat transcripts.\",\n parametersSchema: {\n type: \"object\",\n properties: {\n content: { type: \"string\", minLength: 20, maxLength: 1200 },\n },\n required: [\"content\"],\n additionalProperties: false,\n },\n },\n ],\n ui: {\n slots: [\n {\n type: \"settingsPage\",\n id: MEMORY_SETTINGS_PAGE,\n displayName: \"Supermemory settings\",\n exportName: \"SupermemorySettingsPage\",\n },\n {\n type: \"page\",\n id: MEMORY_PAGE,\n displayName: \"Memory\",\n exportName: \"MemoryPage\",\n routePath: MEMORY_ROUTE,\n },\n {\n type: \"sidebar\",\n id: MEMORY_SIDEBAR,\n displayName: \"Memory\",\n exportName: \"MemorySidebarLink\",\n },\n ],\n },\n};\n\nexport default manifest;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/dist/ui/index.js CHANGED
@@ -44,6 +44,17 @@ async function hostFetchJson(path, init = {}) {
44
44
  function secretId(value) {
45
45
  return typeof value === "object" && value !== null && value.type === "secret_ref" && typeof value.secretId === "string" ? value.secretId : "";
46
46
  }
47
+ function displayError(value) {
48
+ if (value instanceof Error) return value.message;
49
+ if (typeof value === "string") return value;
50
+ if (value && typeof value === "object") {
51
+ const error = value;
52
+ if (typeof error.message === "string" && error.message.trim()) return error.message;
53
+ if (typeof error.details === "string" && error.details.trim()) return error.details;
54
+ if (typeof error.code === "string" && error.code.trim()) return `Operazione non riuscita (${error.code}).`;
55
+ }
56
+ return "Operazione non riuscita. Riprova o controlla la configurazione del plugin.";
57
+ }
47
58
  function pluginConfig(configJson) {
48
59
  const config = configJson ?? {};
49
60
  const grants = Array.isArray(config.agentGrants) ? config.agentGrants.flatMap((entry) => {
@@ -100,7 +111,7 @@ function SupermemorySettingsPage() {
100
111
  setError(null);
101
112
  };
102
113
  void load().catch((cause) => {
103
- if (!cancelled) setError(cause instanceof Error ? cause.message : String(cause));
114
+ if (!cancelled) setError(displayError(cause));
104
115
  }).finally(() => {
105
116
  if (!cancelled) setLoading(false);
106
117
  });
@@ -141,7 +152,7 @@ function SupermemorySettingsPage() {
141
152
  setGrantRows(cleaned.map((row, index) => ({ key: `grant-${index}-${row.agentId}`, agentId: row.agentId, tokenSecretId: row.tokenSecretId })));
142
153
  setSuccess(true);
143
154
  } catch (cause) {
144
- setError(cause instanceof Error ? cause.message : String(cause));
155
+ setError(displayError(cause));
145
156
  } finally {
146
157
  setSaving(false);
147
158
  }
@@ -313,7 +324,7 @@ function MemoryPage() {
313
324
  setError(null);
314
325
  }).catch((cause) => {
315
326
  if (cancelled) return;
316
- setError(cause instanceof Error ? cause.message : String(cause));
327
+ setError(displayError(cause));
317
328
  }).finally(() => {
318
329
  if (!cancelled) setLoading(false);
319
330
  });
@@ -344,7 +355,7 @@ function MemoryPage() {
344
355
  setDirty(false);
345
356
  setMode("read");
346
357
  }).catch((cause) => {
347
- if (!cancelled) setError(cause instanceof Error ? cause.message : String(cause));
358
+ if (!cancelled) setError(displayError(cause));
348
359
  }).finally(() => {
349
360
  if (!cancelled) setBusy(false);
350
361
  });
@@ -385,7 +396,7 @@ function MemoryPage() {
385
396
  toast({ tone: "success", title: "Memoria salvata", body: "Supermemory ha messo il contenuto in coda per l\u2019indicizzazione." });
386
397
  return true;
387
398
  } catch (cause) {
388
- const message = cause instanceof Error ? cause.message : String(cause);
399
+ const message = displayError(cause);
389
400
  setError(message);
390
401
  toast({ tone: "error", title: "Salvataggio non riuscito", body: message });
391
402
  } finally {
@@ -420,7 +431,7 @@ function MemoryPage() {
420
431
  setActiveDocumentKey(`${activeAssignment.id}:${result.document.id}`);
421
432
  toast({ tone: "success", title: "File caricato", body: "Supermemory ha messo il file in coda per l\u2019indicizzazione." });
422
433
  } catch (cause) {
423
- const message = cause instanceof Error ? cause.message : String(cause);
434
+ const message = displayError(cause);
424
435
  setError(message);
425
436
  toast({ tone: "error", title: "Caricamento non riuscito", body: message });
426
437
  } finally {
@@ -434,6 +445,10 @@ function MemoryPage() {
434
445
  }
435
446
  function onDrop(event) {
436
447
  event.preventDefault();
448
+ if (!activeAssignment) {
449
+ setError("Prima assegna o seleziona un namespace; poi puoi caricare il PDF.");
450
+ return;
451
+ }
437
452
  const file = event.dataTransfer.files.item(0);
438
453
  if (file) void handleFile(file);
439
454
  }
@@ -473,7 +488,7 @@ function MemoryPage() {
473
488
  setAllowedAgentIds([]);
474
489
  toast({ tone: "success", title: "Namespace assegnato", body: "Lo spazio di memoria \xE8 limitato all\u2019assegnazione e agli agenti indicati." });
475
490
  } catch (cause) {
476
- const message = cause instanceof Error ? cause.message : String(cause);
491
+ const message = displayError(cause);
477
492
  setError(message);
478
493
  } finally {
479
494
  setBusy(false);
@@ -489,7 +504,7 @@ function MemoryPage() {
489
504
  setActiveDocumentKey("");
490
505
  setDocument(null);
491
506
  } catch (cause) {
492
- setError(cause instanceof Error ? cause.message : String(cause));
507
+ setError(displayError(cause));
493
508
  } finally {
494
509
  setBusy(false);
495
510
  }
@@ -504,7 +519,7 @@ function MemoryPage() {
504
519
  setDocument(null);
505
520
  setActiveDocumentKey("");
506
521
  } catch (cause) {
507
- setError(cause instanceof Error ? cause.message : String(cause));
522
+ setError(displayError(cause));
508
523
  } finally {
509
524
  setBusy(false);
510
525
  }
@@ -626,7 +641,7 @@ function MemoryPage() {
626
641
  ] }),
627
642
  document ? /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "center", gap: 4, border: "1px solid var(--border)", borderRadius: 7, padding: 3 }, children: ["read", "edit", "raw"].map((tab) => /* @__PURE__ */ jsx("button", { type: "button", onClick: () => setMode(tab), style: { border: 0, borderRadius: 5, padding: "6px 10px", background: mode === tab ? "var(--accent, rgba(127,127,127,.18))" : "transparent", color: "var(--foreground)", cursor: "pointer", fontSize: 12 }, children: tab === "read" ? "Leggi" : tab === "edit" ? "Modifica" : "Raw" }, tab)) }) : null
628
643
  ] }),
629
- showUrlForm ? /* @__PURE__ */ jsxs("form", { onSubmit: addUrl, style: { margin: 14, padding: 14, display: "grid", gap: 9, border: "1px solid var(--border)", borderRadius: 8 }, children: [
644
+ showUrlForm && activeAssignment ? /* @__PURE__ */ jsxs("form", { onSubmit: addUrl, style: { margin: 14, padding: 14, display: "grid", gap: 9, border: "1px solid var(--border)", borderRadius: 8 }, children: [
630
645
  /* @__PURE__ */ jsx("strong", { style: { fontSize: 13 }, children: "Aggiungi pagina web" }),
631
646
  /* @__PURE__ */ jsx("input", { style: inputStyle, type: "url", required: true, placeholder: "https://example.com/documentazione", value: urlInput, onChange: (event) => setUrlInput(event.target.value) }),
632
647
  /* @__PURE__ */ jsx("span", { style: { ...mutedStyle, fontSize: 12 }, children: "L\u2019URL viene passato a Supermemory Local. L\u2019estrazione web richiede Firecrawl configurato e invia la pagina al servizio Firecrawl." }),
@@ -635,7 +650,11 @@ function MemoryPage() {
635
650
  /* @__PURE__ */ jsx("button", { type: "button", style: secondaryButtonStyle, onClick: () => setShowUrlForm(false), children: "Annulla" })
636
651
  ] })
637
652
  ] }) : null,
638
- !document ? /* @__PURE__ */ jsx("div", { onDragOver: (event) => event.preventDefault(), onDrop, style: { flex: 1, display: "grid", placeItems: "center", minHeight: 420, padding: 28 }, children: /* @__PURE__ */ jsxs("div", { style: { width: "min(100%, 600px)", border: "1px dashed var(--border)", borderRadius: 12, padding: 28, textAlign: "center" }, children: [
653
+ !activeAssignment ? /* @__PURE__ */ jsx("div", { style: { flex: 1, display: "grid", placeItems: "center", minHeight: 420, padding: 28 }, children: /* @__PURE__ */ jsxs("div", { style: { width: "min(100%, 600px)", border: "1px dashed var(--border)", borderRadius: 12, padding: 28, textAlign: "center" }, children: [
654
+ /* @__PURE__ */ jsx("strong", { children: "Prima assegna un namespace" }),
655
+ /* @__PURE__ */ jsx("p", { style: { ...mutedStyle, fontSize: 13, lineHeight: 1.55 }, children: "Non c\u2019\xE8 uno spazio di memoria attivo in questa organizzazione. Assegna un progetto o un agente; poi selezionalo e carica il PDF." }),
656
+ /* @__PURE__ */ jsx("button", { type: "button", style: primaryButtonStyle, onClick: () => setShowAssignment(true), children: "\uFF0B Assegna namespace" })
657
+ ] }) }) : !document ? /* @__PURE__ */ jsx("div", { onDragOver: (event) => event.preventDefault(), onDrop, style: { flex: 1, display: "grid", placeItems: "center", minHeight: 420, padding: 28 }, children: /* @__PURE__ */ jsxs("div", { style: { width: "min(100%, 600px)", border: "1px dashed var(--border)", borderRadius: 12, padding: 28, textAlign: "center" }, children: [
639
658
  /* @__PURE__ */ jsx("div", { style: { fontSize: 28, marginBottom: 10 }, children: "\u21E7" }),
640
659
  /* @__PURE__ */ jsx("strong", { children: "Trascina qui un file" }),
641
660
  /* @__PURE__ */ jsx("p", { style: { ...mutedStyle, fontSize: 13, lineHeight: 1.55 }, children: "Testo: TXT, Markdown, HTML, JSON e CSV (max 1 MB). File binari verificati per Supermemory Local: PDF, PNG, JPG/JPEG, GIF e WebP (max 6 MiB in questa interfaccia). Puoi anche aggiungere un URL pubblico." }),