@jack200714/mafw 4.5.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/.opencode/mafw/.backup-v61/parametric/base-skill-manifest.yaml +2 -0
- package/.opencode/mafw/STATUS.md +6 -0
- package/.opencode/mafw/ledger.md +20 -0
- package/.opencode/mafw/memory/.harmonic_index.json +28 -0
- package/.opencode/mafw/memory/.review_queue.json +1 -0
- package/.opencode/mafw/memory/tier3/parametric.json +13 -0
- package/.opencode/mafw/memory/tier3/test-goal.json +19 -0
- package/.opencode/mafw/memory-index.json +6 -0
- package/.opencode/mafw/parametric/base-skill-manifest.yaml +2 -0
- package/.opencode/mafw/waves.json +4 -0
- package/.opencode/opencode.json +3 -0
- package/.opencode/plugins/mafw-plugin.ts +8 -0
- package/.opencode/skills/banner-design/SKILL.md +196 -0
- package/.opencode/skills/banner-design/references/banner-sizes-and-styles.md +118 -0
- package/.opencode/skills/brand/SKILL.md +97 -0
- package/.opencode/skills/brand/references/approval-checklist.md +169 -0
- package/.opencode/skills/brand/references/asset-organization.md +157 -0
- package/.opencode/skills/brand/references/brand-guideline-template.md +140 -0
- package/.opencode/skills/brand/references/color-palette-management.md +186 -0
- package/.opencode/skills/brand/references/consistency-checklist.md +94 -0
- package/.opencode/skills/brand/references/logo-usage-rules.md +185 -0
- package/.opencode/skills/brand/references/messaging-framework.md +85 -0
- package/.opencode/skills/brand/references/typography-specifications.md +214 -0
- package/.opencode/skills/brand/references/update.md +118 -0
- package/.opencode/skills/brand/references/visual-identity.md +96 -0
- package/.opencode/skills/brand/references/voice-framework.md +88 -0
- package/.opencode/skills/brand/scripts/extract-colors.cjs +341 -0
- package/.opencode/skills/brand/scripts/inject-brand-context.cjs +349 -0
- package/.opencode/skills/brand/scripts/sync-brand-to-tokens.cjs +248 -0
- package/.opencode/skills/brand/scripts/tests/test_sync_brand_to_tokens.py +52 -0
- package/.opencode/skills/brand/scripts/validate-asset.cjs +387 -0
- package/.opencode/skills/brand/templates/brand-guidelines-starter.md +275 -0
- package/.opencode/skills/design/SKILL.md +313 -0
- package/.opencode/skills/design/data/cip/deliverables.csv +51 -0
- package/.opencode/skills/design/data/cip/industries.csv +21 -0
- package/.opencode/skills/design/data/cip/mockup-contexts.csv +21 -0
- package/.opencode/skills/design/data/cip/styles.csv +21 -0
- package/.opencode/skills/design/data/icon/styles.csv +16 -0
- package/.opencode/skills/design/data/logo/colors.csv +56 -0
- package/.opencode/skills/design/data/logo/industries.csv +56 -0
- package/.opencode/skills/design/data/logo/styles.csv +56 -0
- package/.opencode/skills/design/references/banner-sizes-and-styles.md +118 -0
- package/.opencode/skills/design/references/cip-deliverable-guide.md +95 -0
- package/.opencode/skills/design/references/cip-design.md +121 -0
- package/.opencode/skills/design/references/cip-prompt-engineering.md +84 -0
- package/.opencode/skills/design/references/cip-style-guide.md +68 -0
- package/.opencode/skills/design/references/design-routing.md +207 -0
- package/.opencode/skills/design/references/icon-design.md +122 -0
- package/.opencode/skills/design/references/logo-color-psychology.md +101 -0
- package/.opencode/skills/design/references/logo-design.md +92 -0
- package/.opencode/skills/design/references/logo-prompt-engineering.md +158 -0
- package/.opencode/skills/design/references/logo-style-guide.md +109 -0
- package/.opencode/skills/design/references/slides-copywriting-formulas.md +84 -0
- package/.opencode/skills/design/references/slides-create.md +4 -0
- package/.opencode/skills/design/references/slides-html-template.md +295 -0
- package/.opencode/skills/design/references/slides-layout-patterns.md +137 -0
- package/.opencode/skills/design/references/slides-strategies.md +94 -0
- package/.opencode/skills/design/references/slides.md +42 -0
- package/.opencode/skills/design/references/social-photos-design.md +329 -0
- package/.opencode/skills/design/scripts/cip/core.py +215 -0
- package/.opencode/skills/design/scripts/cip/generate.py +484 -0
- package/.opencode/skills/design/scripts/cip/render-html.py +424 -0
- package/.opencode/skills/design/scripts/cip/search.py +127 -0
- package/.opencode/skills/design/scripts/icon/generate.py +487 -0
- package/.opencode/skills/design/scripts/logo/core.py +175 -0
- package/.opencode/skills/design/scripts/logo/generate.py +362 -0
- package/.opencode/skills/design/scripts/logo/search.py +114 -0
- package/.opencode/skills/design-system/SKILL.md +244 -0
- package/.opencode/skills/design-system/data/slide-backgrounds.csv +11 -0
- package/.opencode/skills/design-system/data/slide-charts.csv +26 -0
- package/.opencode/skills/design-system/data/slide-color-logic.csv +14 -0
- package/.opencode/skills/design-system/data/slide-copy.csv +26 -0
- package/.opencode/skills/design-system/data/slide-layout-logic.csv +16 -0
- package/.opencode/skills/design-system/data/slide-layouts.csv +26 -0
- package/.opencode/skills/design-system/data/slide-strategies.csv +16 -0
- package/.opencode/skills/design-system/data/slide-typography.csv +15 -0
- package/.opencode/skills/design-system/references/component-specs.md +236 -0
- package/.opencode/skills/design-system/references/component-tokens.md +214 -0
- package/.opencode/skills/design-system/references/primitive-tokens.md +203 -0
- package/.opencode/skills/design-system/references/semantic-tokens.md +215 -0
- package/.opencode/skills/design-system/references/states-and-variants.md +241 -0
- package/.opencode/skills/design-system/references/tailwind-integration.md +251 -0
- package/.opencode/skills/design-system/references/token-architecture.md +224 -0
- package/.opencode/skills/design-system/scripts/embed-tokens.cjs +99 -0
- package/.opencode/skills/design-system/scripts/fetch-background.py +317 -0
- package/.opencode/skills/design-system/scripts/generate-slide.py +770 -0
- package/.opencode/skills/design-system/scripts/generate-tokens.cjs +205 -0
- package/.opencode/skills/design-system/scripts/html-token-validator.py +327 -0
- package/.opencode/skills/design-system/scripts/search-slides.py +218 -0
- package/.opencode/skills/design-system/scripts/slide-token-validator.py +35 -0
- package/.opencode/skills/design-system/scripts/slide_search_core.py +453 -0
- package/.opencode/skills/design-system/scripts/tests/test_validate_tokens.py +48 -0
- package/.opencode/skills/design-system/scripts/validate-tokens.cjs +246 -0
- package/.opencode/skills/design-system/templates/design-tokens-starter.json +143 -0
- package/.opencode/skills/frontend-design/LICENSE.txt +21 -0
- package/.opencode/skills/frontend-design/SKILL.md +115 -0
- package/.opencode/skills/mafw-automation-interview/SKILL.md +43 -0
- package/.opencode/skills/mafw-cli-scanner/SKILL.md +37 -0
- package/.opencode/skills/mafw-compression-verifier/SKILL.md +52 -0
- package/.opencode/skills/mafw-desktop-inspector/SKILL.md +170 -0
- package/.opencode/skills/mafw-execute/SKILL.md +62 -0
- package/.opencode/skills/mafw-gateway-restart/SKILL.md +87 -0
- package/.opencode/skills/mafw-github-scanner/SKILL.md +38 -0
- package/.opencode/skills/mafw-goal/SKILL.md +76 -0
- package/.opencode/skills/mafw-interview/SKILL.md +68 -0
- package/.opencode/skills/mafw-memory-extractor/SKILL.md +65 -0
- package/.opencode/skills/mafw-plan/SKILL.md +58 -0
- package/.opencode/skills/mafw-review/SKILL.md +85 -0
- package/.opencode/skills/runtime-plugin-authoring/SKILL.md +791 -0
- package/.opencode/skills/slides/SKILL.md +40 -0
- package/.opencode/skills/slides/references/copywriting-formulas.md +84 -0
- package/.opencode/skills/slides/references/create.md +4 -0
- package/.opencode/skills/slides/references/html-template.md +295 -0
- package/.opencode/skills/slides/references/layout-patterns.md +137 -0
- package/.opencode/skills/slides/references/slide-strategies.md +94 -0
- package/.opencode/skills/ui-styling/LICENSE.txt +202 -0
- package/.opencode/skills/ui-styling/SKILL.md +324 -0
- package/.opencode/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/.opencode/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/.opencode/skills/ui-styling/references/shadcn-components.md +424 -0
- package/.opencode/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/.opencode/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/.opencode/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/.opencode/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/.opencode/skills/ui-styling/scripts/requirements.txt +17 -0
- package/.opencode/skills/ui-styling/scripts/shadcn_add.py +308 -0
- package/.opencode/skills/ui-styling/scripts/tailwind_config_gen.py +473 -0
- package/.opencode/skills/ui-styling/scripts/tests/coverage-ui.json +1 -0
- package/.opencode/skills/ui-styling/scripts/tests/requirements.txt +3 -0
- package/.opencode/skills/ui-styling/scripts/tests/test_shadcn_add.py +266 -0
- package/.opencode/skills/ui-styling/scripts/tests/test_tailwind_config_gen.py +394 -0
- package/.opencode/skills/ui-ux-pro-max/SKILL.md +388 -0
- package/.opencode/skills/ui-ux-pro-max/data/app-interface.csv +31 -0
- package/.opencode/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/.opencode/skills/ui-ux-pro-max/data/colors.csv +193 -0
- package/.opencode/skills/ui-ux-pro-max/data/google-fonts.csv +1924 -0
- package/.opencode/skills/ui-ux-pro-max/data/icons.csv +106 -0
- package/.opencode/skills/ui-ux-pro-max/data/landing.csv +35 -0
- package/.opencode/skills/ui-ux-pro-max/data/motion.csv +17 -0
- package/.opencode/skills/ui-ux-pro-max/data/products.csv +193 -0
- package/.opencode/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/angular.csv +51 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/avalonia.csv +57 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/javafx.csv +76 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +71 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/uno.csv +60 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/uwp.csv +56 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/winui.csv +60 -0
- package/.opencode/skills/ui-ux-pro-max/data/stacks/wpf.csv +57 -0
- package/.opencode/skills/ui-ux-pro-max/data/styles.csv +85 -0
- package/.opencode/skills/ui-ux-pro-max/data/typography.csv +75 -0
- package/.opencode/skills/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
- package/.opencode/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/core.py +464 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/design_system.py +1479 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/search.py +162 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/tests/test_core.py +134 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/tests/test_design_system_mode.py +159 -0
- package/.opencode/skills/ui-ux-pro-max/scripts/validate_data.py +114 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/bin/mafw.js +436 -0
- package/dist/hooks/bash-python-guide.d.ts +4 -0
- package/dist/hooks/bash-python-guide.d.ts.map +1 -0
- package/dist/hooks/bash-python-guide.js +67 -0
- package/dist/hooks/bash-python-guide.js.map +1 -0
- package/dist/hooks/handoff.d.ts +9 -0
- package/dist/hooks/handoff.d.ts.map +1 -0
- package/dist/hooks/handoff.js +8 -0
- package/dist/hooks/handoff.js.map +1 -0
- package/dist/hooks/hook-manager.d.ts +32 -0
- package/dist/hooks/hook-manager.d.ts.map +1 -0
- package/dist/hooks/hook-manager.js +91 -0
- package/dist/hooks/hook-manager.js.map +1 -0
- package/dist/hooks/llm-after.d.ts +8 -0
- package/dist/hooks/llm-after.d.ts.map +1 -0
- package/dist/hooks/llm-after.js +8 -0
- package/dist/hooks/llm-after.js.map +1 -0
- package/dist/hooks/media-ingest.d.ts +43 -0
- package/dist/hooks/media-ingest.d.ts.map +1 -0
- package/dist/hooks/media-ingest.js +269 -0
- package/dist/hooks/media-ingest.js.map +1 -0
- package/dist/hooks/memory-guide.d.ts +3 -0
- package/dist/hooks/memory-guide.d.ts.map +1 -0
- package/dist/hooks/memory-guide.js +47 -0
- package/dist/hooks/memory-guide.js.map +1 -0
- package/dist/hooks/observation-capture.d.ts +17 -0
- package/dist/hooks/observation-capture.d.ts.map +1 -0
- package/dist/hooks/observation-capture.js +20 -0
- package/dist/hooks/observation-capture.js.map +1 -0
- package/dist/hooks/session-compacting.d.ts +6 -0
- package/dist/hooks/session-compacting.d.ts.map +1 -0
- package/dist/hooks/session-compacting.js +6 -0
- package/dist/hooks/session-compacting.js.map +1 -0
- package/dist/hooks/session-ending.d.ts +20 -0
- package/dist/hooks/session-ending.d.ts.map +1 -0
- package/dist/hooks/session-ending.js +113 -0
- package/dist/hooks/session-ending.js.map +1 -0
- package/dist/hooks/session-recall.d.ts +2 -0
- package/dist/hooks/session-recall.d.ts.map +1 -0
- package/dist/hooks/session-recall.js +103 -0
- package/dist/hooks/session-recall.js.map +1 -0
- package/dist/hooks/session-start.d.ts +9 -0
- package/dist/hooks/session-start.d.ts.map +1 -0
- package/dist/hooks/session-start.js +42 -0
- package/dist/hooks/session-start.js.map +1 -0
- package/dist/hooks/tool-before.d.ts +10 -0
- package/dist/hooks/tool-before.d.ts.map +1 -0
- package/dist/hooks/tool-before.js +6 -0
- package/dist/hooks/tool-before.js.map +1 -0
- package/dist/hooks/tool-executed.d.ts +19 -0
- package/dist/hooks/tool-executed.d.ts.map +1 -0
- package/dist/hooks/tool-executed.js +12 -0
- package/dist/hooks/tool-executed.js.map +1 -0
- package/dist/hooks/user-profile.d.ts +2 -0
- package/dist/hooks/user-profile.d.ts.map +1 -0
- package/dist/hooks/user-profile.js +30 -0
- package/dist/hooks/user-profile.js.map +1 -0
- package/dist/hooks/user-prompt.d.ts +9 -0
- package/dist/hooks/user-prompt.d.ts.map +1 -0
- package/dist/hooks/user-prompt.js +8 -0
- package/dist/hooks/user-prompt.js.map +1 -0
- package/dist/hooks/voice-guide.d.ts +8 -0
- package/dist/hooks/voice-guide.d.ts.map +1 -0
- package/dist/hooks/voice-guide.js +101 -0
- package/dist/hooks/voice-guide.js.map +1 -0
- package/dist/plugin.d.ts +55 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +342 -0
- package/dist/plugin.js.map +1 -0
- package/dist/tools/add-memory.d.ts +17 -0
- package/dist/tools/add-memory.d.ts.map +1 -0
- package/dist/tools/add-memory.js +60 -0
- package/dist/tools/add-memory.js.map +1 -0
- package/dist/tools/media-ask.d.ts +14 -0
- package/dist/tools/media-ask.d.ts.map +1 -0
- package/dist/tools/media-ask.js +224 -0
- package/dist/tools/media-ask.js.map +1 -0
- package/dist/tools/media-speak.d.ts +16 -0
- package/dist/tools/media-speak.d.ts.map +1 -0
- package/dist/tools/media-speak.js +78 -0
- package/dist/tools/media-speak.js.map +1 -0
- package/dist/tools/media-upload.d.ts +14 -0
- package/dist/tools/media-upload.d.ts.map +1 -0
- package/dist/tools/media-upload.js +155 -0
- package/dist/tools/media-upload.js.map +1 -0
- package/dist/tools/python-exec.d.ts +13 -0
- package/dist/tools/python-exec.d.ts.map +1 -0
- package/dist/tools/python-exec.js +99 -0
- package/dist/tools/python-exec.js.map +1 -0
- package/dist/tools/python-restart.d.ts +11 -0
- package/dist/tools/python-restart.d.ts.map +1 -0
- package/dist/tools/python-restart.js +33 -0
- package/dist/tools/python-restart.js.map +1 -0
- package/dist/utils/circuit-breaker.d.ts +23 -0
- package/dist/utils/circuit-breaker.d.ts.map +1 -0
- package/dist/utils/circuit-breaker.js +75 -0
- package/dist/utils/circuit-breaker.js.map +1 -0
- package/dist/utils/config-loader.d.ts +20 -0
- package/dist/utils/config-loader.d.ts.map +1 -0
- package/dist/utils/config-loader.js +194 -0
- package/dist/utils/config-loader.js.map +1 -0
- package/dist/utils/fallback.d.ts +7 -0
- package/dist/utils/fallback.d.ts.map +1 -0
- package/dist/utils/fallback.js +20 -0
- package/dist/utils/fallback.js.map +1 -0
- package/dist/utils/git.d.ts +24 -0
- package/dist/utils/git.d.ts.map +1 -0
- package/dist/utils/git.js +71 -0
- package/dist/utils/git.js.map +1 -0
- package/dist/utils/github.d.ts +37 -0
- package/dist/utils/github.d.ts.map +1 -0
- package/dist/utils/github.js +53 -0
- package/dist/utils/github.js.map +1 -0
- package/dist/utils/global-path.d.ts +2 -0
- package/dist/utils/global-path.d.ts.map +1 -0
- package/dist/utils/global-path.js +32 -0
- package/dist/utils/global-path.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +69 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/obs-capture.d.ts +7 -0
- package/dist/utils/obs-capture.d.ts.map +1 -0
- package/dist/utils/obs-capture.js +49 -0
- package/dist/utils/obs-capture.js.map +1 -0
- package/dist/utils/retry.d.ts +11 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +45 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils/self-wiring.d.ts +13 -0
- package/dist/utils/self-wiring.d.ts.map +1 -0
- package/dist/utils/self-wiring.js +86 -0
- package/dist/utils/self-wiring.js.map +1 -0
- package/dist/utils/state.d.ts +106 -0
- package/dist/utils/state.d.ts.map +1 -0
- package/dist/utils/state.js +166 -0
- package/dist/utils/state.js.map +1 -0
- package/dist/utils/status.d.ts +47 -0
- package/dist/utils/status.d.ts.map +1 -0
- package/dist/utils/status.js +147 -0
- package/dist/utils/status.js.map +1 -0
- package/dist/utils/ttl-map.d.ts +17 -0
- package/dist/utils/ttl-map.d.ts.map +1 -0
- package/dist/utils/ttl-map.js +67 -0
- package/dist/utils/ttl-map.js.map +1 -0
- package/gateway/dist/automation-engine.js +729 -0
- package/gateway/dist/chat/chat-sessions.js +95 -0
- package/gateway/dist/chat/graph-runner.js +76 -0
- package/gateway/dist/chat/index.js +7 -0
- package/gateway/dist/chat/intent-classifier.js +23 -0
- package/gateway/dist/config.js +416 -0
- package/gateway/dist/core/auth.js +96 -0
- package/gateway/dist/core/budget-guard.js +52 -0
- package/gateway/dist/core/compression/bm25-index.js +176 -0
- package/gateway/dist/core/compression/compression-pipeline.js +157 -0
- package/gateway/dist/core/compression/compression-strategy-selector.js +32 -0
- package/gateway/dist/core/compression/compression-verifier.js +79 -0
- package/gateway/dist/core/compression/diff-compressor.js +69 -0
- package/gateway/dist/core/compression/hybrid-compressor.js +104 -0
- package/gateway/dist/core/compression/lesson-compactor.js +114 -0
- package/gateway/dist/core/compression/memory-index.js +190 -0
- package/gateway/dist/core/compression/observation-classifier.js +41 -0
- package/gateway/dist/core/compression/observation-deduplicator.js +43 -0
- package/gateway/dist/core/compression/rrf-fusion.js +63 -0
- package/gateway/dist/core/compression/session-pruner.js +137 -0
- package/gateway/dist/core/compression/token-budget-allocator.js +141 -0
- package/gateway/dist/core/compression/vector-index.js +117 -0
- package/gateway/dist/core/compression/zero-token-compressor.js +80 -0
- package/gateway/dist/core/cost/cognitive-router.js +41 -0
- package/gateway/dist/core/cost/cost-estimator.js +63 -0
- package/gateway/dist/core/cost/types.js +19 -0
- package/gateway/dist/core/engine/degradation.js +159 -0
- package/gateway/dist/core/engine/goal-worktree-manager.js +131 -0
- package/gateway/dist/core/engine/lesson-manager.js +222 -0
- package/gateway/dist/core/engine/optimistic-sync.js +100 -0
- package/gateway/dist/core/engine/phase-orchestrator.js +153 -0
- package/gateway/dist/core/engine/report-generator.js +131 -0
- package/gateway/dist/core/engine/state-lock.js +91 -0
- package/gateway/dist/core/engine/task-branch-manager.js +102 -0
- package/gateway/dist/core/engine/wave-dependency.js +67 -0
- package/gateway/dist/core/engine/wave-executor.js +112 -0
- package/gateway/dist/core/goal-budget.js +63 -0
- package/gateway/dist/core/graph/entity-extractor.js +53 -0
- package/gateway/dist/core/graph/graph-searcher.js +120 -0
- package/gateway/dist/core/graph/knowledge-graph-manager.js +138 -0
- package/gateway/dist/core/graph/relation-inferencer.js +67 -0
- package/gateway/dist/core/graph/types.js +2 -0
- package/gateway/dist/core/hooks/handoff.js +7 -0
- package/gateway/dist/core/hooks/hook-manager.js +91 -0
- package/gateway/dist/core/hooks/llm-after.js +7 -0
- package/gateway/dist/core/hooks/observation-capture.js +19 -0
- package/gateway/dist/core/hooks/session-compacting.js +5 -0
- package/gateway/dist/core/hooks/session-ending.js +123 -0
- package/gateway/dist/core/hooks/session-start.js +51 -0
- package/gateway/dist/core/hooks/tool-before.js +5 -0
- package/gateway/dist/core/hooks/tool-executed.js +11 -0
- package/gateway/dist/core/hooks/user-prompt.js +7 -0
- package/gateway/dist/core/index.js +119 -0
- package/gateway/dist/core/langchain/agent-adapter.js +39 -0
- package/gateway/dist/core/langchain/index.js +12 -0
- package/gateway/dist/core/langchain/memory.js +35 -0
- package/gateway/dist/core/langchain/node-runner.js +115 -0
- package/gateway/dist/core/langchain/retriever.js +28 -0
- package/gateway/dist/core/langgraph/checkpointer.js +200 -0
- package/gateway/dist/core/langgraph/graph.js +57 -0
- package/gateway/dist/core/langgraph/index.js +25 -0
- package/gateway/dist/core/langgraph/loop-state.js +71 -0
- package/gateway/dist/core/langgraph/nodes/archive.node.js +27 -0
- package/gateway/dist/core/langgraph/nodes/execute.node.js +5 -0
- package/gateway/dist/core/langgraph/nodes/plan.node.js +101 -0
- package/gateway/dist/core/langgraph/nodes/review.node.js +89 -0
- package/gateway/dist/core/langgraph/nodes/sync.node.js +70 -0
- package/gateway/dist/core/langgraph/review-parser.js +35 -0
- package/gateway/dist/core/langgraph/signature-detector.js +23 -0
- package/gateway/dist/core/manager/goal-snapshot.js +73 -0
- package/gateway/dist/core/manager/milestone-push.js +81 -0
- package/gateway/dist/core/manager/question-ledger.js +121 -0
- package/gateway/dist/core/manager/system-rule-templates.js +76 -0
- package/gateway/dist/core/mcp/tools.js +562 -0
- package/gateway/dist/core/mcp/validator.js +165 -0
- package/gateway/dist/core/mcp-server.js +86 -0
- package/gateway/dist/core/memory/abstraction-distiller.js +44 -0
- package/gateway/dist/core/memory/cognitive-graph.js +103 -0
- package/gateway/dist/core/memory/energy-system.js +69 -0
- package/gateway/dist/core/memory/extractor.js +164 -0
- package/gateway/dist/core/memory/harmonic-index.js +530 -0
- package/gateway/dist/core/memory/harmonic-types.js +6 -0
- package/gateway/dist/core/memory/injector.js +111 -0
- package/gateway/dist/core/memory/l5-store.js +141 -0
- package/gateway/dist/core/memory/matcher.js +66 -0
- package/gateway/dist/core/memory/merger.js +95 -0
- package/gateway/dist/core/memory/migrate-v6.1.js +133 -0
- package/gateway/dist/core/memory/minhash-merger.js +195 -0
- package/gateway/dist/core/memory/observation-service.js +87 -0
- package/gateway/dist/core/memory/privacy-filter.js +163 -0
- package/gateway/dist/core/memory/reranker.js +208 -0
- package/gateway/dist/core/memory/review-scheduler.js +100 -0
- package/gateway/dist/core/memory/salience-perceptor.js +24 -0
- package/gateway/dist/core/memory/store.js +284 -0
- package/gateway/dist/core/memory/t1-store.js +183 -0
- package/gateway/dist/core/memory/t1-to-t2-compressor.js +119 -0
- package/gateway/dist/core/memory/validator.js +66 -0
- package/gateway/dist/core/plugin.js +902 -0
- package/gateway/dist/core/skills/mafw-execute/entry.js +226 -0
- package/gateway/dist/core/skills/mafw-goal/entry.js +203 -0
- package/gateway/dist/core/skills/mafw-plan/entry.js +184 -0
- package/gateway/dist/core/skills/mafw-review/entry.js +200 -0
- package/gateway/dist/core/storage/file-storage.js +120 -0
- package/gateway/dist/core/storage/sqlite-storage.js +205 -0
- package/gateway/dist/core/storage/types.js +2 -0
- package/gateway/dist/core/tools/archive-worktree.js +208 -0
- package/gateway/dist/core/tools/remote-cli.js +106 -0
- package/gateway/dist/core/tools/run-ask-user.js +79 -0
- package/gateway/dist/core/tools/run-execute-wave.js +32 -0
- package/gateway/dist/core/tools/run-plan.js +42 -0
- package/gateway/dist/core/tools/run-record-feedback.js +55 -0
- package/gateway/dist/core/tools/run-review.js +46 -0
- package/gateway/dist/core/tools/write-lesson.js +97 -0
- package/gateway/dist/core/utils/circuit-breaker.js +74 -0
- package/gateway/dist/core/utils/config-loader.js +203 -0
- package/gateway/dist/core/utils/fallback.js +19 -0
- package/gateway/dist/core/utils/git.js +70 -0
- package/gateway/dist/core/utils/github.js +52 -0
- package/gateway/dist/core/utils/global-path.js +41 -0
- package/gateway/dist/core/utils/logger.js +71 -0
- package/gateway/dist/core/utils/retry.js +44 -0
- package/gateway/dist/core/utils/state.js +175 -0
- package/gateway/dist/core/utils/status.js +156 -0
- package/gateway/dist/cost/service.js +17 -0
- package/gateway/dist/dashboard/api.js +1156 -0
- package/gateway/dist/dashboard/public/assets/index-DOXm39dm.css +1 -0
- package/gateway/dist/dashboard/public/index.html +13 -0
- package/gateway/dist/dashboard/server.js +140 -0
- package/gateway/dist/dashboard/types.js +2 -0
- package/gateway/dist/desktop-client.js +124 -0
- package/gateway/dist/eval-endpoint.js +219 -0
- package/gateway/dist/event-bus.js +7 -0
- package/gateway/dist/feedback/anchor-promotion.js +99 -0
- package/gateway/dist/feedback/deferred-memory.js +13 -0
- package/gateway/dist/feedback/miss-attribution.js +20 -0
- package/gateway/dist/graph/anchor-graph-store.js +113 -0
- package/gateway/dist/graph/anchor-graph.js +48 -0
- package/gateway/dist/health.js +53 -0
- package/gateway/dist/heartbeat.js +109 -0
- package/gateway/dist/index.js +6377 -0
- package/gateway/dist/interceptors/memory-injector.js +79 -0
- package/gateway/dist/ledger.js +121 -0
- package/gateway/dist/loop-monitor.js +74 -0
- package/gateway/dist/mcp/handlers/add-memory.js +113 -0
- package/gateway/dist/mcp/handlers/ask-user.js +63 -0
- package/gateway/dist/mcp/handlers/commit-heuristic.js +19 -0
- package/gateway/dist/mcp/handlers/create-goal.js +83 -0
- package/gateway/dist/mcp/handlers/desktop-click.js +18 -0
- package/gateway/dist/mcp/handlers/desktop-get-state.js +15 -0
- package/gateway/dist/mcp/handlers/desktop-navigate.js +18 -0
- package/gateway/dist/mcp/handlers/desktop-screenshot.js +16 -0
- package/gateway/dist/mcp/handlers/desktop-scroll.js +19 -0
- package/gateway/dist/mcp/handlers/desktop-type.js +19 -0
- package/gateway/dist/mcp/handlers/draft-automation-rule.js +45 -0
- package/gateway/dist/mcp/handlers/get-automation-history.js +15 -0
- package/gateway/dist/mcp/handlers/get-automation-rule.js +26 -0
- package/gateway/dist/mcp/handlers/get-axioms.js +14 -0
- package/gateway/dist/mcp/handlers/get-deltas.js +77 -0
- package/gateway/dist/mcp/handlers/get-memory.js +67 -0
- package/gateway/dist/mcp/handlers/get-model-route.js +16 -0
- package/gateway/dist/mcp/handlers/get-triage-item.js +17 -0
- package/gateway/dist/mcp/handlers/list-automation-rules.js +24 -0
- package/gateway/dist/mcp/handlers/list-triage-items.js +14 -0
- package/gateway/dist/mcp/handlers/load-state.js +54 -0
- package/gateway/dist/mcp/handlers/manager-answer-question.js +67 -0
- package/gateway/dist/mcp/handlers/manager-cancel-goal.js +58 -0
- package/gateway/dist/mcp/handlers/manager-get-evidence.js +57 -0
- package/gateway/dist/mcp/handlers/manager-get-goal-status.js +58 -0
- package/gateway/dist/mcp/handlers/manager-list-goals.js +60 -0
- package/gateway/dist/mcp/handlers/manager-list-pending-questions.js +67 -0
- package/gateway/dist/mcp/handlers/manager-set-goal.js +78 -0
- package/gateway/dist/mcp/handlers/merge-memory.js +184 -0
- package/gateway/dist/mcp/handlers/pin-memory.js +53 -0
- package/gateway/dist/mcp/handlers/propose-triage-decision.js +38 -0
- package/gateway/dist/mcp/handlers/record-feedback.js +59 -0
- package/gateway/dist/mcp/handlers/resolve-merge.js +92 -0
- package/gateway/dist/mcp/handlers/restart-agent.js +22 -0
- package/gateway/dist/mcp/handlers/run-automation.js +28 -0
- package/gateway/dist/mcp/handlers/search-hybrid.js +181 -0
- package/gateway/dist/mcp/handlers/supersede-memory.js +47 -0
- package/gateway/dist/mcp/handlers/update-state.js +59 -0
- package/gateway/dist/mcp/handlers/validate-rule.js +39 -0
- package/gateway/dist/mcp/sse-transport.js +97 -0
- package/gateway/dist/mcp/streamable-endpoint.js +98 -0
- package/gateway/dist/mcp/tool-registry.js +630 -0
- package/gateway/dist/media/media-agent.js +755 -0
- package/gateway/dist/media/media-plugin-loader.js +254 -0
- package/gateway/dist/media/media-runtime-executor.js +227 -0
- package/gateway/dist/media/media-service.js +199 -0
- package/gateway/dist/media/pi-adapter.js +159 -0
- package/gateway/dist/media/plugin-context.js +14 -0
- package/gateway/dist/media/tts-service.js +173 -0
- package/gateway/dist/memory/abstraction-matcher.js +28 -0
- package/gateway/dist/memory/consolidation-service.js +209 -0
- package/gateway/dist/memory/derived-terms.js +50 -0
- package/gateway/dist/memory/embedding-provider.js +330 -0
- package/gateway/dist/memory/embedding-runtime.js +174 -0
- package/gateway/dist/memory/event-log.js +84 -0
- package/gateway/dist/memory/gateway-db.js +465 -0
- package/gateway/dist/memory/harmonic-file-store.js +338 -0
- package/gateway/dist/memory/llamacpp-provider.js +370 -0
- package/gateway/dist/memory/okf-index-renderer.js +61 -0
- package/gateway/dist/memory/okf-migrator.js +71 -0
- package/gateway/dist/memory/okf-parser.js +57 -0
- package/gateway/dist/memory/okf-writer.js +107 -0
- package/gateway/dist/memory/service.js +81 -0
- package/gateway/dist/memory/t1-db.js +139 -0
- package/gateway/dist/memory/unmerge-cleanup.js +82 -0
- package/gateway/dist/memory/vector-store.js +246 -0
- package/gateway/dist/memory/write-queue.js +31 -0
- package/gateway/dist/metrics/collector.js +28 -0
- package/gateway/dist/mobile/device-store.js +123 -0
- package/gateway/dist/mobile/mdns-advertiser.js +55 -0
- package/gateway/dist/mobile/media-proxy.js +292 -0
- package/gateway/dist/mobile/pairing.js +139 -0
- package/gateway/dist/mobile/push-gateway.js +126 -0
- package/gateway/dist/mobile/tts-artifact.js +43 -0
- package/gateway/dist/opencode-adapter.js +241 -0
- package/gateway/dist/orchestration/outcome-recorder.js +218 -0
- package/gateway/dist/orchestration/policy.js +57 -0
- package/gateway/dist/orchestration/registry.js +47 -0
- package/gateway/dist/plugins/hub.js +188 -0
- package/gateway/dist/poll.js +110 -0
- package/gateway/dist/python/kernel-service.js +762 -0
- package/gateway/dist/recall/constraints-migrate.js +108 -0
- package/gateway/dist/recall/data-dir-migrate.js +120 -0
- package/gateway/dist/recall/gateway-db-migrate.js +134 -0
- package/gateway/dist/recall/index-scan.js +437 -0
- package/gateway/dist/recall/inject-format.js +222 -0
- package/gateway/dist/recall/legacy-t1-archive.js +86 -0
- package/gateway/dist/recall/memory-worker.js +128 -0
- package/gateway/dist/recall/pipeline-rules.js +76 -0
- package/gateway/dist/recall/recall-context.js +297 -0
- package/gateway/dist/recall/reflect-cursor.js +50 -0
- package/gateway/dist/recall/reflection.js +318 -0
- package/gateway/dist/recall/session-worker-pool.js +100 -0
- package/gateway/dist/recall/stale-verify.js +72 -0
- package/gateway/dist/recall/step-inject.js +173 -0
- package/gateway/dist/recall/time-anchor.js +143 -0
- package/gateway/dist/recall/ttl-map.js +72 -0
- package/gateway/dist/recall/turn-completion.js +44 -0
- package/gateway/dist/recall/turn-pipeline.js +150 -0
- package/gateway/dist/recovery.js +158 -0
- package/gateway/dist/resources/sdk-session.js +202 -0
- package/gateway/dist/retrieval/guided-retriever.js +131 -0
- package/gateway/dist/retrieval/idf-stats.js +31 -0
- package/gateway/dist/routes/embedding-config.js +100 -0
- package/gateway/dist/routes/goal-sessions.js +45 -0
- package/gateway/dist/routes/manager-rotate.js +55 -0
- package/gateway/dist/routes/media-switch.js +78 -0
- package/gateway/dist/routes/model-config.js +132 -0
- package/gateway/dist/routes/note-board.js +51 -0
- package/gateway/dist/routes/permission.js +43 -0
- package/gateway/dist/routes/pinned-recall.js +36 -0
- package/gateway/dist/routes/plugins.js +77 -0
- package/gateway/dist/routes/restart-agent.js +28 -0
- package/gateway/dist/routes/runtime-switch.js +80 -0
- package/gateway/dist/routes/session-branch.js +63 -0
- package/gateway/dist/routes/session-mutations.js +58 -0
- package/gateway/dist/routes/session-summarize.js +49 -0
- package/gateway/dist/routes/usage-plugins.js +251 -0
- package/gateway/dist/runtime/agent-definition.js +2 -0
- package/gateway/dist/runtime/auth.js +80 -0
- package/gateway/dist/runtime/completion-http.js +97 -0
- package/gateway/dist/runtime/contract.js +37 -0
- package/gateway/dist/runtime/loader.js +240 -0
- package/gateway/dist/runtime/normalize.js +59 -0
- package/gateway/dist/runtime/opencode-runtime.js +336 -0
- package/gateway/dist/runtime/pi/pi-agent-config.js +294 -0
- package/gateway/dist/runtime/pi/pi-approval-bridge.js +44 -0
- package/gateway/dist/runtime/pi/pi-approval-extension.js +62 -0
- package/gateway/dist/runtime/pi/pi-events.js +122 -0
- package/gateway/dist/runtime/pi/pi-messages.js +20 -0
- package/gateway/dist/runtime/pi/pi-provider.js +19 -0
- package/gateway/dist/runtime/pi/pi-session-storage.js +44 -0
- package/gateway/dist/runtime/pi/pi-session.js +328 -0
- package/gateway/dist/runtime/plugins/pi-runtime.js +285 -0
- package/gateway/dist/runtime/serve-for-runtime.js +22 -0
- package/gateway/dist/runtime/serve-sidecar.js +164 -0
- package/gateway/dist/runtime/serve-supervisor.js +80 -0
- package/gateway/dist/self-update.js +309 -0
- package/gateway/dist/skills/manager-agent-config.js +37 -0
- package/gateway/dist/skills/manager-identity.js +11 -0
- package/gateway/dist/skills/memory-curator-agent.js +55 -0
- package/gateway/dist/trajectory/api.js +154 -0
- package/gateway/dist/trajectory/backfill-provider.js +41 -0
- package/gateway/dist/trajectory/collector.js +337 -0
- package/gateway/dist/trajectory/trajectory-store.js +336 -0
- package/gateway/dist/trajectory/types.js +17 -0
- package/gateway/dist/tray/index.js +131 -0
- package/gateway/dist/tray/tray.ps1 +96 -0
- package/gateway/dist/types.js +2 -0
- package/gateway/dist/usage/builtin-plugins/commandcode.js +71 -0
- package/gateway/dist/usage/builtin-plugins/deepseek.js +56 -0
- package/gateway/dist/usage/builtin-plugins/gateway.js +127 -0
- package/gateway/dist/usage/builtin-plugins/kimi-for-coding.js +93 -0
- package/gateway/dist/usage/builtin-plugins/kimi.js +48 -0
- package/gateway/dist/usage/builtin-plugins/opencode-go.js +54 -0
- package/gateway/dist/usage/builtin-plugins/openrouter.js +48 -0
- package/gateway/dist/usage/builtin-plugins/siliconflow-cn.js +49 -0
- package/gateway/dist/usage/builtin-plugins/zhipuai-coding-plan.js +44 -0
- package/gateway/dist/usage/model-prices.js +39 -0
- package/gateway/dist/usage/model-stats.js +21 -0
- package/gateway/dist/usage/plugin-context.js +79 -0
- package/gateway/dist/usage/plugin-loader.js +280 -0
- package/gateway/dist/usage/templates.js +227 -0
- package/gateway/dist/usage/types.js +2 -0
- package/gateway/dist/usage/usage-poller.js +216 -0
- package/gateway/package.json +37 -0
- package/package.json +78 -0
- package/packages/tui/dist/cli.js +4664 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReflectionPipeline = exports.QUESTIONS_SYSTEM = exports.REFLECT_SYSTEM = exports.ORPHAN_SESSION = void 0;
|
|
4
|
+
exports.parseQuestions = parseQuestions;
|
|
5
|
+
exports.parseInsights = parseInsights;
|
|
6
|
+
exports.unreflectedBySession = unreflectedBySession;
|
|
7
|
+
const harmonic_file_store_1 = require("../memory/harmonic-file-store");
|
|
8
|
+
const minhash_merger_1 = require("../core/memory/minhash-merger");
|
|
9
|
+
const harmonic_types_1 = require("../core/memory/harmonic-types");
|
|
10
|
+
const salience_perceptor_1 = require("../core/memory/salience-perceptor");
|
|
11
|
+
const memory_curator_agent_1 = require("../skills/memory-curator-agent");
|
|
12
|
+
/** Session key for episodic memories with no source_session_id (legacy data). */
|
|
13
|
+
exports.ORPHAN_SESSION = '__orphan__';
|
|
14
|
+
exports.REFLECT_SYSTEM = `You are a reflection system for a coding agent's long-term memory. Review the episodic memories of one conversation and distill durable, reusable insights. Return ONLY valid JSON, no markdown:
|
|
15
|
+
{"insights":[{"category":"failure|correction|insight|preference|convention|tool-quirk","content":"<one sentence>","cue_anchors":["<keyword>"]}]}
|
|
16
|
+
Rules:
|
|
17
|
+
- no redundant insights; each insight must be a durable lesson, preference, failure, convention, or tool quirk
|
|
18
|
+
- every cue_anchors list MUST include the topic entity names (project, module, API, person, feature) so the insight can be found across sessions
|
|
19
|
+
- for category "preference", include a machine-readable anchor like "pref:<dimension>=<value>" (e.g., "pref:output-language=chinese" or "pref:spicy=false")
|
|
20
|
+
- prefer insights that hold across multiple episodes of this conversation
|
|
21
|
+
Division of labor: focus on CROSS-EPISODE high-level patterns — recurring failure root causes, lessons that generalize to future tasks, user behavior patterns. Do NOT re-record single-point facts already present in the episodic memories (the hourly extract pipeline already saved those).
|
|
22
|
+
|
|
23
|
+
### Cross-Session Entity Linking (CRITICAL):
|
|
24
|
+
- Extract ALL named entities from the episodes: project names, module names, person names, API endpoints, feature names, file paths, commands, error messages, configuration keys
|
|
25
|
+
- For each insight, include entities that would help find this insight in OTHER sessions about the same topic
|
|
26
|
+
- Include entity variants: e.g., both "React" and "react", both "User Auth Module" and "auth module"
|
|
27
|
+
- For technical discussions, include error codes, stack traces, or specific function names as anchors
|
|
28
|
+
- For user preferences, include the dimension AND value: e.g., "pref:ui-language=chinese" AND "chinese" AND "ui-language"
|
|
29
|
+
- Think: "If someone asked about this topic in a different session, what keywords would they search for?"
|
|
30
|
+
${memory_curator_agent_1.HARD_BOUNDARIES}`;
|
|
31
|
+
exports.QUESTIONS_SYSTEM = `You are a reflection system for a coding agent's long-term memory. Review the episodic memories of one conversation and generate the 2-3 most salient high-level questions about this session — questions whose answers would reveal durable patterns, recurring root causes, or generalizable lessons. Return ONLY valid JSON, no markdown:
|
|
32
|
+
{"questions":["<question>","<question>"]}
|
|
33
|
+
Rules:
|
|
34
|
+
- questions must be answerable from past conversations (not speculation)
|
|
35
|
+
- prefer questions that span multiple episodes
|
|
36
|
+
- questions should be specific enough to retrieve relevant memories (include entity names like project, module, API, feature)
|
|
37
|
+
- for multi-topic sessions, generate questions for each topic separately
|
|
38
|
+
- for user preferences, ask about the preference itself (e.g., "What UI language does the user prefer?") rather than the context where it was mentioned
|
|
39
|
+
${memory_curator_agent_1.HARD_BOUNDARIES}`;
|
|
40
|
+
function parseQuestions(text) {
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(text.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/, ''));
|
|
43
|
+
const items = parsed?.questions ?? parsed;
|
|
44
|
+
if (!Array.isArray(items))
|
|
45
|
+
return [];
|
|
46
|
+
return items.filter((q) => typeof q === 'string' && q.trim()).slice(0, 3).map(String);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const CATEGORY_TO_TYPE = {
|
|
53
|
+
failure: 'semantic',
|
|
54
|
+
correction: 'semantic',
|
|
55
|
+
insight: 'semantic',
|
|
56
|
+
preference: 'semantic',
|
|
57
|
+
convention: 'semantic',
|
|
58
|
+
'tool-quirk': 'procedural',
|
|
59
|
+
};
|
|
60
|
+
const CATEGORY_ENERGY = {
|
|
61
|
+
failure: 0.9,
|
|
62
|
+
correction: 0.9,
|
|
63
|
+
insight: 0.8,
|
|
64
|
+
preference: 0.85,
|
|
65
|
+
convention: 0.75,
|
|
66
|
+
'tool-quirk': 0.8,
|
|
67
|
+
};
|
|
68
|
+
function parseInsights(text) {
|
|
69
|
+
try {
|
|
70
|
+
const parsed = JSON.parse(text.replace(/^```(?:json)?\s*/i, '').replace(/```\s*$/, ''));
|
|
71
|
+
const items = parsed?.insights ?? parsed;
|
|
72
|
+
if (!Array.isArray(items))
|
|
73
|
+
return [];
|
|
74
|
+
return items
|
|
75
|
+
.filter((i) => i?.content?.trim() &&
|
|
76
|
+
['failure', 'correction', 'insight', 'preference', 'convention', 'tool-quirk'].includes(i.category))
|
|
77
|
+
.map((i) => ({
|
|
78
|
+
category: i.category,
|
|
79
|
+
content: String(i.content).trim(),
|
|
80
|
+
cue_anchors: Array.isArray(i.cue_anchors) ? i.cue_anchors.slice(0, 8).map(String) : [],
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Groups index episodic entries by session (source_session_id; legacy entries
|
|
89
|
+
* without one go to the ORPHAN group). Returns only unreflected ids.
|
|
90
|
+
*/
|
|
91
|
+
function unreflectedBySession(index, cursor, maxPerSession) {
|
|
92
|
+
const bySession = new Map();
|
|
93
|
+
for (const entry of index.getIndex().entries) {
|
|
94
|
+
if (entry.type !== 'episodic')
|
|
95
|
+
continue;
|
|
96
|
+
const session = entry.source_session_id || exports.ORPHAN_SESSION;
|
|
97
|
+
if (cursor.isReflected(session, entry.id))
|
|
98
|
+
continue;
|
|
99
|
+
let list = bySession.get(session);
|
|
100
|
+
if (!list) {
|
|
101
|
+
list = [];
|
|
102
|
+
bySession.set(session, list);
|
|
103
|
+
}
|
|
104
|
+
if (list.length >= maxPerSession)
|
|
105
|
+
continue;
|
|
106
|
+
list.push({ id: entry.id, text: `${entry.primary_abstraction} ${(entry.cue_anchors ?? []).join(' ')}` });
|
|
107
|
+
}
|
|
108
|
+
return bySession;
|
|
109
|
+
}
|
|
110
|
+
class ReflectionPipeline {
|
|
111
|
+
opts;
|
|
112
|
+
store;
|
|
113
|
+
merger = new minhash_merger_1.MinHashMerger();
|
|
114
|
+
constructor(opts) {
|
|
115
|
+
this.opts = opts;
|
|
116
|
+
this.store = new harmonic_file_store_1.HarmonicUnitFileStore(opts.baseDir, opts.index);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Three-way classification for a new insight against existing memories:
|
|
120
|
+
* - 'duplicate': MinHash > 0.6 → skip (same content)
|
|
121
|
+
* - 'conflict': MinHash 0.4-0.6 + shared cue_anchors → supersede old entry
|
|
122
|
+
* - 'novel': no significant overlap → write normally
|
|
123
|
+
*
|
|
124
|
+
* The conflict band (0.4-0.6) catches "same topic, different value" cases
|
|
125
|
+
* that MinHash dedup misses — e.g., "deploy to us-east-1" vs "deploy to
|
|
126
|
+
* eu-west-1" share structure but differ in the critical detail.
|
|
127
|
+
*/
|
|
128
|
+
classifyInsight(content, cueAnchors) {
|
|
129
|
+
const sig = this.merger.generateSignature(content);
|
|
130
|
+
let bestMatch = null;
|
|
131
|
+
for (const entry of this.opts.index.getIndex().entries) {
|
|
132
|
+
if (entry.type !== 'semantic' && entry.type !== 'procedural')
|
|
133
|
+
continue;
|
|
134
|
+
if (entry.superseded_by)
|
|
135
|
+
continue; // skip already-superseded entries
|
|
136
|
+
// Merged blobs concatenate segments with ' | ' — compare per segment
|
|
137
|
+
// so a true duplicate of one segment is not diluted by the rest.
|
|
138
|
+
let sim = 0;
|
|
139
|
+
for (const seg of minhash_merger_1.MinHashMerger.segmentsOf(entry.primary_abstraction)) {
|
|
140
|
+
const other = `${seg} ${(entry.cue_anchors ?? []).join(' ')}`;
|
|
141
|
+
const s = this.merger.similarity(sig, this.merger.generateSignature(other));
|
|
142
|
+
if (s > sim)
|
|
143
|
+
sim = s;
|
|
144
|
+
}
|
|
145
|
+
if (sim > 0.6)
|
|
146
|
+
return { kind: 'duplicate' };
|
|
147
|
+
if (sim > 0.4 && sim > (bestMatch?.sim ?? 0)) {
|
|
148
|
+
bestMatch = { id: entry.id, sim };
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Conflict requires both MinHash in the 0.4-0.6 band AND at least one shared cue_anchor
|
|
152
|
+
if (bestMatch && bestMatch.sim > 0.4) {
|
|
153
|
+
const targetEntry = this.opts.index.getIndex().entries.find(e => e.id === bestMatch.id);
|
|
154
|
+
const targetAnchors = targetEntry?.cue_anchors ?? [];
|
|
155
|
+
const sharedAnchors = cueAnchors.filter(a => targetAnchors.includes(a));
|
|
156
|
+
if (sharedAnchors.length > 0) {
|
|
157
|
+
return { kind: 'conflict', conflictTarget: bestMatch.id };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return { kind: 'novel' };
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Reflect one session's unreflected episodes. Returns the number of
|
|
164
|
+
* reviewed episodes (0 when nothing pending). Marks ids reflected only
|
|
165
|
+
* after insights were successfully written (failure keeps them pending for
|
|
166
|
+
* the next run).
|
|
167
|
+
*/
|
|
168
|
+
async reflectSession(sessionID, episodes) {
|
|
169
|
+
const result = { sessions: 0, reviewed: 0, distilled: 0, deduped: 0, superseded: 0, failed: 0, pendingSessions: 0 };
|
|
170
|
+
if (episodes.length === 0)
|
|
171
|
+
return result;
|
|
172
|
+
result.reviewed = episodes.length;
|
|
173
|
+
const promptLines = [];
|
|
174
|
+
for (let i = 0; i < episodes.length; i++) {
|
|
175
|
+
const ep = episodes[i];
|
|
176
|
+
let text = ep.text;
|
|
177
|
+
try {
|
|
178
|
+
const unit = await this.store.read(ep.id);
|
|
179
|
+
if (unit?.memory_value)
|
|
180
|
+
text = unit.memory_value.slice(0, 2000);
|
|
181
|
+
}
|
|
182
|
+
catch { /* fall back to summary line */ }
|
|
183
|
+
promptLines.push(`${i + 1}. ${text}`);
|
|
184
|
+
}
|
|
185
|
+
const prompt = promptLines.join('\n');
|
|
186
|
+
const worker = this.opts.workerFor(sessionID);
|
|
187
|
+
let insights = [];
|
|
188
|
+
try {
|
|
189
|
+
// Step 1: generate salient questions
|
|
190
|
+
const qText = await worker.prompt(prompt, exports.QUESTIONS_SYSTEM, this.opts.workerModel, 'memory-curator');
|
|
191
|
+
const questions = parseQuestions(qText);
|
|
192
|
+
// Step 2: retrieve evidence per question (bm25, no graph expansion)
|
|
193
|
+
const evidence = [];
|
|
194
|
+
if (questions.length > 0) {
|
|
195
|
+
for (const q of questions) {
|
|
196
|
+
const hits = this.opts.index.searchScored(q, 5, { retriever: 'bm25', graphExpand: false });
|
|
197
|
+
for (const hit of hits) {
|
|
198
|
+
const line = `- [${hit.entry.id}] ${hit.entry.primary_abstraction}`;
|
|
199
|
+
if (!evidence.includes(line))
|
|
200
|
+
evidence.push(line);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Step 3: distill insights with evidence context
|
|
205
|
+
const evidenceBlock = evidence.length > 0 ? `\n\n### Related Historical Memories\n${evidence.join('\n')}` : '';
|
|
206
|
+
// Step 3.5: Extract entities from episodes for cross-session linking
|
|
207
|
+
const episodeEntities = new Set();
|
|
208
|
+
for (const ep of episodes) {
|
|
209
|
+
// Extract camelCase/PascalCase identifiers
|
|
210
|
+
const camelPascal = ep.text.match(/\b[A-Z][a-z]+(?:[A-Z][a-z]+)+\b/g);
|
|
211
|
+
if (camelPascal)
|
|
212
|
+
camelPascal.forEach(e => episodeEntities.add(e));
|
|
213
|
+
// Extract ALL_CAPS words
|
|
214
|
+
const allCaps = ep.text.match(/\b[A-Z]{2,}\b/g);
|
|
215
|
+
if (allCaps)
|
|
216
|
+
allCaps.forEach(e => { if (e.length >= 3)
|
|
217
|
+
episodeEntities.add(e); });
|
|
218
|
+
// Extract quoted strings
|
|
219
|
+
const quoted = ep.text.match(/['"]([^'"]+)['"]/g);
|
|
220
|
+
if (quoted)
|
|
221
|
+
quoted.forEach(q => episodeEntities.add(q.slice(1, -1).trim()));
|
|
222
|
+
}
|
|
223
|
+
// Inject entity context into evidence block for cross-session linking
|
|
224
|
+
const entityBlock = episodeEntities.size > 0
|
|
225
|
+
? `\n\n### Session Entities (for cross-session linking)\n${[...episodeEntities].slice(0, 20).join(', ')}`
|
|
226
|
+
: '';
|
|
227
|
+
const text = await worker.prompt(prompt + evidenceBlock + entityBlock, exports.REFLECT_SYSTEM, this.opts.workerModel, 'memory-curator');
|
|
228
|
+
insights = parseInsights(text);
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
result.failed++;
|
|
232
|
+
return result; // episodes stay unreflected
|
|
233
|
+
}
|
|
234
|
+
const maxInsights = this.opts.maxInsights ?? 10;
|
|
235
|
+
for (const insight of insights.slice(0, maxInsights)) {
|
|
236
|
+
const classification = this.classifyInsight(insight.content, insight.cue_anchors ?? []);
|
|
237
|
+
if (classification.kind === 'duplicate') {
|
|
238
|
+
result.deduped++;
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
const now = new Date().toISOString();
|
|
242
|
+
const unit = {
|
|
243
|
+
id: (0, harmonic_types_1.generateHarmonicId)(),
|
|
244
|
+
type: CATEGORY_TO_TYPE[insight.category],
|
|
245
|
+
primary_abstraction: insight.content.slice(0, 200),
|
|
246
|
+
cue_anchors: insight.cue_anchors ?? [],
|
|
247
|
+
memory_value: insight.content,
|
|
248
|
+
energy: CATEGORY_ENERGY[insight.category],
|
|
249
|
+
salience: (0, salience_perceptor_1.calculateSalience)(insight.content),
|
|
250
|
+
abstraction_level: 2,
|
|
251
|
+
created_at: now,
|
|
252
|
+
updated_at: now,
|
|
253
|
+
source_session_id: sessionID === exports.ORPHAN_SESSION ? undefined : sessionID,
|
|
254
|
+
};
|
|
255
|
+
try {
|
|
256
|
+
// If this insight conflicts with an existing memory, supersede the old one
|
|
257
|
+
if (classification.kind === 'conflict' && classification.conflictTarget) {
|
|
258
|
+
this.store.markSuperseded(classification.conflictTarget, unit.id);
|
|
259
|
+
result.superseded++;
|
|
260
|
+
}
|
|
261
|
+
await this.store.write(unit);
|
|
262
|
+
result.distilled++;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
result.failed++;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// Mark the batch reflected once the LLM produced a parseable result —
|
|
269
|
+
// regardless of dedup/partial write failures. The episodes were processed;
|
|
270
|
+
// retrying them would only re-extract the same (deduped) insights. Only a
|
|
271
|
+
// hard LLM failure (no insights at all) keeps them pending.
|
|
272
|
+
if (insights.length > 0) {
|
|
273
|
+
this.opts.cursor.markReflected(sessionID, episodes.map((e) => e.id));
|
|
274
|
+
}
|
|
275
|
+
result.sessions = insights.length > 0 ? 1 : 0;
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Reflect all sessions with unreflected episodes (daily cron). Each session
|
|
280
|
+
* goes through the exclusive gate so concurrent triggers (restore, manual)
|
|
281
|
+
* can never double-process the same episodes on the same worker.
|
|
282
|
+
*/
|
|
283
|
+
async runAll() {
|
|
284
|
+
const total = { sessions: 0, reviewed: 0, distilled: 0, deduped: 0, superseded: 0, failed: 0, pendingSessions: 0 };
|
|
285
|
+
const bySession = unreflectedBySession(this.opts.index, this.opts.cursor, this.opts.maxEpisodicPerSession ?? 100);
|
|
286
|
+
const exclusive = this.opts.exclusive ?? ((_sessionID, fn) => fn());
|
|
287
|
+
for (const [sessionID, episodes] of bySession) {
|
|
288
|
+
const res = await exclusive(sessionID, async () => {
|
|
289
|
+
return this.reflectSession(sessionID, episodes);
|
|
290
|
+
});
|
|
291
|
+
const r = res;
|
|
292
|
+
total.sessions += r.sessions;
|
|
293
|
+
total.reviewed += r.reviewed;
|
|
294
|
+
total.distilled += r.distilled;
|
|
295
|
+
total.deduped += r.deduped;
|
|
296
|
+
total.superseded += r.superseded;
|
|
297
|
+
total.failed += r.failed;
|
|
298
|
+
}
|
|
299
|
+
// Maintenance: drop reflected ids that no longer exist in the index so the
|
|
300
|
+
// bounded per-session list never re-exposes stale episodes.
|
|
301
|
+
this.opts.cursor.prune(new Set(this.opts.index.getIndex().entries.map((e) => e.id)));
|
|
302
|
+
return total;
|
|
303
|
+
}
|
|
304
|
+
/** Reflect a single session (restoreWorkerState / shouldReflect path). */
|
|
305
|
+
async runSession(sessionID) {
|
|
306
|
+
const bySession = unreflectedBySession(this.opts.index, this.opts.cursor, this.opts.maxEpisodicPerSession ?? 100);
|
|
307
|
+
const episodes = bySession.get(sessionID);
|
|
308
|
+
if (!episodes || episodes.length === 0)
|
|
309
|
+
return { sessions: 0, reviewed: 0, distilled: 0, deduped: 0, superseded: 0, failed: 0, pendingSessions: 0 };
|
|
310
|
+
return this.reflectSession(sessionID, episodes);
|
|
311
|
+
}
|
|
312
|
+
/** Number of unreflected episodes for a session (shouldReflect gate). */
|
|
313
|
+
pendingFor(sessionID) {
|
|
314
|
+
const bySession = unreflectedBySession(this.opts.index, this.opts.cursor, this.opts.maxEpisodicPerSession ?? 100);
|
|
315
|
+
return bySession.get(sessionID)?.length ?? 0;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
exports.ReflectionPipeline = ReflectionPipeline;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionWorkerPool = void 0;
|
|
4
|
+
// Per-session worker pool: every active session gets its own extract and
|
|
5
|
+
// reflect MemoryWorker (background Observer/Reflector pair). Entries are
|
|
6
|
+
// lazily created, TTL-refreshed on access, and disposed on eviction (24h idle
|
|
7
|
+
// or hard-cap overflow). runExclusive serializes pipeline work per
|
|
8
|
+
// (session, kind) so concurrent triggers (cron + restore + manual) can never
|
|
9
|
+
// run the same worker twice at once.
|
|
10
|
+
const ttl_map_1 = require("./ttl-map");
|
|
11
|
+
const memory_worker_1 = require("./memory-worker");
|
|
12
|
+
class SessionWorkerPool {
|
|
13
|
+
opts;
|
|
14
|
+
entries;
|
|
15
|
+
inflight = new Map();
|
|
16
|
+
creationOrder = [];
|
|
17
|
+
constructor(opts) {
|
|
18
|
+
this.opts = opts;
|
|
19
|
+
const ttlMs = opts.ttlMs;
|
|
20
|
+
this.entries = new ttl_map_1.TtlMap(ttlMs, {
|
|
21
|
+
onEvict: (_key, pair) => {
|
|
22
|
+
void pair.extract.dispose();
|
|
23
|
+
void pair.reflect.dispose();
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
maxSessions() {
|
|
28
|
+
return this.opts.maxSessions ?? 64;
|
|
29
|
+
}
|
|
30
|
+
/** Get (or lazily create) the worker for a session. Touches the TTL. */
|
|
31
|
+
getWorker(sessionID, kind) {
|
|
32
|
+
this.entries.sweep(); // release idle/expired sessions before serving one
|
|
33
|
+
let pair = this.entries.getAndTouch(sessionID, this.opts.ttlMs);
|
|
34
|
+
if (!pair) {
|
|
35
|
+
// Hard cap: evict the oldest entry that is not mid-flight (never kill a
|
|
36
|
+
// worker whose prompt is in progress — that degrades to fallback/retry).
|
|
37
|
+
while (this.entries.size() >= this.maxSessions()) {
|
|
38
|
+
const idx = this.creationOrder.findIndex((id) => id !== sessionID && !this.isRunning(id, 'extract') && !this.isRunning(id, 'reflect'));
|
|
39
|
+
if (idx === -1)
|
|
40
|
+
break; // everything in flight → accept the overflow
|
|
41
|
+
const oldest = this.creationOrder.splice(idx, 1)[0];
|
|
42
|
+
this.entries.delete(oldest);
|
|
43
|
+
}
|
|
44
|
+
const label = `mem-${sessionID}`;
|
|
45
|
+
pair = {
|
|
46
|
+
extract: new memory_worker_1.MemoryWorker(this.opts.client, {
|
|
47
|
+
directory: this.opts.directory,
|
|
48
|
+
label: `${label}:extract`,
|
|
49
|
+
compactIdleMs: this.opts.compactIdleMs,
|
|
50
|
+
onSessionCreated: this.opts.onSessionCreated
|
|
51
|
+
? (sid) => this.opts.onSessionCreated(sid, 'extract')
|
|
52
|
+
: undefined,
|
|
53
|
+
}),
|
|
54
|
+
reflect: new memory_worker_1.MemoryWorker(this.opts.client, {
|
|
55
|
+
directory: this.opts.directory,
|
|
56
|
+
label: `${label}:reflect`,
|
|
57
|
+
compactIdleMs: this.opts.compactIdleMs,
|
|
58
|
+
onSessionCreated: this.opts.onSessionCreated
|
|
59
|
+
? (sid) => this.opts.onSessionCreated(sid, 'reflect')
|
|
60
|
+
: undefined,
|
|
61
|
+
}),
|
|
62
|
+
label,
|
|
63
|
+
};
|
|
64
|
+
this.entries.set(sessionID, pair, this.opts.ttlMs);
|
|
65
|
+
this.creationOrder.push(sessionID);
|
|
66
|
+
}
|
|
67
|
+
return kind === 'extract' ? pair.extract : pair.reflect;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Serialize work per (session, kind): if a run is already in flight for the
|
|
71
|
+
* same key, the new call awaits the existing one instead of starting a
|
|
72
|
+
* second concurrent run (prevents duplicate extraction / cursor races).
|
|
73
|
+
*/
|
|
74
|
+
runExclusive(sessionID, kind, fn) {
|
|
75
|
+
const key = `${sessionID}:${kind}`;
|
|
76
|
+
const prev = this.inflight.get(key);
|
|
77
|
+
if (prev)
|
|
78
|
+
return prev;
|
|
79
|
+
const run = fn().finally(() => {
|
|
80
|
+
if (this.inflight.get(key) === run)
|
|
81
|
+
this.inflight.delete(key);
|
|
82
|
+
});
|
|
83
|
+
this.inflight.set(key, run);
|
|
84
|
+
return run;
|
|
85
|
+
}
|
|
86
|
+
isRunning(sessionID, kind) {
|
|
87
|
+
return this.inflight.has(`${sessionID}:${kind}`);
|
|
88
|
+
}
|
|
89
|
+
size() {
|
|
90
|
+
return this.entries.size();
|
|
91
|
+
}
|
|
92
|
+
/** Dispose every worker (gateway stop / restart). */
|
|
93
|
+
disposeAll() {
|
|
94
|
+
this.entries.clear(); // onEvict disposes pairs
|
|
95
|
+
this.inflight.clear();
|
|
96
|
+
this.creationOrder = [];
|
|
97
|
+
return Promise.resolve();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
exports.SessionWorkerPool = SessionWorkerPool;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StaleVerifyPipeline = exports.STALE_VERIFY_SYSTEM = void 0;
|
|
4
|
+
const memory_curator_agent_1 = require("../skills/memory-curator-agent");
|
|
5
|
+
exports.STALE_VERIFY_SYSTEM = `You are the stale-memory reviewer for the harmonic memory system.
|
|
6
|
+
You receive a list of existing long-term memories. Re-verify each one against the CURRENT environment using read/grep/glob/ls (read-only):
|
|
7
|
+
- still true → do nothing.
|
|
8
|
+
- contradicted by the environment → write the corrected version with mafw_add_memory, passing the old memory's id in its supersedes field (or call mafw_supersede_memory on the old id when there is nothing worth replacing it with).
|
|
9
|
+
- not verifiable with read-only tools (preferences, past events, opinions) → skip it.
|
|
10
|
+
Spend at most 3 probes per memory. Probing verifies a memory; it never continues the work the memory describes.
|
|
11
|
+
${memory_curator_agent_1.HARD_BOUNDARIES}
|
|
12
|
+
|
|
13
|
+
After processing, ALWAYS end your response with exactly one line:
|
|
14
|
+
[STALE-REVIEW: checked=N superseded=M]
|
|
15
|
+
This line MUST be the very last line of your response.`;
|
|
16
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
17
|
+
class StaleVerifyPipeline {
|
|
18
|
+
opts;
|
|
19
|
+
constructor(opts) {
|
|
20
|
+
this.opts = opts;
|
|
21
|
+
}
|
|
22
|
+
/** High-value, drift-exposed memories: procedural/semantic, live (not
|
|
23
|
+
* superseded), older than minAgeDays, ranked by energy × salience. */
|
|
24
|
+
selectCandidates() {
|
|
25
|
+
const now = this.opts.now ?? Date.now();
|
|
26
|
+
const topK = this.opts.topK ?? 10;
|
|
27
|
+
const minAgeDays = this.opts.minAgeDays ?? 14;
|
|
28
|
+
return this.opts.index
|
|
29
|
+
.getIndex()
|
|
30
|
+
.entries.filter((e) => (e.type === 'procedural' || e.type === 'semantic') && !e.superseded_by)
|
|
31
|
+
.filter((e) => {
|
|
32
|
+
const created = e.created_at ? new Date(e.created_at).getTime() : 0;
|
|
33
|
+
return created > 0 && now - created >= minAgeDays * DAY_MS;
|
|
34
|
+
})
|
|
35
|
+
.sort((a, b) => b.energy * (b.salience ?? 1) - a.energy * (a.salience ?? 1))
|
|
36
|
+
.slice(0, topK);
|
|
37
|
+
}
|
|
38
|
+
async runOnce() {
|
|
39
|
+
const candidates = this.selectCandidates();
|
|
40
|
+
const result = {
|
|
41
|
+
candidates: candidates.length,
|
|
42
|
+
checked: 0,
|
|
43
|
+
superseded: 0,
|
|
44
|
+
failed: false,
|
|
45
|
+
};
|
|
46
|
+
if (candidates.length === 0)
|
|
47
|
+
return result;
|
|
48
|
+
const blocks = [];
|
|
49
|
+
for (const c of candidates) {
|
|
50
|
+
const unit = await this.opts.readMemory(c.id).catch(() => null);
|
|
51
|
+
if (!unit)
|
|
52
|
+
continue;
|
|
53
|
+
blocks.push(`---\nid: ${c.id}\ntype: ${c.type}\ncontent:\n${unit.memory_value}`);
|
|
54
|
+
}
|
|
55
|
+
if (blocks.length === 0)
|
|
56
|
+
return result;
|
|
57
|
+
const prompt = `Re-verify the following ${blocks.length} memories against the current environment:\n\n${blocks.join('\n')}`;
|
|
58
|
+
try {
|
|
59
|
+
const reply = await this.opts.worker.prompt(prompt, exports.STALE_VERIFY_SYSTEM, this.opts.workerModel, 'memory-curator');
|
|
60
|
+
const m = reply.match(/\[STALE-REVIEW:\s*checked=(\d+)\s+superseded=(\d+)\s*\]/);
|
|
61
|
+
if (m) {
|
|
62
|
+
result.checked = parseInt(m[1], 10);
|
|
63
|
+
result.superseded = parseInt(m[2], 10);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
result.failed = true;
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.StaleVerifyPipeline = StaleVerifyPipeline;
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StepInjectState = exports.FINISHED_EXCLUSIONS = void 0;
|
|
4
|
+
exports.defaultStepInjectOptions = defaultStepInjectOptions;
|
|
5
|
+
exports.stepPropsFromPartUpdated = stepPropsFromPartUpdated;
|
|
6
|
+
exports.stepPropsFromMessageUpdated = stepPropsFromMessageUpdated;
|
|
7
|
+
exports.shouldConsiderStep = shouldConsiderStep;
|
|
8
|
+
exports.selectMemories = selectMemories;
|
|
9
|
+
exports.memoryFingerprint = memoryFingerprint;
|
|
10
|
+
// Step-ended memory injection (path 1): on a settled LLM step, search high
|
|
11
|
+
// salience memories and, after the session goes idle, promptAsync them back
|
|
12
|
+
// into the session as a memory block so the agent can act on them.
|
|
13
|
+
//
|
|
14
|
+
// Concurrency model: every method below is synchronous — no await in between
|
|
15
|
+
// state reads/writes, so Node's single thread makes each call atomic. Awaiting
|
|
16
|
+
// happens only in the caller (search, promptAsync) and never while holding
|
|
17
|
+
// state. Mark-before-async (markStepSeen) prevents duplicate evaluation when
|
|
18
|
+
// concurrent step.ended events arrive during an await.
|
|
19
|
+
const ttl_map_1 = require("./ttl-map");
|
|
20
|
+
exports.FINISHED_EXCLUSIONS = ['tool-calls', 'unknown'];
|
|
21
|
+
function defaultStepInjectOptions() {
|
|
22
|
+
return {
|
|
23
|
+
queueCap: 3,
|
|
24
|
+
intervalMs: 15 * 60 * 1000,
|
|
25
|
+
ttlMs: 24 * 60 * 60 * 1000,
|
|
26
|
+
threshold: 0.7,
|
|
27
|
+
maxMemories: 2,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// opencode ≥1.18 no longer publishes `session.next.step.ended`. Steps settle as
|
|
31
|
+
// `step-finish` parts carried by `message.part.updated`. Messages also emit
|
|
32
|
+
// `message.updated` with `info.role='assistant'` and `info.time.completed` once
|
|
33
|
+
// the final assistant message is settled. These helpers normalize both shapes
|
|
34
|
+
// back into the old StepEndedProps contract.
|
|
35
|
+
function stepPropsFromPartUpdated(props) {
|
|
36
|
+
const part = props?.part;
|
|
37
|
+
if (!part || part.type !== 'step-finish')
|
|
38
|
+
return null;
|
|
39
|
+
return {
|
|
40
|
+
sessionID: part.sessionID,
|
|
41
|
+
assistantMessageID: part.messageID,
|
|
42
|
+
finish: part.reason,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function stepPropsFromMessageUpdated(props) {
|
|
46
|
+
const info = props?.info;
|
|
47
|
+
if (!info || info.role !== 'assistant' || !info.time?.completed)
|
|
48
|
+
return null;
|
|
49
|
+
return {
|
|
50
|
+
sessionID: info.sessionID,
|
|
51
|
+
assistantMessageID: info.id,
|
|
52
|
+
finish: info.finish,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function shouldConsiderStep(props) {
|
|
56
|
+
if (!props.sessionID || !props.assistantMessageID)
|
|
57
|
+
return false;
|
|
58
|
+
if (exports.FINISHED_EXCLUSIONS.includes(props.finish || ''))
|
|
59
|
+
return false;
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
function selectMemories(results, threshold, max) {
|
|
63
|
+
return results
|
|
64
|
+
.filter((r) => r.energy >= threshold)
|
|
65
|
+
.sort((a, b) => b.energy - a.energy)
|
|
66
|
+
.slice(0, max);
|
|
67
|
+
}
|
|
68
|
+
/** Fingerprint of a memory group by sorted IDs — not block text, so dynamic
|
|
69
|
+
* content (timestamps etc.) never defeats dedup. */
|
|
70
|
+
function memoryFingerprint(memIds) {
|
|
71
|
+
return [...memIds].sort().join('|');
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* All per-session state for step injection. Every method is synchronous; the
|
|
75
|
+
* caller owns all awaiting. Entries expire via TtlMap (idle/ended sessions
|
|
76
|
+
* are released, not leaked).
|
|
77
|
+
*/
|
|
78
|
+
class StepInjectState {
|
|
79
|
+
opts;
|
|
80
|
+
queue = new ttl_map_1.TtlMap();
|
|
81
|
+
lastInjectedAt = new ttl_map_1.TtlMap();
|
|
82
|
+
seenSteps = new ttl_map_1.TtlMap();
|
|
83
|
+
seenFingerprints = new ttl_map_1.TtlMap();
|
|
84
|
+
pushedMemories = new ttl_map_1.TtlMap();
|
|
85
|
+
constructor(opts) {
|
|
86
|
+
this.opts = opts;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* B1 mark-before-async: returns true only the first time this assistant
|
|
90
|
+
* message ID is evaluated; call it *before* any await so concurrent
|
|
91
|
+
* duplicate step.ended events are dropped.
|
|
92
|
+
*/
|
|
93
|
+
markStepSeen(sessionID, assistantMessageID) {
|
|
94
|
+
let set = this.seenSteps.get(sessionID);
|
|
95
|
+
if (!set) {
|
|
96
|
+
set = new Set();
|
|
97
|
+
this.seenSteps.set(sessionID, set);
|
|
98
|
+
}
|
|
99
|
+
if (set.has(assistantMessageID))
|
|
100
|
+
return false;
|
|
101
|
+
set.add(assistantMessageID);
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
/** True if this memory group was already injected this session (fingerprint dedup). */
|
|
105
|
+
fingerprintSeen(sessionID, fp) {
|
|
106
|
+
const set = this.seenFingerprints.get(sessionID);
|
|
107
|
+
return !!set && set.has(fp);
|
|
108
|
+
}
|
|
109
|
+
rememberFingerprint(sessionID, fp) {
|
|
110
|
+
let set = this.seenFingerprints.get(sessionID);
|
|
111
|
+
if (!set) {
|
|
112
|
+
set = new Set();
|
|
113
|
+
this.seenFingerprints.set(sessionID, set);
|
|
114
|
+
}
|
|
115
|
+
set.add(fp);
|
|
116
|
+
}
|
|
117
|
+
enqueue(sessionID, injection) {
|
|
118
|
+
let list = this.queue.get(sessionID);
|
|
119
|
+
if (!list) {
|
|
120
|
+
list = [];
|
|
121
|
+
this.queue.set(sessionID, list);
|
|
122
|
+
}
|
|
123
|
+
if (list.length >= this.opts.queueCap) {
|
|
124
|
+
list.shift(); // drop oldest, keep the newest high-value group
|
|
125
|
+
}
|
|
126
|
+
list.push(injection);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* B2 consumption entry: checks the frequency gate first — if the session
|
|
130
|
+
* injected recently, the whole queue is discarded (single log line) instead
|
|
131
|
+
* of failing each entry.
|
|
132
|
+
*/
|
|
133
|
+
consume(sessionID) {
|
|
134
|
+
const list = this.queue.get(sessionID);
|
|
135
|
+
if (!list || list.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
const last = this.lastInjectedAt.get(sessionID);
|
|
138
|
+
if (last !== undefined && Date.now() - last < this.opts.intervalMs) {
|
|
139
|
+
this.queue.delete(sessionID);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
const next = list.shift();
|
|
143
|
+
if (list.length === 0)
|
|
144
|
+
this.queue.delete(sessionID);
|
|
145
|
+
return next ?? null;
|
|
146
|
+
}
|
|
147
|
+
/** B3: register an injected group; the IDs become invisible to /api/recall/context. */
|
|
148
|
+
markInjected(sessionID, memIds, fp) {
|
|
149
|
+
this.lastInjectedAt.set(sessionID, Date.now());
|
|
150
|
+
this.rememberFingerprint(sessionID, fp);
|
|
151
|
+
let set = this.pushedMemories.get(sessionID);
|
|
152
|
+
if (!set) {
|
|
153
|
+
set = new Set();
|
|
154
|
+
this.pushedMemories.set(sessionID, set);
|
|
155
|
+
}
|
|
156
|
+
for (const id of memIds)
|
|
157
|
+
set.add(id);
|
|
158
|
+
}
|
|
159
|
+
/** B3 rollback on promptAsync failure so IDs are never permanently masked. */
|
|
160
|
+
rollbackPushed(sessionID, memIds) {
|
|
161
|
+
const set = this.pushedMemories.get(sessionID);
|
|
162
|
+
if (!set)
|
|
163
|
+
return;
|
|
164
|
+
for (const id of memIds)
|
|
165
|
+
set.delete(id);
|
|
166
|
+
if (set.size === 0)
|
|
167
|
+
this.pushedMemories.delete(sessionID);
|
|
168
|
+
}
|
|
169
|
+
pushedMemoriesFor(sessionID) {
|
|
170
|
+
return this.pushedMemories.get(sessionID) ?? new Set();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
exports.StepInjectState = StepInjectState;
|