@trops/dash-core 0.1.626 → 0.1.627

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.
@@ -73683,6 +73683,7 @@ const Store = require$$0$5;
73683
73683
  function createElectronHost$1() {
73684
73684
  const store = new Store({ name: "dash-bots" });
73685
73685
  const budgetStore = new Store({ name: "dash-bot-budgets" });
73686
+ const memoryStore = new Store({ name: "dash-bot-memory" });
73686
73687
  const botsRoot = path$3.join(app$2.getPath("userData"), "bots");
73687
73688
 
73688
73689
  return {
@@ -73700,6 +73701,11 @@ function createElectronHost$1() {
73700
73701
  budgetStore.get("store", { budgets: {}, spend: {}, overrides: {} }),
73701
73702
  write: (obj) => budgetStore.set("store", obj),
73702
73703
  },
73704
+ // Separate blob for scoped bot memory (P1: FR-010).
73705
+ memoryPersistence: {
73706
+ read: () => memoryStore.get("store", { scopes: {} }),
73707
+ write: (obj) => memoryStore.set("store", obj),
73708
+ },
73703
73709
  };
73704
73710
  }
73705
73711
 
@@ -74777,6 +74783,7 @@ var engines$1 = { getEngine, listEngines, registerEngine };
74777
74783
  * botId: string,
74778
74784
  * allowedTools?: string[],
74779
74785
  * mcpServers?: string[],
74786
+ * internalServers?: string[],
74780
74787
  * approvalPolicy?: "ask" | "allow",
74781
74788
  * resolveServer: (toolName: string) => (string | null),
74782
74789
  * createApproval: (request: object) => { id: string, promise: Promise<any> },
