@spinabot/brigade 1.13.0 → 1.14.0
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/convex/logs.d.ts +3 -3
- package/convex/memory.d.ts +21 -21
- package/convex/schema.d.ts +9 -9
- package/convex/skills.d.ts +3 -3
- package/dist/buildstamp.json +1 -1
- package/dist/cli/commands/config-cmd.d.ts +12 -19
- package/dist/cli/commands/config-cmd.d.ts.map +1 -1
- package/dist/cli/commands/config-cmd.js +14 -197
- package/dist/cli/commands/config-cmd.js.map +1 -1
- package/dist/core/agents-crud-ops.d.ts +15 -0
- package/dist/core/agents-crud-ops.d.ts.map +1 -0
- package/dist/core/agents-crud-ops.js +27 -0
- package/dist/core/agents-crud-ops.js.map +1 -0
- package/dist/core/agents-ops.d.ts +43 -0
- package/dist/core/agents-ops.d.ts.map +1 -0
- package/dist/core/agents-ops.js +117 -0
- package/dist/core/agents-ops.js.map +1 -0
- package/dist/core/channels-ops.d.ts +30 -0
- package/dist/core/channels-ops.d.ts.map +1 -0
- package/dist/core/channels-ops.js +52 -0
- package/dist/core/channels-ops.js.map +1 -0
- package/dist/core/config-ops.d.ts +77 -0
- package/dist/core/config-ops.d.ts.map +1 -0
- package/dist/core/config-ops.js +241 -0
- package/dist/core/config-ops.js.map +1 -0
- package/dist/core/exec-ops.d.ts +48 -0
- package/dist/core/exec-ops.d.ts.map +1 -0
- package/dist/core/exec-ops.js +101 -0
- package/dist/core/exec-ops.js.map +1 -0
- package/dist/core/integrations-ops.d.ts +25 -0
- package/dist/core/integrations-ops.d.ts.map +1 -0
- package/dist/core/integrations-ops.js +40 -0
- package/dist/core/integrations-ops.js.map +1 -0
- package/dist/core/memory-ops.d.ts +20 -0
- package/dist/core/memory-ops.d.ts.map +1 -0
- package/dist/core/memory-ops.js +40 -0
- package/dist/core/memory-ops.js.map +1 -0
- package/dist/core/pairing-ops.d.ts +33 -0
- package/dist/core/pairing-ops.d.ts.map +1 -0
- package/dist/core/pairing-ops.js +78 -0
- package/dist/core/pairing-ops.js.map +1 -0
- package/dist/core/provider-ops.d.ts +17 -0
- package/dist/core/provider-ops.d.ts.map +1 -0
- package/dist/core/provider-ops.js +29 -0
- package/dist/core/provider-ops.js.map +1 -0
- package/dist/core/server.d.ts.map +1 -1
- package/dist/core/server.js +91 -0
- package/dist/core/server.js.map +1 -1
- package/dist/core/sessions-ops.d.ts +25 -0
- package/dist/core/sessions-ops.d.ts.map +1 -0
- package/dist/core/sessions-ops.js +77 -0
- package/dist/core/sessions-ops.js.map +1 -0
- package/dist/core/skills-ops.d.ts +14 -0
- package/dist/core/skills-ops.d.ts.map +1 -0
- package/dist/core/skills-ops.js +28 -0
- package/dist/core/skills-ops.js.map +1 -0
- package/dist/protocol/methods.d.ts +478 -0
- package/dist/protocol/methods.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel pairing operations behind the `pairing.*` gateway RPCs — the
|
|
3
|
+
* `brigade pairing <list|approve|revoke>` surface, reachable from a remote
|
|
4
|
+
* client.
|
|
5
|
+
*
|
|
6
|
+
* OPERATOR-SCOPED channel access control (approve/deny strangers who DM the
|
|
7
|
+
* bot). Per-channel, never a per-session target, so no per-session guard. The
|
|
8
|
+
* RPCs REQUIRE an explicit `channel` (no CLI-style auto-pick) — a client knows
|
|
9
|
+
* the channel from `system.capabilities`. Reuses the SAME access-control
|
|
10
|
+
* primitives the CLI calls, including the owner-bootstrap + in-channel notify
|
|
11
|
+
* on approve.
|
|
12
|
+
*/
|
|
13
|
+
import { approvePairingCode, readChannelOwner, readPendingPairings, revokePairingCode, setChannelOwner, } from "../agents/channels/access-control/index.js";
|
|
14
|
+
import { BUNDLED_MODULES, loadModules } from "../agents/extensions/index.js";
|
|
15
|
+
import { DEFAULT_AGENT_ID, resolveAgentWorkspaceDir } from "../config/paths.js";
|
|
16
|
+
import { loadConfig } from "./config.js";
|
|
17
|
+
/** Best-effort adapter lookup — only `approve` needs it (owner-bootstrap + notify). */
|
|
18
|
+
async function resolveAdapter(channel) {
|
|
19
|
+
try {
|
|
20
|
+
const config = loadConfig();
|
|
21
|
+
const workspaceDir = resolveAgentWorkspaceDir(DEFAULT_AGENT_ID);
|
|
22
|
+
const registry = await loadModules({
|
|
23
|
+
modules: BUNDLED_MODULES,
|
|
24
|
+
meta: { agentId: DEFAULT_AGENT_ID, workspaceDir, cwd: workspaceDir, config: config },
|
|
25
|
+
});
|
|
26
|
+
return registry.channels.find((c) => c.id === channel);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return undefined;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function handlePairingList(params) {
|
|
33
|
+
const p = (params ?? {});
|
|
34
|
+
const channel = (p.channel ?? "").trim();
|
|
35
|
+
if (!channel)
|
|
36
|
+
throw new Error("pairing.list: missing 'channel'");
|
|
37
|
+
return { channel, pending: readPendingPairings(channel) };
|
|
38
|
+
}
|
|
39
|
+
export async function handlePairingApprove(params) {
|
|
40
|
+
const p = (params ?? {});
|
|
41
|
+
const channel = (p.channel ?? "").trim();
|
|
42
|
+
const code = (p.code ?? "").trim();
|
|
43
|
+
if (!channel || !code)
|
|
44
|
+
return { ok: false, channel, reason: "missing 'channel' or 'code'" };
|
|
45
|
+
const approved = approvePairingCode(channel, code);
|
|
46
|
+
if (!approved)
|
|
47
|
+
return { ok: false, channel, reason: "unknown or expired pairing code" };
|
|
48
|
+
// Owner bootstrap (bot-separate channels like Telegram): the first approved
|
|
49
|
+
// sender becomes the recorded owner so they can run admin commands. Reaching
|
|
50
|
+
// this RPC already proves operator access. Never overwrites an existing owner.
|
|
51
|
+
let becameOwner = false;
|
|
52
|
+
const adapter = await resolveAdapter(channel);
|
|
53
|
+
if (adapter?.pairing?.botIsSeparateFromOperator && !readChannelOwner(channel)) {
|
|
54
|
+
becameOwner = setChannelOwner(channel, approved.senderId);
|
|
55
|
+
}
|
|
56
|
+
// Best-effort in-channel "you're approved" reply when the adapter wires it.
|
|
57
|
+
const notify = adapter?.pairing?.notifyApproval;
|
|
58
|
+
if (notify) {
|
|
59
|
+
try {
|
|
60
|
+
await notify({ senderId: approved.senderId, senderName: approved.senderName });
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
/* non-fatal — the approval already landed in the allow-list */
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return { ok: true, channel, sender: approved.senderId, owner: becameOwner };
|
|
67
|
+
}
|
|
68
|
+
export function handlePairingRevoke(params) {
|
|
69
|
+
const p = (params ?? {});
|
|
70
|
+
const channel = (p.channel ?? "").trim();
|
|
71
|
+
const code = (p.code ?? "").trim();
|
|
72
|
+
if (!channel || !code)
|
|
73
|
+
return { ok: false, channel, reason: "missing 'channel' or 'code'" };
|
|
74
|
+
return revokePairingCode(channel, code)
|
|
75
|
+
? { ok: true, channel }
|
|
76
|
+
: { ok: false, channel, reason: "no matching pending code" };
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=pairing-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing-ops.js","sourceRoot":"","sources":["../../src/core/pairing-ops.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-key removal behind the `provider.remove` gateway RPC.
|
|
3
|
+
*
|
|
4
|
+
* The genuine gap: `add-provider` adds a key, but there was NO way to REMOVE one
|
|
5
|
+
* over the gateway — keys live in `auth-profiles.json` (not config, so config.set
|
|
6
|
+
* can't reach them) and no tool exposes removal. This closes it. Operator-scoped
|
|
7
|
+
* per-agent (no per-session guard — allowlisted).
|
|
8
|
+
*/
|
|
9
|
+
export interface ProviderRemoveResult {
|
|
10
|
+
ok: boolean;
|
|
11
|
+
providerId: string;
|
|
12
|
+
agentId: string;
|
|
13
|
+
removed: number;
|
|
14
|
+
reason?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function handleProviderRemove(params: unknown): ProviderRemoveResult;
|
|
17
|
+
//# sourceMappingURL=provider-ops.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-ops.d.ts","sourceRoot":"","sources":["../../src/core/provider-ops.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,MAAM,WAAW,oBAAoB;IACpC,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AACD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,OAAO,GAAG,oBAAoB,CAe1E"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-key removal behind the `provider.remove` gateway RPC.
|
|
3
|
+
*
|
|
4
|
+
* The genuine gap: `add-provider` adds a key, but there was NO way to REMOVE one
|
|
5
|
+
* over the gateway — keys live in `auth-profiles.json` (not config, so config.set
|
|
6
|
+
* can't reach them) and no tool exposes removal. This closes it. Operator-scoped
|
|
7
|
+
* per-agent (no per-session guard — allowlisted).
|
|
8
|
+
*/
|
|
9
|
+
import { readProfiles, writeProfiles } from "../auth/profiles.js";
|
|
10
|
+
import { DEFAULT_AGENT_ID } from "../config/paths.js";
|
|
11
|
+
export function handleProviderRemove(params) {
|
|
12
|
+
const p = (params ?? {});
|
|
13
|
+
const providerId = (p.providerId ?? "").trim().toLowerCase();
|
|
14
|
+
const agentId = (p.agentId ?? "").trim() || DEFAULT_AGENT_ID;
|
|
15
|
+
if (!providerId)
|
|
16
|
+
return { ok: false, providerId, agentId, removed: 0, reason: "missing 'providerId'" };
|
|
17
|
+
const file = readProfiles(agentId);
|
|
18
|
+
let removed = 0;
|
|
19
|
+
for (const [key, profile] of Object.entries(file.profiles)) {
|
|
20
|
+
if ((profile.provider ?? "").trim().toLowerCase() === providerId) {
|
|
21
|
+
delete file.profiles[key];
|
|
22
|
+
removed++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (removed > 0)
|
|
26
|
+
writeProfiles(agentId, file);
|
|
27
|
+
return { ok: removed > 0, providerId, agentId, removed, ...(removed === 0 ? { reason: "no key found for that provider" } : {}) };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=provider-ops.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-ops.js","sourceRoot":"","sources":["../../src/core/provider-ops.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAStD,MAAM,UAAU,oBAAoB,CAAC,MAAe;IACnD,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,EAAE,CAA8C,CAAC;IACtE,MAAM,UAAU,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC7D,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,gBAAgB,CAAC;IAC7D,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACvG,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5D,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,KAAK,UAAU,EAAE,CAAC;YAClE,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,EAAE,CAAC;QACX,CAAC;IACF,CAAC;IACD,IAAI,OAAO,GAAG,CAAC;QAAE,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC9C,OAAO,EAAE,EAAE,EAAE,OAAO,GAAG,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAClI,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/core/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAySH,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAUzD,MAAM,WAAW,aAAa;IAC7B,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AA8FD,wBAAsB,WAAW,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC,CAwKjF"}
|
package/dist/core/server.js
CHANGED
|
@@ -135,6 +135,17 @@ import { mutateConfigAtomic } from "../config/io.js";
|
|
|
135
135
|
import { acquireGatewayLock } from "./gateway-lock.js";
|
|
136
136
|
import { clearHeartbeatFile, clearPidFile, writeHeartbeatFile, writePidFile } from "./gateway-probe.js";
|
|
137
137
|
import { extractToken, matchesAnyToken, resolveGatewayAuth } from "./gateway-auth.js";
|
|
138
|
+
import { handleConfigGet, handleConfigList, handleConfigSchema, handleConfigSet, handleConfigUnset, handleConfigValidate, } from "./config-ops.js";
|
|
139
|
+
import { handleExecAllow, handleExecAllowPattern, handleExecDenyTest, handleExecList, handleExecRemove, } from "./exec-ops.js";
|
|
140
|
+
import { handleAgentsBind, handleAgentsBindings, handleAgentsUnbind } from "./agents-ops.js";
|
|
141
|
+
import { handlePairingApprove, handlePairingList, handlePairingRevoke } from "./pairing-ops.js";
|
|
142
|
+
import { handleSessionsCleanup } from "./sessions-ops.js";
|
|
143
|
+
import { handleMemoryManage, handleMemoryWrite } from "./memory-ops.js";
|
|
144
|
+
import { handleAgentsAdd, handleAgentsDelete, handleAgentsSetIdentity } from "./agents-crud-ops.js";
|
|
145
|
+
import { handleSkillsCreate, handleSkillsDelete, handleSkillsWriteFile } from "./skills-ops.js";
|
|
146
|
+
import { handleChannelsAllowAdd, handleChannelsAllowList, handleChannelsAllowRemove, handleChannelsConnect, handleChannelsDisconnect, } from "./channels-ops.js";
|
|
147
|
+
import { handleProviderRemove } from "./provider-ops.js";
|
|
148
|
+
import { handleComposio, handleOauth } from "./integrations-ops.js";
|
|
138
149
|
// Persist a model selection to brigade.json's new wizard-shape (the lifted
|
|
139
150
|
// code expected the older flat `defaultProvider`/`defaultModelId` fields).
|
|
140
151
|
// Writes through the same `agents.defaults.{provider, model.primary}` path
|
|
@@ -4093,6 +4104,86 @@ async function continueBoot(args) {
|
|
|
4093
4104
|
disposeHandlers.push(registerGatewayHandler("org.snapshot", (_params) => handleOrgSnapshot(undefined, {
|
|
4094
4105
|
loadConfig: () => loadConfig(),
|
|
4095
4106
|
})));
|
|
4107
|
+
// `config.*` — operator-level config CRUD over the wire (the `brigade
|
|
4108
|
+
// config` CLI, reachable from a remote client). Path/value/redact shape:
|
|
4109
|
+
// never session-targeted, so the guard-sweep correctly needs no per-session
|
|
4110
|
+
// access check. Reads/writes go through the mode-aware loadConfig/saveConfig,
|
|
4111
|
+
// so this works in filesystem AND Convex mode.
|
|
4112
|
+
disposeHandlers.push(registerGatewayHandler("config.get", handleConfigGet));
|
|
4113
|
+
disposeHandlers.push(registerGatewayHandler("config.set", handleConfigSet));
|
|
4114
|
+
disposeHandlers.push(registerGatewayHandler("config.unset", handleConfigUnset));
|
|
4115
|
+
disposeHandlers.push(registerGatewayHandler("config.list", handleConfigList));
|
|
4116
|
+
disposeHandlers.push(registerGatewayHandler("config.schema", handleConfigSchema));
|
|
4117
|
+
disposeHandlers.push(registerGatewayHandler("config.validate", handleConfigValidate));
|
|
4118
|
+
// `exec.*` — operator-level exec-approval allowlist CRUD (the `brigade exec`
|
|
4119
|
+
// CLI over the wire). Per-agent + operator-scoped (the operator manages
|
|
4120
|
+
// their OWN agents' bash-approval allowlist), the same posture as the
|
|
4121
|
+
// allowlisted exec-allow-all / exec-grant-skill RPCs — no per-session guard
|
|
4122
|
+
// (see ALLOWLIST_NO_GUARD_NEEDED in server.guard-sweep.test.ts). The
|
|
4123
|
+
// hard-deny safety net in exec-approvals.ts still applies on every allow.
|
|
4124
|
+
disposeHandlers.push(registerGatewayHandler("exec.list", handleExecList));
|
|
4125
|
+
disposeHandlers.push(registerGatewayHandler("exec.allow", handleExecAllow));
|
|
4126
|
+
disposeHandlers.push(registerGatewayHandler("exec.allow-pattern", handleExecAllowPattern));
|
|
4127
|
+
disposeHandlers.push(registerGatewayHandler("exec.remove", handleExecRemove));
|
|
4128
|
+
disposeHandlers.push(registerGatewayHandler("exec.deny-test", handleExecDenyTest));
|
|
4129
|
+
// `agents.*` — operator-level routing-binding management (which agent owns
|
|
4130
|
+
// which channel/account). The genuine no-other-path gap: agent add/delete/
|
|
4131
|
+
// set-identity are already reachable via the `manage_agent` tool, but
|
|
4132
|
+
// bindings had no remote path. Operator-scoped config mutation, no per-
|
|
4133
|
+
// session guard (allowlisted in server.guard-sweep.test.ts).
|
|
4134
|
+
disposeHandlers.push(registerGatewayHandler("agents.bindings", handleAgentsBindings));
|
|
4135
|
+
disposeHandlers.push(registerGatewayHandler("agents.bind", handleAgentsBind));
|
|
4136
|
+
disposeHandlers.push(registerGatewayHandler("agents.unbind", handleAgentsUnbind));
|
|
4137
|
+
// `pairing.*` — operator-level channel pairing (approve/revoke strangers who
|
|
4138
|
+
// DM the bot). Per-channel + operator-scoped, no per-session guard. The RPCs
|
|
4139
|
+
// require an explicit channel (a client gets the channel list from
|
|
4140
|
+
// system.capabilities), unlike the CLI's single-channel auto-pick.
|
|
4141
|
+
disposeHandlers.push(registerGatewayHandler("pairing.list", handlePairingList));
|
|
4142
|
+
disposeHandlers.push(registerGatewayHandler("pairing.approve", handlePairingApprove));
|
|
4143
|
+
disposeHandlers.push(registerGatewayHandler("pairing.revoke", handlePairingRevoke));
|
|
4144
|
+
// `sessions.cleanup` — operator maintenance: delete an agent's stale idle
|
|
4145
|
+
// transcript files (the gateway regenerates the store entry on next access).
|
|
4146
|
+
// NOT session-content access (unlike sessions.list/history), so no per-
|
|
4147
|
+
// session guard (allowlisted in server.guard-sweep.test.ts).
|
|
4148
|
+
disposeHandlers.push(registerGatewayHandler("sessions.cleanup", handleSessionsCleanup));
|
|
4149
|
+
// `memory.*` — Tideline write + governance (write_memory / manage_memory).
|
|
4150
|
+
// Memory lives in facts.jsonl (NOT config), so config.set can't reach it;
|
|
4151
|
+
// these are the only typed remote path to MUTATE memory (read is covered by
|
|
4152
|
+
// memory-query / memory-graph). Operator-scoped owner origin, no per-session
|
|
4153
|
+
// guard (allowlisted in server.guard-sweep.test.ts).
|
|
4154
|
+
disposeHandlers.push(registerGatewayHandler("memory.write", handleMemoryWrite));
|
|
4155
|
+
disposeHandlers.push(registerGatewayHandler("memory.manage", handleMemoryManage));
|
|
4156
|
+
// agents.add/delete/set-identity — agent CRUD (reuses the manage_agent tool,
|
|
4157
|
+
// which wraps `brigade agents add/delete/set-identity`). Seeds/soft-deletes a
|
|
4158
|
+
// workspace, so config.set alone can't do it. Operator-scoped (allowlisted).
|
|
4159
|
+
disposeHandlers.push(registerGatewayHandler("agents.add", handleAgentsAdd));
|
|
4160
|
+
disposeHandlers.push(registerGatewayHandler("agents.delete", handleAgentsDelete));
|
|
4161
|
+
disposeHandlers.push(registerGatewayHandler("agents.set-identity", handleAgentsSetIdentity));
|
|
4162
|
+
// skills.create/delete/write-file — skill authoring (reuses the manage_skill
|
|
4163
|
+
// tool). SKILL.md files on disk, not config. (status/install/update already
|
|
4164
|
+
// cover read/install/enable.) Operator-scoped (allowlisted).
|
|
4165
|
+
disposeHandlers.push(registerGatewayHandler("skills.create", handleSkillsCreate));
|
|
4166
|
+
disposeHandlers.push(registerGatewayHandler("skills.delete", handleSkillsDelete));
|
|
4167
|
+
disposeHandlers.push(registerGatewayHandler("skills.write-file", handleSkillsWriteFile));
|
|
4168
|
+
// channels.* — LIVE connect/disconnect (runtime adapter via the global
|
|
4169
|
+
// channel manager) + DM allow-from (a per-channel file store, not config).
|
|
4170
|
+
// Channel enable/disable/policy are already config.set-reachable. Operator-
|
|
4171
|
+
// scoped (allowlisted). connect reuses the owner-scoped connect_channel tool.
|
|
4172
|
+
disposeHandlers.push(registerGatewayHandler("channels.connect", handleChannelsConnect));
|
|
4173
|
+
disposeHandlers.push(registerGatewayHandler("channels.disconnect", handleChannelsDisconnect));
|
|
4174
|
+
disposeHandlers.push(registerGatewayHandler("channels.allow-add", handleChannelsAllowAdd));
|
|
4175
|
+
disposeHandlers.push(registerGatewayHandler("channels.allow-remove", handleChannelsAllowRemove));
|
|
4176
|
+
disposeHandlers.push(registerGatewayHandler("channels.allow-list", handleChannelsAllowList));
|
|
4177
|
+
// provider.remove — delete a provider key (auth-profiles.json, not config;
|
|
4178
|
+
// add-provider exists, removal had no gateway path). Operator-scoped.
|
|
4179
|
+
disposeHandlers.push(registerGatewayHandler("provider.remove", handleProviderRemove));
|
|
4180
|
+
// composio + oauth — integrations. `composio` is remote-clean (Composio
|
|
4181
|
+
// hosts the OAuth callback; the gateway hands over a click-link + polls).
|
|
4182
|
+
// `oauth` is the DIY loopback flow (callback on the gateway host — completes
|
|
4183
|
+
// only for a local/tunneled operator; status/token work remotely). Both
|
|
4184
|
+
// reuse the owner-scoped tools. Operator-scoped (allowlisted).
|
|
4185
|
+
disposeHandlers.push(registerGatewayHandler("composio", handleComposio));
|
|
4186
|
+
disposeHandlers.push(registerGatewayHandler("oauth", handleOauth));
|
|
4096
4187
|
// Wave O0.8 GAP 11 — opt the session inbox into JSONL persistence at
|
|
4097
4188
|
// gateway boot. The disk write surface defaults off so the existing
|
|
4098
4189
|
// unit-test fleet (which doesn't tempdir-isolate ~/.brigade) keeps
|