@aladac/hu 0.1.0-a1
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/.tool-versions +1 -0
- package/CLAUDE.md +122 -0
- package/HOOKS-DATA-INTEGRATION.md +457 -0
- package/SAMPLE.md +378 -0
- package/TODO.md +25 -0
- package/biome.json +51 -0
- package/commands/bootstrap.md +13 -0
- package/commands/c.md +1 -0
- package/commands/check-name.md +62 -0
- package/commands/disk.md +141 -0
- package/commands/docs/archive.md +27 -0
- package/commands/docs/check-internal.md +53 -0
- package/commands/docs/cleanup.md +65 -0
- package/commands/docs/consolidate.md +72 -0
- package/commands/docs/get.md +101 -0
- package/commands/docs/list.md +61 -0
- package/commands/docs/sync.md +64 -0
- package/commands/docs/update.md +49 -0
- package/commands/plans/clear.md +23 -0
- package/commands/plans/create.md +71 -0
- package/commands/plans/list.md +21 -0
- package/commands/plans/sync.md +38 -0
- package/commands/reinstall.md +20 -0
- package/commands/replicate.md +303 -0
- package/commands/warp.md +0 -0
- package/doc/README.md +35 -0
- package/doc/claude-code/capabilities.md +202 -0
- package/doc/claude-code/directory-structure.md +246 -0
- package/doc/claude-code/hooks.md +348 -0
- package/doc/claude-code/overview.md +109 -0
- package/doc/claude-code/plugins.md +273 -0
- package/doc/claude-code/sdk-protocols.md +202 -0
- package/document-manifest.toml +29 -0
- package/justfile +39 -0
- package/package.json +33 -0
- package/plans/compiled-watching-feather.md +217 -0
- package/plans/crispy-crafting-pnueli.md +103 -0
- package/plans/greedy-booping-coral.md +146 -0
- package/plans/imperative-sleeping-flamingo.md +192 -0
- package/plans/jaunty-sprouting-marble.md +171 -0
- package/plans/jiggly-discovering-lake.md +68 -0
- package/plans/magical-nibbling-spark.md +144 -0
- package/plans/mellow-kindling-acorn.md +110 -0
- package/plans/recursive-questing-engelbart.md +65 -0
- package/plans/serialized-roaming-kernighan.md +227 -0
- package/plans/structured-wondering-wirth.md +230 -0
- package/plans/vectorized-dreaming-iverson.md +191 -0
- package/plans/velvety-enchanting-ocean.md +92 -0
- package/plans/wiggly-sparking-pixel.md +48 -0
- package/plans/zippy-shimmying-fox.md +188 -0
- package/plugins/installed_plugins.json +4 -0
- package/sample-hooks.json +298 -0
- package/settings.json +24 -0
- package/settings.local.json +7 -0
- package/src/commands/bump.ts +130 -0
- package/src/commands/disk.ts +419 -0
- package/src/commands/docs.ts +729 -0
- package/src/commands/plans.ts +259 -0
- package/src/commands/utils.ts +299 -0
- package/src/index.ts +26 -0
- package/src/lib/colors.ts +87 -0
- package/src/lib/exec.ts +25 -0
- package/src/lib/fs.ts +119 -0
- package/src/lib/html.ts +205 -0
- package/src/lib/spinner.ts +42 -0
- package/src/types/index.ts +61 -0
- package/tests/lib/colors.test.ts +69 -0
- package/tests/lib/fs.test.ts +65 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +15 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# Plan: honbu data Subcommand for Claude Code Data Integration
|
|
2
|
+
|
|
3
|
+
Implements the `honbu data` command hierarchy to access Claude Code's local data stores, enabling hooks to query session transcripts, history, stats, todos, and file history.
|
|
4
|
+
|
|
5
|
+
## Phase 1: Core Data Access Commands
|
|
6
|
+
|
|
7
|
+
### Description
|
|
8
|
+
Implement read-only access to the primary data stores: sessions, history, and stats. These form the foundation for all subsequent queries.
|
|
9
|
+
|
|
10
|
+
### Steps
|
|
11
|
+
|
|
12
|
+
#### Step 1.1: Create data command module structure
|
|
13
|
+
- **Objective**: Set up the data subcommand with initial scaffolding
|
|
14
|
+
- **Files**: `src/commands/data.ts`
|
|
15
|
+
- **Dependencies**: None
|
|
16
|
+
- **Implementation**:
|
|
17
|
+
- Create `dataCommand` with subCommands structure
|
|
18
|
+
- Add placeholder subcommands: session, stats, history
|
|
19
|
+
- Register in `src/index.ts`
|
|
20
|
+
|
|
21
|
+
#### Step 1.2: Add data store path utilities
|
|
22
|
+
- **Objective**: Centralize paths to Claude Code data stores
|
|
23
|
+
- **Files**: `src/lib/fs.ts`
|
|
24
|
+
- **Dependencies**: Step 1.1
|
|
25
|
+
- **Implementation**:
|
|
26
|
+
- Add constants: `PROJECTS_DIR`, `HISTORY_FILE`, `STATS_FILE`, `TODOS_DIR`, `FILE_HISTORY_DIR`, `DEBUG_DIR`
|
|
27
|
+
- Add `encodeProjectPath(path)` function (mirrors Claude's encoding)
|
|
28
|
+
- Add `decodeProjectPath(encoded)` function
|
|
29
|
+
|
|
30
|
+
#### Step 1.3: Implement session list command
|
|
31
|
+
- **Objective**: List sessions with optional project filter
|
|
32
|
+
- **Files**: `src/commands/data.ts`
|
|
33
|
+
- **Dependencies**: Step 1.2
|
|
34
|
+
- **Implementation**:
|
|
35
|
+
- `honbu data session list [--project <path>] [--limit n] [--json]`
|
|
36
|
+
- Read projects/ directory structure
|
|
37
|
+
- Parse JSONL files to extract session metadata
|
|
38
|
+
- Display: sessionId, timestamp, messageCount, project
|
|
39
|
+
|
|
40
|
+
#### Step 1.4: Implement session read command
|
|
41
|
+
- **Objective**: Read and format a session transcript
|
|
42
|
+
- **Files**: `src/commands/data.ts`
|
|
43
|
+
- **Dependencies**: Step 1.3
|
|
44
|
+
- **Implementation**:
|
|
45
|
+
- `honbu data session read <id> [--format json|md]`
|
|
46
|
+
- Parse JSONL file, reconstruct message thread via parentUuid
|
|
47
|
+
- JSON: output raw messages
|
|
48
|
+
- Markdown: format as conversation with tool calls summarized
|
|
49
|
+
|
|
50
|
+
#### Step 1.5: Implement stats command
|
|
51
|
+
- **Objective**: Display usage statistics
|
|
52
|
+
- **Files**: `src/commands/data.ts`
|
|
53
|
+
- **Dependencies**: Step 1.2
|
|
54
|
+
- **Implementation**:
|
|
55
|
+
- `honbu data stats [--period <days>] [--json]`
|
|
56
|
+
- Read and parse stats-cache.json
|
|
57
|
+
- Display: totalSessions, totalMessages, modelUsage, dailyActivity
|
|
58
|
+
- Filter by period if specified
|
|
59
|
+
|
|
60
|
+
#### Step 1.6: Implement history command
|
|
61
|
+
- **Objective**: List and search session history
|
|
62
|
+
- **Files**: `src/commands/data.ts`
|
|
63
|
+
- **Dependencies**: Step 1.2
|
|
64
|
+
- **Implementation**:
|
|
65
|
+
- `honbu data history [--project <path>] [--limit n] [--json]`
|
|
66
|
+
- Read history.jsonl
|
|
67
|
+
- Filter by project if specified
|
|
68
|
+
- Display: timestamp, display (prompt preview), project
|
|
69
|
+
|
|
70
|
+
## Phase 2: Extended Data Access
|
|
71
|
+
|
|
72
|
+
### Description
|
|
73
|
+
Add commands for todos, file history, and the current session context.
|
|
74
|
+
|
|
75
|
+
### Steps
|
|
76
|
+
|
|
77
|
+
#### Step 2.1: Implement todos list command
|
|
78
|
+
- **Objective**: List todos across sessions
|
|
79
|
+
- **Files**: `src/commands/data.ts`
|
|
80
|
+
- **Dependencies**: Phase 1
|
|
81
|
+
- **Implementation**:
|
|
82
|
+
- `honbu data todos [--status <status>] [--session <id>] [--json]`
|
|
83
|
+
- Read todos/*.json files
|
|
84
|
+
- Filter by status (pending/in_progress/completed)
|
|
85
|
+
- Display: content, status, session association
|
|
86
|
+
|
|
87
|
+
#### Step 2.2: Implement todos pending command
|
|
88
|
+
- **Objective**: Show incomplete todos across all sessions
|
|
89
|
+
- **Files**: `src/commands/data.ts`
|
|
90
|
+
- **Dependencies**: Step 2.1
|
|
91
|
+
- **Implementation**:
|
|
92
|
+
- `honbu data todos pending [--project <path>] [--json]`
|
|
93
|
+
- Filter for status != "completed"
|
|
94
|
+
- Group by session or project
|
|
95
|
+
|
|
96
|
+
#### Step 2.3: Implement file-history list command
|
|
97
|
+
- **Objective**: List files modified in sessions
|
|
98
|
+
- **Files**: `src/commands/data.ts`
|
|
99
|
+
- **Dependencies**: Phase 1
|
|
100
|
+
- **Implementation**:
|
|
101
|
+
- `honbu data files [--session <id>] [--recent <days>] [--json]`
|
|
102
|
+
- Read file-history/{session}/ directories
|
|
103
|
+
- Extract file paths from hash-based names (requires reverse lookup)
|
|
104
|
+
- Display: file path, version count, last modified
|
|
105
|
+
|
|
106
|
+
#### Step 2.4: Implement session current command
|
|
107
|
+
- **Objective**: Get current session from environment
|
|
108
|
+
- **Files**: `src/commands/data.ts`
|
|
109
|
+
- **Dependencies**: Step 1.4
|
|
110
|
+
- **Implementation**:
|
|
111
|
+
- `honbu data session current`
|
|
112
|
+
- Read $SESSION_ID environment variable
|
|
113
|
+
- Output session info or error if not in session context
|
|
114
|
+
|
|
115
|
+
## Phase 3: Search and Query
|
|
116
|
+
|
|
117
|
+
### Description
|
|
118
|
+
Add full-text search across sessions and pattern analysis.
|
|
119
|
+
|
|
120
|
+
### Steps
|
|
121
|
+
|
|
122
|
+
#### Step 3.1: Implement session search command
|
|
123
|
+
- **Objective**: Search message content across sessions
|
|
124
|
+
- **Files**: `src/commands/data.ts`
|
|
125
|
+
- **Dependencies**: Phase 1
|
|
126
|
+
- **Implementation**:
|
|
127
|
+
- `honbu data search <query> [--limit n] [--json]`
|
|
128
|
+
- Scan JSONL files for matching content
|
|
129
|
+
- Return: sessionId, messageId, matched text snippet, timestamp
|
|
130
|
+
|
|
131
|
+
#### Step 3.2: Implement tools usage command
|
|
132
|
+
- **Objective**: Analyze tool usage patterns
|
|
133
|
+
- **Files**: `src/commands/data.ts`
|
|
134
|
+
- **Dependencies**: Phase 1
|
|
135
|
+
- **Implementation**:
|
|
136
|
+
- `honbu data tools [--tool <name>] [--session <id>] [--json]`
|
|
137
|
+
- Parse assistant messages for tool_use content blocks
|
|
138
|
+
- Aggregate: tool name, call count, common inputs
|
|
139
|
+
|
|
140
|
+
#### Step 3.3: Implement errors command
|
|
141
|
+
- **Objective**: Extract errors from debug logs
|
|
142
|
+
- **Files**: `src/commands/data.ts`
|
|
143
|
+
- **Dependencies**: Phase 1
|
|
144
|
+
- **Implementation**:
|
|
145
|
+
- `honbu data errors [--session <id>] [--recent <days>] [--json]`
|
|
146
|
+
- Parse debug/*.txt files for error patterns
|
|
147
|
+
- Display: timestamp, error message, session context
|
|
148
|
+
|
|
149
|
+
## Phase 4: JSONL Parsing Library
|
|
150
|
+
|
|
151
|
+
### Description
|
|
152
|
+
Create reusable parsing utilities for JSONL data stores.
|
|
153
|
+
|
|
154
|
+
### Steps
|
|
155
|
+
|
|
156
|
+
#### Step 4.1: Create JSONL parser module
|
|
157
|
+
- **Objective**: Efficient JSONL reading with streaming support
|
|
158
|
+
- **Files**: `src/lib/jsonl.ts`
|
|
159
|
+
- **Dependencies**: None
|
|
160
|
+
- **Implementation**:
|
|
161
|
+
- `parseJsonlFile(path)` - returns array of parsed objects
|
|
162
|
+
- `streamJsonlFile(path, callback)` - streaming parser for large files
|
|
163
|
+
- `appendJsonl(path, object)` - append single record
|
|
164
|
+
|
|
165
|
+
#### Step 4.2: Create session transcript parser
|
|
166
|
+
- **Objective**: Parse and thread session messages
|
|
167
|
+
- **Files**: `src/lib/transcript.ts`
|
|
168
|
+
- **Dependencies**: Step 4.1
|
|
169
|
+
- **Implementation**:
|
|
170
|
+
- `parseTranscript(path)` - parse JSONL to message array
|
|
171
|
+
- `threadMessages(messages)` - reconstruct conversation tree
|
|
172
|
+
- `extractToolCalls(message)` - extract tool usage from content
|
|
173
|
+
- `summarizeSession(messages)` - generate session summary
|
|
174
|
+
|
|
175
|
+
#### Step 4.3: Refactor data commands to use parsers
|
|
176
|
+
- **Objective**: Use new parsing utilities in data commands
|
|
177
|
+
- **Files**: `src/commands/data.ts`
|
|
178
|
+
- **Dependencies**: Steps 4.1, 4.2
|
|
179
|
+
- **Implementation**:
|
|
180
|
+
- Replace inline parsing with library calls
|
|
181
|
+
- Add error handling for malformed JSONL
|
|
182
|
+
- Optimize for large session files
|
|
183
|
+
|
|
184
|
+
## Verification
|
|
185
|
+
|
|
186
|
+
### Unit Tests
|
|
187
|
+
- Test JSONL parsing with sample data
|
|
188
|
+
- Test project path encoding/decoding
|
|
189
|
+
- Test message threading logic
|
|
190
|
+
|
|
191
|
+
### Integration Tests
|
|
192
|
+
```bash
|
|
193
|
+
# Phase 1 verification
|
|
194
|
+
honbu data session list
|
|
195
|
+
honbu data session list --project ~/.claude --json
|
|
196
|
+
honbu data session read <session-id>
|
|
197
|
+
honbu data stats
|
|
198
|
+
honbu data stats --period 7
|
|
199
|
+
honbu data history --limit 10
|
|
200
|
+
|
|
201
|
+
# Phase 2 verification
|
|
202
|
+
honbu data todos
|
|
203
|
+
honbu data todos pending
|
|
204
|
+
honbu data files --recent 1
|
|
205
|
+
|
|
206
|
+
# Phase 3 verification
|
|
207
|
+
honbu data search "error"
|
|
208
|
+
honbu data tools --tool Bash
|
|
209
|
+
honbu data errors --recent 7
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Hook Integration Test
|
|
213
|
+
```bash
|
|
214
|
+
# Test from a hook context
|
|
215
|
+
export SESSION_ID="test-session-id"
|
|
216
|
+
honbu data session current
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## Files Summary
|
|
220
|
+
|
|
221
|
+
| File | Action |
|
|
222
|
+
|------|--------|
|
|
223
|
+
| `src/commands/data.ts` | Create |
|
|
224
|
+
| `src/lib/fs.ts` | Modify (add paths) |
|
|
225
|
+
| `src/lib/jsonl.ts` | Create |
|
|
226
|
+
| `src/lib/transcript.ts` | Create |
|
|
227
|
+
| `src/index.ts` | Modify (register command) |
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# Internal AI Utility Interface Design
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Design an internal AI utility system leveraging existing Ollama/LM Studio connections for text processing tasks like:
|
|
5
|
+
- Extracting model settings from CivitAI HTML descriptions
|
|
6
|
+
- JSON correction/formatting
|
|
7
|
+
- Text organization utilities
|
|
8
|
+
|
|
9
|
+
## Current Infrastructure
|
|
10
|
+
|
|
11
|
+
### Existing Connections (from `src/prompts/extract/client.py`)
|
|
12
|
+
| Host | Backend | Endpoint | Purpose |
|
|
13
|
+
|------|---------|----------|---------|
|
|
14
|
+
| junkpile | Ollama | `192.168.0.26:11434` | Vision models (GGUF) |
|
|
15
|
+
| fuji | LM Studio | `localhost:1234` | Local dev (MLX) |
|
|
16
|
+
|
|
17
|
+
### Available Text Models
|
|
18
|
+
- `hermes3` - Structured output (Ollama)
|
|
19
|
+
- `huihui_ai/dolphin3-abliterated` - Text synthesis (Ollama)
|
|
20
|
+
- `dolphin-2.9-llama3-8b-mlx` - Text (LM Studio)
|
|
21
|
+
|
|
22
|
+
### Existing Pattern
|
|
23
|
+
- `VisionClient` class wraps OpenAI SDK
|
|
24
|
+
- Auto-detects backend from port
|
|
25
|
+
- Environment variables: `OPENAPI_HOST`, `OPENAPI_BACKEND`
|
|
26
|
+
|
|
27
|
+
## Design
|
|
28
|
+
|
|
29
|
+
### Architecture Overview
|
|
30
|
+
|
|
31
|
+
Reuse `VisionClient` from `src/prompts/extract/client.py` since it already supports text-only generation via `_generate_text()`. Create a thin wrapper with task-specific processors.
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
src/prompts/ai/
|
|
35
|
+
├── __init__.py # Exports AIClient, processors
|
|
36
|
+
├── client.py # AIClient wrapping VisionClient for text tasks
|
|
37
|
+
├── processors.py # SettingsExtractor, JSONFixer, TextTransformer
|
|
38
|
+
└── cli.py # CLI commands: prompts ai extract-settings, fix-json
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Default Model Selection
|
|
42
|
+
|
|
43
|
+
| Host | Default Model | Reason |
|
|
44
|
+
|------|---------------|--------|
|
|
45
|
+
| junkpile (Ollama) | `hermes3` | Structured output, good at extraction |
|
|
46
|
+
| fuji (LM Studio) | `dolphin-2.9-llama3-8b-mlx` | MLX optimized |
|
|
47
|
+
|
|
48
|
+
### AIClient Class
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# src/prompts/ai/client.py
|
|
52
|
+
from prompts.extract.client import VisionClient
|
|
53
|
+
|
|
54
|
+
DEFAULT_MODEL = "hermes3" # Best for structured extraction
|
|
55
|
+
|
|
56
|
+
class AIClient:
|
|
57
|
+
"""AI utility client for text processing tasks."""
|
|
58
|
+
|
|
59
|
+
def __init__(self, host=None, model=None):
|
|
60
|
+
self._vision = VisionClient(host=host)
|
|
61
|
+
self.model = model or DEFAULT_MODEL
|
|
62
|
+
|
|
63
|
+
def generate(self, prompt: str, system: str = None) -> str:
|
|
64
|
+
"""Generate text response."""
|
|
65
|
+
full_prompt = f"{system}\n\n{prompt}" if system else prompt
|
|
66
|
+
return self._vision._generate_text(self.model, full_prompt)
|
|
67
|
+
|
|
68
|
+
def extract_settings(self, html: str) -> ModelSettings:
|
|
69
|
+
"""Extract SD settings from HTML description."""
|
|
70
|
+
return SettingsExtractor(self).extract(html)
|
|
71
|
+
|
|
72
|
+
def fix_json(self, broken_json: str) -> str:
|
|
73
|
+
"""Fix malformed JSON."""
|
|
74
|
+
return JSONFixer(self).fix(broken_json)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Processors
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# src/prompts/ai/processors.py
|
|
81
|
+
from pydantic import BaseModel
|
|
82
|
+
from typing import Optional
|
|
83
|
+
|
|
84
|
+
class ModelSettings(BaseModel):
|
|
85
|
+
"""Extracted SD model settings."""
|
|
86
|
+
sampler: Optional[str] = None
|
|
87
|
+
scheduler: Optional[str] = None
|
|
88
|
+
steps: Optional[str] = None # Can be range like "20-35"
|
|
89
|
+
cfg_scale: Optional[str] = None # Can be range like "1-2"
|
|
90
|
+
clip_skip: Optional[int] = None
|
|
91
|
+
vae: Optional[str] = None
|
|
92
|
+
notes: Optional[str] = None
|
|
93
|
+
|
|
94
|
+
SETTINGS_SYSTEM_PROMPT = """Extract Stable Diffusion generation settings from the HTML description.
|
|
95
|
+
Return ONLY valid JSON matching this schema:
|
|
96
|
+
{
|
|
97
|
+
"sampler": "sampler name or null",
|
|
98
|
+
"scheduler": "scheduler name or null",
|
|
99
|
+
"steps": "step count or range like '20-35' or null",
|
|
100
|
+
"cfg_scale": "CFG value or range like '1-2' or null",
|
|
101
|
+
"clip_skip": clip skip number or null,
|
|
102
|
+
"vae": "VAE name or null",
|
|
103
|
+
"notes": "any other relevant settings notes or null"
|
|
104
|
+
}
|
|
105
|
+
Do not include any other text, only the JSON object."""
|
|
106
|
+
|
|
107
|
+
class SettingsExtractor:
|
|
108
|
+
def __init__(self, client):
|
|
109
|
+
self.client = client
|
|
110
|
+
|
|
111
|
+
def extract(self, html: str) -> ModelSettings:
|
|
112
|
+
response = self.client.generate(
|
|
113
|
+
prompt=f"Extract settings from:\n\n{html}",
|
|
114
|
+
system=SETTINGS_SYSTEM_PROMPT
|
|
115
|
+
)
|
|
116
|
+
# Parse JSON response into ModelSettings
|
|
117
|
+
import json
|
|
118
|
+
data = json.loads(response)
|
|
119
|
+
return ModelSettings(**data)
|
|
120
|
+
|
|
121
|
+
JSON_FIX_PROMPT = """Fix the following malformed JSON and return ONLY the corrected JSON.
|
|
122
|
+
Do not explain, just output valid JSON."""
|
|
123
|
+
|
|
124
|
+
class JSONFixer:
|
|
125
|
+
def __init__(self, client):
|
|
126
|
+
self.client = client
|
|
127
|
+
|
|
128
|
+
def fix(self, broken: str) -> str:
|
|
129
|
+
return self.client.generate(
|
|
130
|
+
prompt=f"Fix this JSON:\n\n{broken}",
|
|
131
|
+
system=JSON_FIX_PROMPT
|
|
132
|
+
)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### CLI Commands
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
# src/prompts/ai/cli.py
|
|
139
|
+
import click
|
|
140
|
+
from .client import AIClient
|
|
141
|
+
|
|
142
|
+
@click.group()
|
|
143
|
+
def ai():
|
|
144
|
+
"""AI-powered text utilities."""
|
|
145
|
+
pass
|
|
146
|
+
|
|
147
|
+
@ai.command("extract-settings")
|
|
148
|
+
@click.argument("model_id", type=int)
|
|
149
|
+
@click.option("--host", help="AI backend host")
|
|
150
|
+
def extract_settings(model_id: int, host: str):
|
|
151
|
+
"""Extract SD settings from CivitAI model description."""
|
|
152
|
+
from prompts.civitai.cache import get_cached_model
|
|
153
|
+
|
|
154
|
+
cached = get_cached_model(model_id)
|
|
155
|
+
if not cached:
|
|
156
|
+
click.echo(f"Model {model_id} not in cache. Run: prompts models info {model_id}")
|
|
157
|
+
return
|
|
158
|
+
|
|
159
|
+
html = cached.get("description", "")
|
|
160
|
+
client = AIClient(host=host)
|
|
161
|
+
settings = client.extract_settings(html)
|
|
162
|
+
|
|
163
|
+
click.echo(settings.model_dump_json(indent=2))
|
|
164
|
+
|
|
165
|
+
@ai.command("fix-json")
|
|
166
|
+
@click.argument("file", type=click.Path(exists=True))
|
|
167
|
+
@click.option("--output", "-o", help="Output file (default: stdout)")
|
|
168
|
+
def fix_json(file: str, output: str):
|
|
169
|
+
"""Fix malformed JSON file."""
|
|
170
|
+
from pathlib import Path
|
|
171
|
+
|
|
172
|
+
broken = Path(file).read_text()
|
|
173
|
+
client = AIClient()
|
|
174
|
+
fixed = client.fix_json(broken)
|
|
175
|
+
|
|
176
|
+
if output:
|
|
177
|
+
Path(output).write_text(fixed)
|
|
178
|
+
click.echo(f"Fixed JSON written to {output}")
|
|
179
|
+
else:
|
|
180
|
+
click.echo(fixed)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Integration with Scene Generation
|
|
184
|
+
|
|
185
|
+
Update `prompts scenes json` to auto-extract settings:
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# In scenes/cli.py
|
|
189
|
+
@scenes.command("json")
|
|
190
|
+
@click.option("--auto-settings", is_flag=True, help="Extract settings from CivitAI")
|
|
191
|
+
def generate_json(..., auto_settings: bool):
|
|
192
|
+
if auto_settings and model_id:
|
|
193
|
+
from prompts.ai.client import AIClient
|
|
194
|
+
client = AIClient()
|
|
195
|
+
# Get cached model description
|
|
196
|
+
settings = client.extract_settings(html)
|
|
197
|
+
# Apply to scene
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Files to Create/Modify
|
|
201
|
+
|
|
202
|
+
| File | Action |
|
|
203
|
+
|------|--------|
|
|
204
|
+
| `src/prompts/ai/__init__.py` | Create |
|
|
205
|
+
| `src/prompts/ai/client.py` | Create |
|
|
206
|
+
| `src/prompts/ai/processors.py` | Create |
|
|
207
|
+
| `src/prompts/ai/cli.py` | Create |
|
|
208
|
+
| `src/prompts/cli.py` | Add `ai` group import |
|
|
209
|
+
|
|
210
|
+
## Verification
|
|
211
|
+
|
|
212
|
+
1. **Test extraction**:
|
|
213
|
+
```bash
|
|
214
|
+
# First cache a model
|
|
215
|
+
uv run prompts models info 1836956
|
|
216
|
+
|
|
217
|
+
# Then extract settings
|
|
218
|
+
uv run prompts ai extract-settings 1836956
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
2. **Test JSON fixing**:
|
|
222
|
+
```bash
|
|
223
|
+
echo '{"broken: json}' > /tmp/broken.json
|
|
224
|
+
uv run prompts ai fix-json /tmp/broken.json
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
3. **Verify hermes3 is available**:
|
|
228
|
+
```bash
|
|
229
|
+
curl http://192.168.0.26:11434/api/tags | jq '.models[].name'
|
|
230
|
+
```
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Refactor: Internal Model ID as Primary Key
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Make the 8-character internal ID the primary key for all model operations. All commands that operate on a single model will use `-m/--model-id` accepting our internal ID format.
|
|
6
|
+
|
|
7
|
+
## Key Design Decisions
|
|
8
|
+
|
|
9
|
+
1. **Internal ID is primary** - All lookups start with internal 8-char ID
|
|
10
|
+
2. **CivitAI IDs retained** - Stored as `civitai_id` field, used for API calls
|
|
11
|
+
3. **Unified lookup function** - New `resolve_model()` function handles ID resolution
|
|
12
|
+
4. **Consistent CLI pattern** - All single-model commands use `-m MODEL_ID` or `--model-id MODEL_ID`
|
|
13
|
+
|
|
14
|
+
## Files to Modify
|
|
15
|
+
|
|
16
|
+
### 1. `src/prompts/models/cache.py` - Add Unified Lookup
|
|
17
|
+
|
|
18
|
+
Add a `resolve()` method to `ModelCache` that accepts flexible input:
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
def resolve(self, identifier: str) -> Optional[CachedModel]:
|
|
22
|
+
"""Resolve a model by internal ID (primary), name, or CivitAI ID.
|
|
23
|
+
|
|
24
|
+
Lookup order:
|
|
25
|
+
1. Exact internal ID match (8-char)
|
|
26
|
+
2. CivitAI ID (if numeric)
|
|
27
|
+
3. Name partial match (fallback)
|
|
28
|
+
"""
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### 2. `src/prompts/models/cli.py` - Standardize Commands
|
|
32
|
+
|
|
33
|
+
| Command | Current | New |
|
|
34
|
+
|---------|---------|-----|
|
|
35
|
+
| `models info` | `@click.argument("name_or_id")` | `@click.option("-m", "--model-id")` |
|
|
36
|
+
| `models set` | `@click.argument("model_id")` | `@click.option("-m", "--model-id", required=True)` |
|
|
37
|
+
| `models show` | `@click.argument("model_id")` | `@click.option("-m", "--model-id", required=True)` |
|
|
38
|
+
| `models cache clear` | `@click.argument("model_id", type=int)` | `@click.option("-m", "--model-id")` |
|
|
39
|
+
|
|
40
|
+
### 3. `src/prompts/civitai/cli.py` - Update CivitAI Commands
|
|
41
|
+
|
|
42
|
+
| Command | Current | New |
|
|
43
|
+
|---------|---------|-----|
|
|
44
|
+
| `civitai prompts` | `@click.argument("model_id", type=int)` | `@click.option("-m", "--model-id", required=True)` |
|
|
45
|
+
| `civitai images` | `@click.argument("model_id", type=int)` | `@click.option("-m", "--model-id", required=True)` |
|
|
46
|
+
|
|
47
|
+
These commands need to:
|
|
48
|
+
1. Accept internal ID
|
|
49
|
+
2. Resolve to CachedModel
|
|
50
|
+
3. Use `civitai_id` for API calls
|
|
51
|
+
|
|
52
|
+
### 4. `src/prompts/ai/cli.py` - Update AI Commands
|
|
53
|
+
|
|
54
|
+
| Command | Current | New |
|
|
55
|
+
|---------|---------|-----|
|
|
56
|
+
| `ai extract-settings` | `@click.argument("model_id", type=int)` | `@click.option("-m", "--model-id", required=True)` |
|
|
57
|
+
|
|
58
|
+
### 5. `src/prompts/scenes/cli.py` - Update Scene Commands
|
|
59
|
+
|
|
60
|
+
| Command | Current | New |
|
|
61
|
+
|---------|---------|-----|
|
|
62
|
+
| `scenes json` | `--model-id/-m type=int` | `--model-id/-m` (string, internal ID) |
|
|
63
|
+
| `scenes list` | `--model/-m` | `--model-id/-m` (for consistency) |
|
|
64
|
+
|
|
65
|
+
## Implementation Steps
|
|
66
|
+
|
|
67
|
+
### Step 1: Add `resolve()` to ModelCache
|
|
68
|
+
|
|
69
|
+
Location: `src/prompts/models/cache.py`
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
def resolve(self, identifier: str) -> Optional[CachedModel]:
|
|
73
|
+
"""Resolve model by internal ID, CivitAI ID, or name."""
|
|
74
|
+
# 1. Try exact internal ID (case-insensitive)
|
|
75
|
+
model = self.get(identifier.upper())
|
|
76
|
+
if model:
|
|
77
|
+
return model
|
|
78
|
+
|
|
79
|
+
# 2. Try CivitAI ID if numeric
|
|
80
|
+
try:
|
|
81
|
+
civitai_id = int(identifier)
|
|
82
|
+
model = self.get_by_civitai_id(civitai_id)
|
|
83
|
+
if model:
|
|
84
|
+
return model
|
|
85
|
+
except ValueError:
|
|
86
|
+
pass
|
|
87
|
+
|
|
88
|
+
# 3. Try name partial match
|
|
89
|
+
identifier_lower = identifier.lower()
|
|
90
|
+
for model in self._models.values():
|
|
91
|
+
if identifier_lower in model.name.lower():
|
|
92
|
+
return model
|
|
93
|
+
|
|
94
|
+
return None
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Step 2: Update `models` CLI Commands
|
|
98
|
+
|
|
99
|
+
File: `src/prompts/models/cli.py`
|
|
100
|
+
|
|
101
|
+
**`models info`** (line 582):
|
|
102
|
+
- Change from `@click.argument("name_or_id")` to `@click.option("-m", "--model-id", required=True)`
|
|
103
|
+
- Use `cache.resolve(model_id)` for lookup
|
|
104
|
+
- If model has `civitai_id`, fetch from CivitAI API
|
|
105
|
+
|
|
106
|
+
**`models set`** (line 1021):
|
|
107
|
+
- Change from `@click.argument("model_id")` to `@click.option("-m", "--model-id", required=True)`
|
|
108
|
+
- Use `cache.resolve(model_id)`
|
|
109
|
+
|
|
110
|
+
**`models show`** (line 1091):
|
|
111
|
+
- Change from `@click.argument("model_id")` to `@click.option("-m", "--model-id", required=True)`
|
|
112
|
+
- Use `cache.resolve(model_id)`
|
|
113
|
+
|
|
114
|
+
**`models cache clear`** (line 964):
|
|
115
|
+
- Change from `@click.argument("model_id", type=int)` to `@click.option("-m", "--model-id")`
|
|
116
|
+
- Resolve internal ID to get `civitai_id` for cache clear
|
|
117
|
+
|
|
118
|
+
### Step 3: Update `civitai` CLI Commands
|
|
119
|
+
|
|
120
|
+
File: `src/prompts/civitai/cli.py`
|
|
121
|
+
|
|
122
|
+
**`civitai prompts`** (line 270):
|
|
123
|
+
```python
|
|
124
|
+
@civitai.command("prompts")
|
|
125
|
+
@click.option("-m", "--model-id", required=True, help="Model ID (internal or CivitAI)")
|
|
126
|
+
def get_prompts(model_id: str, ...):
|
|
127
|
+
cache = get_cache()
|
|
128
|
+
model = cache.resolve(model_id)
|
|
129
|
+
if not model or not model.civitai_id:
|
|
130
|
+
console.print(f"[red]Model not found or has no CivitAI ID[/red]")
|
|
131
|
+
return
|
|
132
|
+
# Use model.civitai_id for API call
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**`civitai images`** (line 304):
|
|
136
|
+
- Same pattern as above
|
|
137
|
+
|
|
138
|
+
### Step 4: Update `ai` CLI Commands
|
|
139
|
+
|
|
140
|
+
File: `src/prompts/ai/cli.py`
|
|
141
|
+
|
|
142
|
+
**`ai extract-settings`** (line 20):
|
|
143
|
+
- Change from `@click.argument("model_id", type=int)` to `@click.option("-m", "--model-id", required=True)`
|
|
144
|
+
- Resolve internal ID, use `civitai_id` for cache lookup
|
|
145
|
+
|
|
146
|
+
### Step 5: Update `scenes` CLI Commands
|
|
147
|
+
|
|
148
|
+
File: `src/prompts/scenes/cli.py`
|
|
149
|
+
|
|
150
|
+
**`scenes json`** (line 413):
|
|
151
|
+
- Change `type=int` to string
|
|
152
|
+
- Resolve internal ID to get model file path
|
|
153
|
+
|
|
154
|
+
**`scenes list`** (line 227):
|
|
155
|
+
- Rename `--model` to `--model-id` for consistency
|
|
156
|
+
- Keep existing filter logic (base model matching)
|
|
157
|
+
|
|
158
|
+
## Verification
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
# Test internal ID lookup
|
|
162
|
+
uv run prompts models show -m C1GVKMA9
|
|
163
|
+
|
|
164
|
+
# Test CivitAI ID fallback
|
|
165
|
+
uv run prompts models show -m 827184
|
|
166
|
+
|
|
167
|
+
# Test name fallback
|
|
168
|
+
uv run prompts models show -m "WAI"
|
|
169
|
+
|
|
170
|
+
# Test civitai commands with internal ID
|
|
171
|
+
uv run prompts civitai prompts -m C1GVKMA9
|
|
172
|
+
|
|
173
|
+
# Test scenes with internal ID
|
|
174
|
+
uv run prompts scenes json wc-r01 -m C1GVKMA9
|
|
175
|
+
|
|
176
|
+
# Test set command
|
|
177
|
+
uv run prompts models set -m C1GVKMA9 --favorite
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## Error Messages
|
|
181
|
+
|
|
182
|
+
When model not found:
|
|
183
|
+
```
|
|
184
|
+
Model 'XYZ' not found.
|
|
185
|
+
Use 'prompts models list' to see available models and their IDs.
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
When CivitAI ID required but not available:
|
|
189
|
+
```
|
|
190
|
+
Model 'XYZ' has no CivitAI ID. This command requires a model from CivitAI.
|
|
191
|
+
```
|