@infinitedusky/indusk-mcp 1.2.9 → 1.4.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/dist/bin/commands/extensions.d.ts +1 -0
- package/dist/bin/commands/extensions.js +77 -0
- package/dist/bin/commands/init-docs.js +6 -0
- package/dist/bin/commands/init.js +7 -7
- package/dist/lib/extension-loader.d.ts +1 -0
- package/extensions/dash0/manifest.json +19 -0
- package/extensions/dash0/skill.md +70 -0
- package/package.json +1 -1
- package/skills/document.md +25 -6
|
@@ -6,3 +6,4 @@ export declare function extensionsAdd(projectRoot: string, name: string, from: s
|
|
|
6
6
|
export declare function extensionsRemove(projectRoot: string, names: string[]): Promise<void>;
|
|
7
7
|
export declare function extensionsUpdate(projectRoot: string, names?: string[]): Promise<void>;
|
|
8
8
|
export declare function extensionsSuggest(projectRoot: string): Promise<void>;
|
|
9
|
+
export declare function autoEnableExtensions(projectRoot: string): Promise<void>;
|
|
@@ -323,6 +323,7 @@ export async function extensionsUpdate(projectRoot, names) {
|
|
|
323
323
|
}
|
|
324
324
|
else {
|
|
325
325
|
console.info(`\n${updated} extension(s) updated.`);
|
|
326
|
+
console.info("\n⚠ Restart Claude Code to load the updated extensions.");
|
|
326
327
|
}
|
|
327
328
|
}
|
|
328
329
|
export async function extensionsSuggest(projectRoot) {
|
|
@@ -361,6 +362,20 @@ export async function extensionsSuggest(projectRoot) {
|
|
|
361
362
|
}
|
|
362
363
|
}
|
|
363
364
|
}
|
|
365
|
+
if (ext.detect.mcp_server) {
|
|
366
|
+
try {
|
|
367
|
+
const mcpPath = join(projectRoot, ".mcp.json");
|
|
368
|
+
if (existsSync(mcpPath)) {
|
|
369
|
+
const mcp = JSON.parse(readFileSync(mcpPath, "utf-8"));
|
|
370
|
+
if (mcp.mcpServers?.[ext.detect.mcp_server]) {
|
|
371
|
+
suggestions.push({ name: ext.name, reason: `${ext.detect.mcp_server} in .mcp.json` });
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
catch {
|
|
376
|
+
// ignore
|
|
377
|
+
}
|
|
378
|
+
}
|
|
364
379
|
}
|
|
365
380
|
if (suggestions.length === 0) {
|
|
366
381
|
console.info("No extension suggestions — all detected extensions are already enabled.");
|
|
@@ -372,6 +387,68 @@ export async function extensionsSuggest(projectRoot) {
|
|
|
372
387
|
}
|
|
373
388
|
console.info(`\nEnable with: extensions enable ${suggestions.map((s) => s.name).join(" ")}`);
|
|
374
389
|
}
|
|
390
|
+
export async function autoEnableExtensions(projectRoot) {
|
|
391
|
+
const builtins = getBuiltinExtensions();
|
|
392
|
+
let enabled = 0;
|
|
393
|
+
for (const ext of builtins) {
|
|
394
|
+
if (isEnabled(projectRoot, ext.name))
|
|
395
|
+
continue;
|
|
396
|
+
if (!ext.detect)
|
|
397
|
+
continue;
|
|
398
|
+
let detected = false;
|
|
399
|
+
let reason = "";
|
|
400
|
+
if (ext.detect.file && existsSync(join(projectRoot, ext.detect.file))) {
|
|
401
|
+
detected = true;
|
|
402
|
+
reason = `${ext.detect.file} found`;
|
|
403
|
+
}
|
|
404
|
+
if (!detected && ext.detect.file_pattern) {
|
|
405
|
+
const matches = globSync(ext.detect.file_pattern, { cwd: projectRoot, maxDepth: 3 });
|
|
406
|
+
if (matches.length > 0) {
|
|
407
|
+
detected = true;
|
|
408
|
+
reason = `${ext.detect.file_pattern} found`;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (!detected && (ext.detect.dependency || ext.detect.devDependency)) {
|
|
412
|
+
const pkgPath = join(projectRoot, "package.json");
|
|
413
|
+
if (existsSync(pkgPath)) {
|
|
414
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
415
|
+
const deps = pkg.dependencies ?? {};
|
|
416
|
+
const devDeps = pkg.devDependencies ?? {};
|
|
417
|
+
if (ext.detect.dependency && deps[ext.detect.dependency]) {
|
|
418
|
+
detected = true;
|
|
419
|
+
reason = `${ext.detect.dependency} in dependencies`;
|
|
420
|
+
}
|
|
421
|
+
else if (ext.detect.devDependency && devDeps[ext.detect.devDependency]) {
|
|
422
|
+
detected = true;
|
|
423
|
+
reason = `${ext.detect.devDependency} in devDependencies`;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
if (!detected && ext.detect.mcp_server) {
|
|
428
|
+
try {
|
|
429
|
+
const mcpPath = join(projectRoot, ".mcp.json");
|
|
430
|
+
if (existsSync(mcpPath)) {
|
|
431
|
+
const mcp = JSON.parse(readFileSync(mcpPath, "utf-8"));
|
|
432
|
+
if (mcp.mcpServers?.[ext.detect.mcp_server]) {
|
|
433
|
+
detected = true;
|
|
434
|
+
reason = `${ext.detect.mcp_server} in .mcp.json`;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch {
|
|
439
|
+
// ignore parse errors
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
if (detected) {
|
|
443
|
+
await extensionsEnable(projectRoot, [ext.name]);
|
|
444
|
+
console.info(` (detected: ${reason})`);
|
|
445
|
+
enabled++;
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (enabled === 0) {
|
|
449
|
+
console.info(" No new extensions detected.");
|
|
450
|
+
}
|
|
451
|
+
}
|
|
375
452
|
// --- Helpers ---
|
|
376
453
|
function runHook(projectRoot, name, hook) {
|
|
377
454
|
const extPath = join(extensionsDir(projectRoot), `${name}.json`);
|
|
@@ -231,6 +231,12 @@ Architecture decision records for ${projectName}. Each decision documents what w
|
|
|
231
231
|
writeFileSync(join(docsDir, "src/lessons/index.md"), `# Lessons Learned
|
|
232
232
|
|
|
233
233
|
Insights from building ${projectName}. Each lesson captures what we learned, what surprised us, and what we'd do differently.
|
|
234
|
+
`);
|
|
235
|
+
writeFileSync(join(docsDir, "src/changelog.md"), `# Changelog
|
|
236
|
+
|
|
237
|
+
All notable changes to ${projectName} are documented here. Follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
238
|
+
|
|
239
|
+
## [Unreleased]
|
|
234
240
|
`);
|
|
235
241
|
// Dockerfile for local dev
|
|
236
242
|
const dockerDir = join(projectRoot, "docker");
|
|
@@ -294,15 +294,15 @@ export async function init(projectRoot, options = {}) {
|
|
|
294
294
|
console.info(" skipped (CGC not available)");
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
-
// 11.
|
|
297
|
+
// 11. Auto-enable detected extensions
|
|
298
298
|
console.info("\n[Extensions]");
|
|
299
|
-
const {
|
|
300
|
-
await
|
|
299
|
+
const { autoEnableExtensions } = await import("./extensions.js");
|
|
300
|
+
await autoEnableExtensions(projectRoot);
|
|
301
301
|
// Summary
|
|
302
302
|
console.info("\nDone!");
|
|
303
|
+
console.info("\n⚠ Restart Claude Code to load the updated MCP server and skills.");
|
|
303
304
|
console.info("\nNext steps:");
|
|
304
|
-
console.info(" 1.
|
|
305
|
-
console.info(" 2.
|
|
306
|
-
console.info(" 3. Start
|
|
307
|
-
console.info(" 4. Start planning: /plan your-first-feature");
|
|
305
|
+
console.info(" 1. Restart Claude Code");
|
|
306
|
+
console.info(" 2. Edit CLAUDE.md with your project details");
|
|
307
|
+
console.info(" 3. Start planning: /plan your-first-feature");
|
|
308
308
|
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dash0",
|
|
3
|
+
"description": "Dash0 observability — query logs, traces, and metrics from your OpenTelemetry data via MCP",
|
|
4
|
+
"provides": {
|
|
5
|
+
"skill": true,
|
|
6
|
+
"health_checks": [
|
|
7
|
+
{
|
|
8
|
+
"name": "dash0-mcp-configured",
|
|
9
|
+
"command": "node -e \"const m=JSON.parse(require('fs').readFileSync('.mcp.json','utf-8'));process.exit(m.mcpServers?.dash0 ? 0 : 1)\""
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"hooks": {
|
|
14
|
+
"on_init": "echo 'Dash0 extension enabled. Configure the Dash0 MCP server in .mcp.json if not already present.'"
|
|
15
|
+
},
|
|
16
|
+
"detect": {
|
|
17
|
+
"mcp_server": "dash0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Dash0 Observability
|
|
2
|
+
|
|
3
|
+
Dash0 provides access to your OpenTelemetry data — logs, traces, and metrics — directly from Claude Code via its MCP server.
|
|
4
|
+
|
|
5
|
+
## When to Use Dash0
|
|
6
|
+
|
|
7
|
+
- **Test failures**: query recent traces to see what happened in the service during the test
|
|
8
|
+
- **Debugging production issues**: search logs for errors, find related traces by trace ID
|
|
9
|
+
- **Performance investigation**: query metrics (PromQL) to check latency, throughput, error rates
|
|
10
|
+
- **Deployment verification**: check traces and error rates after deploying a change
|
|
11
|
+
- **During /work verification**: if a verification step involves checking service health, query Dash0
|
|
12
|
+
|
|
13
|
+
## Available Tools (from Dash0 MCP server)
|
|
14
|
+
|
|
15
|
+
Dash0's MCP server provides 23 tools. The most useful for development:
|
|
16
|
+
|
|
17
|
+
| Tool | When |
|
|
18
|
+
|------|------|
|
|
19
|
+
| Search logs | Find errors, warnings, or specific log messages |
|
|
20
|
+
| Search traces | Find request traces by service, endpoint, status, or trace ID |
|
|
21
|
+
| Query metrics (PromQL) | Check latency percentiles, error rates, throughput |
|
|
22
|
+
| List services | See what services are sending telemetry |
|
|
23
|
+
| Get trace details | Deep-dive into a specific trace's spans |
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
1. Sign up at [dash0.com](https://www.dash0.com)
|
|
28
|
+
2. Get your API token from the Dash0 dashboard
|
|
29
|
+
3. Add the Dash0 MCP server to your `.mcp.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"dash0": {
|
|
35
|
+
"command": "npx",
|
|
36
|
+
"args": ["@dash0hq/mcp-server"],
|
|
37
|
+
"env": {
|
|
38
|
+
"DASH0_API_TOKEN": "your-token-here",
|
|
39
|
+
"DASH0_DATASET": "default"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
4. Enable the extension: `extensions enable dash0`
|
|
47
|
+
|
|
48
|
+
## Workflow Integration
|
|
49
|
+
|
|
50
|
+
### During verification
|
|
51
|
+
When a verification step involves checking that a service is working correctly, don't just check the HTTP status — query Dash0 for:
|
|
52
|
+
- Recent error traces for the service
|
|
53
|
+
- Error rate metrics before and after your change
|
|
54
|
+
- Log entries matching the feature you modified
|
|
55
|
+
|
|
56
|
+
### During debugging
|
|
57
|
+
When something fails:
|
|
58
|
+
1. Check logs first — search for errors in the relevant service
|
|
59
|
+
2. Find the trace — use the trace ID from logs to get the full request flow
|
|
60
|
+
3. Check metrics — is this a new problem or an existing one? Compare error rates over time.
|
|
61
|
+
|
|
62
|
+
### During retrospective
|
|
63
|
+
Query Dash0 for metrics that show the impact of the plan:
|
|
64
|
+
- Error rate before vs after
|
|
65
|
+
- Latency changes
|
|
66
|
+
- New services or endpoints that appeared
|
|
67
|
+
|
|
68
|
+
## Connecting to OpenTelemetry
|
|
69
|
+
|
|
70
|
+
Dash0 ingests standard OpenTelemetry data. If your services already export OTLP telemetry, point the OTLP exporter at Dash0's endpoint. See [Dash0 docs](https://www.dash0.com/documentation/dash0) for setup per language.
|
package/package.json
CHANGED
package/skills/document.md
CHANGED
|
@@ -60,7 +60,8 @@ apps/indusk-docs/src/
|
|
|
60
60
|
│ ├── skills/ # One page per skill
|
|
61
61
|
│ └── tools/ # One page per tool (Biome, CGC, composable.env)
|
|
62
62
|
├── decisions/ # Distilled from ADRs during retrospective/archival
|
|
63
|
-
|
|
63
|
+
├── lessons/ # Distilled from retrospective insights during archival
|
|
64
|
+
└── changelog.md # Version history — Added, Changed, Fixed, etc.
|
|
64
65
|
```
|
|
65
66
|
|
|
66
67
|
**CRITICAL: Every new page must be added to the sidebar.** The sidebar is configured in a single file: `apps/indusk-docs/src/.vitepress/config.ts` under `themeConfig.sidebar`. If you create a page but don't add it to the sidebar, it is invisible — users cannot navigate to it. This is the most common documentation mistake.
|
|
@@ -79,11 +80,29 @@ Never consider a documentation item complete until the sidebar entry exists.
|
|
|
79
80
|
|
|
80
81
|
| What changed | Where to document | Doc type |
|
|
81
82
|
|---|---|---|
|
|
82
|
-
| New feature or tool | `reference/` | Reference page |
|
|
83
|
-
| New workflow or process | `guide/` | How-to guide |
|
|
84
|
-
| Configuration change | `reference/` (update existing
|
|
85
|
-
|
|
|
86
|
-
|
|
|
83
|
+
| New feature or tool | `reference/` + changelog | Reference page + Added |
|
|
84
|
+
| New workflow or process | `guide/` + changelog | How-to guide + Added |
|
|
85
|
+
| Configuration change | `reference/` (update existing) + changelog | Reference update + Changed |
|
|
86
|
+
| Bug fix | Existing page (if relevant) + changelog | Fixed |
|
|
87
|
+
| Architecture change | `reference/` + diagram + changelog | Reference + diagram + Changed |
|
|
88
|
+
| Nothing user-facing | Skip changelog | — |
|
|
89
|
+
|
|
90
|
+
### Changelog
|
|
91
|
+
|
|
92
|
+
The changelog lives at `changelog.md` in the docs site. It uses [Keep a Changelog](https://keepachangelog.com) categories:
|
|
93
|
+
|
|
94
|
+
- **Added** — new features (from `feature` workflow plans)
|
|
95
|
+
- **Changed** — changes to existing functionality (from `refactor` workflows)
|
|
96
|
+
- **Fixed** — bug fixes (from `bugfix` workflows)
|
|
97
|
+
- **Deprecated** — soon to be removed
|
|
98
|
+
- **Removed** — removed features
|
|
99
|
+
- **Security** — vulnerability fixes
|
|
100
|
+
|
|
101
|
+
**When to write:** During the Document gate of each phase that changes user-facing behavior. Add the entry under `## [Unreleased]`. At publish time, move Unreleased entries into a versioned section.
|
|
102
|
+
|
|
103
|
+
**What to write:** One line per change. Human-readable — what users gain, not what code changed. The workflow type from the impl frontmatter tells you the category (feature → Added, bugfix → Fixed, refactor → Changed).
|
|
104
|
+
|
|
105
|
+
**During planning:** The ADR's Documentation Plan section should include planned changelog entries. This forces you to think about user impact during planning, not after.
|
|
87
106
|
|
|
88
107
|
### Decisions and Lessons
|
|
89
108
|
|