@unerr-ai/unerr 0.2.1 → 0.2.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/README.md +36 -45
- package/dist/cli.js +37443 -36022
- package/package.json +2 -1
- package/dist/behaviors/agent-llm-bridge.js +0 -166
- package/dist/behaviors/architecture-guard.js +0 -256
- package/dist/behaviors/auto-doc.js +0 -247
- package/dist/behaviors/cascade-guard.js +0 -289
- package/dist/behaviors/change-narrative.js +0 -270
- package/dist/behaviors/convention-drift.js +0 -290
- package/dist/behaviors/framework.js +0 -235
- package/dist/behaviors/guard-formatter.js +0 -44
- package/dist/behaviors/incomplete-work.js +0 -270
- package/dist/behaviors/loop-breaker.js +0 -300
- package/dist/behaviors/session-continuity.js +0 -208
- package/dist/commands/branches.js +0 -97
- package/dist/commands/check-commit.js +0 -225
- package/dist/commands/compress-output.js +0 -64
- package/dist/commands/config-verify.js +0 -243
- package/dist/commands/daemon.js +0 -905
- package/dist/commands/dashboard.js +0 -52
- package/dist/commands/debug.js +0 -200
- package/dist/commands/enrich.js +0 -184
- package/dist/commands/exec.js +0 -233
- package/dist/commands/gain.js +0 -156
- package/dist/commands/hook.js +0 -88
- package/dist/commands/index.js +0 -88
- package/dist/commands/init.js +0 -74
- package/dist/commands/install.js +0 -505
- package/dist/commands/learn.js +0 -116
- package/dist/commands/manifest.js +0 -193
- package/dist/commands/rewind.js +0 -103
- package/dist/commands/serve.js +0 -19
- package/dist/commands/setup-wizard.js +0 -414
- package/dist/commands/skills.js +0 -64
- package/dist/commands/stats.js +0 -20
- package/dist/commands/status.js +0 -654
- package/dist/commands/timeline.js +0 -139
- package/dist/commands/uninstall.js +0 -230
- package/dist/components/App.js +0 -109
- package/dist/components/Banner.js +0 -12
- package/dist/components/ConfirmPrompt.js +0 -25
- package/dist/components/DriftSummary.js +0 -23
- package/dist/components/GradeBadge.js +0 -15
- package/dist/components/HealthCard.js +0 -18
- package/dist/components/InkSpinner.js +0 -22
- package/dist/components/InputBox.js +0 -17
- package/dist/components/KeyValue.js +0 -13
- package/dist/components/MessageList.js +0 -14
- package/dist/components/ProgressBar.js +0 -26
- package/dist/components/Section.js +0 -16
- package/dist/components/SessionSummaryCard.js +0 -73
- package/dist/components/StartupDisplay.js +0 -24
- package/dist/components/StatusDashboard.js +0 -57
- package/dist/components/StatusLine.js +0 -8
- package/dist/components/StepLine.js +0 -22
- package/dist/components/Theme.js +0 -20
- package/dist/components/ToolProgress.js +0 -8
- package/dist/components/ViolationList.js +0 -21
- package/dist/components/render.js +0 -13
- package/dist/config/agent-registry.js +0 -237
- package/dist/config/claude-settings-hooks.js +0 -304
- package/dist/config/hook-installer.js +0 -65
- package/dist/config/instruction-writer.js +0 -388
- package/dist/config/mcp-config-writer.js +0 -266
- package/dist/config/settings.js +0 -174
- package/dist/config/tool-detector.js +0 -42
- package/dist/config/value-surfacing.js +0 -119
- package/dist/core/context-assembly.js +0 -108
- package/dist/core/conversation.js +0 -33
- package/dist/core/local-chat-provider.js +0 -475
- package/dist/core/provider-factory.js +0 -55
- package/dist/core/providers.js +0 -90
- package/dist/core/query-engine.js +0 -174
- package/dist/daemon/api.js +0 -312
- package/dist/daemon/autostart.js +0 -119
- package/dist/daemon/bootstrap.js +0 -39
- package/dist/daemon/client.js +0 -164
- package/dist/daemon/detect-ci.js +0 -81
- package/dist/daemon/platform-linux.js +0 -146
- package/dist/daemon/platform-macos.js +0 -134
- package/dist/daemon/platform-windows.js +0 -116
- package/dist/daemon/process-manager.js +0 -299
- package/dist/daemon/protocol.js +0 -23
- package/dist/daemon/registry.js +0 -270
- package/dist/daemon/settings-schema.js +0 -72
- package/dist/daemon/system-health.js +0 -134
- package/dist/daemon/version-checker.js +0 -262
- package/dist/daemon/warm-start.js +0 -223
- package/dist/entrypoints/cli.js +0 -1043
- package/dist/entrypoints/daemon.js +0 -380
- package/dist/entrypoints/repl.js +0 -147
- package/dist/hooks/adapters/claude-code.js +0 -90
- package/dist/hooks/adapters/cline.js +0 -100
- package/dist/hooks/adapters/cursor.js +0 -98
- package/dist/hooks/hook-dedup.js +0 -79
- package/dist/hooks/hook-runner.js +0 -113
- package/dist/hooks/navigation-hooks.js +0 -175
- package/dist/hooks/prompt-hooks.js +0 -63
- package/dist/hooks/shell-hooks.js +0 -47
- package/dist/ignore.js +0 -111
- package/dist/intelligence/approach-suggester.js +0 -61
- package/dist/intelligence/ast-extractor.js +0 -2615
- package/dist/intelligence/ast-worker.js +0 -34
- package/dist/intelligence/background-indexer.js +0 -121
- package/dist/intelligence/blast-radius.js +0 -200
- package/dist/intelligence/community-detection.js +0 -691
- package/dist/intelligence/community-detector.js +0 -184
- package/dist/intelligence/computation-scheduler.js +0 -75
- package/dist/intelligence/confidence-propagation.js +0 -47
- package/dist/intelligence/convention-detector.js +0 -242
- package/dist/intelligence/convention-learner.js +0 -205
- package/dist/intelligence/convention-matcher.js +0 -205
- package/dist/intelligence/cozo-schema.js +0 -376
- package/dist/intelligence/decision-point-detector.js +0 -90
- package/dist/intelligence/deep-dive-tools.js +0 -586
- package/dist/intelligence/durability-scorer.js +0 -84
- package/dist/intelligence/exploration-cost.js +0 -204
- package/dist/intelligence/exploration-pattern-tracker.js +0 -61
- package/dist/intelligence/fact-generator.js +0 -322
- package/dist/intelligence/facts-schema.js +0 -90
- package/dist/intelligence/file-intelligence.js +0 -59
- package/dist/intelligence/graph-holder.js +0 -220
- package/dist/intelligence/graph-temporal-joiner.js +0 -238
- package/dist/intelligence/health-grade.js +0 -423
- package/dist/intelligence/health-grader.js +0 -200
- package/dist/intelligence/health-map-data.js +0 -259
- package/dist/intelligence/import-symbols.js +0 -136
- package/dist/intelligence/incremental-indexer.js +0 -658
- package/dist/intelligence/indexer/centrality.js +0 -62
- package/dist/intelligence/indexer/cfg-context.js +0 -95
- package/dist/intelligence/indexer/confidence.js +0 -34
- package/dist/intelligence/indexer/cross-file-resolver.js +0 -104
- package/dist/intelligence/indexer/edge-repair.js +0 -89
- package/dist/intelligence/indexer/entity-key.js +0 -17
- package/dist/intelligence/indexer/export-map.js +0 -132
- package/dist/intelligence/indexer/git-cochange.js +0 -128
- package/dist/intelligence/indexer/graph-patch.js +0 -147
- package/dist/intelligence/indexer/incremental.js +0 -78
- package/dist/intelligence/indexer/ingest.js +0 -160
- package/dist/intelligence/indexer/language-detect.js +0 -226
- package/dist/intelligence/indexer/metadata.js +0 -63
- package/dist/intelligence/indexer/mutation-tracker.js +0 -79
- package/dist/intelligence/indexer/orchestrator.js +0 -155
- package/dist/intelligence/indexer/plugin-interface.js +0 -31
- package/dist/intelligence/indexer/plugins/csharp.js +0 -440
- package/dist/intelligence/indexer/plugins/go.js +0 -335
- package/dist/intelligence/indexer/plugins/java.js +0 -370
- package/dist/intelligence/indexer/plugins/python.js +0 -358
- package/dist/intelligence/indexer/plugins/regex-fallback.js +0 -82
- package/dist/intelligence/indexer/plugins/ruby.js +0 -290
- package/dist/intelligence/indexer/plugins/rust.js +0 -484
- package/dist/intelligence/indexer/plugins/tier2-generic.js +0 -310
- package/dist/intelligence/indexer/plugins/typescript.js +0 -456
- package/dist/intelligence/indexer/resource-monitor.js +0 -93
- package/dist/intelligence/indexer/scip/decoder.js +0 -253
- package/dist/intelligence/indexer/scip/detector.js +0 -232
- package/dist/intelligence/indexer/scip/downloader.js +0 -427
- package/dist/intelligence/indexer/scip/fallback.js +0 -34
- package/dist/intelligence/indexer/scip/merger.js +0 -109
- package/dist/intelligence/indexer/scip/orchestrator.js +0 -433
- package/dist/intelligence/indexer/scip/runner.js +0 -98
- package/dist/intelligence/indexer/snapshot.js +0 -66
- package/dist/intelligence/indexer/test-detector.js +0 -196
- package/dist/intelligence/indexer/watch-integration.js +0 -61
- package/dist/intelligence/indexer/worker.js +0 -85
- package/dist/intelligence/local-convention-detector.js +0 -437
- package/dist/intelligence/local-embeddings.js +0 -190
- package/dist/intelligence/local-graph.js +0 -1946
- package/dist/intelligence/local-indexer.js +0 -1575
- package/dist/intelligence/local-llm.js +0 -163
- package/dist/intelligence/local-rule-generator.js +0 -154
- package/dist/intelligence/local-snapshot.js +0 -213
- package/dist/intelligence/negative-knowledge.js +0 -103
- package/dist/intelligence/persistent-db.js +0 -85
- package/dist/intelligence/query-router.js +0 -2556
- package/dist/intelligence/risk-classifier.js +0 -116
- package/dist/intelligence/rule-evaluator.js +0 -380
- package/dist/intelligence/rule-generator.js +0 -49
- package/dist/intelligence/search-index.js +0 -173
- package/dist/intelligence/semantic/docstring-extractor.js +0 -67
- package/dist/intelligence/semantic/embedding-store.js +0 -52
- package/dist/intelligence/semantic/enrichment-orchestrator.js +0 -48
- package/dist/intelligence/semantic/git-message-miner.js +0 -114
- package/dist/intelligence/semantic/identifier-tokenizer.js +0 -51
- package/dist/intelligence/semantic/node2vec-embeddings.js +0 -71
- package/dist/intelligence/semantic/node2vec-walks.js +0 -103
- package/dist/intelligence/semantic/path-domain-inference.js +0 -112
- package/dist/intelligence/semantic/similarity-engine.js +0 -60
- package/dist/intelligence/semantic/tfidf-vectors.js +0 -88
- package/dist/intelligence/session-brief-builder.js +0 -159
- package/dist/intelligence/session-context.js +0 -221
- package/dist/intelligence/session-health-monitor.js +0 -211
- package/dist/intelligence/session-narrative.js +0 -197
- package/dist/intelligence/session-pattern-analyzer.js +0 -218
- package/dist/intelligence/signal-scorer.js +0 -390
- package/dist/intelligence/signal-show-store.js +0 -182
- package/dist/intelligence/smart-truncate.js +0 -158
- package/dist/intelligence/subgraph-cache.js +0 -88
- package/dist/intelligence/temporal-facts.js +0 -494
- package/dist/intelligence/token-estimator.js +0 -100
- package/dist/intelligence/tool-injector.js +0 -87
- package/dist/intelligence/tree-sitter-loader.js +0 -71
- package/dist/intelligence/worker-pool.js +0 -116
- package/dist/proxy/arg-validator.js +0 -79
- package/dist/proxy/auto-bootstrap.js +0 -167
- package/dist/proxy/bridge.js +0 -147
- package/dist/proxy/budget-enforcer.js +0 -70
- package/dist/proxy/compression-quality-monitor.js +0 -160
- package/dist/proxy/compression-stats.js +0 -51
- package/dist/proxy/context-rot-detector.js +0 -137
- package/dist/proxy/drift-detector.js +0 -139
- package/dist/proxy/efficiency-tracker.js +0 -79
- package/dist/proxy/fact-ranking.js +0 -154
- package/dist/proxy/format-encoder.js +0 -266
- package/dist/proxy/http-transport.js +0 -90
- package/dist/proxy/lifecycle-actor.js +0 -55
- package/dist/proxy/lifecycle-machine.js +0 -187
- package/dist/proxy/log-tailer.js +0 -265
- package/dist/proxy/model-pricing.js +0 -98
- package/dist/proxy/network-firewall.js +0 -141
- package/dist/proxy/nudge-state.js +0 -93
- package/dist/proxy/output-compressor.js +0 -185
- package/dist/proxy/pid-lock.js +0 -291
- package/dist/proxy/proxy-context.js +0 -11
- package/dist/proxy/proxy.js +0 -2633
- package/dist/proxy/response-enrichment.js +0 -32
- package/dist/proxy/response-envelope.js +0 -313
- package/dist/proxy/session-dedup.js +0 -82
- package/dist/proxy/session-legend.js +0 -30
- package/dist/proxy/session-persistence.js +0 -210
- package/dist/proxy/session-resume.js +0 -94
- package/dist/proxy/session-stats.js +0 -513
- package/dist/proxy/shell-classifier.js +0 -1346
- package/dist/proxy/shell-compression-log.js +0 -93
- package/dist/proxy/shell-compressor.js +0 -390
- package/dist/proxy/shell-graph-boost.js +0 -202
- package/dist/proxy/shell-monitor-map.js +0 -18
- package/dist/proxy/shell-stats.js +0 -54
- package/dist/proxy/shell-strategies/cloud.js +0 -215
- package/dist/proxy/shell-strategies/diff.js +0 -159
- package/dist/proxy/shell-strategies/error-diagnostic.js +0 -796
- package/dist/proxy/shell-strategies/filter-dsl.js +0 -358
- package/dist/proxy/shell-strategies/git-status.js +0 -177
- package/dist/proxy/shell-strategies/key-value.js +0 -193
- package/dist/proxy/shell-strategies/log-text.js +0 -154
- package/dist/proxy/shell-strategies/omni.js +0 -188
- package/dist/proxy/shell-strategies/progress.js +0 -55
- package/dist/proxy/shell-strategies/redact.js +0 -76
- package/dist/proxy/shell-strategies/structured.js +0 -241
- package/dist/proxy/shell-strategies/tabular.js +0 -243
- package/dist/proxy/shell-strategies/test-results-types.js +0 -13
- package/dist/proxy/shell-strategies/test-results.js +0 -784
- package/dist/proxy/shell-strategies/tree-paths.js +0 -144
- package/dist/proxy/shell-strategies/yaml.js +0 -182
- package/dist/proxy/shell-tee.js +0 -111
- package/dist/proxy/signal-dedup.js +0 -171
- package/dist/proxy/startup-renderer.js +0 -158
- package/dist/proxy/task-token-display.js +0 -38
- package/dist/proxy/token-counter.js +0 -61
- package/dist/proxy/tool-clusters.js +0 -273
- package/dist/proxy/tool-definitions.js +0 -525
- package/dist/proxy/transport-mux.js +0 -229
- package/dist/proxy/wire-cap.js +0 -268
- package/dist/rules/developer.mozilla.org.json +0 -9
- package/dist/rules/github.com.json +0 -21
- package/dist/schemas/api/skills.js +0 -19
- package/dist/schemas/common/errors.js +0 -7
- package/dist/schemas/common/headers.js +0 -5
- package/dist/schemas/entities/edge.js +0 -25
- package/dist/schemas/entities/entity.js +0 -22
- package/dist/schemas/entities/rule.js +0 -18
- package/dist/schemas/index.js +0 -14
- package/dist/server/event-bus.js +0 -59
- package/dist/server/http.js +0 -156
- package/dist/server/middleware.js +0 -70
- package/dist/server/routes/drift.js +0 -97
- package/dist/server/routes/intelligence.js +0 -1217
- package/dist/server/routes/reasoning-quality.js +0 -444
- package/dist/server/routes/session.js +0 -86
- package/dist/server/routes/stream.js +0 -120
- package/dist/server/routes/system.js +0 -73
- package/dist/server/routes/temporal.js +0 -170
- package/dist/server/routes/timeline.js +0 -232
- package/dist/server/routes/token-flow.js +0 -403
- package/dist/skills/effectiveness-tracker.js +0 -93
- package/dist/skills/local-pack.js +0 -380
- package/dist/skills/resolver.js +0 -495
- package/dist/state-detector.js +0 -83
- package/dist/timeline/intent-detector.js +0 -263
- package/dist/timeline/loop-miner.js +0 -140
- package/dist/timeline/open-threads.js +0 -49
- package/dist/timeline/signal-reinforcer.js +0 -62
- package/dist/timeline/timeline-bootstrap.js +0 -151
- package/dist/timeline/timeline-store.js +0 -618
- package/dist/tools/coding/bash.js +0 -49
- package/dist/tools/coding/file-edit.js +0 -72
- package/dist/tools/coding/file-outline.js +0 -227
- package/dist/tools/coding/file-read-protocol.js +0 -425
- package/dist/tools/coding/file-read.js +0 -35
- package/dist/tools/coding/file-write.js +0 -43
- package/dist/tools/coding/glob-tool.js +0 -109
- package/dist/tools/coding/grep.js +0 -162
- package/dist/tools/coding/index.js +0 -27
- package/dist/tools/intelligence/index.js +0 -269
- package/dist/tools/intelligence/record-fact.js +0 -48
- package/dist/tools/intelligence/timeline-markers.js +0 -130
- package/dist/tools/registry.js +0 -47
- package/dist/tools/types.js +0 -8
- package/dist/tracking/auto-snapshot-triggers.js +0 -246
- package/dist/tracking/branch-context.js +0 -115
- package/dist/tracking/branch-snapshot.js +0 -217
- package/dist/tracking/causal-bridge.js +0 -317
- package/dist/tracking/circuit-breaker.js +0 -147
- package/dist/tracking/commit-watcher.js +0 -114
- package/dist/tracking/context-ledger.js +0 -119
- package/dist/tracking/correction-detector.js +0 -324
- package/dist/tracking/drift-tracker.js +0 -874
- package/dist/tracking/durability-tracker.js +0 -94
- package/dist/tracking/entity-rewind.js +0 -200
- package/dist/tracking/file-hash-state.js +0 -114
- package/dist/tracking/git-attribution.js +0 -132
- package/dist/tracking/git-trailers.js +0 -171
- package/dist/tracking/intelligence-counter.js +0 -46
- package/dist/tracking/intent-correlator.js +0 -202
- package/dist/tracking/intent-encoder.js +0 -52
- package/dist/tracking/intent-token-tracker.js +0 -159
- package/dist/tracking/ledger-archiver.js +0 -94
- package/dist/tracking/ledger-chains.js +0 -245
- package/dist/tracking/metrics-store.js +0 -361
- package/dist/tracking/native-watcher.js +0 -131
- package/dist/tracking/offline-rewind.js +0 -295
- package/dist/tracking/pending-violations.js +0 -74
- package/dist/tracking/persistence-effectiveness.js +0 -167
- package/dist/tracking/prompt-durability.js +0 -202
- package/dist/tracking/quality-signals.js +0 -213
- package/dist/tracking/redactor.js +0 -73
- package/dist/tracking/rewind-engine.js +0 -161
- package/dist/tracking/session-history.js +0 -128
- package/dist/tracking/session-receipt.js +0 -88
- package/dist/tracking/session-summary-writer.js +0 -157
- package/dist/tracking/shadow-ledger.js +0 -321
- package/dist/tracking/stash-manager.js +0 -258
- package/dist/tracking/timeline-fork.js +0 -213
- package/dist/tracking/timeline.js +0 -69
- package/dist/tracking/token-flow.js +0 -276
- package/dist/tracking/turn-segmenter.js +0 -122
- package/dist/tracking/weekly-accumulator.js +0 -179
- package/dist/tracking/working-snapshots.js +0 -188
- package/dist/tracking/workspace-manifest.js +0 -176
- package/dist/transport/http.js +0 -102
- package/dist/utils/counterfactual.js +0 -65
- package/dist/utils/deep-link.js +0 -34
- package/dist/utils/detect.js +0 -193
- package/dist/utils/exec.js +0 -73
- package/dist/utils/file-logger.js +0 -87
- package/dist/utils/format-error.js +0 -29
- package/dist/utils/git.js +0 -181
- package/dist/utils/log.js +0 -57
- package/dist/utils/logger.js +0 -35
- package/dist/utils/mcp-content-json.js +0 -8
- package/dist/utils/session-logger.js +0 -154
- package/dist/utils/startup-log.js +0 -512
- package/dist/utils/ui.js +0 -56
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Composite fact ranking — used by both recall_facts handlers (mcp-server.ts +
|
|
3
|
-
* proxy.ts) so they stay in lock-step.
|
|
4
|
-
*
|
|
5
|
-
* Score = effective_confidence × (1 + log2(1 + reinforcements) × 0.3) × type_weight
|
|
6
|
-
*
|
|
7
|
-
* type_weight values codify "how anti-drift is this kind of fact":
|
|
8
|
-
* negative 1.5 (highest — anti-pattern, prevents future failure)
|
|
9
|
-
* convention 1.4 (project standard, must follow)
|
|
10
|
-
* semantic 1.2 (architecture / design context)
|
|
11
|
-
* procedural 1.0 (hot-file, modification pattern — useful but lower priority)
|
|
12
|
-
* episodic 0.8 (session history, lowest — interesting but rarely actionable)
|
|
13
|
-
*/
|
|
14
|
-
const TYPE_WEIGHT = {
|
|
15
|
-
negative: 1.5,
|
|
16
|
-
convention: 1.4,
|
|
17
|
-
semantic: 1.2,
|
|
18
|
-
procedural: 1.0,
|
|
19
|
-
episodic: 0.8,
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Per-type rotation decay coefficient: how aggressively a fact's effective
|
|
23
|
-
* rank drops with each show. Tuned so the *importance* gradient mirrors
|
|
24
|
-
* TYPE_WEIGHT but inverted — anti-patterns must keep surfacing even after
|
|
25
|
-
* being shown (low decay), episodic noise should age out quickly.
|
|
26
|
-
*
|
|
27
|
-
* effective_score = composite_score / (1 + shows × decay)
|
|
28
|
-
*/
|
|
29
|
-
const TYPE_DECAY = {
|
|
30
|
-
negative: 0.3, // must-know — repeat slowly
|
|
31
|
-
convention: 0.4,
|
|
32
|
-
semantic: 0.5,
|
|
33
|
-
procedural: 0.6,
|
|
34
|
-
episodic: 0.8, // session history — fade fast
|
|
35
|
-
};
|
|
36
|
-
export function factTypeWeight(type) {
|
|
37
|
-
return TYPE_WEIGHT[type] ?? 1.0;
|
|
38
|
-
}
|
|
39
|
-
export function factTypeDecay(type) {
|
|
40
|
-
return TYPE_DECAY[type] ?? 0.5;
|
|
41
|
-
}
|
|
42
|
-
export function factScore(f) {
|
|
43
|
-
return (f.effective_confidence *
|
|
44
|
-
(1 + Math.log2(1 + f.reinforcement_count) * 0.3) *
|
|
45
|
-
factTypeWeight(f.fact_type));
|
|
46
|
-
}
|
|
47
|
-
/** Sort facts by composite score descending (does not mutate input). */
|
|
48
|
-
export function rankFacts(facts) {
|
|
49
|
-
return [...facts].sort((a, b) => factScore(b) - factScore(a));
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Cross-channel dedup window: a fact surfaced via `ur|fct` (smuggle channel)
|
|
53
|
-
* gets a temporary score penalty so explicit `recall_facts` calls right after
|
|
54
|
-
* don't dominate top slots with the same fact.
|
|
55
|
-
*
|
|
56
|
-
* Penalty decays linearly from `RECENT_SHOW_PENALTY_MIN` (immediately after a
|
|
57
|
-
* show) up to 1.0 at the edge of `RECENT_SHOW_WINDOW_MS`.
|
|
58
|
-
*/
|
|
59
|
-
export const RECENT_SHOW_WINDOW_MS = 5 * 60 * 1000;
|
|
60
|
-
export const RECENT_SHOW_PENALTY_MIN = 0.3;
|
|
61
|
-
/** Multiplier applied when a fact's subject is in the active-session
|
|
62
|
-
* recency set (gives "current task" facts a gentle nudge above strangers). */
|
|
63
|
-
export const ACTIVE_SUBJECT_BOOST = 1.25;
|
|
64
|
-
/**
|
|
65
|
-
* Rotation-, recency-, and subject-aware ranker for recall_facts.
|
|
66
|
-
*
|
|
67
|
-
* - Per-type decay: anti-patterns repeat slowly, episodic noise fades fast.
|
|
68
|
-
* - Cross-channel dedup: facts smuggled in the last 5 min are penalized.
|
|
69
|
-
* - Active-subject boost: facts about recently-touched entities outrank strangers.
|
|
70
|
-
*
|
|
71
|
-
* Backward compatible: with no options, behaves like rankFacts().
|
|
72
|
-
*/
|
|
73
|
-
export function rankFactsWithRotation(facts, opts = {}) {
|
|
74
|
-
const { getShowCount, getLastShownMs, recentSubjects, now = Date.now(), } = opts;
|
|
75
|
-
if (!getShowCount && !getLastShownMs && !recentSubjects) {
|
|
76
|
-
return rankFacts(facts);
|
|
77
|
-
}
|
|
78
|
-
const scored = facts.map((f) => {
|
|
79
|
-
let score = factScore(f);
|
|
80
|
-
if (getShowCount) {
|
|
81
|
-
const shows = getShowCount(f.fact_id);
|
|
82
|
-
const decay = factTypeDecay(f.fact_type);
|
|
83
|
-
score = score / (1 + shows * decay);
|
|
84
|
-
}
|
|
85
|
-
if (getLastShownMs) {
|
|
86
|
-
const last = getLastShownMs(f.fact_id);
|
|
87
|
-
if (last > 0) {
|
|
88
|
-
const age = now - last;
|
|
89
|
-
if (age < RECENT_SHOW_WINDOW_MS) {
|
|
90
|
-
// Linear: penalty=MIN immediately after, 1.0 at window edge.
|
|
91
|
-
const t = Math.max(0, age) / RECENT_SHOW_WINDOW_MS;
|
|
92
|
-
const factor = RECENT_SHOW_PENALTY_MIN + (1 - RECENT_SHOW_PENALTY_MIN) * t;
|
|
93
|
-
score *= factor;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
if (recentSubjects && f.subject && recentSubjects.has(f.subject)) {
|
|
98
|
-
score *= ACTIVE_SUBJECT_BOOST;
|
|
99
|
-
}
|
|
100
|
-
return { fact: f, score };
|
|
101
|
-
});
|
|
102
|
-
return scored.sort((a, b) => b.score - a.score).map(({ fact }) => fact);
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Slice the ranked list to `limit` while enforcing diversity quotas so a hot
|
|
106
|
-
* file doesn't dominate the top-N with five same-type, same-subject facts.
|
|
107
|
-
*
|
|
108
|
-
* - max 60% of slots same fact_type
|
|
109
|
-
* - max 2 slots per subject
|
|
110
|
-
*
|
|
111
|
-
* Two-pass: first fills slots that satisfy both quotas; second pass relaxes
|
|
112
|
-
* quotas to fill any remaining gaps so we never under-return.
|
|
113
|
-
*/
|
|
114
|
-
export function applyDiversityQuota(ranked, limit, opts = {}) {
|
|
115
|
-
if (ranked.length <= limit)
|
|
116
|
-
return [...ranked];
|
|
117
|
-
const { maxSameTypePct = 0.6, maxSameSubject = 2 } = opts;
|
|
118
|
-
const maxSameType = Math.max(1, Math.floor(limit * maxSameTypePct));
|
|
119
|
-
const result = [];
|
|
120
|
-
const skipped = [];
|
|
121
|
-
const typeCounts = new Map();
|
|
122
|
-
const subjectCounts = new Map();
|
|
123
|
-
for (const f of ranked) {
|
|
124
|
-
if (result.length >= limit)
|
|
125
|
-
break;
|
|
126
|
-
const tc = typeCounts.get(f.fact_type) ?? 0;
|
|
127
|
-
const sc = f.subject ? (subjectCounts.get(f.subject) ?? 0) : 0;
|
|
128
|
-
if (tc >= maxSameType || sc >= maxSameSubject) {
|
|
129
|
-
skipped.push(f);
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
result.push(f);
|
|
133
|
-
typeCounts.set(f.fact_type, tc + 1);
|
|
134
|
-
if (f.subject)
|
|
135
|
-
subjectCounts.set(f.subject, sc + 1);
|
|
136
|
-
}
|
|
137
|
-
for (const f of skipped) {
|
|
138
|
-
if (result.length >= limit)
|
|
139
|
-
break;
|
|
140
|
-
result.push(f);
|
|
141
|
-
}
|
|
142
|
-
return result;
|
|
143
|
-
}
|
|
144
|
-
/**
|
|
145
|
-
* Default visible-cap for recall_facts.
|
|
146
|
-
* Override via `args.limit` (max 25 to keep wire bounded).
|
|
147
|
-
*/
|
|
148
|
-
export const DEFAULT_FACT_LIMIT = 5;
|
|
149
|
-
export const MAX_FACT_LIMIT = 25;
|
|
150
|
-
export function resolveFactLimit(argsLimit) {
|
|
151
|
-
if (typeof argsLimit !== "number" || argsLimit <= 0)
|
|
152
|
-
return DEFAULT_FACT_LIMIT;
|
|
153
|
-
return Math.min(Math.floor(argsLimit), MAX_FACT_LIMIT);
|
|
154
|
-
}
|
|
@@ -1,266 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Layer 6 — shape-aware columnar wire encoding for MCP tool payloads.
|
|
3
|
-
* Sprint FE-C (encoder core) + FE-E (session legends, tier fallback).
|
|
4
|
-
*/
|
|
5
|
-
import { OUTPUT_FORMAT_LEGEND, } from "./session-legend.js";
|
|
6
|
-
export const COLUMNAR_LEGEND_TEXT = "Layer 6 columnar: body starts with _fmt:columnar; next line is pipe-separated headers; following lines are rows in column order. Newlines in cells are escaped as \\\\n. Cells containing | or quotes use CSV-style double quotes.";
|
|
7
|
-
export function isUniformObjectArray(arr) {
|
|
8
|
-
const objects = arr.filter((x) => x !== null && typeof x === "object" && !Array.isArray(x));
|
|
9
|
-
if (objects.length !== arr.length || objects.length === 0)
|
|
10
|
-
return false;
|
|
11
|
-
const firstKeys = new Set(Object.keys(objects[0]));
|
|
12
|
-
for (let i = 1; i < objects.length; i++) {
|
|
13
|
-
const k = new Set(Object.keys(objects[i]));
|
|
14
|
-
if (k.size !== firstKeys.size)
|
|
15
|
-
return false;
|
|
16
|
-
for (const key of firstKeys) {
|
|
17
|
-
if (!k.has(key))
|
|
18
|
-
return false;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
return true;
|
|
22
|
-
}
|
|
23
|
-
export function detectShape(data) {
|
|
24
|
-
if (Array.isArray(data)) {
|
|
25
|
-
if (data.length === 0)
|
|
26
|
-
return "heterogeneous";
|
|
27
|
-
return isUniformObjectArray(data) ? "uniform-array" : "heterogeneous";
|
|
28
|
-
}
|
|
29
|
-
if (data !== null && typeof data === "object" && !(data instanceof Date)) {
|
|
30
|
-
const o = data;
|
|
31
|
-
if (Object.keys(o).length === 0)
|
|
32
|
-
return "heterogeneous";
|
|
33
|
-
return "single-object";
|
|
34
|
-
}
|
|
35
|
-
return "heterogeneous";
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Escape a columnar cell for pipe-separated output.
|
|
39
|
-
* Newlines are replaced with literal \\n (backslash-n) so rows stay on one line.
|
|
40
|
-
* Pipes and double-quotes trigger CSV-style quoting (cell wrapped in `"`).
|
|
41
|
-
*/
|
|
42
|
-
export function escapeColumnarCell(value) {
|
|
43
|
-
if (value === null || value === undefined)
|
|
44
|
-
return "";
|
|
45
|
-
let s = typeof value === "string" ? value : JSON.stringify(value);
|
|
46
|
-
// Flatten newlines FIRST so rows never span multiple lines
|
|
47
|
-
s = s.replace(/\r\n/g, "\\n").replace(/\n/g, "\\n").replace(/\r/g, "\\n");
|
|
48
|
-
// If pipe or double-quote remains, use CSV-style quoting
|
|
49
|
-
if (/[|"]/.test(s)) {
|
|
50
|
-
return `"${s.replace(/"/g, '""')}"`;
|
|
51
|
-
}
|
|
52
|
-
return s;
|
|
53
|
-
}
|
|
54
|
-
export function encodeColumnar(rows, columns) {
|
|
55
|
-
const header = `_fmt:columnar\n${columns.join("|")}`;
|
|
56
|
-
const lines = rows.map((row) => columns.map((c) => escapeColumnarCell(row[c])).join("|"));
|
|
57
|
-
return `${header}\n${lines.join("\n")}`;
|
|
58
|
-
}
|
|
59
|
-
function sortedColumnsFromFirstRow(rows) {
|
|
60
|
-
const first = rows[0];
|
|
61
|
-
if (!first)
|
|
62
|
-
return [];
|
|
63
|
-
return Object.keys(first).sort();
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* P6.2: encode an object with multiple uniform arrays as `_fmt:multi`.
|
|
67
|
-
*
|
|
68
|
-
* Format:
|
|
69
|
-
* _fmt:multi
|
|
70
|
-
* @meta k1=v1|k2=v2|... ← scalars (one line)
|
|
71
|
-
* @<arrayName>[col1|col2|...] ← uniform-object array, columnar
|
|
72
|
-
* val|val|val
|
|
73
|
-
* ...
|
|
74
|
-
* @<arrayName>[] ← string-array (line per item)
|
|
75
|
-
* item
|
|
76
|
-
* item
|
|
77
|
-
*
|
|
78
|
-
* Used when a response has 2+ recognized uniform arrays (file_outline has
|
|
79
|
-
* entities/imports/exports; file_connections has connections/entities).
|
|
80
|
-
*/
|
|
81
|
-
export function encodeMultiSection(scalars, sections) {
|
|
82
|
-
const lines = ["_fmt:multi"];
|
|
83
|
-
// Scalars row
|
|
84
|
-
const scalarPairs = Object.entries(scalars)
|
|
85
|
-
.filter(([, v]) => v !== undefined && v !== null && typeof v !== "object")
|
|
86
|
-
.map(([k, v]) => `${k}=${String(v)}`);
|
|
87
|
-
if (scalarPairs.length > 0) {
|
|
88
|
-
lines.push(`@meta ${scalarPairs.join("|")}`);
|
|
89
|
-
}
|
|
90
|
-
// Sections
|
|
91
|
-
for (const sec of sections) {
|
|
92
|
-
if (sec.items.length === 0) {
|
|
93
|
-
lines.push(`@${sec.name}[]`);
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (sec.kind === "uniform-object") {
|
|
97
|
-
const rows = sec.items;
|
|
98
|
-
const columns = sortedColumnsFromFirstRow(rows);
|
|
99
|
-
lines.push(`@${sec.name}[${columns.join("|")}]`);
|
|
100
|
-
for (const row of rows) {
|
|
101
|
-
lines.push(columns.map((c) => escapeColumnarCell(row[c])).join("|"));
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
// string-list: one item per line
|
|
106
|
-
lines.push(`@${sec.name}[]`);
|
|
107
|
-
for (const item of sec.items) {
|
|
108
|
-
const s = typeof item === "string" ? item : JSON.stringify(item);
|
|
109
|
-
// Flatten newlines so each item stays on one line
|
|
110
|
-
lines.push(s.replace(/\r\n|\n|\r/g, "\\n"));
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return lines.join("\n");
|
|
115
|
-
}
|
|
116
|
-
function isErrorEnvelope(x) {
|
|
117
|
-
return (typeof x === "object" &&
|
|
118
|
-
x !== null &&
|
|
119
|
-
!Array.isArray(x) &&
|
|
120
|
-
"error" in x &&
|
|
121
|
-
typeof x.error === "string");
|
|
122
|
-
}
|
|
123
|
-
function shouldSkipFormatting(meta) {
|
|
124
|
-
return meta.format === "outline" || meta.gated === true;
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Apply columnar encoding to uniform arrays. Mutates `meta.format`, `meta.columns`, legends.
|
|
128
|
-
* Single objects, strings, errors, outline payloads, and heterogeneous data pass through as JSON.
|
|
129
|
-
*/
|
|
130
|
-
export function formatToolOutput(toolName, content, meta, options) {
|
|
131
|
-
void toolName;
|
|
132
|
-
const tier = options?.tier ?? "columnar";
|
|
133
|
-
const legend = options?.legend ?? null;
|
|
134
|
-
// BA-4.3: Attach output format legend once per session (first formatted response)
|
|
135
|
-
if (legend?.consumeOutputFormatLegend()) {
|
|
136
|
-
meta.output_format_legend = OUTPUT_FORMAT_LEGEND;
|
|
137
|
-
}
|
|
138
|
-
if (shouldSkipFormatting(meta))
|
|
139
|
-
return content;
|
|
140
|
-
if (content === null || content === undefined)
|
|
141
|
-
return content;
|
|
142
|
-
if (typeof content === "string")
|
|
143
|
-
return content;
|
|
144
|
-
if (isErrorEnvelope(content))
|
|
145
|
-
return content;
|
|
146
|
-
if (typeof content === "object" &&
|
|
147
|
-
content !== null &&
|
|
148
|
-
"message" in content &&
|
|
149
|
-
("progress" in content || "total" in content) &&
|
|
150
|
-
typeof content.message === "string") {
|
|
151
|
-
return content;
|
|
152
|
-
}
|
|
153
|
-
if (tier === "expanded") {
|
|
154
|
-
meta.format = "json";
|
|
155
|
-
return content;
|
|
156
|
-
}
|
|
157
|
-
const skipColumnar = tier === "minified";
|
|
158
|
-
const shape = detectShape(content);
|
|
159
|
-
const attachColumnarLegend = () => {
|
|
160
|
-
if (legend?.consumeColumnarLegend()) {
|
|
161
|
-
meta.columnar_legend = COLUMNAR_LEGEND_TEXT;
|
|
162
|
-
}
|
|
163
|
-
};
|
|
164
|
-
if (!skipColumnar && shape === "uniform-array" && Array.isArray(content)) {
|
|
165
|
-
const rows = content;
|
|
166
|
-
const columns = sortedColumnsFromFirstRow(rows);
|
|
167
|
-
meta.format = "columnar";
|
|
168
|
-
meta.columns = columns;
|
|
169
|
-
attachColumnarLegend();
|
|
170
|
-
return encodeColumnar(rows, columns);
|
|
171
|
-
}
|
|
172
|
-
// Tier-3 P6.1: extended wrapper detection.
|
|
173
|
-
// Recognize known wrapper-array field names; columnar-encode the array
|
|
174
|
-
// if it's uniform-object AND it's the only array in the wrapper. When
|
|
175
|
-
// multiple arrays coexist (file_outline has entities + imports + exports),
|
|
176
|
-
// bail out — that's P6.2's _fmt:multi job.
|
|
177
|
-
const KNOWN_ARRAY_WRAPPERS = [
|
|
178
|
-
"items",
|
|
179
|
-
"facts",
|
|
180
|
-
"references",
|
|
181
|
-
"connections",
|
|
182
|
-
"entities",
|
|
183
|
-
"imports",
|
|
184
|
-
"exports",
|
|
185
|
-
"tests",
|
|
186
|
-
"candidates",
|
|
187
|
-
// get_conventions: kinds hoisted to top level for _fmt:multi
|
|
188
|
-
"naming",
|
|
189
|
-
"import_direction",
|
|
190
|
-
"structure",
|
|
191
|
-
"other",
|
|
192
|
-
"guidance",
|
|
193
|
-
];
|
|
194
|
-
if (!skipColumnar) {
|
|
195
|
-
if (typeof content === "object" && content !== null) {
|
|
196
|
-
const obj = content;
|
|
197
|
-
const arrayFieldsPresent = KNOWN_ARRAY_WRAPPERS.filter((k) => k in obj && Array.isArray(obj[k]));
|
|
198
|
-
// P6.2: 2+ recognized arrays → _fmt:multi.
|
|
199
|
-
if (arrayFieldsPresent.length >= 2) {
|
|
200
|
-
const sections = arrayFieldsPresent.map((k) => {
|
|
201
|
-
const items = obj[k];
|
|
202
|
-
const kind = items.length > 0 &&
|
|
203
|
-
typeof items[0] === "object" &&
|
|
204
|
-
items[0] !== null &&
|
|
205
|
-
isUniformObjectArray(items)
|
|
206
|
-
? "uniform-object"
|
|
207
|
-
: "string-list";
|
|
208
|
-
return { name: k, items, kind };
|
|
209
|
-
});
|
|
210
|
-
// Scalars: everything that's not one of the array fields, not nested object
|
|
211
|
-
const scalars = {};
|
|
212
|
-
for (const [k, v] of Object.entries(obj)) {
|
|
213
|
-
if (arrayFieldsPresent.includes(k))
|
|
214
|
-
continue;
|
|
215
|
-
scalars[k] = v;
|
|
216
|
-
}
|
|
217
|
-
meta.format = "columnar"; // Re-use the columnar format flag; legend covers _fmt:multi too.
|
|
218
|
-
attachColumnarLegend();
|
|
219
|
-
return encodeMultiSection(scalars, sections);
|
|
220
|
-
}
|
|
221
|
-
// Single recognized array → columnar it.
|
|
222
|
-
if (arrayFieldsPresent.length === 1) {
|
|
223
|
-
const arrayKey = arrayFieldsPresent[0];
|
|
224
|
-
const items = obj[arrayKey];
|
|
225
|
-
if (items.length > 0 && isUniformObjectArray(items)) {
|
|
226
|
-
const columns = sortedColumnsFromFirstRow(items);
|
|
227
|
-
meta.format = "columnar";
|
|
228
|
-
meta.columns = columns;
|
|
229
|
-
attachColumnarLegend();
|
|
230
|
-
// Preserve all non-array scalars as a one-line metadata header.
|
|
231
|
-
const scalarFields = Object.entries(obj)
|
|
232
|
-
.filter(([k, v]) => k !== arrayKey &&
|
|
233
|
-
!Array.isArray(v) &&
|
|
234
|
-
v !== undefined &&
|
|
235
|
-
v !== null &&
|
|
236
|
-
typeof v !== "object")
|
|
237
|
-
.map(([k, v]) => `${k}=${String(v)}`)
|
|
238
|
-
.join("|");
|
|
239
|
-
// encodeColumnar already prepends `_fmt:columnar` — don't double it.
|
|
240
|
-
// The wrapper context (which array this is) lives in `_list_meta:`
|
|
241
|
-
// (when there are scalars) or is implicit from the toolName.
|
|
242
|
-
let text = encodeColumnar(items, columns);
|
|
243
|
-
if (scalarFields) {
|
|
244
|
-
text = `_list_meta:${scalarFields}\n${text}`;
|
|
245
|
-
}
|
|
246
|
-
return text;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
if (shape === "uniform-array" && Array.isArray(content)) {
|
|
253
|
-
meta.format = "json";
|
|
254
|
-
return content;
|
|
255
|
-
}
|
|
256
|
-
if (typeof content === "object" &&
|
|
257
|
-
content !== null &&
|
|
258
|
-
"items" in content &&
|
|
259
|
-
Array.isArray(content.items)) {
|
|
260
|
-
meta.format = "json";
|
|
261
|
-
return content;
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
meta.format = "json";
|
|
265
|
-
return content;
|
|
266
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sprint 5.3: HTTP/SSE Transport for Main Proxy
|
|
3
|
-
*
|
|
4
|
-
* Adds Streamable HTTP transport alongside STDIO for remote/CI access.
|
|
5
|
-
* Endpoints:
|
|
6
|
-
* POST /mcp — MCP Streamable HTTP (recommended)
|
|
7
|
-
* GET /mcp — SSE stream for server-initiated messages
|
|
8
|
-
* GET /health — Health check (no auth)
|
|
9
|
-
*
|
|
10
|
-
* Bearer token auth required on /mcp (uses proxy credentials).
|
|
11
|
-
* All output to stderr — stdout reserved for STDIO MCP.
|
|
12
|
-
*/
|
|
13
|
-
import { createServer as createHttpServer, } from "node:http";
|
|
14
|
-
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
15
|
-
/**
|
|
16
|
-
* Start an HTTP server that serves MCP via Streamable HTTP transport.
|
|
17
|
-
* Returns a handle for shutdown.
|
|
18
|
-
*/
|
|
19
|
-
export async function startHttpTransport(opts) {
|
|
20
|
-
const { port, apiKey, mcpServer, log = () => { } } = opts;
|
|
21
|
-
// Create a stateful transport (session-aware)
|
|
22
|
-
const transport = new StreamableHTTPServerTransport({
|
|
23
|
-
sessionIdGenerator: () => crypto.randomUUID(),
|
|
24
|
-
});
|
|
25
|
-
// Connect to MCP server
|
|
26
|
-
await mcpServer.connect(transport);
|
|
27
|
-
const httpServer = createHttpServer(async (req, res) => {
|
|
28
|
-
const url = new URL(req.url ?? "/", `http://localhost:${port}`);
|
|
29
|
-
// CORS
|
|
30
|
-
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
31
|
-
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
32
|
-
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Mcp-Session-Id");
|
|
33
|
-
res.setHeader("Access-Control-Expose-Headers", "Mcp-Session-Id");
|
|
34
|
-
if (req.method === "OPTIONS") {
|
|
35
|
-
res.writeHead(204);
|
|
36
|
-
res.end();
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
// Health — no auth
|
|
40
|
-
if (url.pathname === "/health") {
|
|
41
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
42
|
-
res.end(JSON.stringify({
|
|
43
|
-
status: "ok",
|
|
44
|
-
transport: "streamable-http",
|
|
45
|
-
pid: process.pid,
|
|
46
|
-
}));
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
// Auth check for /mcp
|
|
50
|
-
if (url.pathname === "/mcp") {
|
|
51
|
-
if (apiKey) {
|
|
52
|
-
const authHeader = req.headers.authorization;
|
|
53
|
-
const token = authHeader?.startsWith("Bearer ")
|
|
54
|
-
? authHeader.slice(7)
|
|
55
|
-
: authHeader;
|
|
56
|
-
if (token !== apiKey) {
|
|
57
|
-
res.writeHead(401, { "Content-Type": "application/json" });
|
|
58
|
-
res.end(JSON.stringify({ error: "Unauthorized" }));
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
// Delegate to StreamableHTTPServerTransport
|
|
63
|
-
await transport.handleRequest(req, res);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
// 404
|
|
67
|
-
res.writeHead(404, { "Content-Type": "application/json" });
|
|
68
|
-
res.end(JSON.stringify({
|
|
69
|
-
error: "Not found",
|
|
70
|
-
endpoints: ["/mcp", "/health"],
|
|
71
|
-
}));
|
|
72
|
-
});
|
|
73
|
-
return new Promise((resolve) => {
|
|
74
|
-
httpServer.listen(port, "127.0.0.1", () => {
|
|
75
|
-
const addr = httpServer.address();
|
|
76
|
-
const resolvedPort = typeof addr === "object" && addr ? addr.port : port;
|
|
77
|
-
log(`HTTP transport listening on http://127.0.0.1:${resolvedPort}/mcp`);
|
|
78
|
-
resolve({
|
|
79
|
-
server: httpServer,
|
|
80
|
-
port: resolvedPort,
|
|
81
|
-
close: () => {
|
|
82
|
-
transport.close().catch(() => { });
|
|
83
|
-
httpServer.close();
|
|
84
|
-
},
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
// Don't block process exit
|
|
88
|
-
httpServer.unref();
|
|
89
|
-
});
|
|
90
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Proxy Lifecycle Actor — wraps XState machine with a convenient imperative API.
|
|
3
|
-
*
|
|
4
|
-
* proxy.ts creates one LifecycleActor per boot. The actor:
|
|
5
|
-
* - Receives events from each boot step
|
|
6
|
-
* - Emits state transitions for subscribers (startup renderer, telemetry)
|
|
7
|
-
* - Provides .waitFor(state) for async coordination
|
|
8
|
-
* - Tracks timing for each phase (detecting, indexing, etc.)
|
|
9
|
-
*/
|
|
10
|
-
import { createActor, waitFor } from "xstate";
|
|
11
|
-
import { proxyMachine, } from "./lifecycle-machine.js";
|
|
12
|
-
export function createLifecycleActor(repoPath) {
|
|
13
|
-
const actor = createActor(proxyMachine, {
|
|
14
|
-
input: { repoPath },
|
|
15
|
-
});
|
|
16
|
-
actor.start();
|
|
17
|
-
const send = (event) => {
|
|
18
|
-
actor.send(event);
|
|
19
|
-
};
|
|
20
|
-
const getState = () => {
|
|
21
|
-
return actor.getSnapshot().value;
|
|
22
|
-
};
|
|
23
|
-
const getContext = () => {
|
|
24
|
-
return actor.getSnapshot().context;
|
|
25
|
-
};
|
|
26
|
-
const getSnapshot = () => ({
|
|
27
|
-
value: getState(),
|
|
28
|
-
context: getContext(),
|
|
29
|
-
});
|
|
30
|
-
const waitForState = async (state, timeoutMs = 30_000) => {
|
|
31
|
-
const snap = actor.getSnapshot();
|
|
32
|
-
if (snap.value === state)
|
|
33
|
-
return;
|
|
34
|
-
if (snap.status === "done")
|
|
35
|
-
return;
|
|
36
|
-
await waitFor(actor, (snapshot) => snapshot.value === state || snapshot.status === "done", { timeout: timeoutMs });
|
|
37
|
-
};
|
|
38
|
-
const subscribe = (callback) => {
|
|
39
|
-
return actor.subscribe((snapshot) => {
|
|
40
|
-
callback(snapshot.value, snapshot.context);
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
const stop = () => {
|
|
44
|
-
actor.stop();
|
|
45
|
-
};
|
|
46
|
-
return {
|
|
47
|
-
send,
|
|
48
|
-
getState,
|
|
49
|
-
getContext,
|
|
50
|
-
getSnapshot,
|
|
51
|
-
waitForState,
|
|
52
|
-
subscribe,
|
|
53
|
-
stop,
|
|
54
|
-
};
|
|
55
|
-
}
|