ragcode-context-engine 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +366 -0
- package/README.zh-CN.md +363 -0
- package/dist/src/cli/configure/app.d.ts +6 -0
- package/dist/src/cli/configure/app.js +81 -0
- package/dist/src/cli/configure/run.d.ts +5 -0
- package/dist/src/cli/configure/run.js +85 -0
- package/dist/src/cli/configure/state.d.ts +42 -0
- package/dist/src/cli/configure/state.js +174 -0
- package/dist/src/cli/configure.d.ts +31 -0
- package/dist/src/cli/configure.js +101 -0
- package/dist/src/cli/index.d.ts +2 -0
- package/dist/src/cli/index.js +503 -0
- package/dist/src/cli/tui/index-progress.d.ts +12 -0
- package/dist/src/cli/tui/index-progress.js +49 -0
- package/dist/src/cli/tui/watch-status.d.ts +10 -0
- package/dist/src/cli/tui/watch-status.js +27 -0
- package/dist/src/cli/update.d.ts +18 -0
- package/dist/src/cli/update.js +111 -0
- package/dist/src/config/dotenv.d.ts +1 -0
- package/dist/src/config/dotenv.js +14 -0
- package/dist/src/config/graph-runtime.d.ts +13 -0
- package/dist/src/config/graph-runtime.js +29 -0
- package/dist/src/config/runtime-config.d.ts +87 -0
- package/dist/src/config/runtime-config.js +215 -0
- package/dist/src/config/semantic-runtime.d.ts +24 -0
- package/dist/src/config/semantic-runtime.js +89 -0
- package/dist/src/context/context-builder.d.ts +20 -0
- package/dist/src/context/context-builder.js +277 -0
- package/dist/src/context/expansion-policy.d.ts +6 -0
- package/dist/src/context/expansion-policy.js +49 -0
- package/dist/src/context/skeletonizer.d.ts +2 -0
- package/dist/src/context/skeletonizer.js +79 -0
- package/dist/src/context/snippet-renderer.d.ts +2 -0
- package/dist/src/context/snippet-renderer.js +67 -0
- package/dist/src/core/contracts.d.ts +74 -0
- package/dist/src/core/contracts.js +1 -0
- package/dist/src/core/engine.d.ts +64 -0
- package/dist/src/core/engine.js +442 -0
- package/dist/src/core/types.d.ts +490 -0
- package/dist/src/core/types.js +1 -0
- package/dist/src/diagnostics/doctor.d.ts +66 -0
- package/dist/src/diagnostics/doctor.js +193 -0
- package/dist/src/diagnostics/embedding-test.d.ts +24 -0
- package/dist/src/diagnostics/embedding-test.js +83 -0
- package/dist/src/graph/diff-files.d.ts +1 -0
- package/dist/src/graph/diff-files.js +14 -0
- package/dist/src/graph/impact-report.d.ts +10 -0
- package/dist/src/graph/impact-report.js +173 -0
- package/dist/src/graph/in-memory-graph-store.d.ts +36 -0
- package/dist/src/graph/in-memory-graph-store.js +395 -0
- package/dist/src/graph/owner-ranking.d.ts +2 -0
- package/dist/src/graph/owner-ranking.js +41 -0
- package/dist/src/graph/sqlite-graph-store.d.ts +51 -0
- package/dist/src/graph/sqlite-graph-store.js +724 -0
- package/dist/src/graph/sqlite-statements.d.ts +36 -0
- package/dist/src/graph/sqlite-statements.js +105 -0
- package/dist/src/graph/target-matcher.d.ts +13 -0
- package/dist/src/graph/target-matcher.js +64 -0
- package/dist/src/index.d.ts +32 -0
- package/dist/src/index.js +32 -0
- package/dist/src/indexing/analyzers/fallback-analyzer.d.ts +6 -0
- package/dist/src/indexing/analyzers/fallback-analyzer.js +45 -0
- package/dist/src/indexing/analyzers/go-treesitter-analyzer.d.ts +2 -0
- package/dist/src/indexing/analyzers/go-treesitter-analyzer.js +87 -0
- package/dist/src/indexing/analyzers/java-treesitter-analyzer.d.ts +2 -0
- package/dist/src/indexing/analyzers/java-treesitter-analyzer.js +88 -0
- package/dist/src/indexing/analyzers/python-treesitter-analyzer.d.ts +2 -0
- package/dist/src/indexing/analyzers/python-treesitter-analyzer.js +96 -0
- package/dist/src/indexing/analyzers/registry.d.ts +5 -0
- package/dist/src/indexing/analyzers/registry.js +23 -0
- package/dist/src/indexing/analyzers/rust-treesitter-analyzer.d.ts +2 -0
- package/dist/src/indexing/analyzers/rust-treesitter-analyzer.js +96 -0
- package/dist/src/indexing/analyzers/tree-sitter-base.d.ts +30 -0
- package/dist/src/indexing/analyzers/tree-sitter-base.js +163 -0
- package/dist/src/indexing/analyzers/types.d.ts +17 -0
- package/dist/src/indexing/analyzers/types.js +1 -0
- package/dist/src/indexing/analyzers/typescript-analyzer.d.ts +5 -0
- package/dist/src/indexing/analyzers/typescript-analyzer.js +199 -0
- package/dist/src/indexing/ast-analyzer.d.ts +11 -0
- package/dist/src/indexing/ast-analyzer.js +11 -0
- package/dist/src/indexing/chunker.d.ts +11 -0
- package/dist/src/indexing/chunker.js +157 -0
- package/dist/src/indexing/ignore-policy.d.ts +6 -0
- package/dist/src/indexing/ignore-policy.js +40 -0
- package/dist/src/indexing/indexer.d.ts +13 -0
- package/dist/src/indexing/indexer.js +189 -0
- package/dist/src/indexing/language.d.ts +3 -0
- package/dist/src/indexing/language.js +24 -0
- package/dist/src/indexing/scanner.d.ts +13 -0
- package/dist/src/indexing/scanner.js +87 -0
- package/dist/src/lsp/definition-resolver.d.ts +6 -0
- package/dist/src/lsp/definition-resolver.js +60 -0
- package/dist/src/lsp/typescript-language-service.d.ts +21 -0
- package/dist/src/lsp/typescript-language-service.js +82 -0
- package/dist/src/mcp/server.d.ts +11 -0
- package/dist/src/mcp/server.js +64 -0
- package/dist/src/mcp/tools.d.ts +266 -0
- package/dist/src/mcp/tools.js +309 -0
- package/dist/src/project/project-identity.d.ts +2 -0
- package/dist/src/project/project-identity.js +24 -0
- package/dist/src/project/project-registry.d.ts +12 -0
- package/dist/src/project/project-registry.js +49 -0
- package/dist/src/project/workspace-resolver.d.ts +20 -0
- package/dist/src/project/workspace-resolver.js +62 -0
- package/dist/src/retrieval/graph-reranker.d.ts +11 -0
- package/dist/src/retrieval/graph-reranker.js +0 -0
- package/dist/src/retrieval/hybrid-retriever.d.ts +31 -0
- package/dist/src/retrieval/hybrid-retriever.js +111 -0
- package/dist/src/retrieval/path-classification.d.ts +6 -0
- package/dist/src/retrieval/path-classification.js +22 -0
- package/dist/src/retrieval/query-matching.d.ts +22 -0
- package/dist/src/retrieval/query-matching.js +166 -0
- package/dist/src/retrieval/query-planner.d.ts +5 -0
- package/dist/src/retrieval/query-planner.js +77 -0
- package/dist/src/retrieval/ranking-signals.d.ts +19 -0
- package/dist/src/retrieval/ranking-signals.js +97 -0
- package/dist/src/retrieval/topology-distance.d.ts +21 -0
- package/dist/src/retrieval/topology-distance.js +116 -0
- package/dist/src/reuse/reuse-detector.d.ts +12 -0
- package/dist/src/reuse/reuse-detector.js +564 -0
- package/dist/src/semantic/deterministic-embedding.d.ts +7 -0
- package/dist/src/semantic/deterministic-embedding.js +31 -0
- package/dist/src/semantic/in-memory-semantic-store.d.ts +11 -0
- package/dist/src/semantic/in-memory-semantic-store.js +65 -0
- package/dist/src/semantic/lance-semantic-store.d.ts +131 -0
- package/dist/src/semantic/lance-semantic-store.js +623 -0
- package/dist/src/semantic/openai-compatible-embedding.d.ts +19 -0
- package/dist/src/semantic/openai-compatible-embedding.js +75 -0
- package/dist/src/service/service-identity.d.ts +13 -0
- package/dist/src/service/service-identity.js +48 -0
- package/dist/src/service/service-manager.d.ts +29 -0
- package/dist/src/service/service-manager.js +231 -0
- package/dist/src/service/service-templates.d.ts +22 -0
- package/dist/src/service/service-templates.js +101 -0
- package/dist/src/subgraph/impact-explainer.d.ts +2 -0
- package/dist/src/subgraph/impact-explainer.js +54 -0
- package/dist/src/subgraph/node-expander.d.ts +13 -0
- package/dist/src/subgraph/node-expander.js +139 -0
- package/dist/src/subgraph/output-preset.d.ts +3 -0
- package/dist/src/subgraph/output-preset.js +102 -0
- package/dist/src/subgraph/subgraph-builder.d.ts +17 -0
- package/dist/src/subgraph/subgraph-builder.js +688 -0
- package/dist/src/topology/export-index.d.ts +7 -0
- package/dist/src/topology/export-index.js +14 -0
- package/dist/src/topology/framework-topology.d.ts +3 -0
- package/dist/src/topology/framework-topology.js +460 -0
- package/dist/src/topology/import-resolver.d.ts +2 -0
- package/dist/src/topology/import-resolver.js +29 -0
- package/dist/src/topology/orm-topology.d.ts +3 -0
- package/dist/src/topology/orm-topology.js +200 -0
- package/dist/src/topology/runtime-topology.d.ts +3 -0
- package/dist/src/topology/runtime-topology.js +204 -0
- package/dist/src/topology/symbol-resolver.d.ts +6 -0
- package/dist/src/topology/symbol-resolver.js +74 -0
- package/dist/src/topology/test-topology.d.ts +2 -0
- package/dist/src/topology/test-topology.js +82 -0
- package/dist/src/utils/hash.d.ts +2 -0
- package/dist/src/utils/hash.js +7 -0
- package/dist/src/utils/path.d.ts +2 -0
- package/dist/src/utils/path.js +7 -0
- package/dist/src/watch/event-journal.d.ts +17 -0
- package/dist/src/watch/event-journal.js +81 -0
- package/dist/src/watch/file-event-coalescer.d.ts +9 -0
- package/dist/src/watch/file-event-coalescer.js +39 -0
- package/dist/src/watch/index-scheduler.d.ts +52 -0
- package/dist/src/watch/index-scheduler.js +190 -0
- package/dist/src/watch/watch-daemon.d.ts +73 -0
- package/dist/src/watch/watch-daemon.js +368 -0
- package/dist/src/watch/watcher-liveness.d.ts +47 -0
- package/dist/src/watch/watcher-liveness.js +168 -0
- package/dist/src/web/server.d.ts +1 -0
- package/dist/src/web/server.js +375 -0
- package/package.json +94 -0
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { loadDotEnv } from "../config/dotenv.js";
|
|
5
|
+
import { createRuntimeComponentsForRepo } from "../config/runtime-config.js";
|
|
6
|
+
import { RagCodeEngine } from "../core/engine.js";
|
|
7
|
+
import { runConfigureCommand } from "./configure.js";
|
|
8
|
+
import { runDoctor } from "../diagnostics/doctor.js";
|
|
9
|
+
import { startStdioMcpServer } from "../mcp/server.js";
|
|
10
|
+
import { buildExplainImpactReport } from "../subgraph/impact-explainer.js";
|
|
11
|
+
import { expandNode, parseNodeRef } from "../subgraph/node-expander.js";
|
|
12
|
+
import { FileWatchDaemon } from "../watch/watch-daemon.js";
|
|
13
|
+
import { WatcherLockError, readWatcherLiveness } from "../watch/watcher-liveness.js";
|
|
14
|
+
import { installWatcherService, uninstallWatcherService, watcherServiceStatus } from "../service/service-manager.js";
|
|
15
|
+
import { runInitConfig } from "../../scripts/init-config.js";
|
|
16
|
+
import { setupMCP } from "../../scripts/setup-mcp.js";
|
|
17
|
+
import { runUpdate } from "./update.js";
|
|
18
|
+
loadDotEnv();
|
|
19
|
+
const program = new Command();
|
|
20
|
+
program.name("ragcode").description("Local code intelligence context engine").version("0.1.0");
|
|
21
|
+
program
|
|
22
|
+
.command("index")
|
|
23
|
+
.argument("<repoRoot>")
|
|
24
|
+
.description("Index a repository")
|
|
25
|
+
.action(async (repoRoot) => {
|
|
26
|
+
if (process.stdout.isTTY) {
|
|
27
|
+
const { runIndexProgressTui } = await import("./tui/index-progress.js");
|
|
28
|
+
await runIndexProgressTui({
|
|
29
|
+
repoRoot,
|
|
30
|
+
run: async (onProgress) => withEngine(repoRoot, (engine) => engine.indexRepo(repoRoot, { onProgress }))
|
|
31
|
+
});
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
await withEngine(repoRoot, async (engine) => {
|
|
35
|
+
const result = await engine.indexRepo(repoRoot);
|
|
36
|
+
console.log(JSON.stringify({ repoRoot: result.repoRoot, files: result.files.length, chunks: result.chunks.length }, null, 2));
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
program
|
|
40
|
+
.command("search")
|
|
41
|
+
.argument("<repoRoot>")
|
|
42
|
+
.argument("<query>")
|
|
43
|
+
.option("-l, --limit <number>", "maximum hits", parseNumber)
|
|
44
|
+
.description("Search an already-indexed repository without re-indexing")
|
|
45
|
+
.action(async (repoRoot, query, options) => {
|
|
46
|
+
await withEngine(repoRoot, async (engine) => {
|
|
47
|
+
const hits = await engine.searchCode({ repoRoot, query, limit: options.limit });
|
|
48
|
+
console.log(JSON.stringify(hits.map((hit) => ({ filePath: hit.chunk.filePath, startLine: hit.chunk.startLine, endLine: hit.chunk.endLine, score: hit.score, source: hit.source, reason: hit.reason })), null, 2));
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
program
|
|
52
|
+
.command("status")
|
|
53
|
+
.argument("<repoRoot>")
|
|
54
|
+
.description("Report persisted index and dirty watcher state without indexing")
|
|
55
|
+
.action(async (repoRoot) => {
|
|
56
|
+
await withEngine(repoRoot, async (engine) => {
|
|
57
|
+
console.log(JSON.stringify(await engine.indexStatus(repoRoot), null, 2));
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
program
|
|
61
|
+
.command("context")
|
|
62
|
+
.argument("<repoRoot>")
|
|
63
|
+
.argument("<query>")
|
|
64
|
+
.option("-m, --mode <mode>", "context mode: auto/debug/feature/refactor/review/explain")
|
|
65
|
+
.option("-b, --budget <chars>", "character budget", parseNumber)
|
|
66
|
+
.description("Build a context pack")
|
|
67
|
+
.action(async (repoRoot, query, options) => {
|
|
68
|
+
await withEngine(repoRoot, async (engine) => {
|
|
69
|
+
const context = await engine.getContext({ repoRoot, query, budgetChars: options.budget, mode: options.mode });
|
|
70
|
+
console.log(JSON.stringify(context, null, 2));
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
program
|
|
74
|
+
.command("owner")
|
|
75
|
+
.argument("<repoRoot>")
|
|
76
|
+
.argument("<query>")
|
|
77
|
+
.description("Find likely owner files and symbols")
|
|
78
|
+
.action(async (repoRoot, query) => {
|
|
79
|
+
await withEngine(repoRoot, async (engine) => {
|
|
80
|
+
console.log(JSON.stringify(await engine.findOwner(repoRoot, query), null, 2));
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
program
|
|
84
|
+
.command("reuse")
|
|
85
|
+
.argument("<repoRoot>")
|
|
86
|
+
.argument("<query>")
|
|
87
|
+
.option("-l, --limit <number>", "maximum candidates", parseNumber)
|
|
88
|
+
.description("Find reusable existing code before implementing new behavior")
|
|
89
|
+
.action(async (repoRoot, query, options) => {
|
|
90
|
+
await withEngine(repoRoot, async (engine) => {
|
|
91
|
+
console.log(JSON.stringify(await engine.findReuseCandidates({ repoRoot, query, limit: options.limit }), null, 2));
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
program
|
|
95
|
+
.command("expand-node")
|
|
96
|
+
.argument("<repoRoot>")
|
|
97
|
+
.argument("<nodeRef>")
|
|
98
|
+
.option("-e, --expansion <level>", "file_card/skeleton/focused_body/full_body")
|
|
99
|
+
.option("-b, --budget <chars>", "character budget", parseNumber)
|
|
100
|
+
.description("Expand one compact subgraph node under budget")
|
|
101
|
+
.action(async (repoRoot, nodeRef, options) => {
|
|
102
|
+
await withEngine(repoRoot, async (engine) => {
|
|
103
|
+
const parsed = parseNodeRef(nodeRef);
|
|
104
|
+
const indexedFile = await engine.explainFile(repoRoot, parsed.filePath);
|
|
105
|
+
console.log(JSON.stringify(expandNode({
|
|
106
|
+
nodeRef,
|
|
107
|
+
chunks: indexedFile.chunks,
|
|
108
|
+
symbols: indexedFile.symbols,
|
|
109
|
+
expansionLevel: options.expansion,
|
|
110
|
+
budgetChars: options.budget
|
|
111
|
+
}), null, 2));
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
program
|
|
115
|
+
.command("impact")
|
|
116
|
+
.argument("<repoRoot>")
|
|
117
|
+
.argument("<target>")
|
|
118
|
+
.description("Estimate structural impact for a file or symbol")
|
|
119
|
+
.action(async (repoRoot, target) => {
|
|
120
|
+
await withEngine(repoRoot, async (engine) => {
|
|
121
|
+
console.log(JSON.stringify(await engine.impactAnalysis(repoRoot, target), null, 2));
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
program
|
|
125
|
+
.command("explain-impact")
|
|
126
|
+
.argument("<repoRoot>")
|
|
127
|
+
.argument("<target>")
|
|
128
|
+
.option("-b, --budget <chars>", "character budget", parseNumber)
|
|
129
|
+
.option("--max-hops <number>", "maximum graph hops", parseNumber)
|
|
130
|
+
.description("Explain blast radius as a verified minimal code subgraph")
|
|
131
|
+
.action(async (repoRoot, target, options) => {
|
|
132
|
+
await withEngine(repoRoot, async (engine) => {
|
|
133
|
+
const subgraph = await engine.verifiedSubgraph({
|
|
134
|
+
repoRoot,
|
|
135
|
+
query: target,
|
|
136
|
+
seed: target,
|
|
137
|
+
mode: "impact",
|
|
138
|
+
budgetChars: options.budget,
|
|
139
|
+
maxHops: options.maxHops
|
|
140
|
+
});
|
|
141
|
+
console.log(JSON.stringify(buildExplainImpactReport(target, subgraph), null, 2));
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
program
|
|
145
|
+
.command("tests")
|
|
146
|
+
.argument("<repoRoot>")
|
|
147
|
+
.argument("<target>")
|
|
148
|
+
.description("Find likely related tests")
|
|
149
|
+
.action(async (repoRoot, target) => {
|
|
150
|
+
await withEngine(repoRoot, async (engine) => {
|
|
151
|
+
console.log(JSON.stringify(await engine.relatedTests(repoRoot, target), null, 2));
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
program
|
|
155
|
+
.command("trace-request-flow")
|
|
156
|
+
.argument("<repoRoot>")
|
|
157
|
+
.argument("<entry>")
|
|
158
|
+
.option("-q, --query <query>", "optional flow query text")
|
|
159
|
+
.option("-b, --budget <chars>", "character budget", parseNumber)
|
|
160
|
+
.option("--max-hops <number>", "maximum graph hops", parseNumber)
|
|
161
|
+
.description("Trace request/data flow as a verified ordered code subgraph")
|
|
162
|
+
.action(async (repoRoot, entry, options) => {
|
|
163
|
+
await withEngine(repoRoot, async (engine) => {
|
|
164
|
+
console.log(JSON.stringify(await engine.verifiedSubgraph({
|
|
165
|
+
repoRoot,
|
|
166
|
+
query: options.query ?? entry,
|
|
167
|
+
seed: entry,
|
|
168
|
+
mode: "flow",
|
|
169
|
+
budgetChars: options.budget,
|
|
170
|
+
maxHops: options.maxHops
|
|
171
|
+
}), null, 2));
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
program
|
|
175
|
+
.command("record-events")
|
|
176
|
+
.argument("<repoRoot>")
|
|
177
|
+
.argument("<filePaths...>")
|
|
178
|
+
.option("--burst-threshold <number>", "dirty file count that activates burst mode", parseNumber)
|
|
179
|
+
.option("--max-dirty-files <number>", "maximum dirty file paths to retain from one batch", parseNumber)
|
|
180
|
+
.description("Record watcher file events as dirty state without indexing immediately")
|
|
181
|
+
.action(async (repoRoot, filePaths, options) => {
|
|
182
|
+
await withEngine(repoRoot, async (engine) => {
|
|
183
|
+
console.log(JSON.stringify(await engine.recordFileEvents(repoRoot, filePaths, options), null, 2));
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
program
|
|
187
|
+
.command("watch")
|
|
188
|
+
.argument("<repoRoot>")
|
|
189
|
+
.option("--batch-delay <ms>", "delay before background indexing after dirty events", parseNumber)
|
|
190
|
+
.option("--quiet <ms>", "minimum quiet period before indexing", parseNumber)
|
|
191
|
+
.option("--flush-events <ms>", "delay before flushing observed file events to dirty state", parseNumber)
|
|
192
|
+
.option("--await-write <ms>", "await-write-finish stability threshold", parseNumber)
|
|
193
|
+
.option("--burst-threshold <number>", "dirty file count that activates burst mode", parseNumber)
|
|
194
|
+
.option("--max-dirty-files <number>", "maximum dirty file paths to retain from one batch", parseNumber)
|
|
195
|
+
.option("--max-batch-files <number>", "maximum dirty file paths to mark indexing in one scheduler batch", parseNumber)
|
|
196
|
+
.option("--poll", "use polling instead of native fs.watch")
|
|
197
|
+
.option("--no-auto-index", "record dirty events but do not run background refresh")
|
|
198
|
+
.option("--no-index-on-start", "fail if the repo is not already indexed instead of indexing before watching")
|
|
199
|
+
.description("Run a long-lived filesystem watcher daemon with event journal replay and background batch indexing")
|
|
200
|
+
.action(async (repoRoot, options) => {
|
|
201
|
+
const engine = buildCliEngine(repoRoot);
|
|
202
|
+
if (process.stdout.isTTY) {
|
|
203
|
+
const { createWatchStatusTui } = await import("./tui/watch-status.js");
|
|
204
|
+
const absoluteRoot = path.resolve(repoRoot);
|
|
205
|
+
let tui;
|
|
206
|
+
let shuttingDown = false;
|
|
207
|
+
const daemon = new FileWatchDaemon(engine, repoRoot, {
|
|
208
|
+
batchDelayMs: options.batchDelay,
|
|
209
|
+
minQuietMs: options.quiet,
|
|
210
|
+
flushEventsMs: options.flushEvents,
|
|
211
|
+
awaitWriteFinishMs: options.awaitWrite,
|
|
212
|
+
burstThreshold: options.burstThreshold,
|
|
213
|
+
maxDirtyFiles: options.maxDirtyFiles,
|
|
214
|
+
maxBatchFiles: options.maxBatchFiles,
|
|
215
|
+
usePolling: options.poll,
|
|
216
|
+
autoIndex: options.autoIndex,
|
|
217
|
+
indexOnStart: options.indexOnStart,
|
|
218
|
+
onStatus: (status) => tui?.update(status)
|
|
219
|
+
});
|
|
220
|
+
tui = createWatchStatusTui({
|
|
221
|
+
repoRoot: absoluteRoot,
|
|
222
|
+
running: false,
|
|
223
|
+
ready: false,
|
|
224
|
+
bufferedEvents: 0,
|
|
225
|
+
scheduler: {
|
|
226
|
+
repoRoot: absoluteRoot,
|
|
227
|
+
running: false,
|
|
228
|
+
scheduled: false,
|
|
229
|
+
indexing: false,
|
|
230
|
+
pendingFiles: 0,
|
|
231
|
+
indexingFiles: 0
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
const shutdown = async () => {
|
|
235
|
+
if (shuttingDown)
|
|
236
|
+
return;
|
|
237
|
+
shuttingDown = true;
|
|
238
|
+
await daemon.stop();
|
|
239
|
+
engine.close();
|
|
240
|
+
tui?.unmount();
|
|
241
|
+
};
|
|
242
|
+
const exitFromSignal = () => {
|
|
243
|
+
void shutdown().finally(() => process.exit(0));
|
|
244
|
+
};
|
|
245
|
+
process.once("SIGINT", exitFromSignal);
|
|
246
|
+
process.once("SIGTERM", exitFromSignal);
|
|
247
|
+
try {
|
|
248
|
+
await daemon.start();
|
|
249
|
+
tui.update(await daemon.status());
|
|
250
|
+
await tui.waitUntilExit();
|
|
251
|
+
}
|
|
252
|
+
catch (error) {
|
|
253
|
+
if (error instanceof WatcherLockError) {
|
|
254
|
+
// Another live watcher already owns this repo. shutdown() (guarded, runs in finally)
|
|
255
|
+
// tears down our half-started daemon and closes the engine; just surface the reason.
|
|
256
|
+
tui?.unmount();
|
|
257
|
+
console.error(`⚠️ ${error.message}`);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
throw error;
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
process.removeListener("SIGINT", exitFromSignal);
|
|
264
|
+
process.removeListener("SIGTERM", exitFromSignal);
|
|
265
|
+
await shutdown();
|
|
266
|
+
}
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
const daemon = new FileWatchDaemon(engine, repoRoot, {
|
|
270
|
+
batchDelayMs: options.batchDelay,
|
|
271
|
+
minQuietMs: options.quiet,
|
|
272
|
+
flushEventsMs: options.flushEvents,
|
|
273
|
+
awaitWriteFinishMs: options.awaitWrite,
|
|
274
|
+
burstThreshold: options.burstThreshold,
|
|
275
|
+
maxDirtyFiles: options.maxDirtyFiles,
|
|
276
|
+
maxBatchFiles: options.maxBatchFiles,
|
|
277
|
+
usePolling: options.poll,
|
|
278
|
+
autoIndex: options.autoIndex,
|
|
279
|
+
indexOnStart: options.indexOnStart,
|
|
280
|
+
onStatus: (status) => {
|
|
281
|
+
console.error(JSON.stringify({ watcher: status }));
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
const shutdown = async () => {
|
|
285
|
+
await daemon.stop();
|
|
286
|
+
engine.close();
|
|
287
|
+
};
|
|
288
|
+
process.once("SIGINT", () => {
|
|
289
|
+
void shutdown().finally(() => process.exit(0));
|
|
290
|
+
});
|
|
291
|
+
process.once("SIGTERM", () => {
|
|
292
|
+
void shutdown().finally(() => process.exit(0));
|
|
293
|
+
});
|
|
294
|
+
try {
|
|
295
|
+
await daemon.start();
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
if (error instanceof WatcherLockError) {
|
|
299
|
+
engine.close();
|
|
300
|
+
console.error(error.message);
|
|
301
|
+
process.exitCode = 1;
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
console.log(JSON.stringify(await daemon.status(), null, 2));
|
|
307
|
+
});
|
|
308
|
+
const service = program
|
|
309
|
+
.command("service")
|
|
310
|
+
.description("Manage the background watcher as an OS service (one per repo) so freshness survives reboots");
|
|
311
|
+
service
|
|
312
|
+
.command("install")
|
|
313
|
+
.argument("<repoRoot>")
|
|
314
|
+
.option("--poll", "register the watcher with polling instead of native fs.watch")
|
|
315
|
+
.description("Register and start a background watcher service for this repo (systemd user / launchd / Task Scheduler)")
|
|
316
|
+
.action(async (repoRoot, options) => {
|
|
317
|
+
// Index once up front so the service can start with --no-index-on-start and not block on a full
|
|
318
|
+
// reindex at boot. Then register the OS unit. The per-repo lock (P0) makes redundant launches safe.
|
|
319
|
+
await withEngine(repoRoot, (engine) => engine.indexRepo(repoRoot));
|
|
320
|
+
try {
|
|
321
|
+
const result = await installWatcherService(repoRoot, { extraArgs: options.poll ? ["--poll"] : undefined });
|
|
322
|
+
console.log(JSON.stringify(result, null, 2));
|
|
323
|
+
if (!result.ok)
|
|
324
|
+
process.exitCode = 1;
|
|
325
|
+
}
|
|
326
|
+
catch (error) {
|
|
327
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
328
|
+
process.exitCode = 1;
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
service
|
|
332
|
+
.command("uninstall")
|
|
333
|
+
.argument("<repoRoot>")
|
|
334
|
+
.description("Stop and remove the background watcher service for this repo")
|
|
335
|
+
.action(async (repoRoot) => {
|
|
336
|
+
try {
|
|
337
|
+
const result = await uninstallWatcherService(repoRoot);
|
|
338
|
+
console.log(JSON.stringify(result, null, 2));
|
|
339
|
+
if (!result.ok)
|
|
340
|
+
process.exitCode = 1;
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
344
|
+
process.exitCode = 1;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
service
|
|
348
|
+
.command("status")
|
|
349
|
+
.argument("<repoRoot>")
|
|
350
|
+
.description("Report whether a watcher service is registered and whether the watcher process is alive")
|
|
351
|
+
.action(async (repoRoot) => {
|
|
352
|
+
const [registration, liveness] = await Promise.all([
|
|
353
|
+
watcherServiceStatus(repoRoot),
|
|
354
|
+
readWatcherLiveness(path.resolve(repoRoot))
|
|
355
|
+
]);
|
|
356
|
+
console.log(JSON.stringify({ registration, liveness }, null, 2));
|
|
357
|
+
});
|
|
358
|
+
program
|
|
359
|
+
.command("doctor")
|
|
360
|
+
.argument("[repoRoot]")
|
|
361
|
+
.option("-q, --query <query>", "query to use when repoRoot smoke indexing is enabled")
|
|
362
|
+
.description("Check runtime dependencies, env config, MCP registration, and optional repo indexing/search smoke")
|
|
363
|
+
.action(async (repoRoot, options) => {
|
|
364
|
+
const report = await runDoctor({ repoRoot, searchQuery: options.query });
|
|
365
|
+
console.log(JSON.stringify(report, null, 2));
|
|
366
|
+
if (!report.ok)
|
|
367
|
+
process.exitCode = 1;
|
|
368
|
+
});
|
|
369
|
+
program
|
|
370
|
+
.command("mcp")
|
|
371
|
+
.description("Start the RagCode MCP server over stdio")
|
|
372
|
+
.action(async () => {
|
|
373
|
+
await startStdioMcpServer();
|
|
374
|
+
});
|
|
375
|
+
program
|
|
376
|
+
.command("init")
|
|
377
|
+
.argument("[directory]")
|
|
378
|
+
.option("-y, --yes", "write offline-first defaults without interactive prompts")
|
|
379
|
+
.option("--defaults", "write offline-first defaults without interactive prompts")
|
|
380
|
+
.description("Initialize RagCode configuration (interactive first-run setup)")
|
|
381
|
+
.action(async (directory, options) => {
|
|
382
|
+
const targetDir = directory || process.cwd();
|
|
383
|
+
const defaults = Boolean(options.yes || options.defaults);
|
|
384
|
+
if (!defaults && process.stdin.isTTY) {
|
|
385
|
+
// Interactive first-run goes through the Ink wizard (same app as `ragcode configure`,
|
|
386
|
+
// first_run mode defaults index/setup-mcp to yes). Loaded lazily to keep --defaults light.
|
|
387
|
+
const { runInkConfigure } = await import("./configure/run.js");
|
|
388
|
+
await runInkConfigure({ repoRoot: targetDir, mode: "first_run" });
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
await runInitConfig({ targetDir, defaults: true });
|
|
392
|
+
});
|
|
393
|
+
program
|
|
394
|
+
.command("setup-mcp")
|
|
395
|
+
.option("--config <path>", "Custom MCP config path")
|
|
396
|
+
.option("--print", "Print config without writing")
|
|
397
|
+
.option("--include-secrets", "Include real secrets instead of redacted placeholders")
|
|
398
|
+
.option("--client <client>", "Client format: claude (Desktop), claude-code (project .mcp.json), codex (~/.codex/config.toml), or generic")
|
|
399
|
+
.option("--force", "Overwrite an existing ragcode entry without prompting")
|
|
400
|
+
.description("Register RagCode as an MCP server for Claude Desktop, Claude Code, or Codex")
|
|
401
|
+
.action(async (options) => {
|
|
402
|
+
setupMCP({
|
|
403
|
+
configPath: options.config,
|
|
404
|
+
print: options.print,
|
|
405
|
+
includeSecrets: options.includeSecrets,
|
|
406
|
+
client: options.client,
|
|
407
|
+
force: options.force,
|
|
408
|
+
cwd: process.cwd(),
|
|
409
|
+
env: process.env
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
program
|
|
413
|
+
.command("configure")
|
|
414
|
+
.argument("[repoRoot]")
|
|
415
|
+
.option("--show", "Print the effective runtime config (secrets redacted) and exit")
|
|
416
|
+
.option("--graph-store <store>", "Graph store: memory or sqlite")
|
|
417
|
+
.option("--sqlite-path <path>", "SQLite graph database path")
|
|
418
|
+
.option("--semantic-store <store>", "Semantic store: memory or lancedb")
|
|
419
|
+
.option("--lancedb-uri <path>", "LanceDB storage path")
|
|
420
|
+
.option("--embedding-provider <provider>", "Embedding provider: deterministic or openai-compatible")
|
|
421
|
+
.option("--base-url <url>", "Embedding API base URL")
|
|
422
|
+
.option("--model <model>", "Embedding model name")
|
|
423
|
+
.option("--api-key <key>", "Embedding API key (persisted to .ragcode/config.json)")
|
|
424
|
+
.option("--dimensions <number>", "Embedding dimensions", parseNumber)
|
|
425
|
+
.option("--request-dimensions <bool>", "Send dimensions parameter to the provider (true/false)")
|
|
426
|
+
.description("Edit storage and embedding runtime config from the terminal, with embedding test")
|
|
427
|
+
.action(async (repoRoot, options) => {
|
|
428
|
+
await runConfigureCommand(repoRoot, {
|
|
429
|
+
show: options.show,
|
|
430
|
+
test: options.test,
|
|
431
|
+
graphStore: options.graphStore,
|
|
432
|
+
sqlitePath: options.sqlitePath,
|
|
433
|
+
semanticStore: options.semanticStore,
|
|
434
|
+
lancedbUri: options.lancedbUri,
|
|
435
|
+
embeddingProvider: options.embeddingProvider,
|
|
436
|
+
embeddingBaseUrl: options.baseUrl,
|
|
437
|
+
embeddingModel: options.model,
|
|
438
|
+
embeddingApiKey: options.apiKey,
|
|
439
|
+
embeddingDimensions: options.dimensions,
|
|
440
|
+
embeddingRequestDimensions: options.requestDimensions === undefined ? undefined : options.requestDimensions === "true"
|
|
441
|
+
});
|
|
442
|
+
});
|
|
443
|
+
program
|
|
444
|
+
.command("update")
|
|
445
|
+
.option("--check", "only report whether a newer version is available; don't install")
|
|
446
|
+
.option("--pm <manager>", "package manager to use: npm, pnpm, or yarn (default: auto-detect)")
|
|
447
|
+
.option("--version <version>", "install a specific version or dist-tag instead of latest")
|
|
448
|
+
.description("Update the globally-installed RagCode CLI to the latest version")
|
|
449
|
+
.action(async (options) => {
|
|
450
|
+
const result = await runUpdate({ checkOnly: options.check, packageManager: options.pm, version: options.version });
|
|
451
|
+
console.log(result.message);
|
|
452
|
+
if (!result.ok)
|
|
453
|
+
process.exitCode = 1;
|
|
454
|
+
});
|
|
455
|
+
program
|
|
456
|
+
.command("dashboard")
|
|
457
|
+
.description("Start the Web observability dashboard API (graph/search/context/watch observation)")
|
|
458
|
+
.action(async () => {
|
|
459
|
+
await import("../web/server.js");
|
|
460
|
+
});
|
|
461
|
+
program.parseAsync().catch((error) => {
|
|
462
|
+
const message = formatCliError(error);
|
|
463
|
+
console.error(message);
|
|
464
|
+
process.exitCode = 1;
|
|
465
|
+
});
|
|
466
|
+
async function withEngine(repoRoot, fn) {
|
|
467
|
+
const engine = buildCliEngine(repoRoot);
|
|
468
|
+
try {
|
|
469
|
+
return await fn(engine);
|
|
470
|
+
}
|
|
471
|
+
finally {
|
|
472
|
+
engine.close();
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// CLI commands resolve runtime config through the shared loader so that explicit args, env,
|
|
476
|
+
// .ragcode/config.json, and offline-first defaults (sqlite + lancedb + deterministic) apply
|
|
477
|
+
// uniformly across CLI, MCP, Web, and doctor. The engine constructor itself stays env-driven
|
|
478
|
+
// for embedded/library/test usage.
|
|
479
|
+
function buildCliEngine(repoRoot) {
|
|
480
|
+
const components = createRuntimeComponentsForRepo({
|
|
481
|
+
cwd: process.cwd(),
|
|
482
|
+
overrides: repoRoot ? { repoRoot } : undefined
|
|
483
|
+
});
|
|
484
|
+
return new RagCodeEngine({
|
|
485
|
+
cwd: repoRoot,
|
|
486
|
+
graphStore: components.graphStore,
|
|
487
|
+
semanticStore: components.semanticStore,
|
|
488
|
+
embeddingProvider: components.embeddingProvider
|
|
489
|
+
});
|
|
490
|
+
}
|
|
491
|
+
function parseNumber(value) {
|
|
492
|
+
const parsed = Number(value);
|
|
493
|
+
if (!Number.isFinite(parsed))
|
|
494
|
+
throw new Error(`Invalid number: ${value}`);
|
|
495
|
+
return parsed;
|
|
496
|
+
}
|
|
497
|
+
function formatCliError(error) {
|
|
498
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
499
|
+
if (/Workspace is not indexed|Missing workspace|Repository is not indexed/i.test(message)) {
|
|
500
|
+
return `${message}\nRun "ragcode index <repoRoot>" first, then retry the read command. CLI reads default to SQLite at <repoRoot>/.ragcode/graph.sqlite unless RAGCODE_SQLITE_PATH is set.`;
|
|
501
|
+
}
|
|
502
|
+
return message;
|
|
503
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IndexProgressEvent, RepoIndex } from "../../core/types.js";
|
|
2
|
+
export interface IndexProgressAppProps {
|
|
3
|
+
repoRoot: string;
|
|
4
|
+
events: IndexProgressEvent[];
|
|
5
|
+
result?: RepoIndex;
|
|
6
|
+
error?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function IndexProgressApp({ repoRoot, events, result, error }: IndexProgressAppProps): React.ReactElement;
|
|
9
|
+
export declare function runIndexProgressTui(options: {
|
|
10
|
+
repoRoot: string;
|
|
11
|
+
run: (onProgress: (event: IndexProgressEvent) => void) => Promise<RepoIndex>;
|
|
12
|
+
}): Promise<RepoIndex>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { render, Box, Text } from "ink";
|
|
3
|
+
export function IndexProgressApp({ repoRoot, events, result, error }) {
|
|
4
|
+
const latest = events.at(-1);
|
|
5
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "RagCode Index" }), _jsxs(Text, { dimColor: true, children: ["repo: ", repoRoot] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [events.slice(-6).map((event, index) => (_jsxs(Text, { color: index === events.slice(-6).length - 1 && !result && !error ? "green" : undefined, children: [event.phase === "complete" ? "✓" : "•", " ", event.message, formatEventStats(event)] }, `${event.phase}-${index}`))), !latest ? _jsx(Text, { children: "\u2022 Preparing index" }) : null] }), result ? (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { color: "green", children: ["Indexed ", result.files.length, " files, ", result.chunks.length, " chunks."] }), _jsxs(Text, { dimColor: true, children: ["changed ", result.changedFiles.length, ", deleted ", result.deletedFiles.length, ", refreshed ", result.refreshedFiles?.length ?? 0] })] })) : null, error ? _jsxs(Text, { color: "red", children: ["Index failed: ", error] }) : null] }));
|
|
6
|
+
}
|
|
7
|
+
export async function runIndexProgressTui(options) {
|
|
8
|
+
const events = [];
|
|
9
|
+
let result;
|
|
10
|
+
let error;
|
|
11
|
+
const app = render(_jsx(IndexProgressApp, { repoRoot: options.repoRoot, events: events }));
|
|
12
|
+
const update = () => {
|
|
13
|
+
app.rerender(_jsx(IndexProgressApp, { repoRoot: options.repoRoot, events: [...events], result: result, error: error }));
|
|
14
|
+
};
|
|
15
|
+
try {
|
|
16
|
+
result = await options.run((event) => {
|
|
17
|
+
events.push(event);
|
|
18
|
+
update();
|
|
19
|
+
});
|
|
20
|
+
update();
|
|
21
|
+
return result;
|
|
22
|
+
}
|
|
23
|
+
catch (caught) {
|
|
24
|
+
error = caught instanceof Error ? caught.message : String(caught);
|
|
25
|
+
update();
|
|
26
|
+
throw caught;
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
app.unmount();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function formatEventStats(event) {
|
|
33
|
+
const parts = [];
|
|
34
|
+
if (event.scannedFiles !== undefined)
|
|
35
|
+
parts.push(`scanned ${event.scannedFiles}`);
|
|
36
|
+
if (event.changedFiles !== undefined)
|
|
37
|
+
parts.push(`changed ${event.changedFiles}`);
|
|
38
|
+
if (event.deletedFiles !== undefined)
|
|
39
|
+
parts.push(`deleted ${event.deletedFiles}`);
|
|
40
|
+
if (event.refreshedFiles !== undefined)
|
|
41
|
+
parts.push(`refreshed ${event.refreshedFiles}`);
|
|
42
|
+
if (event.chunks !== undefined)
|
|
43
|
+
parts.push(`chunks ${event.chunks}`);
|
|
44
|
+
if (event.symbols !== undefined)
|
|
45
|
+
parts.push(`symbols ${event.symbols}`);
|
|
46
|
+
if (event.edges !== undefined)
|
|
47
|
+
parts.push(`edges ${event.edges}`);
|
|
48
|
+
return parts.length > 0 ? ` (${parts.join(", ")})` : "";
|
|
49
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WatchDaemonStatus } from "../../watch/watch-daemon.js";
|
|
2
|
+
export interface WatchStatusAppProps {
|
|
3
|
+
status: WatchDaemonStatus;
|
|
4
|
+
}
|
|
5
|
+
export declare function WatchStatusApp({ status }: WatchStatusAppProps): React.ReactElement;
|
|
6
|
+
export declare function createWatchStatusTui(initialStatus: WatchDaemonStatus): {
|
|
7
|
+
update(status: WatchDaemonStatus): void;
|
|
8
|
+
waitUntilExit(): Promise<void>;
|
|
9
|
+
unmount(): void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { render, Box, Text, useApp, useInput } from "ink";
|
|
3
|
+
export function WatchStatusApp({ status }) {
|
|
4
|
+
const { exit } = useApp();
|
|
5
|
+
useInput((input, key) => {
|
|
6
|
+
if (key.escape || (key.ctrl && input === "c"))
|
|
7
|
+
exit();
|
|
8
|
+
});
|
|
9
|
+
const scheduler = status.scheduler;
|
|
10
|
+
const healthColor = scheduler.lastError ? "red" : status.ready ? "green" : "yellow";
|
|
11
|
+
const health = scheduler.lastError ? "error" : status.ready ? "ready" : "starting";
|
|
12
|
+
return (_jsxs(Box, { flexDirection: "column", paddingX: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "RagCode Watch" }), _jsxs(Text, { dimColor: true, children: ["repo: ", status.repoRoot] }), _jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsxs(Text, { children: ["Status: ", _jsx(Text, { color: healthColor, children: health }), " ", status.running ? "running" : "stopped"] }), _jsxs(Text, { children: ["Events: buffered ", status.bufferedEvents, ", pending ", scheduler.pendingFiles, ", indexing ", scheduler.indexingFiles] }), _jsxs(Text, { children: ["Scheduler: ", scheduler.running ? "running" : "stopped", ", ", scheduler.scheduled ? "scheduled" : "idle", ", ", scheduler.indexing ? "indexing" : "not indexing"] }), _jsxs(Text, { children: ["Last indexed: ", scheduler.lastIndexedAtMs ? new Date(scheduler.lastIndexedAtMs).toLocaleString() : "never in this session"] }), scheduler.lastError ? _jsxs(Text, { color: "red", children: ["Last error: ", scheduler.lastError] }) : null] }), _jsx(Text, { dimColor: true, children: "Ctrl+C or Esc to stop" })] }));
|
|
13
|
+
}
|
|
14
|
+
export function createWatchStatusTui(initialStatus) {
|
|
15
|
+
const app = render(_jsx(WatchStatusApp, { status: initialStatus }));
|
|
16
|
+
return {
|
|
17
|
+
update(status) {
|
|
18
|
+
app.rerender(_jsx(WatchStatusApp, { status: status }));
|
|
19
|
+
},
|
|
20
|
+
async waitUntilExit() {
|
|
21
|
+
await app.waitUntilExit();
|
|
22
|
+
},
|
|
23
|
+
unmount() {
|
|
24
|
+
app.unmount();
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export declare const PACKAGE_NAME = "ragcode-context-engine";
|
|
2
|
+
export interface UpdateOptions {
|
|
3
|
+
/** Only report current vs latest; don't install. */
|
|
4
|
+
checkOnly?: boolean;
|
|
5
|
+
/** Override the package manager (npm/pnpm/yarn). Defaults to auto-detect. */
|
|
6
|
+
packageManager?: string;
|
|
7
|
+
/** Override the dist-tag/version to install. Defaults to "latest". */
|
|
8
|
+
version?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface UpdateResult {
|
|
11
|
+
ok: boolean;
|
|
12
|
+
currentVersion: string;
|
|
13
|
+
latestVersion?: string;
|
|
14
|
+
upToDate: boolean;
|
|
15
|
+
installed: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function runUpdate(options?: UpdateOptions): Promise<UpdateResult>;
|