@geminixiang/mama 0.2.0-beta.2 → 0.2.0-beta.21

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.
Files changed (264) hide show
  1. package/README.md +157 -391
  2. package/dist/adapter.d.ts +31 -7
  3. package/dist/adapter.d.ts.map +1 -1
  4. package/dist/adapter.js.map +1 -1
  5. package/dist/adapters/discord/bot.d.ts +10 -5
  6. package/dist/adapters/discord/bot.d.ts.map +1 -1
  7. package/dist/adapters/discord/bot.js +347 -115
  8. package/dist/adapters/discord/bot.js.map +1 -1
  9. package/dist/adapters/discord/context.d.ts +1 -1
  10. package/dist/adapters/discord/context.d.ts.map +1 -1
  11. package/dist/adapters/discord/context.js +118 -25
  12. package/dist/adapters/discord/context.js.map +1 -1
  13. package/dist/adapters/shared.d.ts +91 -0
  14. package/dist/adapters/shared.d.ts.map +1 -0
  15. package/dist/adapters/shared.js +191 -0
  16. package/dist/adapters/shared.js.map +1 -0
  17. package/dist/adapters/slack/bot.d.ts +21 -22
  18. package/dist/adapters/slack/bot.d.ts.map +1 -1
  19. package/dist/adapters/slack/bot.js +530 -221
  20. package/dist/adapters/slack/bot.js.map +1 -1
  21. package/dist/adapters/slack/branch-manager.d.ts +28 -0
  22. package/dist/adapters/slack/branch-manager.d.ts.map +1 -0
  23. package/dist/adapters/slack/branch-manager.js +107 -0
  24. package/dist/adapters/slack/branch-manager.js.map +1 -0
  25. package/dist/adapters/slack/context.d.ts +4 -1
  26. package/dist/adapters/slack/context.d.ts.map +1 -1
  27. package/dist/adapters/slack/context.js +193 -75
  28. package/dist/adapters/slack/context.js.map +1 -1
  29. package/dist/adapters/slack/session.d.ts +38 -0
  30. package/dist/adapters/slack/session.d.ts.map +1 -0
  31. package/dist/adapters/slack/session.js +66 -0
  32. package/dist/adapters/slack/session.js.map +1 -0
  33. package/dist/adapters/slack/tools/attach.d.ts +1 -1
  34. package/dist/adapters/slack/tools/attach.d.ts.map +1 -1
  35. package/dist/adapters/slack/tools/attach.js.map +1 -1
  36. package/dist/adapters/telegram/bot.d.ts.map +1 -1
  37. package/dist/adapters/telegram/bot.js +140 -153
  38. package/dist/adapters/telegram/bot.js.map +1 -1
  39. package/dist/adapters/telegram/context.d.ts +1 -1
  40. package/dist/adapters/telegram/context.d.ts.map +1 -1
  41. package/dist/adapters/telegram/context.js +74 -20
  42. package/dist/adapters/telegram/context.js.map +1 -1
  43. package/dist/agent.d.ts +13 -3
  44. package/dist/agent.d.ts.map +1 -1
  45. package/dist/agent.js +677 -552
  46. package/dist/agent.js.map +1 -1
  47. package/dist/commands/auto-reply.d.ts +16 -0
  48. package/dist/commands/auto-reply.d.ts.map +1 -0
  49. package/dist/commands/auto-reply.js +72 -0
  50. package/dist/commands/auto-reply.js.map +1 -0
  51. package/dist/commands/index.d.ts +5 -0
  52. package/dist/commands/index.d.ts.map +1 -0
  53. package/dist/commands/index.js +18 -0
  54. package/dist/commands/index.js.map +1 -0
  55. package/dist/commands/login.d.ts +5 -0
  56. package/dist/commands/login.d.ts.map +1 -0
  57. package/dist/commands/login.js +91 -0
  58. package/dist/commands/login.js.map +1 -0
  59. package/dist/commands/model.d.ts +14 -0
  60. package/dist/commands/model.d.ts.map +1 -0
  61. package/dist/commands/model.js +112 -0
  62. package/dist/commands/model.js.map +1 -0
  63. package/dist/commands/new.d.ts +9 -0
  64. package/dist/commands/new.d.ts.map +1 -0
  65. package/dist/commands/new.js +28 -0
  66. package/dist/commands/new.js.map +1 -0
  67. package/dist/commands/registry.d.ts +4 -0
  68. package/dist/commands/registry.d.ts.map +1 -0
  69. package/dist/commands/registry.js +9 -0
  70. package/dist/commands/registry.js.map +1 -0
  71. package/dist/commands/sandbox.d.ts +10 -0
  72. package/dist/commands/sandbox.d.ts.map +1 -0
  73. package/dist/commands/sandbox.js +88 -0
  74. package/dist/commands/sandbox.js.map +1 -0
  75. package/dist/commands/session-view.d.ts +5 -0
  76. package/dist/commands/session-view.d.ts.map +1 -0
  77. package/dist/commands/session-view.js +62 -0
  78. package/dist/commands/session-view.js.map +1 -0
  79. package/dist/commands/types.d.ts +41 -0
  80. package/dist/commands/types.d.ts.map +1 -0
  81. package/dist/commands/types.js +2 -0
  82. package/dist/commands/types.js.map +1 -0
  83. package/dist/commands/utils.d.ts +8 -0
  84. package/dist/commands/utils.d.ts.map +1 -0
  85. package/dist/commands/utils.js +14 -0
  86. package/dist/commands/utils.js.map +1 -0
  87. package/dist/config.d.ts +46 -8
  88. package/dist/config.d.ts.map +1 -1
  89. package/dist/config.js +306 -67
  90. package/dist/config.js.map +1 -1
  91. package/dist/context.d.ts +10 -42
  92. package/dist/context.d.ts.map +1 -1
  93. package/dist/context.js +14 -127
  94. package/dist/context.js.map +1 -1
  95. package/dist/events.d.ts +2 -0
  96. package/dist/events.d.ts.map +1 -1
  97. package/dist/events.js +148 -67
  98. package/dist/events.js.map +1 -1
  99. package/dist/execution-resolver.d.ts +12 -7
  100. package/dist/execution-resolver.d.ts.map +1 -1
  101. package/dist/execution-resolver.js +150 -21
  102. package/dist/execution-resolver.js.map +1 -1
  103. package/dist/file-guards.d.ts +9 -0
  104. package/dist/file-guards.d.ts.map +1 -0
  105. package/dist/file-guards.js +56 -0
  106. package/dist/file-guards.js.map +1 -0
  107. package/dist/fs-atomic.d.ts +10 -0
  108. package/dist/fs-atomic.d.ts.map +1 -0
  109. package/dist/fs-atomic.js +45 -0
  110. package/dist/fs-atomic.js.map +1 -0
  111. package/dist/index.d.ts +7 -0
  112. package/dist/index.d.ts.map +1 -0
  113. package/dist/index.js +4 -0
  114. package/dist/index.js.map +1 -0
  115. package/dist/instrument.d.ts.map +1 -1
  116. package/dist/instrument.js +2 -3
  117. package/dist/instrument.js.map +1 -1
  118. package/dist/log.d.ts +1 -12
  119. package/dist/log.d.ts.map +1 -1
  120. package/dist/log.js +12 -143
  121. package/dist/log.js.map +1 -1
  122. package/dist/{login.d.ts → login/index.d.ts} +16 -3
  123. package/dist/login/index.d.ts.map +1 -0
  124. package/dist/{login.js → login/index.js} +94 -17
  125. package/dist/login/index.js.map +1 -0
  126. package/dist/{link-server.d.ts → login/portal.d.ts} +6 -4
  127. package/dist/login/portal.d.ts.map +1 -0
  128. package/dist/login/portal.js +1544 -0
  129. package/dist/login/portal.js.map +1 -0
  130. package/dist/login/session.d.ts +26 -0
  131. package/dist/login/session.d.ts.map +1 -0
  132. package/dist/{link-token.js → login/session.js} +10 -22
  133. package/dist/login/session.js.map +1 -0
  134. package/dist/main.d.ts.map +1 -1
  135. package/dist/main.js +138 -352
  136. package/dist/main.js.map +1 -1
  137. package/dist/provisioner.d.ts +42 -11
  138. package/dist/provisioner.d.ts.map +1 -1
  139. package/dist/provisioner.js +273 -64
  140. package/dist/provisioner.js.map +1 -1
  141. package/dist/runtime/conversation-orchestrator.d.ts +40 -0
  142. package/dist/runtime/conversation-orchestrator.d.ts.map +1 -0
  143. package/dist/runtime/conversation-orchestrator.js +183 -0
  144. package/dist/runtime/conversation-orchestrator.js.map +1 -0
  145. package/dist/runtime/index.d.ts +2 -0
  146. package/dist/runtime/index.d.ts.map +1 -0
  147. package/dist/runtime/index.js +2 -0
  148. package/dist/runtime/index.js.map +1 -0
  149. package/dist/runtime/session-runtime.d.ts +26 -0
  150. package/dist/runtime/session-runtime.d.ts.map +1 -0
  151. package/dist/runtime/session-runtime.js +221 -0
  152. package/dist/runtime/session-runtime.js.map +1 -0
  153. package/dist/sandbox/cloudflare.d.ts +15 -0
  154. package/dist/sandbox/cloudflare.d.ts.map +1 -0
  155. package/dist/sandbox/cloudflare.js +137 -0
  156. package/dist/sandbox/cloudflare.js.map +1 -0
  157. package/dist/sandbox/container.d.ts +2 -1
  158. package/dist/sandbox/container.d.ts.map +1 -1
  159. package/dist/sandbox/container.js +18 -2
  160. package/dist/sandbox/container.js.map +1 -1
  161. package/dist/sandbox/firecracker.d.ts +2 -1
  162. package/dist/sandbox/firecracker.d.ts.map +1 -1
  163. package/dist/sandbox/firecracker.js +6 -0
  164. package/dist/sandbox/firecracker.js.map +1 -1
  165. package/dist/sandbox/host.d.ts +2 -1
  166. package/dist/sandbox/host.d.ts.map +1 -1
  167. package/dist/sandbox/host.js +4 -0
  168. package/dist/sandbox/host.js.map +1 -1
  169. package/dist/sandbox/index.d.ts +6 -4
  170. package/dist/sandbox/index.d.ts.map +1 -1
  171. package/dist/sandbox/index.js +9 -6
  172. package/dist/sandbox/index.js.map +1 -1
  173. package/dist/sandbox/path-context.d.ts +4 -0
  174. package/dist/sandbox/path-context.d.ts.map +1 -0
  175. package/dist/sandbox/path-context.js +20 -0
  176. package/dist/sandbox/path-context.js.map +1 -0
  177. package/dist/sandbox/types.d.ts +17 -1
  178. package/dist/sandbox/types.d.ts.map +1 -1
  179. package/dist/sandbox/types.js.map +1 -1
  180. package/dist/sentry.d.ts +20 -1
  181. package/dist/sentry.d.ts.map +1 -1
  182. package/dist/sentry.js +58 -8
  183. package/dist/sentry.js.map +1 -1
  184. package/dist/session-policy.d.ts +13 -0
  185. package/dist/session-policy.d.ts.map +1 -0
  186. package/dist/session-policy.js +23 -0
  187. package/dist/session-policy.js.map +1 -0
  188. package/dist/session-store.d.ts +33 -2
  189. package/dist/session-store.d.ts.map +1 -1
  190. package/dist/session-store.js +179 -13
  191. package/dist/session-store.js.map +1 -1
  192. package/dist/session-view/command.d.ts +5 -0
  193. package/dist/session-view/command.d.ts.map +1 -0
  194. package/dist/session-view/command.js +11 -0
  195. package/dist/session-view/command.js.map +1 -0
  196. package/dist/session-view/portal.d.ts +16 -0
  197. package/dist/session-view/portal.d.ts.map +1 -0
  198. package/dist/session-view/portal.js +1822 -0
  199. package/dist/session-view/portal.js.map +1 -0
  200. package/dist/session-view/service.d.ts +34 -0
  201. package/dist/session-view/service.d.ts.map +1 -0
  202. package/dist/session-view/service.js +427 -0
  203. package/dist/session-view/service.js.map +1 -0
  204. package/dist/session-view/store.d.ts +18 -0
  205. package/dist/session-view/store.d.ts.map +1 -0
  206. package/dist/session-view/store.js +36 -0
  207. package/dist/session-view/store.js.map +1 -0
  208. package/dist/store.d.ts +3 -6
  209. package/dist/store.d.ts.map +1 -1
  210. package/dist/store.js +22 -48
  211. package/dist/store.js.map +1 -1
  212. package/dist/tool-diagnostics.d.ts +2 -0
  213. package/dist/tool-diagnostics.d.ts.map +1 -0
  214. package/dist/tool-diagnostics.js +7 -0
  215. package/dist/tool-diagnostics.js.map +1 -0
  216. package/dist/tools/bash.d.ts +2 -2
  217. package/dist/tools/bash.d.ts.map +1 -1
  218. package/dist/tools/bash.js.map +1 -1
  219. package/dist/tools/edit.d.ts +2 -2
  220. package/dist/tools/edit.d.ts.map +1 -1
  221. package/dist/tools/edit.js.map +1 -1
  222. package/dist/tools/event.d.ts +42 -2
  223. package/dist/tools/event.d.ts.map +1 -1
  224. package/dist/tools/event.js +43 -9
  225. package/dist/tools/event.js.map +1 -1
  226. package/dist/tools/index.d.ts +2 -2
  227. package/dist/tools/index.d.ts.map +1 -1
  228. package/dist/tools/index.js +2 -2
  229. package/dist/tools/index.js.map +1 -1
  230. package/dist/tools/read.d.ts +2 -2
  231. package/dist/tools/read.d.ts.map +1 -1
  232. package/dist/tools/read.js.map +1 -1
  233. package/dist/tools/write.d.ts +2 -2
  234. package/dist/tools/write.d.ts.map +1 -1
  235. package/dist/tools/write.js.map +1 -1
  236. package/dist/trigger.d.ts +31 -0
  237. package/dist/trigger.d.ts.map +1 -0
  238. package/dist/trigger.js +98 -0
  239. package/dist/trigger.js.map +1 -0
  240. package/dist/vault-routing.d.ts +2 -7
  241. package/dist/vault-routing.d.ts.map +1 -1
  242. package/dist/vault-routing.js +6 -42
  243. package/dist/vault-routing.js.map +1 -1
  244. package/dist/vault.d.ts +22 -56
  245. package/dist/vault.d.ts.map +1 -1
  246. package/dist/vault.js +155 -263
  247. package/dist/vault.js.map +1 -1
  248. package/package.json +11 -11
  249. package/dist/bindings.d.ts +0 -44
  250. package/dist/bindings.d.ts.map +0 -1
  251. package/dist/bindings.js +0 -74
  252. package/dist/bindings.js.map +0 -1
  253. package/dist/link-server.d.ts.map +0 -1
  254. package/dist/link-server.js +0 -899
  255. package/dist/link-server.js.map +0 -1
  256. package/dist/link-token.d.ts +0 -32
  257. package/dist/link-token.d.ts.map +0 -1
  258. package/dist/link-token.js.map +0 -1
  259. package/dist/login.d.ts.map +0 -1
  260. package/dist/login.js.map +0 -1
  261. package/dist/sandbox.d.ts +0 -2
  262. package/dist/sandbox.d.ts.map +0 -1
  263. package/dist/sandbox.js +0 -2
  264. package/dist/sandbox.js.map +0 -1
