@jvittechs/jai1-cli 0.1.72 → 0.1.74

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 CHANGED
@@ -1,433 +1,15 @@
1
1
  # @jvittechs/jai1-cli
2
2
 
3
- A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework and sync Redmine issues as context for agentic coding workflows.
3
+ > **🇻🇳:** Đây là công cụ CLI thống nhất dành cho các developer của JV-IT TECHS để quản Jai1 Framework. Vui lòng liên hệ với TeamAI để được hướng dẫn cách sử dụng.
4
+ >
5
+ > **🇯🇵:** これはJV-IT TECHSの開発者がJai1 Frameworkを管理するための統合CLIツールです。使用方法についてはTeamAIにお問い合わせください。
6
+ >
7
+ > **🇬🇧:** A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.
4
8
 
5
- ## Features
6
-
7
- ### Jai1 Framework Management
8
- - 📦 Download and update Jai1 Framework from Jai1 Store
9
- - 🔄 Sync framework to any project with one command
10
- - 🔐 Secure access key authentication
11
- - 📋 Version checking and auto-update support
12
-
13
- ### Redmine Context Sync
14
- - 🎯 Extract Redmine issues as structured context for AI agents
15
- - 📝 Sync individual issues or entire projects to local Markdown files
16
- - ⚡ Incremental updates with change detection
17
- - 💬 Comment synchronization with tracking
18
- - 🔧 Configurable filename patterns and slug generation
19
- - 🚀 Concurrent processing for large projects
20
- - 🔁 Retry logic and rate limiting
21
- - ✅ YAML configuration with validation
22
-
23
- ## Installation
9
+ ## Cài đặt / インストール / Installation
24
10
 
25
11
  ```bash
26
12
  npm install -g @jvittechs/jai1-cli
27
13
  # or
28
14
  pnpm add -g @jvittechs/jai1-cli
29
15
  ```
