@upgraide/ui-notes-cli 0.2.4 → 0.2.6
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/README.md +111 -37
- package/commands/doctor.ts +106 -0
- package/commands/update.ts +81 -0
- package/index.ts +16 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,44 +31,32 @@ uinotes resolve 42 "Fixed in latest deploy"
|
|
|
31
31
|
View or update configuration.
|
|
32
32
|
|
|
33
33
|
```bash
|
|
34
|
-
# Show current config
|
|
35
|
-
uinotes config
|
|
36
|
-
|
|
37
|
-
# Set a value
|
|
34
|
+
uinotes config # Show current config
|
|
38
35
|
uinotes config set apiUrl https://my-api.example.com
|
|
36
|
+
uinotes config set apiKey <your-key>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### `uinotes set project`
|
|
40
|
+
|
|
41
|
+
Bind a project to the current directory (creates `.uinotes` file).
|
|
39
42
|
|
|
40
|
-
|
|
43
|
+
```bash
|
|
41
44
|
uinotes set project my-app
|
|
42
45
|
```
|
|
43
46
|
|
|
44
|
-
**Config keys:** `apiUrl`, `apiKey`
|
|
45
|
-
|
|
46
47
|
### `uinotes projects`
|
|
47
48
|
|
|
48
49
|
Manage projects.
|
|
49
50
|
|
|
50
51
|
```bash
|
|
51
|
-
# List all projects
|
|
52
|
-
uinotes projects
|
|
53
|
-
|
|
54
|
-
# Include archived projects
|
|
55
|
-
uinotes projects --archived
|
|
56
|
-
|
|
57
|
-
# Create a project with URL patterns
|
|
58
|
-
uinotes projects create my-app "My Application" --url "https://myapp.com/*"
|
|
59
|
-
|
|
60
|
-
# Get project details
|
|
52
|
+
uinotes projects # List all projects
|
|
53
|
+
uinotes projects --archived # Include archived
|
|
54
|
+
uinotes projects create my-app "My App" --url "https://myapp.com/*"
|
|
61
55
|
uinotes projects get my-app
|
|
62
|
-
|
|
63
|
-
# Rename a project
|
|
64
56
|
uinotes projects rename my-app "New Name"
|
|
65
|
-
|
|
66
|
-
# Add/remove URL patterns
|
|
67
57
|
uinotes projects add-url my-app "https://staging.myapp.com/*"
|
|
68
58
|
uinotes projects remove-url my-app "https://old.myapp.com/*"
|
|
69
|
-
|
|
70
|
-
# Archive a project
|
|
71
|
-
uinotes projects delete my-app
|
|
59
|
+
uinotes projects delete my-app # Archive
|
|
72
60
|
```
|
|
73
61
|
|
|
74
62
|
### `uinotes pull`
|
|
@@ -78,31 +66,117 @@ Fetch notes from the API.
|
|
|
78
66
|
```bash
|
|
79
67
|
uinotes pull
|
|
80
68
|
uinotes pull --project my-app --status open --type bug --limit 50
|
|
69
|
+
uinotes pull --resolve-files --root-dir . # Map notes to source files
|
|
81
70
|
```
|
|
82
71
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
### `uinotes context`
|
|
73
|
+
|
|
74
|
+
AI-optimized digest of open notes.
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
uinotes context --project my-app
|
|
78
|
+
uinotes context --format xml --component Header
|
|
79
|
+
uinotes context --resolve-files --root-dir .
|
|
80
|
+
```
|
|
89
81
|
|
|
90
|
-
### `uinotes
|
|
82
|
+
### `uinotes explain`
|
|
91
83
|
|
|
92
|
-
|
|
84
|
+
Full context for a single note (body, comments, history, visual diffs).
|
|
93
85
|
|
|
94
86
|
```bash
|
|
95
|
-
uinotes
|
|
96
|
-
uinotes
|
|
87
|
+
uinotes explain <note-id>
|
|
88
|
+
uinotes explain <note-id> --format json
|
|
97
89
|
```
|
|
98
90
|
|
|
99
|
-
### `uinotes wontfix`
|
|
91
|
+
### `uinotes resolve` / `uinotes wontfix`
|
|
100
92
|
|
|
101
|
-
Mark a note as won't fix.
|
|
93
|
+
Mark a note as resolved or won't fix.
|
|
102
94
|
|
|
103
95
|
```bash
|
|
96
|
+
uinotes resolve <id> [message]
|
|
104
97
|
uinotes wontfix <id> [message]
|
|
105
|
-
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### `uinotes comment` / `uinotes comments`
|
|
101
|
+
|
|
102
|
+
Add or list comments on a note.
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uinotes comment <id> "Comment text"
|
|
106
|
+
uinotes comments <id>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### `uinotes resolve-by-component` / `uinotes resolve-by-selector`
|
|
110
|
+
|
|
111
|
+
Bulk resolve notes matching a component or selector.
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
uinotes resolve-by-component OldWidget "Replaced with NewWidget"
|
|
115
|
+
uinotes resolve-by-selector ".deprecated" "Removed" --dry-run
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### `uinotes changelog`
|
|
119
|
+
|
|
120
|
+
Generate a changelog from resolved notes.
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
uinotes changelog --since HEAD~5
|
|
124
|
+
uinotes changelog --since v1.2.0 --format conventional
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### `uinotes visual-diff`
|
|
128
|
+
|
|
129
|
+
Capture and compare page screenshots.
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
uinotes visual-diff --project my-app
|
|
133
|
+
uinotes visual-diff --compare --width 1440
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### `uinotes batch`
|
|
137
|
+
|
|
138
|
+
Execute NDJSON batch operations.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
echo '{"op":"resolve","id":"abc","message":"Fixed"}' | uinotes batch -
|
|
142
|
+
uinotes batch ops.ndjson --dry-run --concurrency 10
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### `uinotes schema`
|
|
146
|
+
|
|
147
|
+
List or print API resource schemas.
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
uinotes schema
|
|
151
|
+
uinotes schema --resource notes
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `uinotes install-skills`
|
|
155
|
+
|
|
156
|
+
Install Claude Code skill files into `.claude/skills/`.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
uinotes install-skills
|
|
160
|
+
uinotes install-skills --dir /path/to/project/.claude/skills
|
|
161
|
+
uinotes install-skills --check
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### `uinotes doctor`
|
|
165
|
+
|
|
166
|
+
Check CLI configuration, API connectivity, and version.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
uinotes doctor
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Checks: config file, API URL, API key, API reachability, project binding, skills installed, CLI version.
|
|
173
|
+
|
|
174
|
+
### `uinotes update`
|
|
175
|
+
|
|
176
|
+
Check for and install CLI updates.
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
uinotes update
|
|
106
180
|
```
|
|
107
181
|
|
|
108
182
|
## Configuration
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
import { getConfig, getConfigPath } from '../config.js';
|
|
5
|
+
|
|
6
|
+
const PACKAGE_NAME = '@upgraide/ui-notes-cli';
|
|
7
|
+
|
|
8
|
+
const PASS = '\x1b[32m✓\x1b[0m';
|
|
9
|
+
const FAIL = '\x1b[31m✗\x1b[0m';
|
|
10
|
+
const WARN = '\x1b[33m!\x1b[0m';
|
|
11
|
+
|
|
12
|
+
function check(ok: boolean, label: string, detail?: string): boolean {
|
|
13
|
+
const icon = ok ? PASS : FAIL;
|
|
14
|
+
console.log(` ${icon} ${label}${detail ? ` ${detail}` : ''}`);
|
|
15
|
+
return ok;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function warn(label: string, detail?: string): void {
|
|
19
|
+
console.log(` ${WARN} ${label}${detail ? ` ${detail}` : ''}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function doctor(): Promise<void> {
|
|
23
|
+
console.log('uinotes doctor\n');
|
|
24
|
+
let issues = 0;
|
|
25
|
+
|
|
26
|
+
// 1. Config file
|
|
27
|
+
const globalPath = join(homedir(), '.uinotes.json');
|
|
28
|
+
const localPath = join(process.cwd(), '.uinotes.json');
|
|
29
|
+
const hasGlobal = existsSync(globalPath);
|
|
30
|
+
const hasLocal = existsSync(localPath);
|
|
31
|
+
const configExists = hasGlobal || hasLocal;
|
|
32
|
+
if (!check(configExists, 'Config file', configExists ? `(${getConfigPath()})` : 'not found')) {
|
|
33
|
+
issues++;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 2. API URL
|
|
37
|
+
const config = getConfig();
|
|
38
|
+
const hasUrl = !!config.apiUrl;
|
|
39
|
+
if (!check(hasUrl, 'API URL', hasUrl ? config.apiUrl : 'not set')) {
|
|
40
|
+
issues++;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 3. API key
|
|
44
|
+
const hasKey = !!config.apiKey;
|
|
45
|
+
if (!check(hasKey, 'API key', hasKey ? 'configured' : 'not set — run: uinotes config set apiKey <key>')) {
|
|
46
|
+
issues++;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 4. API reachability
|
|
50
|
+
if (hasUrl && hasKey) {
|
|
51
|
+
try {
|
|
52
|
+
const res = await fetch(`${config.apiUrl}/api/projects`, {
|
|
53
|
+
headers: { 'x-api-key': config.apiKey },
|
|
54
|
+
});
|
|
55
|
+
if (!check(res.ok, 'API reachable', `HTTP ${res.status}`)) {
|
|
56
|
+
issues++;
|
|
57
|
+
}
|
|
58
|
+
} catch (err: any) {
|
|
59
|
+
check(false, 'API reachable', err.message);
|
|
60
|
+
issues++;
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
warn('API reachable', 'skipped (no API key)');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 5. Project binding
|
|
67
|
+
const hasProject = !!config.project;
|
|
68
|
+
if (!check(hasProject, 'Project bound', hasProject ? config.project : 'none — run: uinotes set project <slug>')) {
|
|
69
|
+
issues++;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 6. Skills installed
|
|
73
|
+
const skillPath = join(process.cwd(), '.claude', 'skills', 'ui-notes', 'SKILL.md');
|
|
74
|
+
const skillsInstalled = existsSync(skillPath);
|
|
75
|
+
if (!check(skillsInstalled, 'Skills installed', skillsInstalled ? skillPath : 'not found — run: uinotes install-skills')) {
|
|
76
|
+
issues++;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// 7. CLI version
|
|
80
|
+
const pkgPath = join(import.meta.dir, '..', 'package.json');
|
|
81
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
82
|
+
const currentVersion = pkg.version as string;
|
|
83
|
+
try {
|
|
84
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
|
|
85
|
+
if (res.ok) {
|
|
86
|
+
const data = await res.json() as { version: string };
|
|
87
|
+
const latest = data.version;
|
|
88
|
+
const upToDate = currentVersion === latest;
|
|
89
|
+
if (!check(upToDate, 'CLI version', upToDate ? `${currentVersion} (latest)` : `${currentVersion} → ${latest} available — run: uinotes update`)) {
|
|
90
|
+
issues++;
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
warn('CLI version', `${currentVersion} (could not check registry)`);
|
|
94
|
+
}
|
|
95
|
+
} catch {
|
|
96
|
+
warn('CLI version', `${currentVersion} (could not reach registry)`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Summary
|
|
100
|
+
console.log('');
|
|
101
|
+
if (issues === 0) {
|
|
102
|
+
console.log('All checks passed.');
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`${issues} issue${issues > 1 ? 's' : ''} found.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
|
|
4
|
+
const PACKAGE_NAME = '@upgraide/ui-notes-cli';
|
|
5
|
+
|
|
6
|
+
function parseVersion(v: string): number[] {
|
|
7
|
+
return v.replace(/^v/, '').split('.').map(Number);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function isNewer(latest: number[], current: number[]): boolean {
|
|
11
|
+
for (let i = 0; i < Math.max(latest.length, current.length); i++) {
|
|
12
|
+
const a = latest[i] ?? 0;
|
|
13
|
+
const b = current[i] ?? 0;
|
|
14
|
+
if (a > b) return true;
|
|
15
|
+
if (a < b) return false;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function detectPackageManager(): Promise<'bun' | 'npm'> {
|
|
21
|
+
try {
|
|
22
|
+
const proc = Bun.spawn(['bun', '--version'], { stdout: 'pipe', stderr: 'pipe' });
|
|
23
|
+
await proc.exited;
|
|
24
|
+
if (proc.exitCode === 0) return 'bun';
|
|
25
|
+
} catch {}
|
|
26
|
+
return 'npm';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function update(): Promise<void> {
|
|
30
|
+
// Read current version
|
|
31
|
+
const pkgPath = join(import.meta.dir, '..', 'package.json');
|
|
32
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
33
|
+
const currentVersion = pkg.version as string;
|
|
34
|
+
|
|
35
|
+
console.log(`Current version: ${currentVersion}`);
|
|
36
|
+
console.log('Checking for updates...');
|
|
37
|
+
|
|
38
|
+
// Fetch latest from npm registry
|
|
39
|
+
let latestVersion: string;
|
|
40
|
+
try {
|
|
41
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`);
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
console.error(`Failed to check registry (HTTP ${res.status})`);
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
const data = await res.json() as { version: string };
|
|
47
|
+
latestVersion = data.version;
|
|
48
|
+
} catch (err: any) {
|
|
49
|
+
console.error(`Failed to reach npm registry: ${err.message}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const current = parseVersion(currentVersion);
|
|
54
|
+
const latest = parseVersion(latestVersion);
|
|
55
|
+
|
|
56
|
+
if (!isNewer(latest, current)) {
|
|
57
|
+
console.log(`Already up to date (${currentVersion})`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
console.log(`New version available: ${latestVersion}`);
|
|
62
|
+
|
|
63
|
+
const pm = await detectPackageManager();
|
|
64
|
+
const cmd = pm === 'bun'
|
|
65
|
+
? ['bun', 'add', '-g', PACKAGE_NAME]
|
|
66
|
+
: ['npm', 'install', '-g', PACKAGE_NAME];
|
|
67
|
+
|
|
68
|
+
console.log(`Installing with ${pm}...`);
|
|
69
|
+
const proc = Bun.spawn(cmd, {
|
|
70
|
+
stdout: 'inherit',
|
|
71
|
+
stderr: 'inherit',
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const exitCode = await proc.exited;
|
|
75
|
+
if (exitCode !== 0) {
|
|
76
|
+
console.error('Update failed.');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log(`Updated to ${latestVersion}`);
|
|
81
|
+
}
|
package/index.ts
CHANGED
|
@@ -36,6 +36,8 @@ Commands:
|
|
|
36
36
|
batch <file|-> Execute NDJSON batch operations
|
|
37
37
|
schema List or print API resource schemas
|
|
38
38
|
install-skills Install Claude Code skill files
|
|
39
|
+
doctor Check CLI config, connectivity & version
|
|
40
|
+
update Check for and install CLI updates
|
|
39
41
|
config View/edit configuration
|
|
40
42
|
|
|
41
43
|
Options:
|
|
@@ -143,6 +145,20 @@ async function main() {
|
|
|
143
145
|
return;
|
|
144
146
|
}
|
|
145
147
|
|
|
148
|
+
// doctor is local-only, no API key needed
|
|
149
|
+
if (command === 'doctor') {
|
|
150
|
+
const { doctor } = await import('./commands/doctor.js');
|
|
151
|
+
await doctor();
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// update is local-only, no API key needed
|
|
156
|
+
if (command === 'update') {
|
|
157
|
+
const { update } = await import('./commands/update.js');
|
|
158
|
+
await update();
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
146
162
|
// install-skills is local-only, no API key needed
|
|
147
163
|
if (command === 'install-skills') {
|
|
148
164
|
const { installSkills } = await import('./commands/install-skills.js');
|