package/dist/log.js CHANGED
@@ -1,64 +1,4 @@
1
- import { Logging } from "@google-cloud/logging";
2
- import { Writable } from "node:stream";
3
1
  import chalk from "chalk";
4
- import pino from "pino";
5
- const PINO_TO_GCP = {
6
- 10: "DEBUG",
7
- 20: "DEBUG",
8
- 30: "INFO",
9
- 40: "WARNING",
10
- 50: "ERROR",
11
- 60: "CRITICAL",
12
- };
13
- function createGcpStream() {
14
- const log = new Logging().log("mama");
15
- return new Writable({
16
- write(chunk, _encoding, callback) {
17
- try {
18
- const line = chunk.toString().trim();
19
- if (line) {
20
- const { level, time, pid: _pid, hostname: _hostname, msg, ...rest } = JSON.parse(line);
21
- const entry = log.entry({ severity: PINO_TO_GCP[level] ?? "DEFAULT", timestamp: new Date(time) }, { message: msg, ...rest });
22
- log.write(entry).catch((err) => console.error("GCP log write failed:", err));
23
- }
24
- }
25
- catch {
26
- // ignore parse errors
27
- }
28
- callback();
29
- },
30
- });
31
- }
32
- let logger = null;
33
- export function initLogger(config) {
34
- if (logger)
35
- return;
36
- const format = config?.logFormat ?? "console";
37
- const level = config?.logLevel ?? "info";
38
- if (format === "json") {
39
- try {
40
- logger = pino({ level }, createGcpStream());
41
- console.log(`📝 GCP logging enabled (level: ${level})`);
42
- }
43
- catch (err) {
44
- console.warn("⚠️ Failed to init GCP logger, JSON logging disabled:", err);
45
- }
46
- }
47
- }
48
- /** Only for use in tests. */
49
- export function __resetLoggerForTest() {
50
- logger = null;
51
- }
52
- function ctxFields(ctx) {
53
- const out = { channel: ctx.conversationId };
54
- if (ctx.userName)
55
- out.user = ctx.userName;
56
- if (ctx.conversationName)
57
- out.channelName = ctx.conversationName;
58
- if (ctx.sessionId)
59
- out.sessionId = ctx.sessionId;
60
- return out;
61
- }
62
2
  function timestamp() {
63
3
  const now = new Date();
64
4
  const hh = String(now.getHours()).padStart(2, "0");
@@ -119,14 +59,10 @@ function formatToolArgs(args) {
119
59
  }
120
60
  // User messages
121
61
  export function logUserMessage(ctx, text) {
122
- if (logger)
123
- logger.info({ event: "user_message", ...ctxFields(ctx), text }, text);
124
62
  console.log(chalk.green(`${timestamp()} ${formatContext(ctx)} ${text}`));
125
63
  }
126
64
  // Tool execution
127
65
  export function logToolStart(ctx, toolName, label, args) {
128
- if (logger)
129
- logger.debug({ event: "tool_start", ...ctxFields(ctx), tool: toolName, label, args }, `${toolName}: ${label}`);
130
66
  const formattedArgs = formatToolArgs(args);
131
67
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ↳ ${toolName}: ${label}`));
132
68
  if (formattedArgs) {
@@ -139,8 +75,6 @@ export function logToolStart(ctx, toolName, label, args) {
139
75
  }
140
76
  }
141
77
  export function logToolSuccess(ctx, toolName, durationMs, result) {
142
- if (logger)
143
- logger.debug({ event: "tool_success", ...ctxFields(ctx), tool: toolName, durationMs, result }, `${toolName} completed`);
144
78
  const duration = (durationMs / 1000).toFixed(1);
145
79
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✓ ${toolName} (${duration}s)`));
146
80
  const truncated = truncate(result, 1000);
