@unerr-ai/unerr 0.2.0 → 0.2.2
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 +6 -0
- package/dist/cli.js +37236 -35793
- package/package.json +6 -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,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Per-session flag state for the Tier 0/1/2 nudge system (N1, N3, N5).
|
|
3
|
-
*
|
|
4
|
-
* State is a small JSON file at `.unerr/state/nudge-<session>.flags`. Session
|
|
5
|
-
* id comes from UNERR_SESSION_ID (set by the daemon/IDE). If unset, we fall
|
|
6
|
-
* back to a per-PID file — no cross-process state, but still beats v1.
|
|
7
|
-
*
|
|
8
|
-
* The store is best-effort and idempotent: if read or write fails, we treat
|
|
9
|
-
* it as "no state" — at worst the agent sees the Tier-0 reminder twice. We
|
|
10
|
-
* never throw; nudge emission must never crash the host command.
|
|
11
|
-
*/
|
|
12
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
13
|
-
import { join } from "node:path";
|
|
14
|
-
function defaultState() {
|
|
15
|
-
return {
|
|
16
|
-
tier0_emitted: false,
|
|
17
|
-
tier1_emitted_kinds: [],
|
|
18
|
-
drift_count: 0,
|
|
19
|
-
tier2_emitted: false,
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function statePath(cwd) {
|
|
23
|
-
const sessionId = process.env.UNERR_SESSION_ID ?? `pid-${process.pid}`;
|
|
24
|
-
return join(cwd, ".unerr", "state", `nudge-${sessionId}.flags`);
|
|
25
|
-
}
|
|
26
|
-
export function readNudgeState(cwd) {
|
|
27
|
-
try {
|
|
28
|
-
const path = statePath(cwd);
|
|
29
|
-
if (!existsSync(path))
|
|
30
|
-
return defaultState();
|
|
31
|
-
const raw = readFileSync(path, "utf8");
|
|
32
|
-
const parsed = JSON.parse(raw);
|
|
33
|
-
return {
|
|
34
|
-
tier0_emitted: Boolean(parsed.tier0_emitted),
|
|
35
|
-
tier1_emitted_kinds: Array.isArray(parsed.tier1_emitted_kinds)
|
|
36
|
-
? parsed.tier1_emitted_kinds.filter((s) => typeof s === "string")
|
|
37
|
-
: [],
|
|
38
|
-
drift_count: typeof parsed.drift_count === "number" ? parsed.drift_count : 0,
|
|
39
|
-
tier2_emitted: Boolean(parsed.tier2_emitted),
|
|
40
|
-
last_unerr_tool_at: typeof parsed.last_unerr_tool_at === "string"
|
|
41
|
-
? parsed.last_unerr_tool_at
|
|
42
|
-
: undefined,
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
return defaultState();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
export function writeNudgeState(cwd, state) {
|
|
50
|
-
try {
|
|
51
|
-
const path = statePath(cwd);
|
|
52
|
-
const dir = path.slice(0, path.lastIndexOf("/"));
|
|
53
|
-
if (!existsSync(dir))
|
|
54
|
-
mkdirSync(dir, { recursive: true });
|
|
55
|
-
writeFileSync(path, JSON.stringify(state), "utf8");
|
|
56
|
-
}
|
|
57
|
-
catch {
|
|
58
|
-
/* best effort */
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
/** Convenience helper: read, mutate, write atomically. */
|
|
62
|
-
export function updateNudgeState(cwd, mutator) {
|
|
63
|
-
const s = readNudgeState(cwd);
|
|
64
|
-
mutator(s);
|
|
65
|
-
writeNudgeState(cwd, s);
|
|
66
|
-
return s;
|
|
67
|
-
}
|
|
68
|
-
/** Reset all flags for the current session — escape hatch for tests. */
|
|
69
|
-
export function _resetNudgeState(cwd) {
|
|
70
|
-
try {
|
|
71
|
-
writeNudgeState(cwd, defaultState());
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
/* ignore */
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Called by the MCP layer on every successful unerr tool invocation.
|
|
79
|
-
* Resets the drift accumulator and stamps the last-used timestamp so
|
|
80
|
-
* Tier-2 escalation only fires on persistent drift.
|
|
81
|
-
*/
|
|
82
|
-
export function markUnerrToolUsed(cwd) {
|
|
83
|
-
try {
|
|
84
|
-
updateNudgeState(cwd, (s) => {
|
|
85
|
-
s.drift_count = 0;
|
|
86
|
-
s.tier2_emitted = false;
|
|
87
|
-
s.last_unerr_tool_at = new Date().toISOString();
|
|
88
|
-
});
|
|
89
|
-
}
|
|
90
|
-
catch {
|
|
91
|
-
/* best effort */
|
|
92
|
-
}
|
|
93
|
-
}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Graph-Aware Output Compressor — intelligent truncation of large outputs.
|
|
3
|
-
*
|
|
4
|
-
* Intercepts large command outputs (>2K tokens) and compresses them by:
|
|
5
|
-
* 1. Identifying sections (file headers, diff hunks, error blocks)
|
|
6
|
-
* 2. Scoring sections by entity risk, caller count, change significance
|
|
7
|
-
* 3. Budget allocation — high-score sections get full text, low-score get summaries
|
|
8
|
-
* 4. Annotating preserved lines with graph intelligence
|
|
9
|
-
*
|
|
10
|
-
* Only applies to raw text outputs (git diff, test results, ls).
|
|
11
|
-
* Structured MCP tool responses pass through unchanged.
|
|
12
|
-
*/
|
|
13
|
-
import { estimateTokenCount } from "../intelligence/token-estimator.js";
|
|
14
|
-
const ERROR_PATTERNS = [
|
|
15
|
-
/error/i,
|
|
16
|
-
/ERR[_!]/,
|
|
17
|
-
/FAIL/,
|
|
18
|
-
/TypeError/,
|
|
19
|
-
/SyntaxError/,
|
|
20
|
-
/ReferenceError/,
|
|
21
|
-
/ENOENT/,
|
|
22
|
-
/Cannot find/,
|
|
23
|
-
/Unexpected/,
|
|
24
|
-
/✗|✕|×/,
|
|
25
|
-
];
|
|
26
|
-
const DIFF_HEADER = /^(diff --git|---|\+\+\+|@@)/;
|
|
27
|
-
const FILE_HEADER = /^(diff --git a\/(.+) b\/|---\s+a\/(.+)|[\w/]+\.[a-z]+:)/;
|
|
28
|
-
function isErrorLine(line) {
|
|
29
|
-
return ERROR_PATTERNS.some((p) => p.test(line));
|
|
30
|
-
}
|
|
31
|
-
function extractFilePath(line) {
|
|
32
|
-
const diffMatch = line.match(/^diff --git a\/(.+?) b\//);
|
|
33
|
-
if (diffMatch)
|
|
34
|
-
return diffMatch[1] ?? null;
|
|
35
|
-
const fileMatch = line.match(/^---\s+a\/(.+)/);
|
|
36
|
-
if (fileMatch)
|
|
37
|
-
return fileMatch[1] ?? null;
|
|
38
|
-
const colonMatch = line.match(/^([\w/.]+\.[a-z]+):/);
|
|
39
|
-
if (colonMatch)
|
|
40
|
-
return colonMatch[1] ?? null;
|
|
41
|
-
return null;
|
|
42
|
-
}
|
|
43
|
-
function splitIntoSections(text) {
|
|
44
|
-
const lines = text.split("\n");
|
|
45
|
-
const sections = [];
|
|
46
|
-
let current = {
|
|
47
|
-
lines: [],
|
|
48
|
-
score: 0,
|
|
49
|
-
type: "content",
|
|
50
|
-
annotations: [],
|
|
51
|
-
};
|
|
52
|
-
for (const line of lines) {
|
|
53
|
-
if (DIFF_HEADER.test(line)) {
|
|
54
|
-
if (current.lines.length > 0)
|
|
55
|
-
sections.push(current);
|
|
56
|
-
const filePath = extractFilePath(line);
|
|
57
|
-
current = {
|
|
58
|
-
lines: [line],
|
|
59
|
-
score: 1,
|
|
60
|
-
type: FILE_HEADER.test(line) ? "header" : "hunk",
|
|
61
|
-
filePath: filePath ?? undefined,
|
|
62
|
-
annotations: [],
|
|
63
|
-
};
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (line.trim() === "" &&
|
|
67
|
-
current.lines.length > 0 &&
|
|
68
|
-
current.lines.every((l) => l.trim() === "")) {
|
|
69
|
-
current.type = "blank";
|
|
70
|
-
}
|
|
71
|
-
if (isErrorLine(line)) {
|
|
72
|
-
if (current.lines.length > 0 && current.type !== "error") {
|
|
73
|
-
sections.push(current);
|
|
74
|
-
current = { lines: [], score: 5, type: "error", annotations: [] };
|
|
75
|
-
}
|
|
76
|
-
current.type = "error";
|
|
77
|
-
current.score = Math.max(current.score, 5);
|
|
78
|
-
}
|
|
79
|
-
current.lines.push(line);
|
|
80
|
-
}
|
|
81
|
-
if (current.lines.length > 0)
|
|
82
|
-
sections.push(current);
|
|
83
|
-
return sections;
|
|
84
|
-
}
|
|
85
|
-
function scoreSections(sections, entityRiskMap) {
|
|
86
|
-
for (const section of sections) {
|
|
87
|
-
if (section.type === "error")
|
|
88
|
-
section.score += 10;
|
|
89
|
-
if (section.type === "header")
|
|
90
|
-
section.score += 3;
|
|
91
|
-
if (section.filePath && entityRiskMap) {
|
|
92
|
-
for (const [entityKey, info] of entityRiskMap) {
|
|
93
|
-
if (entityKey.startsWith(section.filePath)) {
|
|
94
|
-
if (info.riskLevel === "high") {
|
|
95
|
-
section.score += 8;
|
|
96
|
-
section.annotations.push(`[HIGH_RISK: ${info.fanIn} callers]`);
|
|
97
|
-
}
|
|
98
|
-
else if (info.riskLevel === "medium") {
|
|
99
|
-
section.score += 4;
|
|
100
|
-
}
|
|
101
|
-
if (info.isChokepoint) {
|
|
102
|
-
section.score += 6;
|
|
103
|
-
section.annotations.push("[CHOKEPOINT]");
|
|
104
|
-
}
|
|
105
|
-
if (info.conventions && info.conventions.length > 0) {
|
|
106
|
-
section.annotations.push(`[CONVENTION: ${info.conventions[0]}]`);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
if (section.type === "blank")
|
|
112
|
-
section.score = 0;
|
|
113
|
-
const addedLines = section.lines.filter((l) => l.startsWith("+")).length;
|
|
114
|
-
const removedLines = section.lines.filter((l) => l.startsWith("-")).length;
|
|
115
|
-
section.score += (addedLines + removedLines) * 0.1;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Compress a large text output using graph-aware truncation.
|
|
120
|
-
* Preserves high-value sections and annotates with risk metadata.
|
|
121
|
-
*/
|
|
122
|
-
export function compressOutput(text, options = {}) {
|
|
123
|
-
const { tokenBudget = 2000, preserveFirstLines = 5, preserveLastLines = 3, entityRiskMap, } = options;
|
|
124
|
-
const originalTokens = estimateTokenCount(text);
|
|
125
|
-
if (originalTokens <= tokenBudget) {
|
|
126
|
-
return {
|
|
127
|
-
output: text,
|
|
128
|
-
originalTokens,
|
|
129
|
-
compressedTokens: originalTokens,
|
|
130
|
-
sectionsPreserved: 0,
|
|
131
|
-
sectionsOmitted: 0,
|
|
132
|
-
annotations: [],
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
const sections = splitIntoSections(text);
|
|
136
|
-
scoreSections(sections, entityRiskMap);
|
|
137
|
-
sections.sort((a, b) => b.score - a.score);
|
|
138
|
-
const result = [];
|
|
139
|
-
let currentTokens = 0;
|
|
140
|
-
let sectionsPreserved = 0;
|
|
141
|
-
let sectionsOmitted = 0;
|
|
142
|
-
const allAnnotations = [];
|
|
143
|
-
const lines = text.split("\n");
|
|
144
|
-
const firstLines = lines.slice(0, preserveFirstLines).join("\n");
|
|
145
|
-
const lastLines = lines.slice(-preserveLastLines).join("\n");
|
|
146
|
-
currentTokens += estimateTokenCount(firstLines);
|
|
147
|
-
currentTokens += estimateTokenCount(lastLines);
|
|
148
|
-
result.push(firstLines);
|
|
149
|
-
for (const section of sections) {
|
|
150
|
-
const sectionText = section.lines.join("\n");
|
|
151
|
-
const sectionTokens = estimateTokenCount(sectionText);
|
|
152
|
-
if (currentTokens + sectionTokens <= tokenBudget * 0.85) {
|
|
153
|
-
let annotated = sectionText;
|
|
154
|
-
if (section.annotations.length > 0) {
|
|
155
|
-
const prefix = section.annotations.join(" ");
|
|
156
|
-
annotated = `${prefix}\n${sectionText}`;
|
|
157
|
-
allAnnotations.push(...section.annotations);
|
|
158
|
-
}
|
|
159
|
-
result.push(annotated);
|
|
160
|
-
currentTokens += estimateTokenCount(annotated);
|
|
161
|
-
sectionsPreserved++;
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
const lineCount = section.lines.length;
|
|
165
|
-
const label = section.type === "blank"
|
|
166
|
-
? "blank lines"
|
|
167
|
-
: section.filePath
|
|
168
|
-
? `${section.filePath}`
|
|
169
|
-
: section.type;
|
|
170
|
-
result.push(`[... ${lineCount} lines omitted (${label}) ...]`);
|
|
171
|
-
sectionsOmitted++;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
result.push(lastLines);
|
|
175
|
-
const output = result.join("\n");
|
|
176
|
-
const compressedTokens = estimateTokenCount(output);
|
|
177
|
-
return {
|
|
178
|
-
output,
|
|
179
|
-
originalTokens,
|
|
180
|
-
compressedTokens,
|
|
181
|
-
sectionsPreserved,
|
|
182
|
-
sectionsOmitted,
|
|
183
|
-
annotations: allAnnotations,
|
|
184
|
-
};
|
|
185
|
-
}
|
package/dist/proxy/pid-lock.js
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* PID Lock — single-instance enforcement for the proxy.
|
|
3
|
-
*
|
|
4
|
-
* PID file format (JSON): { pid, startedAt, healthPort }
|
|
5
|
-
* Health check HTTP endpoint on random high port for stale detection.
|
|
6
|
-
* Heartbeat every 10s. Backward-compatible with plain PID format.
|
|
7
|
-
*/
|
|
8
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync, } from "node:fs";
|
|
9
|
-
import { createServer } from "node:http";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
const HEARTBEAT_INTERVAL_MS = 10_000;
|
|
12
|
-
const PID_FILENAME = "proxy.pid";
|
|
13
|
-
const HEALTH_CHECK_TIMEOUT_MS = 500;
|
|
14
|
-
export class PidLock {
|
|
15
|
-
pidPath;
|
|
16
|
-
heartbeatTimer = null;
|
|
17
|
-
healthServer = null;
|
|
18
|
-
healthPort = 0;
|
|
19
|
-
startedAt = "";
|
|
20
|
-
toolCalls = 0;
|
|
21
|
-
mode = "full";
|
|
22
|
-
constructor(unerrStateDir) {
|
|
23
|
-
this.pidPath = join(unerrStateDir, PID_FILENAME);
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Set the current operating mode (for health endpoint).
|
|
27
|
-
*/
|
|
28
|
-
setMode(mode) {
|
|
29
|
-
this.mode = mode;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Increment tool call counter (for health endpoint).
|
|
33
|
-
*/
|
|
34
|
-
recordToolCall() {
|
|
35
|
-
this.toolCalls++;
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Get the health port (for external discovery).
|
|
39
|
-
*/
|
|
40
|
-
getHealthPort() {
|
|
41
|
-
return this.healthPort;
|
|
42
|
-
}
|
|
43
|
-
/**
|
|
44
|
-
* Attempt to acquire the PID lock.
|
|
45
|
-
* Returns outcome: primary (we're the proxy), secondary (another is running), stale_recovered.
|
|
46
|
-
*/
|
|
47
|
-
async acquire() {
|
|
48
|
-
const stateDir = join(this.pidPath, "..");
|
|
49
|
-
if (!existsSync(stateDir)) {
|
|
50
|
-
mkdirSync(stateDir, { recursive: true });
|
|
51
|
-
}
|
|
52
|
-
// Check existing PID
|
|
53
|
-
if (existsSync(this.pidPath)) {
|
|
54
|
-
try {
|
|
55
|
-
const raw = readFileSync(this.pidPath, "utf-8").trim();
|
|
56
|
-
const pidData = parsePidFile(raw);
|
|
57
|
-
if (pidData && isProcessAlive(pidData.pid)) {
|
|
58
|
-
// Process is alive — verify it's really unerr via health check
|
|
59
|
-
if (pidData.healthPort) {
|
|
60
|
-
const healthy = await checkHealth(pidData.healthPort);
|
|
61
|
-
if (healthy) {
|
|
62
|
-
return {
|
|
63
|
-
acquired: false,
|
|
64
|
-
outcome: "secondary",
|
|
65
|
-
existingPid: pidData.pid,
|
|
66
|
-
existingHealthPort: pidData.healthPort,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
// Health check failed but process exists → likely recycled PID → stale
|
|
70
|
-
unlinkSync(this.pidPath);
|
|
71
|
-
return await this.becomePrimary("stale_recovered");
|
|
72
|
-
}
|
|
73
|
-
// No health port (legacy format) → assume real proxy
|
|
74
|
-
return {
|
|
75
|
-
acquired: false,
|
|
76
|
-
outcome: "secondary",
|
|
77
|
-
existingPid: pidData.pid,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
// Stale — clean up
|
|
81
|
-
unlinkSync(this.pidPath);
|
|
82
|
-
return await this.becomePrimary("stale_recovered");
|
|
83
|
-
}
|
|
84
|
-
catch {
|
|
85
|
-
// Corrupt PID file — remove it
|
|
86
|
-
try {
|
|
87
|
-
unlinkSync(this.pidPath);
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
/* ignore */
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return await this.becomePrimary("primary");
|
|
95
|
-
}
|
|
96
|
-
async becomePrimary(outcome) {
|
|
97
|
-
// Start health server on random port
|
|
98
|
-
await this.startHealthServer();
|
|
99
|
-
this.startedAt = new Date().toISOString();
|
|
100
|
-
// Write JSON PID file
|
|
101
|
-
this.writePidFile();
|
|
102
|
-
// Start heartbeat
|
|
103
|
-
this.heartbeatTimer = setInterval(() => {
|
|
104
|
-
try {
|
|
105
|
-
this.writePidFile();
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
// PID file disappeared — directory might be deleted
|
|
109
|
-
}
|
|
110
|
-
}, HEARTBEAT_INTERVAL_MS);
|
|
111
|
-
if (this.heartbeatTimer.unref) {
|
|
112
|
-
this.heartbeatTimer.unref();
|
|
113
|
-
}
|
|
114
|
-
// Cleanup on exit (crash recovery)
|
|
115
|
-
process.on("exit", () => {
|
|
116
|
-
try {
|
|
117
|
-
unlinkSync(this.pidPath);
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
/* ignore */
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
return { acquired: true, outcome, healthPort: this.healthPort };
|
|
124
|
-
}
|
|
125
|
-
writePidFile() {
|
|
126
|
-
const data = {
|
|
127
|
-
pid: process.pid,
|
|
128
|
-
startedAt: this.startedAt,
|
|
129
|
-
healthPort: this.healthPort,
|
|
130
|
-
};
|
|
131
|
-
writeFileSync(this.pidPath, JSON.stringify(data), "utf-8");
|
|
132
|
-
}
|
|
133
|
-
async startHealthServer() {
|
|
134
|
-
return new Promise((resolve) => {
|
|
135
|
-
this.healthServer = createServer((req, res) => {
|
|
136
|
-
if (req.url === "/health" && req.method === "GET") {
|
|
137
|
-
const uptimeS = Math.round((Date.now() - new Date(this.startedAt).getTime()) / 1000);
|
|
138
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
139
|
-
res.end(JSON.stringify({
|
|
140
|
-
status: "ok",
|
|
141
|
-
uptime_s: uptimeS,
|
|
142
|
-
tool_calls: this.toolCalls,
|
|
143
|
-
mode: this.mode,
|
|
144
|
-
pid: process.pid,
|
|
145
|
-
}));
|
|
146
|
-
}
|
|
147
|
-
else {
|
|
148
|
-
res.writeHead(404);
|
|
149
|
-
res.end();
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
// Listen on random port (0 = OS assigns)
|
|
153
|
-
this.healthServer.listen(0, "127.0.0.1", () => {
|
|
154
|
-
const addr = this.healthServer?.address();
|
|
155
|
-
this.healthPort = typeof addr === "object" && addr ? addr.port : 0;
|
|
156
|
-
resolve();
|
|
157
|
-
});
|
|
158
|
-
this.healthServer.unref();
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
|
-
* Release the PID lock, stop heartbeat, and close health server.
|
|
163
|
-
*/
|
|
164
|
-
release() {
|
|
165
|
-
if (this.heartbeatTimer) {
|
|
166
|
-
clearInterval(this.heartbeatTimer);
|
|
167
|
-
this.heartbeatTimer = null;
|
|
168
|
-
}
|
|
169
|
-
if (this.healthServer) {
|
|
170
|
-
this.healthServer.close();
|
|
171
|
-
this.healthServer = null;
|
|
172
|
-
}
|
|
173
|
-
try {
|
|
174
|
-
if (existsSync(this.pidPath)) {
|
|
175
|
-
const raw = readFileSync(this.pidPath, "utf-8").trim();
|
|
176
|
-
const data = parsePidFile(raw);
|
|
177
|
-
if (data && data.pid === process.pid) {
|
|
178
|
-
unlinkSync(this.pidPath);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
catch {
|
|
183
|
-
// Best effort cleanup
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Check if a proxy is currently running (for external callers).
|
|
188
|
-
*/
|
|
189
|
-
isLocked() {
|
|
190
|
-
if (!existsSync(this.pidPath))
|
|
191
|
-
return { locked: false };
|
|
192
|
-
try {
|
|
193
|
-
const raw = readFileSync(this.pidPath, "utf-8").trim();
|
|
194
|
-
const data = parsePidFile(raw);
|
|
195
|
-
if (data && isProcessAlive(data.pid)) {
|
|
196
|
-
return { locked: true, pid: data.pid, healthPort: data.healthPort };
|
|
197
|
-
}
|
|
198
|
-
return { locked: false };
|
|
199
|
-
}
|
|
200
|
-
catch {
|
|
201
|
-
return { locked: false };
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Non-destructive probe: check if proxy is alive without acquiring the lock.
|
|
206
|
-
* Uses health check for full verification (unlike isLocked() which is sync-only).
|
|
207
|
-
*/
|
|
208
|
-
async probe() {
|
|
209
|
-
if (!existsSync(this.pidPath))
|
|
210
|
-
return { alive: false };
|
|
211
|
-
try {
|
|
212
|
-
const raw = readFileSync(this.pidPath, "utf-8").trim();
|
|
213
|
-
const pidData = parsePidFile(raw);
|
|
214
|
-
if (!pidData || !isProcessAlive(pidData.pid))
|
|
215
|
-
return { alive: false };
|
|
216
|
-
if (pidData.healthPort) {
|
|
217
|
-
const healthy = await checkHealth(pidData.healthPort);
|
|
218
|
-
if (!healthy)
|
|
219
|
-
return { alive: false };
|
|
220
|
-
}
|
|
221
|
-
return { alive: true, pid: pidData.pid, healthPort: pidData.healthPort };
|
|
222
|
-
}
|
|
223
|
-
catch {
|
|
224
|
-
return { alive: false };
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Read the PID file data (for external callers like --mcp bridge).
|
|
229
|
-
*/
|
|
230
|
-
static readPidFile(stateDir) {
|
|
231
|
-
const pidPath = join(stateDir, PID_FILENAME);
|
|
232
|
-
if (!existsSync(pidPath))
|
|
233
|
-
return null;
|
|
234
|
-
try {
|
|
235
|
-
const raw = readFileSync(pidPath, "utf-8").trim();
|
|
236
|
-
const data = parsePidFile(raw);
|
|
237
|
-
if (data && isProcessAlive(data.pid))
|
|
238
|
-
return data;
|
|
239
|
-
return null;
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
return null;
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Parse PID file — handles both JSON format and legacy plain number.
|
|
248
|
-
*/
|
|
249
|
-
function parsePidFile(raw) {
|
|
250
|
-
// Try JSON first
|
|
251
|
-
if (raw.startsWith("{")) {
|
|
252
|
-
try {
|
|
253
|
-
const data = JSON.parse(raw);
|
|
254
|
-
if (typeof data.pid === "number" && !Number.isNaN(data.pid)) {
|
|
255
|
-
return data;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
catch {
|
|
259
|
-
/* fall through */
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
// Legacy: plain PID number
|
|
263
|
-
const pid = Number.parseInt(raw, 10);
|
|
264
|
-
if (!Number.isNaN(pid)) {
|
|
265
|
-
return { pid, startedAt: "", healthPort: 0 };
|
|
266
|
-
}
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
function isProcessAlive(pid) {
|
|
270
|
-
try {
|
|
271
|
-
process.kill(pid, 0);
|
|
272
|
-
return true;
|
|
273
|
-
}
|
|
274
|
-
catch {
|
|
275
|
-
return false;
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
/**
|
|
279
|
-
* Check if a health endpoint is responding (used for stale PID verification).
|
|
280
|
-
*/
|
|
281
|
-
async function checkHealth(port) {
|
|
282
|
-
try {
|
|
283
|
-
const res = await fetch(`http://127.0.0.1:${port}/health`, {
|
|
284
|
-
signal: AbortSignal.timeout(HEALTH_CHECK_TIMEOUT_MS),
|
|
285
|
-
});
|
|
286
|
-
return res.ok;
|
|
287
|
-
}
|
|
288
|
-
catch {
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ProxyContext — Local-only context for the proxy.
|
|
3
|
-
*
|
|
4
|
-
* Local-only LLM adapter — optional BYO-LLM capability.
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Create a ProxyContext with optional BYO-LLM adapter.
|
|
8
|
-
*/
|
|
9
|
-
export function createLocalContext(llmAdapter = null) {
|
|
10
|
-
return { llmAdapter };
|
|
11
|
-
}
|