@pellux/goodvibes-agent 0.1.59 → 0.1.61
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/CHANGELOG.md +14 -0
- package/package.json +2 -18
- package/src/cli/help.ts +3 -17
- package/src/cli/package-verification.ts +1 -4
- package/src/input/commands/guidance-runtime.ts +1 -2
- package/src/input/commands/health-runtime.ts +2 -36
- package/src/input/commands/shell-core.ts +8 -12
- package/src/input/commands.ts +0 -2
- package/src/panels/builtin/operations.ts +0 -15
- package/src/panels/index.ts +0 -2
- package/src/panels/provider-health-domains.ts +0 -27
- package/src/panels/provider-health-panel.ts +0 -4
- package/src/renderer/code-block.ts +2 -13
- package/src/version.ts +1 -1
- package/.goodvibes/GOODVIBES.md +0 -35
- package/.goodvibes/skills/add-provider/SKILL.md +0 -199
- package/src/input/commands/intelligence-runtime.ts +0 -223
- package/src/panels/debug-panel.ts +0 -432
- package/src/panels/intelligence-panel.ts +0 -176
- package/src/renderer/semantic-diff.ts +0 -369
- package/src/renderer/syntax-highlighter.ts +0 -542
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: add-provider
|
|
3
|
-
description: Adds custom LLM providers and models to GoodVibes Agent. Use when the user wants to add a provider, add a model, configure Ollama, Together AI, OpenRouter, Groq, LM Studio, Fireworks, vLLM, or any OpenAI-compatible endpoint.
|
|
4
|
-
version: 1.0.0
|
|
5
|
-
triggers:
|
|
6
|
-
- /add-provider
|
|
7
|
-
- add provider
|
|
8
|
-
- add a provider
|
|
9
|
-
- new provider
|
|
10
|
-
- custom provider
|
|
11
|
-
- add model
|
|
12
|
-
- add a model
|
|
13
|
-
author: goodvibes
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
# Add Custom Provider
|
|
17
|
-
|
|
18
|
-
Interactively collect provider and model details from the user, then write a JSON config to `~/.goodvibes/agent/providers/{name}.json`.
|
|
19
|
-
|
|
20
|
-
## Workflow
|
|
21
|
-
|
|
22
|
-
### Step 1: Check for Existing Provider
|
|
23
|
-
|
|
24
|
-
Before collecting info, check if `~/.goodvibes/agent/providers/` already has JSON files. If the user names a provider that already exists, ask:
|
|
25
|
-
- **Add models** to the existing provider, or
|
|
26
|
-
- **Overwrite** it entirely
|
|
27
|
-
|
|
28
|
-
If adding models, read the existing JSON, append new models, and write back.
|
|
29
|
-
|
|
30
|
-
### Step 2: Collect Provider Details
|
|
31
|
-
|
|
32
|
-
Ask the user for each field. Apply smart defaults when the provider name matches a known service.
|
|
33
|
-
|
|
34
|
-
#### Required Fields
|
|
35
|
-
|
|
36
|
-
| Field | Description | Validation |
|
|
37
|
-
|-------|-------------|------------|
|
|
38
|
-
| `name` | Internal ID | Lowercase alphanumeric + hyphens only, 1-64 chars |
|
|
39
|
-
| `displayName` | Human-readable name | Non-empty string |
|
|
40
|
-
| `type` | API compatibility | `openai-compat` (recommended) or `anthropic-compat` (not yet supported — use `openai-compat`) |
|
|
41
|
-
| `baseURL` | API endpoint | Must start with `http://` or `https://` |
|
|
42
|
-
|
|
43
|
-
> **Note:** `anthropic-compat` is accepted in the JSON schema for forward compatibility but is not yet functional at runtime. The loader will skip configs with this type and emit a warning. Use `openai-compat` for now — most Anthropic-compatible proxies (e.g., via LiteLLM) expose an OpenAI-compatible endpoint.
|
|
44
|
-
|
|
45
|
-
#### Optional Fields
|
|
46
|
-
|
|
47
|
-
| Field | Description | Default |
|
|
48
|
-
|-------|-------------|---------|
|
|
49
|
-
| `apiKeyEnv` | Environment variable for API key | None |
|
|
50
|
-
| `apiKey` | Explicit API key (not recommended) | None |
|
|
51
|
-
| `defaultHeaders` | Custom HTTP headers sent with every API request (e.g., for proxy authentication or routing) | None |
|
|
52
|
-
|
|
53
|
-
### Smart Defaults
|
|
54
|
-
|
|
55
|
-
When the user mentions a known provider, pre-fill these values and confirm:
|
|
56
|
-
|
|
57
|
-
```yaml
|
|
58
|
-
ollama:
|
|
59
|
-
displayName: Ollama
|
|
60
|
-
type: openai-compat
|
|
61
|
-
baseURL: http://localhost:11434/v1
|
|
62
|
-
apiKeyEnv: null
|
|
63
|
-
|
|
64
|
-
together:
|
|
65
|
-
displayName: Together AI
|
|
66
|
-
type: openai-compat
|
|
67
|
-
baseURL: https://api.together.xyz/v1
|
|
68
|
-
apiKeyEnv: TOGETHER_API_KEY
|
|
69
|
-
|
|
70
|
-
openrouter:
|
|
71
|
-
displayName: OpenRouter
|
|
72
|
-
type: openai-compat
|
|
73
|
-
baseURL: https://openrouter.ai/api/v1
|
|
74
|
-
apiKeyEnv: OPENROUTER_API_KEY
|
|
75
|
-
|
|
76
|
-
groq:
|
|
77
|
-
displayName: Groq
|
|
78
|
-
type: openai-compat
|
|
79
|
-
baseURL: https://api.groq.com/openai/v1
|
|
80
|
-
apiKeyEnv: GROQ_API_KEY
|
|
81
|
-
|
|
82
|
-
lm-studio:
|
|
83
|
-
displayName: LM Studio
|
|
84
|
-
type: openai-compat
|
|
85
|
-
baseURL: http://localhost:1234/v1
|
|
86
|
-
apiKeyEnv: null
|
|
87
|
-
|
|
88
|
-
fireworks:
|
|
89
|
-
displayName: Fireworks AI
|
|
90
|
-
type: openai-compat
|
|
91
|
-
baseURL: https://api.fireworks.ai/inference/v1
|
|
92
|
-
apiKeyEnv: FIREWORKS_API_KEY
|
|
93
|
-
|
|
94
|
-
vllm:
|
|
95
|
-
displayName: vLLM
|
|
96
|
-
type: openai-compat
|
|
97
|
-
baseURL: http://localhost:8000/v1
|
|
98
|
-
apiKeyEnv: null
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
If the name does not match a known provider, ask for all fields individually.
|
|
102
|
-
|
|
103
|
-
### Step 3: Collect Model Details
|
|
104
|
-
|
|
105
|
-
Collect at least one model. For each model:
|
|
106
|
-
|
|
107
|
-
| Field | Description | Validation |
|
|
108
|
-
|-------|-------------|------------|
|
|
109
|
-
| `id` | Model identifier sent to the API | Non-empty string |
|
|
110
|
-
| `displayName` | Human-readable name | Non-empty string |
|
|
111
|
-
| `description` | Short description | Optional, auto-generate if blank |
|
|
112
|
-
| `contextWindow` | Max tokens in context | Positive integer |
|
|
113
|
-
| `capabilities.toolCalling` | Supports function/tool calling | Boolean, default `true` |
|
|
114
|
-
| `capabilities.codeEditing` | Good at code editing tasks | Boolean, default `true` |
|
|
115
|
-
| `capabilities.reasoning` | Extended reasoning/chain-of-thought | Boolean, default `false` |
|
|
116
|
-
| `capabilities.multimodal` | Supports image input | Boolean, default `false` |
|
|
117
|
-
| `reasoningEffort` | Supported reasoning effort levels | Optional, e.g., `["low", "medium", "high"]` |
|
|
118
|
-
|
|
119
|
-
After each model, ask: "Add another model?" Loop until done.
|
|
120
|
-
|
|
121
|
-
### Step 4: Preview and Confirm
|
|
122
|
-
|
|
123
|
-
Show the complete JSON to the user and ask for confirmation before writing.
|
|
124
|
-
|
|
125
|
-
Example output:
|
|
126
|
-
|
|
127
|
-
```json
|
|
128
|
-
{
|
|
129
|
-
"name": "ollama",
|
|
130
|
-
"displayName": "Ollama",
|
|
131
|
-
"type": "openai-compat",
|
|
132
|
-
"baseURL": "http://localhost:11434/v1",
|
|
133
|
-
"models": [
|
|
134
|
-
{
|
|
135
|
-
"id": "llama3.3-70b",
|
|
136
|
-
"displayName": "Llama 3.3 70B",
|
|
137
|
-
"description": "Meta's Llama 3.3 70B parameter model",
|
|
138
|
-
"contextWindow": 131072,
|
|
139
|
-
"capabilities": {
|
|
140
|
-
"toolCalling": true,
|
|
141
|
-
"codeEditing": true,
|
|
142
|
-
"reasoning": true,
|
|
143
|
-
"multimodal": false
|
|
144
|
-
},
|
|
145
|
-
"reasoningEffort": ["low", "medium", "high"]
|
|
146
|
-
}
|
|
147
|
-
]
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### Step 5: Write the File
|
|
152
|
-
|
|
153
|
-
Write to `~/.goodvibes/agent/providers/{name}.json`. Create the directory if it does not exist.
|
|
154
|
-
|
|
155
|
-
Use `precision_write` with `mode: "fail_if_exists"` for new providers. Use `mode: "overwrite"` when the user chose to overwrite an existing provider or when merging models into an existing file.
|
|
156
|
-
|
|
157
|
-
If the `apiKeyEnv` field is set, include it in the JSON. If the user provided an explicit `apiKey`, include it but warn that storing keys in plain text is not recommended -- suggest using an environment variable instead.
|
|
158
|
-
|
|
159
|
-
If `defaultHeaders` were provided, include them.
|
|
160
|
-
|
|
161
|
-
### Step 6: Confirm
|
|
162
|
-
|
|
163
|
-
Tell the user:
|
|
164
|
-
- The file was written to `~/.goodvibes/agent/providers/{name}.json`
|
|
165
|
-
- The provider should be available to the Agent runtime after provider reload or next Agent startup
|
|
166
|
-
- If an API key is needed, remind them to set the environment variable
|
|
167
|
-
|
|
168
|
-
## Validation Rules
|
|
169
|
-
|
|
170
|
-
Before writing, verify:
|
|
171
|
-
1. `name` matches `/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/` and is 1-64 characters (no trailing hyphens)
|
|
172
|
-
2. `baseURL` starts with `http://` or `https://`
|
|
173
|
-
3. `contextWindow` is a positive integer for every model
|
|
174
|
-
4. At least one model is defined
|
|
175
|
-
5. Every model has a non-empty `id` and `displayName`
|
|
176
|
-
|
|
177
|
-
If validation fails, tell the user which field is invalid and ask for correction.
|
|
178
|
-
|
|
179
|
-
## JSON Schema Reference
|
|
180
|
-
|
|
181
|
-
The provider JSON maps to the codebase types:
|
|
182
|
-
|
|
183
|
-
- Provider registration uses `OpenAICompatProvider` for `openai-compat` type. The `anthropic-compat` type is parsed and accepted in the JSON but is **not yet supported at runtime** — the loader skips it with a warning. Recommend `openai-compat` for all custom providers.
|
|
184
|
-
- `OpenAICompatOptions`: `{ name, baseURL, apiKey, defaultModel, models }`
|
|
185
|
-
- Model entries map to `ModelDefinition`: `{ id, provider, displayName, description, contextWindow, capabilities, reasoningEffort?, selectable }`
|
|
186
|
-
- `reasoningEffort?: string[]` — optional array of supported effort levels, e.g., `["low", "medium", "high"]`
|
|
187
|
-
- The `selectable` field defaults to `true` for custom models
|
|
188
|
-
- The `provider` field in `ModelDefinition` is auto-set to the provider `name`
|
|
189
|
-
|
|
190
|
-
## Conversational Style
|
|
191
|
-
|
|
192
|
-
Be natural and helpful. Guide users step-by-step but do not be overly verbose. If the user provides multiple details at once (e.g., "add ollama with llama3.3-70b"), extract what you can and only ask for missing fields.
|
|
193
|
-
|
|
194
|
-
## Edge Cases
|
|
195
|
-
|
|
196
|
-
- **Unknown context window**: Suggest 4096 as a safe default, note the user can update later
|
|
197
|
-
- **No API key needed**: Omit `apiKeyEnv` and `apiKey` from the JSON entirely
|
|
198
|
-
- **User provides a full JSON blob**: Validate it against the schema and write directly
|
|
199
|
-
- **Multiple providers in one session**: After completing one, ask if they want to add another
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
import type { CommandContext, CommandRegistry } from '../command-registry.ts';
|
|
4
|
-
import { CodeIntelligence } from '@pellux/goodvibes-sdk/platform/intelligence';
|
|
5
|
-
import type { DocumentSymbol } from '@pellux/goodvibes-sdk/platform/intelligence';
|
|
6
|
-
import type { SymbolInfo } from '@pellux/goodvibes-sdk/platform/intelligence';
|
|
7
|
-
import { openCommandPanel, requireReadModels, requireShellPaths } from './runtime-services.ts';
|
|
8
|
-
|
|
9
|
-
function resolveTargetPath(pathArg: string, ctx: CommandContext): string {
|
|
10
|
-
return requireShellPaths(ctx).resolveWorkspacePath(pathArg);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function parsePosition(lineArg: string | undefined, columnArg: string | undefined): { line: number; column: number } | null {
|
|
14
|
-
const line = Number.parseInt(lineArg ?? '', 10);
|
|
15
|
-
const column = Number.parseInt(columnArg ?? '', 10);
|
|
16
|
-
if (!Number.isFinite(line) || line < 1 || !Number.isFinite(column) || column < 1) return null;
|
|
17
|
-
return { line: line - 1, column: column - 1 };
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function formatSymbolKind(kind: number | string | undefined): string {
|
|
21
|
-
if (typeof kind === 'number') return `kind=${kind}`;
|
|
22
|
-
if (typeof kind === 'string' && kind.trim().length > 0) return kind;
|
|
23
|
-
return 'symbol';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function formatDocumentSymbol(symbol: DocumentSymbol): string {
|
|
27
|
-
const line = (symbol.selectionRange?.start.line ?? symbol.range.start.line) + 1;
|
|
28
|
-
const column = (symbol.selectionRange?.start.character ?? symbol.range.start.character) + 1;
|
|
29
|
-
return ` ${symbol.name} ${formatSymbolKind(symbol.kind)} ${line}:${column}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function formatTreeSitterSymbol(symbol: SymbolInfo): string {
|
|
33
|
-
return ` ${symbol.name} ${formatSymbolKind(symbol.kind)} ${symbol.line + 1}:${symbol.column + 1}`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function ensureExistingFile(pathArg: string | undefined, ctx: CommandContext): string | null {
|
|
37
|
-
if (!pathArg) {
|
|
38
|
-
ctx.print('Intelligence Review\n Missing file path.');
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
const targetPath = resolveTargetPath(pathArg, ctx);
|
|
42
|
-
if (!existsSync(targetPath)) {
|
|
43
|
-
ctx.print(`Intelligence Review\n File not found: ${targetPath}`);
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
return targetPath;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function registerIntelligenceRuntimeCommands(registry: CommandRegistry): void {
|
|
50
|
-
registry.register({
|
|
51
|
-
name: 'intelligence',
|
|
52
|
-
aliases: ['intel'],
|
|
53
|
-
description: 'Review workspace intelligence readiness, diagnostics posture, and symbol search availability',
|
|
54
|
-
usage: '[review|panel|diagnostics [file]|symbols <file>|outline <file>|definition <file> <line> <column>|references <file> <line> <column>|hover <file> <line> <column>|repair]',
|
|
55
|
-
async handler(args, ctx) {
|
|
56
|
-
const sub = (args[0] ?? 'review').toLowerCase();
|
|
57
|
-
if (sub === 'panel' || sub === 'open') {
|
|
58
|
-
openCommandPanel(ctx, 'intelligence');
|
|
59
|
-
return;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const intelligence = new CodeIntelligence();
|
|
63
|
-
const state = requireReadModels(ctx).intelligence.getSnapshot();
|
|
64
|
-
|
|
65
|
-
if (sub === 'symbols' || sub === 'outline') {
|
|
66
|
-
const targetPath = ensureExistingFile(args[1], ctx);
|
|
67
|
-
if (!targetPath) return;
|
|
68
|
-
const content = readFileSync(targetPath, 'utf-8');
|
|
69
|
-
if (sub === 'symbols') {
|
|
70
|
-
const symbols = await intelligence.getDocumentSymbols(targetPath, content);
|
|
71
|
-
const entries = symbols.slice(0, 12).map((symbol) => ('selectionRange' in symbol ? formatDocumentSymbol(symbol) : formatTreeSitterSymbol(symbol)));
|
|
72
|
-
ctx.print([
|
|
73
|
-
`Intelligence Symbols: ${targetPath}`,
|
|
74
|
-
` source: ${state.symbolSearchStatus === 'ready' ? 'LSP/tree-sitter' : 'best-effort tree-sitter/LSP fallback'}`,
|
|
75
|
-
` status: ${state.symbolSearchStatus}`,
|
|
76
|
-
` results: ${symbols.length}`,
|
|
77
|
-
...(entries.length > 0 ? entries : [' No symbols available for this file.']),
|
|
78
|
-
' next: /health intelligence',
|
|
79
|
-
].join('\n'));
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const outline = await intelligence.getOutline(targetPath, content);
|
|
84
|
-
ctx.print([
|
|
85
|
-
`Intelligence Outline: ${targetPath}`,
|
|
86
|
-
` source: tree-sitter outline extraction`,
|
|
87
|
-
` language ready: ${intelligence.hasTreeSitter(targetPath) ? 'yes' : 'no'}`,
|
|
88
|
-
` results: ${outline.length}`,
|
|
89
|
-
...(outline.slice(0, 12).map((entry) => ` ${entry.signature || entry.name} line ${entry.line}`)),
|
|
90
|
-
...(outline.length === 0 ? [' No outline entries available for this file.'] : []),
|
|
91
|
-
' next: /intelligence symbols ' + targetPath,
|
|
92
|
-
].join('\n'));
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (sub === 'definition' || sub === 'references' || sub === 'hover') {
|
|
97
|
-
const targetPath = ensureExistingFile(args[1], ctx);
|
|
98
|
-
if (!targetPath) return;
|
|
99
|
-
const position = parsePosition(args[2], args[3]);
|
|
100
|
-
if (!position) {
|
|
101
|
-
ctx.print(`Intelligence ${sub[0]!.toUpperCase()}${sub.slice(1)}\n Usage: /intelligence ${sub} <file> <line> <column>`);
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (sub === 'definition') {
|
|
106
|
-
const definition = await intelligence.getDefinition(targetPath, position.line, position.column);
|
|
107
|
-
ctx.print([
|
|
108
|
-
`Intelligence Definition: ${targetPath}:${position.line + 1}:${position.column + 1}`,
|
|
109
|
-
` status: ${state.hoverStatus === 'ready' || state.symbolSearchStatus === 'ready' ? 'available' : 'best-effort'}`,
|
|
110
|
-
...(definition
|
|
111
|
-
? [
|
|
112
|
-
` target: ${definition.uri}`,
|
|
113
|
-
` line: ${definition.range.start.line + 1}`,
|
|
114
|
-
` column: ${definition.range.start.character + 1}`,
|
|
115
|
-
' next: open the target file or use /intelligence references on the same symbol',
|
|
116
|
-
]
|
|
117
|
-
: [' No definition was returned for that position.', ' next: /health intelligence']),
|
|
118
|
-
].join('\n'));
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (sub === 'references') {
|
|
123
|
-
const references = await intelligence.getReferences(targetPath, position.line, position.column);
|
|
124
|
-
ctx.print([
|
|
125
|
-
`Intelligence References: ${targetPath}:${position.line + 1}:${position.column + 1}`,
|
|
126
|
-
` status: ${state.symbolSearchStatus}`,
|
|
127
|
-
` results: ${references.length}`,
|
|
128
|
-
...(references.slice(0, 12).map((reference) => ` ${reference.uri} ${reference.range.start.line + 1}:${reference.range.start.character + 1}`)),
|
|
129
|
-
...(references.length === 0 ? [' No references were returned for that position.'] : []),
|
|
130
|
-
' next: /intelligence definition ' + `${targetPath} ${position.line + 1} ${position.column + 1}`,
|
|
131
|
-
].join('\n'));
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const hover = await intelligence.getHover(targetPath, position.line, position.column);
|
|
136
|
-
const hoverLines = typeof hover?.contents === 'string'
|
|
137
|
-
? hover.contents.split('\n')
|
|
138
|
-
: Array.isArray(hover?.contents)
|
|
139
|
-
? hover.contents.flatMap((entry) => typeof entry === 'string' ? entry : entry.value.split('\n'))
|
|
140
|
-
: hover?.contents && 'value' in hover.contents
|
|
141
|
-
? hover.contents.value.split('\n')
|
|
142
|
-
: [];
|
|
143
|
-
ctx.print([
|
|
144
|
-
`Intelligence Hover: ${targetPath}:${position.line + 1}:${position.column + 1}`,
|
|
145
|
-
` status: ${state.hoverStatus}`,
|
|
146
|
-
...(hoverLines.length > 0 ? hoverLines.slice(0, 8).map((line) => ` ${line}`) : [' No hover information was returned for that position.']),
|
|
147
|
-
' next: /health intelligence',
|
|
148
|
-
].join('\n'));
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (sub === 'diagnostics') {
|
|
153
|
-
const file = args[1];
|
|
154
|
-
const entries = [...state.diagnostics.entries()]
|
|
155
|
-
.map(([filePath, diagnostics]) => ({
|
|
156
|
-
filePath,
|
|
157
|
-
diagnostics,
|
|
158
|
-
errors: diagnostics.filter((entry) => entry.severity === 'error').length,
|
|
159
|
-
warnings: diagnostics.filter((entry) => entry.severity === 'warning').length,
|
|
160
|
-
}))
|
|
161
|
-
.sort((a, b) => (b.errors - a.errors) || (b.warnings - a.warnings) || a.filePath.localeCompare(b.filePath));
|
|
162
|
-
const selected = file
|
|
163
|
-
? entries.find((entry) => entry.filePath === file)
|
|
164
|
-
: entries[0];
|
|
165
|
-
if (!selected) {
|
|
166
|
-
ctx.print('Intelligence Diagnostics\n No diagnostics are currently tracked.');
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
ctx.print([
|
|
170
|
-
`Intelligence Diagnostics: ${selected.filePath}`,
|
|
171
|
-
` errors: ${selected.errors}`,
|
|
172
|
-
` warnings: ${selected.warnings}`,
|
|
173
|
-
...selected.diagnostics.slice(0, 8).map((diagnostic) => (
|
|
174
|
-
` [${diagnostic.severity}] ${diagnostic.line + 1}:${diagnostic.column + 1} ${diagnostic.message}`
|
|
175
|
-
)),
|
|
176
|
-
...(entries.length > 1 ? [` next: /intelligence diagnostics ${entries[1]!.filePath}`] : []),
|
|
177
|
-
].join('\n'));
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
if (sub === 'repair') {
|
|
182
|
-
const lines = [
|
|
183
|
-
'Intelligence Repair',
|
|
184
|
-
' verify: /health intelligence',
|
|
185
|
-
...(state.diagnosticsStatus !== 'ready' ? [' /setup review', ' /health intelligence'] : []),
|
|
186
|
-
...(state.symbolSearchStatus !== 'ready' ? [' /symbols', ' /intelligence symbols <file>', ' /health intelligence'] : []),
|
|
187
|
-
...(state.completionsStatus !== 'ready' || state.hoverStatus !== 'ready'
|
|
188
|
-
? [' /intelligence review', ' /intelligence hover <file> <line> <column>', ' /setup onboarding']
|
|
189
|
-
: []),
|
|
190
|
-
];
|
|
191
|
-
ctx.print(lines.length > 1 ? lines.join('\n') : 'Intelligence Repair\n No active repair actions suggested.');
|
|
192
|
-
return;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
const issues: string[] = [];
|
|
196
|
-
if (state.diagnosticsStatus !== 'ready') issues.push(`diagnostics=${state.diagnosticsStatus}`);
|
|
197
|
-
if (state.symbolSearchStatus !== 'ready') issues.push(`symbols=${state.symbolSearchStatus}`);
|
|
198
|
-
if (state.completionsStatus !== 'ready') issues.push(`completions=${state.completionsStatus}`);
|
|
199
|
-
if (state.hoverStatus !== 'ready') issues.push(`hover=${state.hoverStatus}`);
|
|
200
|
-
|
|
201
|
-
ctx.print([
|
|
202
|
-
'Intelligence Review',
|
|
203
|
-
` diagnostics: ${state.diagnosticsStatus}`,
|
|
204
|
-
` symbols: ${state.symbolSearchStatus}`,
|
|
205
|
-
` completions: ${state.completionsStatus}`,
|
|
206
|
-
` hover: ${state.hoverStatus}`,
|
|
207
|
-
` errors: ${state.errorCount}`,
|
|
208
|
-
` warnings: ${state.warningCount}`,
|
|
209
|
-
` requests: ${state.totalRequests}`,
|
|
210
|
-
` avg latency: ${Math.round(state.avgLatencyMs)}ms`,
|
|
211
|
-
...(issues.length > 0 ? [` issues: ${issues.join(', ')}`] : [' issues: none']),
|
|
212
|
-
` diagnostic files: ${state.diagnostics.size}`,
|
|
213
|
-
...(state.diagnostics.size > 0 ? [' next: /intelligence diagnostics'] : []),
|
|
214
|
-
' next: /intelligence symbols <file>',
|
|
215
|
-
' next: /intelligence outline <file>',
|
|
216
|
-
' next: /intelligence references <file> <line> <column>',
|
|
217
|
-
' next: /intelligence definition <file> <line> <column>',
|
|
218
|
-
' next: /intelligence hover <file> <line> <column>',
|
|
219
|
-
' next: /intelligence repair',
|
|
220
|
-
].join('\n'));
|
|
221
|
-
},
|
|
222
|
-
});
|
|
223
|
-
}
|