@@ -153,8 +87,6 @@ export function logToolSuccess(ctx, toolName, durationMs, result) {
153
87
  }
154
88
  }
155
89
  export function logToolError(ctx, toolName, durationMs, error) {
156
- if (logger)
157
- logger.warn({ event: "tool_error", ...ctxFields(ctx), tool: toolName, durationMs, error }, `${toolName} failed`);
158
90
  const duration = (durationMs / 1000).toFixed(1);
159
91
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✗ ${toolName} (${duration}s)`));
160
92
  const truncated = truncate(error, 1000);
@@ -166,13 +98,9 @@ export function logToolError(ctx, toolName, durationMs, error) {
166
98
  }
167
99
  // Response streaming
168
100
  export function logResponseStart(ctx) {
169
- if (logger)
170
- logger.debug({ event: "response_start", ...ctxFields(ctx) }, "Streaming response");
171
101
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} → Streaming response...`));
172
102
  }
173
103
  export function logThinking(ctx, thinking) {
174
- if (logger)
175
- logger.debug({ event: "thinking", ...ctxFields(ctx), text: thinking }, "Thinking");
176
104
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💭 Thinking`));
177
105
  const truncated = truncate(thinking, 1000);
178
106
  const indented = truncated
@@ -182,8 +110,6 @@ export function logThinking(ctx, thinking) {
182
110
  console.log(chalk.dim(indented));
183
111
  }
184
112
  export function logResponse(ctx, text) {
185
- if (logger)
186
- logger.info({ event: "response", ...ctxFields(ctx), text }, "Response");
187
113
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💬 Response`));
188
114
  const truncated = truncate(text, 1000);
189
115
  const indented = truncated
@@ -192,40 +118,11 @@ export function logResponse(ctx, text) {
192
118
  .join("\n");
193
119
  console.log(chalk.dim(indented));
194
120
  }
195
- // Attachments
196
- export function logDownloadStart(ctx, filename, localPath) {
197
- if (logger)
198
- logger.debug({ event: "download_start", ...ctxFields(ctx), filename, localPath }, `Downloading ${filename}`);
199
- console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ↓ Downloading attachment`));
200
- console.log(chalk.dim(` ${filename} → ${localPath}`));
201
- }
202
- export function logDownloadSuccess(ctx, sizeKB) {
203
- if (logger)
204
- logger.info({ event: "download_success", ...ctxFields(ctx), sizeKB }, `Downloaded (${sizeKB} KB)`);
205
- console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✓ Downloaded (${sizeKB.toLocaleString()} KB)`));
206
- }
207
- export function logDownloadError(ctx, filename, error) {
208
- if (logger)
209
- logger.warn({ event: "download_error", ...ctxFields(ctx), filename, error }, `Download failed: ${filename}`);
210
- console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✗ Download failed`));
211
- console.log(chalk.dim(` ${filename}: ${error}`));
212
- }
213
- // Control
214
- export function logStopRequest(ctx) {
215
- if (logger)
216
- logger.info({ event: "stop_request", ...ctxFields(ctx) }, "Stop requested");
217
- console.log(chalk.green(`${timestamp()} ${formatContext(ctx)} stop`));
218
- console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ⊗ Stop requested - aborting`));
219
- }
220
121
  // System
221
122
  export function logInfo(message) {
222
- if (logger)
223
- logger.info({ event: "info" }, message);
224
123
  console.log(chalk.blue(`${timestamp()} [system] ${message}`));
225
124
  }
