@pi-unipi/unipi 2.6.0 → 2.6.2
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 +19 -0
- package/package.json +21 -22
- package/packages/ask-user/package.json +2 -2
- package/packages/ask-user/settings-tui.ts +18 -34
- package/packages/autocomplete/package.json +1 -1
- package/packages/autocomplete/src/constants.ts +2 -15
- package/packages/autocomplete/src/provider.ts +3 -17
- package/packages/btw/extensions/btw.ts +18 -45
- package/packages/btw/package.json +2 -2
- package/packages/compactor/README.md +2 -2
- package/packages/compactor/package.json +3 -3
- package/packages/compactor/skills/compactor/SKILL.md +1 -1
- package/packages/compactor/skills/compactor-detail/SKILL.md +3 -5
- package/packages/compactor/skills/compactor-doctor/SKILL.md +1 -1
- package/packages/compactor/skills/compactor-stats/SKILL.md +1 -1
- package/packages/compactor/src/commands/index.ts +47 -78
- package/packages/compactor/src/compaction/brief.ts +161 -90
- package/packages/compactor/src/compaction/build-sections.ts +3 -4
- package/packages/compactor/src/compaction/compact-args.ts +86 -0
- package/packages/compactor/src/compaction/cut.ts +270 -28
- package/packages/compactor/src/compaction/drill-down.ts +261 -0
- package/packages/compactor/src/compaction/format-recall.ts +96 -0
- package/packages/compactor/src/compaction/format.ts +8 -3
- package/packages/compactor/src/compaction/hooks.ts +248 -72
- package/packages/compactor/src/compaction/merge.ts +34 -4
- package/packages/compactor/src/compaction/rank.ts +270 -0
- package/packages/compactor/src/compaction/recall-scope.ts +28 -0
- package/packages/compactor/src/compaction/search-entries.ts +333 -96
- package/packages/compactor/src/compaction/skill-collapse.ts +35 -0
- package/packages/compactor/src/compaction/summarize.ts +37 -6
- package/packages/compactor/src/compaction/token-estimate.ts +104 -0
- package/packages/compactor/src/compaction/touched-files.ts +35 -0
- package/packages/compactor/src/config/manager.ts +2 -27
- package/packages/compactor/src/config/presets.ts +0 -2
- package/packages/compactor/src/config/schema.ts +2 -16
- package/packages/compactor/src/executor/executor.ts +6 -15
- package/packages/compactor/src/executor/runtime.ts +2 -12
- package/packages/compactor/src/index.ts +4 -121
- package/packages/compactor/src/info-screen.ts +3 -10
- package/packages/compactor/src/security/evaluator.ts +0 -53
- package/packages/compactor/src/security/policy.ts +7 -8
- package/packages/compactor/src/session/db.ts +0 -6
- package/packages/compactor/src/tools/ctx-execute-file.ts +0 -5
- package/packages/compactor/src/tools/register.ts +27 -50
- package/packages/compactor/src/tools/vcc-recall.ts +86 -48
- package/packages/compactor/src/tui/settings-overlay.ts +20 -40
- package/packages/compactor/src/types.ts +43 -100
- package/packages/core/constants.ts +1 -28
- package/packages/core/events.ts +1 -83
- package/packages/core/index.ts +1 -0
- package/packages/core/model-cache.ts +18 -12
- package/packages/core/package.json +3 -1
- package/packages/core/tui-overlay.ts +89 -0
- package/packages/core/tui-width.ts +18 -0
- package/packages/core/utils.ts +43 -0
- package/packages/footer/package.json +2 -2
- package/packages/footer/src/help.ts +2 -2
- package/packages/footer/src/index.ts +9 -10
- package/packages/footer/src/presets.ts +1 -27
- package/packages/footer/src/registry/index.ts +0 -23
- package/packages/footer/src/rendering/icons.ts +0 -13
- package/packages/footer/src/rendering/renderer.ts +5 -40
- package/packages/footer/src/rendering/separators.ts +0 -10
- package/packages/footer/src/rendering/theme.ts +1 -15
- package/packages/footer/src/segments/compactor.ts +7 -14
- package/packages/footer/src/segments/core.ts +15 -54
- package/packages/footer/src/segments/kanboard.ts +5 -5
- package/packages/footer/src/segments/mcp.ts +5 -5
- package/packages/footer/src/segments/memory.ts +4 -4
- package/packages/footer/src/segments/notify.ts +2 -2
- package/packages/footer/src/segments/ralph.ts +3 -3
- package/packages/footer/src/segments/status-ext.ts +1 -1
- package/packages/footer/src/segments/workflow.ts +3 -3
- package/packages/footer/src/tps-tracker.ts +0 -8
- package/packages/footer/src/tui/settings-tui.ts +14 -31
- package/packages/footer/src/types.ts +0 -15
- package/packages/image/package.json +2 -2
- package/packages/image/src/register-providers.ts +0 -11
- package/packages/image/src/tools.ts +0 -3
- package/packages/image/src/tui/model-selector.ts +36 -71
- package/packages/info-screen/config.ts +0 -16
- package/packages/info-screen/core-groups.ts +0 -10
- package/packages/info-screen/index.ts +22 -13
- package/packages/info-screen/package.json +2 -2
- package/packages/info-screen/registry.ts +1 -72
- package/packages/info-screen/tui/info-overlay.ts +85 -100
- package/packages/info-screen/usage-parser.ts +12 -47
- package/packages/input-shortcuts/package.json +2 -2
- package/packages/input-shortcuts/src/index.ts +3 -3
- package/packages/input-shortcuts/src/registers.ts +0 -8
- package/packages/input-shortcuts/src/settings-overlay.ts +4 -13
- package/packages/input-shortcuts/src/undo-redo.ts +0 -12
- package/packages/kanboard/package.json +2 -2
- package/packages/mcp/package.json +2 -2
- package/packages/mcp/src/bridge/client.ts +0 -15
- package/packages/mcp/src/config/manager.ts +0 -38
- package/packages/mcp/src/config/schema.ts +0 -27
- package/packages/mcp/src/config/sync.ts +0 -29
- package/packages/mcp/src/index.ts +1 -1
- package/packages/mcp/src/tui/add-overlay.ts +6 -6
- package/packages/mcp/src/types.ts +0 -6
- package/packages/memory/embedding.ts +0 -31
- package/packages/memory/mempalace.ts +0 -16
- package/packages/memory/package.json +4 -8
- package/packages/memory/storage.ts +56 -753
- package/packages/milestone/hooks.ts +1 -6
- package/packages/milestone/milestone.ts +2 -41
- package/packages/milestone/package.json +2 -2
- package/packages/notify/README.md +1 -0
- package/packages/notify/commands.ts +61 -3
- package/packages/notify/events.ts +0 -10
- package/packages/notify/package.json +2 -2
- package/packages/notify/settings.ts +0 -19
- package/packages/notify/tui/gotify-setup.ts +108 -143
- package/packages/notify/tui/ntfy-setup.ts +137 -172
- package/packages/notify/tui/recap-model-selector.ts +107 -101
- package/packages/notify/tui/settings-overlay.ts +94 -117
- package/packages/notify/tui/telegram-setup.ts +48 -79
- package/packages/notify/types.ts +0 -2
- package/packages/ralph/index.ts +11 -35
- package/packages/ralph/package.json +3 -3
- package/packages/ralph/ralph-loop.ts +3 -44
- package/packages/subagents/package.json +2 -1
- package/packages/subagents/src/agent-manager.ts +0 -51
- package/packages/subagents/src/agent-runner.ts +6 -80
- package/packages/subagents/src/conversation-viewer.ts +1 -19
- package/packages/subagents/src/core-compat.ts +8 -25
- package/packages/subagents/src/custom-agents.ts +0 -1
- package/packages/subagents/src/index.ts +3 -48
- package/packages/subagents/src/types.ts +0 -11
- package/packages/subagents/src/widget.ts +5 -5
- package/packages/unipi/bundled.js +4468 -7769
- package/packages/unipi/index.ts +6 -3
- package/packages/updater/package.json +2 -2
- package/packages/updater/src/changelog.ts +1 -16
- package/packages/updater/src/index.ts +0 -5
- package/packages/updater/src/installer.ts +4 -26
- package/packages/updater/src/markdown.ts +6 -152
- package/packages/updater/src/settings.ts +0 -15
- package/packages/updater/src/tui/changelog-overlay.ts +42 -234
- package/packages/updater/src/tui/list-detail-overlay.ts +260 -0
- package/packages/updater/src/tui/readme-overlay.ts +53 -210
- package/packages/updater/src/tui/settings-overlay.ts +13 -26
- package/packages/updater/src/version.ts +2 -31
- package/packages/utility/package.json +2 -4
- package/packages/utility/src/commands.ts +4 -5
- package/packages/utility/src/herdr-sync.ts +136 -0
- package/packages/utility/src/index.ts +11 -68
- package/packages/utility/src/lifecycle/cleanup.ts +2 -16
- package/packages/utility/src/{diff/settings.ts → settings.ts} +42 -80
- package/packages/utility/src/tools/env.ts +0 -0
- package/packages/utility/src/tui/name-badge-state.ts +18 -2
- package/packages/utility/src/tui/name-badge.ts +5 -4
- package/packages/utility/src/tui/util-settings-tui.ts +41 -224
- package/packages/web-api/package.json +2 -6
- package/packages/web-api/src/engine/dependencies.ts +13 -134
- package/packages/web-api/src/engine/extract.ts +9 -99
- package/packages/web-api/src/engine/format.ts +0 -75
- package/packages/web-api/src/engine/types.ts +0 -39
- package/packages/web-api/src/index.ts +1 -2
- package/packages/web-api/src/providers/base.ts +0 -10
- package/packages/web-api/src/providers/duckduckgo.ts +0 -1
- package/packages/web-api/src/providers/firecrawl.ts +0 -9
- package/packages/web-api/src/providers/jina-reader.ts +0 -9
- package/packages/web-api/src/providers/jina-search.ts +0 -9
- package/packages/web-api/src/providers/perplexity.ts +0 -9
- package/packages/web-api/src/providers/registry.ts +0 -80
- package/packages/web-api/src/providers/serpapi.ts +0 -9
- package/packages/web-api/src/providers/tavily.ts +0 -9
- package/packages/web-api/src/providers/wigolo-client.ts +0 -30
- package/packages/web-api/src/providers/wigolo.ts +0 -1
- package/packages/web-api/src/settings.ts +17 -77
- package/packages/web-api/src/tools.ts +21 -24
- package/packages/web-api/src/tui/settings-dialog.ts +0 -1
- package/packages/workflow/commands.ts +38 -122
- package/packages/workflow/index.ts +1 -5
- package/packages/workflow/package.json +2 -2
- package/packages/cocoindex/README.md +0 -94
- package/packages/cocoindex/bridge.ts +0 -842
- package/packages/cocoindex/commands.ts +0 -175
- package/packages/cocoindex/index.ts +0 -48
- package/packages/cocoindex/installer.ts +0 -397
- package/packages/cocoindex/package.json +0 -49
- package/packages/cocoindex/skills/cocoindex/SKILL.md +0 -88
- package/packages/cocoindex/tools.ts +0 -157
- package/packages/compactor/src/display/diff-renderer.ts +0 -281
- package/packages/compactor/src/display/line-width-safety.ts +0 -28
- package/packages/compactor/src/display/render-utils.ts +0 -52
- package/packages/compactor/src/display/thinking-label.ts +0 -18
- package/packages/compactor/src/display/tool-overrides.ts +0 -136
- package/packages/compactor/src/tools/compact.ts +0 -20
- package/packages/subagents/src/file-lock.ts +0 -102
- package/packages/utility/src/cache/ttl-cache.ts +0 -311
- package/packages/utility/src/diff/highlighter.ts +0 -352
- package/packages/utility/src/diff/parser.ts +0 -191
- package/packages/utility/src/diff/renderer.ts +0 -395
- package/packages/utility/src/diff/theme.ts +0 -316
- package/packages/utility/src/diff/wrapper.ts +0 -339
- package/packages/utility/src/display/capabilities.ts +0 -214
- package/packages/utility/src/display/width.ts +0 -226
- package/packages/utility/src/tools/batch.ts +0 -229
- package/packages/utility/src/tui/badge-settings-tui.ts +0 -388
- package/packages/utility/src/tui/badge-settings.ts +0 -67
- package/packages/utility/src/tui/settings-inspector.ts +0 -303
- package/packages/web-api/src/providers/llm-summarize.ts +0 -71
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: cocoindex
|
|
3
|
-
description: "CocoIndex content indexing and search — use when you need to search indexed project content or trigger re-indexing"
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# CocoIndex Skill
|
|
7
|
-
|
|
8
|
-
## When to Use CocoIndex
|
|
9
|
-
|
|
10
|
-
Use CocoIndex tools and commands when you need to:
|
|
11
|
-
|
|
12
|
-
1. **Search indexed project content** — use `cocoindex_search` instead of `content_search` or `ctx_search`
|
|
13
|
-
2. **Trigger re-indexing** — use `/unipi:cocoindex-update` after significant code changes
|
|
14
|
-
3. **Initialize indexing** — use `/unipi:cocoindex-init` for new projects
|
|
15
|
-
|
|
16
|
-
## Key Differences from Old FTS5 Content Store
|
|
17
|
-
|
|
18
|
-
| Aspect | Old (FTS5) | New (CocoIndex) |
|
|
19
|
-
|--------|-----------|-----------------|
|
|
20
|
-
| Chunking | Heading/paragraph split | AST-aware code, recursive text |
|
|
21
|
-
| Search | BM25 + trigram fuzzy | Semantic vector + full-text |
|
|
22
|
-
| Incremental | Full re-index every time | Delta-only (changed files) |
|
|
23
|
-
| Scale | Small corpus | Multi-GiB, parallel |
|
|
24
|
-
| Store | SQLite FTS5 | LanceDB |
|
|
25
|
-
|
|
26
|
-
## Tools
|
|
27
|
-
|
|
28
|
-
### `cocoindex_search`
|
|
29
|
-
Search indexed content. It uses semantic vector search when the LanceDB table has vectors, LanceDB full-text search when an inverted index exists, and a lexical fallback for older text-only indexes.
|
|
30
|
-
|
|
31
|
-
```
|
|
32
|
-
cocoindex_search({ query: "how authentication works", limit: 10 })
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Returns results with `title`, `content`, `source`, `rank`, `contentType`, and `matchLayer`.
|
|
36
|
-
|
|
37
|
-
### `cocoindex_status`
|
|
38
|
-
Check indexing status — pipeline configured, last run, doc count, CLI availability.
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
cocoindex_status({})
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Commands
|
|
45
|
-
|
|
46
|
-
| Command | Description |
|
|
47
|
-
|---------|-------------|
|
|
48
|
-
| `/unipi:cocoindex-update` | Run `cocoindex update` on current project |
|
|
49
|
-
| `/unipi:cocoindex-status` | Show indexing status |
|
|
50
|
-
| `/unipi:cocoindex-init` | Scaffold a default pipeline |
|
|
51
|
-
| `/unipi:cocoindex-search <query>` | Search indexed codebase semantically |
|
|
52
|
-
| `/unipi:cocoindex-settings` | Show configuration |
|
|
53
|
-
|
|
54
|
-
## Prerequisites
|
|
55
|
-
|
|
56
|
-
1. **Python 3.10+** with `cocoindex` installed:
|
|
57
|
-
```bash
|
|
58
|
-
pip install cocoindex
|
|
59
|
-
pip install 'cocoindex[lancedb]'
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
2. **Pipeline initialized** — run `/unipi:cocoindex-init` once per project
|
|
63
|
-
|
|
64
|
-
3. **Embedding config** — CocoIndex reuses the memory package's embedding settings:
|
|
65
|
-
- API key from `~/.unipi/memory/config.json`
|
|
66
|
-
- Same model and dimensions for cross-system search
|
|
67
|
-
|
|
68
|
-
## Architecture
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
Project files → LocalFile source → SplitRecursively → EmbedText → LanceDB
|
|
72
|
-
↓
|
|
73
|
-
Agent query ──────────────────────────────→ vector search → ranked results
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
- Pipeline defined in `.unipi/cocoindex/main.py` (auto-generated, customizable)
|
|
77
|
-
- Data stored in `.unipi/cocoindex/.lancedb/`
|
|
78
|
-
- Search queries LanceDB directly via Node.js SDK (no CLI round-trip)
|
|
79
|
-
|
|
80
|
-
## Troubleshooting
|
|
81
|
-
|
|
82
|
-
| Issue | Fix |
|
|
83
|
-
|-------|-----|
|
|
84
|
-
| "CLI not found" | `pip install cocoindex` |
|
|
85
|
-
| "Pipeline not initialized" | `/unipi:cocoindex-init` |
|
|
86
|
-
| "Search unavailable" | `npm install @lancedb/lancedb` |
|
|
87
|
-
| "No results" | Run `/unipi:cocoindex-update` first |
|
|
88
|
-
| Embedding errors | Check `~/.unipi/memory/config.json` API key |
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* tools.ts — CocoIndex tool registration
|
|
3
|
-
*
|
|
4
|
-
* Exposes cocoindex operations as Pi agent tools:
|
|
5
|
-
* - cocoindex_search: Search indexed content
|
|
6
|
-
* - cocoindex_status: Show indexing status
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { Type } from "typebox";
|
|
10
|
-
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
11
|
-
import { COCOINDEX_PACKAGE_SPEC, COCOINDEX_TOOLS } from "@pi-unipi/core";
|
|
12
|
-
import * as bridge from "./bridge.js";
|
|
13
|
-
|
|
14
|
-
export interface CocoindexToolDeps {
|
|
15
|
-
getProjectDir(ctx: ExtensionContext): string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// ─────────────────────────────────────────────────────────
|
|
19
|
-
// Schemas
|
|
20
|
-
// ─────────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
export const MAX_SEARCH_RESULTS = 50;
|
|
23
|
-
|
|
24
|
-
export function normalizeSearchPage(limit?: number, offset?: number): { limit: number; offset: number } {
|
|
25
|
-
const requestedLimit = Number.isFinite(limit) ? Math.floor(limit!) : 10;
|
|
26
|
-
const requestedOffset = Number.isFinite(offset) ? Math.floor(offset!) : 0;
|
|
27
|
-
return {
|
|
28
|
-
limit: Math.min(MAX_SEARCH_RESULTS, Math.max(1, requestedLimit)),
|
|
29
|
-
offset: Math.max(0, requestedOffset),
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const SearchParams = Type.Object({
|
|
34
|
-
query: Type.String({ description: "Search query against indexed content" }),
|
|
35
|
-
limit: Type.Optional(Type.Number({
|
|
36
|
-
description: `Max results (default 10, hard cap ${MAX_SEARCH_RESULTS})`,
|
|
37
|
-
minimum: 1,
|
|
38
|
-
maximum: MAX_SEARCH_RESULTS,
|
|
39
|
-
})),
|
|
40
|
-
offset: Type.Optional(Type.Number({ description: "Pagination offset", minimum: 0 })),
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const StatusParams = Type.Object({});
|
|
44
|
-
|
|
45
|
-
// ─────────────────────────────────────────────────────────
|
|
46
|
-
// Helpers
|
|
47
|
-
// ─────────────────────────────────────────────────────────
|
|
48
|
-
|
|
49
|
-
function textResult(text: string, details?: Record<string, unknown>): any {
|
|
50
|
-
return {
|
|
51
|
-
content: [{ type: "text", text }],
|
|
52
|
-
details,
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// ─────────────────────────────────────────────────────────
|
|
57
|
-
// Registration
|
|
58
|
-
// ─────────────────────────────────────────────────────────
|
|
59
|
-
|
|
60
|
-
export function registerCocoindexTools(pi: ExtensionAPI, deps: CocoindexToolDeps): void {
|
|
61
|
-
// cocoindex_search — search indexed content via LanceDB
|
|
62
|
-
pi.registerTool({
|
|
63
|
-
name: COCOINDEX_TOOLS.SEARCH,
|
|
64
|
-
label: "CocoIndex Search",
|
|
65
|
-
description:
|
|
66
|
-
"Search indexed content using semantic vector search when available, with full-text/lexical fallbacks. " +
|
|
67
|
-
"Diagnostic/search only: this tool never installs CocoIndex. " +
|
|
68
|
-
"Use /unipi:cocoindex-init to set up/install, then /unipi:cocoindex-update to index.",
|
|
69
|
-
parameters: SearchParams,
|
|
70
|
-
async execute(
|
|
71
|
-
_toolCallId: string,
|
|
72
|
-
params: any,
|
|
73
|
-
_signal: AbortSignal | undefined,
|
|
74
|
-
_onUpdate: unknown,
|
|
75
|
-
ctx: ExtensionContext,
|
|
76
|
-
): Promise<any> {
|
|
77
|
-
try {
|
|
78
|
-
const available = await bridge.isAvailable();
|
|
79
|
-
if (!available) {
|
|
80
|
-
return textResult(
|
|
81
|
-
"Search Unavailable: CocoIndex CLI is not installed. " +
|
|
82
|
-
"Run /unipi:cocoindex-init for guided install, or manually run " +
|
|
83
|
-
`uv tool install '${COCOINDEX_PACKAGE_SPEC}'.`,
|
|
84
|
-
{ cliAvailable: false },
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Clamp in execution as well as schema validation: Pi extensions may
|
|
89
|
-
// mutate tool inputs after validation and custom hosts may skip it.
|
|
90
|
-
const { limit, offset } = normalizeSearchPage(params.limit, params.offset);
|
|
91
|
-
const results = await bridge.search(deps.getProjectDir(ctx), params.query, {
|
|
92
|
-
limit,
|
|
93
|
-
offset,
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (results.length === 0) {
|
|
97
|
-
return textResult(
|
|
98
|
-
`No results for "${params.query}" in the current CocoIndex data. ` +
|
|
99
|
-
"If this seems wrong, run /unipi:cocoindex-status to confirm the pipeline has data, then /unipi:cocoindex-update to refresh it.",
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const lines = results.map(
|
|
104
|
-
(r, i) =>
|
|
105
|
-
`[${i + 1}] ${r.title} (${r.matchLayer}, rank: ${r.rank.toFixed(3)})\n${r.content.slice(0, 300)}`,
|
|
106
|
-
);
|
|
107
|
-
return textResult(
|
|
108
|
-
`Found ${results.length} results for "${params.query}":\n\n${lines.join("\n\n")}`,
|
|
109
|
-
// Avoid duplicating full result content in model-visible details.
|
|
110
|
-
{ count: results.length, query: params.query, limit, offset },
|
|
111
|
-
);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
return textResult(`CocoIndex search error: ${err}`, { error: true });
|
|
114
|
-
}
|
|
115
|
-
},
|
|
116
|
-
} as any);
|
|
117
|
-
|
|
118
|
-
// cocoindex_status — show indexing status
|
|
119
|
-
pi.registerTool({
|
|
120
|
-
name: COCOINDEX_TOOLS.STATUS,
|
|
121
|
-
label: "CocoIndex Status",
|
|
122
|
-
description: "Check CocoIndex indexing status. Diagnostic only; use commands for interactive install/update.",
|
|
123
|
-
parameters: StatusParams,
|
|
124
|
-
async execute(
|
|
125
|
-
_toolCallId: string,
|
|
126
|
-
_params: Record<string, never>,
|
|
127
|
-
_signal: AbortSignal | undefined,
|
|
128
|
-
_onUpdate: unknown,
|
|
129
|
-
ctx: ExtensionContext,
|
|
130
|
-
): Promise<any> {
|
|
131
|
-
try {
|
|
132
|
-
const info = await bridge.status(deps.getProjectDir(ctx));
|
|
133
|
-
const lines = [
|
|
134
|
-
`📦 CocoIndex Status`,
|
|
135
|
-
`CLI available: ${info.cliAvailable ? "✅" : "❌"}`,
|
|
136
|
-
`Pipeline configured: ${info.pipelineConfigured ? "✅" : "❌"}`,
|
|
137
|
-
`Target store: ${info.targetStore}`,
|
|
138
|
-
`Indexed: ${info.indexed ? "✅" : "— (no data)"}`,
|
|
139
|
-
`Doc count: ${info.docCount}`,
|
|
140
|
-
`Last run: ${info.lastRun ?? "never"}`,
|
|
141
|
-
];
|
|
142
|
-
if (!info.cliAvailable) {
|
|
143
|
-
lines.push(
|
|
144
|
-
"",
|
|
145
|
-
"Install guidance:",
|
|
146
|
-
" • Run /unipi:cocoindex-init for guided install.",
|
|
147
|
-
` • Manual: uv tool install '${COCOINDEX_PACKAGE_SPEC}'`,
|
|
148
|
-
" • If uv is missing and mise is available: mise use -g uv@latest",
|
|
149
|
-
);
|
|
150
|
-
}
|
|
151
|
-
return textResult(lines.join("\n"), info as unknown as Record<string, unknown>);
|
|
152
|
-
} catch (err) {
|
|
153
|
-
return textResult(`CocoIndex status error: ${err}`, { error: true });
|
|
154
|
-
}
|
|
155
|
-
},
|
|
156
|
-
} as any);
|
|
157
|
-
}
|
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Diff rendering engine — LCS-based diff with 3 layouts, 3 indicators,
|
|
3
|
-
* syntax highlighting, and Nerd Font detection
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { visibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
|
|
7
|
-
|
|
8
|
-
export type DiffLayout = "auto" | "split" | "unified";
|
|
9
|
-
export type DiffIndicator = "bars" | "classic" | "nerd" | "none";
|
|
10
|
-
|
|
11
|
-
// --- Nerd Font Detection ---
|
|
12
|
-
|
|
13
|
-
let nerdFontDetected: boolean | null = null;
|
|
14
|
-
|
|
15
|
-
/** Detect if terminal supports Nerd Font icons */
|
|
16
|
-
export function detectNerdFont(): boolean {
|
|
17
|
-
if (nerdFontDetected !== null) return nerdFontDetected;
|
|
18
|
-
// Check common Nerd Font env vars or terminal emulators
|
|
19
|
-
const term = process.env.TERM_PROGRAM ?? "";
|
|
20
|
-
const termFont = process.env.TERM_FONT ?? "";
|
|
21
|
-
nerdFontDetected =
|
|
22
|
-
termFont.toLowerCase().includes("nerd") ||
|
|
23
|
-
process.env.NERD_FONT === "1" ||
|
|
24
|
-
term === "WezTerm" ||
|
|
25
|
-
term === "iTerm.app" ||
|
|
26
|
-
(process.env.TERMINAL_EMULATOR ?? "").includes("JetBrains") ||
|
|
27
|
-
false;
|
|
28
|
-
return nerdFontDetected;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Nerd Font indicator chars */
|
|
32
|
-
const NERD_INDICATORS = {
|
|
33
|
-
add: "\uf055 ", // nf-fa-plus_circle
|
|
34
|
-
remove: "\uf056 ", // nf-fa-minus_circle
|
|
35
|
-
same: " ",
|
|
36
|
-
} as const;
|
|
37
|
-
|
|
38
|
-
// --- Syntax Highlighting ---
|
|
39
|
-
|
|
40
|
-
const KEYWORDS: Record<string, Set<string>> = {
|
|
41
|
-
js: new Set(["const", "let", "var", "function", "return", "if", "else", "for", "while", "class", "import", "export", "from", "async", "await", "try", "catch", "throw", "new", "this", "typeof", "instanceof", "in", "of", "switch", "case", "break", "continue", "default", "yield", "void", "delete", "null", "undefined", "true", "false"]),
|
|
42
|
-
py: new Set(["def", "class", "import", "from", "return", "if", "elif", "else", "for", "while", "try", "except", "finally", "raise", "with", "as", "yield", "lambda", "pass", "break", "continue", "and", "or", "not", "in", "is", "None", "True", "False", "self", "async", "await"]),
|
|
43
|
-
ts: new Set(["const", "let", "var", "function", "return", "if", "else", "for", "while", "class", "import", "export", "from", "async", "await", "try", "catch", "throw", "new", "this", "typeof", "instanceof", "interface", "type", "enum", "namespace", "module", "declare", "implements", "extends", "public", "private", "protected", "readonly", "static", "abstract", "override", "keyof", "infer", "never", "unknown", "any", "void", "string", "number", "boolean", "null", "undefined", "true", "false"]),
|
|
44
|
-
sh: new Set(["if", "then", "else", "elif", "fi", "for", "while", "do", "done", "case", "esac", "function", "return", "local", "export", "readonly", "declare", "unset", "shift", "source", "exit", "echo", "printf", "read", "test", "true", "false"]),
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
/** Apply basic syntax highlighting to a line */
|
|
48
|
-
function highlightLine(line: string, lang?: string): string {
|
|
49
|
-
if (!lang) return line;
|
|
50
|
-
const keywords = KEYWORDS[lang] ?? KEYWORDS.js;
|
|
51
|
-
// Highlight keywords (simple word boundary match)
|
|
52
|
-
return line.replace(/\b([a-zA-Z_]\w*)\b/g, (match) => {
|
|
53
|
-
if (keywords.has(match)) return `\x1b[34m${match}\x1b[0m`; // blue
|
|
54
|
-
return match;
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Detect language from file extension or content */
|
|
59
|
-
function detectLanguage(filePath?: string, content?: string): string | undefined {
|
|
60
|
-
if (filePath) {
|
|
61
|
-
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
62
|
-
const extMap: Record<string, string> = {
|
|
63
|
-
js: "js", mjs: "js", cjs: "js", jsx: "js",
|
|
64
|
-
ts: "ts", mts: "ts", cts: "ts", tsx: "ts",
|
|
65
|
-
py: "py", pyw: "py",
|
|
66
|
-
sh: "sh", bash: "sh", zsh: "sh",
|
|
67
|
-
};
|
|
68
|
-
if (ext && extMap[ext]) return extMap[ext];
|
|
69
|
-
}
|
|
70
|
-
if (content) {
|
|
71
|
-
if (content.includes("def ") || content.includes("import ")) return "py";
|
|
72
|
-
if (content.includes("function ") || content.includes("const ")) return "js";
|
|
73
|
-
if (content.includes("#!/bin/")) return "sh";
|
|
74
|
-
}
|
|
75
|
-
return undefined;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
interface DiffLine {
|
|
79
|
-
type: "same" | "add" | "remove";
|
|
80
|
-
text: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function lcs<T>(a: T[], b: T[]): T[] {
|
|
84
|
-
const m = a.length;
|
|
85
|
-
const n = b.length;
|
|
86
|
-
const dp: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
|
|
87
|
-
|
|
88
|
-
for (let i = 1; i <= m; i++) {
|
|
89
|
-
for (let j = 1; j <= n; j++) {
|
|
90
|
-
if (a[i - 1] === b[j - 1]) {
|
|
91
|
-
dp[i][j] = dp[i - 1][j - 1] + 1;
|
|
92
|
-
} else {
|
|
93
|
-
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
const result: T[] = [];
|
|
99
|
-
let i = m, j = n;
|
|
100
|
-
while (i > 0 && j > 0) {
|
|
101
|
-
if (a[i - 1] === b[j - 1]) {
|
|
102
|
-
result.unshift(a[i - 1]);
|
|
103
|
-
i--;
|
|
104
|
-
j--;
|
|
105
|
-
} else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
106
|
-
i--;
|
|
107
|
-
} else {
|
|
108
|
-
j--;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return result;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function computeDiff(before: string[], after: string[]): DiffLine[] {
|
|
116
|
-
const common = lcs(before, after);
|
|
117
|
-
const result: DiffLine[] = [];
|
|
118
|
-
let i = 0, j = 0, k = 0;
|
|
119
|
-
|
|
120
|
-
while (i < before.length || j < after.length) {
|
|
121
|
-
if (k < common.length && before[i] === common[k] && after[j] === common[k]) {
|
|
122
|
-
result.push({ type: "same", text: after[j] });
|
|
123
|
-
i++;
|
|
124
|
-
j++;
|
|
125
|
-
k++;
|
|
126
|
-
} else if (i < before.length && (k >= common.length || before[i] !== common[k])) {
|
|
127
|
-
result.push({ type: "remove", text: before[i] });
|
|
128
|
-
i++;
|
|
129
|
-
} else if (j < after.length && (k >= common.length || after[j] !== common[k])) {
|
|
130
|
-
result.push({ type: "add", text: after[j] });
|
|
131
|
-
j++;
|
|
132
|
-
} else {
|
|
133
|
-
break;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return result;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
function indicatorChar(type: DiffLine["type"], style: DiffIndicator): string {
|
|
141
|
-
if (style === "none") return " ";
|
|
142
|
-
if (style === "nerd") {
|
|
143
|
-
if (type === "add") return `\x1b[32m${NERD_INDICATORS.add}\x1b[0m`;
|
|
144
|
-
if (type === "remove") return `\x1b[31m${NERD_INDICATORS.remove}\x1b[0m`;
|
|
145
|
-
return NERD_INDICATORS.same;
|
|
146
|
-
}
|
|
147
|
-
if (style === "bars") {
|
|
148
|
-
if (type === "add") return `\x1b[32m│ \x1b[0m`;
|
|
149
|
-
if (type === "remove") return `\x1b[31m│ \x1b[0m`;
|
|
150
|
-
return " ";
|
|
151
|
-
}
|
|
152
|
-
return type === "add" ? "+ " : type === "remove" ? "- " : " ";
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function renderUnified(
|
|
156
|
-
diff: DiffLine[],
|
|
157
|
-
indicator: DiffIndicator,
|
|
158
|
-
maxWidth?: number,
|
|
159
|
-
): string {
|
|
160
|
-
return diff.map((line) => {
|
|
161
|
-
const prefix = indicator === "bars"
|
|
162
|
-
? (line.type === "add" ? "│ " : line.type === "remove" ? "│ " : " ")
|
|
163
|
-
: indicatorChar(line.type, indicator);
|
|
164
|
-
const rendered = prefix + line.text;
|
|
165
|
-
if (maxWidth && visibleWidth(rendered) > maxWidth) {
|
|
166
|
-
return truncateToWidth(rendered, maxWidth, "…");
|
|
167
|
-
}
|
|
168
|
-
return rendered;
|
|
169
|
-
}).join("\n");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function renderSplit(
|
|
173
|
-
diff: DiffLine[],
|
|
174
|
-
indicator: DiffIndicator,
|
|
175
|
-
maxW?: number,
|
|
176
|
-
): string {
|
|
177
|
-
const left: string[] = [];
|
|
178
|
-
const right: string[] = [];
|
|
179
|
-
|
|
180
|
-
for (const line of diff) {
|
|
181
|
-
if (line.type === "same") {
|
|
182
|
-
left.push(" " + line.text);
|
|
183
|
-
right.push(" " + line.text);
|
|
184
|
-
} else if (line.type === "remove") {
|
|
185
|
-
left.push(indicatorChar("remove", indicator) + line.text);
|
|
186
|
-
right.push("");
|
|
187
|
-
} else if (line.type === "add") {
|
|
188
|
-
left.push("");
|
|
189
|
-
right.push(indicatorChar("add", indicator) + line.text);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const halfW = maxW ? Math.floor(maxW / 2) - 2 : 40;
|
|
194
|
-
const colW = Math.max(
|
|
195
|
-
...left.map((l) => visibleWidth(l)),
|
|
196
|
-
...right.map((l) => visibleWidth(l)),
|
|
197
|
-
Math.min(halfW, 40),
|
|
198
|
-
);
|
|
199
|
-
const result: string[] = [];
|
|
200
|
-
for (let i = 0; i < left.length; i++) {
|
|
201
|
-
const lTrunc = visibleWidth(left[i]) > colW
|
|
202
|
-
? truncateToWidth(left[i], colW, "…")
|
|
203
|
-
: left[i].padEnd(colW);
|
|
204
|
-
const sep = left[i] && right[i] ? " │ " : " ";
|
|
205
|
-
let rLine = right[i];
|
|
206
|
-
if (maxW && visibleWidth(lTrunc + sep + rLine) > maxW) {
|
|
207
|
-
const rBudget = maxW - visibleWidth(lTrunc + sep);
|
|
208
|
-
rLine = truncateToWidth(rLine, Math.max(1, rBudget), "…");
|
|
209
|
-
}
|
|
210
|
-
result.push(lTrunc + sep + rLine);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return result.join("\n");
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
export function renderDiff(
|
|
217
|
-
before: string,
|
|
218
|
-
after: string,
|
|
219
|
-
opts?: { layout?: DiffLayout; indicator?: DiffIndicator; maxWidth?: number; filePath?: string; highlight?: boolean },
|
|
220
|
-
): string {
|
|
221
|
-
const layout = opts?.layout ?? "auto";
|
|
222
|
-
let indicator = opts?.indicator ?? "bars";
|
|
223
|
-
const maxWidth = opts?.maxWidth ?? 120;
|
|
224
|
-
const doHighlight = opts?.highlight ?? true;
|
|
225
|
-
|
|
226
|
-
// Auto-detect Nerd Font for indicator selection
|
|
227
|
-
if (indicator === "bars" && detectNerdFont()) {
|
|
228
|
-
indicator = "nerd";
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const beforeLines = before.split("\n");
|
|
232
|
-
const afterLines = after.split("\n");
|
|
233
|
-
const diff = computeDiff(beforeLines, afterLines);
|
|
234
|
-
|
|
235
|
-
const effectiveLayout = layout === "auto"
|
|
236
|
-
? (maxWidth >= 100 ? "split" : "unified")
|
|
237
|
-
: layout;
|
|
238
|
-
|
|
239
|
-
let effectiveIndicator = indicator;
|
|
240
|
-
// Auto mode: use classic indicator for unified to keep output clean
|
|
241
|
-
if (layout === "auto" && effectiveLayout === "unified" && indicator !== "nerd") {
|
|
242
|
-
effectiveIndicator = "classic";
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Apply syntax highlighting if enabled
|
|
246
|
-
let highlightedDiff = diff;
|
|
247
|
-
if (doHighlight) {
|
|
248
|
-
const lang = detectLanguage(opts?.filePath, after);
|
|
249
|
-
if (lang) {
|
|
250
|
-
highlightedDiff = diff.map((line) => ({
|
|
251
|
-
...line,
|
|
252
|
-
text: highlightLine(line.text, lang),
|
|
253
|
-
}));
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
if (effectiveLayout === "split") {
|
|
258
|
-
return renderSplit(highlightedDiff, effectiveIndicator, maxWidth);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return renderUnified(highlightedDiff, effectiveIndicator, maxWidth);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
export function renderEditDiffResult(
|
|
265
|
-
previousContent: string,
|
|
266
|
-
newContent: string,
|
|
267
|
-
opts?: { layout?: DiffLayout; indicator?: DiffIndicator; maxWidth?: number },
|
|
268
|
-
): string {
|
|
269
|
-
return renderDiff(previousContent, newContent, opts);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export function renderWriteDiffResult(
|
|
273
|
-
previousContent: string | undefined,
|
|
274
|
-
newContent: string,
|
|
275
|
-
opts?: { layout?: DiffLayout; indicator?: DiffIndicator; maxWidth?: number },
|
|
276
|
-
): string {
|
|
277
|
-
if (!previousContent) {
|
|
278
|
-
return "[New file created]\n" + newContent.split("\n").map((l) => "+ " + l).join("\n");
|
|
279
|
-
}
|
|
280
|
-
return renderDiff(previousContent, newContent, opts);
|
|
281
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Line width safety — width clamping with collapsed hints
|
|
3
|
-
*
|
|
4
|
-
* Uses ANSI-aware visibleWidth measurement from pi-tui to properly
|
|
5
|
-
* handle lines containing escape codes. Falls back to raw-length
|
|
6
|
-
* measurement when pi-tui is unavailable.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { visibleWidth, truncateToWidth } from "@earendil-works/pi-tui";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Clamp each line to maxWidth visible columns.
|
|
13
|
-
* Uses pi-tui's visibleWidth() for ANSI-aware measurement and
|
|
14
|
-
* truncateToWidth() for ANSI-safe truncation.
|
|
15
|
-
*/
|
|
16
|
-
export function clampLineWidth(lines: string[], maxWidth: number): string[] {
|
|
17
|
-
return lines.map((line) => {
|
|
18
|
-
const vw = visibleWidth(line);
|
|
19
|
-
if (vw <= maxWidth) return line;
|
|
20
|
-
return truncateToWidth(line, maxWidth, "…");
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function collapseHint(originalCount: number, shownCount: number): string {
|
|
25
|
-
const omitted = originalCount - shownCount;
|
|
26
|
-
if (omitted <= 0) return "";
|
|
27
|
-
return `...(${omitted} more lines)...`;
|
|
28
|
-
}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shared display rendering utilities
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export function splitLines(text: string): string[] {
|
|
6
|
-
return text.split(/\r?\n/);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function countNonEmptyLines(text: string): number {
|
|
10
|
-
return splitLines(text).filter((l) => l.trim()).length;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function compactOutputLines(text: string, maxLines: number): string {
|
|
14
|
-
const lines = splitLines(text);
|
|
15
|
-
if (lines.length <= maxLines) return text;
|
|
16
|
-
const omitted = lines.length - maxLines;
|
|
17
|
-
return `...(${omitted} lines omitted)...\n${lines.slice(-maxLines).join("\n")}`;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function previewLines(text: string, lines: number): string {
|
|
21
|
-
const all = splitLines(text);
|
|
22
|
-
if (all.length <= lines) return text;
|
|
23
|
-
return all.slice(0, lines).join("\n") + `\n...(${all.length - lines} more lines)`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function pluralize(count: number, singular: string, plural?: string): string {
|
|
27
|
-
return count === 1 ? `${count} ${singular}` : `${count} ${plural ?? singular + "s"}`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function shortenPath(path: string, maxLen: number = 60): string {
|
|
31
|
-
if (path.length <= maxLen) return path;
|
|
32
|
-
const parts = path.split("/");
|
|
33
|
-
if (parts.length <= 2) return "..." + path.slice(-(maxLen - 3));
|
|
34
|
-
return parts[0] + "/.../" + parts.slice(-2).join("/");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function extractTextOutput(result: any): string {
|
|
38
|
-
if (typeof result === "string") return result;
|
|
39
|
-
if (result?.output) return String(result.output);
|
|
40
|
-
if (result?.stdout) return String(result.stdout);
|
|
41
|
-
return "";
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function isLikelyQuietCommand(command: string): boolean {
|
|
45
|
-
const quietPatterns = [/^\s*cd\s/, /^\s*mkdir\s+-p/, /^\s*touch\s/, /^\s*rm\s+/];
|
|
46
|
-
return quietPatterns.some((re) => re.test(command));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export function sanitizeAnsiForThemedOutput(text: string): string {
|
|
50
|
-
// Strip ANSI escape sequences for clean themed rendering
|
|
51
|
-
return text.replace(/\x1b\[[0-9;]*m/g, "");
|
|
52
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thinking labels during streaming
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export function formatThinkingLabel(text: string, opts?: { prefix?: string }): string {
|
|
6
|
-
const prefix = opts?.prefix ?? "🤔";
|
|
7
|
-
const lines = text.split("\n");
|
|
8
|
-
if (lines.length === 1) return `${prefix} ${lines[0]}`;
|
|
9
|
-
return `${prefix} Thinking...\n${text}`;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function sanitizeThinkingArtifacts(text: string): string {
|
|
13
|
-
// Remove thinking blocks from context before LLM turn
|
|
14
|
-
return text
|
|
15
|
-
.replace(/<thinking>[\s\S]*?<\/thinking>/g, "")
|
|
16
|
-
.replace(/\[thinking\][\s\S]*?\[\/thinking\]/g, "")
|
|
17
|
-
.trim();
|
|
18
|
-
}
|