@jungjaehoon/mama-os 0.8.3 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/agent/agent-loop.d.ts +1 -8
  3. package/dist/agent/agent-loop.d.ts.map +1 -1
  4. package/dist/agent/agent-loop.js +44 -159
  5. package/dist/agent/agent-loop.js.map +1 -1
  6. package/dist/agent/claude-cli-wrapper.d.ts +6 -0
  7. package/dist/agent/claude-cli-wrapper.d.ts.map +1 -1
  8. package/dist/agent/claude-cli-wrapper.js +6 -0
  9. package/dist/agent/claude-cli-wrapper.js.map +1 -1
  10. package/dist/agent/codex-mcp-process.d.ts +85 -0
  11. package/dist/agent/codex-mcp-process.d.ts.map +1 -0
  12. package/dist/agent/codex-mcp-process.js +357 -0
  13. package/dist/agent/codex-mcp-process.js.map +1 -0
  14. package/dist/agent/session-pool.d.ts +17 -2
  15. package/dist/agent/session-pool.d.ts.map +1 -1
  16. package/dist/agent/session-pool.js +51 -26
  17. package/dist/agent/session-pool.js.map +1 -1
  18. package/dist/agent/types.d.ts +9 -24
  19. package/dist/agent/types.d.ts.map +1 -1
  20. package/dist/agent/types.js.map +1 -1
  21. package/dist/api/graph-api.d.ts.map +1 -1
  22. package/dist/api/graph-api.js +133 -45
  23. package/dist/api/graph-api.js.map +1 -1
  24. package/dist/cli/commands/init.d.ts +1 -1
  25. package/dist/cli/commands/init.d.ts.map +1 -1
  26. package/dist/cli/commands/init.js +14 -25
  27. package/dist/cli/commands/init.js.map +1 -1
  28. package/dist/cli/commands/run.d.ts.map +1 -1
  29. package/dist/cli/commands/run.js +3 -10
  30. package/dist/cli/commands/run.js.map +1 -1
  31. package/dist/cli/commands/start.d.ts.map +1 -1
  32. package/dist/cli/commands/start.js +143 -54
  33. package/dist/cli/commands/start.js.map +1 -1
  34. package/dist/cli/commands/status.d.ts.map +1 -1
  35. package/dist/cli/commands/status.js +2 -7
  36. package/dist/cli/commands/status.js.map +1 -1
  37. package/dist/cli/config/config-manager.d.ts.map +1 -1
  38. package/dist/cli/config/config-manager.js +9 -17
  39. package/dist/cli/config/config-manager.js.map +1 -1
  40. package/dist/cli/config/types.d.ts +19 -25
  41. package/dist/cli/config/types.d.ts.map +1 -1
  42. package/dist/cli/config/types.js.map +1 -1
  43. package/dist/cli/index.js +2 -2
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/gateways/context-injector.d.ts.map +1 -1
  46. package/dist/gateways/context-injector.js +6 -3
  47. package/dist/gateways/context-injector.js.map +1 -1
  48. package/dist/gateways/discord.d.ts +4 -0
  49. package/dist/gateways/discord.d.ts.map +1 -1
  50. package/dist/gateways/discord.js +39 -16
  51. package/dist/gateways/discord.js.map +1 -1
  52. package/dist/gateways/message-router.d.ts +6 -1
  53. package/dist/gateways/message-router.d.ts.map +1 -1
  54. package/dist/gateways/message-router.js +92 -7
  55. package/dist/gateways/message-router.js.map +1 -1
  56. package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
  57. package/dist/multi-agent/agent-process-manager.js +36 -9
  58. package/dist/multi-agent/agent-process-manager.js.map +1 -1
  59. package/dist/multi-agent/runtime-process.d.ts +4 -4
  60. package/dist/multi-agent/runtime-process.d.ts.map +1 -1
  61. package/dist/multi-agent/runtime-process.js +9 -20
  62. package/dist/multi-agent/runtime-process.js.map +1 -1
  63. package/dist/multi-agent/types.d.ts +13 -8
  64. package/dist/multi-agent/types.d.ts.map +1 -1
  65. package/dist/multi-agent/types.js.map +1 -1
  66. package/dist/setup/setup-prompt.d.ts +1 -1
  67. package/dist/setup/setup-prompt.d.ts.map +1 -1
  68. package/dist/setup/setup-prompt.js +19 -0
  69. package/dist/setup/setup-prompt.js.map +1 -1
  70. package/dist/setup/setup-server.d.ts.map +1 -1
  71. package/dist/setup/setup-server.js +39 -16
  72. package/dist/setup/setup-server.js.map +1 -1
  73. package/dist/skills/skill-registry.d.ts.map +1 -1
  74. package/dist/skills/skill-registry.js +5 -2
  75. package/dist/skills/skill-registry.js.map +1 -1
  76. package/package.json +5 -3
  77. package/public/setup.html +12 -1
  78. package/public/viewer/js/modules/chat.js +1760 -1976
  79. package/public/viewer/js/modules/dashboard.js +613 -695
  80. package/public/viewer/js/modules/graph.js +857 -970
  81. package/public/viewer/js/modules/memory.js +357 -312
  82. package/public/viewer/js/modules/settings.js +1009 -1026
  83. package/public/viewer/js/modules/skills.js +336 -355
  84. package/public/viewer/js/utils/api.js +255 -255
  85. package/public/viewer/js/utils/debug-logger.js +20 -26
  86. package/public/viewer/js/utils/dom.js +73 -60
  87. package/public/viewer/js/utils/format.js +182 -228
  88. package/public/viewer/js/utils/markdown.js +40 -0
  89. package/public/viewer/src/modules/chat.ts +2258 -0
  90. package/public/viewer/src/modules/dashboard.ts +1052 -0
  91. package/public/viewer/src/modules/graph.ts +1080 -0
  92. package/public/viewer/src/modules/memory.ts +453 -0
  93. package/public/viewer/src/modules/settings.ts +1398 -0
  94. package/public/viewer/src/modules/skills.ts +457 -0
  95. package/public/viewer/src/types/global.d.ts +168 -0
  96. package/public/viewer/src/utils/api.ts +650 -0
  97. package/public/viewer/src/utils/debug-logger.ts +36 -0
  98. package/public/viewer/src/utils/dom.ts +138 -0
  99. package/public/viewer/src/utils/format.ts +331 -0
  100. package/public/viewer/src/utils/markdown.ts +46 -0
  101. package/public/viewer/tsconfig.viewer.json +18 -0
  102. package/public/viewer/viewer.html +214 -311
  103. package/dist/agent/codex-cli-wrapper.d.ts +0 -85
  104. package/dist/agent/codex-cli-wrapper.d.ts.map +0 -1
  105. package/dist/agent/codex-cli-wrapper.js +0 -295
  106. package/dist/agent/codex-cli-wrapper.js.map +0 -1
