@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,72 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* FileEdit Tool — perform exact string replacements in files.
|
|
3
|
-
* Safer than full file writes — only modifies the targeted section.
|
|
4
|
-
*/
|
|
5
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
6
|
-
import { resolve } from "node:path";
|
|
7
|
-
export const fileEditTool = {
|
|
8
|
-
name: "file_edit",
|
|
9
|
-
description: "Perform an exact string replacement in a file. The old_string must be unique in the file " +
|
|
10
|
-
"(provide more surrounding context if needed). Use replace_all: true to replace every occurrence.",
|
|
11
|
-
inputSchema: {
|
|
12
|
-
type: "object",
|
|
13
|
-
properties: {
|
|
14
|
-
file_path: {
|
|
15
|
-
type: "string",
|
|
16
|
-
description: "Path to the file to edit",
|
|
17
|
-
},
|
|
18
|
-
old_string: {
|
|
19
|
-
type: "string",
|
|
20
|
-
description: "The exact string to find and replace",
|
|
21
|
-
},
|
|
22
|
-
new_string: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: "The replacement string",
|
|
25
|
-
},
|
|
26
|
-
replace_all: {
|
|
27
|
-
type: "boolean",
|
|
28
|
-
description: "Replace all occurrences instead of just the first. Default: false",
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
required: ["file_path", "old_string", "new_string"],
|
|
32
|
-
},
|
|
33
|
-
isReadOnly: false,
|
|
34
|
-
requiresPermission: true,
|
|
35
|
-
async execute(args, ctx) {
|
|
36
|
-
const filePath = resolve(ctx.cwd, args.file_path);
|
|
37
|
-
const oldString = args.old_string;
|
|
38
|
-
const newString = args.new_string;
|
|
39
|
-
const replaceAll = args.replace_all ?? false;
|
|
40
|
-
if (!existsSync(filePath)) {
|
|
41
|
-
return { content: `File not found: ${filePath}`, isError: true };
|
|
42
|
-
}
|
|
43
|
-
try {
|
|
44
|
-
const content = readFileSync(filePath, "utf-8");
|
|
45
|
-
const occurrences = content.split(oldString).length - 1;
|
|
46
|
-
if (occurrences === 0) {
|
|
47
|
-
return {
|
|
48
|
-
content: `old_string not found in ${filePath}. Likely causes: (1) file changed since last read, (2) whitespace or line-ending mismatch. Call file_read on the target range first to capture the exact text, then retry the edit with the bytes from that read.`,
|
|
49
|
-
isError: true,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (!replaceAll && occurrences > 1) {
|
|
53
|
-
return {
|
|
54
|
-
content: `old_string found ${occurrences} times in ${filePath}. Provide more context to make it unique, or use replace_all: true.`,
|
|
55
|
-
isError: true,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
const updated = replaceAll
|
|
59
|
-
? content.replaceAll(oldString, newString)
|
|
60
|
-
: content.replace(oldString, newString);
|
|
61
|
-
writeFileSync(filePath, updated, "utf-8");
|
|
62
|
-
const replaced = replaceAll ? occurrences : 1;
|
|
63
|
-
return { content: `Replaced ${replaced} occurrence(s) in ${filePath}` };
|
|
64
|
-
}
|
|
65
|
-
catch (err) {
|
|
66
|
-
return {
|
|
67
|
-
content: `Error editing file: ${err instanceof Error ? err.message : String(err)}`,
|
|
68
|
-
isError: true,
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
};
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sprint FRP-3 — structural file outline with exported detection, token estimation,
|
|
3
|
-
* and stable entity sort. Combines ast-extractor with CozoDB graph when available.
|
|
4
|
-
*/
|
|
5
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
6
|
-
import { relative, resolve } from "node:path";
|
|
7
|
-
import { detectLanguage, extractEntities, } from "../../intelligence/ast-extractor.js";
|
|
8
|
-
const CHARS_PER_TOKEN = 4;
|
|
9
|
-
const GRAPH_TIMEOUT_MS = 100;
|
|
10
|
-
function normRisk(rl) {
|
|
11
|
-
const x = (rl ?? "low").toLowerCase();
|
|
12
|
-
if (x === "critical")
|
|
13
|
-
return "critical";
|
|
14
|
-
if (x === "high")
|
|
15
|
-
return "high";
|
|
16
|
-
if (x === "medium")
|
|
17
|
-
return "medium";
|
|
18
|
-
return "low";
|
|
19
|
-
}
|
|
20
|
-
function lineEndFromBody(startLine, body) {
|
|
21
|
-
const n = body.split("\n").length;
|
|
22
|
-
return Math.max(startLine, startLine + n - 1);
|
|
23
|
-
}
|
|
24
|
-
function extractMdHeadings(lines) {
|
|
25
|
-
const out = [];
|
|
26
|
-
for (const line of lines.slice(0, 400)) {
|
|
27
|
-
const t = line.trim();
|
|
28
|
-
if (/^#{1,6}\s+\S/.test(t))
|
|
29
|
-
out.push(t.slice(0, 200));
|
|
30
|
-
if (out.length >= 60)
|
|
31
|
-
break;
|
|
32
|
-
}
|
|
33
|
-
return out;
|
|
34
|
-
}
|
|
35
|
-
function extractYamlKeys(lines) {
|
|
36
|
-
const keys = [];
|
|
37
|
-
for (const line of lines.slice(0, 150)) {
|
|
38
|
-
const m = /^([\w.-]+)\s*:/.exec(line.trim());
|
|
39
|
-
if (m)
|
|
40
|
-
keys.push(m[1]);
|
|
41
|
-
}
|
|
42
|
-
return keys.slice(0, 80);
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Detect exported entity names from source lines.
|
|
46
|
-
* Handles: `export function X`, `export const X`, `export class X`,
|
|
47
|
-
* `export default function X`, `export { X }`, etc.
|
|
48
|
-
*/
|
|
49
|
-
function detectExportedNames(lines, scanLimit) {
|
|
50
|
-
const exported = new Set();
|
|
51
|
-
const limit = Math.min(lines.length, scanLimit);
|
|
52
|
-
for (let i = 0; i < limit; i++) {
|
|
53
|
-
const t = (lines[i] ?? "").trim();
|
|
54
|
-
if (!/^export\s/.test(t))
|
|
55
|
-
continue;
|
|
56
|
-
// export function/const/let/var/class/interface/type/enum Name
|
|
57
|
-
const m = /^export\s+(?:default\s+)?(?:async\s+)?(?:function\*?\s+|const\s+|let\s+|var\s+|class\s+|interface\s+|type\s+|enum\s+)(\w+)/.exec(t);
|
|
58
|
-
if (m?.[1]) {
|
|
59
|
-
exported.add(m[1]);
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
// export { name1, name2 }
|
|
63
|
-
const braceMatch = /^export\s*\{([^}]+)\}/.exec(t);
|
|
64
|
-
if (braceMatch?.[1]) {
|
|
65
|
-
const names = braceMatch[1].split(",").map((n) => {
|
|
66
|
-
const asMatch = /(\w+)\s+as\s+\w+/.exec(n.trim());
|
|
67
|
-
return asMatch ? asMatch[1] : n.trim();
|
|
68
|
-
});
|
|
69
|
-
for (const n of names) {
|
|
70
|
-
if (n)
|
|
71
|
-
exported.add(n);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
return exported;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Build a structural outline for `file_path` relative to `cwd`.
|
|
79
|
-
* When `graph` is null, uses AST extraction only (parse / degraded modes).
|
|
80
|
-
*/
|
|
81
|
-
export async function buildFileOutline(params) {
|
|
82
|
-
const abs = resolve(params.cwd, params.filePathArg);
|
|
83
|
-
const rel = relative(params.cwd, abs).replace(/\\/g, "/") || params.filePathArg;
|
|
84
|
-
if (!existsSync(abs)) {
|
|
85
|
-
throw new Error(`File not found: ${abs}`);
|
|
86
|
-
}
|
|
87
|
-
const raw = readFileSync(abs);
|
|
88
|
-
const sampleEnd = Math.min(raw.length, 8192);
|
|
89
|
-
for (let i = 0; i < sampleEnd; i++) {
|
|
90
|
-
if (raw[i] === 0) {
|
|
91
|
-
throw new Error("File appears to be binary — text outline is not available.");
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
const content = raw.toString("utf-8");
|
|
95
|
-
const lines = content.split("\n");
|
|
96
|
-
const total_lines = lines.length;
|
|
97
|
-
const lang = detectLanguage(rel) ?? "unknown";
|
|
98
|
-
// Skip graph queries for out-of-project files (rel starts with "..")
|
|
99
|
-
// and add timeout protection to prevent hangs during background indexing
|
|
100
|
-
const isOutOfProject = rel.startsWith("..");
|
|
101
|
-
const graphEntities = params.graph && !isOutOfProject
|
|
102
|
-
? await Promise.race([
|
|
103
|
-
params.graph.getEntitiesByFile(rel),
|
|
104
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("graph_timeout")), GRAPH_TIMEOUT_MS)),
|
|
105
|
-
]).catch(() => [])
|
|
106
|
-
: [];
|
|
107
|
-
const driftRows = params.graph && !isOutOfProject
|
|
108
|
-
? await Promise.race([
|
|
109
|
-
params.graph.getDriftEntitiesForFile(rel),
|
|
110
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("graph_timeout")), GRAPH_TIMEOUT_MS)),
|
|
111
|
-
]).catch(() => [])
|
|
112
|
-
: [];
|
|
113
|
-
const driftKeys = new Set(driftRows.map((d) => d.key));
|
|
114
|
-
// Detect exports from source
|
|
115
|
-
const exportedNames = detectExportedNames(lines, Math.min(lines.length, 2000));
|
|
116
|
-
const entities = [];
|
|
117
|
-
if (graphEntities.length > 0) {
|
|
118
|
-
for (const ge of graphEntities) {
|
|
119
|
-
entities.push({
|
|
120
|
-
name: ge.name,
|
|
121
|
-
kind: ge.kind,
|
|
122
|
-
lines: [ge.start_line, lineEndFromBody(ge.start_line, ge.body)],
|
|
123
|
-
risk: normRisk(ge.risk_level),
|
|
124
|
-
callers: ge.fan_in,
|
|
125
|
-
drift: driftKeys.has(ge.key),
|
|
126
|
-
exported: exportedNames.has(ge.name),
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
const extracted = extractEntities(content, rel);
|
|
132
|
-
for (const ex of extracted) {
|
|
133
|
-
entities.push({
|
|
134
|
-
name: ex.name,
|
|
135
|
-
kind: ex.kind,
|
|
136
|
-
lines: [ex.line_start, ex.line_end],
|
|
137
|
-
risk: "low",
|
|
138
|
-
callers: 0,
|
|
139
|
-
drift: false,
|
|
140
|
-
exported: exportedNames.has(ex.name),
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
// Stable sort: by start line, then by name for same-line entities
|
|
145
|
-
entities.sort((a, b) => a.lines[0] - b.lines[0] || a.name.localeCompare(b.name));
|
|
146
|
-
const imports = [];
|
|
147
|
-
const exports = [];
|
|
148
|
-
const scan = Math.min(lines.length, 400);
|
|
149
|
-
for (let i = 0; i < scan; i++) {
|
|
150
|
-
const line = lines[i] ?? "";
|
|
151
|
-
const t = line.trim();
|
|
152
|
-
if (/^import\s/.test(t))
|
|
153
|
-
imports.push(t.slice(0, 160));
|
|
154
|
-
else if (/^export\s/.test(t))
|
|
155
|
-
exports.push(t.slice(0, 160));
|
|
156
|
-
}
|
|
157
|
-
let headings;
|
|
158
|
-
if (rel.endsWith(".md") || rel.endsWith(".mdx")) {
|
|
159
|
-
headings = extractMdHeadings(lines);
|
|
160
|
-
}
|
|
161
|
-
let config_keys;
|
|
162
|
-
if (/\.json$/i.test(rel) && content.length < 400_000) {
|
|
163
|
-
try {
|
|
164
|
-
const j = JSON.parse(content);
|
|
165
|
-
config_keys = Object.keys(j).slice(0, 80);
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
/* ignore invalid JSON */
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
else if (/\.ya?ml$/i.test(rel)) {
|
|
172
|
-
config_keys = extractYamlKeys(lines);
|
|
173
|
-
}
|
|
174
|
-
const token_estimate = Math.ceil(content.length / CHARS_PER_TOKEN);
|
|
175
|
-
const out = {
|
|
176
|
-
file_path: rel,
|
|
177
|
-
total_lines,
|
|
178
|
-
language: lang,
|
|
179
|
-
entities,
|
|
180
|
-
imports: imports.slice(0, 40),
|
|
181
|
-
exports: exports.slice(0, 40),
|
|
182
|
-
token_estimate,
|
|
183
|
-
_hint: "Use file_read with offset/limit or entity (symbol name) for targeted content.",
|
|
184
|
-
};
|
|
185
|
-
if (headings?.length)
|
|
186
|
-
out.headings = headings;
|
|
187
|
-
if (config_keys?.length)
|
|
188
|
-
out.config_keys = config_keys;
|
|
189
|
-
return out;
|
|
190
|
-
}
|
|
191
|
-
/** MCP + coding-tools wrapper for `buildFileOutline`. */
|
|
192
|
-
export const fileOutlineTool = {
|
|
193
|
-
name: "file_outline",
|
|
194
|
-
description: "Structural outline of a source file — entities, imports/exports, headings (markdown), config keys (JSON/YAML), line counts. Call before reading large files.",
|
|
195
|
-
inputSchema: {
|
|
196
|
-
type: "object",
|
|
197
|
-
properties: {
|
|
198
|
-
file_path: {
|
|
199
|
-
type: "string",
|
|
200
|
-
description: "Path to the file (relative to project root or absolute)",
|
|
201
|
-
},
|
|
202
|
-
},
|
|
203
|
-
required: ["file_path"],
|
|
204
|
-
},
|
|
205
|
-
isReadOnly: true,
|
|
206
|
-
requiresPermission: false,
|
|
207
|
-
async execute(args, ctx) {
|
|
208
|
-
const fp = args.file_path;
|
|
209
|
-
if (!fp) {
|
|
210
|
-
return { content: "file_outline requires file_path", isError: true };
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
const outline = await buildFileOutline({
|
|
214
|
-
cwd: ctx.cwd,
|
|
215
|
-
filePathArg: fp,
|
|
216
|
-
graph: ctx.graph ?? null,
|
|
217
|
-
});
|
|
218
|
-
return { content: outline };
|
|
219
|
-
}
|
|
220
|
-
catch (e) {
|
|
221
|
-
return {
|
|
222
|
-
content: `file_outline failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
223
|
-
isError: true,
|
|
224
|
-
};
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
};
|