30
-
31
- ## Quick Start
32
-
33
- ```bash
34
- # 1. Initialize Jai1 CLI with your access key
35
- jai1 init
36
-
37
- # 2. Download and sync framework to your project
38
- jai1 update
39
-
40
- # 3. Setup Redmine config (create redmine.config.yaml)
41
- # 4. Sync Redmine issues
42
- jai1 redmine sync project
43
- ```
44
-
45
- ---
46
-
47
- ## Jai1 Framework Commands
48
-
49
- ### Apply Components (Install/Update)
50
-
51
- The `apply` command is the main entry point for installing or updating components. It supports interactive mode, packages, or specific files.
52
-
53
- ```bash
54
- # Interactive mode (Browse packages/components)
55
- jai1 apply
56
-
57
- # Apply a specific package (e.g., 'core')
58
- jai1 apply package core
59
-
60
- # Apply specific components by path
61
- jai1 apply workflows/commit-it.md
62
- jai1 apply skills/gen-commit-message
63
- ```
64
-
65
- **Features:**
66
- - **Dependency Resolution**: Automatically installs required dependencies.
67
- - **Search**: Interactive search for components.
68
- - **Backup**: Automatically backs up modified files to `.jai1_backup/`.
69
-
70
- ### Check for Updates
71
-
72
- Check if any installed components have newer versions available in the store.
73
-
74
- ```bash
75
- jai1 check
76
- ```
77
-
78
- **Output:**
79
- ```
80
- Checking 5 components...
81
- 📦 workflows/commit-it.md: v1.0.0 (Latest)
82
- 📦 skills/gen-commit-message: v1.0.0 -> v1.1.0 ⚠️ Update available
83
- ```
84
-
85
- ### Update All Components
86
-
87
- Update all currently installed components to their latest versions.
88
-
89
- ```bash
90
- jai1 update
91
- ```
92
-
93
- **Output:**
94
- ```
95
- ✅ Updated workflows/commit-it.md (v1.0.1)
96
- ✅ Updated skills/gen-commit-message (v1.1.0)
97
- Backup created at .jai1_backup/2023-12-10T10-00-00/
98
- ```
99
-
100
- ### Manage Backups
101
-
102
- Clear old backups to free up space.
103
-
104
- ```bash
105
- # Clear all backups
106
- jai1 clear-backups
107
-
108
- # Clear backups older than 7 days
109
- jai1 clear-backups --older-than 7d
110
- ```
111
-
112
- ### Show Info
113
-
114
- Display configuration and environment information.
115
-
116
- ```bash
117
- jai1 info
118
- ```
119
-
120
- ---
121
-
122
- ## Redmine Commands
123
-
124
- ### Check Connectivity
125
-
126
- ```bash
127
- jai1 redmine check
128
- ```
129
-
130
- **Output:**
131
- ```
132
- ✓ Redmine API accessible
133
- ✓ Project found: my-project (ID: 123)
134
- ✓ Issues API: 45 issues available
135
- ```
136
-
137
- ### Sync Single Issue
138
-
139
- ```bash
140
- # By ID
141
- jai1 redmine sync issue --id 123
142
-
143
- # By URL
144
- jai1 redmine sync issue --url https://redmine.example.com/issues/123
145
-
146
- # Dry run (preview changes)
147
- jai1 redmine sync issue --id 123 --dry-run
148
- ```
149
-
150
- ### Sync Project
151
-
152
- ```bash
153
- # Sync all issues
154
- jai1 redmine sync project
155
-
156
- # Filter by status
157
- jai1 redmine sync project --status "open"
158
-
159
- # Sync issues updated since date
160
- jai1 redmine sync project --updated-since 2023-01-01
161
-
162
- # Custom concurrency and page size
163
- jai1 redmine sync project --concurrency 8 --page-size 50
164
-
165
- # Dry run
166
- jai1 redmine sync project --dry-run
167
- ```
168
-
169
- **Output:**
170
- ```
171
- Syncing project: my-project (ID: 123)
172
- [████████████████████████████████] 45/45 issues
173
-
174
- Summary:
175
- Created: 5 issues
176
- Updated: 12 issues
177
- Unchanged: 28 issues
178
-
179
- Output: .jai1/redmine/
180
- ```
181
-
182
- ---
183
-
184
- ## VSCode Commands
185
-
186
- Manage VSCode settings for optimal IDE performance with modular optimization groups.
187
-
188
- ### Quick Start
189
-
190
- ```bash
191
- # Interactive mode
192
- jai1 vscode
193
-
194
- # Max performance (enable all optimizations)
195
- jai1 vscode max-performance
196
-
197
- # List available groups
198
- jai1 vscode list
199
- ```
200
-
201
- ### Available Commands
202
-
203
- | Command | Description |
204
- |---------|-------------|
205
- | `jai1 vscode` | Interactive mode to select groups |
206
- | `jai1 vscode enable [groups...]` | Enable specific optimization groups |
207
- | `jai1 vscode disable [groups...]` | Disable specific optimization groups |
208
- | `jai1 vscode max-performance` | Enable all optimizations |
209
- | `jai1 vscode reset [groups...]` | Reset to default settings |
210
- | `jai1 vscode list` | List all available groups |
211
-
212
- ### Performance Groups
213
-
214
- | Group | Description | Impact |
215
- |-------|-------------|--------|
216
- | `telemetry` | Disable all telemetry and data collection | 🟢 Low |
217
- | `languageServers` | Disable/reduce language servers (tsserver, eslint...) | 🔴 High |
218
- | `git` | Disable Git integration | 🟡 Medium |
219
- | `fileWatcher` | Exclude directories from file watcher | 🟡 Medium |
220
- | `search` | Exclude directories from search | 🟢 Low |
221
- | `extensions` | Disable auto-update extensions | 🟢 Low |
222
- | `editorRendering` | Optimize rendering (minimap, whitespace...) | 🟡 Medium |
223
- | `uiElements` | Hide unnecessary UI elements | 🟢 Low |
224
-
225
- ### Common Scenarios
226
-
227
- **Large Project (Node.js/React):**
228
- ```bash
229
- jai1 vscode enable fileWatcher search extensions
230
- ```
231
-
232
- **Low-spec Machine:**
233
- ```bash
234
- jai1 vscode max-performance
235
- ```
236
-
237
- **Privacy (Disable Telemetry):**
238
- ```bash
239
- jai1 vscode enable telemetry
240
- ```
241
-
242
- **Minimal UI:**
243
- ```bash
244
- jai1 vscode enable uiElements editorRendering
245
- ```
246
-
247
- **Restore Features:**
248
- ```bash
249
- # Restore specific group
250
- jai1 vscode disable languageServers
251
-
252
- # Restore all
253
- jai1 vscode reset
254
- ```
255
-
256
- ### Documentation
257
-
258
- - [Full Documentation](./docs/VSCODE_COMMAND.md) - Detailed guide with all settings
259
- - [Quick Reference](./docs/VSCODE_QUICK_REF.md) - Quick reference for common use cases
260
- - [Refactoring Summary](./docs/REFACTOR_VSCODE_COMMAND.md) - Technical details of the refactoring
261
-
262
- ---
263
-
264
- ## Configuration
265
-
266
- ### Global Config: `~/.jai1/config.json`
267
-
268
- Created by `jai1 init`:
269
-
270
- ```json
271
- {
272
- "apiUrl": "https://store.jai1.io",
273
- "accessKey": "YOUR_ACCESS_KEY",
274
- "version": "1.2.3",
275
- "lastUpdated": "2025-12-09T00:00:00Z"
276
- }
277
- ```
278
-
279
- ### Redmine Config: `redmine.config.yaml`
280
-
281
- Create this file in your project root:
282
-
283
- ```yaml
284
- baseUrl: https://redmine.example.com
285
- apiAccessToken: YOUR_API_TOKEN
286
- project:
287
- id: 123
288
- identifier: my-project
289
- outputDir: .jai1/redmine
290
- defaults:
291
- include: [journals, relations, attachments]
292
- status: '*'
293
- pageSize: 100
294
- concurrency: 4
295
- retry:
296
- retries: 3
297
- baseMs: 300
298
- filename:
299
- pattern: '{issueId}-{slug}.md'
300
- slug:
301
- maxLength: 80
302
- dedupe: true
303
- lowercase: true
304
- renameOnTitleChange: false
305
- comments:
306
- anchors:
307
- start: '<!-- redmine:comments:start -->'
308
- end: '<!-- redmine:comments:end -->'
309
- trackBy: journalId
310
- ```
311
-
312
- ### Configuration Options
313
-
314
- | Option | Type | Description | Default |
315
- |--------|------|-------------|---------|
316
- | `baseUrl` | string | Redmine instance URL | Required |
317
- | `apiAccessToken` | string | Redmine API access token | Required |
318
- | `project.id` | number | Project ID (numeric) | Required |
319
- | `project.identifier` | string | Project identifier (string) | Required |
320
- | `outputDir` | string | Directory to store markdown files | `.jai1/redmine` |
321
- | `defaults.include` | array | What to include (journals, relations, attachments) | `[journals]` |
322
- | `defaults.status` | string | Filter by status (`*` for all) | `*` |
323
- | `defaults.pageSize` | number | API page size (1-100) | `100` |
324
- | `defaults.concurrency` | number | Concurrent requests (1-10) | `4` |
325
- | `filename.pattern` | string | Filename pattern with placeholders | `{issueId}-{slug}.md` |
326
- | `comments.trackBy` | string | How to track new comments | `journalId` |
327
-
328
- ---
329
-
330
- ## Global Options
331
-
332
- | Option | Description |
333
- |--------|-------------|
334
- | `-c, --config <path>` | Path to configuration file |
335
- | `-o, --output-dir <path>` | Output directory for files |
336
- | `--dry-run` | Show what would be done without making changes |
337
- | `--json` | Output results as JSON |
338
- | `--verbose` | Enable verbose logging |
339
- | `--version` | Show CLI version |
340
- | `--help` | Show help |
341
-
342
- ---
343
-
344
- ## Output Format
345
-
346
- Redmine issues are saved as Markdown files with frontmatter:
347
-
348
- ```markdown
349
- ---
350
- id: 123
351
- subject: 'Example Issue'
352
- status: 'Open'
353
- priority: 'Normal'
354
- author: 'John Doe'
355
- assigned_to: 'Jane Smith'
356
- created_on: '2023-01-01T10:00:00Z'
357
- updated_on: '2023-01-02T15:30:00Z'
358
- project: 'My Project'
359
- tracker: 'Bug'
360
- lastJournalId: 456
361
- ---
362
-
363
- # Issue Description
364
-
365
- This is the issue description...
366
-
367
- <!-- redmine:comments:start -->
368
-
369
- ## John Doe - 2023-01-02 15:30
370
-
371
- This is a comment on the issue.
372
-
373
- ---
374
-
375
- ## Jane Smith - 2023-01-03 09:15
376
-
377
- Another comment with changes.
378
-
379
- **Changes:**
380
-
381
- - status: Open → In Progress
382
- - assigned_to: John Doe → Jane Smith
383
-
384
- ---
385
-
386
- <!-- redmine:comments:end -->
387
- ```
388
-
389
- ---
390
-
391
- ## Development
392
-
393
- ```bash
394
- # Install dependencies
395
- pnpm install
396
-
397
- # Run in development mode
398
- pnpm dev
399
-
400
- # Build
401
- pnpm build
402
-
403
- # Run tests
404
- pnpm test
405
-
406
- # Lint
407
- pnpm lint
408
- ```
409
-
410
- ---
411
-
412
- ## Exit Codes
413
-
414
- | Code | Description |
415
- |------|-------------|
416
- | `0` | Success |
417
- | `1` | General error |
418
- | `2` | Validation error (configuration, arguments) |
419
- | `3` | Authentication error (invalid access key) |
420
- | `4` | Resource not found (issue, project) |
421
- | `5` | System/network error |
422
-
423
- ---
424
-
425
- ## Documentation
426
-
427
- - [PRD (Product Requirements Document)](./docs/PRD-jai1-client.md)
428
-
429
- ---
430
-
431
- ## License
432
-
433
- MIT
package/dist/cli.js CHANGED
@@ -33,8 +33,8 @@ var NetworkError = class extends Jai1Error {
33
33
  // package.json
34
34
  var package_default = {
35
35
  name: "@jvittechs/jai1-cli",
36
- version: "0.1.72",
37
- description: "Unified CLI for Jai1 Framework Management and Redmine Context Sync",
36
+ version: "0.1.74",
37
+ description: "A unified CLI tool for JV-IT TECHS developers to manage Jai1 Framework. Please contact TeamAI for usage instructions.",
38
38
  type: "module",
39
39
  bin: {
40
40
  jai1: "dist/cli.js"
@@ -4031,7 +4031,7 @@ function useLlmApi(service) {
4031
4031
  }
4032
4032
  }, []);
4033
4033
  const refetch = useCallback2(() => {
4034
- fetchData(false);
4034
+ fetchData(true);
4035
4035
  }, [fetchData]);
4036
4036
  return {
4037
4037
  ...state,
@@ -4218,9 +4218,13 @@ var ChatApp = ({ service, initialModel }) => {
4218
4218
  const [slashMenuIndex, setSlashMenuIndex] = useState13(0);
4219
4219
  const [inputValue, setInputValue] = useState13("");
4220
4220
  const [selectedModel, setSelectedModel] = useState13("");
4221
- const { models, loading, refetch } = useLlmApi(service);
4221
+ const { models, loading, error, refetch } = useLlmApi(service);
4222
4222
  const { messages, isStreaming, sendMessage } = useChat(service);
4223
4223
  useEffect5(() => {
4224
+ if (error && !loading) {
4225
+ setCurrentView("error");
4226
+ return;
4227
+ }
4224
4228
  if (models.length > 0 && !selectedModel) {
4225
4229
  const first = models.find((m) => m.allowed);
4226
4230
  if (first) {
@@ -4228,7 +4232,7 @@ var ChatApp = ({ service, initialModel }) => {
4228
4232
  setCurrentView("chat");
4229
4233
  }
4230
4234
  }
4231
- }, [models, selectedModel, initialModel]);
4235
+ }, [models, selectedModel, initialModel, error, loading]);
4232
4236
  const filteredCommands = useMemo2(() => {
4233
4237
  if (!inputValue.startsWith("/")) return SLASH_COMMANDS;
4234
4238
  const filter = inputValue.slice(1).toLowerCase();
@@ -4280,13 +4284,18 @@ var ChatApp = ({ service, initialModel }) => {
4280
4284
  if (showSlashMenu) {
4281
4285
  setShowSlashMenu(false);
4282
4286
  setInputValue("");
4283
- } else if (currentView !== "chat" && currentView !== "loading") {
4287
+ } else if (currentView !== "chat" && currentView !== "loading" && currentView !== "error") {
4284
4288
  setCurrentView("chat");
4285
4289
  } else {
4286
4290
  exit();
4287
4291
  }
4288
4292
  return;
4289
4293
  }
4294
+ if (currentView === "error" && (key.return || input === "r")) {
4295
+ setCurrentView("loading");
4296
+ refetch();
4297
+ return;
4298
+ }
4290
4299
  if (key.tab && currentView === "chat" && !showSlashMenu && !isStreaming) {
4291
4300
  cycleModel();
4292
4301
  }
@@ -4323,8 +4332,8 @@ var ChatApp = ({ service, initialModel }) => {
4323
4332
  return /* @__PURE__ */ React25.createElement(Box16, { key: m.id, flexDirection: "column" }, /* @__PURE__ */ React25.createElement(Text17, { color: m.id === selectedModel ? "yellow" : "white" }, m.id === selectedModel ? "\u25BA " : " ", m.id), /* @__PURE__ */ React25.createElement(Text17, { color: pct > 80 ? "red" : pct > 50 ? "yellow" : "green" }, " ", bar, " ", /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, used, "/", limit)));
4324
4333
  }), /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, "[Esc] Back"));