@@ -0,0 +1,650 @@
1
+ /**
2
+ * API Utility Functions
3
+ * @module utils/api
4
+ * @version 1.0.0
5
+ */
6
+
7
+ /* eslint-env browser */
8
+
9
+ /**
10
+ * API client for MAMA viewer
11
+ */
12
+ export type QueryValue = string | number | boolean | null | undefined;
13
+ export type QueryParams = Record<string, QueryValue>;
14
+ export type ApiErrorPayload = { message?: string; error?: string };
15
+ export type JsonRecord = Record<string, unknown>;
16
+
17
+ export interface GraphNode {
18
+ id: string | number;
19
+ topic?: string;
20
+ outcome?: string;
21
+ [key: string]: unknown;
22
+ }
23
+
24
+ export interface GraphEdge {
25
+ from: string | number;
26
+ to: string | number;
27
+ relationship?: string;
28
+ [key: string]: unknown;
29
+ }
30
+
31
+ export interface GraphResponse {
32
+ nodes: GraphNode[];
33
+ edges: GraphEdge[];
34
+ meta?: JsonRecord;
35
+ }
36
+
37
+ export interface SimilarDecision {
38
+ id?: string | number;
39
+ topic?: string;
40
+ decision?: string;
41
+ reasoning?: string;
42
+ relationship?: string;
43
+ similarity?: number;
44
+ [key: string]: unknown;
45
+ }
46
+
47
+ export interface SimilarDecisionsResponse {
48
+ similar: SimilarDecision[];
49
+ [key: string]: unknown;
50
+ }
51
+
52
+ export type GraphSimilarResponse = GraphResponse & SimilarDecisionsResponse;
53
+
54
+ export interface CheckpointSummary {
55
+ id?: string;
56
+ timestamp?: string;
57
+ summary?: string;
58
+ [key: string]: unknown;
59
+ }
60
+
61
+ export interface CheckpointListResponse {
62
+ checkpoints: CheckpointSummary[];
63
+ [key: string]: unknown;
64
+ }
65
+
66
+ export interface MemorySearchItem {
67
+ id?: string;
68
+ topic?: string;
69
+ decision?: string;
70
+ reasoning?: string;
71
+ outcome?: string;
72
+ similarity?: number;
73
+ created_at?: string;
74
+ [key: string]: unknown;
75
+ }
76
+
77
+ export interface MemorySearchResponse {
78
+ results: MemorySearchItem[];
79
+ [key: string]: unknown;
80
+ }
81
+
82
+ export interface MamaDecisionPayload {
83
+ topic: string;
84
+ decision: string;
85
+ reasoning?: string;
86
+ confidence?: number;
87
+ }
88
+
89
+ export interface ApiConfigResponse {
90
+ discord?: ApiGatewayConfig;
91
+ slack?: ApiGatewayConfig;
92
+ telegram?: ApiGatewayConfig;
93
+ chatwork?: ApiGatewayConfig;
94
+ heartbeat?: ApiHeartbeatConfig;
95
+ agent?: ApiAgentConfig;
96
+ roles?: ApiRolesConfig;
97
+ token_budget?: ApiTokenBudgetConfig;
98
+ [key: string]: unknown;
99
+ }
100
+
101
+ export interface ApiGatewayConfig {
102
+ enabled?: boolean;
103
+ token?: string;
104
+ default_channel_id?: string;
105
+ bot_token?: string;
106
+ app_token?: string;
107
+ api_token?: string;
108
+ [key: string]: unknown;
109
+ }
110
+
111
+ export interface ApiHeartbeatConfig {
112
+ enabled?: boolean;
113
+ interval?: number;
114
+ quiet_start?: number;
115
+ quiet_end?: number;
116
+ quietStart?: number;
117
+ quietEnd?: number;
118
+ [key: string]: unknown;
119
+ }
120
+
121
+ export interface ApiAgentToolsConfig {
122
+ gateway?: string[];
123
+ mcp?: string[];
124
+ [key: string]: unknown;
125
+ }
126
+
127
+ export type EffortLevel = 'low' | 'medium' | 'high';
128
+
129
+ export interface ApiAgentConfig {
130
+ backend?: 'claude' | 'codex-mcp';
131
+ model?: string;
132
+ effort?: EffortLevel;
133
+ tools?: ApiAgentToolsConfig;
134
+ use_persistent_cli?: boolean;
135
+ max_turns?: number;
136
+ timeout?: number;
137
+ [key: string]: unknown;
138
+ }
139
+
140
+ export interface ApiRoleDefinition {
141
+ allowedTools?: string[];
142
+ blockedTools?: string[];
143
+ systemControl?: boolean;
144
+ sensitiveAccess?: boolean;
145
+ model?: string;
146
+ maxTurns?: number;
147
+ [key: string]: unknown;
148
+ }
149
+
150
+ export interface ApiRolesConfig {
151
+ definitions?: Record<string, ApiRoleDefinition>;
152
+ sourceMapping?: Record<string, string>;
153
+ [key: string]: unknown;
154
+ }
155
+
156
+ export interface ApiTokenBudgetConfig {
157
+ daily_limit?: number;
158
+ alert_threshold?: number;
159
+ [key: string]: unknown;
160
+ }
161
+
162
+ export interface McpServer {
163
+ name?: string;
164
+ type?: string;
165
+ url?: string;
166
+ hasUrl?: boolean;
167
+ command?: string;
168
+ hasCommand?: boolean;
169
+ hasArgs?: boolean;
170
+ argCount?: number;
171
+ enabled?: boolean;
172
+ [key: string]: unknown;
173
+ }
174
+
175
+ export interface McpServersResponse {
176
+ servers: McpServer[];
177
+ }
178
+
179
+ export interface MultiAgentAgent {
180
+ id?: string;
181
+ enabled?: boolean;
182
+ name?: string;
183
+ display_name?: string;
184
+ tier?: number;
185
+ status?: string;
186
+ model?: string;
187
+ backend?: 'claude' | 'codex-mcp';
188
+ bot_token?: string;
189
+ slack_bot_token?: string | null;
190
+ slack_app_token?: string | null;
191
+ lastActivity?: number | string;
192
+ last_activity?: number | string;
193
+ max_turns?: number;
194
+ timeout?: number;
195
+ use_persistent_cli?: boolean;
196
+ persona_file?: string | null;
197
+ trigger_prefix?: string | null;
198
+ can_delegate?: boolean;
199
+ cooldown_ms?: number;
200
+ outcome?: string;
201
+ tools?: {
202
+ gateway?: string[];
203
+ mcp?: string[];
204
+ mcp_config?: string;
205
+ };
206
+ auto_respond_keywords?: string[];
207
+ tool_permissions?: {
208
+ allowed?: string[];
209
+ blocked?: string[];
210
+ };
211
+ [key: string]: unknown;
212
+ }
213
+
214
+ export interface MultiAgentAgentsResponse {
215
+ enabled?: boolean;
216
+ agents: MultiAgentAgent[];
217
+ }
218
+
219
+ export interface MultiAgentDashboardStatus {
220
+ enabled: boolean;
221
+ agents: MultiAgentAgent[];
222
+ recentDelegations?: {
223
+ id?: string;
224
+ description?: string;
225
+ category?: string;
226
+ wave?: number;
227
+ status?: string;
228
+ claimedBy?: string | null;
229
+ claimedAt?: number | null;
230
+ completedAt?: number | null;
231
+ }[];
232
+ activeChains?: number;
233
+ }
234
+
235
+ export interface SkillItem {
236
+ id: string;
237
+ source: string;
238
+ name: string;
239
+ description?: string;
240
+ enabled?: boolean;
241
+ [key: string]: unknown;
242
+ }
243
+
244
+ export interface SkillsResponse {
245
+ skills: SkillItem[];
246
+ [key: string]: unknown;
247
+ }
248
+
249
+ export interface TokenSummaryPeriod {
250
+ input_tokens?: number;
251
+ output_tokens?: number;
252
+ cache_read_tokens?: number;
253
+ cost_usd?: number;
254
+ request_count?: number;
255
+ [key: string]: unknown;
256
+ }
257
+
258
+ export interface TokenSummaryResponse {
259
+ today?: TokenSummaryPeriod;
260
+ week?: TokenSummaryPeriod;
261
+ month?: TokenSummaryPeriod;
262
+ [key: string]: unknown;
263
+ }
264
+
265
+ export interface TokenByAgentRecord {
266
+ agent_id?: string;
267
+ agent_name?: string;
268
+ input_tokens?: number;
269
+ output_tokens?: number;
270
+ cache_read_tokens?: number;
271
+ cost_usd?: number;
272
+ request_count?: number;
273
+ [key: string]: unknown;
274
+ }
275
+
276
+ export interface TokensByAgentResponse {
277
+ agents: TokenByAgentRecord[];
278
+ [key: string]: unknown;
279
+ }
280
+
281
+ export interface CronJob {
282
+ id: string;
283
+ name: string;
284
+ schedule?: string;
285
+ cronExpr?: string;
286
+ prompt?: string;
287
+ enabled?: boolean;
288
+ nextRun?: string;
289
+ [key: string]: unknown;
290
+ }
291
+
292
+ export interface CronJobsResponse {
293
+ jobs: CronJob[];
294
+ [key: string]: unknown;
295
+ }
296
+
297
+ export interface SessionInfo {
298
+ id: string;
299
+ isAlive?: boolean;
300
+ [key: string]: unknown;
301
+ }
302
+
303
+ export interface SessionsResponse {
304
+ sessions: SessionInfo[];
305
+ }
306
+
307
+ export type LastActiveSessionResponse = SessionInfo;
308
+
309
+ export interface CreateSessionResponse {
310
+ sessionId: string;
311
+ }
312
+
313
+ export interface CronLogEntry {
314
+ ts?: string;
315
+ message?: string;
316
+ [key: string]: unknown;
317
+ }
318
+
319
+ export interface CronLogResponse {
320
+ logs: CronLogEntry[];
321
+ [key: string]: unknown;
322
+ }
323
+
324
+ export class API {
325
+ /**
326
+ * Base URL for API requests (empty for same origin)
327
+ */
328
+ static baseUrl: string = '';
329
+
330
+ /**
331
+ * Parse JSON response safely with explicit error context.
332
+ */
333
+ static async parseJsonResponse<T = unknown>(response: Response, context = '요청'): Promise<T> {
334
+ const contentType = response.headers.get('content-type') || '';
335
+ const text = await response.text();
336
+
337
+ if (!contentType.includes('application/json')) {
338
+ const snippet = text.slice(0, 80).replace(/\n/g, ' ');
339
+ throw new Error(
340
+ `${context}에서 JSON 응답이 아닙니다. content-type: ${
341
+ contentType || '없음'
342
+ }, body: ${snippet}`
343
+ );
344
+ }
345
+
346
+ try {
347
+ if (!text) {
348
+ throw new Error(
349
+ `${context} 응답 본문이 비어 있습니다. status=${response.status}, url=${response.url}`
350
+ );
351
+ }
352
+ return JSON.parse(text) as T;
353
+ } catch (error) {
354
+ const snippet = text.slice(0, 120).replace(/\n/g, ' ');
355
+ const cause = error instanceof Error ? error.message : String(error);
356
+ throw new Error(`${context} 응답 JSON 파싱 실패: ${cause} (샘플: ${snippet})`);
357
+ }
358
+ }
359
+
360
+ /**
361
+ * Perform GET request
362
+ */
363
+ static async get<T = unknown>(endpoint: string, params: QueryParams | null = null): Promise<T> {
364
+ const url = new URL(endpoint, window.location.origin);
365
+ if (params) {
366
+ Object.entries(params).forEach(([key, value]) => {
367
+ if (value !== null && value !== undefined) {
368
+ url.searchParams.set(key, String(value));
369
+ }
370
+ });
371
+ }
372
+
373
+ const response = await fetch(url);
374
+ if (!response.ok) {
375
+ let errorMessage = `HTTP ${response.status}`;
376
+ try {
377
+ const errorData = await this.parseJsonResponse<ApiErrorPayload>(
378
+ response,
379
+ `GET ${endpoint}`
380
+ );
381
+ errorMessage = errorData.message || errorData.error || errorMessage;
382
+ } catch (parseError: unknown) {
383
+ errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
384
+ }
385
+ throw new Error(errorMessage);
386
+ }
387
+
388
+ return this.parseJsonResponse(response, `GET ${endpoint}`);
389
+ }
390
+
391
+ /**
392
+ * Perform POST request
393
+ * @param {string} endpoint - API endpoint
394
+ * @param {Object} body - Request body
395
+ * @returns {Promise<Object>} Response data
396
+ */
397
+ static async post<T = unknown, B = unknown>(endpoint: string, body: B): Promise<T> {
398
+ const response = await fetch(endpoint, {
399
+ method: 'POST',
400
+ headers: { 'Content-Type': 'application/json' },
401
+ body: JSON.stringify(body),
402
+ });
403
+
404
+ if (!response.ok) {
405
+ let errorMessage = `HTTP ${response.status}`;
406
+ try {
407
+ const errorData = await this.parseJsonResponse<ApiErrorPayload>(
408
+ response,
409
+ `POST ${endpoint}`
410
+ );
411
+ errorMessage = errorData.message || errorData.error || errorMessage;
412
+ } catch (parseError: unknown) {
413
+ errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
414
+ }
415
+ throw new Error(errorMessage);
416
+ }
417
+
418
+ return this.parseJsonResponse(response, `POST ${endpoint}`);
419
+ }
420
+
421
+ /**
422
+ * Perform PUT request
423
+ */
424
+ static async put<T = unknown, B = unknown>(endpoint: string, body: B): Promise<T> {
425
+ const response = await fetch(endpoint, {
426
+ method: 'PUT',
427
+ headers: { 'Content-Type': 'application/json' },
428
+ body: JSON.stringify(body),
429
+ });
430
+ if (!response.ok) {
431
+ let errorMessage = `HTTP ${response.status}`;
432
+ try {
433
+ const errorData = await this.parseJsonResponse<ApiErrorPayload>(
434
+ response,
435
+ `PUT ${endpoint}`
436
+ );
437
+ errorMessage = errorData.message || errorData.error || errorMessage;
438
+ } catch (parseError: unknown) {
439
+ errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
440
+ }
441
+ throw new Error(errorMessage);
442
+ }
443
+ return this.parseJsonResponse(response, `PUT ${endpoint}`);
444
+ }
445
+
446
+ /**
447
+ * Perform DELETE request
448
+ */
449
+ static async del<T = unknown>(endpoint: string): Promise<T> {
450
+ const response = await fetch(endpoint, { method: 'DELETE' });
451
+ if (!response.ok) {
452
+ let errorMessage = `HTTP ${response.status}`;
453
+ try {
454
+ const errorData = await this.parseJsonResponse<ApiErrorPayload>(
455
+ response,
456
+ `DELETE ${endpoint}`
457
+ );
458
+ errorMessage = errorData.message || errorData.error || errorMessage;
459
+ } catch (parseError: unknown) {
460
+ errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
461
+ }
462
+ throw new Error(errorMessage);
463
+ }
464
+
465
+ return this.parseJsonResponse(response, `DELETE ${endpoint}`);
466
+ }
467
+
468
+ // =============================================
469
+ // Graph API
470
+ // =============================================
471
+
472
+ /**
473
+ * Get graph data
474
+ * @param {Object} params - Query parameters
475
+ * @returns {Promise<Object>} Graph data
476
+ */
477
+ static async getGraph(params: QueryParams = {}): Promise<GraphResponse> {
478
+ // cluster: false by default to avoid slow embedding calculations
479
+ return this.get<GraphResponse>('/graph', { cluster: 'false', ...params });
480
+ }
481
+
482
+ /**
483
+ * Get similar decisions for a node
484
+ * @param {string} nodeId - Node ID
485
+ * @returns {Promise<Object>} Similar decisions
486
+ */
487
+ static async getSimilarDecisions(nodeId: string): Promise<GraphSimilarResponse> {
488
+ return this.get<GraphSimilarResponse>('/graph/similar', { id: nodeId });
489
+ }
490
+
491
+ /**
492
+ * Update decision outcome
493
+ * @param {string} id - Decision ID
494
+ * @param {string} outcome - Outcome value
495
+ * @param {string} reason - Optional reason
496
+ * @returns {Promise<Object>} Update result
497
+ */
498
+ static async updateOutcome(
499
+ id: string,
500
+ outcome: string,
501
+ reason: string | null = null
502
+ ): Promise<JsonRecord> {
503
+ return this.post<JsonRecord, { id: string; outcome: string; reason: string | null }>(
504
+ '/graph/update',
505
+ { id, outcome, reason }
506
+ );
507
+ }
508
+
509
+ // =============================================
510
+ // Checkpoint API
511
+ // =============================================
512
+
513
+ /**
514
+ * Get all checkpoints
515
+ * @returns {Promise<Object>} Checkpoints data
516
+ */
517
+ static async getCheckpoints(): Promise<CheckpointListResponse> {
518
+ return this.get<CheckpointListResponse>('/checkpoints');
519
+ }
520
+
521
+ // =============================================
522
+ // MAMA Memory API
523
+ // =============================================
524
+
525
+ /**
526
+ * Search MAMA decisions
527
+ * @param {string} query - Search query
528
+ * @param {number} limit - Maximum results
529
+ * @returns {Promise<Object>} Search results
530
+ */
531
+ static async searchMemory(query: string, limit = 10): Promise<MemorySearchResponse> {
532
+ return this.get<MemorySearchResponse>('/api/mama/search', { q: query, limit });
533
+ }
534
+
535
+ /**
536
+ * Save a new decision to MAMA
537
+ * @param {Object} data - Decision data
538
+ * @param {string} data.topic - Decision topic
539
+ * @param {string} data.decision - Decision text
540
+ * @param {string} data.reasoning - Reasoning text
541
+ * @param {number} data.confidence - Confidence (0-1)
542
+ * @returns {Promise<Object>} Save result
543
+ */
544
+ static async saveDecision(data: MamaDecisionPayload): Promise<JsonRecord> {
545
+ return this.post<JsonRecord, MamaDecisionPayload>('/api/mama/save', data);
546
+ }
547
+
548
+ // =============================================
549
+ // Session API
550
+ // =============================================
551
+
552
+ /**
553
+ * Create a new chat session
554
+ * @param {string} projectDir - Project directory
555
+ * @returns {Promise<Object>} Session data
556
+ */
557
+ static async createSession(projectDir = '.'): Promise<CreateSessionResponse> {
558
+ return this.post<CreateSessionResponse, { projectDir: string }>('/api/sessions', {
559
+ projectDir,
560
+ });
561
+ }
562
+
563
+ /**
564
+ * Get the last active session
565
+ * @returns {Promise<Object>} Last active session
566
+ */
567
+ static async getLastActiveSession(): Promise<LastActiveSessionResponse> {
568
+ return this.get<LastActiveSessionResponse>('/api/sessions/last-active');
569
+ }
570
+
571
+ /**
572
+ * Get all active sessions
573
+ * @returns {Promise<Object>} Sessions list
574
+ */
575
+ static async getSessions(): Promise<SessionsResponse> {
576
+ return this.get<SessionsResponse>('/api/sessions');
577
+ }
578
+
579
+ // =============================================
580
+ // Cron API
581
+ // =============================================
582
+
583
+ static async getCronJobs(): Promise<CronJobsResponse> {
584
+ return this.get<CronJobsResponse>('/api/cron');
585
+ }
586
+
587
+ static async updateCronJob(id: string, data: JsonRecord): Promise<JsonRecord> {
588
+ return this.put<JsonRecord, JsonRecord>(`/api/cron/${encodeURIComponent(id)}`, data);
589
+ }
590
+
591
+ static async runCronJob(id: string): Promise<JsonRecord> {
592
+ return this.post<JsonRecord, JsonRecord>(`/api/cron/${encodeURIComponent(id)}/run`, {});
593
+ }
594
+
595
+ static async getCronLogs(id: string, limit = 5): Promise<CronLogResponse> {
596
+ return this.get<CronLogResponse>(`/api/cron/${encodeURIComponent(id)}/logs`, { limit });
597
+ }
598
+
599
+ // =============================================
600
+ // Token API
601
+ // =============================================
602
+
603
+ static async getTokenSummary(): Promise<TokenSummaryResponse> {
604
+ return this.get<TokenSummaryResponse>('/api/tokens/summary');
605
+ }
606
+
607
+ static async getTokensByAgent(): Promise<TokensByAgentResponse> {
608
+ return this.get<TokensByAgentResponse>('/api/tokens/by-agent');
609
+ }
610
+
611
+ static async getTokensDaily(days = 30): Promise<JsonRecord> {
612
+ return this.get<JsonRecord>('/api/tokens/daily', { days });
613
+ }
614
+
615
+ // =============================================
616
+ // Skills API
617
+ // =============================================
618
+
619
+ static async getSkills(): Promise<SkillsResponse> {
620
+ return this.get<SkillsResponse>('/api/skills');
621
+ }
622
+
623
+ static async getSkillCatalog(source = 'all'): Promise<SkillsResponse> {
624
+ return this.get<SkillsResponse>('/api/skills/catalog', { source });
625
+ }
626
+
627
+ static async searchSkills(query: string, source = 'all'): Promise<SkillsResponse> {
628
+ return this.get<SkillsResponse>('/api/skills/search', { q: query, source });
629
+ }
630
+
631
+ static async installSkill(source: string, name: string): Promise<JsonRecord> {
632
+ return this.post('/api/skills/install', { source, name });
633
+ }
634
+
635
+ static async uninstallSkill(name: string, source = 'mama'): Promise<JsonRecord> {
636
+ return this.del(`/api/skills/${encodeURIComponent(name)}?source=${encodeURIComponent(source)}`);
637
+ }
638
+
639
+ static async toggleSkill(name: string, enabled: boolean, source = 'mama'): Promise<JsonRecord> {
640
+ return this.put(`/api/skills/${encodeURIComponent(name)}`, { enabled, source });
641
+ }
642
+
643
+ static async getSkillContent(name: string, source = 'mama'): Promise<JsonRecord> {
644
+ return this.get(`/api/skills/${encodeURIComponent(name)}/readme`, { source });
645
+ }
646
+
647
+ static async installSkillFromUrl(url: string): Promise<JsonRecord> {
648
+ return this.post('/api/skills/install-url', { url });
649
+ }
650
+ }
@@ -0,0 +1,36 @@
1
+ /* eslint-env browser */
2
+
3
+ /**
4
+ * Lightweight DebugLogger for viewer modules.
5
+ * Mirrors mama-core DebugLogger behavior (no console.log usage).
6
+ */
7
+ export class DebugLogger {
8
+ context: string;
9
+
10
+ constructor(context = 'Viewer') {
11
+ this.context = String(context);
12
+ }
13
+
14
+ private _format(level: string, args: unknown[]) {
15
+ const ts = new Date().toISOString();
16
+ return [`[${ts}] [${this.context}] [${level}]`, ...args];
17
+ }
18
+
19
+ debug(...args: unknown[]) {
20
+ console.debug(...this._format('DEBUG', args));
21
+ }
22
+
23
+ info(...args: unknown[]) {
24
+ console.info(...this._format('INFO', args));
25
+ }
26
+
27
+ warn(...args: unknown[]) {
28
+ console.warn(...this._format('WARN', args));
29
+ }
30
+
31
+ error(...args: unknown[]) {
32
+ console.error(...this._format('ERROR', args));
33
+ }
34
+ }
35
+
36
+ export default DebugLogger;