@geminixiang/mama 0.2.0-beta.1 → 0.2.0-beta.10
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 +168 -371
- package/dist/adapter.d.ts +36 -12
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js.map +1 -1
- package/dist/adapters/discord/bot.d.ts +12 -7
- package/dist/adapters/discord/bot.d.ts.map +1 -1
- package/dist/adapters/discord/bot.js +358 -135
- package/dist/adapters/discord/bot.js.map +1 -1
- package/dist/adapters/discord/context.d.ts +1 -1
- package/dist/adapters/discord/context.d.ts.map +1 -1
- package/dist/adapters/discord/context.js +100 -36
- package/dist/adapters/discord/context.js.map +1 -1
- package/dist/adapters/shared.d.ts +71 -0
- package/dist/adapters/shared.d.ts.map +1 -0
- package/dist/adapters/shared.js +168 -0
- package/dist/adapters/shared.js.map +1 -0
- package/dist/adapters/slack/bot.d.ts +30 -24
- package/dist/adapters/slack/bot.d.ts.map +1 -1
- package/dist/adapters/slack/bot.js +620 -224
- package/dist/adapters/slack/bot.js.map +1 -1
- package/dist/adapters/slack/branch-manager.d.ts +22 -0
- package/dist/adapters/slack/branch-manager.d.ts.map +1 -0
- package/dist/adapters/slack/branch-manager.js +97 -0
- package/dist/adapters/slack/branch-manager.js.map +1 -0
- package/dist/adapters/slack/context.d.ts +1 -1
- package/dist/adapters/slack/context.d.ts.map +1 -1
- package/dist/adapters/slack/context.js +127 -72
- package/dist/adapters/slack/context.js.map +1 -1
- package/dist/adapters/slack/session.d.ts +3 -0
- package/dist/adapters/slack/session.d.ts.map +1 -0
- package/dist/adapters/slack/session.js +16 -0
- package/dist/adapters/slack/session.js.map +1 -0
- package/dist/adapters/slack/tools/attach.d.ts +1 -1
- package/dist/adapters/slack/tools/attach.d.ts.map +1 -1
- package/dist/adapters/slack/tools/attach.js.map +1 -1
- package/dist/adapters/telegram/bot.d.ts +4 -2
- package/dist/adapters/telegram/bot.d.ts.map +1 -1
- package/dist/adapters/telegram/bot.js +193 -147
- package/dist/adapters/telegram/bot.js.map +1 -1
- package/dist/adapters/telegram/context.d.ts.map +1 -1
- package/dist/adapters/telegram/context.js +58 -111
- package/dist/adapters/telegram/context.js.map +1 -1
- package/dist/adapters/telegram/html.d.ts +3 -0
- package/dist/adapters/telegram/html.d.ts.map +1 -0
- package/dist/adapters/telegram/html.js +98 -0
- package/dist/adapters/telegram/html.js.map +1 -0
- package/dist/agent.d.ts +9 -13
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +601 -567
- package/dist/agent.js.map +1 -1
- package/dist/commands/auto-reply.d.ts +16 -0
- package/dist/commands/auto-reply.d.ts.map +1 -0
- package/dist/commands/auto-reply.js +69 -0
- package/dist/commands/auto-reply.js.map +1 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +19 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/login.d.ts +5 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +76 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/model.d.ts +14 -0
- package/dist/commands/model.d.ts.map +1 -0
- package/dist/commands/model.js +112 -0
- package/dist/commands/model.js.map +1 -0
- package/dist/commands/new.d.ts +9 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +28 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/registry.d.ts +7 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +14 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/sandbox.d.ts +10 -0
- package/dist/commands/sandbox.d.ts.map +1 -0
- package/dist/commands/sandbox.js +88 -0
- package/dist/commands/sandbox.js.map +1 -0
- package/dist/commands/session-view.d.ts +5 -0
- package/dist/commands/session-view.d.ts.map +1 -0
- package/dist/commands/session-view.js +62 -0
- package/dist/commands/session-view.js.map +1 -0
- package/dist/commands/types.d.ts +41 -0
- package/dist/commands/types.d.ts.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/commands/utils.d.ts +8 -0
- package/dist/commands/utils.d.ts.map +1 -0
- package/dist/commands/utils.js +14 -0
- package/dist/commands/utils.js.map +1 -0
- package/dist/config.d.ts +49 -30
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +313 -75
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +10 -42
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +14 -127
- package/dist/context.js.map +1 -1
- package/dist/events.d.ts +13 -6
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +118 -64
- package/dist/events.js.map +1 -1
- package/dist/execution-resolver.d.ts +9 -5
- package/dist/execution-resolver.d.ts.map +1 -1
- package/dist/execution-resolver.js +82 -18
- package/dist/execution-resolver.js.map +1 -1
- package/dist/file-guards.d.ts +6 -0
- package/dist/file-guards.d.ts.map +1 -0
- package/dist/file-guards.js +48 -0
- package/dist/file-guards.js.map +1 -0
- package/dist/fs-atomic.d.ts +10 -0
- package/dist/fs-atomic.d.ts.map +1 -0
- package/dist/fs-atomic.js +45 -0
- package/dist/fs-atomic.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/instrument.d.ts.map +1 -1
- package/dist/instrument.js +4 -11
- package/dist/instrument.js.map +1 -1
- package/dist/log.d.ts +1 -5
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +13 -38
- package/dist/log.js.map +1 -1
- package/dist/{login.d.ts → login/index.d.ts} +16 -4
- package/dist/login/index.d.ts.map +1 -0
- package/dist/{login.js → login/index.js} +55 -17
- package/dist/login/index.js.map +1 -0
- package/dist/{link-server.d.ts → login/portal.d.ts} +7 -4
- package/dist/login/portal.d.ts.map +1 -0
- package/dist/login/portal.js +1453 -0
- package/dist/login/portal.js.map +1 -0
- package/dist/{link-token.d.ts → login/session.d.ts} +4 -3
- package/dist/login/session.d.ts.map +1 -0
- package/dist/{link-token.js → login/session.js} +1 -1
- package/dist/login/session.js.map +1 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +151 -373
- package/dist/main.js.map +1 -1
- package/dist/provisioner.d.ts +38 -52
- package/dist/provisioner.d.ts.map +1 -1
- package/dist/provisioner.js +212 -111
- package/dist/provisioner.js.map +1 -1
- package/dist/runtime/conversation-orchestrator.d.ts +42 -0
- package/dist/runtime/conversation-orchestrator.d.ts.map +1 -0
- package/dist/runtime/conversation-orchestrator.js +150 -0
- package/dist/runtime/conversation-orchestrator.js.map +1 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +2 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/session-runtime.d.ts +27 -0
- package/dist/runtime/session-runtime.d.ts.map +1 -0
- package/dist/runtime/session-runtime.js +211 -0
- package/dist/runtime/session-runtime.js.map +1 -0
- package/dist/sandbox/cloudflare.d.ts +15 -0
- package/dist/sandbox/cloudflare.d.ts.map +1 -0
- package/dist/sandbox/cloudflare.js +137 -0
- package/dist/sandbox/cloudflare.js.map +1 -0
- package/dist/sandbox/container.d.ts +2 -1
- package/dist/sandbox/container.d.ts.map +1 -1
- package/dist/sandbox/container.js +5 -1
- package/dist/sandbox/container.js.map +1 -1
- package/dist/sandbox/firecracker.d.ts +2 -1
- package/dist/sandbox/firecracker.d.ts.map +1 -1
- package/dist/sandbox/firecracker.js +6 -0
- package/dist/sandbox/firecracker.js.map +1 -1
- package/dist/sandbox/host.d.ts +2 -3
- package/dist/sandbox/host.d.ts.map +1 -1
- package/dist/sandbox/host.js +5 -5
- package/dist/sandbox/host.js.map +1 -1
- package/dist/sandbox/index.d.ts +6 -4
- package/dist/sandbox/index.d.ts.map +1 -1
- package/dist/sandbox/index.js +9 -6
- package/dist/sandbox/index.js.map +1 -1
- package/dist/sandbox/path-context.d.ts +4 -0
- package/dist/sandbox/path-context.d.ts.map +1 -0
- package/dist/sandbox/path-context.js +20 -0
- package/dist/sandbox/path-context.js.map +1 -0
- package/dist/sandbox/types.d.ts +17 -1
- package/dist/sandbox/types.d.ts.map +1 -1
- package/dist/sandbox/types.js.map +1 -1
- package/dist/sentry.d.ts +1 -1
- package/dist/sentry.d.ts.map +1 -1
- package/dist/sentry.js +4 -2
- package/dist/sentry.js.map +1 -1
- package/dist/session-policy.d.ts +13 -0
- package/dist/session-policy.d.ts.map +1 -0
- package/dist/session-policy.js +23 -0
- package/dist/session-policy.js.map +1 -0
- package/dist/session-store.d.ts +34 -3
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +184 -22
- package/dist/session-store.js.map +1 -1
- package/dist/session-view/command.d.ts +5 -0
- package/dist/session-view/command.d.ts.map +1 -0
- package/dist/session-view/command.js +11 -0
- package/dist/session-view/command.js.map +1 -0
- package/dist/session-view/portal.d.ts +16 -0
- package/dist/session-view/portal.d.ts.map +1 -0
- package/dist/session-view/portal.js +1742 -0
- package/dist/session-view/portal.js.map +1 -0
- package/dist/session-view/service.d.ts +34 -0
- package/dist/session-view/service.d.ts.map +1 -0
- package/dist/session-view/service.js +427 -0
- package/dist/session-view/service.js.map +1 -0
- package/dist/session-view/store.d.ts +18 -0
- package/dist/session-view/store.d.ts.map +1 -0
- package/dist/session-view/store.js +39 -0
- package/dist/session-view/store.js.map +1 -0
- package/dist/store.d.ts +3 -6
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +22 -48
- package/dist/store.js.map +1 -1
- package/dist/tool-diagnostics.d.ts +2 -0
- package/dist/tool-diagnostics.d.ts.map +1 -0
- package/dist/tool-diagnostics.js +7 -0
- package/dist/tool-diagnostics.js.map +1 -0
- package/dist/tools/bash.d.ts +1 -1
- package/dist/tools/bash.d.ts.map +1 -1
- package/dist/tools/bash.js.map +1 -1
- package/dist/tools/edit.d.ts +1 -1
- package/dist/tools/edit.d.ts.map +1 -1
- package/dist/tools/edit.js.map +1 -1
- package/dist/tools/event.d.ts +43 -2
- package/dist/tools/event.d.ts.map +1 -1
- package/dist/tools/event.js +48 -13
- package/dist/tools/event.js.map +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +3 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read.d.ts +1 -1
- package/dist/tools/read.d.ts.map +1 -1
- package/dist/tools/read.js.map +1 -1
- package/dist/tools/write.d.ts +1 -1
- package/dist/tools/write.d.ts.map +1 -1
- package/dist/tools/write.js.map +1 -1
- package/dist/trigger.d.ts +31 -0
- package/dist/trigger.d.ts.map +1 -0
- package/dist/trigger.js +98 -0
- package/dist/trigger.js.map +1 -0
- package/dist/ui-copy.d.ts +1 -0
- package/dist/ui-copy.d.ts.map +1 -1
- package/dist/ui-copy.js +3 -0
- package/dist/ui-copy.js.map +1 -1
- package/dist/vault-routing.d.ts +1 -7
- package/dist/vault-routing.d.ts.map +1 -1
- package/dist/vault-routing.js +6 -48
- package/dist/vault-routing.js.map +1 -1
- package/dist/vault.d.ts +21 -55
- package/dist/vault.d.ts.map +1 -1
- package/dist/vault.js +138 -263
- package/dist/vault.js.map +1 -1
- package/package.json +12 -10
- package/dist/bindings.d.ts +0 -63
- package/dist/bindings.d.ts.map +0 -1
- package/dist/bindings.js +0 -94
- package/dist/bindings.js.map +0 -1
- package/dist/link-server.d.ts.map +0 -1
- package/dist/link-server.js +0 -839
- package/dist/link-server.js.map +0 -1
- package/dist/link-token.d.ts.map +0 -1
- package/dist/link-token.js.map +0 -1
- package/dist/login.d.ts.map +0 -1
- package/dist/login.js.map +0 -1
- package/dist/vault.test.d.ts +0 -2
- package/dist/vault.test.d.ts.map +0 -1
- package/dist/vault.test.js +0 -67
- package/dist/vault.test.js.map +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Bot, BotAdapters, PlatformName } from "../adapter.js";
|
|
2
|
+
import type { DockerContainerManager } from "../provisioner.js";
|
|
3
|
+
import type { SessionRuntime } from "../runtime/session-runtime.js";
|
|
4
|
+
import type { SandboxConfig } from "../sandbox.js";
|
|
5
|
+
import type { VaultManager } from "../vault.js";
|
|
6
|
+
export interface LinkTokenStoreLike {
|
|
7
|
+
create(platform: PlatformName, platformUserId: string, conversationId: string, vaultId: string, providerId: string): {
|
|
8
|
+
token: string;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface SessionViewTokenStoreLike {
|
|
12
|
+
create(platform: PlatformName, platformUserId: string, conversationId: string, sessionKey: string, sessionFile: string, platformUserName?: string): {
|
|
13
|
+
token: string;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
export interface CommandServices {
|
|
17
|
+
workingDir: string;
|
|
18
|
+
runtime?: SessionRuntime;
|
|
19
|
+
sandbox: SandboxConfig;
|
|
20
|
+
vaultManager: VaultManager;
|
|
21
|
+
provisioner?: DockerContainerManager;
|
|
22
|
+
linkTokenStore: LinkTokenStoreLike;
|
|
23
|
+
sessionViewTokenStore: SessionViewTokenStoreLike;
|
|
24
|
+
portalBaseUrl?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface CommandContext {
|
|
27
|
+
bot: Bot;
|
|
28
|
+
responseCtx: BotAdapters["responseCtx"];
|
|
29
|
+
platform: PlatformName;
|
|
30
|
+
platformUserId: string;
|
|
31
|
+
conversationId: string;
|
|
32
|
+
vaultConversationId?: string;
|
|
33
|
+
sessionKey: string;
|
|
34
|
+
commandText: string;
|
|
35
|
+
privateConversation: boolean;
|
|
36
|
+
services: CommandServices;
|
|
37
|
+
}
|
|
38
|
+
export interface CommandHandler {
|
|
39
|
+
tryHandle(context: CommandContext): Promise<boolean>;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,kBAAkB;IACjC,MAAM,CACJ,QAAQ,EAAE,YAAY,EACtB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACtB;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,CACJ,QAAQ,EAAE,YAAY,EACtB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,EACnB,gBAAgB,CAAC,EAAE,MAAM,GACxB;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,CAAC,EAAE,sBAAsB,CAAC;IACrC,cAAc,EAAE,kBAAkB,CAAC;IACnC,qBAAqB,EAAE,yBAAyB,CAAC;IACjD,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,GAAG,CAAC;IACT,WAAW,EAAE,WAAW,CAAC,aAAa,CAAC,CAAC;IACxC,QAAQ,EAAE,YAAY,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,eAAe,CAAC;CAC3B;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACtD","sourcesContent":["import type { Bot, BotAdapters, PlatformName } from \"../adapter.js\";\nimport type { DockerContainerManager } from \"../provisioner.js\";\nimport type { SessionRuntime } from \"../runtime/session-runtime.js\";\nimport type { SandboxConfig } from \"../sandbox.js\";\nimport type { VaultManager } from \"../vault.js\";\n\nexport interface LinkTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n}\n\nexport interface SessionViewTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n sessionKey: string,\n sessionFile: string,\n platformUserName?: string,\n ): { token: string };\n}\n\nexport interface CommandServices {\n workingDir: string;\n runtime?: SessionRuntime;\n sandbox: SandboxConfig;\n vaultManager: VaultManager;\n provisioner?: DockerContainerManager;\n linkTokenStore: LinkTokenStoreLike;\n sessionViewTokenStore: SessionViewTokenStoreLike;\n portalBaseUrl?: string;\n}\n\nexport interface CommandContext {\n bot: Bot;\n responseCtx: BotAdapters[\"responseCtx\"];\n platform: PlatformName;\n platformUserId: string;\n conversationId: string;\n vaultConversationId?: string;\n sessionKey: string;\n commandText: string;\n privateConversation: boolean;\n services: CommandServices;\n}\n\nexport interface CommandHandler {\n tryHandle(context: CommandContext): Promise<boolean>;\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { Bot, BotAdapters, PlatformName } from \"../adapter.js\";\nimport type { DockerContainerManager } from \"../provisioner.js\";\nimport type { SessionRuntime } from \"../runtime/session-runtime.js\";\nimport type { SandboxConfig } from \"../sandbox.js\";\nimport type { VaultManager } from \"../vault.js\";\n\nexport interface LinkTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n vaultId: string,\n providerId: string,\n ): { token: string };\n}\n\nexport interface SessionViewTokenStoreLike {\n create(\n platform: PlatformName,\n platformUserId: string,\n conversationId: string,\n sessionKey: string,\n sessionFile: string,\n platformUserName?: string,\n ): { token: string };\n}\n\nexport interface CommandServices {\n workingDir: string;\n runtime?: SessionRuntime;\n sandbox: SandboxConfig;\n vaultManager: VaultManager;\n provisioner?: DockerContainerManager;\n linkTokenStore: LinkTokenStoreLike;\n sessionViewTokenStore: SessionViewTokenStoreLike;\n portalBaseUrl?: string;\n}\n\nexport interface CommandContext {\n bot: Bot;\n responseCtx: BotAdapters[\"responseCtx\"];\n platform: PlatformName;\n platformUserId: string;\n conversationId: string;\n vaultConversationId?: string;\n sessionKey: string;\n commandText: string;\n privateConversation: boolean;\n services: CommandServices;\n}\n\nexport interface CommandHandler {\n tryHandle(context: CommandContext): Promise<boolean>;\n}\n"]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BotEvent } from "../adapter.js";
|
|
2
|
+
import type { CommandContext } from "./types.js";
|
|
3
|
+
export declare function replyWithContext(responseCtx: CommandContext["responseCtx"], text: string): Promise<void>;
|
|
4
|
+
export declare function replyDiagnosticWithContext(responseCtx: CommandContext["responseCtx"], text: string, options?: {
|
|
5
|
+
style?: "muted" | "error";
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function isPrivateConversation(event: BotEvent): boolean;
|
|
8
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/commands/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,cAAc,CAAC,aAAa,CAAC,EAC1C,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,cAAc,CAAC,aAAa,CAAC,EAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAA;CAAE,GACtC,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO,CAE9D","sourcesContent":["import type { BotEvent } from \"../adapter.js\";\nimport type { CommandContext } from \"./types.js\";\n\nexport async function replyWithContext(\n responseCtx: CommandContext[\"responseCtx\"],\n text: string,\n): Promise<void> {\n await responseCtx.setTyping(false);\n await responseCtx.setWorking(false);\n await responseCtx.respond(text);\n}\n\nexport async function replyDiagnosticWithContext(\n responseCtx: CommandContext[\"responseCtx\"],\n text: string,\n options?: { style?: \"muted\" | \"error\" },\n): Promise<void> {\n await responseCtx.setTyping(false);\n await responseCtx.setWorking(false);\n await responseCtx.respondDiagnostic(text, options);\n}\n\nexport function isPrivateConversation(event: BotEvent): boolean {\n return event.conversationKind === \"direct\" || event.type === \"dm\";\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export async function replyWithContext(responseCtx, text) {
|
|
2
|
+
await responseCtx.setTyping(false);
|
|
3
|
+
await responseCtx.setWorking(false);
|
|
4
|
+
await responseCtx.respond(text);
|
|
5
|
+
}
|
|
6
|
+
export async function replyDiagnosticWithContext(responseCtx, text, options) {
|
|
7
|
+
await responseCtx.setTyping(false);
|
|
8
|
+
await responseCtx.setWorking(false);
|
|
9
|
+
await responseCtx.respondDiagnostic(text, options);
|
|
10
|
+
}
|
|
11
|
+
export function isPrivateConversation(event) {
|
|
12
|
+
return event.conversationKind === "direct" || event.type === "dm";
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/commands/utils.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,WAA0C,EAC1C,IAAY;IAEZ,MAAM,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,WAA0C,EAC1C,IAAY,EACZ,OAAuC;IAEvC,MAAM,WAAW,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,MAAM,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACpC,MAAM,WAAW,CAAC,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAe;IACnD,OAAO,KAAK,CAAC,gBAAgB,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;AACpE,CAAC","sourcesContent":["import type { BotEvent } from \"../adapter.js\";\nimport type { CommandContext } from \"./types.js\";\n\nexport async function replyWithContext(\n responseCtx: CommandContext[\"responseCtx\"],\n text: string,\n): Promise<void> {\n await responseCtx.setTyping(false);\n await responseCtx.setWorking(false);\n await responseCtx.respond(text);\n}\n\nexport async function replyDiagnosticWithContext(\n responseCtx: CommandContext[\"responseCtx\"],\n text: string,\n options?: { style?: \"muted\" | \"error\" },\n): Promise<void> {\n await responseCtx.setTyping(false);\n await responseCtx.setWorking(false);\n await responseCtx.respondDiagnostic(text, options);\n}\n\nexport function isPrivateConversation(event: BotEvent): boolean {\n return event.conversationKind === \"direct\" || event.type === \"dm\";\n}\n"]}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,41 +1,60 @@
|
|
|
1
|
+
import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
|
|
2
|
+
export declare class MissingGlobalSettingsError extends Error {
|
|
3
|
+
readonly settingsPath: string;
|
|
4
|
+
constructor(settingsPath: string);
|
|
5
|
+
}
|
|
1
6
|
export interface AgentConfig {
|
|
2
|
-
provider
|
|
3
|
-
model
|
|
4
|
-
thinkingLevel
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
logLevel?: "trace" | "debug" | "info" | "warn" | "error";
|
|
7
|
+
provider: string;
|
|
8
|
+
model: string;
|
|
9
|
+
thinkingLevel: ThinkingLevel;
|
|
10
|
+
logFormat: "console" | "json";
|
|
11
|
+
logLevel: "trace" | "debug" | "info" | "warn" | "error";
|
|
8
12
|
sentryDsn?: string;
|
|
13
|
+
sandboxCpus?: string;
|
|
14
|
+
sandboxMemory?: string;
|
|
15
|
+
sandboxBoostCpus?: string;
|
|
16
|
+
sandboxBoostMemory?: string;
|
|
17
|
+
sandboxImageWorkspaceMount?: "private" | "full";
|
|
18
|
+
}
|
|
19
|
+
export interface AutoReplyConfig {
|
|
20
|
+
enabled: boolean;
|
|
21
|
+
rules: string[];
|
|
22
|
+
}
|
|
23
|
+
export interface JudgeModelConfig {
|
|
24
|
+
provider: string;
|
|
25
|
+
model: string;
|
|
9
26
|
}
|
|
10
|
-
export declare function loadAgentConfig(
|
|
27
|
+
export declare function loadAgentConfig(): AgentConfig;
|
|
28
|
+
export declare function loadAgentConfigForConversation(conversationDir: string): AgentConfig;
|
|
29
|
+
export declare function saveConversationModelConfig(conversationDir: string, config: Pick<AgentConfig, "provider" | "model"> & Partial<Pick<AgentConfig, "thinkingLevel">>): void;
|
|
30
|
+
export declare function saveConversationSandboxConfig(conversationDir: string, config: {
|
|
31
|
+
imageWorkspaceMount: AgentConfig["sandboxImageWorkspaceMount"];
|
|
32
|
+
}): void;
|
|
11
33
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
34
|
+
* Resolve the model used to judge auto-reply rules. Falls back to the main
|
|
35
|
+
* llm.{provider,model} when llm.autoReply is not set, so a missing override
|
|
36
|
+
* keeps current behavior.
|
|
15
37
|
*/
|
|
16
|
-
export declare function
|
|
17
|
-
created: boolean;
|
|
18
|
-
config: AgentConfig;
|
|
19
|
-
};
|
|
20
|
-
export declare function resolveWorkspaceDirFromArgv(args?: string[]): string | undefined;
|
|
21
|
-
export declare function resolveSentryDsn(stateDir: string): string | undefined;
|
|
38
|
+
export declare function loadAutoReplyJudgeModel(conversationDir?: string): JudgeModelConfig;
|
|
22
39
|
/**
|
|
23
|
-
*
|
|
24
|
-
* `https://mama.example.com` (no trailing slash). Read from `MOM_LINK_URL`,
|
|
25
|
-
* the same env var the bot uses to build `/link?token=...` invitations.
|
|
40
|
+
* Load the mom-compatible auto-reply marker file state for a conversation.
|
|
26
41
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* (Host / X-Forwarded-*), which is insecure in production because those
|
|
31
|
-
* headers are client-controlled.
|
|
42
|
+
* - `auto-reply` exists: enabled; empty file means reply to any top-level message.
|
|
43
|
+
* - `auto-reply.disabled` exists: disabled, preserving any rules text for re-enable.
|
|
44
|
+
* - neither exists: disabled.
|
|
32
45
|
*/
|
|
33
|
-
export declare function
|
|
46
|
+
export declare function loadConversationAutoReplyConfig(conversationDir: string): AutoReplyConfig;
|
|
47
|
+
/** Save auto-reply state using mom-compatible marker files. */
|
|
48
|
+
export declare function saveConversationAutoReplyConfig(conversationDir: string, config: AutoReplyConfig): void;
|
|
49
|
+
export declare function resolveWorkspaceDirFromArgv(args?: string[]): string | undefined;
|
|
50
|
+
export declare function resolveStateDirFromArgv(args?: string[]): string;
|
|
51
|
+
export declare function resolveSentryDsn(): string | undefined;
|
|
52
|
+
export declare function createGlobalSettingsFile(stateDir: string): string;
|
|
34
53
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
54
|
+
* Externally-visible base URL of the link/OAuth server, e.g.
|
|
55
|
+
* `https://mama.example.com` (no trailing slash). Read from `MAMA_LINK_URL`,
|
|
56
|
+
* the same env var the bot uses to build credential onboarding links.
|
|
38
57
|
*/
|
|
39
|
-
export declare function
|
|
40
|
-
export declare function saveAgentConfig(
|
|
58
|
+
export declare function resolveLinkBaseUrl(): string | undefined;
|
|
59
|
+
export declare function saveAgentConfig(config: Partial<AgentConfig>): void;
|
|
41
60
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAWD,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAa7D;AAUD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAQ9F;AAED,wBAAgB,2BAA2B,CAAC,IAAI,WAAwB,GAAG,MAAM,GAAG,SAAS,CAuB5F;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAErE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,GAAG,SAAS,CAQpB;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,IAAI,CAgB3E","sourcesContent":["import { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nexport interface AgentConfig {\n provider?: string;\n model?: string;\n thinkingLevel?: string;\n sessionScope?: \"thread\" | \"channel\";\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n sentryDsn?: string;\n}\n\nconst SETTINGS_TEMPLATE: AgentConfig = {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-6\",\n thinkingLevel: \"off\",\n sessionScope: \"thread\",\n logFormat: \"console\",\n logLevel: \"info\",\n};\n\nexport function loadAgentConfig(stateDir: string): AgentConfig {\n const settingsPath = join(stateDir, \"settings.json\");\n let fromFile: AgentConfig = {};\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n fromFile = parsed as AgentConfig;\n }\n } catch {\n // File missing or malformed\n }\n return applyEnvOverrides(fromFile);\n}\n\nfunction applyEnvOverrides(config: AgentConfig): AgentConfig {\n return {\n ...config,\n provider: process.env.MOM_AI_PROVIDER ?? config.provider,\n model: process.env.MOM_AI_MODEL ?? config.model,\n };\n}\n\n/**\n * Ensure settings.json exists in stateDir.\n * If missing, writes a default template and returns it.\n * If it already exists, loads and returns the current config.\n */\nexport function ensureSettingsFile(stateDir: string): { created: boolean; config: AgentConfig } {\n const settingsPath = join(stateDir, \"settings.json\");\n if (!existsSync(settingsPath)) {\n mkdirSync(stateDir, { recursive: true });\n writeFileSync(settingsPath, JSON.stringify(SETTINGS_TEMPLATE, null, 2) + \"\\n\", \"utf-8\");\n return { created: true, config: applyEnvOverrides(SETTINGS_TEMPLATE) };\n }\n return { created: false, config: loadAgentConfig(stateDir) };\n}\n\nexport function resolveWorkspaceDirFromArgv(args = process.argv.slice(2)): string | undefined {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === \"--sandbox\" || arg === \"--download\") {\n i += 1;\n continue;\n }\n\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\") {\n continue;\n }\n\n if (arg.startsWith(\"--sandbox=\") || arg.startsWith(\"--download=\")) {\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n\n return undefined;\n}\n\nexport function resolveSentryDsn(stateDir: string): string | undefined {\n return loadAgentConfig(stateDir).sentryDsn;\n}\n\n/**\n * Externally-visible base URL of the link/OAuth server, e.g.\n * `https://mama.example.com` (no trailing slash). Read from `MOM_LINK_URL`,\n * the same env var the bot uses to build `/link?token=...` invitations.\n *\n * Used by the link server to build OAuth `redirect_uri` values that must\n * match the registered callback URL at the identity provider. When unset,\n * the link server falls back to deriving the base from request headers\n * (Host / X-Forwarded-*), which is insecure in production because those\n * headers are client-controlled.\n */\nexport function resolveLinkBaseUrl(): string | undefined {\n const raw = process.env.MOM_LINK_URL?.trim();\n if (!raw) return undefined;\n return raw.replace(/\\/+$/, \"\");\n}\n\n/**\n * Resolve Sentry DSN from settings.json, checking both the new stateDir location\n * (default: ~/.mama/settings.json) and the legacy workspace location for backwards compatibility.\n * Returns undefined if not found in either location.\n */\nexport function resolveSentryDsnFromConfig(\n stateDir: string,\n workingDir?: string,\n): string | undefined {\n // First check the new stateDir location\n const stateDirDsn = resolveSentryDsn(stateDir);\n if (stateDirDsn) {\n return stateDirDsn;\n }\n // Fall back to legacy workspace location for backwards compatibility\n return workingDir ? resolveSentryDsn(workingDir) : undefined;\n}\n\nexport function saveAgentConfig(stateDir: string, config: AgentConfig): void {\n const settingsPath = join(stateDir, \"settings.json\");\n\n let existing: AgentConfig = {};\n try {\n const raw = readFileSync(settingsPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") {\n existing = parsed as AgentConfig;\n }\n } catch {\n // Start fresh if file is missing or malformed\n }\n\n mkdirSync(dirname(settingsPath), { recursive: true });\n writeFileSync(settingsPath, JSON.stringify({ ...existing, ...config }, null, 2), \"utf-8\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAOnE,qBAAa,0BAA2B,SAAQ,KAAK;aACvB,YAAY,EAAE,MAAM;IAAhD,YAA4B,YAAY,EAAE,MAAM,EAG/C;CACF;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,aAAa,CAAC;IAC7B,SAAS,EAAE,SAAS,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC;CACjD;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AA8JD,wBAAgB,eAAe,IAAI,WAAW,CAE7C;AAED,wBAAgB,8BAA8B,CAAC,eAAe,EAAE,MAAM,GAAG,WAAW,CAMnF;AAED,wBAAgB,2BAA2B,CACzC,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,GAAG,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC,GAC5F,IAAI,CAWN;AAED,wBAAgB,6BAA6B,CAC3C,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE;IAAE,mBAAmB,EAAE,WAAW,CAAC,4BAA4B,CAAC,CAAA;CAAE,GACzE,IAAI,CAiBN;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAUlF;AAUD;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAYxF;AAED,+DAA+D;AAC/D,wBAAgB,+BAA+B,CAC7C,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,eAAe,GACtB,IAAI,CAeN;AAED,wBAAgB,2BAA2B,CAAC,IAAI,WAAwB,GAAG,MAAM,GAAG,SAAS,CA2B5F;AAED,wBAAgB,uBAAuB,CAAC,IAAI,WAAwB,GAAG,MAAM,CAY5E;AAED,wBAAgB,gBAAgB,IAAI,MAAM,GAAG,SAAS,CAOrD;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUjE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAIvD;AAyDD,wBAAgB,eAAe,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAsBlE","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { dirname, join, resolve } from \"path\";\nimport { ensureDirExists, isRecord, readJsonFileIfExists } from \"./file-guards.js\";\nimport { atomicWritePrivateFile } from \"./fs-atomic.js\";\n\nexport class MissingGlobalSettingsError extends Error {\n constructor(public readonly settingsPath: string) {\n super(`Missing global settings file at ${settingsPath}`);\n this.name = \"MissingGlobalSettingsError\";\n }\n}\n\nexport interface AgentConfig {\n provider: string;\n model: string;\n thinkingLevel: ThinkingLevel;\n logFormat: \"console\" | \"json\";\n logLevel: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n sentryDsn?: string;\n sandboxCpus?: string;\n sandboxMemory?: string;\n sandboxBoostCpus?: string;\n sandboxBoostMemory?: string;\n sandboxImageWorkspaceMount?: \"private\" | \"full\";\n}\n\nexport interface AutoReplyConfig {\n enabled: boolean;\n rules: string[];\n}\n\nexport interface JudgeModelConfig {\n provider: string;\n model: string;\n}\n\nconst ONBOARD_SETTINGS: SettingsFileConfig = {\n llm: {\n provider: \"anthropic\",\n model: \"claude-sonnet-4-6\",\n thinkingLevel: \"off\",\n autoReply: {\n provider: \"anthropic\",\n model: \"claude-haiku-4-5\",\n },\n },\n log: {\n format: \"console\",\n level: \"info\",\n },\n sandbox: {\n cpus: \"0.5\",\n memory: \"1g\",\n boost: {\n cpus: \"2\",\n memory: \"4g\",\n },\n image: {\n workspaceMount: \"private\",\n },\n },\n};\n\ninterface SettingsFileConfig {\n llm?: Partial<Pick<AgentConfig, \"provider\" | \"model\" | \"thinkingLevel\">> & {\n autoReply?: { provider?: string; model?: string };\n };\n log?: { format?: AgentConfig[\"logFormat\"]; level?: AgentConfig[\"logLevel\"] };\n sentry?: { dsn?: string };\n sandbox?: {\n cpus?: string;\n memory?: string;\n boost?: { cpus?: string; memory?: string };\n image?: { workspaceMount?: AgentConfig[\"sandboxImageWorkspaceMount\"] };\n };\n autoReply?: {\n enabled?: boolean;\n rules?: string[];\n };\n}\n\nfunction loadSettingsFile(settingsPath: string): SettingsFileConfig | undefined {\n return readJsonFileIfExists(\n settingsPath,\n (value): value is SettingsFileConfig => isRecord(value),\n (detail) =>\n detail === \"unexpected JSON shape\"\n ? `Malformed settings file at ${settingsPath}: expected a JSON object at the top level`\n : `Malformed settings file at ${settingsPath}: ${detail}`,\n );\n}\n\nfunction getStateDir(): string {\n const raw = process.env.MAMA_STATE_DIR?.trim();\n return raw ? resolve(raw) : join(homedir(), \".mama\");\n}\n\nfunction normalizeSettingsConfig(config: SettingsFileConfig): Partial<AgentConfig> {\n return {\n ...(config.llm?.provider !== undefined ? { provider: config.llm.provider } : {}),\n ...(config.llm?.model !== undefined ? { model: config.llm.model } : {}),\n ...(config.llm?.thinkingLevel !== undefined ? { thinkingLevel: config.llm.thinkingLevel } : {}),\n ...(config.log?.format !== undefined ? { logFormat: config.log.format } : {}),\n ...(config.log?.level !== undefined ? { logLevel: config.log.level } : {}),\n ...(config.sentry?.dsn !== undefined ? { sentryDsn: config.sentry.dsn } : {}),\n ...(config.sandbox?.cpus !== undefined ? { sandboxCpus: config.sandbox.cpus } : {}),\n ...(config.sandbox?.memory !== undefined ? { sandboxMemory: config.sandbox.memory } : {}),\n ...(config.sandbox?.boost?.cpus !== undefined\n ? { sandboxBoostCpus: config.sandbox.boost.cpus }\n : {}),\n ...(config.sandbox?.boost?.memory !== undefined\n ? { sandboxBoostMemory: config.sandbox.boost.memory }\n : {}),\n ...(config.sandbox?.image?.workspaceMount !== undefined\n ? { sandboxImageWorkspaceMount: config.sandbox.image.workspaceMount }\n : {}),\n };\n}\n\nfunction getSettingsPath(): string {\n return join(getStateDir(), \"settings.json\");\n}\n\nfunction requireGlobalSettings(): SettingsFileConfig {\n const settingsPath = getSettingsPath();\n const config = loadSettingsFile(settingsPath);\n if (!config) {\n throw new MissingGlobalSettingsError(settingsPath);\n }\n return config;\n}\n\nfunction requireString(value: string | undefined, path: string): string {\n if (!value) {\n throw new Error(\n `Missing required global setting: ${path}. Run \\`mama --onboard\\` to create settings.json.`,\n );\n }\n return value;\n}\n\nfunction requireThinkingLevel(value: ThinkingLevel | undefined): ThinkingLevel {\n return requireString(value, \"llm.thinkingLevel\") as ThinkingLevel;\n}\n\nfunction requireLogFormat(value: AgentConfig[\"logFormat\"] | undefined): AgentConfig[\"logFormat\"] {\n if (value !== \"console\" && value !== \"json\") {\n throw new Error(\"Missing or invalid required global setting: log.format\");\n }\n return value;\n}\n\nfunction requireLogLevel(value: AgentConfig[\"logLevel\"] | undefined): AgentConfig[\"logLevel\"] {\n const allowed = [\"trace\", \"debug\", \"info\", \"warn\", \"error\"];\n if (!value || !allowed.includes(value)) {\n throw new Error(\"Missing or invalid required global setting: log.level\");\n }\n return value;\n}\n\nfunction toAgentConfig(fromFile: Partial<AgentConfig>): AgentConfig {\n const provider = requireString(fromFile.provider, \"llm.provider\");\n const model = requireString(fromFile.model, \"llm.model\");\n const thinkingLevel = requireThinkingLevel(fromFile.thinkingLevel);\n const logFormat = requireLogFormat(fromFile.logFormat);\n const logLevel = requireLogLevel(fromFile.logLevel);\n const sentryDsn = fromFile.sentryDsn ?? process.env.SENTRY_DSN;\n const sandboxCpus = fromFile.sandboxCpus;\n const sandboxMemory = fromFile.sandboxMemory;\n const sandboxBoostCpus = fromFile.sandboxBoostCpus;\n const sandboxBoostMemory = fromFile.sandboxBoostMemory;\n const sandboxImageWorkspaceMount = fromFile.sandboxImageWorkspaceMount;\n\n return {\n provider,\n model,\n thinkingLevel,\n logFormat,\n logLevel,\n sentryDsn,\n sandboxCpus,\n sandboxMemory,\n sandboxBoostCpus,\n sandboxBoostMemory,\n sandboxImageWorkspaceMount,\n };\n}\n\nfunction loadRawAgentConfig(): Partial<AgentConfig> {\n return normalizeSettingsConfig(requireGlobalSettings());\n}\n\nexport function loadAgentConfig(): AgentConfig {\n return toAgentConfig(loadRawAgentConfig());\n}\n\nexport function loadAgentConfigForConversation(conversationDir: string): AgentConfig {\n const globalConfig = loadRawAgentConfig();\n const conversationConfig = normalizeSettingsConfig(\n loadSettingsFile(join(conversationDir, \"settings.json\")) ?? {},\n );\n return toAgentConfig({ ...globalConfig, ...conversationConfig });\n}\n\nexport function saveConversationModelConfig(\n conversationDir: string,\n config: Pick<AgentConfig, \"provider\" | \"model\"> & Partial<Pick<AgentConfig, \"thinkingLevel\">>,\n): void {\n if (!existsSync(conversationDir)) {\n ensureDirExists(conversationDir);\n }\n const settingsPath = join(conversationDir, \"settings.json\");\n const existing = loadSettingsFile(settingsPath) ?? {};\n const scopedConfig: SettingsFileConfig = {\n ...existing,\n llm: { ...existing.llm, ...config },\n };\n atomicWritePrivateFile(settingsPath, JSON.stringify(scopedConfig, null, 2));\n}\n\nexport function saveConversationSandboxConfig(\n conversationDir: string,\n config: { imageWorkspaceMount: AgentConfig[\"sandboxImageWorkspaceMount\"] },\n): void {\n if (!existsSync(conversationDir)) {\n ensureDirExists(conversationDir);\n }\n const settingsPath = join(conversationDir, \"settings.json\");\n const existing = loadSettingsFile(settingsPath) ?? {};\n const scopedConfig: SettingsFileConfig = {\n ...existing,\n sandbox: {\n ...existing.sandbox,\n image: {\n ...existing.sandbox?.image,\n workspaceMount: config.imageWorkspaceMount,\n },\n },\n };\n atomicWritePrivateFile(settingsPath, JSON.stringify(scopedConfig, null, 2));\n}\n\n/**\n * Resolve the model used to judge auto-reply rules. Falls back to the main\n * llm.{provider,model} when llm.autoReply is not set, so a missing override\n * keeps current behavior.\n */\nexport function loadAutoReplyJudgeModel(conversationDir?: string): JudgeModelConfig {\n const global = requireGlobalSettings();\n const local = conversationDir\n ? (loadSettingsFile(join(conversationDir, \"settings.json\")) ?? {})\n : {};\n const merged: SettingsFileConfig[\"llm\"] = { ...global.llm, ...local.llm };\n const judge = { ...global.llm?.autoReply, ...local.llm?.autoReply };\n const provider = requireString(judge.provider ?? merged?.provider, \"llm.autoReply.provider\");\n const model = requireString(judge.model ?? merged?.model, \"llm.autoReply.model\");\n return { provider, model };\n}\n\nconst AUTO_REPLY_FILE = \"auto-reply\";\nconst AUTO_REPLY_DISABLED_FILE = \"auto-reply.disabled\";\n\nfunction readAutoReplyRulesFile(path: string): string[] {\n const text = readFileSync(path, \"utf-8\").trim();\n return text ? [text] : [];\n}\n\n/**\n * Load the mom-compatible auto-reply marker file state for a conversation.\n *\n * - `auto-reply` exists: enabled; empty file means reply to any top-level message.\n * - `auto-reply.disabled` exists: disabled, preserving any rules text for re-enable.\n * - neither exists: disabled.\n */\nexport function loadConversationAutoReplyConfig(conversationDir: string): AutoReplyConfig {\n const enabledPath = join(conversationDir, AUTO_REPLY_FILE);\n if (existsSync(enabledPath)) {\n return { enabled: true, rules: readAutoReplyRulesFile(enabledPath) };\n }\n\n const disabledPath = join(conversationDir, AUTO_REPLY_DISABLED_FILE);\n if (existsSync(disabledPath)) {\n return { enabled: false, rules: readAutoReplyRulesFile(disabledPath) };\n }\n\n return { enabled: false, rules: [] };\n}\n\n/** Save auto-reply state using mom-compatible marker files. */\nexport function saveConversationAutoReplyConfig(\n conversationDir: string,\n config: AutoReplyConfig,\n): void {\n if (!existsSync(conversationDir)) {\n mkdirSync(conversationDir, { recursive: true });\n }\n\n const enabledPath = join(conversationDir, AUTO_REPLY_FILE);\n const disabledPath = join(conversationDir, AUTO_REPLY_DISABLED_FILE);\n const targetPath = config.enabled ? enabledPath : disabledPath;\n const otherPath = config.enabled ? disabledPath : enabledPath;\n\n if (existsSync(otherPath)) {\n renameSync(otherPath, targetPath);\n }\n\n writeFileSync(targetPath, config.rules.join(\"\\n\"), \"utf-8\");\n}\n\nexport function resolveWorkspaceDirFromArgv(args = process.argv.slice(2)): string | undefined {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === \"--sandbox\" || arg === \"--download\" || arg === \"--state-dir\") {\n i += 1;\n continue;\n }\n\n if (arg === \"--version\" || arg === \"-v\" || arg === \"-V\" || arg === \"--onboard\") {\n continue;\n }\n\n if (\n arg.startsWith(\"--sandbox=\") ||\n arg.startsWith(\"--download=\") ||\n arg.startsWith(\"--state-dir=\")\n ) {\n continue;\n }\n\n if (!arg.startsWith(\"-\")) {\n return arg;\n }\n }\n\n return undefined;\n}\n\nexport function resolveStateDirFromArgv(args = process.argv.slice(2)): string {\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n if (arg.startsWith(\"--state-dir=\")) {\n return resolve(arg.slice(\"--state-dir=\".length));\n }\n if (arg === \"--state-dir\") {\n return resolve(args[++i] || \"\");\n }\n }\n\n return join(homedir(), \".mama\");\n}\n\nexport function resolveSentryDsn(): string | undefined {\n const fromFile = normalizeSettingsConfig(loadSettingsFile(getSettingsPath()) ?? {});\n if (fromFile.sentryDsn) {\n return fromFile.sentryDsn;\n }\n\n return process.env.SENTRY_DSN;\n}\n\nexport function createGlobalSettingsFile(stateDir: string): string {\n const settingsPath = join(stateDir, \"settings.json\");\n if (existsSync(settingsPath)) {\n throw new Error(`Global settings already exists at ${settingsPath}`);\n }\n if (!existsSync(stateDir)) {\n ensureDirExists(stateDir);\n }\n atomicWritePrivateFile(settingsPath, JSON.stringify(ONBOARD_SETTINGS, null, 2));\n return settingsPath;\n}\n\n/**\n * Externally-visible base URL of the link/OAuth server, e.g.\n * `https://mama.example.com` (no trailing slash). Read from `MAMA_LINK_URL`,\n * the same env var the bot uses to build credential onboarding links.\n */\nexport function resolveLinkBaseUrl(): string | undefined {\n const raw = process.env.MAMA_LINK_URL?.trim();\n if (!raw) return undefined;\n return raw.replace(/\\/+$/, \"\");\n}\n\nfunction hasDefinedValue(values: Record<string, unknown> | undefined): boolean {\n return values !== undefined && Object.values(values).some((value) => value !== undefined);\n}\n\nfunction compactSettingsConfig(config: SettingsFileConfig): SettingsFileConfig {\n return {\n ...(hasDefinedValue(config.llm) ? { llm: config.llm } : {}),\n ...(hasDefinedValue(config.log) ? { log: config.log } : {}),\n ...(hasDefinedValue(config.sentry) ? { sentry: config.sentry } : {}),\n ...(hasDefinedValue(config.sandbox) ? { sandbox: config.sandbox } : {}),\n ...(hasDefinedValue(config.autoReply) ? { autoReply: config.autoReply } : {}),\n };\n}\n\nfunction patchSettingsConfig(\n existing: SettingsFileConfig,\n config: Partial<AgentConfig>,\n): SettingsFileConfig {\n const patched: SettingsFileConfig = {\n ...existing,\n llm: {\n ...existing.llm,\n ...(config.provider !== undefined ? { provider: config.provider } : {}),\n ...(config.model !== undefined ? { model: config.model } : {}),\n ...(config.thinkingLevel !== undefined ? { thinkingLevel: config.thinkingLevel } : {}),\n },\n log: {\n ...existing.log,\n ...(config.logFormat !== undefined ? { format: config.logFormat } : {}),\n ...(config.logLevel !== undefined ? { level: config.logLevel } : {}),\n },\n sentry: {\n ...existing.sentry,\n ...(config.sentryDsn !== undefined ? { dsn: config.sentryDsn } : {}),\n },\n sandbox: {\n ...existing.sandbox,\n ...(config.sandboxCpus !== undefined ? { cpus: config.sandboxCpus } : {}),\n ...(config.sandboxMemory !== undefined ? { memory: config.sandboxMemory } : {}),\n ...(config.sandboxBoostCpus !== undefined || config.sandboxBoostMemory !== undefined\n ? {\n boost: {\n ...existing.sandbox?.boost,\n ...(config.sandboxBoostCpus !== undefined ? { cpus: config.sandboxBoostCpus } : {}),\n ...(config.sandboxBoostMemory !== undefined\n ? { memory: config.sandboxBoostMemory }\n : {}),\n },\n }\n : {}),\n },\n };\n return compactSettingsConfig(patched);\n}\n\nexport function saveAgentConfig(config: Partial<AgentConfig>): void {\n const settingsPath = join(getStateDir(), \"settings.json\");\n\n let existing: SettingsFileConfig = ONBOARD_SETTINGS;\n if (existsSync(settingsPath)) {\n try {\n existing = loadSettingsFile(settingsPath) ?? {};\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n const message = detail.startsWith(\"Malformed settings file\")\n ? detail.replace(\"Malformed settings file\", \"Refusing to overwrite malformed settings file\")\n : detail;\n throw new Error(message, { cause: err });\n }\n }\n\n const merged = patchSettingsConfig(existing, config);\n\n const dir = dirname(settingsPath);\n ensureDirExists(dir);\n\n atomicWritePrivateFile(settingsPath, JSON.stringify(merged, null, 2));\n}\n"]}
|