@maadb/core 0.0.1 → 0.7.10-rc.3
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/LICENSE +21 -0
- package/README.md +371 -3
- package/dist/architect.d.ts +2 -0
- package/dist/architect.d.ts.map +1 -0
- package/dist/architect.js +273 -0
- package/dist/architect.js.map +1 -0
- package/dist/auth/resolve.d.ts +36 -0
- package/dist/auth/resolve.d.ts.map +1 -0
- package/dist/auth/resolve.js +77 -0
- package/dist/auth/resolve.js.map +1 -0
- package/dist/auth/token-store.d.ts +82 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +464 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/auth/types.d.ts +75 -0
- package/dist/auth/types.d.ts.map +1 -0
- package/dist/auth/types.js +15 -0
- package/dist/auth/types.js.map +1 -0
- package/dist/backend/adapter.d.ts +57 -0
- package/dist/backend/adapter.d.ts.map +1 -0
- package/dist/backend/adapter.js +6 -0
- package/dist/backend/adapter.js.map +1 -0
- package/dist/backend/index.d.ts +3 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +2 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/sqlite/index.d.ts +63 -0
- package/dist/backend/sqlite/index.d.ts.map +1 -0
- package/dist/backend/sqlite/index.js +521 -0
- package/dist/backend/sqlite/index.js.map +1 -0
- package/dist/backend/sqlite/schema.d.ts +2 -0
- package/dist/backend/sqlite/schema.d.ts.map +1 -0
- package/dist/backend/sqlite/schema.js +88 -0
- package/dist/backend/sqlite/schema.js.map +1 -0
- package/dist/claude-md.d.ts +2 -0
- package/dist/claude-md.d.ts.map +1 -0
- package/dist/claude-md.js +97 -0
- package/dist/claude-md.js.map +1 -0
- package/dist/cli/commands/audit.d.ts +4 -0
- package/dist/cli/commands/audit.d.ts.map +1 -0
- package/dist/cli/commands/audit.js +39 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/auth.d.ts +8 -0
- package/dist/cli/commands/auth.d.ts.map +1 -0
- package/dist/cli/commands/auth.js +242 -0
- package/dist/cli/commands/auth.js.map +1 -0
- package/dist/cli/commands/discover.d.ts +5 -0
- package/dist/cli/commands/discover.d.ts.map +1 -0
- package/dist/cli/commands/discover.js +48 -0
- package/dist/cli/commands/discover.js.map +1 -0
- package/dist/cli/commands/maintain.d.ts +6 -0
- package/dist/cli/commands/maintain.d.ts.map +1 -0
- package/dist/cli/commands/maintain.js +168 -0
- package/dist/cli/commands/maintain.js.map +1 -0
- package/dist/cli/commands/read.d.ts +7 -0
- package/dist/cli/commands/read.d.ts.map +1 -0
- package/dist/cli/commands/read.js +139 -0
- package/dist/cli/commands/read.js.map +1 -0
- package/dist/cli/commands/write.d.ts +4 -0
- package/dist/cli/commands/write.d.ts.map +1 -0
- package/dist/cli/commands/write.js +99 -0
- package/dist/cli/commands/write.js.map +1 -0
- package/dist/cli/helpers.d.ts +8 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +17 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +296 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -0
- package/dist/engine/audit.d.ts +15 -0
- package/dist/engine/audit.d.ts.map +1 -0
- package/dist/engine/audit.js +42 -0
- package/dist/engine/audit.js.map +1 -0
- package/dist/engine/backup.d.ts +9 -0
- package/dist/engine/backup.d.ts.map +1 -0
- package/dist/engine/backup.js +100 -0
- package/dist/engine/backup.js.map +1 -0
- package/dist/engine/composites.d.ts +6 -0
- package/dist/engine/composites.d.ts.map +1 -0
- package/dist/engine/composites.js +102 -0
- package/dist/engine/composites.js.map +1 -0
- package/dist/engine/context.d.ts +47 -0
- package/dist/engine/context.d.ts.map +1 -0
- package/dist/engine/context.js +55 -0
- package/dist/engine/context.js.map +1 -0
- package/dist/engine/docid-safe.d.ts +8 -0
- package/dist/engine/docid-safe.d.ts.map +1 -0
- package/dist/engine/docid-safe.js +0 -0
- package/dist/engine/docid-safe.js.map +1 -0
- package/dist/engine/helpers.d.ts +8 -0
- package/dist/engine/helpers.d.ts.map +1 -0
- package/dist/engine/helpers.js +102 -0
- package/dist/engine/helpers.js.map +1 -0
- package/dist/engine/index.d.ts +215 -0
- package/dist/engine/index.d.ts.map +1 -0
- package/dist/engine/index.js +494 -0
- package/dist/engine/index.js.map +1 -0
- package/dist/engine/indexing.d.ts +14 -0
- package/dist/engine/indexing.d.ts.map +1 -0
- package/dist/engine/indexing.js +225 -0
- package/dist/engine/indexing.js.map +1 -0
- package/dist/engine/journal.d.ts +32 -0
- package/dist/engine/journal.d.ts.map +1 -0
- package/dist/engine/journal.js +111 -0
- package/dist/engine/journal.js.map +1 -0
- package/dist/engine/logger.d.ts +19 -0
- package/dist/engine/logger.d.ts.map +1 -0
- package/dist/engine/logger.js +40 -0
- package/dist/engine/logger.js.map +1 -0
- package/dist/engine/maintenance.d.ts +15 -0
- package/dist/engine/maintenance.d.ts.map +1 -0
- package/dist/engine/maintenance.js +87 -0
- package/dist/engine/maintenance.js.map +1 -0
- package/dist/engine/mutex.d.ts +24 -0
- package/dist/engine/mutex.d.ts.map +1 -0
- package/dist/engine/mutex.js +50 -0
- package/dist/engine/mutex.js.map +1 -0
- package/dist/engine/pathguard.d.ts +16 -0
- package/dist/engine/pathguard.d.ts.map +1 -0
- package/dist/engine/pathguard.js +41 -0
- package/dist/engine/pathguard.js.map +1 -0
- package/dist/engine/reads.d.ts +25 -0
- package/dist/engine/reads.d.ts.map +1 -0
- package/dist/engine/reads.js +904 -0
- package/dist/engine/reads.js.map +1 -0
- package/dist/engine/types.d.ts +396 -0
- package/dist/engine/types.d.ts.map +1 -0
- package/dist/engine/types.js +5 -0
- package/dist/engine/types.js.map +1 -0
- package/dist/engine/writes.d.ts +10 -0
- package/dist/engine/writes.d.ts.map +1 -0
- package/dist/engine/writes.js +606 -0
- package/dist/engine/writes.js.map +1 -0
- package/dist/engine.d.ts +3 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +6 -0
- package/dist/engine.js.map +1 -0
- package/dist/errors.d.ts +20 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +17 -0
- package/dist/errors.js.map +1 -0
- package/dist/extractor/fields.d.ts +3 -0
- package/dist/extractor/fields.d.ts.map +1 -0
- package/dist/extractor/fields.js +58 -0
- package/dist/extractor/fields.js.map +1 -0
- package/dist/extractor/index.d.ts +7 -0
- package/dist/extractor/index.d.ts.map +1 -0
- package/dist/extractor/index.js +22 -0
- package/dist/extractor/index.js.map +1 -0
- package/dist/extractor/normalizers.d.ts +22 -0
- package/dist/extractor/normalizers.d.ts.map +1 -0
- package/dist/extractor/normalizers.js +250 -0
- package/dist/extractor/normalizers.js.map +1 -0
- package/dist/extractor/objects.d.ts +3 -0
- package/dist/extractor/objects.d.ts.map +1 -0
- package/dist/extractor/objects.js +33 -0
- package/dist/extractor/objects.js.map +1 -0
- package/dist/extractor/relationships.d.ts +3 -0
- package/dist/extractor/relationships.d.ts.map +1 -0
- package/dist/extractor/relationships.js +58 -0
- package/dist/extractor/relationships.js.map +1 -0
- package/dist/git/commit.d.ts +63 -0
- package/dist/git/commit.d.ts.map +1 -0
- package/dist/git/commit.js +161 -0
- package/dist/git/commit.js.map +1 -0
- package/dist/git/diff.d.ts +4 -0
- package/dist/git/diff.d.ts.map +1 -0
- package/dist/git/diff.js +56 -0
- package/dist/git/diff.js.map +1 -0
- package/dist/git/index.d.ts +63 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +151 -0
- package/dist/git/index.js.map +1 -0
- package/dist/git/log.d.ts +13 -0
- package/dist/git/log.d.ts.map +1 -0
- package/dist/git/log.js +116 -0
- package/dist/git/log.js.map +1 -0
- package/dist/git/snapshot.d.ts +4 -0
- package/dist/git/snapshot.d.ts.map +1 -0
- package/dist/git/snapshot.js +65 -0
- package/dist/git/snapshot.js.map +1 -0
- package/dist/instance/config.d.ts +19 -0
- package/dist/instance/config.d.ts.map +1 -0
- package/dist/instance/config.js +107 -0
- package/dist/instance/config.js.map +1 -0
- package/dist/instance/pool.d.ts +138 -0
- package/dist/instance/pool.d.ts.map +1 -0
- package/dist/instance/pool.js +335 -0
- package/dist/instance/pool.js.map +1 -0
- package/dist/instance/session.d.ts +140 -0
- package/dist/instance/session.d.ts.map +1 -0
- package/dist/instance/session.js +267 -0
- package/dist/instance/session.js.map +1 -0
- package/dist/logging.d.ts +108 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +120 -0
- package/dist/logging.js.map +1 -0
- package/dist/maad-md.d.ts +11 -0
- package/dist/maad-md.d.ts.map +1 -0
- package/dist/maad-md.js +252 -0
- package/dist/maad-md.js.map +1 -0
- package/dist/mcp/bulk-cap.d.ts +10 -0
- package/dist/mcp/bulk-cap.d.ts.map +1 -0
- package/dist/mcp/bulk-cap.js +37 -0
- package/dist/mcp/bulk-cap.js.map +1 -0
- package/dist/mcp/config.d.ts +18 -0
- package/dist/mcp/config.d.ts.map +1 -0
- package/dist/mcp/config.js +20 -0
- package/dist/mcp/config.js.map +1 -0
- package/dist/mcp/ctx.d.ts +17 -0
- package/dist/mcp/ctx.d.ts.map +1 -0
- package/dist/mcp/ctx.js +7 -0
- package/dist/mcp/ctx.js.map +1 -0
- package/dist/mcp/guardrails.d.ts +42 -0
- package/dist/mcp/guardrails.d.ts.map +1 -0
- package/dist/mcp/guardrails.js +58 -0
- package/dist/mcp/guardrails.js.map +1 -0
- package/dist/mcp/idempotency.d.ts +69 -0
- package/dist/mcp/idempotency.d.ts.map +1 -0
- package/dist/mcp/idempotency.js +168 -0
- package/dist/mcp/idempotency.js.map +1 -0
- package/dist/mcp/instance-reload.d.ts +23 -0
- package/dist/mcp/instance-reload.d.ts.map +1 -0
- package/dist/mcp/instance-reload.js +126 -0
- package/dist/mcp/instance-reload.js.map +1 -0
- package/dist/mcp/kinds.d.ts +22 -0
- package/dist/mcp/kinds.d.ts.map +1 -0
- package/dist/mcp/kinds.js +112 -0
- package/dist/mcp/kinds.js.map +1 -0
- package/dist/mcp/lifecycle.d.ts +8 -0
- package/dist/mcp/lifecycle.d.ts.map +1 -0
- package/dist/mcp/lifecycle.js +65 -0
- package/dist/mcp/lifecycle.js.map +1 -0
- package/dist/mcp/memory-pressure.d.ts +37 -0
- package/dist/mcp/memory-pressure.d.ts.map +1 -0
- package/dist/mcp/memory-pressure.js +179 -0
- package/dist/mcp/memory-pressure.js.map +1 -0
- package/dist/mcp/notifications.d.ts +87 -0
- package/dist/mcp/notifications.d.ts.map +1 -0
- package/dist/mcp/notifications.js +154 -0
- package/dist/mcp/notifications.js.map +1 -0
- package/dist/mcp/query-depth.d.ts +28 -0
- package/dist/mcp/query-depth.d.ts.map +1 -0
- package/dist/mcp/query-depth.js +43 -0
- package/dist/mcp/query-depth.js.map +1 -0
- package/dist/mcp/rate-limit.d.ts +60 -0
- package/dist/mcp/rate-limit.d.ts.map +1 -0
- package/dist/mcp/rate-limit.js +203 -0
- package/dist/mcp/rate-limit.js.map +1 -0
- package/dist/mcp/reload-signal.d.ts +13 -0
- package/dist/mcp/reload-signal.d.ts.map +1 -0
- package/dist/mcp/reload-signal.js +68 -0
- package/dist/mcp/reload-signal.js.map +1 -0
- package/dist/mcp/response.d.ts +109 -0
- package/dist/mcp/response.d.ts.map +1 -0
- package/dist/mcp/response.js +132 -0
- package/dist/mcp/response.js.map +1 -0
- package/dist/mcp/roles.d.ts +7 -0
- package/dist/mcp/roles.d.ts.map +1 -0
- package/dist/mcp/roles.js +57 -0
- package/dist/mcp/roles.js.map +1 -0
- package/dist/mcp/server.d.ts +33 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +252 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/shutdown.d.ts +32 -0
- package/dist/mcp/shutdown.d.ts.map +1 -0
- package/dist/mcp/shutdown.js +130 -0
- package/dist/mcp/shutdown.js.map +1 -0
- package/dist/mcp/tools/audit.d.ts +4 -0
- package/dist/mcp/tools/audit.d.ts.map +1 -0
- package/dist/mcp/tools/audit.js +45 -0
- package/dist/mcp/tools/audit.js.map +1 -0
- package/dist/mcp/tools/auth.d.ts +4 -0
- package/dist/mcp/tools/auth.d.ts.map +1 -0
- package/dist/mcp/tools/auth.js +181 -0
- package/dist/mcp/tools/auth.js.map +1 -0
- package/dist/mcp/tools/backup.d.ts +4 -0
- package/dist/mcp/tools/backup.d.ts.map +1 -0
- package/dist/mcp/tools/backup.js +52 -0
- package/dist/mcp/tools/backup.js.map +1 -0
- package/dist/mcp/tools/discover.d.ts +4 -0
- package/dist/mcp/tools/discover.d.ts.map +1 -0
- package/dist/mcp/tools/discover.js +83 -0
- package/dist/mcp/tools/discover.js.map +1 -0
- package/dist/mcp/tools/instance.d.ts +15 -0
- package/dist/mcp/tools/instance.d.ts.map +1 -0
- package/dist/mcp/tools/instance.js +207 -0
- package/dist/mcp/tools/instance.js.map +1 -0
- package/dist/mcp/tools/maintain.d.ts +4 -0
- package/dist/mcp/tools/maintain.d.ts.map +1 -0
- package/dist/mcp/tools/maintain.js +123 -0
- package/dist/mcp/tools/maintain.js.map +1 -0
- package/dist/mcp/tools/read.d.ts +4 -0
- package/dist/mcp/tools/read.d.ts.map +1 -0
- package/dist/mcp/tools/read.js +304 -0
- package/dist/mcp/tools/read.js.map +1 -0
- package/dist/mcp/tools/write.d.ts +4 -0
- package/dist/mcp/tools/write.d.ts.map +1 -0
- package/dist/mcp/tools/write.js +342 -0
- package/dist/mcp/tools/write.js.map +1 -0
- package/dist/mcp/transport/auth.d.ts +41 -0
- package/dist/mcp/transport/auth.d.ts.map +1 -0
- package/dist/mcp/transport/auth.js +115 -0
- package/dist/mcp/transport/auth.js.map +1 -0
- package/dist/mcp/transport/http.d.ts +62 -0
- package/dist/mcp/transport/http.d.ts.map +1 -0
- package/dist/mcp/transport/http.js +357 -0
- package/dist/mcp/transport/http.js.map +1 -0
- package/dist/mcp/transport/pin.d.ts +15 -0
- package/dist/mcp/transport/pin.d.ts.map +1 -0
- package/dist/mcp/transport/pin.js +71 -0
- package/dist/mcp/transport/pin.js.map +1 -0
- package/dist/mcp/transport/telemetry.d.ts +79 -0
- package/dist/mcp/transport/telemetry.d.ts.map +1 -0
- package/dist/mcp/transport/telemetry.js +97 -0
- package/dist/mcp/transport/telemetry.js.map +1 -0
- package/dist/mcp/with-session.d.ts +26 -0
- package/dist/mcp/with-session.d.ts.map +1 -0
- package/dist/mcp/with-session.js +275 -0
- package/dist/mcp/with-session.js.map +1 -0
- package/dist/parser/annotations.d.ts +3 -0
- package/dist/parser/annotations.d.ts.map +1 -0
- package/dist/parser/annotations.js +41 -0
- package/dist/parser/annotations.js.map +1 -0
- package/dist/parser/blocks.d.ts +3 -0
- package/dist/parser/blocks.d.ts.map +1 -0
- package/dist/parser/blocks.js +101 -0
- package/dist/parser/blocks.js.map +1 -0
- package/dist/parser/frontmatter.d.ts +9 -0
- package/dist/parser/frontmatter.d.ts.map +1 -0
- package/dist/parser/frontmatter.js +33 -0
- package/dist/parser/frontmatter.js.map +1 -0
- package/dist/parser/index.d.ts +11 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +54 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/matter.d.ts +3 -0
- package/dist/parser/matter.d.ts.map +1 -0
- package/dist/parser/matter.js +32 -0
- package/dist/parser/matter.js.map +1 -0
- package/dist/parser/tags.d.ts +3 -0
- package/dist/parser/tags.d.ts.map +1 -0
- package/dist/parser/tags.js +32 -0
- package/dist/parser/tags.js.map +1 -0
- package/dist/parser/verbatim.d.ts +4 -0
- package/dist/parser/verbatim.d.ts.map +1 -0
- package/dist/parser/verbatim.js +121 -0
- package/dist/parser/verbatim.js.map +1 -0
- package/dist/parser/yaml-profile.d.ts +4 -0
- package/dist/parser/yaml-profile.d.ts.map +1 -0
- package/dist/parser/yaml-profile.js +73 -0
- package/dist/parser/yaml-profile.js.map +1 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +2 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/loader.d.ts +4 -0
- package/dist/registry/loader.d.ts.map +1 -0
- package/dist/registry/loader.js +147 -0
- package/dist/registry/loader.js.map +1 -0
- package/dist/registry/types.d.ts +2 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +5 -0
- package/dist/registry/types.js.map +1 -0
- package/dist/scanner.d.ts +57 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +223 -0
- package/dist/scanner.js.map +1 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/schema/loader.d.ts +4 -0
- package/dist/schema/loader.d.ts.map +1 -0
- package/dist/schema/loader.js +303 -0
- package/dist/schema/loader.js.map +1 -0
- package/dist/schema/precision.d.ts +6 -0
- package/dist/schema/precision.d.ts.map +1 -0
- package/dist/schema/precision.js +59 -0
- package/dist/schema/precision.js.map +1 -0
- package/dist/schema/validator.d.ts +21 -0
- package/dist/schema/validator.d.ts.map +1 -0
- package/dist/schema/validator.js +200 -0
- package/dist/schema/validator.js.map +1 -0
- package/dist/schema-md.d.ts +8 -0
- package/dist/schema-md.d.ts.map +1 -0
- package/dist/schema-md.js +98 -0
- package/dist/schema-md.js.map +1 -0
- package/dist/skill-files.d.ts +3 -0
- package/dist/skill-files.d.ts.map +1 -0
- package/dist/skill-files.js +362 -0
- package/dist/skill-files.js.map +1 -0
- package/dist/skills-scaffold.d.ts +10 -0
- package/dist/skills-scaffold.d.ts.map +1 -0
- package/dist/skills-scaffold.js +52 -0
- package/dist/skills-scaffold.js.map +1 -0
- package/dist/types.d.ts +309 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +111 -0
- package/dist/types.js.map +1 -0
- package/dist/writer/index.d.ts +7 -0
- package/dist/writer/index.d.ts.map +1 -0
- package/dist/writer/index.js +32 -0
- package/dist/writer/index.js.map +1 -0
- package/dist/writer/serializer.d.ts +4 -0
- package/dist/writer/serializer.d.ts.map +1 -0
- package/dist/writer/serializer.js +103 -0
- package/dist/writer/serializer.js.map +1 -0
- package/dist/writer/template.d.ts +3 -0
- package/dist/writer/template.d.ts.map +1 -0
- package/dist/writer/template.js +27 -0
- package/dist/writer/template.js.map +1 -0
- package/package.json +59 -7
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Memory Pressure Watcher — periodic V8 heap-usage sampler.
|
|
3
|
+
//
|
|
4
|
+
// Samples process.memoryUsage().heapUsed against v8.getHeapStatistics()
|
|
5
|
+
// heap_size_limit on an interval and emits a degraded-severity log event
|
|
6
|
+
// when the ratio passes a configured threshold. Pure observability — never
|
|
7
|
+
// mutates engine state, never throws, never blocks shutdown.
|
|
8
|
+
//
|
|
9
|
+
// Background: cgroup-capped deployments (e.g. 512 MiB container on Node 24)
|
|
10
|
+
// trip V8's auto-calibrated old-space cap at ~253 MB heap_size_limit. Without
|
|
11
|
+
// this surface, the only signal that a process is approaching the cap is
|
|
12
|
+
// post-mortem (exitCode=134 with "Reached heap limit"). The watcher gives
|
|
13
|
+
// operators a pre-OOM warning + a counter in maad_health.
|
|
14
|
+
//
|
|
15
|
+
// Disabled when intervalMs <= 0 (set MAAD_MEMORY_PRESSURE_INTERVAL_MS=0).
|
|
16
|
+
// Cooldown prevents log spam under sustained pressure — one fire per
|
|
17
|
+
// cooldown window while the ratio stays above threshold; the first sample
|
|
18
|
+
// below threshold re-arms the edge trigger.
|
|
19
|
+
// ============================================================================
|
|
20
|
+
import v8 from 'node:v8';
|
|
21
|
+
import { logger } from '../engine/logger.js';
|
|
22
|
+
const DEFAULT_INTERVAL_MS = 60_000;
|
|
23
|
+
const DEFAULT_THRESHOLD_RATIO = 0.8;
|
|
24
|
+
const DEFAULT_COOLDOWN_MS = 5 * 60_000;
|
|
25
|
+
const defaultSampler = () => {
|
|
26
|
+
const stats = v8.getHeapStatistics();
|
|
27
|
+
return {
|
|
28
|
+
heapUsedBytes: stats.used_heap_size,
|
|
29
|
+
heapCapBytes: stats.heap_size_limit,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const state = {
|
|
33
|
+
intervalMs: 0,
|
|
34
|
+
thresholdRatio: DEFAULT_THRESHOLD_RATIO,
|
|
35
|
+
cooldownMs: DEFAULT_COOLDOWN_MS,
|
|
36
|
+
sampler: defaultSampler,
|
|
37
|
+
now: () => Date.now(),
|
|
38
|
+
timer: null,
|
|
39
|
+
lastSampleAtMs: null,
|
|
40
|
+
heapUsedBytes: null,
|
|
41
|
+
heapCapBytes: null,
|
|
42
|
+
inPressure: false,
|
|
43
|
+
lastPressureAtMs: null,
|
|
44
|
+
lastFireAtMs: null,
|
|
45
|
+
pressureFiresTotal: 0,
|
|
46
|
+
};
|
|
47
|
+
export function readMemoryPressureEnv() {
|
|
48
|
+
const intervalMs = parseNumericEnv(process.env.MAAD_MEMORY_PRESSURE_INTERVAL_MS, DEFAULT_INTERVAL_MS);
|
|
49
|
+
const rawThreshold = parseNumericEnv(process.env.MAAD_MEMORY_PRESSURE_RATIO, DEFAULT_THRESHOLD_RATIO);
|
|
50
|
+
const cooldownMs = parseNumericEnv(process.env.MAAD_MEMORY_PRESSURE_COOLDOWN_MS, DEFAULT_COOLDOWN_MS);
|
|
51
|
+
const thresholdRatio = clamp(rawThreshold, 0, 1);
|
|
52
|
+
return { intervalMs, thresholdRatio, cooldownMs };
|
|
53
|
+
}
|
|
54
|
+
function parseNumericEnv(raw, fallback) {
|
|
55
|
+
if (!raw)
|
|
56
|
+
return fallback;
|
|
57
|
+
const parsed = Number(raw);
|
|
58
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
59
|
+
}
|
|
60
|
+
export function initMemoryPressureWatcher(opts) {
|
|
61
|
+
stopMemoryPressureWatcher();
|
|
62
|
+
state.intervalMs = opts.intervalMs;
|
|
63
|
+
state.thresholdRatio = clamp(opts.thresholdRatio, 0, 1);
|
|
64
|
+
state.cooldownMs = Math.max(0, opts.cooldownMs);
|
|
65
|
+
state.sampler = opts.sampler ?? defaultSampler;
|
|
66
|
+
state.now = opts.now ?? (() => Date.now());
|
|
67
|
+
state.lastSampleAtMs = null;
|
|
68
|
+
state.heapUsedBytes = null;
|
|
69
|
+
state.heapCapBytes = null;
|
|
70
|
+
state.inPressure = false;
|
|
71
|
+
state.lastPressureAtMs = null;
|
|
72
|
+
state.lastFireAtMs = null;
|
|
73
|
+
state.pressureFiresTotal = 0;
|
|
74
|
+
if (opts.intervalMs <= 0)
|
|
75
|
+
return;
|
|
76
|
+
const timer = setInterval(sampleOnce, opts.intervalMs);
|
|
77
|
+
timer.unref();
|
|
78
|
+
state.timer = timer;
|
|
79
|
+
}
|
|
80
|
+
export function stopMemoryPressureWatcher() {
|
|
81
|
+
if (state.timer) {
|
|
82
|
+
clearInterval(state.timer);
|
|
83
|
+
state.timer = null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Run one sample. Public so tests and shutdown paths can probe without
|
|
88
|
+
* waiting for the interval to fire. Never throws.
|
|
89
|
+
*/
|
|
90
|
+
export function sampleOnce() {
|
|
91
|
+
let sample;
|
|
92
|
+
try {
|
|
93
|
+
sample = state.sampler();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
const nowMs = state.now();
|
|
99
|
+
state.lastSampleAtMs = nowMs;
|
|
100
|
+
state.heapUsedBytes = sample.heapUsedBytes;
|
|
101
|
+
state.heapCapBytes = sample.heapCapBytes;
|
|
102
|
+
if (sample.heapCapBytes <= 0)
|
|
103
|
+
return;
|
|
104
|
+
const ratio = sample.heapUsedBytes / sample.heapCapBytes;
|
|
105
|
+
if (ratio >= state.thresholdRatio) {
|
|
106
|
+
const cooldownPassed = state.lastFireAtMs === null
|
|
107
|
+
|| (nowMs - state.lastFireAtMs) >= state.cooldownMs;
|
|
108
|
+
const edgeTrigger = !state.inPressure;
|
|
109
|
+
if (edgeTrigger || cooldownPassed) {
|
|
110
|
+
logger.degraded('engine', 'memory_pressure', `V8 heap at ${formatPct(ratio)}% of cap (${bytesToMb(sample.heapUsedBytes)}MB / ${bytesToMb(sample.heapCapBytes)}MB)`, {
|
|
111
|
+
heap_used_mb: bytesToMb(sample.heapUsedBytes),
|
|
112
|
+
heap_cap_mb: bytesToMb(sample.heapCapBytes),
|
|
113
|
+
ratio: round3(ratio),
|
|
114
|
+
threshold_ratio: state.thresholdRatio,
|
|
115
|
+
edge: edgeTrigger,
|
|
116
|
+
});
|
|
117
|
+
state.pressureFiresTotal++;
|
|
118
|
+
state.lastFireAtMs = nowMs;
|
|
119
|
+
state.lastPressureAtMs = nowMs;
|
|
120
|
+
}
|
|
121
|
+
state.inPressure = true;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
state.inPressure = false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export function getMemoryPressureSnapshot() {
|
|
128
|
+
const heapUsed = state.heapUsedBytes;
|
|
129
|
+
const heapCap = state.heapCapBytes;
|
|
130
|
+
const ratio = heapUsed !== null && heapCap !== null && heapCap > 0
|
|
131
|
+
? round3(heapUsed / heapCap) : null;
|
|
132
|
+
return {
|
|
133
|
+
enabled: state.intervalMs > 0,
|
|
134
|
+
intervalMs: state.intervalMs,
|
|
135
|
+
thresholdRatio: state.thresholdRatio,
|
|
136
|
+
lastSampleAt: state.lastSampleAtMs !== null ? new Date(state.lastSampleAtMs).toISOString() : null,
|
|
137
|
+
heapUsedMb: heapUsed !== null ? bytesToMb(heapUsed) : null,
|
|
138
|
+
heapCapMb: heapCap !== null ? bytesToMb(heapCap) : null,
|
|
139
|
+
ratio,
|
|
140
|
+
inPressure: state.inPressure,
|
|
141
|
+
lastPressureAt: state.lastPressureAtMs !== null ? new Date(state.lastPressureAtMs).toISOString() : null,
|
|
142
|
+
pressureFiresTotal: state.pressureFiresTotal,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Test hook — resets module state. Never call from production code.
|
|
147
|
+
*/
|
|
148
|
+
export function __resetMemoryPressureForTests() {
|
|
149
|
+
stopMemoryPressureWatcher();
|
|
150
|
+
state.intervalMs = 0;
|
|
151
|
+
state.thresholdRatio = DEFAULT_THRESHOLD_RATIO;
|
|
152
|
+
state.cooldownMs = DEFAULT_COOLDOWN_MS;
|
|
153
|
+
state.sampler = defaultSampler;
|
|
154
|
+
state.now = () => Date.now();
|
|
155
|
+
state.lastSampleAtMs = null;
|
|
156
|
+
state.heapUsedBytes = null;
|
|
157
|
+
state.heapCapBytes = null;
|
|
158
|
+
state.inPressure = false;
|
|
159
|
+
state.lastPressureAtMs = null;
|
|
160
|
+
state.lastFireAtMs = null;
|
|
161
|
+
state.pressureFiresTotal = 0;
|
|
162
|
+
}
|
|
163
|
+
function bytesToMb(b) {
|
|
164
|
+
return Math.round((b / 1024 / 1024) * 10) / 10;
|
|
165
|
+
}
|
|
166
|
+
function round3(n) {
|
|
167
|
+
return Math.round(n * 1000) / 1000;
|
|
168
|
+
}
|
|
169
|
+
function formatPct(ratio) {
|
|
170
|
+
return (ratio * 100).toFixed(1);
|
|
171
|
+
}
|
|
172
|
+
function clamp(n, lo, hi) {
|
|
173
|
+
if (n < lo)
|
|
174
|
+
return lo;
|
|
175
|
+
if (n > hi)
|
|
176
|
+
return hi;
|
|
177
|
+
return n;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=memory-pressure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-pressure.js","sourceRoot":"","sources":["../../src/mcp/memory-pressure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { InstanceCtx } from './ctx.js';
|
|
2
|
+
/**
|
|
3
|
+
* Event shape emitted on durable writes. Used both as the payload mapped into
|
|
4
|
+
* MCP's `notifications/resources/updated` and as the match target for
|
|
5
|
+
* per-session filters.
|
|
6
|
+
*/
|
|
7
|
+
export interface ChangeEvent {
|
|
8
|
+
action: 'create' | 'update' | 'delete';
|
|
9
|
+
docId: string;
|
|
10
|
+
docType: string;
|
|
11
|
+
project: string;
|
|
12
|
+
updatedAt: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Callback that pushes a ChangeEvent to a single MCP session's client. The
|
|
16
|
+
* transport layer (HTTP or stdio) registers this closure when it builds the
|
|
17
|
+
* per-session McpServer. Failures are logged but never thrown — a broken
|
|
18
|
+
* notifier channel must not kill the write that triggered it.
|
|
19
|
+
*/
|
|
20
|
+
export type Notifier = (event: ChangeEvent) => Promise<void>;
|
|
21
|
+
/**
|
|
22
|
+
* Register a notifier for a session. Called by the transport once the
|
|
23
|
+
* per-session McpServer is connected and ready to emit. Overwrites any
|
|
24
|
+
* prior registration for the same sessionId (transport reconnect path).
|
|
25
|
+
*/
|
|
26
|
+
export declare function registerNotifier(sessionId: string, fn: Notifier): void;
|
|
27
|
+
/**
|
|
28
|
+
* Remove a notifier. Called when a session is destroyed (SessionRegistry
|
|
29
|
+
* close handler fans this out). Safe to call with an unknown sessionId.
|
|
30
|
+
*/
|
|
31
|
+
export declare function unregisterNotifier(sessionId: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* Current count of registered notifiers. Used by maad_health telemetry and
|
|
34
|
+
* by zero-overhead fast-path detection in `notifyWrite`.
|
|
35
|
+
*/
|
|
36
|
+
export declare function notifierCount(): number;
|
|
37
|
+
/**
|
|
38
|
+
* Test hook — drops every registered notifier. Production code never calls
|
|
39
|
+
* this; vitest suites that reuse the process need it between cases.
|
|
40
|
+
*/
|
|
41
|
+
export declare function __resetNotifiers(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Fan-out entry point called by MCP write tool handlers after a successful
|
|
44
|
+
* durable commit. Iterates sessions with subscriptions, matches the filter,
|
|
45
|
+
* and invokes each session's notifier. Zero overhead when no session has a
|
|
46
|
+
* subscription (the count check bypasses the iteration).
|
|
47
|
+
*
|
|
48
|
+
* Caller MUST only invoke this when `writeDurable === true` on the engine
|
|
49
|
+
* result — the durability gate is upstream, not here. Delete operations
|
|
50
|
+
* should pass `action: 'delete'` and the docType recorded before deletion.
|
|
51
|
+
*/
|
|
52
|
+
export declare function notifyWrite(ctx: InstanceCtx, event: ChangeEvent): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* 0.6.12 — Inventory of active subscriptions across an instance. Produced
|
|
55
|
+
* by `maad_subscriptions` (admin-only). Extracted here so the aggregation
|
|
56
|
+
* logic is unit-testable without spinning up a full MCP server.
|
|
57
|
+
*
|
|
58
|
+
* `byProject` reflects "who would receive an event for project X": single-mode
|
|
59
|
+
* sessions bin under their activeProject; multi-mode sessions without an
|
|
60
|
+
* explicit project filter bin under every whitelisted project; sessions with
|
|
61
|
+
* an explicit filter bin only under that project.
|
|
62
|
+
*
|
|
63
|
+
* `byDocType` uses `*` as the any-type bucket (subscribers that omitted the
|
|
64
|
+
* docTypes filter) so admins can tell at a glance how many "firehose" vs
|
|
65
|
+
* "type-narrowed" subscribers are active.
|
|
66
|
+
*/
|
|
67
|
+
export interface SubscriptionInventoryEntry {
|
|
68
|
+
sessionId: string;
|
|
69
|
+
mode: string | null;
|
|
70
|
+
activeProject: string | null;
|
|
71
|
+
whitelist: string[] | null;
|
|
72
|
+
subscription: {
|
|
73
|
+
docTypes: string[] | null;
|
|
74
|
+
project: string | null;
|
|
75
|
+
createdAt: string;
|
|
76
|
+
};
|
|
77
|
+
bindingSource: string | null;
|
|
78
|
+
lastActivityAt: string;
|
|
79
|
+
}
|
|
80
|
+
export interface SubscriptionInventory {
|
|
81
|
+
totalSubscriptions: number;
|
|
82
|
+
subscriptions: SubscriptionInventoryEntry[];
|
|
83
|
+
byProject: Record<string, number>;
|
|
84
|
+
byDocType: Record<string, number>;
|
|
85
|
+
}
|
|
86
|
+
export declare function collectSubscriptions(sessions: InstanceCtx['sessions']): SubscriptionInventory;
|
|
87
|
+
//# sourceMappingURL=notifications.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.d.ts","sourceRoot":"","sources":["../../src/mcp/notifications.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI5C;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAI7D;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI,CAEtE;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAE1D;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAwBD;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBrF;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,0BAA0B;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAC3B,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IACvF,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,0BAA0B,EAAE,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,WAAW,CAAC,UAAU,CAAC,GAAG,qBAAqB,CA+C7F"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Live notifications — 0.6.11 (fup-2026-035)
|
|
3
|
+
//
|
|
4
|
+
// Per-session notifier registry + filtered fan-out for `maad_subscribe`. Each
|
|
5
|
+
// connected MCP session registers one notifier closure that wraps its
|
|
6
|
+
// McpServer's `sendResourceUpdated`. On a durable write (CommitOutcome =
|
|
7
|
+
// 'committed'), the MCP tool handler calls `notifyWrite(ctx, event)`, which
|
|
8
|
+
// walks every session with an active subscription, matches the filter, and
|
|
9
|
+
// fires the notifier.
|
|
10
|
+
//
|
|
11
|
+
// Durability gate: the write-tool handler skips this call when
|
|
12
|
+
// `writeDurable === false` or the underlying commit was a noop. Subscribers
|
|
13
|
+
// never see events for non-durable or no-op writes — the whole point of
|
|
14
|
+
// shipping 0.6.10 durability first.
|
|
15
|
+
//
|
|
16
|
+
// Zero-overhead path: `notifyWrite` early-returns when no session has a
|
|
17
|
+
// subscription. Cheap Map iteration with a single boolean check per session.
|
|
18
|
+
// Sessions without subscriptions pay nothing for the notification path.
|
|
19
|
+
// ============================================================================
|
|
20
|
+
import { logger } from '../engine/logger.js';
|
|
21
|
+
const notifiers = new Map();
|
|
22
|
+
/**
|
|
23
|
+
* Register a notifier for a session. Called by the transport once the
|
|
24
|
+
* per-session McpServer is connected and ready to emit. Overwrites any
|
|
25
|
+
* prior registration for the same sessionId (transport reconnect path).
|
|
26
|
+
*/
|
|
27
|
+
export function registerNotifier(sessionId, fn) {
|
|
28
|
+
notifiers.set(sessionId, fn);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Remove a notifier. Called when a session is destroyed (SessionRegistry
|
|
32
|
+
* close handler fans this out). Safe to call with an unknown sessionId.
|
|
33
|
+
*/
|
|
34
|
+
export function unregisterNotifier(sessionId) {
|
|
35
|
+
notifiers.delete(sessionId);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Current count of registered notifiers. Used by maad_health telemetry and
|
|
39
|
+
* by zero-overhead fast-path detection in `notifyWrite`.
|
|
40
|
+
*/
|
|
41
|
+
export function notifierCount() {
|
|
42
|
+
return notifiers.size;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Test hook — drops every registered notifier. Production code never calls
|
|
46
|
+
* this; vitest suites that reuse the process need it between cases.
|
|
47
|
+
*/
|
|
48
|
+
export function __resetNotifiers() {
|
|
49
|
+
notifiers.clear();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Does this session's subscription filter match the event? Null filter
|
|
53
|
+
* fields mean "accept any." In single-mode sessions, if the subscription's
|
|
54
|
+
* `project` is null, it implicitly matches the session's activeProject.
|
|
55
|
+
* In multi-mode, null matches any project in the whitelist.
|
|
56
|
+
*/
|
|
57
|
+
function matchesSubscription(state, event) {
|
|
58
|
+
const sub = state.subscription;
|
|
59
|
+
if (!sub)
|
|
60
|
+
return false;
|
|
61
|
+
if (sub.docTypes !== null && !sub.docTypes.includes(event.docType))
|
|
62
|
+
return false;
|
|
63
|
+
if (sub.project !== null) {
|
|
64
|
+
if (sub.project !== event.project)
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Null project: match the session's visible project scope.
|
|
69
|
+
if (state.mode === 'single' && state.activeProject !== event.project)
|
|
70
|
+
return false;
|
|
71
|
+
if (state.mode === 'multi' && !(state.whitelist ?? []).includes(event.project))
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Fan-out entry point called by MCP write tool handlers after a successful
|
|
78
|
+
* durable commit. Iterates sessions with subscriptions, matches the filter,
|
|
79
|
+
* and invokes each session's notifier. Zero overhead when no session has a
|
|
80
|
+
* subscription (the count check bypasses the iteration).
|
|
81
|
+
*
|
|
82
|
+
* Caller MUST only invoke this when `writeDurable === true` on the engine
|
|
83
|
+
* result — the durability gate is upstream, not here. Delete operations
|
|
84
|
+
* should pass `action: 'delete'` and the docType recorded before deletion.
|
|
85
|
+
*/
|
|
86
|
+
export async function notifyWrite(ctx, event) {
|
|
87
|
+
if (notifiers.size === 0)
|
|
88
|
+
return; // fast path: nobody listening
|
|
89
|
+
for (const state of ctx.sessions.snapshot()) {
|
|
90
|
+
if (!matchesSubscription(state, event))
|
|
91
|
+
continue;
|
|
92
|
+
const fn = notifiers.get(state.sessionId);
|
|
93
|
+
if (!fn)
|
|
94
|
+
continue;
|
|
95
|
+
try {
|
|
96
|
+
await fn(event);
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
// Notifier delivery failure is non-fatal to the write. Log so
|
|
100
|
+
// operators can spot broken transports (disconnected SSE, stale
|
|
101
|
+
// McpServer) — but never propagate the error back to the writer.
|
|
102
|
+
logger.bestEffort('notify', 'deliver', `Notifier failed for session ${state.sessionId}: ${e instanceof Error ? e.message : String(e)}`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function collectSubscriptions(sessions) {
|
|
107
|
+
const subscriptions = [];
|
|
108
|
+
const byProject = {};
|
|
109
|
+
const byDocType = {};
|
|
110
|
+
for (const state of sessions.snapshot()) {
|
|
111
|
+
if (!state.subscription)
|
|
112
|
+
continue;
|
|
113
|
+
subscriptions.push({
|
|
114
|
+
sessionId: state.sessionId,
|
|
115
|
+
mode: state.mode,
|
|
116
|
+
activeProject: state.activeProject ?? null,
|
|
117
|
+
whitelist: state.whitelist ?? null,
|
|
118
|
+
subscription: {
|
|
119
|
+
docTypes: state.subscription.docTypes,
|
|
120
|
+
project: state.subscription.project,
|
|
121
|
+
createdAt: state.subscription.createdAt.toISOString(),
|
|
122
|
+
},
|
|
123
|
+
bindingSource: state.bindingSource,
|
|
124
|
+
lastActivityAt: state.lastActivityAt.toISOString(),
|
|
125
|
+
});
|
|
126
|
+
const explicitProject = state.subscription.project;
|
|
127
|
+
if (explicitProject !== null) {
|
|
128
|
+
byProject[explicitProject] = (byProject[explicitProject] ?? 0) + 1;
|
|
129
|
+
}
|
|
130
|
+
else if (state.mode === 'single' && state.activeProject) {
|
|
131
|
+
byProject[state.activeProject] = (byProject[state.activeProject] ?? 0) + 1;
|
|
132
|
+
}
|
|
133
|
+
else if (state.mode === 'multi' && state.whitelist) {
|
|
134
|
+
for (const p of state.whitelist) {
|
|
135
|
+
byProject[p] = (byProject[p] ?? 0) + 1;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (state.subscription.docTypes === null) {
|
|
139
|
+
byDocType['*'] = (byDocType['*'] ?? 0) + 1;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
for (const t of state.subscription.docTypes) {
|
|
143
|
+
byDocType[t] = (byDocType[t] ?? 0) + 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
totalSubscriptions: subscriptions.length,
|
|
149
|
+
subscriptions,
|
|
150
|
+
byProject,
|
|
151
|
+
byDocType,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=notifications.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"notifications.js","sourceRoot":"","sources":["../../src/mcp/notifications.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { DocId } from '../types.js';
|
|
2
|
+
import type { DocumentMatch } from '../types.js';
|
|
3
|
+
import type { GetResult, GetFullResult } from '../engine/types.js';
|
|
4
|
+
import type { Result } from '../errors.js';
|
|
5
|
+
export type QueryDepth = 'hot' | 'cold' | 'full';
|
|
6
|
+
export interface HydrationEngine {
|
|
7
|
+
getDocument(id: DocId, depth: 'cold'): Promise<Result<GetResult>>;
|
|
8
|
+
getDocumentFull(id: DocId): Promise<Result<GetFullResult>>;
|
|
9
|
+
}
|
|
10
|
+
export interface HydrationOptions {
|
|
11
|
+
depth: QueryDepth;
|
|
12
|
+
depthMaxResults?: number;
|
|
13
|
+
}
|
|
14
|
+
export interface HydratedRow extends DocumentMatch {
|
|
15
|
+
body?: string;
|
|
16
|
+
composite?: GetFullResult;
|
|
17
|
+
_hydrationError?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface HydrationOutcome {
|
|
20
|
+
rows: HydratedRow[];
|
|
21
|
+
meta: {
|
|
22
|
+
depth: QueryDepth;
|
|
23
|
+
hydrated: number;
|
|
24
|
+
capped?: boolean;
|
|
25
|
+
} | null;
|
|
26
|
+
}
|
|
27
|
+
export declare function hydrateQueryRows(engine: HydrationEngine, rows: DocumentMatch[], opts: HydrationOptions): Promise<HydrationOutcome>;
|
|
28
|
+
//# sourceMappingURL=query-depth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-depth.d.ts","sourceRoot":"","sources":["../../src/mcp/query-depth.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IAClE,eAAe,CAAC,EAAE,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,WAAY,SAAQ,aAAa;IAChD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,EAAE,CAAC;IACpB,IAAI,EAAE;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;CACxE;AAKD,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,aAAa,EAAE,EACrB,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,gBAAgB,CAAC,CA0B3B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// 0.7.3 (fup-2026-079[a]) — maad_query depth hydration helper.
|
|
3
|
+
//
|
|
4
|
+
// Composite that kills the query-then-N-gets agent pattern. After the engine
|
|
5
|
+
// finds matching pointer rows, the handler optionally hydrates each row with
|
|
6
|
+
// body content (depth=cold) or full composite (depth=full).
|
|
7
|
+
//
|
|
8
|
+
// Sequential per-row to keep memory bounded and to mirror per-doc error
|
|
9
|
+
// surfaces; one failure does not abort the batch — failed rows omit
|
|
10
|
+
// body/composite and stamp `_hydrationError` so callers see the partial.
|
|
11
|
+
//
|
|
12
|
+
// Hard cap on hydration count (default 50, max 100) keeps response payloads
|
|
13
|
+
// from blowing past the response-size guard. Beyond cap, remaining rows
|
|
14
|
+
// return at hot depth.
|
|
15
|
+
// ============================================================================
|
|
16
|
+
const HARD_CAP = 100;
|
|
17
|
+
const DEFAULT_CAP = 50;
|
|
18
|
+
export async function hydrateQueryRows(engine, rows, opts) {
|
|
19
|
+
if (opts.depth === 'hot') {
|
|
20
|
+
return { rows, meta: null };
|
|
21
|
+
}
|
|
22
|
+
const requested = opts.depthMaxResults ?? DEFAULT_CAP;
|
|
23
|
+
const cap = Math.min(Math.max(1, requested), HARD_CAP);
|
|
24
|
+
const toHydrate = Math.min(rows.length, cap);
|
|
25
|
+
const hydrated = await Promise.all(rows.slice(0, toHydrate).map(async (row) => {
|
|
26
|
+
if (opts.depth === 'cold') {
|
|
27
|
+
const r = await engine.getDocument(row.docId, 'cold');
|
|
28
|
+
if (r.ok)
|
|
29
|
+
return { ...row, body: r.value.body ?? '' };
|
|
30
|
+
return { ...row, _hydrationError: r.errors[0]?.code ?? 'UNKNOWN' };
|
|
31
|
+
}
|
|
32
|
+
const r = await engine.getDocumentFull(row.docId);
|
|
33
|
+
if (r.ok)
|
|
34
|
+
return { ...row, composite: r.value };
|
|
35
|
+
return { ...row, _hydrationError: r.errors[0]?.code ?? 'UNKNOWN' };
|
|
36
|
+
}));
|
|
37
|
+
const merged = [...hydrated, ...rows.slice(toHydrate)];
|
|
38
|
+
const meta = { depth: opts.depth, hydrated: toHydrate };
|
|
39
|
+
if (rows.length > cap)
|
|
40
|
+
meta.capped = true;
|
|
41
|
+
return { rows: merged, meta };
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=query-depth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-depth.js","sourceRoot":"","sources":["../../src/mcp/query-depth.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,+DAA+D;AAC/D,EAAE;AACF,6EAA6E;AAC7E,6EAA6E;AAC7E,4DAA4D;AAC5D,EAAE;AACF,wEAAwE;AACxE,oEAAoE;AACpE,yEAAyE;AACzE,EAAE;AACF,4EAA4E;AAC5E,wEAAwE;AACxE,uBAAuB;AACvB,+EAA+E;AA8B/E,MAAM,QAAQ,GAAG,GAAG,CAAC;AACrB,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAuB,EACvB,IAAqB,EACrB,IAAsB;IAEtB,IAAI,IAAI,CAAC,KAAK,KAAK,KAAK,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC9B,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,IAAI,WAAW,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAkB,MAAM,OAAO,CAAC,GAAG,CAC/C,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAwB,EAAE;QAC/D,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1B,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YACtD,IAAI,CAAC,CAAC,EAAE;gBAAE,OAAO,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,CAAC;YACtD,OAAO,EAAE,GAAG,GAAG,EAAE,eAAe,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC;QACrE,CAAC;QACD,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClD,IAAI,CAAC,CAAC,EAAE;YAAE,OAAO,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QAChD,OAAO,EAAE,GAAG,GAAG,EAAE,eAAe,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,IAAI,SAAS,EAAE,CAAC;IACrE,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,GAAkB,CAAC,GAAG,QAAQ,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;IACtE,MAAM,IAAI,GAA6B,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;IAClF,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;QAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface RateLimitConfig {
|
|
2
|
+
writesPerSec: number;
|
|
3
|
+
writesPerMin: number;
|
|
4
|
+
concurrent: number;
|
|
5
|
+
payloadBytes: number;
|
|
6
|
+
disabled: boolean;
|
|
7
|
+
now: () => number;
|
|
8
|
+
}
|
|
9
|
+
export declare function readRateLimitEnv(): Partial<RateLimitConfig>;
|
|
10
|
+
export type RateLimitReason = 'writes_per_sec' | 'writes_per_min' | 'concurrent' | 'payload_too_large';
|
|
11
|
+
export interface RateLimitRejection {
|
|
12
|
+
reason: RateLimitReason;
|
|
13
|
+
limit: number;
|
|
14
|
+
retryAfterMs: number | null;
|
|
15
|
+
}
|
|
16
|
+
export declare function isMutatingTool(toolName: string): boolean;
|
|
17
|
+
export declare class SessionRateLimiter {
|
|
18
|
+
private config;
|
|
19
|
+
private writesSec;
|
|
20
|
+
private writesMin;
|
|
21
|
+
private inFlight;
|
|
22
|
+
constructor(opts?: Partial<RateLimitConfig>);
|
|
23
|
+
/**
|
|
24
|
+
* Per-request payload size gate. Returns null on success or a rejection
|
|
25
|
+
* describing the breach. Runs before anything else — oversize args waste
|
|
26
|
+
* compute.
|
|
27
|
+
*/
|
|
28
|
+
checkPayloadSize(bytes: number): RateLimitRejection | null;
|
|
29
|
+
/**
|
|
30
|
+
* Acquire a concurrent-in-flight slot. Returns { release } on success or
|
|
31
|
+
* a rejection. ALL tool calls (reads and writes) use this cap.
|
|
32
|
+
*/
|
|
33
|
+
tryAcquireConcurrent(sessionId: string): {
|
|
34
|
+
ok: true;
|
|
35
|
+
release: () => void;
|
|
36
|
+
} | {
|
|
37
|
+
ok: false;
|
|
38
|
+
rejection: RateLimitRejection;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Consume one token each from writes/sec and writes/min. Only called for
|
|
42
|
+
* mutating tools. Returns null on success or a rejection identifying which
|
|
43
|
+
* bucket failed.
|
|
44
|
+
*/
|
|
45
|
+
tryAcquireWrite(sessionId: string): RateLimitRejection | null;
|
|
46
|
+
/**
|
|
47
|
+
* Total in-flight requests across all sessions. Used by the H7 graceful
|
|
48
|
+
* shutdown drain loop.
|
|
49
|
+
*/
|
|
50
|
+
totalInFlight(): number;
|
|
51
|
+
/** Discard all per-session state for `sessionId`. Called on disconnect. */
|
|
52
|
+
disposeSession(sessionId: string): void;
|
|
53
|
+
/** Test helper — peek at in-flight count for a single session. */
|
|
54
|
+
inFlightFor(sessionId: string): number;
|
|
55
|
+
/** Test helper — peek at current config (for assertions). */
|
|
56
|
+
getConfig(): Readonly<RateLimitConfig>;
|
|
57
|
+
}
|
|
58
|
+
export declare function initRateLimiter(opts: Partial<RateLimitConfig>): void;
|
|
59
|
+
export declare function getRateLimiter(): SessionRateLimiter;
|
|
60
|
+
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/mcp/rate-limit.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,eAAe;IAC9B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,GAAG,EAAE,MAAM,MAAM,CAAC;CACnB;AAUD,wBAAgB,gBAAgB,IAAI,OAAO,CAAC,eAAe,CAAC,CAU3D;AAID,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,YAAY,GAAG,mBAAmB,CAAC;AAEvG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7B;AAeD,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAExD;AAID,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,SAAS,CAAkC;IACnD,OAAO,CAAC,QAAQ,CAA6B;gBAEjC,IAAI,GAAE,OAAO,CAAC,eAAe,CAAM;IAQ/C;;;;OAIG;IACH,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAU1D;;;OAGG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,IAAI,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,SAAS,EAAE,kBAAkB,CAAA;KAAE;IAqBzH;;;;OAIG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAsC7D;;;OAGG;IACH,aAAa,IAAI,MAAM;IAMvB,2EAA2E;IAC3E,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAMvC,kEAAkE;IAClE,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAItC,6DAA6D;IAC7D,SAAS,IAAI,QAAQ,CAAC,eAAe,CAAC;CAGvC;AAMD,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,CAAC,eAAe,CAAC,GAAG,IAAI,CAEpE;AAED,wBAAgB,cAAc,IAAI,kBAAkB,CAEnD"}
|