@infinitedusky/indusk-mcp 1.10.1 → 1.10.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -44,12 +44,28 @@ export declare function getConfigPath(projectRoot: string): string;
44
44
  export declare function readConfig(projectRoot: string): InduskConfig | null;
45
45
  export declare function writeConfig(projectRoot: string, config: InduskConfig): void;
46
46
  export declare function getPlanningDir(projectRoot: string): string;
47
+ /**
48
+ * Sanitize a string into a valid Graphiti group id.
49
+ *
50
+ * Graphiti uses RediSearch under the hood, which treats `-` as a token separator.
51
+ * A query like `chitin-sportsbook` parses as "find chitin, exclude sportsbook" and
52
+ * fails with `Syntax error at offset N near chitin`. Anything that isn't
53
+ * `[A-Za-z0-9_]` gets replaced with `_`. Multiple separators collapse to one.
54
+ *
55
+ * Examples:
56
+ * "chitin-sportsbook" → "chitin_sportsbook"
57
+ * "my.cool.project" → "my_cool_project"
58
+ * "@scope/pkg" → "scope_pkg"
59
+ * "indusk_already_ok" → "indusk_already_ok" (no change)
60
+ */
61
+ export declare function sanitizeGroupId(raw: string): string;
47
62
  /**
48
63
  * Get the Graphiti group id for project-specific episodes.
49
64
  *
50
65
  * Resolution order:
51
- * 1. .indusk/config.json `graphiti.groupId` if set
52
- * 2. Project directory basename
66
+ * 1. .indusk/config.json `graphiti.groupId` if set (used as-is, not sanitized —
67
+ * explicit overrides are trusted; if you set a hyphenated id, that's on you)
68
+ * 2. Sanitized project directory basename (`-` → `_`, etc., for RediSearch safety)
53
69
  *
54
70
  * Use `[getProjectGroupId(root), "shared"]` as the default group_ids list when
55
71
  * searching Graphiti — this gives both project-scoped and cross-project knowledge.
@@ -26,12 +26,30 @@ export function getPlanningDir(projectRoot) {
26
26
  // Default to new path (will be created by init)
27
27
  return newPath;
28
28
  }
29
+ /**
30
+ * Sanitize a string into a valid Graphiti group id.
31
+ *
32
+ * Graphiti uses RediSearch under the hood, which treats `-` as a token separator.
33
+ * A query like `chitin-sportsbook` parses as "find chitin, exclude sportsbook" and
34
+ * fails with `Syntax error at offset N near chitin`. Anything that isn't
35
+ * `[A-Za-z0-9_]` gets replaced with `_`. Multiple separators collapse to one.
36
+ *
37
+ * Examples:
38
+ * "chitin-sportsbook" → "chitin_sportsbook"
39
+ * "my.cool.project" → "my_cool_project"
40
+ * "@scope/pkg" → "scope_pkg"
41
+ * "indusk_already_ok" → "indusk_already_ok" (no change)
42
+ */
43
+ export function sanitizeGroupId(raw) {
44
+ return raw.replace(/[^A-Za-z0-9_]+/g, "_").replace(/^_+|_+$/g, "");
45
+ }
29
46
  /**
30
47
  * Get the Graphiti group id for project-specific episodes.
31
48
  *
32
49
  * Resolution order:
33
- * 1. .indusk/config.json `graphiti.groupId` if set
34
- * 2. Project directory basename
50
+ * 1. .indusk/config.json `graphiti.groupId` if set (used as-is, not sanitized —
51
+ * explicit overrides are trusted; if you set a hyphenated id, that's on you)
52
+ * 2. Sanitized project directory basename (`-` → `_`, etc., for RediSearch safety)
35
53
  *
36
54
  * Use `[getProjectGroupId(root), "shared"]` as the default group_ids list when
37
55
  * searching Graphiti — this gives both project-scoped and cross-project knowledge.
@@ -40,7 +58,7 @@ export function getProjectGroupId(projectRoot) {
40
58
  const config = readConfig(projectRoot);
41
59
  if (config?.graphiti?.groupId)
42
60
  return config.graphiti.groupId;
43
- return basename(projectRoot);
61
+ return sanitizeGroupId(basename(projectRoot));
44
62
  }
45
63
  /**
46
64
  * Whether the OTel gate should fire for this project.
@@ -65,14 +65,22 @@ The MCP server provides 23 tools. The key ones for debugging:
65
65
  - **`getFailedChecks`** / **`getFailedCheckDetails`** — View check failures
66
66
  - **`searchKnowledgeBase`** — Search Dash0 documentation
67
67
 
68
- ### MCP Usage Pattern
68
+ ### MCP Usage Pattern — Traces First
69
+
70
+ **Always start with spans.** Logs are correlated with traces, so finding the right trace first helps you find the right logs — not the other way around.
71
+
69
72
  ```
70
- 1. getLogRecordsfind the log summary, get log record IDs
71
- 2. getFullLogRecorddrill into a specific log for all attributes
72
- 3. If log has traceId getTraceDetails to see the full request chain
73
- 4. getServiceCatalogsee all services, error rates, dependencies
73
+ 1. getSpans (last 30s, no filters) scan recent spans for anything matching your investigation
74
+ 2. Found a relevant span? getTraceDetails to see the full request chain
75
+ 3. Use trace/span IDs to find correlated logs getLogRecords with traceId filter
76
+ 4. getFullLogRecorddrill into a specific log for all attributes
74
77
  ```
75
78
 
79
+ **Why traces first:**
80
+ - Spans show the full request lifecycle — what happened, how long, what called what
81
+ - Logs are attached to spans via trace context — the trace tells you which logs matter
82
+ - Starting with logs means guessing at filters; starting with spans gives you the map
83
+
76
84
  ## When to Use MCP vs CLI
77
85
 
78
86
  | Task | Use |
@@ -83,7 +91,7 @@ The MCP server provides 23 tools. The key ones for debugging:
83
91
  | Get full trace hierarchy | MCP `getTraceDetails` (preferred) |
84
92
  | Run PromQL metrics query | Either — MCP for simple, CLI for complex |
85
93
  | Deploy dashboard from YAML | CLI (`dash0 apply -f`) |
86
- | Diagnose a failing service | MCP `getServiceCatalog` → `getLogRecords` → `getFullLogRecord` |
94
+ | Diagnose a failing service | MCP `getSpans` (last 30s) → `getTraceDetails` → `getLogRecords` (by traceId) |
87
95
  | CI/CD observability checks | CLI (scriptable, agent mode) |
88
96
  | Discover available attributes | MCP `getAttributeKeys` / `getAttributeValues` |
89
97
 
@@ -178,14 +186,16 @@ The CLI auto-detects Claude Code sessions and switches to agent mode (JSON outpu
178
186
 
179
187
  ### During verification
180
188
  When a verification step involves checking that a service is working correctly, don't just check the HTTP status — query Dash0 for:
181
- - Recent error logs for the service: `dash0 --experimental logs query --from now-15m --filter "service.name is game-server" --filter "otel.log.severity.range is_one_of ERROR WARN"`
182
- - Log entries matching the feature you modified
189
+ - **Recent spans first**: use MCP `getSpans` with a short time range (last 30s) to see what the service just did look for errors, slow spans, or missing expected operations
190
+ - **Then correlated logs**: once you have a trace ID from a relevant span, use `getLogRecords` filtered by that trace ID to see exactly what happened during that request
191
+ - **Only use broad log queries as a fallback** if no spans are present (e.g., the service isn't instrumented yet)
183
192
 
184
193
  ### During debugging
185
194
  When something fails:
186
- 1. Check logs first — `dash0 --experimental logs query --from now-1h --filter "otel.log.severity.range is_one_of ERROR WARN" -o csv`
187
- 2. Find the trace — look for trace IDs in log entries, then `dash0 --experimental traces get <trace-id>`
188
- 3. Check metricsis this a new problem or an existing one? Compare error rates over time.
195
+ 1. **Get recent spans first**use MCP `getSpans` with a short time range (last 30s–1m). Don't filter yet scan the results for spans matching what you're investigating.
196
+ 2. **Drill into the trace**found a relevant span? Use `getTraceDetails` to see the full request chain, timing, errors, and hierarchy.
197
+ 3. **Find correlated logs** use the trace ID from step 2 to query `getLogRecords` with a `traceId` filter. This gives you exactly the logs tied to that request, no guessing.
198
+ 4. **Check metrics** — is this a new problem or an existing one? Compare error rates over time.
189
199
 
190
200
  ### During retrospective
191
201
  Query Dash0 for metrics that show the impact of the plan:
@@ -201,5 +211,5 @@ Dash0 ingests standard OpenTelemetry data. If your services already export OTLP
201
211
 
202
212
  - **CLI `--experimental` required**: All query commands (logs, traces, metrics) require the `--experimental` flag. This will change when these commands become stable.
203
213
  - **Default time range is narrow**: Always specify `--from` when querying logs. Without it, you may get empty results.
204
- - **No trace search**: The CLI can only fetch traces by ID (`traces get <id>`), not search for them. Find trace IDs in log entries first.
214
+ - **CLI has no trace search**: The CLI can only fetch traces by ID (`traces get <id>`), not search for them. Use the MCP `getSpans` tool to search spans — it supports filters and time ranges. The CLI requires you to already have a trace ID.
205
215
  - **Profile auth may not load in Claude Code shell**: Run `source ~/.zshrc` before `dash0` commands if auth fails.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infinitedusky/indusk-mcp",
3
- "version": "1.10.1",
3
+ "version": "1.10.3",
4
4
  "description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
5
5
  "type": "module",
6
6
  "files": [