@jungjaehoon/mama-os 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -0
- package/README.md +643 -0
- package/dist/agent/agent-loop.d.ts +98 -0
- package/dist/agent/agent-loop.d.ts.map +1 -0
- package/dist/agent/agent-loop.js +417 -0
- package/dist/agent/agent-loop.js.map +1 -0
- package/dist/agent/auto-recall.d.ts +48 -0
- package/dist/agent/auto-recall.d.ts.map +1 -0
- package/dist/agent/auto-recall.js +178 -0
- package/dist/agent/auto-recall.js.map +1 -0
- package/dist/agent/claude-cli-wrapper.d.ts +130 -0
- package/dist/agent/claude-cli-wrapper.d.ts.map +1 -0
- package/dist/agent/claude-cli-wrapper.js +227 -0
- package/dist/agent/claude-cli-wrapper.js.map +1 -0
- package/dist/agent/claude-client.d.ts +50 -0
- package/dist/agent/claude-client.d.ts.map +1 -0
- package/dist/agent/claude-client.js +214 -0
- package/dist/agent/claude-client.js.map +1 -0
- package/dist/agent/gateway-tool-executor.d.ts +75 -0
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -0
- package/dist/agent/gateway-tool-executor.js +348 -0
- package/dist/agent/gateway-tool-executor.js.map +1 -0
- package/dist/agent/index.d.ts +13 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +18 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/mcp-executor.d.ts +75 -0
- package/dist/agent/mcp-executor.d.ts.map +1 -0
- package/dist/agent/mcp-executor.js +307 -0
- package/dist/agent/mcp-executor.js.map +1 -0
- package/dist/agent/session-pool.d.ts +148 -0
- package/dist/agent/session-pool.d.ts.map +1 -0
- package/dist/agent/session-pool.js +272 -0
- package/dist/agent/session-pool.js.map +1 -0
- package/dist/agent/streaming-callback-manager.d.ts +85 -0
- package/dist/agent/streaming-callback-manager.d.ts.map +1 -0
- package/dist/agent/streaming-callback-manager.js +103 -0
- package/dist/agent/streaming-callback-manager.js.map +1 -0
- package/dist/agent/types.d.ts +437 -0
- package/dist/agent/types.d.ts.map +1 -0
- package/dist/agent/types.js +29 -0
- package/dist/agent/types.js.map +1 -0
- package/dist/api/cron-handler.d.ts +44 -0
- package/dist/api/cron-handler.d.ts.map +1 -0
- package/dist/api/cron-handler.js +195 -0
- package/dist/api/cron-handler.js.map +1 -0
- package/dist/api/error-handler.d.ts +22 -0
- package/dist/api/error-handler.d.ts.map +1 -0
- package/dist/api/error-handler.js +104 -0
- package/dist/api/error-handler.js.map +1 -0
- package/dist/api/heartbeat-handler.d.ts +49 -0
- package/dist/api/heartbeat-handler.d.ts.map +1 -0
- package/dist/api/heartbeat-handler.js +91 -0
- package/dist/api/heartbeat-handler.js.map +1 -0
- package/dist/api/index.d.ts +61 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +145 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/types.d.ts +156 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +62 -0
- package/dist/api/types.js.map +1 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +11 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/oauth-manager.d.ts +59 -0
- package/dist/auth/oauth-manager.d.ts.map +1 -0
- package/dist/auth/oauth-manager.js +237 -0
- package/dist/auth/oauth-manager.js.map +1 -0
- package/dist/auth/types.d.ts +92 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +23 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +155 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/run.d.ts +19 -0
- package/dist/cli/commands/run.d.ts.map +1 -0
- package/dist/cli/commands/run.js +89 -0
- package/dist/cli/commands/run.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +19 -0
- package/dist/cli/commands/setup.d.ts.map +1 -0
- package/dist/cli/commands/setup.js +134 -0
- package/dist/cli/commands/setup.js.map +1 -0
- package/dist/cli/commands/start.d.ts +24 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +1073 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +10 -0
- package/dist/cli/commands/status.d.ts.map +1 -0
- package/dist/cli/commands/status.js +85 -0
- package/dist/cli/commands/status.js.map +1 -0
- package/dist/cli/commands/stop.d.ts +10 -0
- package/dist/cli/commands/stop.d.ts.map +1 -0
- package/dist/cli/commands/stop.js +65 -0
- package/dist/cli/commands/stop.js.map +1 -0
- package/dist/cli/config/config-manager.d.ts +51 -0
- package/dist/cli/config/config-manager.d.ts.map +1 -0
- package/dist/cli/config/config-manager.js +216 -0
- package/dist/cli/config/config-manager.js.map +1 -0
- package/dist/cli/config/types.d.ts +172 -0
- package/dist/cli/config/types.d.ts.map +1 -0
- package/dist/cli/config/types.js +48 -0
- package/dist/cli/config/types.js.map +1 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +92 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/utils/pid-manager.d.ts +66 -0
- package/dist/cli/utils/pid-manager.d.ts.map +1 -0
- package/dist/cli/utils/pid-manager.js +167 -0
- package/dist/cli/utils/pid-manager.js.map +1 -0
- package/dist/concurrency/index.d.ts +13 -0
- package/dist/concurrency/index.d.ts.map +1 -0
- package/dist/concurrency/index.js +22 -0
- package/dist/concurrency/index.js.map +1 -0
- package/dist/concurrency/lane-manager.d.ts +113 -0
- package/dist/concurrency/lane-manager.d.ts.map +1 -0
- package/dist/concurrency/lane-manager.js +245 -0
- package/dist/concurrency/lane-manager.js.map +1 -0
- package/dist/concurrency/session-key.d.ts +41 -0
- package/dist/concurrency/session-key.d.ts.map +1 -0
- package/dist/concurrency/session-key.js +61 -0
- package/dist/concurrency/session-key.js.map +1 -0
- package/dist/concurrency/types.d.ts +69 -0
- package/dist/concurrency/types.d.ts.map +1 -0
- package/dist/concurrency/types.js +16 -0
- package/dist/concurrency/types.js.map +1 -0
- package/dist/gateways/channel-history.d.ts +102 -0
- package/dist/gateways/channel-history.d.ts.map +1 -0
- package/dist/gateways/channel-history.js +181 -0
- package/dist/gateways/channel-history.js.map +1 -0
- package/dist/gateways/context-injector.d.ts +74 -0
- package/dist/gateways/context-injector.d.ts.map +1 -0
- package/dist/gateways/context-injector.js +121 -0
- package/dist/gateways/context-injector.js.map +1 -0
- package/dist/gateways/discord.d.ts +122 -0
- package/dist/gateways/discord.d.ts.map +1 -0
- package/dist/gateways/discord.js +602 -0
- package/dist/gateways/discord.js.map +1 -0
- package/dist/gateways/index.d.ts +30 -0
- package/dist/gateways/index.d.ts.map +1 -0
- package/dist/gateways/index.js +49 -0
- package/dist/gateways/index.js.map +1 -0
- package/dist/gateways/message-router.d.ts +116 -0
- package/dist/gateways/message-router.d.ts.map +1 -0
- package/dist/gateways/message-router.js +315 -0
- package/dist/gateways/message-router.js.map +1 -0
- package/dist/gateways/message-splitter.d.ts +54 -0
- package/dist/gateways/message-splitter.d.ts.map +1 -0
- package/dist/gateways/message-splitter.js +146 -0
- package/dist/gateways/message-splitter.js.map +1 -0
- package/dist/gateways/plugin-loader.d.ts +76 -0
- package/dist/gateways/plugin-loader.d.ts.map +1 -0
- package/dist/gateways/plugin-loader.js +221 -0
- package/dist/gateways/plugin-loader.js.map +1 -0
- package/dist/gateways/session-store.d.ts +77 -0
- package/dist/gateways/session-store.d.ts.map +1 -0
- package/dist/gateways/session-store.js +233 -0
- package/dist/gateways/session-store.js.map +1 -0
- package/dist/gateways/slack.d.ts +90 -0
- package/dist/gateways/slack.d.ts.map +1 -0
- package/dist/gateways/slack.js +281 -0
- package/dist/gateways/slack.js.map +1 -0
- package/dist/gateways/telegram.d.ts +79 -0
- package/dist/gateways/telegram.d.ts.map +1 -0
- package/dist/gateways/telegram.js +207 -0
- package/dist/gateways/telegram.js.map +1 -0
- package/dist/gateways/types.d.ts +340 -0
- package/dist/gateways/types.d.ts.map +1 -0
- package/dist/gateways/types.js +6 -0
- package/dist/gateways/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/memory/memory-logger.d.ts +47 -0
- package/dist/memory/memory-logger.d.ts.map +1 -0
- package/dist/memory/memory-logger.js +126 -0
- package/dist/memory/memory-logger.js.map +1 -0
- package/dist/onboarding/all-tools.d.ts +18 -0
- package/dist/onboarding/all-tools.d.ts.map +1 -0
- package/dist/onboarding/all-tools.js +149 -0
- package/dist/onboarding/all-tools.js.map +1 -0
- package/dist/onboarding/autonomous-discovery-tools.d.ts +13 -0
- package/dist/onboarding/autonomous-discovery-tools.d.ts.map +1 -0
- package/dist/onboarding/autonomous-discovery-tools.js +268 -0
- package/dist/onboarding/autonomous-discovery-tools.js.map +1 -0
- package/dist/onboarding/bootstrap-template.d.ts +5 -0
- package/dist/onboarding/bootstrap-template.d.ts.map +1 -0
- package/dist/onboarding/bootstrap-template.js +142 -0
- package/dist/onboarding/bootstrap-template.js.map +1 -0
- package/dist/onboarding/complete-autonomous-prompt.d.ts +13 -0
- package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -0
- package/dist/onboarding/complete-autonomous-prompt.js +1220 -0
- package/dist/onboarding/complete-autonomous-prompt.js.map +1 -0
- package/dist/onboarding/onboarding-state.d.ts +70 -0
- package/dist/onboarding/onboarding-state.d.ts.map +1 -0
- package/dist/onboarding/onboarding-state.js +184 -0
- package/dist/onboarding/onboarding-state.js.map +1 -0
- package/dist/onboarding/personality-quiz.d.ts +35 -0
- package/dist/onboarding/personality-quiz.d.ts.map +1 -0
- package/dist/onboarding/personality-quiz.js +219 -0
- package/dist/onboarding/personality-quiz.js.map +1 -0
- package/dist/onboarding/phase-5-summary.d.ts +22 -0
- package/dist/onboarding/phase-5-summary.d.ts.map +1 -0
- package/dist/onboarding/phase-5-summary.js +151 -0
- package/dist/onboarding/phase-5-summary.js.map +1 -0
- package/dist/onboarding/phase-6-security.d.ts +33 -0
- package/dist/onboarding/phase-6-security.d.ts.map +1 -0
- package/dist/onboarding/phase-6-security.js +473 -0
- package/dist/onboarding/phase-6-security.js.map +1 -0
- package/dist/onboarding/phase-7-integrations.d.ts +66 -0
- package/dist/onboarding/phase-7-integrations.d.ts.map +1 -0
- package/dist/onboarding/phase-7-integrations.js +619 -0
- package/dist/onboarding/phase-7-integrations.js.map +1 -0
- package/dist/onboarding/phase-8-demo.d.ts +43 -0
- package/dist/onboarding/phase-8-demo.d.ts.map +1 -0
- package/dist/onboarding/phase-8-demo.js +346 -0
- package/dist/onboarding/phase-8-demo.js.map +1 -0
- package/dist/onboarding/phase-9-finalization.d.ts +22 -0
- package/dist/onboarding/phase-9-finalization.d.ts.map +1 -0
- package/dist/onboarding/phase-9-finalization.js +375 -0
- package/dist/onboarding/phase-9-finalization.js.map +1 -0
- package/dist/onboarding/ritual-prompt.d.ts +2 -0
- package/dist/onboarding/ritual-prompt.d.ts.map +1 -0
- package/dist/onboarding/ritual-prompt.js +285 -0
- package/dist/onboarding/ritual-prompt.js.map +1 -0
- package/dist/onboarding/ritual-tools.d.ts +13 -0
- package/dist/onboarding/ritual-tools.d.ts.map +1 -0
- package/dist/onboarding/ritual-tools.js +93 -0
- package/dist/onboarding/ritual-tools.js.map +1 -0
- package/dist/runners/cli-runner.d.ts +59 -0
- package/dist/runners/cli-runner.d.ts.map +1 -0
- package/dist/runners/cli-runner.js +190 -0
- package/dist/runners/cli-runner.js.map +1 -0
- package/dist/runners/index.d.ts +11 -0
- package/dist/runners/index.d.ts.map +1 -0
- package/dist/runners/index.js +15 -0
- package/dist/runners/index.js.map +1 -0
- package/dist/runners/types.d.ts +81 -0
- package/dist/runners/types.d.ts.map +1 -0
- package/dist/runners/types.js +31 -0
- package/dist/runners/types.js.map +1 -0
- package/dist/scheduler/cron-scheduler.d.ts +115 -0
- package/dist/scheduler/cron-scheduler.d.ts.map +1 -0
- package/dist/scheduler/cron-scheduler.js +320 -0
- package/dist/scheduler/cron-scheduler.js.map +1 -0
- package/dist/scheduler/heartbeat.d.ts +53 -0
- package/dist/scheduler/heartbeat.d.ts.map +1 -0
- package/dist/scheduler/heartbeat.js +160 -0
- package/dist/scheduler/heartbeat.js.map +1 -0
- package/dist/scheduler/index.d.ts +22 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js +31 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/scheduler/job-lock.d.ts +85 -0
- package/dist/scheduler/job-lock.d.ts.map +1 -0
- package/dist/scheduler/job-lock.js +137 -0
- package/dist/scheduler/job-lock.js.map +1 -0
- package/dist/scheduler/recovery.d.ts +78 -0
- package/dist/scheduler/recovery.d.ts.map +1 -0
- package/dist/scheduler/recovery.js +124 -0
- package/dist/scheduler/recovery.js.map +1 -0
- package/dist/scheduler/schedule-store.d.ts +112 -0
- package/dist/scheduler/schedule-store.d.ts.map +1 -0
- package/dist/scheduler/schedule-store.js +259 -0
- package/dist/scheduler/schedule-store.js.map +1 -0
- package/dist/scheduler/token-keep-alive.d.ts +49 -0
- package/dist/scheduler/token-keep-alive.d.ts.map +1 -0
- package/dist/scheduler/token-keep-alive.js +102 -0
- package/dist/scheduler/token-keep-alive.js.map +1 -0
- package/dist/scheduler/types.d.ts +96 -0
- package/dist/scheduler/types.d.ts.map +1 -0
- package/dist/scheduler/types.js +21 -0
- package/dist/scheduler/types.js.map +1 -0
- package/dist/setup/setup-prompt.d.ts +2 -0
- package/dist/setup/setup-prompt.d.ts.map +1 -0
- package/dist/setup/setup-prompt.js +138 -0
- package/dist/setup/setup-prompt.js.map +1 -0
- package/dist/setup/setup-server.d.ts +8 -0
- package/dist/setup/setup-server.d.ts.map +1 -0
- package/dist/setup/setup-server.js +71 -0
- package/dist/setup/setup-server.js.map +1 -0
- package/dist/setup/setup-tools.d.ts +13 -0
- package/dist/setup/setup-tools.d.ts.map +1 -0
- package/dist/setup/setup-tools.js +103 -0
- package/dist/setup/setup-tools.js.map +1 -0
- package/dist/setup/setup-websocket.d.ts +6 -0
- package/dist/setup/setup-websocket.d.ts.map +1 -0
- package/dist/setup/setup-websocket.js +312 -0
- package/dist/setup/setup-websocket.js.map +1 -0
- package/dist/skills/index.d.ts +10 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +26 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-executor.d.ts +48 -0
- package/dist/skills/skill-executor.d.ts.map +1 -0
- package/dist/skills/skill-executor.js +483 -0
- package/dist/skills/skill-executor.js.map +1 -0
- package/dist/skills/skill-loader.d.ts +40 -0
- package/dist/skills/skill-loader.d.ts.map +1 -0
- package/dist/skills/skill-loader.js +225 -0
- package/dist/skills/skill-loader.js.map +1 -0
- package/dist/skills/skill-matcher.d.ts +33 -0
- package/dist/skills/skill-matcher.d.ts.map +1 -0
- package/dist/skills/skill-matcher.js +190 -0
- package/dist/skills/skill-matcher.js.map +1 -0
- package/dist/skills/types.d.ts +123 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +12 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/browser-tool.d.ts +149 -0
- package/dist/tools/browser-tool.d.ts.map +1 -0
- package/dist/tools/browser-tool.js +257 -0
- package/dist/tools/browser-tool.js.map +1 -0
- package/package.json +84 -0
- package/public/favicon.ico +0 -0
- package/public/setup.html +1026 -0
- package/public/viewer/icons/icon-192.png +0 -0
- package/public/viewer/icons/icon-512.png +0 -0
- package/public/viewer/js/modules/chat.js +1587 -0
- package/public/viewer/js/modules/dashboard.js +275 -0
- package/public/viewer/js/modules/graph.js +997 -0
- package/public/viewer/js/modules/memory.js +353 -0
- package/public/viewer/js/modules/settings.js +255 -0
- package/public/viewer/js/utils/api.js +169 -0
- package/public/viewer/js/utils/dom.js +92 -0
- package/public/viewer/js/utils/format.js +192 -0
- package/public/viewer/manifest.json +26 -0
- package/public/viewer/sw.js +131 -0
- package/public/viewer/viewer.css +500 -0
- package/public/viewer/viewer.html +1535 -0
- package/scripts/postinstall.js +118 -0
- package/templates/skills/document-analyze.md +63 -0
- package/templates/skills/heartbeat-report.md +75 -0
- package/templates/skills/image-translate.md +67 -0
- package/templates/workspace/skill-forge/DESIGN.md +115 -0
- package/templates/workspace/skill-forge/agents/architect.ts +295 -0
- package/templates/workspace/skill-forge/agents/developer.ts +364 -0
- package/templates/workspace/skill-forge/agents/qa.ts +313 -0
- package/templates/workspace/skill-forge/claude-api.ts +353 -0
- package/templates/workspace/skill-forge/discord-ui.ts +580 -0
- package/templates/workspace/skill-forge/error-handler.ts +354 -0
- package/templates/workspace/skill-forge/mama-integration.ts +357 -0
- package/templates/workspace/skill-forge/orchestrator.ts +495 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/README.md +24 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/index.ts +79 -0
- package/templates/workspace/skill-forge/output/generated-skills/skills/hello-world/types.ts +17 -0
- package/templates/workspace/skill-forge/package.json +21 -0
- package/templates/workspace/skill-forge/state/session.json +132 -0
- package/templates/workspace/skill-forge/test-e2e.ts +139 -0
- package/templates/workspace/skill-forge/tsconfig.json +20 -0
- package/templates/workspace/skill-forge/types.ts +159 -0
|
@@ -0,0 +1,169 @@
|
|
|
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 class API {
|
|
13
|
+
/**
|
|
14
|
+
* Base URL for API requests (empty for same origin)
|
|
15
|
+
*/
|
|
16
|
+
static baseUrl = '';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Perform GET request
|
|
20
|
+
* @param {string} endpoint - API endpoint
|
|
21
|
+
* @param {Object} params - Query parameters
|
|
22
|
+
* @returns {Promise<Object>} Response data
|
|
23
|
+
*/
|
|
24
|
+
static async get(endpoint, params = null) {
|
|
25
|
+
const url = new URL(endpoint, window.location.origin);
|
|
26
|
+
if (params) {
|
|
27
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
28
|
+
if (value !== null && value !== undefined) {
|
|
29
|
+
url.searchParams.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const response = await fetch(url);
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
const error = await response.json().catch(() => ({}));
|
|
37
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return response.json();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Perform POST request
|
|
45
|
+
* @param {string} endpoint - API endpoint
|
|
46
|
+
* @param {Object} body - Request body
|
|
47
|
+
* @returns {Promise<Object>} Response data
|
|
48
|
+
*/
|
|
49
|
+
static async post(endpoint, body) {
|
|
50
|
+
const response = await fetch(endpoint, {
|
|
51
|
+
method: 'POST',
|
|
52
|
+
headers: { 'Content-Type': 'application/json' },
|
|
53
|
+
body: JSON.stringify(body),
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (!response.ok) {
|
|
57
|
+
const error = await response.json().catch(() => ({}));
|
|
58
|
+
throw new Error(error.message || `HTTP ${response.status}`);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return response.json();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// =============================================
|
|
65
|
+
// Graph API
|
|
66
|
+
// =============================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Get graph data
|
|
70
|
+
* @param {Object} params - Query parameters
|
|
71
|
+
* @returns {Promise<Object>} Graph data
|
|
72
|
+
*/
|
|
73
|
+
static async getGraph(params = {}) {
|
|
74
|
+
// cluster: false by default to avoid slow embedding calculations
|
|
75
|
+
return this.get('/graph', { cluster: 'false', ...params });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get similar decisions for a node
|
|
80
|
+
* @param {string} nodeId - Node ID
|
|
81
|
+
* @returns {Promise<Object>} Similar decisions
|
|
82
|
+
*/
|
|
83
|
+
static async getSimilarDecisions(nodeId) {
|
|
84
|
+
return this.get('/graph/similar', { id: nodeId });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Update decision outcome
|
|
89
|
+
* @param {string} id - Decision ID
|
|
90
|
+
* @param {string} outcome - Outcome value
|
|
91
|
+
* @param {string} reason - Optional reason
|
|
92
|
+
* @returns {Promise<Object>} Update result
|
|
93
|
+
*/
|
|
94
|
+
static async updateOutcome(id, outcome, reason = null) {
|
|
95
|
+
return this.post('/graph/update', { id, outcome, reason });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// =============================================
|
|
99
|
+
// Checkpoint API
|
|
100
|
+
// =============================================
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Get all checkpoints
|
|
104
|
+
* @returns {Promise<Object>} Checkpoints data
|
|
105
|
+
*/
|
|
106
|
+
static async getCheckpoints() {
|
|
107
|
+
return this.get('/checkpoints');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// =============================================
|
|
111
|
+
// MAMA Memory API
|
|
112
|
+
// =============================================
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Search MAMA decisions
|
|
116
|
+
* @param {string} query - Search query
|
|
117
|
+
* @param {number} limit - Maximum results
|
|
118
|
+
* @returns {Promise<Object>} Search results
|
|
119
|
+
*/
|
|
120
|
+
static async searchMemory(query, limit = 10) {
|
|
121
|
+
return this.get('/api/mama/search', { q: query, limit });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Save a new decision to MAMA
|
|
126
|
+
* @param {Object} data - Decision data
|
|
127
|
+
* @param {string} data.topic - Decision topic
|
|
128
|
+
* @param {string} data.decision - Decision text
|
|
129
|
+
* @param {string} data.reasoning - Reasoning text
|
|
130
|
+
* @param {number} data.confidence - Confidence (0-1)
|
|
131
|
+
* @returns {Promise<Object>} Save result
|
|
132
|
+
*/
|
|
133
|
+
static async saveDecision(data) {
|
|
134
|
+
return this.post('/api/mama/save', data);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// =============================================
|
|
138
|
+
// Session API
|
|
139
|
+
// =============================================
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create a new chat session
|
|
143
|
+
* @param {string} projectDir - Project directory
|
|
144
|
+
* @returns {Promise<Object>} Session data
|
|
145
|
+
*/
|
|
146
|
+
static async createSession(projectDir = '.') {
|
|
147
|
+
return this.post('/api/sessions', { projectDir });
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Get the last active session
|
|
152
|
+
* @returns {Promise<Object|null>} Last active session or null
|
|
153
|
+
*/
|
|
154
|
+
static async getLastActiveSession() {
|
|
155
|
+
try {
|
|
156
|
+
return await this.get('/api/sessions/last-active');
|
|
157
|
+
} catch {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Get all active sessions
|
|
164
|
+
* @returns {Promise<Object>} Sessions list
|
|
165
|
+
*/
|
|
166
|
+
static async getSessions() {
|
|
167
|
+
return this.get('/api/sessions');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM Utility Functions
|
|
3
|
+
* @module utils/dom
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* eslint-env browser */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Escape HTML to prevent XSS
|
|
11
|
+
* @param {string} text - Text to escape
|
|
12
|
+
* @returns {string} Escaped HTML
|
|
13
|
+
*/
|
|
14
|
+
export function escapeHtml(text) {
|
|
15
|
+
if (!text) {
|
|
16
|
+
return '';
|
|
17
|
+
}
|
|
18
|
+
const div = document.createElement('div');
|
|
19
|
+
div.textContent = text;
|
|
20
|
+
return div.innerHTML;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Debounce function calls
|
|
25
|
+
* @param {Function} func - Function to debounce
|
|
26
|
+
* @param {number} wait - Wait time in milliseconds
|
|
27
|
+
* @returns {Function} Debounced function
|
|
28
|
+
*/
|
|
29
|
+
export function debounce(func, wait) {
|
|
30
|
+
let timeout;
|
|
31
|
+
return function executedFunction(...args) {
|
|
32
|
+
const later = () => {
|
|
33
|
+
clearTimeout(timeout);
|
|
34
|
+
func(...args);
|
|
35
|
+
};
|
|
36
|
+
clearTimeout(timeout);
|
|
37
|
+
timeout = setTimeout(later, wait);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Show toast notification
|
|
43
|
+
* @param {string} message - Message to display
|
|
44
|
+
* @param {number} duration - Duration in milliseconds
|
|
45
|
+
*/
|
|
46
|
+
export function showToast(message, duration = 3000) {
|
|
47
|
+
// Remove existing toast
|
|
48
|
+
const existingToast = document.querySelector('.toast-notification');
|
|
49
|
+
if (existingToast) {
|
|
50
|
+
existingToast.remove();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const toast = document.createElement('div');
|
|
54
|
+
toast.className = 'toast-notification';
|
|
55
|
+
toast.textContent = message;
|
|
56
|
+
document.body.appendChild(toast);
|
|
57
|
+
|
|
58
|
+
// Trigger animation
|
|
59
|
+
requestAnimationFrame(() => {
|
|
60
|
+
toast.classList.add('visible');
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Auto-remove
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
toast.classList.remove('visible');
|
|
66
|
+
setTimeout(() => toast.remove(), 300);
|
|
67
|
+
}, duration);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Scroll element to bottom
|
|
72
|
+
* @param {HTMLElement} container - Container to scroll
|
|
73
|
+
*/
|
|
74
|
+
export function scrollToBottom(container) {
|
|
75
|
+
// Use setTimeout to ensure DOM has updated before scrolling
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
container.scrollTop = container.scrollHeight;
|
|
78
|
+
}, 50);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Auto-resize textarea to fit content
|
|
83
|
+
* @param {HTMLTextAreaElement} textarea - Textarea element
|
|
84
|
+
* @param {number} maxRows - Maximum number of rows (default: 5)
|
|
85
|
+
*/
|
|
86
|
+
export function autoResizeTextarea(textarea, maxRows = 5) {
|
|
87
|
+
textarea.style.height = 'auto';
|
|
88
|
+
const lineHeight = parseInt(getComputedStyle(textarea).lineHeight);
|
|
89
|
+
const maxHeight = lineHeight * maxRows;
|
|
90
|
+
const newHeight = Math.min(textarea.scrollHeight, maxHeight);
|
|
91
|
+
textarea.style.height = newHeight + 'px';
|
|
92
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting Utility Functions
|
|
3
|
+
* @module utils/format
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* eslint-env browser */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Format message timestamp
|
|
11
|
+
* @param {Date} date - Date object
|
|
12
|
+
* @returns {string} Formatted time (HH:MM)
|
|
13
|
+
*/
|
|
14
|
+
export function formatMessageTime(date) {
|
|
15
|
+
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Format checkpoint timestamp
|
|
20
|
+
* @param {string|Date} timestamp - Timestamp
|
|
21
|
+
* @returns {string} Formatted relative time
|
|
22
|
+
*/
|
|
23
|
+
export function formatCheckpointTime(timestamp) {
|
|
24
|
+
const date = new Date(timestamp);
|
|
25
|
+
const now = new Date();
|
|
26
|
+
const diff = now - date;
|
|
27
|
+
|
|
28
|
+
if (diff < 3600000) {
|
|
29
|
+
const mins = Math.floor(diff / 60000);
|
|
30
|
+
return `${mins}m ago`;
|
|
31
|
+
}
|
|
32
|
+
if (diff < 86400000) {
|
|
33
|
+
const hours = Math.floor(diff / 3600000);
|
|
34
|
+
return `${hours}h ago`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
date.toLocaleDateString() +
|
|
39
|
+
' ' +
|
|
40
|
+
date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Format relative time
|
|
46
|
+
* @param {string|Date} timestamp - Timestamp
|
|
47
|
+
* @returns {string} Relative time string
|
|
48
|
+
*/
|
|
49
|
+
export function formatRelativeTime(timestamp) {
|
|
50
|
+
if (!timestamp) {
|
|
51
|
+
return '';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const date = new Date(timestamp);
|
|
55
|
+
const now = new Date();
|
|
56
|
+
const diff = now - date;
|
|
57
|
+
|
|
58
|
+
if (diff < 60000) {
|
|
59
|
+
return 'Just now';
|
|
60
|
+
}
|
|
61
|
+
if (diff < 3600000) {
|
|
62
|
+
const mins = Math.floor(diff / 60000);
|
|
63
|
+
return `${mins}m ago`;
|
|
64
|
+
}
|
|
65
|
+
if (diff < 86400000) {
|
|
66
|
+
const hours = Math.floor(diff / 3600000);
|
|
67
|
+
return `${hours}h ago`;
|
|
68
|
+
}
|
|
69
|
+
if (diff < 604800000) {
|
|
70
|
+
const days = Math.floor(diff / 86400000);
|
|
71
|
+
return `${days}d ago`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return date.toLocaleDateString();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Truncate text with ellipsis
|
|
79
|
+
* @param {string} text - Text to truncate
|
|
80
|
+
* @param {number} maxLength - Maximum length
|
|
81
|
+
* @returns {string} Truncated text
|
|
82
|
+
*/
|
|
83
|
+
export function truncateText(text, maxLength) {
|
|
84
|
+
if (!text) {
|
|
85
|
+
return '';
|
|
86
|
+
}
|
|
87
|
+
if (text.length <= maxLength) {
|
|
88
|
+
return text;
|
|
89
|
+
}
|
|
90
|
+
return text.substring(0, maxLength) + '...';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Extract first meaningful line from text
|
|
95
|
+
* @param {string} text - Text to extract from
|
|
96
|
+
* @returns {string} First meaningful line
|
|
97
|
+
*/
|
|
98
|
+
export function extractFirstLine(text) {
|
|
99
|
+
if (!text) {
|
|
100
|
+
return 'No summary';
|
|
101
|
+
}
|
|
102
|
+
const lines = text.split('\n').filter((l) => l.trim() && !l.startsWith('**'));
|
|
103
|
+
return lines[0] || text.substring(0, 100);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Format assistant message with markdown support
|
|
108
|
+
* @param {string} text - Text to format
|
|
109
|
+
* @returns {string} Formatted HTML
|
|
110
|
+
*/
|
|
111
|
+
export function formatAssistantMessage(text) {
|
|
112
|
+
if (!text) {
|
|
113
|
+
return '';
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// First escape HTML to prevent XSS
|
|
117
|
+
let formatted = escapeHtmlForMarkdown(text);
|
|
118
|
+
|
|
119
|
+
// Code blocks with optional language (```js ... ```)
|
|
120
|
+
formatted = formatted.replace(/```(\w*)\n?([\s\S]*?)```/g, (match, lang, code) => {
|
|
121
|
+
const langClass = lang ? ` class="language-${lang}"` : '';
|
|
122
|
+
return `<pre class="code-block"><code${langClass}>${code.trim()}</code></pre>`;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Inline code
|
|
126
|
+
formatted = formatted.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
127
|
+
|
|
128
|
+
// Bold
|
|
129
|
+
formatted = formatted.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
130
|
+
|
|
131
|
+
// Italic (avoiding conflicts with bold)
|
|
132
|
+
formatted = formatted.replace(/(?<!\*)\*([^*]+)\*(?!\*)/g, '<em>$1</em>');
|
|
133
|
+
|
|
134
|
+
// Links: [text](url)
|
|
135
|
+
formatted = formatted.replace(
|
|
136
|
+
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
137
|
+
'<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
// Auto-detect URLs (not already in anchor tags)
|
|
141
|
+
formatted = formatted.replace(
|
|
142
|
+
/(?<!href="|>)(https?:\/\/[^\s<]+)/g,
|
|
143
|
+
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>'
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Headers (## and ###)
|
|
147
|
+
formatted = formatted.replace(
|
|
148
|
+
/^### (.+)$/gm,
|
|
149
|
+
'<h4 class="text-sm font-semibold mt-2 mb-1">$1</h4>'
|
|
150
|
+
);
|
|
151
|
+
formatted = formatted.replace(
|
|
152
|
+
/^## (.+)$/gm,
|
|
153
|
+
'<h3 class="text-base font-semibold mt-3 mb-1">$1</h3>'
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Bullet lists (- item)
|
|
157
|
+
formatted = formatted.replace(/^- (.+)$/gm, '<li class="ml-4">• $1</li>');
|
|
158
|
+
|
|
159
|
+
// Quiz choices as buttons - patterns like **A)** text or A) text
|
|
160
|
+
// Also handles blockquote prefix (> or >)
|
|
161
|
+
// Match patterns: A) text, **A)** text, > A) text, etc.
|
|
162
|
+
formatted = formatted.replace(
|
|
163
|
+
/^(?:>\s*)?(?:<strong>)?([A-D])\)(?:<\/strong>)?\s*(.+)$/gim,
|
|
164
|
+
(match, letter, text) => {
|
|
165
|
+
const upperLetter = letter.toUpperCase();
|
|
166
|
+
return `<button class="quiz-choice-btn" data-choice="${upperLetter}" onclick="window.sendQuizChoice('${upperLetter}')">${upperLetter}) ${text.trim()}</button>`;
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
// Line breaks
|
|
171
|
+
formatted = formatted.replace(/\n/g, '<br>');
|
|
172
|
+
|
|
173
|
+
// Clean up multiple <br> in lists
|
|
174
|
+
formatted = formatted.replace(/<\/li><br><li/g, '</li><li');
|
|
175
|
+
|
|
176
|
+
// Clean up <br> before/after quiz buttons
|
|
177
|
+
formatted = formatted.replace(/<br>(<button class="quiz-choice-btn")/g, '$1');
|
|
178
|
+
formatted = formatted.replace(/(<\/button>)<br>/g, '$1');
|
|
179
|
+
|
|
180
|
+
return formatted;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Escape HTML for markdown processing
|
|
185
|
+
* @param {string} text - Text to escape
|
|
186
|
+
* @returns {string} Escaped text
|
|
187
|
+
*/
|
|
188
|
+
function escapeHtmlForMarkdown(text) {
|
|
189
|
+
const div = document.createElement('div');
|
|
190
|
+
div.textContent = text;
|
|
191
|
+
return div.innerHTML;
|
|
192
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "MAMA Mobile",
|
|
3
|
+
"short_name": "MAMA",
|
|
4
|
+
"description": "Mobile interface for MAMA - Memory-Augmented MCP Assistant",
|
|
5
|
+
"start_url": "/viewer",
|
|
6
|
+
"display": "standalone",
|
|
7
|
+
"background_color": "#1a1a2e",
|
|
8
|
+
"theme_color": "#1a1a2e",
|
|
9
|
+
"orientation": "portrait-primary",
|
|
10
|
+
"icons": [
|
|
11
|
+
{
|
|
12
|
+
"src": "/viewer/icon-192.png",
|
|
13
|
+
"sizes": "192x192",
|
|
14
|
+
"type": "image/png",
|
|
15
|
+
"purpose": "any maskable"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"src": "/viewer/icon-512.png",
|
|
19
|
+
"sizes": "512x512",
|
|
20
|
+
"type": "image/png",
|
|
21
|
+
"purpose": "any maskable"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"categories": ["productivity", "developer tools"],
|
|
25
|
+
"lang": "ko"
|
|
26
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Service Worker for MAMA Mobile PWA
|
|
3
|
+
* @version 1.5.0
|
|
4
|
+
*
|
|
5
|
+
* Provides offline caching for static assets using cache-first strategy.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/* eslint-env serviceworker */
|
|
9
|
+
|
|
10
|
+
const CACHE_NAME = 'mama-mobile-v1.5.1';
|
|
11
|
+
const STATIC_ASSETS = [
|
|
12
|
+
'/viewer',
|
|
13
|
+
'/viewer/viewer.css',
|
|
14
|
+
'/viewer/viewer.js',
|
|
15
|
+
'/viewer/manifest.json',
|
|
16
|
+
'/viewer/js/modules/graph.js',
|
|
17
|
+
'/viewer/js/modules/chat.js',
|
|
18
|
+
'/viewer/js/modules/memory.js',
|
|
19
|
+
'/viewer/js/utils/dom.js',
|
|
20
|
+
'/viewer/js/utils/format.js',
|
|
21
|
+
'/viewer/js/utils/api.js',
|
|
22
|
+
'/viewer/icons/icon-192.png',
|
|
23
|
+
'/viewer/icons/icon-512.png',
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Install event - cache static assets
|
|
28
|
+
*/
|
|
29
|
+
self.addEventListener('install', (event) => {
|
|
30
|
+
event.waitUntil(
|
|
31
|
+
caches.open(CACHE_NAME).then((cache) => {
|
|
32
|
+
console.log('[SW] Caching static assets (graceful)');
|
|
33
|
+
// Graceful caching - 실패해도 계속 진행
|
|
34
|
+
return Promise.allSettled(
|
|
35
|
+
STATIC_ASSETS.map((url) =>
|
|
36
|
+
fetch(url)
|
|
37
|
+
.then((res) => {
|
|
38
|
+
if (res.ok) {
|
|
39
|
+
return cache.put(url, res);
|
|
40
|
+
}
|
|
41
|
+
console.warn('[SW] Failed to cache:', url, res.status);
|
|
42
|
+
return null;
|
|
43
|
+
})
|
|
44
|
+
.catch((err) => {
|
|
45
|
+
console.warn('[SW] Cache fetch error:', url, err.message);
|
|
46
|
+
return null;
|
|
47
|
+
})
|
|
48
|
+
)
|
|
49
|
+
);
|
|
50
|
+
})
|
|
51
|
+
);
|
|
52
|
+
// Activate immediately
|
|
53
|
+
self.skipWaiting();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Activate event - clean up old caches
|
|
58
|
+
*/
|
|
59
|
+
self.addEventListener('activate', (event) => {
|
|
60
|
+
event.waitUntil(
|
|
61
|
+
caches.keys().then((cacheNames) => {
|
|
62
|
+
return Promise.all(
|
|
63
|
+
cacheNames
|
|
64
|
+
.filter((name) => name !== CACHE_NAME)
|
|
65
|
+
.map((name) => {
|
|
66
|
+
console.log('[SW] Deleting old cache:', name);
|
|
67
|
+
return caches.delete(name);
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
})
|
|
71
|
+
);
|
|
72
|
+
// Take control of all pages immediately
|
|
73
|
+
self.clients.claim();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Fetch event - cache-first strategy for static assets
|
|
78
|
+
*/
|
|
79
|
+
self.addEventListener('fetch', (event) => {
|
|
80
|
+
const { request } = event;
|
|
81
|
+
const url = new URL(request.url);
|
|
82
|
+
|
|
83
|
+
// Only handle GET requests
|
|
84
|
+
if (request.method !== 'GET') {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Skip WebSocket and API requests
|
|
89
|
+
if (url.pathname.startsWith('/ws') || url.pathname.startsWith('/api/')) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Cache-first for static assets
|
|
94
|
+
if (STATIC_ASSETS.some((asset) => url.pathname.startsWith(asset.split('?')[0]))) {
|
|
95
|
+
event.respondWith(
|
|
96
|
+
caches.match(request).then((cachedResponse) => {
|
|
97
|
+
if (cachedResponse) {
|
|
98
|
+
return cachedResponse;
|
|
99
|
+
}
|
|
100
|
+
return fetch(request).then((response) => {
|
|
101
|
+
// Cache successful responses
|
|
102
|
+
if (response.ok) {
|
|
103
|
+
const responseClone = response.clone();
|
|
104
|
+
caches.open(CACHE_NAME).then((cache) => {
|
|
105
|
+
cache.put(request, responseClone);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
return response;
|
|
109
|
+
});
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Network-first for everything else
|
|
116
|
+
event.respondWith(
|
|
117
|
+
fetch(request).catch(() => {
|
|
118
|
+
// Return offline fallback if available
|
|
119
|
+
return caches.match('/viewer');
|
|
120
|
+
})
|
|
121
|
+
);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Message event - handle skip waiting message
|
|
126
|
+
*/
|
|
127
|
+
self.addEventListener('message', (event) => {
|
|
128
|
+
if (event.data === 'skipWaiting') {
|
|
129
|
+
self.skipWaiting();
|
|
130
|
+
}
|
|
131
|
+
});
|