@@ -74792,6 +74799,7 @@ function createRequestPermission$1(ctx) {
74792
74799
  botId,
74793
74800
  allowedTools = [],
74794
74801
  mcpServers = [],
74802
+ internalServers = [],
74795
74803
  resolveServer,
74796
74804
  createApproval,
74797
74805
  audit = () => {},
@@ -74840,6 +74848,16 @@ function createRequestPermission$1(ctx) {
74840
74848
 
74841
74849
  const serverName = resolveServer(toolName);
74842
74850
 
74851
+ // 1b. Internal Bot Factory tools (e.g. bot-memory) are the bot's own
74852
+ // sandbox — auto-allowed, never a consent prompt or external action.
74853
+ if (serverName && internalServers.includes(serverName)) {
74854
+ return record(
74855
+ toolName,
74856
+ { allow: true },
74857
+ { outcome: "internal", serverName },
74858
+ );
74859
+ }
74860
+
74843
74861
  // 2. A tool whose server the bot was never configured with is denied
74844
74862
  // without prompting — it's not a consent gap, it's out of scope.
74845
74863
  if (!serverName || !mcpServers.includes(serverName)) {
@@ -74959,6 +74977,9 @@ let BotRunner$1 = class BotRunner {
74959
74977
  this._makeRequestPermission =
74960
74978
  deps.makeRequestPermission || createRequestPermission;
74961
74979
  this._gate = deps.gate; // forwarded to PermissionGate ctx (optional)
74980
+ // Virtual servers whose tools are auto-allowed (e.g. "bot-memory") — the
74981
+ // bot's own sandbox, not external actions. Forwarded to the gate ctx.
74982
+ this._internalServers = deps.internalServers || [];
74962
74983
  this._isPaused = deps.isPaused || (() => false);
74963
74984
  // Called after each run with the run's token usage so budgets (Slice 5)
74964
74985
  // can accrue cost. Optional — default no-op keeps the runner portable.
@@ -75030,6 +75051,7 @@ let BotRunner$1 = class BotRunner {
75030
75051
  workspaceId: bot.workspaceId,
75031
75052
  allowedTools: bot.allowedTools || [],
75032
75053
  mcpServers: bot.mcpServers || [],
75054
+ internalServers: this._internalServers,
75033
75055
  resolveServer,
75034
75056
  createApproval: (request) => this._approvals.create(request),
75035
75057
  audit: this._audit,
@@ -75491,6 +75513,233 @@ let PauseController$1 = class PauseController {
75491
75513
 
75492
75514
  var PauseController_1 = PauseController$1;
75493
75515
 
75516
+ /**
75517
+ * BotMemory.js
75518
+ *
75519
+ * Durable, scoped key-value memory for bots (PRD FR-010 / FR-012, US-012/015):
75520
+ * a bot can remember facts across runs. Values are namespaced by scope
75521
+ * (`workspace` — isolated per workspace — or `global` — shared across a
75522
+ * principal's bots) and carry a monotonic `version` + `updatedAt` so a later
75523
+ * slice can add history/optimistic concurrency without a data migration.
75524
+ *
75525
+ * Portable (NFR-006): the durable blob is injected as `persistence` (same shape
75526
+ * as BotStore/BudgetController), so this loads and runs under plain Node. The
75527
+ * Electron wiring (electron-store) lives in host.js. A KV store needs no SQL for
75528
+ * v1; SQLite can later slot in behind this exact interface if volume demands.
75529
+ */
75530
+
75531
+ const VALID_SCOPES = ["workspace", "global"];
75532
+
75533
+ /** Bucket key for a (scope, id) pair. Global collapses all ids to one bucket. */
75534
+ function bucketKey(scope, id) {
75535
+ return scope === "global" ? "global" : `workspace:${id || "default"}`;
75536
+ }
75537
+
75538
+ let BotMemory$1 = class BotMemory {
75539
+ /**
75540
+ * @param {{ persistence: { read: () => object, write: (o: object) => void },
75541
+ * clock?: { now: () => string } }} deps
75542
+ */
75543
+ constructor({ persistence, clock } = {}) {
75544
+ if (!persistence) throw new Error("BotMemory: persistence is required");
75545
+ this._persistence = persistence;
75546
+ this._now = (clock && clock.now) || (() => new Date().toISOString());
75547
+ }
75548
+
75549
+ _read() {
75550
+ const blob = this._persistence.read() || {};
75551
+ return blob.scopes ? blob : { scopes: {} };
75552
+ }
75553
+
75554
+ _write(blob) {
75555
+ this._persistence.write(blob);
75556
+ }
75557
+
75558
+ /** @returns {*} the stored value, or undefined if absent. */
75559
+ get(scope, id, key) {
75560
+ const bucket = this._read().scopes[bucketKey(scope, id)] || {};
75561
+ const entry = bucket[key];
75562
+ return entry ? entry.value : undefined;
75563
+ }
75564
+
75565
+ /** Store (or overwrite) a value; bumps version. @returns the stored entry. */
75566
+ set(scope, id, key, value) {
75567
+ const blob = this._read();
75568
+ const bk = bucketKey(scope, id);
75569
+ const bucket = blob.scopes[bk] || (blob.scopes[bk] = {});
75570
+ const prev = bucket[key];
75571
+ const entry = {
75572
+ value,
75573
+ version: prev ? prev.version + 1 : 1,
75574
+ updatedAt: this._now(),
75575
+ };
75576
+ bucket[key] = entry;
75577
+ this._write(blob);
75578
+ return entry;
75579
+ }
75580
+
75581
+ /** @returns {Array<{key,value,version,updatedAt}>} entries, optionally prefixed. */
75582
+ list(scope, id, prefix) {
75583
+ const bucket = this._read().scopes[bucketKey(scope, id)] || {};
75584
+ return Object.keys(bucket)
75585
+ .filter((k) => !prefix || k.startsWith(prefix))
75586
+ .sort()
75587
+ .map((k) => ({
75588
+ key: k,
75589
+ value: bucket[k].value,
75590
+ version: bucket[k].version,
75591
+ updatedAt: bucket[k].updatedAt,
75592
+ }));
75593
+ }
75594
+
75595
+ /** @returns {boolean} true if a value was removed. */
75596
+ delete(scope, id, key) {
75597
+ const blob = this._read();
75598
+ const bucket = blob.scopes[bucketKey(scope, id)];
75599
+ if (!bucket || !(key in bucket)) return false;
75600
+ delete bucket[key];
75601
+ this._write(blob);
75602
+ return true;
75603
+ }
75604
+ };
75605
+
75606
+ var BotMemory_1 = { BotMemory: BotMemory$1, VALID_SCOPES };
75607
+
75608
+ /**
75609
+ * memoryTools.js
75610
+ *
75611
+ * Exposes BotMemory to bots as in-process tools (PRD FR-010): memory_get /
75612
+ * memory_set / memory_list / memory_delete. These are served under a virtual
75613
+ * "bot-memory" server that the bot PermissionGate auto-allows (it's the bot's
75614
+ * own sandbox, not an external action), so no consent prompt is required.
75615
+ *
75616
+ * Portable (NFR-006): no Electron. botController wires a BotMemory instance and
75617
+ * the calling bot's scope, and routes MEMORY_SERVER tool calls here. The result
75618
+ * shape matches the tool-loop engine's executeTool contract: { text, isError }.
75619
+ */
75620
+
75621
+ const MEMORY_SERVER$1 = "bot-memory";
75622
+
75623
+ const SCOPE_PROP = {
75624
+ type: "string",
75625
+ enum: ["workspace", "global"],
75626
+ description:
75627
+ "Which memory scope to use: 'workspace' (default, isolated to this bot's workspace) or 'global' (shared across your bots).",
75628
+ };
75629
+
75630
+ const MEMORY_TOOLS$1 = [
75631
+ {
75632
+ name: "memory_set",
75633
+ description:
75634
+ "Store a value in your durable memory under a key. Persists across runs so you can recall it later.",
75635
+ inputSchema: {
75636
+ type: "object",
75637
+ properties: {
75638
+ key: { type: "string", description: "Key to store the value under." },
75639
+ value: { description: "The value to store (any JSON)." },
75640
+ scope: SCOPE_PROP,
75641
+ },
75642
+ required: ["key", "value"],
75643
+ },
75644
+ },
75645
+ {
75646
+ name: "memory_get",
75647
+ description:
75648
+ "Retrieve a value previously stored with memory_set. Returns the value, or a note if nothing is stored.",
75649
+ inputSchema: {
75650
+ type: "object",
75651
+ properties: {
75652
+ key: { type: "string", description: "Key to look up." },
75653
+ scope: SCOPE_PROP,
75654
+ },
75655
+ required: ["key"],
75656
+ },
75657
+ },
75658
+ {
75659
+ name: "memory_list",
75660
+ description:
75661
+ "List the keys currently in your memory, optionally filtered by a key prefix.",
75662
+ inputSchema: {
75663
+ type: "object",
75664
+ properties: {
75665
+ prefix: {
75666
+ type: "string",
75667
+ description: "Only list keys with this prefix.",
75668
+ },
75669
+ scope: SCOPE_PROP,
75670
+ },
75671
+ },
75672
+ },
75673
+ {
75674
+ name: "memory_delete",
75675
+ description: "Delete a key from your memory.",
75676
+ inputSchema: {
75677
+ type: "object",
75678
+ properties: {
75679
+ key: { type: "string", description: "Key to delete." },
75680
+ scope: SCOPE_PROP,
75681
+ },
75682
+ required: ["key"],
75683
+ },
75684
+ },
75685
+ ];
75686
+
75687
+ function ok$1(text) {
75688
+ return { text, isError: false };
75689
+ }
75690
+ function fail$1(text) {
75691
+ return { text, isError: true };
75692
+ }
75693
+
75694
+ /**
75695
+ * Execute a memory_* tool call in-process.
75696
+ * @param {import("./BotMemory").BotMemory} memory
75697
+ * @param {{ workspaceId?: string }} ctx the calling bot's scope context
75698
+ * @param {string} toolName
75699
+ * @param {object} args
75700
+ * @returns {{ text: string, isError: boolean }}
75701
+ */
75702
+ function handleMemoryTool$1(memory, ctx, toolName, args = {}) {
75703
+ const scope = args && args.scope === "global" ? "global" : "workspace";
75704
+ const id = ctx && ctx.workspaceId;
75705
+ try {
75706
+ switch (toolName) {
75707
+ case "memory_set": {
75708
+ if (!args || !args.key) return fail$1("memory_set requires a 'key'.");
75709
+ const entry = memory.set(scope, id, args.key, args.value);
75710
+ return ok$1(`Stored '${args.key}' (${scope}, v${entry.version}).`);
75711
+ }
75712
+ case "memory_get": {
75713
+ if (!args || !args.key) return fail$1("memory_get requires a 'key'.");
75714
+ const value = memory.get(scope, id, args.key);
75715
+ if (value === undefined)
75716
+ return ok$1(`No value stored for '${args.key}' (${scope}).`);
75717
+ return ok$1(typeof value === "string" ? value : JSON.stringify(value));
75718
+ }
75719
+ case "memory_list": {
75720
+ const entries = memory.list(scope, id, args && args.prefix);
75721
+ if (!entries.length) return ok$1(`No memory keys stored (${scope}).`);
75722
+ return ok$1(entries.map((e) => `${e.key} (v${e.version})`).join("\n"));
75723
+ }
75724
+ case "memory_delete": {
75725
+ if (!args || !args.key) return fail$1("memory_delete requires a 'key'.");
75726
+ const removed = memory.delete(scope, id, args.key);
75727
+ return ok$1(
75728
+ removed
75729
+ ? `Deleted '${args.key}' (${scope}).`
75730
+ : `No value to delete for '${args.key}' (${scope}).`,
75731
+ );
75732
+ }
75733
+ default:
75734
+ return fail$1(`Unknown memory tool '${toolName}'.`);
75735
+ }
75736
+ } catch (e) {
75737
+ return fail$1(`Memory tool error: ${(e && e.message) || e}`);
75738
+ }
75739
+ }
75740
+
75741
+ var memoryTools = { MEMORY_SERVER: MEMORY_SERVER$1, MEMORY_TOOLS: MEMORY_TOOLS$1, handleMemoryTool: handleMemoryTool$1 };
75742
+
75494
75743
  /**
75495
75744
  * mcpResult.js
75496
75745
  *
@@ -75557,6 +75806,12 @@ const BotRunner = BotRunner_1;
75557
75806
  const BotScheduler = BotScheduler_1;
75558
75807
  const BudgetController = BudgetControllerExports;
75559
75808
  const PauseController = PauseController_1;
75809
+ const { BotMemory } = BotMemory_1;
75810
+ const {
75811
+ MEMORY_SERVER,
75812
+ MEMORY_TOOLS,
75813
+ handleMemoryTool,
75814
+ } = memoryTools;
75560
75815
  const { normalizeMcpResult } = mcpResult;
75561
75816
  const {
75562
75817
  getProvider: getProvider$1,
@@ -75633,10 +75888,16 @@ const botController$1 = {
75633
75888
  getPricing: pricingFor,
75634
75889
  });
75635
75890
 
75891
+ // Scoped, durable bot memory (P1: FR-010), served as in-process memory_*
75892
+ // tools that every bot can use without a consent prompt.
75893
+ this._memory = new BotMemory({ persistence: host.memoryPersistence });
75894
+
75636
75895
  this._runner = new BotRunner({
75637
75896
  engines,
75638
75897
  store: this._store,
75639
75898
  approvals: approvalsForRunner,
75899
+ // Memory tools are the bot's own sandbox — auto-allowed at the gate.
75900
+ internalServers: [MEMORY_SERVER],
75640
75901
  resolveRunProfile: (bot) => this._resolveRunProfile(bot),
75641
75902
  resolveTools: (bot) => this._resolveTools(bot),
75642
75903
  callTool: (serverName, toolName, args, o) =>
@@ -75869,10 +76130,24 @@ const botController$1 = {
75869
76130
  toolServer[tool.name] = server.serverName;
75870
76131
  }
75871
76132
  }
76133
+ // Always-available in-process memory tools (P1: FR-010).
76134
+ for (const tool of MEMORY_TOOLS) {
76135
+ tools.push(tool);
76136
+ toolServer[tool.name] = MEMORY_SERVER;
76137
+ }
75872
76138
  return { tools, resolveServer: (toolName) => toolServer[toolName] || null };
75873
76139
  },
75874
76140
 
75875
76141
  async _callTool(serverName, toolName, args, opts = {}) {
76142
+ // In-process memory tools bypass MCP; scoped to the calling bot's workspace.
76143
+ if (serverName === MEMORY_SERVER) {
76144
+ return handleMemoryTool(
76145
+ this._memory,
76146
+ { workspaceId: opts.workspaceId },
76147
+ toolName,
76148
+ args,
76149
+ );
76150
+ }
75876
76151
  const win = this._getMainWindow();
75877
76152
  // widgetId + token are null → the widget permission gate is bypassed; bot
75878
76153
  // tool calls are gated upstream by the bot PermissionGate.