4325
4334
  }, [models, selectedModel]);
4326
- const footer = currentView === "model" || currentView === "stats" ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Back" : showSlashMenu ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Cancel" : "[Tab] Next Model \u2022 [/] Commands \u2022 [Esc] Quit";
4327
- return /* @__PURE__ */ React25.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React25.createElement(Box16, { borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Text17, { bold: true, color: "magenta" }, "\u{1F916} Jai1 Chat"), /* @__PURE__ */ React25.createElement(Box16, { flexGrow: 1 }), /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, "Model: "), /* @__PURE__ */ React25.createElement(Text17, { color: "yellow", bold: true }, selectedModel || "...")), currentView === "loading" ? /* @__PURE__ */ React25.createElement(Box16, { padding: 2, minHeight: contentHeight.current, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React25.createElement(Text17, null, /* @__PURE__ */ React25.createElement(Spinner4, { type: "dots" }), " Loading...")) : currentView === "model" ? /* @__PURE__ */ React25.createElement(Box16, { padding: 1, minHeight: contentHeight.current, justifyContent: "center", alignItems: "center" }, /* @__PURE__ */ React25.createElement(
4335
+ const footer = currentView === "error" ? "[Enter/r] Retry \u2022 [Esc] Quit" : currentView === "model" || currentView === "stats" ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Back" : showSlashMenu ? "[\u2191\u2193] Navigate \u2022 [Enter] Select \u2022 [Esc] Cancel" : "[Tab] Next Model \u2022 [/] Commands \u2022 [Esc] Quit";
4336
+ return /* @__PURE__ */ React25.createElement(Box16, { flexDirection: "column" }, /* @__PURE__ */ React25.createElement(Box16, { borderStyle: "double", borderColor: "magenta", paddingX: 1 }, /* @__PURE__ */ React25.createElement(Text17, { bold: true, color: "magenta" }, "\u{1F916} Jai1 Chat"), /* @__PURE__ */ React25.createElement(Box16, { flexGrow: 1 }), /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, "Model: "), /* @__PURE__ */ React25.createElement(Text17, { color: "yellow", bold: true }, selectedModel || "...")), currentView === "loading" ? /* @__PURE__ */ React25.createElement(Box16, { padding: 2, minHeight: contentHeight.current, alignItems: "center", justifyContent: "center" }, /* @__PURE__ */ React25.createElement(Text17, null, /* @__PURE__ */ React25.createElement(Spinner4, { type: "dots" }), " Loading...")) : currentView === "error" ? /* @__PURE__ */ React25.createElement(Box16, { padding: 2, minHeight: contentHeight.current, alignItems: "center", justifyContent: "center", flexDirection: "column" }, /* @__PURE__ */ React25.createElement(Text17, { color: "red", bold: true }, "Connection Error"), /* @__PURE__ */ React25.createElement(Text17, { color: "red" }, error), /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, " "), /* @__PURE__ */ React25.createElement(Text17, { dimColor: true }, "Press Enter or 'r' to retry")) : currentView === "model" ? /* @__PURE__ */ React25.createElement(Box16, { padding: 1, minHeight: contentHeight.current, justifyContent: "center", alignItems: "center" }, /* @__PURE__ */ React25.createElement(
4328
4337
  ModelSelector,
4329
4338
  {
4330
4339
  models,