@trops/dash-core 0.1.625 → 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.
- package/dist/electron/index.js +275 -0
- package/dist/electron/index.js.map +1 -1
- package/dist/index.esm.js +409 -46
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +409 -46
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/electron/index.js
CHANGED
|
@@ -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.
|