Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,12 @@ The lock files for projects with zero direct `PackageReference` entries (e.g. `t
| DTOs | `Models/FileRecord.cs`, `Models/ChunkRecord.cs`, `Models/SymbolRecord.cs`, `Models/ReferenceRecord.cs` | Records shared by indexing, storage, query, and MCP layers. |
| Tests | `tests/CodeIndex.Tests/*Tests.cs`, `TestProjectHelper.cs`, `TestConsoleLock.cs` | Focused unit/integration coverage for chunking, extraction, DB reads/writes, CLI behavior, MCP behavior, git helpers, and shared test harness utilities. |

### Workspaces

`cdidx.workspace.json` and `.cdidx-workspace.json` declare monorepo members without adding a YAML dependency. The supported schema is additive: `members` is an array of member paths relative to the manifest directory, `index_strategy` is `per_member` or `single`, `default_db_name` overrides `codeindex.db`, and `shared_ignores` is reserved for shared ignore policy. `cdidx workspace list` and `cdidx workspace status` report member DB paths.

`cdidx workspace use <name>` writes the active workspace to the per-user config directory. Query DB resolution keeps existing precedence: explicit `--db`, then explicit `--data-dir` / `CDIDX_DATA_DIR`, then active workspace state, then ancestor/CWD discovery.

### Observability

CodeIndex exposes an opt-in `ActivitySource` named `CodeIndex`. MCP JSON-RPC frames create `mcp.request` server spans and SQLite commands routed through tracked database helpers create `db.query` spans. MCP callers can pass W3C trace context as `params._meta.traceparent`; when present, the MCP span uses that trace as its parent. No exporter dependency is bundled, so spans are emitted only when the host process installs an OpenTelemetry/Diagnostics listener.
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ Output controls:
| Need | Option |
|---|---|
| Owner-only persistent stderr logs on POSIX | Global tool stderr logs are forced to `0600` permissions on every open, including existing date-stamped log files. Use `--log-format text|json`, `--log-retain-count <N>`, `--log-max-size-mb <N>`, or the matching `CDIDX_LOG_*` environment variables to make lifecycle logs JSONL-friendly and rotate them for aggregation. |
| Checked-in configuration | Use `.cdidx/config.json` for repository defaults such as `search.limit`, `search.snippet_lines`, and `search.max_line_width`; run `cdidx validate-config` to validate the discovered file. |
| Checked-in configuration | Use `.cdidx/config.json` for repository defaults such as `search.limit`, `search.snippet_lines`, and `search.max_line_width`; run `cdidx validate-config` to validate the discovered file and `cdidx config show` to inspect precedence. |
| Workspaces | Use `cdidx.workspace.json` or `.cdidx-workspace.json` to declare monorepo members, `cdidx workspace list` to inspect them, and `cdidx workspace use <name>` / `cdidx workspace current` for a persisted active workspace. |
| ASCII-only terminal output | Use `--ascii`, `CDIDX_ASCII=1`, `NO_UNICODE`, `TERM=dumb`, accessibility env hints, or a non-UTF-8 locale. Spinners use pipe, slash, dash, and backslash frames; progress bars use `#` / `-`; very narrow terminals fall back to percentage-only progress. |
| Color and terminal capability | `--color auto` emits ANSI only for capable interactive terminals; `TERM=dumb`, `CI=true`, missing Unix terminal hints, `NO_COLOR`, or `CLICOLOR=0` disable ANSI/progress control sequences. `--palette basic|256|truecolor` can override the `COLORTERM` / `TERM` color-depth detection. |
| UTF-8 JSON pipelines | CLI `--json` output is written as UTF-8 without a BOM and never includes ANSI escape sequences, even when color is forced for human output. |
Expand Down Expand Up @@ -326,7 +327,8 @@ extractor fixture を確認できます。詳細は
| 目的 | option / 動作 |
|---|---|
| POSIX の persistent stderr log を owner-only にする | global tool stderr log は開くたびに `0600` 権限へ補正され、既存の日付付き log file も同じ扱いになります。 |
| checked-in configuration | repository 既定値には `.cdidx/config.json` を使えます。例: `search.limit`、`search.snippet_lines`、`search.max_line_width`。検出された file は `cdidx validate-config` で検証できます。 |
| checked-in configuration | repository 既定値には `.cdidx/config.json` を使えます。例: `search.limit`、`search.snippet_lines`、`search.max_line_width`。検出された file は `cdidx validate-config` で検証でき、`cdidx config show` で優先順位を確認できます。 |
| workspaces | monorepo member は `cdidx.workspace.json` または `.cdidx-workspace.json` で宣言し、`cdidx workspace list` で確認できます。`cdidx workspace use <name>` / `cdidx workspace current` は永続 active workspace を扱います。 |
| ASCII-only 端末で崩れない表示にする | `--ascii`、`CDIDX_ASCII=1`、`NO_UNICODE`、`TERM=dumb`、accessibility 系の環境変数、非 UTF-8 locale を使います。スピナーは pipe、slash、dash、backslash の frame、進捗バーは `#` / `-` になり、幅が非常に狭い端末では percentage-only になります。 |
| color と端末 capability | `--color auto` は対応する interactive terminal でだけ ANSI を出力します。`TERM=dumb`、`CI=true`、Unix で端末 hint が無い場合、`NO_COLOR`、`CLICOLOR=0` では ANSI / progress 制御シーケンスを抑止します。`--palette basic|256|truecolor` で `COLORTERM` / `TERM` による color-depth 判定を上書きできます。 |
| UTF-8 JSON pipeline | CLI の `--json` 出力は BOM なし UTF-8 で書き出され、human output 向けに色を強制していても ANSI escape sequence を含みません。 |
Expand Down
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1708.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: added
issues:
- 1708
---

## English

- Added JSON workspace manifests (`cdidx.workspace.json` / `.cdidx-workspace.json`) and `cdidx workspace list/status` for monorepo member topology.

## 日本語

- monorepo member 構成を宣言する JSON workspace manifest (`cdidx.workspace.json` / `.cdidx-workspace.json`) と `cdidx workspace list/status` を追加しました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1709.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: added
issues:
- 1709
---

## English

- Added `cdidx config show` to report discovered workspace config, active workspace state, and config precedence.

## 日本語

- 検出された workspace config、active workspace state、config 優先順位を表示する `cdidx config show` を追加しました。
13 changes: 13 additions & 0 deletions changelog.d/unreleased/1710.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
category: added
issues:
- 1710
---

## English

- Added persisted active workspace state with `cdidx workspace use/current` and query DB resolution after explicit flags and environment settings.

## 日本語

- `cdidx workspace use/current` による永続 active workspace state と、明示 flag / 環境設定の後に使われる query DB 解決を追加しました。
12 changes: 12 additions & 0 deletions examples/cdidx.workspace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"members": [
"src/CodeIndex",
"tests/CodeIndex.Tests"
],
"index_strategy": "per_member",
"default_db_name": "codeindex.db",
"shared_ignores": [
"bin/",
"obj/"
]
}
60 changes: 60 additions & 0 deletions src/CodeIndex/Cli/ActiveWorkspace.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System.Text.Json;
using CodeIndex.Indexer;

namespace CodeIndex.Cli;

internal sealed record ActiveWorkspaceState(string Name, string Root, string DbPath);

internal static class ActiveWorkspace
{
internal const string EnvironmentVariable = "CDIDX_ACTIVE_WORKSPACE";

internal static string StatePath
{
get
{
var configHome = Environment.GetEnvironmentVariable("XDG_CONFIG_HOME");
var root = string.IsNullOrWhiteSpace(configHome)
? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".config")
: configHome;
return Path.Combine(root, "cdidx", "active.json");
}
}

internal static ActiveWorkspaceState? Load()
{
var envPath = Environment.GetEnvironmentVariable(EnvironmentVariable);
if (!string.IsNullOrWhiteSpace(envPath))
return new ActiveWorkspaceState("env", Path.GetDirectoryName(Path.GetFullPath(envPath)) ?? Environment.CurrentDirectory, Path.GetFullPath(envPath));

var path = StatePath;
if (!File.Exists(LongPath.EnsureWindowsPrefix(path)))
return null;

try
{
using var document = JsonDocument.Parse(File.ReadAllText(LongPath.EnsureWindowsPrefix(path)));
var root = document.RootElement;
var name = ReadString(root, "name") ?? "default";
var workspaceRoot = ReadString(root, "root") ?? Environment.CurrentDirectory;
var dbPath = ReadString(root, "db_path");
if (string.IsNullOrWhiteSpace(dbPath))
return null;
return new ActiveWorkspaceState(name, Path.GetFullPath(workspaceRoot), Path.GetFullPath(dbPath));
}
catch (Exception ex) when (ex is JsonException or IOException or UnauthorizedAccessException or ArgumentException or NotSupportedException)
{
return null;
}
}

internal static void Save(ActiveWorkspaceState state)
{
Directory.CreateDirectory(Path.GetDirectoryName(StatePath)!);
var payload = new ActiveWorkspaceState(state.Name, Path.GetFullPath(state.Root), Path.GetFullPath(state.DbPath));
File.WriteAllText(StatePath, JsonSerializer.Serialize(payload, ProgramRunner.CreateDefaultJsonOptions()));
}

private static string? ReadString(JsonElement element, string name)
=> element.TryGetProperty(name, out var value) && value.ValueKind == JsonValueKind.String ? value.GetString() : null;
}
26 changes: 26 additions & 0 deletions src/CodeIndex/Cli/CdidxConfigFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,32 @@ internal static int RunValidate(string[] args, JsonSerializerOptions jsonOptions
return CommandExitCodes.Success;
}

internal static int RunShow(string[] args, JsonSerializerOptions jsonOptions)
{
var json = args.Contains("--json", StringComparer.Ordinal);
args = args.Where(a => a != "--json").ToArray();
if (args.Length > 0)
return CommandErrorWriter.WriteJsonOrHuman(json, jsonOptions, "config show does not accept positional arguments.", CommandExitCodes.UsageError, "run `cdidx config show` from the workspace whose config should be shown.");

var path = FindConfigFile(Environment.CurrentDirectory);
var active = ActiveWorkspace.Load();
var payload = new ConfigShowJsonResult(
path,
active,
["cli", "env", "config_file", "active_workspace", "cwd_default"],
[ProjectConfigRelativePath, FileName]);
if (json)
Console.WriteLine(JsonSerializer.Serialize(payload, jsonOptions));
else
{
Console.WriteLine($"Config path : {path ?? "(none)"}");
Console.WriteLine($"Active workspace : {(active == null ? "(none)" : active.Name + " -> " + active.DbPath)}");
Console.WriteLine("Precedence : CLI > env > config file > active workspace > CWD default");
}

return CommandExitCodes.Success;
}

private static bool ValidateOptionalObject(JsonElement root, string key, IReadOnlyList<string> knownKeys, string path, out string? error)
{
error = null;
Expand Down
4 changes: 4 additions & 0 deletions src/CodeIndex/Cli/ConsoleUi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ private static readonly (string Command, string Usage)[] CommandUsageLines =
("inspect", "cdidx inspect <query>|--query <query>|-- <query> [--db <path>] [--json] [--verbose] [--limit <n>|--top <n>] [--lang <lang>] [--path <glob>] [--exclude-path <glob>] [--exclude-tests] [--body] [--max-line-width <n>] [--exact|--exact-name]"),
("outline", "cdidx outline <path> [--db <path>] [--json] [--verbose]"),
("status", "cdidx status [--db <path>] [--json] [--verbose] [--check[=workspace,fold,graph,issues,hotspot,csharp,sql,newer]] [--stale-after <duration>] [--explain <field>] [--log-path] [--config] [--check-updates]"),
("workspace", "cdidx workspace <list|status|use|current> [name] [--json]"),
("config", "cdidx config show [--json]"),
("validate-config", "cdidx validate-config"),
("db", "cdidx db --integrity-check [--db <path>] [--json]"),
("diff", "cdidx diff <db1> <db2> [--json] [--summary-only] [--detailed] [--limit <n>]"),
Expand Down Expand Up @@ -744,6 +746,8 @@ private static void PrintCommandSummary()
Console.WriteLine(" inspect <query> Bundle definition, graph, and nearby symbol context");
Console.WriteLine(" outline <path> Show a file outline ordered by line, start column, kind, and name");
Console.WriteLine(" status Show database statistics; add --check for freshness, --config for effective config, --explain <field> for readiness, or --log-path for logs");
Console.WriteLine(" workspace List manifest members and manage the active workspace");
Console.WriteLine(" config show Show resolved workspace config and precedence");
Console.WriteLine(" upgrade Check for and install the latest release via install.sh");
Console.WriteLine(" validate-config Validate .cdidx/config.json or .cdidxrc.json");
Console.WriteLine(" db --integrity-check Run SQLite `PRAGMA integrity_check` and report findings");
Expand Down
5 changes: 5 additions & 0 deletions src/CodeIndex/Cli/DbPathResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public static class DbPathResolver
public const string DataDirEnvironmentVariable = "CDIDX_DATA_DIR";
public const string DataDirSourceFlag = "flag";
public const string DataDirSourceEnv = "env";
public const string DataDirSourceActiveWorkspace = "active_workspace";
public const string DataDirSourceXdg = "xdg";
public const string DataDirSourceWorkspace = "workspace";

Expand Down Expand Up @@ -68,6 +69,10 @@ internal static DbPathResolution ResolveDataDirForQuery(string workspacePath, st
if (!string.IsNullOrWhiteSpace(environmentDataDir))
return BuildDataDirResolution(environmentDataDir, DataDirSourceEnv);

var active = ActiveWorkspace.Load();
if (active != null)
return new DbPathResolution(active.DbPath, Path.GetDirectoryName(active.DbPath), DataDirSourceActiveWorkspace);

if (!string.IsNullOrWhiteSpace(xdgDataHome))
{
var ancestorXdgDataDir = TryResolveOutermostAncestorXdgDataDir(fullWorkspacePath, xdgDataHome);
Expand Down
6 changes: 6 additions & 0 deletions src/CodeIndex/Cli/JsonOutputContracts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,15 @@ internal sealed record VersionInfoJsonResult(
PropertyNamingPolicy = JsonKnownNamingPolicy.SnakeCaseLower,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull)]
[JsonSerializable(typeof(BackfillFoldJsonResult))]
[JsonSerializable(typeof(ActiveWorkspaceJsonResult))]
[JsonSerializable(typeof(ActiveWorkspaceState))]
[JsonSerializable(typeof(CalleeResult))]
[JsonSerializable(typeof(CallerResult))]
[JsonSerializable(typeof(CliJsonMessage))]
[JsonSerializable(typeof(CompactSearchResult))]
[JsonSerializable(typeof(CompactSearchResult[]))]
[JsonSerializable(typeof(CommandErrorJsonResult))]
[JsonSerializable(typeof(ConfigShowJsonResult))]
[JsonSerializable(typeof(DbIntegrityCheckJsonResult))]
[JsonSerializable(typeof(DefinitionResult))]
[JsonSerializable(typeof(Dictionary<string, int>))]
Expand Down Expand Up @@ -359,6 +362,9 @@ internal sealed record VersionInfoJsonResult(
[JsonSerializable(typeof(CodeIndex.Models.UpdateCheckResult))]
[JsonSerializable(typeof(VacuumResult))]
[JsonSerializable(typeof(VersionInfoJsonResult))]
[JsonSerializable(typeof(WorkspaceListJsonResult))]
[JsonSerializable(typeof(WorkspaceManifest))]
[JsonSerializable(typeof(WorkspaceMember))]
internal partial class CliJsonSerializerContext : JsonSerializerContext;

internal static class CliJsonSerializerContextFactory
Expand Down
9 changes: 9 additions & 0 deletions src/CodeIndex/Cli/ProgramRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,15 @@ internal static int Run(
"optimize" => IndexCommandRunner.RunOptimizeFts(subArgs, jsonOptions),
"vacuum" => QueryCommandRunner.RunVacuum(subArgs, jsonOptions),
"validate-config" => CdidxConfigFile.RunValidate(subArgs, jsonOptions),
"config" => subArgs.Length > 0 && subArgs[0] == "show"
? CdidxConfigFile.RunShow(subArgs[1..], jsonOptions)
: CommandErrorWriter.WriteJsonOrHuman(
ContainsJsonOutputFlag(subArgs),
jsonOptions,
"Unknown config command: use `cdidx config show`.",
CommandExitCodes.UsageError,
"use `cdidx config show`."),
"workspace" => WorkspaceCommandRunner.Run(subArgs, jsonOptions),
"db" => DbCommandRunner.RunIntegrityCheck(subArgs, jsonOptions),
"report" => ReportCommandRunner.Run(subArgs, jsonOptions, appVersion),
"test-extractor" => RunTestExtractor(subArgs, jsonOptions),
Expand Down
Loading
Loading