226
125
  export function logWarning(message, details) {
227
- if (logger)
228
- logger.warn({ event: "warning", ...(details ? { details } : {}) }, message);
229
126
  console.log(chalk.yellow(`${timestamp()} [system] ⚠ ${message}`));
230
127
  if (details) {
231
128
  const indented = details
@@ -236,10 +133,6 @@ export function logWarning(message, details) {
236
133
  }
237
134
  }
238
135
  export function logAgentError(ctx, error) {
239
- if (logger) {
240
- const extra = ctx === "system" ? { error } : { ...ctxFields(ctx), error };
241
- logger.error({ event: "agent_error", ...extra }, "Agent error");
242
- }
243
136
  const context = ctx === "system" ? "[system]" : formatContext(ctx);
244
137
  console.log(chalk.yellow(`${timestamp()} ${context} ✗ Agent error`));
245
138
  const indented = error
@@ -248,17 +141,17 @@ export function logAgentError(ctx, error) {
248
141
  .join("\n");
249
142
  console.log(chalk.dim(indented));
250
143
  }
144
+ function formatTokenCount(count) {
145
+ if (count < 1000)
146
+ return count.toString();
147
+ if (count < 10000)
148
+ return `${(count / 1000).toFixed(1)}k`;
149
+ if (count < 1000000)
150
+ return `${Math.round(count / 1000)}k`;
151
+ return `${(count / 1000000).toFixed(1)}M`;
152
+ }
251
153
  // Usage summary
252
154
  export function logUsageSummary(ctx, usage, contextTokens, contextWindow) {
253
- const formatTokens = (count) => {
254
- if (count < 1000)
255
- return count.toString();
256
- if (count < 10000)
257
- return `${(count / 1000).toFixed(1)}k`;
258
- if (count < 1000000)
259
- return `${Math.round(count / 1000)}k`;
260
- return `${(count / 1000000).toFixed(1)}M`;
261
- };
262
155
  const lines = [];
263
156
  lines.push("_Usage Summary_");
264
157
  lines.push(`Tokens: ${usage.input.toLocaleString()} in, ${usage.output.toLocaleString()} out`);
@@ -267,7 +160,7 @@ export function logUsageSummary(ctx, usage, contextTokens, contextWindow) {
267
160
  }
268
161
  if (contextTokens && contextWindow) {
269
162
  const contextPercent = ((contextTokens / contextWindow) * 100).toFixed(1);
270
- lines.push(`Context: ${formatTokens(contextTokens)} / ${formatTokens(contextWindow)} (${contextPercent}%)`);
163
+ lines.push(`Context: ${formatTokenCount(contextTokens)} / ${formatTokenCount(contextWindow)} (${contextPercent}%)`);
271
164
  }
272
165
  lines.push(`Cost: $${usage.cost.input.toFixed(4)} in, $${usage.cost.output.toFixed(4)} out` +
273
166
  (usage.cacheRead > 0 || usage.cacheWrite > 0
@@ -275,18 +168,6 @@ export function logUsageSummary(ctx, usage, contextTokens, contextWindow) {
275
168
  : ""));
276
169
  lines.push(`*Total: $${usage.cost.total.toFixed(4)}*`);
277
170
  const summary = lines.join("\n");
278
- // Log to console
279
- if (logger) {
280
- logger.info({
281
- event: "usage",
282
- ...ctxFields(ctx),
283
- tokensIn: usage.input,
284
- tokensOut: usage.output,
285
- cacheRead: usage.cacheRead,
286
- cacheWrite: usage.cacheWrite,
287
- cost: usage.cost.total,
288
- }, `Usage: $${usage.cost.total.toFixed(4)}`);
289
- }
290
171
  console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💰 Usage`));
291
172
  console.log(chalk.dim(` ${usage.input.toLocaleString()} in + ${usage.output.toLocaleString()} out` +
292
173
  (usage.cacheRead > 0 || usage.cacheWrite > 0
@@ -297,37 +178,25 @@ export function logUsageSummary(ctx, usage, contextTokens, contextWindow) {
297
178
  }
298
179
  // Startup (no context needed)
299
180
  export function logStartup(workingDir, sandbox) {
300
- if (logger)
301
- logger.info({ event: "startup", workingDir, sandbox }, "Starting mama");
302
181
  console.log("Starting mama...");
303
182
  console.log(` Working directory: ${workingDir}`);
304
183
  console.log(` Sandbox: ${sandbox}`);
305
184
  }
306
- export function logConnected() {
307
- if (logger)
308
- logger.info({ event: "connected" }, "Mama connected and listening");
309
- console.log("⚡️ Mama connected and listening!");
185
+ export function logConnected(platform) {
186
+ console.log(`⚡️ Mama connected to ${platform} and listening!`);
310
187
  console.log("");
311
188
  }
312
189
  export function logDisconnected() {
313
- if (logger)
314
- logger.info({ event: "disconnected" }, "Mama disconnected");
315
190
  console.log("Mama disconnected.");
316
191
  }
317
192
  // Backfill
318
193
  export function logBackfillStart(channelCount) {
319
- if (logger)
320
- logger.info({ event: "backfill_start", channelCount }, `Backfilling ${channelCount} channels`);
321
194
  console.log(chalk.blue(`${timestamp()} [system] Backfilling ${channelCount} channels...`));
322
195
  }
323
196
  export function logBackfillChannel(channelName, messageCount) {
324
- if (logger)
325
- logger.debug({ event: "backfill_channel", channelName, messageCount }, `#${channelName}: ${messageCount} messages`);
326
197
  console.log(chalk.blue(`${timestamp()} [system] #${channelName}: ${messageCount} messages`));
327
198
  }
328
199
  export function logBackfillComplete(totalMessages, durationMs) {
329
- if (logger)
330
- logger.info({ event: "backfill_complete", totalMessages, durationMs }, `Backfill complete: ${totalMessages} messages`);
331
200
  const duration = (durationMs / 1000).toFixed(1);
332
201
  console.log(chalk.blue(`${timestamp()} [system] Backfill complete: ${totalMessages} messages in ${duration}s`));
333
202
  }
package/dist/log.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"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","sourcesContent":["import { Logging } from \"@google-cloud/logging\";\nimport { Writable } from \"node:stream\";\nimport chalk from \"chalk\";\nimport pino from \"pino\";\n\nconst PINO_TO_GCP: Record<number, string> = {\n 10: \"DEBUG\",\n 20: \"DEBUG\",\n 30: \"INFO\",\n 40: \"WARNING\",\n 50: \"ERROR\",\n 60: \"CRITICAL\",\n};\n\nfunction createGcpStream(): Writable {\n const log = new Logging().log(\"mama\");\n return new Writable({\n write(chunk, _encoding, callback) {\n try {\n const line = chunk.toString().trim();\n if (line) {\n const { level, time, pid: _pid, hostname: _hostname, msg, ...rest } = JSON.parse(line);\n const entry = log.entry(\n { severity: PINO_TO_GCP[level] ?? \"DEFAULT\", timestamp: new Date(time) },\n { message: msg, ...rest },\n );\n log.write(entry).catch((err) => console.error(\"GCP log write failed:\", err));\n }\n } catch {\n // ignore parse errors\n }\n callback();\n },\n });\n}\n\nexport interface LogContext {\n conversationId: string;\n userName?: string;\n conversationName?: string; // For display like #dev-team vs C16HET4EQ\n sessionId?: string;\n}\n\nexport interface LogConfig {\n logFormat?: \"console\" | \"json\";\n logLevel?: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\";\n}\n\nlet logger: pino.Logger | null = null;\n\nexport function initLogger(config?: LogConfig): void {\n if (logger) return;\n\n const format = config?.logFormat ?? \"console\";\n const level = config?.logLevel ?? \"info\";\n\n if (format === \"json\") {\n try {\n logger = pino({ level }, createGcpStream());\n console.log(`📝 GCP logging enabled (level: ${level})`);\n } catch (err) {\n console.warn(\"⚠️ Failed to init GCP logger, JSON logging disabled:\", err);\n }\n }\n}\n\n/** Only for use in tests. */\nexport function __resetLoggerForTest(): void {\n logger = null;\n}\n\nfunction ctxFields(ctx: LogContext): Record<string, string> {\n const out: Record<string, string> = { channel: ctx.conversationId };\n if (ctx.userName) out.user = ctx.userName;\n if (ctx.conversationName) out.channelName = ctx.conversationName;\n if (ctx.sessionId) out.sessionId = ctx.sessionId;\n return out;\n}\n\nfunction timestamp(): string {\n const now = new Date();\n const hh = String(now.getHours()).padStart(2, \"0\");\n const mm = String(now.getMinutes()).padStart(2, \"0\");\n const ss = String(now.getSeconds()).padStart(2, \"0\");\n return `[${hh}:${mm}:${ss}]`;\n}\n\nfunction formatContext(ctx: LogContext): string {\n const session = ctx.sessionId ? `:${ctx.sessionId}` : \"\";\n if (ctx.conversationId.startsWith(\"D\")) {\n return `[DM:${ctx.userName || ctx.conversationId}${session}]`;\n }\n const conversation = ctx.conversationName || ctx.conversationId;\n const user = ctx.userName || \"unknown\";\n return `[${conversation.startsWith(\"#\") ? conversation : `#${conversation}`}:${user}${session}]`;\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return `${text.substring(0, maxLen)}\\n(truncated at ${maxLen} chars)`;\n}\n\nfunction formatToolArgs(args: Record<string, unknown>): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n // Skip the label - it's already shown in the tool name\n if (key === \"label\") continue;\n\n // For read tool, format path with offset/limit\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n if (offset !== undefined && limit !== undefined) {\n lines.push(`${value}:${offset}-${offset + limit}`);\n } else {\n lines.push(value);\n }\n continue;\n }\n\n // Skip offset/limit since we already handled them\n if (key === \"offset\" || key === \"limit\") continue;\n\n // For other values, format them\n if (typeof value === \"string\") {\n // Multi-line strings get indented\n if (value.includes(\"\\n\")) {\n lines.push(value);\n } else {\n lines.push(value);\n }\n } else {\n lines.push(JSON.stringify(value));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// User messages\nexport function logUserMessage(ctx: LogContext, text: string): void {\n if (logger) logger.info({ event: \"user_message\", ...ctxFields(ctx), text }, text);\n console.log(chalk.green(`${timestamp()} ${formatContext(ctx)} ${text}`));\n}\n\n// Tool execution\nexport function logToolStart(\n ctx: LogContext,\n toolName: string,\n label: string,\n args: Record<string, unknown>,\n): void {\n if (logger)\n logger.debug(\n { event: \"tool_start\", ...ctxFields(ctx), tool: toolName, label, args },\n `${toolName}: ${label}`,\n );\n const formattedArgs = formatToolArgs(args);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ↳ ${toolName}: ${label}`));\n if (formattedArgs) {\n // Indent the args\n const indented = formattedArgs\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logToolSuccess(\n ctx: LogContext,\n toolName: string,\n durationMs: number,\n result: string,\n): void {\n if (logger)\n logger.debug(\n { event: \"tool_success\", ...ctxFields(ctx), tool: toolName, durationMs, result },\n `${toolName} completed`,\n );\n const duration = (durationMs / 1000).toFixed(1);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✓ ${toolName} (${duration}s)`));\n\n const truncated = truncate(result, 1000);\n if (truncated) {\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logToolError(\n ctx: LogContext,\n toolName: string,\n durationMs: number,\n error: string,\n): void {\n if (logger)\n logger.warn(\n { event: \"tool_error\", ...ctxFields(ctx), tool: toolName, durationMs, error },\n `${toolName} failed`,\n );\n const duration = (durationMs / 1000).toFixed(1);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✗ ${toolName} (${duration}s)`));\n\n const truncated = truncate(error, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\n// Response streaming\nexport function logResponseStart(ctx: LogContext): void {\n if (logger) logger.debug({ event: \"response_start\", ...ctxFields(ctx) }, \"Streaming response\");\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} → Streaming response...`));\n}\n\nexport function logThinking(ctx: LogContext, thinking: string): void {\n if (logger) logger.debug({ event: \"thinking\", ...ctxFields(ctx), text: thinking }, \"Thinking\");\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💭 Thinking`));\n const truncated = truncate(thinking, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\nexport function logResponse(ctx: LogContext, text: string): void {\n if (logger) logger.info({ event: \"response\", ...ctxFields(ctx), text }, \"Response\");\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💬 Response`));\n const truncated = truncate(text, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\n// Attachments\nexport function logDownloadStart(ctx: LogContext, filename: string, localPath: string): void {\n if (logger)\n logger.debug(\n { event: \"download_start\", ...ctxFields(ctx), filename, localPath },\n `Downloading ${filename}`,\n );\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ↓ Downloading attachment`));\n console.log(chalk.dim(` ${filename} → ${localPath}`));\n}\n\nexport function logDownloadSuccess(ctx: LogContext, sizeKB: number): void {\n if (logger)\n logger.info(\n { event: \"download_success\", ...ctxFields(ctx), sizeKB },\n `Downloaded (${sizeKB} KB)`,\n );\n console.log(\n chalk.yellow(\n `${timestamp()} ${formatContext(ctx)} ✓ Downloaded (${sizeKB.toLocaleString()} KB)`,\n ),\n );\n}\n\nexport function logDownloadError(ctx: LogContext, filename: string, error: string): void {\n if (logger)\n logger.warn(\n { event: \"download_error\", ...ctxFields(ctx), filename, error },\n `Download failed: ${filename}`,\n );\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✗ Download failed`));\n console.log(chalk.dim(` ${filename}: ${error}`));\n}\n\n// Control\nexport function logStopRequest(ctx: LogContext): void {\n if (logger) logger.info({ event: \"stop_request\", ...ctxFields(ctx) }, \"Stop requested\");\n console.log(chalk.green(`${timestamp()} ${formatContext(ctx)} stop`));\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ⊗ Stop requested - aborting`));\n}\n\n// System\nexport function logInfo(message: string): void {\n if (logger) logger.info({ event: \"info\" }, message);\n console.log(chalk.blue(`${timestamp()} [system] ${message}`));\n}\n\nexport function logWarning(message: string, details?: string): void {\n if (logger) logger.warn({ event: \"warning\", ...(details ? { details } : {}) }, message);\n console.log(chalk.yellow(`${timestamp()} [system] ⚠ ${message}`));\n if (details) {\n const indented = details\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logAgentError(ctx: LogContext | \"system\", error: string): void {\n if (logger) {\n const extra = ctx === \"system\" ? { error } : { ...ctxFields(ctx), error };\n logger.error({ event: \"agent_error\", ...extra }, \"Agent error\");\n }\n const context = ctx === \"system\" ? \"[system]\" : formatContext(ctx);\n console.log(chalk.yellow(`${timestamp()} ${context} ✗ Agent error`));\n const indented = error\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\n// Usage summary\nexport function logUsageSummary(\n ctx: LogContext,\n usage: {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };\n },\n contextTokens?: number,\n contextWindow?: number,\n): string {\n const formatTokens = (count: number): string => {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1000000) return `${Math.round(count / 1000)}k`;\n return `${(count / 1000000).toFixed(1)}M`;\n };\n\n const lines: string[] = [];\n lines.push(\"_Usage Summary_\");\n lines.push(`Tokens: ${usage.input.toLocaleString()} in, ${usage.output.toLocaleString()} out`);\n if (usage.cacheRead > 0 || usage.cacheWrite > 0) {\n lines.push(\n `Cache: ${usage.cacheRead.toLocaleString()} read, ${usage.cacheWrite.toLocaleString()} write`,\n );\n }\n if (contextTokens && contextWindow) {\n const contextPercent = ((contextTokens / contextWindow) * 100).toFixed(1);\n lines.push(\n `Context: ${formatTokens(contextTokens)} / ${formatTokens(contextWindow)} (${contextPercent}%)`,\n );\n }\n lines.push(\n `Cost: $${usage.cost.input.toFixed(4)} in, $${usage.cost.output.toFixed(4)} out` +\n (usage.cacheRead > 0 || usage.cacheWrite > 0\n ? `, $${usage.cost.cacheRead.toFixed(4)} cache read, $${usage.cost.cacheWrite.toFixed(4)} cache write`\n : \"\"),\n );\n lines.push(`*Total: $${usage.cost.total.toFixed(4)}*`);\n\n const summary = lines.join(\"\\n\");\n\n // Log to console\n if (logger) {\n logger.info(\n {\n event: \"usage\",\n ...ctxFields(ctx),\n tokensIn: usage.input,\n tokensOut: usage.output,\n cacheRead: usage.cacheRead,\n cacheWrite: usage.cacheWrite,\n cost: usage.cost.total,\n },\n `Usage: $${usage.cost.total.toFixed(4)}`,\n );\n }\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💰 Usage`));\n console.log(\n chalk.dim(\n ` ${usage.input.toLocaleString()} in + ${usage.output.toLocaleString()} out` +\n (usage.cacheRead > 0 || usage.cacheWrite > 0\n ? ` (${usage.cacheRead.toLocaleString()} cache read, ${usage.cacheWrite.toLocaleString()} cache write)`\n : \"\") +\n ` = $${usage.cost.total.toFixed(4)}`,\n ),\n );\n\n return summary;\n}\n\n// Startup (no context needed)\nexport function logStartup(workingDir: string, sandbox: string): void {\n if (logger) logger.info({ event: \"startup\", workingDir, sandbox }, \"Starting mama\");\n console.log(\"Starting mama...\");\n console.log(` Working directory: ${workingDir}`);\n console.log(` Sandbox: ${sandbox}`);\n}\n\nexport function logConnected(): void {\n if (logger) logger.info({ event: \"connected\" }, \"Mama connected and listening\");\n console.log(\"⚡️ Mama connected and listening!\");\n console.log(\"\");\n}\n\nexport function logDisconnected(): void {\n if (logger) logger.info({ event: \"disconnected\" }, \"Mama disconnected\");\n console.log(\"Mama disconnected.\");\n}\n\n// Backfill\nexport function logBackfillStart(channelCount: number): void {\n if (logger)\n logger.info({ event: \"backfill_start\", channelCount }, `Backfilling ${channelCount} channels`);\n console.log(chalk.blue(`${timestamp()} [system] Backfilling ${channelCount} channels...`));\n}\n\nexport function logBackfillChannel(channelName: string, messageCount: number): void {\n if (logger)\n logger.debug(\n { event: \"backfill_channel\", channelName, messageCount },\n `#${channelName}: ${messageCount} messages`,\n );\n console.log(chalk.blue(`${timestamp()} [system] #${channelName}: ${messageCount} messages`));\n}\n\nexport function logBackfillComplete(totalMessages: number, durationMs: number): void {\n if (logger)\n logger.info(\n { event: \"backfill_complete\", totalMessages, durationMs },\n `Backfill complete: ${totalMessages} messages`,\n );\n const duration = (durationMs / 1000).toFixed(1);\n console.log(\n chalk.blue(\n `${timestamp()} [system] Backfill complete: ${totalMessages} messages in ${duration}s`,\n ),\n );\n}\n"]}
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"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","sourcesContent":["import chalk from \"chalk\";\n\nexport interface LogContext {\n conversationId: string;\n userName?: string;\n conversationName?: string; // For display like #dev-team vs C16HET4EQ\n sessionId?: string;\n}\n\nfunction timestamp(): string {\n const now = new Date();\n const hh = String(now.getHours()).padStart(2, \"0\");\n const mm = String(now.getMinutes()).padStart(2, \"0\");\n const ss = String(now.getSeconds()).padStart(2, \"0\");\n return `[${hh}:${mm}:${ss}]`;\n}\n\nfunction formatContext(ctx: LogContext): string {\n const session = ctx.sessionId ? `:${ctx.sessionId}` : \"\";\n if (ctx.conversationId.startsWith(\"D\")) {\n return `[DM:${ctx.userName || ctx.conversationId}${session}]`;\n }\n const conversation = ctx.conversationName || ctx.conversationId;\n const user = ctx.userName || \"unknown\";\n return `[${conversation.startsWith(\"#\") ? conversation : `#${conversation}`}:${user}${session}]`;\n}\n\nfunction truncate(text: string, maxLen: number): string {\n if (text.length <= maxLen) return text;\n return `${text.substring(0, maxLen)}\\n(truncated at ${maxLen} chars)`;\n}\n\nfunction formatToolArgs(args: Record<string, unknown>): string {\n const lines: string[] = [];\n\n for (const [key, value] of Object.entries(args)) {\n // Skip the label - it's already shown in the tool name\n if (key === \"label\") continue;\n\n // For read tool, format path with offset/limit\n if (key === \"path\" && typeof value === \"string\") {\n const offset = args.offset as number | undefined;\n const limit = args.limit as number | undefined;\n if (offset !== undefined && limit !== undefined) {\n lines.push(`${value}:${offset}-${offset + limit}`);\n } else {\n lines.push(value);\n }\n continue;\n }\n\n // Skip offset/limit since we already handled them\n if (key === \"offset\" || key === \"limit\") continue;\n\n // For other values, format them\n if (typeof value === \"string\") {\n // Multi-line strings get indented\n if (value.includes(\"\\n\")) {\n lines.push(value);\n } else {\n lines.push(value);\n }\n } else {\n lines.push(JSON.stringify(value));\n }\n }\n\n return lines.join(\"\\n\");\n}\n\n// User messages\nexport function logUserMessage(ctx: LogContext, text: string): void {\n console.log(chalk.green(`${timestamp()} ${formatContext(ctx)} ${text}`));\n}\n\n// Tool execution\nexport function logToolStart(\n ctx: LogContext,\n toolName: string,\n label: string,\n args: Record<string, unknown>,\n): void {\n const formattedArgs = formatToolArgs(args);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ↳ ${toolName}: ${label}`));\n if (formattedArgs) {\n // Indent the args\n const indented = formattedArgs\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logToolSuccess(\n ctx: LogContext,\n toolName: string,\n durationMs: number,\n result: string,\n): void {\n const duration = (durationMs / 1000).toFixed(1);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✓ ${toolName} (${duration}s)`));\n\n const truncated = truncate(result, 1000);\n if (truncated) {\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logToolError(\n ctx: LogContext,\n toolName: string,\n durationMs: number,\n error: string,\n): void {\n const duration = (durationMs / 1000).toFixed(1);\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} ✗ ${toolName} (${duration}s)`));\n\n const truncated = truncate(error, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\n// Response streaming\nexport function logResponseStart(ctx: LogContext): void {\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} → Streaming response...`));\n}\n\nexport function logThinking(ctx: LogContext, thinking: string): void {\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💭 Thinking`));\n const truncated = truncate(thinking, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\nexport function logResponse(ctx: LogContext, text: string): void {\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💬 Response`));\n const truncated = truncate(text, 1000);\n const indented = truncated\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\n// System\nexport function logInfo(message: string): void {\n console.log(chalk.blue(`${timestamp()} [system] ${message}`));\n}\n\nexport function logWarning(message: string, details?: string): void {\n console.log(chalk.yellow(`${timestamp()} [system] ⚠ ${message}`));\n if (details) {\n const indented = details\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n }\n}\n\nexport function logAgentError(ctx: LogContext | \"system\", error: string): void {\n const context = ctx === \"system\" ? \"[system]\" : formatContext(ctx);\n console.log(chalk.yellow(`${timestamp()} ${context} ✗ Agent error`));\n const indented = error\n .split(\"\\n\")\n .map((line) => ` ${line}`)\n .join(\"\\n\");\n console.log(chalk.dim(indented));\n}\n\nfunction formatTokenCount(count: number): string {\n if (count < 1000) return count.toString();\n if (count < 10000) return `${(count / 1000).toFixed(1)}k`;\n if (count < 1000000) return `${Math.round(count / 1000)}k`;\n return `${(count / 1000000).toFixed(1)}M`;\n}\n\n// Usage summary\nexport function logUsageSummary(\n ctx: LogContext,\n usage: {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n cost: { input: number; output: number; cacheRead: number; cacheWrite: number; total: number };\n },\n contextTokens?: number,\n contextWindow?: number,\n): string {\n const lines: string[] = [];\n lines.push(\"_Usage Summary_\");\n lines.push(`Tokens: ${usage.input.toLocaleString()} in, ${usage.output.toLocaleString()} out`);\n if (usage.cacheRead > 0 || usage.cacheWrite > 0) {\n lines.push(\n `Cache: ${usage.cacheRead.toLocaleString()} read, ${usage.cacheWrite.toLocaleString()} write`,\n );\n }\n if (contextTokens && contextWindow) {\n const contextPercent = ((contextTokens / contextWindow) * 100).toFixed(1);\n lines.push(\n `Context: ${formatTokenCount(contextTokens)} / ${formatTokenCount(contextWindow)} (${contextPercent}%)`,\n );\n }\n lines.push(\n `Cost: $${usage.cost.input.toFixed(4)} in, $${usage.cost.output.toFixed(4)} out` +\n (usage.cacheRead > 0 || usage.cacheWrite > 0\n ? `, $${usage.cost.cacheRead.toFixed(4)} cache read, $${usage.cost.cacheWrite.toFixed(4)} cache write`\n : \"\"),\n );\n lines.push(`*Total: $${usage.cost.total.toFixed(4)}*`);\n\n const summary = lines.join(\"\\n\");\n\n console.log(chalk.yellow(`${timestamp()} ${formatContext(ctx)} 💰 Usage`));\n console.log(\n chalk.dim(\n ` ${usage.input.toLocaleString()} in + ${usage.output.toLocaleString()} out` +\n (usage.cacheRead > 0 || usage.cacheWrite > 0\n ? ` (${usage.cacheRead.toLocaleString()} cache read, ${usage.cacheWrite.toLocaleString()} cache write)`\n : \"\") +\n ` = $${usage.cost.total.toFixed(4)}`,\n ),\n );\n\n return summary;\n}\n\n// Startup (no context needed)\nexport function logStartup(workingDir: string, sandbox: string): void {\n console.log(\"Starting mama...\");\n console.log(` Working directory: ${workingDir}`);\n console.log(` Sandbox: ${sandbox}`);\n}\n\nexport function logConnected(platform: string): void {\n console.log(`⚡️ Mama connected to ${platform} and listening!`);\n console.log(\"\");\n}\n\nexport function logDisconnected(): void {\n console.log(\"Mama disconnected.\");\n}\n\n// Backfill\nexport function logBackfillStart(channelCount: number): void {\n console.log(chalk.blue(`${timestamp()} [system] Backfilling ${channelCount} channels...`));\n}\n\nexport function logBackfillChannel(channelName: string, messageCount: number): void {\n console.log(chalk.blue(`${timestamp()} [system] #${channelName}: ${messageCount} messages`));\n}\n\nexport function logBackfillComplete(totalMessages: number, durationMs: number): void {\n const duration = (durationMs / 1000).toFixed(1);\n console.log(\n chalk.blue(\n `${timestamp()} [system] Backfill complete: ${totalMessages} messages in ${duration}s`,\n ),\n );\n}\n"]}
@@ -4,6 +4,7 @@ export interface OAuthAuthorizedUserFileOutput {
4
4
  relativePath: string;
5
5
  targetPath?: string;
6
6
  envKey?: string;
7
+ additionalEnvKeys?: string[];
7
8
  }
8
9
  export interface OAuthService {
9
10
  id: string;
@@ -20,10 +21,22 @@ export interface OAuthService {
20
21
  authorizationParams?: Record<string, string>;
21
22
  fileOutput?: OAuthAuthorizedUserFileOutput;
22
23
  }
23
- export interface ParsedLoginCommand {
24
+ export type ParsedLoginCommand = {
24
25
  command: "login" | "/login" | "/pi-login";
25
- }
26
+ action: "setup";
27
+ } | {
28
+ command: "login" | "/login" | "/pi-login";
29
+ action: "shared_create" | "shared_update" | "shared_delete";
30
+ name: string;
31
+ } | {
32
+ command: "login" | "/login" | "/pi-login";
33
+ action: "shared_list";
34
+ } | {
35
+ command: "login" | "/login" | "/pi-login";
36
+ action: "copy_shared";
37
+ name: string;
38
+ };
26
39
  export declare function getOAuthServices(): OAuthService[];
27
40
  export declare function resolveOAuthService(input: string): OAuthService | undefined;
28
41
  export declare function parseLoginCommand(text: string): ParsedLoginCommand | null;
29
- //# sourceMappingURL=login.d.ts.map
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/login/index.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,iBAAiB,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,4BAA4B,CAAC,EAAE,MAAM,EAAE,CAAC;IACxC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,UAAU,CAAC,EAAE,6BAA6B,CAAC;CAC5C;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GAC9D;IACE,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1C,MAAM,EAAE,eAAe,GAAG,eAAe,GAAG,eAAe,CAAC;IAC5D,IAAI,EAAE,MAAM,CAAC;CACd,GACD;IAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,GACpE;IAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,WAAW,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAkHvF,wBAAgB,gBAAgB,IAAI,YAAY,EAAE,CAwHjD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAM3E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAqCzE","sourcesContent":["import * as log from \"../log.js\";\nimport { isRecord, parseJsonValue } from \"../file-guards.js\";\n\nexport type LoginCredentialKind = \"api_key\" | \"oauth\";\n\nexport interface OAuthAuthorizedUserFileOutput {\n type: \"authorized_user\";\n relativePath: string;\n targetPath?: string;\n envKey?: string;\n additionalEnvKeys?: string[];\n}\n\nexport interface OAuthService {\n id: string;\n label: string;\n aliases: string[];\n authorizationUrl: string;\n tokenUrl: string;\n scopes: string[];\n clientIdEnvKey: string;\n clientSecretEnvKey: string;\n accessTokenEnvKey?: string;\n additionalAccessTokenEnvKeys?: string[];\n refreshTokenEnvKey?: string;\n authorizationParams?: Record<string, string>;\n fileOutput?: OAuthAuthorizedUserFileOutput;\n}\n\nexport type ParsedLoginCommand =\n | { command: \"login\" | \"/login\" | \"/pi-login\"; action: \"setup\" }\n | {\n command: \"login\" | \"/login\" | \"/pi-login\";\n action: \"shared_create\" | \"shared_update\" | \"shared_delete\";\n name: string;\n }\n | { command: \"login\" | \"/login\" | \"/pi-login\"; action: \"shared_list\" }\n | { command: \"login\" | \"/login\" | \"/pi-login\"; action: \"copy_shared\"; name: string };\n\nconst DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES = [\n \"https://www.googleapis.com/auth/drive\",\n \"https://mail.google.com/\",\n \"https://www.googleapis.com/auth/calendar\",\n \"https://www.googleapis.com/auth/spreadsheets\",\n \"https://www.googleapis.com/auth/documents\",\n \"https://www.googleapis.com/auth/chat.messages.create\",\n];\n\nconst DEFAULT_GOOGLE_CLOUD_SDK_SCOPES = [\n \"openid\",\n \"https://www.googleapis.com/auth/userinfo.email\",\n \"https://www.googleapis.com/auth/cloud-platform\",\n];\n\n// Conservative default: enough for `gh` CLI repo/user/org operations, but\n// without `workflow` (can dispatch CI), `write:packages` (can publish\n// packages), or `project`. Operators who need those can opt in via\n// MAMA_GITHUB_OAUTH_SCOPES to keep the blast radius of a compromised agent\n// host explicit and configurable.\nconst DEFAULT_GITHUB_OAUTH_SCOPES = [\"repo\", \"read:user\", \"user:email\", \"read:org\", \"gist\"];\n\nfunction resolveScopesFromEnv(envKey: string, fallback: string[]): string[] {\n const raw = process.env[envKey]?.trim();\n if (!raw) return fallback;\n\n const scopes = raw\n .split(/[\\s,]+/)\n .map((scope) => scope.trim())\n .filter(Boolean);\n\n return scopes.length > 0 ? scopes : fallback;\n}\n\nfunction resolveGoogleWorkspaceCliScopes(): string[] {\n return resolveScopesFromEnv(\n \"MAMA_GOOGLE_WORKSPACE_CLI_OAUTH_SCOPES\",\n DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES,\n );\n}\n\nfunction resolveGoogleCloudSdkScopes(): string[] {\n return resolveScopesFromEnv(\n \"MAMA_GOOGLE_CLOUD_SDK_OAUTH_SCOPES\",\n DEFAULT_GOOGLE_CLOUD_SDK_SCOPES,\n );\n}\n\nfunction resolveGitHubOAuthScopes(): string[] {\n return resolveScopesFromEnv(\"MAMA_GITHUB_OAUTH_SCOPES\", DEFAULT_GITHUB_OAUTH_SCOPES);\n}\n\nfunction getBuiltinOAuthServices(): OAuthService[] {\n return [\n {\n id: \"github\",\n label: \"GitHub\",\n aliases: [\"github\", \"github_oauth\", \"gh_oauth\"],\n authorizationUrl: \"https://github.com/login/oauth/authorize\",\n tokenUrl: \"https://github.com/login/oauth/access_token\",\n scopes: resolveGitHubOAuthScopes(),\n clientIdEnvKey: \"GITHUB_OAUTH_CLIENT_ID\",\n clientSecretEnvKey: \"GITHUB_OAUTH_CLIENT_SECRET\",\n accessTokenEnvKey: \"GITHUB_OAUTH_ACCESS_TOKEN\",\n additionalAccessTokenEnvKeys: [\"GH_TOKEN\"],\n refreshTokenEnvKey: \"GITHUB_OAUTH_REFRESH_TOKEN\",\n },\n {\n id: \"google_workspace_cli\",\n label: \"Google Workspace CLI\",\n aliases: [\"google_workspace_cli\", \"gws\", \"googleworkspace\", \"google-workspace-cli\"],\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n scopes: resolveGoogleWorkspaceCliScopes(),\n clientIdEnvKey: \"GOOGLE_WORKSPACE_CLI_CLIENT_ID\",\n clientSecretEnvKey: \"GOOGLE_WORKSPACE_CLI_CLIENT_SECRET\",\n authorizationParams: {\n access_type: \"offline\",\n include_granted_scopes: \"true\",\n prompt: \"consent\",\n },\n fileOutput: {\n type: \"authorized_user\",\n relativePath: \"gws.json\",\n targetPath: \"/root/.config/gws/credentials.json\",\n },\n },\n {\n id: \"google_cloud_sdk\",\n label: \"Google Cloud SDK (gcloud)\",\n aliases: [\"google_cloud_sdk\", \"gcloud\", \"google-cloud-sdk\", \"google_cloud\", \"gcp\"],\n authorizationUrl: \"https://accounts.google.com/o/oauth2/v2/auth\",\n tokenUrl: \"https://oauth2.googleapis.com/token\",\n scopes: resolveGoogleCloudSdkScopes(),\n clientIdEnvKey: \"GOOGLE_CLOUD_SDK_CLIENT_ID\",\n clientSecretEnvKey: \"GOOGLE_CLOUD_SDK_CLIENT_SECRET\",\n authorizationParams: {\n access_type: \"offline\",\n include_granted_scopes: \"true\",\n prompt: \"consent\",\n },\n fileOutput: {\n type: \"authorized_user\",\n relativePath: \"gcloud-adc.json\",\n targetPath: \"/root/.config/gcloud/application_default_credentials.json\",\n envKey: \"GOOGLE_APPLICATION_CREDENTIALS\",\n additionalEnvKeys: [\"CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE\"],\n },\n },\n ];\n}\n\nexport function getOAuthServices(): OAuthService[] {\n const raw = process.env.MAMA_OAUTH_SERVICES_JSON?.trim();\n const builtins = getBuiltinOAuthServices();\n if (!raw) return builtins;\n\n let parsed: unknown[];\n try {\n parsed = parseJsonValue(raw, Array.isArray, (detail) =>\n detail === \"unexpected JSON shape\"\n ? \"expected a JSON array of OAuth service definitions\"\n : detail,\n );\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n log.logWarning(\n detail === \"expected a JSON array of OAuth service definitions\"\n ? \"Ignoring MAMA_OAUTH_SERVICES_JSON: expected a JSON array of OAuth service definitions\"\n : \"Ignoring MAMA_OAUTH_SERVICES_JSON: invalid JSON\",\n detail,\n );\n return builtins;\n }\n try {\n const custom = parsed\n .map((serviceValue): OAuthService | null => {\n if (!isRecord(serviceValue)) return null;\n const obj = serviceValue;\n const id = typeof obj.id === \"string\" ? obj.id.trim() : \"\";\n const label = typeof obj.label === \"string\" ? obj.label.trim() : \"\";\n const authorizationUrl =\n typeof obj.authorizationUrl === \"string\" ? obj.authorizationUrl.trim() : \"\";\n const tokenUrl = typeof obj.tokenUrl === \"string\" ? obj.tokenUrl.trim() : \"\";\n const clientIdEnvKey =\n typeof obj.clientIdEnvKey === \"string\" ? obj.clientIdEnvKey.trim() : \"\";\n const clientSecretEnvKey =\n typeof obj.clientSecretEnvKey === \"string\" ? obj.clientSecretEnvKey.trim() : \"\";\n const accessTokenEnvKey =\n typeof obj.accessTokenEnvKey === \"string\" ? obj.accessTokenEnvKey.trim() : undefined;\n if (\n !id ||\n !label ||\n !authorizationUrl ||\n !tokenUrl ||\n !clientIdEnvKey ||\n !clientSecretEnvKey\n ) {\n return null;\n }\n\n let fileOutput: OAuthService[\"fileOutput\"];\n if (isRecord(obj.fileOutput)) {\n const fileOutputObj = obj.fileOutput;\n const type = typeof fileOutputObj.type === \"string\" ? fileOutputObj.type.trim() : \"\";\n const relativePath =\n typeof fileOutputObj.relativePath === \"string\" ? fileOutputObj.relativePath.trim() : \"\";\n const targetPath =\n typeof fileOutputObj.targetPath === \"string\"\n ? fileOutputObj.targetPath.trim()\n : undefined;\n const envKey =\n typeof fileOutputObj.envKey === \"string\" ? fileOutputObj.envKey.trim() : undefined;\n const additionalEnvKeys = Array.isArray(fileOutputObj.additionalEnvKeys)\n ? fileOutputObj.additionalEnvKeys.filter((v): v is string => typeof v === \"string\")\n : undefined;\n if (type === \"authorized_user\" && relativePath) {\n fileOutput = {\n type: \"authorized_user\",\n relativePath,\n targetPath,\n envKey,\n additionalEnvKeys,\n };\n }\n }\n\n return {\n id: id.toLowerCase(),\n label,\n aliases: Array.isArray(obj.aliases)\n ? obj.aliases\n .filter((v): v is string => typeof v === \"string\")\n .map((v) => v.toLowerCase())\n : [id.toLowerCase()],\n authorizationUrl,\n tokenUrl,\n scopes: Array.isArray(obj.scopes)\n ? obj.scopes.filter((v): v is string => typeof v === \"string\")\n : [],\n clientIdEnvKey,\n clientSecretEnvKey,\n accessTokenEnvKey,\n additionalAccessTokenEnvKeys: Array.isArray(obj.additionalAccessTokenEnvKeys)\n ? obj.additionalAccessTokenEnvKeys.filter((v): v is string => typeof v === \"string\")\n : undefined,\n refreshTokenEnvKey:\n typeof obj.refreshTokenEnvKey === \"string\" ? obj.refreshTokenEnvKey.trim() : undefined,\n authorizationParams: isRecord(obj.authorizationParams)\n ? Object.fromEntries(\n Object.entries(obj.authorizationParams).filter(\n (authorizationEntry): authorizationEntry is [string, string] =>\n typeof authorizationEntry[1] === \"string\",\n ),\n )\n : undefined,\n fileOutput,\n };\n })\n .filter((service): service is OAuthService => service !== null);\n\n const byId = new Map<string, OAuthService>();\n for (const service of builtins) byId.set(service.id, service);\n for (const service of custom) byId.set(service.id, service);\n return [...byId.values()];\n } catch (err) {\n log.logWarning(\n \"Failed to apply MAMA_OAUTH_SERVICES_JSON overrides; using builtin OAuth services\",\n err instanceof Error ? err.message : String(err),\n );\n return builtins;\n }\n}\n\nexport function resolveOAuthService(input: string): OAuthService | undefined {\n const normalized = input.trim().toLowerCase();\n if (!normalized) return undefined;\n return getOAuthServices().find(\n (service) => service.id === normalized || service.aliases.includes(normalized),\n );\n}\n\nexport function parseLoginCommand(text: string): ParsedLoginCommand | null {\n const tokens = text.trim().split(/\\s+/).filter(Boolean);\n if (tokens.length === 0) return null;\n\n const command = tokens[0].toLowerCase();\n if (command !== \"login\" && command !== \"/login\" && command !== \"/pi-login\") {\n return null;\n }\n const typedCommand = command as \"login\" | \"/login\" | \"/pi-login\";\n const [subcommand, operation, name, ...extra] = tokens.slice(1);\n\n if (!subcommand) return { command: typedCommand, action: \"setup\" };\n\n if (subcommand.toLowerCase() === \"shared\") {\n const op = operation?.toLowerCase();\n if (op === \"list\" && !name && extra.length === 0) {\n return { command: typedCommand, action: \"shared_list\" };\n }\n if ((op === \"create\" || op === \"update\" || op === \"delete\") && !!name && extra.length === 0) {\n return {\n command: typedCommand,\n action: `shared_${op}` as \"shared_create\" | \"shared_update\" | \"shared_delete\",\n name,\n };\n }\n return null;\n }\n\n if (subcommand.toLowerCase() === \"copy\" && operation && !name && extra.length === 0) {\n return { command: typedCommand, action: \"copy_shared\", name: operation };\n }\n\n // Backward-compatible: older `/pi-login gh` / `/pi-login gws` forms opened the\n // generic login page and let the portal handle provider choice.\n if (!operation && extra.length === 0) return { command: typedCommand, action: \"setup\" };\n\n return null;\n}\n"]}
@@ -1,3 +1,5 @@
1
+ import * as log from "../log.js";
2
+ import { isRecord, parseJsonValue } from "../file-guards.js";
1
3
  const DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES = [
2
4
  "https://www.googleapis.com/auth/drive",
3
5
  "https://mail.google.com/",
@@ -6,10 +8,15 @@ const DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES = [
6
8
  "https://www.googleapis.com/auth/documents",
7
9
  "https://www.googleapis.com/auth/chat.messages.create",
8
10
  ];
11
+ const DEFAULT_GOOGLE_CLOUD_SDK_SCOPES = [
12
+ "openid",
13
+ "https://www.googleapis.com/auth/userinfo.email",
14
+ "https://www.googleapis.com/auth/cloud-platform",
15
+ ];
9
16
  // Conservative default: enough for `gh` CLI repo/user/org operations, but
10
17
  // without `workflow` (can dispatch CI), `write:packages` (can publish
11
18
  // packages), or `project`. Operators who need those can opt in via
12
- // MOM_GITHUB_OAUTH_SCOPES to keep the blast radius of a compromised agent
19
+ // MAMA_GITHUB_OAUTH_SCOPES to keep the blast radius of a compromised agent
13
20
  // host explicit and configurable.
14
21
  const DEFAULT_GITHUB_OAUTH_SCOPES = ["repo", "read:user", "user:email", "read:org", "gist"];
15
22
  function resolveScopesFromEnv(envKey, fallback) {
@@ -23,10 +30,13 @@ function resolveScopesFromEnv(envKey, fallback) {
23
30
  return scopes.length > 0 ? scopes : fallback;
24
31
  }
25
32
  function resolveGoogleWorkspaceCliScopes() {
26
- return resolveScopesFromEnv("MOM_GOOGLE_WORKSPACE_CLI_OAUTH_SCOPES", DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES);
33
+ return resolveScopesFromEnv("MAMA_GOOGLE_WORKSPACE_CLI_OAUTH_SCOPES", DEFAULT_GOOGLE_WORKSPACE_CLI_SCOPES);
34
+ }
35
+ function resolveGoogleCloudSdkScopes() {
36
+ return resolveScopesFromEnv("MAMA_GOOGLE_CLOUD_SDK_OAUTH_SCOPES", DEFAULT_GOOGLE_CLOUD_SDK_SCOPES);
27
37
  }
28
38
  function resolveGitHubOAuthScopes() {
29
- return resolveScopesFromEnv("MOM_GITHUB_OAUTH_SCOPES", DEFAULT_GITHUB_OAUTH_SCOPES);
39
+ return resolveScopesFromEnv("MAMA_GITHUB_OAUTH_SCOPES", DEFAULT_GITHUB_OAUTH_SCOPES);
30
40
  }
31
41
  function getBuiltinOAuthServices() {
32
42
  return [
@@ -63,22 +73,54 @@ function getBuiltinOAuthServices() {
63
73
  targetPath: "/root/.config/gws/credentials.json",
64
74
  },
65
75
  },
76
+ {
77
+ id: "google_cloud_sdk",
78
+ label: "Google Cloud SDK (gcloud)",
79
+ aliases: ["google_cloud_sdk", "gcloud", "google-cloud-sdk", "google_cloud", "gcp"],
80
+ authorizationUrl: "https://accounts.google.com/o/oauth2/v2/auth",
81
+ tokenUrl: "https://oauth2.googleapis.com/token",
82
+ scopes: resolveGoogleCloudSdkScopes(),
83
+ clientIdEnvKey: "GOOGLE_CLOUD_SDK_CLIENT_ID",
84
+ clientSecretEnvKey: "GOOGLE_CLOUD_SDK_CLIENT_SECRET",
85
+ authorizationParams: {
86
+ access_type: "offline",
87
+ include_granted_scopes: "true",
88
+ prompt: "consent",
89
+ },
90
+ fileOutput: {
91
+ type: "authorized_user",
92
+ relativePath: "gcloud-adc.json",
93
+ targetPath: "/root/.config/gcloud/application_default_credentials.json",
94
+ envKey: "GOOGLE_APPLICATION_CREDENTIALS",
95
+ additionalEnvKeys: ["CLOUDSDK_AUTH_CREDENTIAL_FILE_OVERRIDE"],
96
+ },
97
+ },
66
98
  ];
67
99
  }
68
100
  export function getOAuthServices() {
69
- const raw = process.env.MOM_OAUTH_SERVICES_JSON?.trim();
101
+ const raw = process.env.MAMA_OAUTH_SERVICES_JSON?.trim();
70
102
  const builtins = getBuiltinOAuthServices();
71
103
  if (!raw)
72
104
  return builtins;
105
+ let parsed;
106
+ try {
107
+ parsed = parseJsonValue(raw, Array.isArray, (detail) => detail === "unexpected JSON shape"
108
+ ? "expected a JSON array of OAuth service definitions"
109
+ : detail);
110
+ }
111
+ catch (err) {
112
+ const detail = err instanceof Error ? err.message : String(err);
113
+ log.logWarning(detail === "expected a JSON array of OAuth service definitions"
114
+ ? "Ignoring MAMA_OAUTH_SERVICES_JSON: expected a JSON array of OAuth service definitions"
115
+ : "Ignoring MAMA_OAUTH_SERVICES_JSON: invalid JSON", detail);
116
+ return builtins;
117
+ }
73
118
  try {
74
- const parsed = JSON.parse(raw);
75
- if (!Array.isArray(parsed))
76
- return builtins;
77
119
  const custom = parsed
78
- .map((entry) => {
79
- if (!entry || typeof entry !== "object")
120
+ .map((serviceValue) => {
121
+ if (!isRecord(serviceValue))
80
122
  return null;
81
- const obj = entry;
123
+ const obj = serviceValue;
82
124
  const id = typeof obj.id === "string" ? obj.id.trim() : "";
83
125
  const label = typeof obj.label === "string" ? obj.label.trim() : "";
84
126
  const authorizationUrl = typeof obj.authorizationUrl === "string" ? obj.authorizationUrl.trim() : "";
@@ -95,7 +137,7 @@ export function getOAuthServices() {
95
137
  return null;
96
138
  }
97
139
  let fileOutput;
98
- if (obj.fileOutput && typeof obj.fileOutput === "object") {
140
+ if (isRecord(obj.fileOutput)) {
99
141
  const fileOutputObj = obj.fileOutput;
100
142
  const type = typeof fileOutputObj.type === "string" ? fileOutputObj.type.trim() : "";
101
143
  const relativePath = typeof fileOutputObj.relativePath === "string" ? fileOutputObj.relativePath.trim() : "";
@@ -103,8 +145,17 @@ export function getOAuthServices() {
103
145
  ? fileOutputObj.targetPath.trim()
104
146
  : undefined;
105
147
  const envKey = typeof fileOutputObj.envKey === "string" ? fileOutputObj.envKey.trim() : undefined;
148
+ const additionalEnvKeys = Array.isArray(fileOutputObj.additionalEnvKeys)
149
+ ? fileOutputObj.additionalEnvKeys.filter((v) => typeof v === "string")
150
+ : undefined;
106
151
  if (type === "authorized_user" && relativePath) {
107
- fileOutput = { type: "authorized_user", relativePath, targetPath, envKey };
152
+ fileOutput = {
153
+ type: "authorized_user",
154
+ relativePath,
155
+ targetPath,
156
+ envKey,
157
+ additionalEnvKeys,
158
+ };
108
159
  }
109
160
  }
110
161
  return {
@@ -127,8 +178,8 @@ export function getOAuthServices() {
127
178
  ? obj.additionalAccessTokenEnvKeys.filter((v) => typeof v === "string")
128
179
  : undefined,
129
180
  refreshTokenEnvKey: typeof obj.refreshTokenEnvKey === "string" ? obj.refreshTokenEnvKey.trim() : undefined,
130
- authorizationParams: obj.authorizationParams && typeof obj.authorizationParams === "object"
131
- ? Object.fromEntries(Object.entries(obj.authorizationParams).filter((entry) => typeof entry[1] === "string"))
181
+ authorizationParams: isRecord(obj.authorizationParams)
182
+ ? Object.fromEntries(Object.entries(obj.authorizationParams).filter((authorizationEntry) => typeof authorizationEntry[1] === "string"))
132
183
  : undefined,
133
184
  fileOutput,
134
185
  };
@@ -141,7 +192,8 @@ export function getOAuthServices() {
141
192
  byId.set(service.id, service);
142
193
  return [...byId.values()];
143
194
  }
144
- catch {
195
+ catch (err) {
196
+ log.logWarning("Failed to apply MAMA_OAUTH_SERVICES_JSON overrides; using builtin OAuth services", err instanceof Error ? err.message : String(err));
145
197
  return builtins;
146
198
  }
147
199
  }
@@ -159,6 +211,31 @@ export function parseLoginCommand(text) {
159
211
  if (command !== "login" && command !== "/login" && command !== "/pi-login") {
160
212
  return null;
161
213
  }
162
- return { command: command };
214
+ const typedCommand = command;
215
+ const [subcommand, operation, name, ...extra] = tokens.slice(1);
216
+ if (!subcommand)
217
+ return { command: typedCommand, action: "setup" };
218
+ if (subcommand.toLowerCase() === "shared") {
219
+ const op = operation?.toLowerCase();
220
+ if (op === "list" && !name && extra.length === 0) {
221
+ return { command: typedCommand, action: "shared_list" };
222
+ }
223
+ if ((op === "create" || op === "update" || op === "delete") && !!name && extra.length === 0) {
224
+ return {
225
+ command: typedCommand,
226
+ action: `shared_${op}`,
227
+ name,
228
+ };
229
+ }
230
+ return null;
231
+ }
232
+ if (subcommand.toLowerCase() === "copy" && operation && !name && extra.length === 0) {
233
+ return { command: typedCommand, action: "copy_shared", name: operation };
234
+ }
235
+ // Backward-compatible: older `/pi-login gh` / `/pi-login gws` forms opened the
236
+ // generic login page and let the portal handle provider choice.
237
+ if (!operation && extra.length === 0)
238
+ return { command: typedCommand, action: "setup" };
239
+ return null;
163
240
  }
164
- //# sourceMappingURL=login.js.map
241
+ //# sourceMappingURL=index.js.map