janet-cli 0.2.2__tar.gz
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.
- janet_cli-0.2.2/.env.example +11 -0
- janet_cli-0.2.2/LICENSE +21 -0
- janet_cli-0.2.2/MANIFEST.in +5 -0
- janet_cli-0.2.2/PKG-INFO +220 -0
- janet_cli-0.2.2/README.md +178 -0
- janet_cli-0.2.2/janet/__init__.py +3 -0
- janet_cli-0.2.2/janet/__main__.py +6 -0
- janet_cli-0.2.2/janet/api/__init__.py +0 -0
- janet_cli-0.2.2/janet/api/client.py +128 -0
- janet_cli-0.2.2/janet/api/models.py +92 -0
- janet_cli-0.2.2/janet/api/organizations.py +57 -0
- janet_cli-0.2.2/janet/api/projects.py +57 -0
- janet_cli-0.2.2/janet/api/tickets.py +125 -0
- janet_cli-0.2.2/janet/auth/__init__.py +0 -0
- janet_cli-0.2.2/janet/auth/callback_server.py +360 -0
- janet_cli-0.2.2/janet/auth/oauth_flow.py +276 -0
- janet_cli-0.2.2/janet/auth/token_manager.py +92 -0
- janet_cli-0.2.2/janet/cli.py +602 -0
- janet_cli-0.2.2/janet/config/__init__.py +0 -0
- janet_cli-0.2.2/janet/config/manager.py +116 -0
- janet_cli-0.2.2/janet/config/models.py +66 -0
- janet_cli-0.2.2/janet/markdown/__init__.py +0 -0
- janet_cli-0.2.2/janet/markdown/generator.py +272 -0
- janet_cli-0.2.2/janet/markdown/yjs_converter.py +225 -0
- janet_cli-0.2.2/janet/sync/__init__.py +0 -0
- janet_cli-0.2.2/janet/sync/file_manager.py +199 -0
- janet_cli-0.2.2/janet/sync/readme_generator.py +174 -0
- janet_cli-0.2.2/janet/sync/sync_engine.py +271 -0
- janet_cli-0.2.2/janet/utils/__init__.py +0 -0
- janet_cli-0.2.2/janet/utils/console.py +39 -0
- janet_cli-0.2.2/janet/utils/errors.py +49 -0
- janet_cli-0.2.2/janet/utils/paths.py +66 -0
- janet_cli-0.2.2/janet_cli.egg-info/PKG-INFO +220 -0
- janet_cli-0.2.2/janet_cli.egg-info/SOURCES.txt +39 -0
- janet_cli-0.2.2/janet_cli.egg-info/dependency_links.txt +1 -0
- janet_cli-0.2.2/janet_cli.egg-info/entry_points.txt +2 -0
- janet_cli-0.2.2/janet_cli.egg-info/requires.txt +19 -0
- janet_cli-0.2.2/janet_cli.egg-info/top_level.txt +1 -0
- janet_cli-0.2.2/pyproject.toml +83 -0
- janet_cli-0.2.2/requirements.txt +10 -0
- janet_cli-0.2.2/setup.cfg +4 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Development Configuration
|
|
2
|
+
# These are only needed for local development and testing
|
|
3
|
+
# Production users don't need these - defaults are built-in
|
|
4
|
+
|
|
5
|
+
# WorkOS Configuration (optional - defaults to production)
|
|
6
|
+
# WORKOS_CLIENT_ID=client_01K3HX06N4GEBHXP0SG87B183V
|
|
7
|
+
# WORKOS_API_URL=https://api.workos.com
|
|
8
|
+
|
|
9
|
+
# Janet API Configuration (optional - defaults to https://api.tryjanet.ai)
|
|
10
|
+
# Uncomment to use local backend:
|
|
11
|
+
# JANET_API_BASE_URL=http://localhost:8000
|
janet_cli-0.2.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Janet AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
janet_cli-0.2.2/PKG-INFO
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: janet-cli
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: CLI tool to sync Janet AI tickets to local markdown files
|
|
5
|
+
Author-email: Janet AI <support@janet-ai.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/janet-ai/janet-cli
|
|
8
|
+
Project-URL: Repository, https://github.com/janet-ai/janet-cli
|
|
9
|
+
Project-URL: Issues, https://github.com/janet-ai/janet-cli/issues
|
|
10
|
+
Keywords: cli,janet,tickets,markdown,sync
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: typer>=0.12.0
|
|
24
|
+
Requires-Dist: httpx>=0.27.0
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0
|
|
26
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
27
|
+
Requires-Dist: rich>=13.0.0
|
|
28
|
+
Requires-Dist: platformdirs>=4.0.0
|
|
29
|
+
Requires-Dist: keyring>=25.0.0
|
|
30
|
+
Requires-Dist: python-dateutil>=2.8.0
|
|
31
|
+
Requires-Dist: pycrdt>=0.9.0
|
|
32
|
+
Requires-Dist: InquirerPy>=0.3.4
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
37
|
+
Requires-Dist: httpx-mock>=0.15.0; extra == "dev"
|
|
38
|
+
Requires-Dist: black>=24.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy>=1.8.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.2.0; extra == "dev"
|
|
41
|
+
Dynamic: license-file
|
|
42
|
+
|
|
43
|
+
# Janet AI CLI
|
|
44
|
+
|
|
45
|
+
> Sync your Janet AI tickets to local markdown files for seamless integration with AI coding agents.
|
|
46
|
+
|
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
|
48
|
+
[](https://www.python.org/downloads/)
|
|
49
|
+
|
|
50
|
+
## What is Janet AI?
|
|
51
|
+
|
|
52
|
+
[Janet AI](https://tryjanet.ai) is an AI-native project management platform for modern software teams. The Janet CLI allows developers to sync their tickets locally as markdown files, enabling AI coding assistants like Claude Code, Cursor, and GitHub Copilot to have full project context.
|
|
53
|
+
|
|
54
|
+
## Why Use the CLI?
|
|
55
|
+
|
|
56
|
+
AI coding assistants work better when they understand your project's tickets, requirements, and priorities. By syncing Janet AI tickets to your workspace, AI agents can:
|
|
57
|
+
|
|
58
|
+
- Reference specific tickets while writing code
|
|
59
|
+
- Understand requirements and acceptance criteria
|
|
60
|
+
- Answer questions about project priorities
|
|
61
|
+
- Suggest implementations based on ticket descriptions
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install janet-cli
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
### 1. Authenticate
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
janet login
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Sync Tickets
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
janet sync
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 3. Use with AI Agents
|
|
84
|
+
|
|
85
|
+
Your tickets are now available as markdown files! Point your AI coding agent to the sync directory.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Example prompts for Claude Code, Cursor, etc:
|
|
89
|
+
"Look at ticket CS-42 and implement the authentication flow"
|
|
90
|
+
"What are the high priority tickets in the Backend project?"
|
|
91
|
+
"Implement the feature described in PROJ-15"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Usage
|
|
95
|
+
|
|
96
|
+
### Basic Commands
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
# Authentication
|
|
100
|
+
janet login # Authenticate with Janet AI
|
|
101
|
+
janet logout # Clear credentials
|
|
102
|
+
janet auth status # Show authentication status
|
|
103
|
+
|
|
104
|
+
# Organization Management
|
|
105
|
+
janet org list # List your organizations
|
|
106
|
+
janet org select <org-id> # Switch organization
|
|
107
|
+
|
|
108
|
+
# Project Management
|
|
109
|
+
janet project list # List projects in current org
|
|
110
|
+
|
|
111
|
+
# Syncing
|
|
112
|
+
janet sync # Interactive mode
|
|
113
|
+
janet sync --all # Sync all projects (skip selection)
|
|
114
|
+
janet sync --dir ./tickets # Specify custom directory
|
|
115
|
+
|
|
116
|
+
# Status & Configuration
|
|
117
|
+
janet status # Show overall status
|
|
118
|
+
janet config show # Display configuration
|
|
119
|
+
janet --help # Show help
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Example Workflow
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# First time setup
|
|
126
|
+
janet login
|
|
127
|
+
janet sync
|
|
128
|
+
|
|
129
|
+
# Re-sync to get updates
|
|
130
|
+
janet sync
|
|
131
|
+
|
|
132
|
+
# Sync to specific directory
|
|
133
|
+
cd /path/to/my/project
|
|
134
|
+
janet sync --dir ./janet-tickets
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## File Organization
|
|
138
|
+
|
|
139
|
+
Tickets are organized in a clear hierarchy:
|
|
140
|
+
|
|
141
|
+
```
|
|
142
|
+
janet-tickets/
|
|
143
|
+
├── README.md # Context for AI agents
|
|
144
|
+
└── My Organization/
|
|
145
|
+
├── Backend/
|
|
146
|
+
│ ├── BACK-1.md
|
|
147
|
+
│ ├── BACK-2.md
|
|
148
|
+
│ └── BACK-42.md
|
|
149
|
+
└── Frontend/
|
|
150
|
+
├── FRONT-1.md
|
|
151
|
+
└── FRONT-15.md
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Markdown Format
|
|
155
|
+
|
|
156
|
+
Each ticket is exported with complete information:
|
|
157
|
+
|
|
158
|
+
```markdown
|
|
159
|
+
# PROJ-42: Add user authentication
|
|
160
|
+
|
|
161
|
+
## Metadata
|
|
162
|
+
- **Status:** In Progress
|
|
163
|
+
- **Priority:** High
|
|
164
|
+
- **Type:** Feature
|
|
165
|
+
- **Assignees:** John Doe, Jane Smith
|
|
166
|
+
- **Created:** Jan 07, 2026 10:30 AM
|
|
167
|
+
- **Updated:** Jan 07, 2026 02:45 PM
|
|
168
|
+
- **Labels:** backend, security
|
|
169
|
+
|
|
170
|
+
## Description
|
|
171
|
+
|
|
172
|
+
We need to implement OAuth authentication...
|
|
173
|
+
|
|
174
|
+
### Requirements
|
|
175
|
+
- Support multiple auth providers
|
|
176
|
+
- Handle token refresh
|
|
177
|
+
- Secure token storage
|
|
178
|
+
|
|
179
|
+
## Comments (2)
|
|
180
|
+
|
|
181
|
+
### John Doe - Jan 07, 2026 11:00 AM
|
|
182
|
+
|
|
183
|
+
Started working on the OAuth flow.
|
|
184
|
+
|
|
185
|
+
### Jane Smith - Jan 07, 2026 01:30 PM
|
|
186
|
+
|
|
187
|
+
Looks good! Add tests when done.
|
|
188
|
+
|
|
189
|
+
## Attachments (1)
|
|
190
|
+
|
|
191
|
+
### design-mockup.png
|
|
192
|
+
- **Type:** image/png
|
|
193
|
+
- **Uploaded by:** Jane Smith
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## Configuration
|
|
197
|
+
|
|
198
|
+
The CLI stores configuration at:
|
|
199
|
+
- **macOS/Linux:** `~/.config/janet-cli/config.json`
|
|
200
|
+
- **Windows:** `%APPDATA%\janet-cli\config.json`
|
|
201
|
+
|
|
202
|
+
Configuration includes authentication tokens and your selected organization.
|
|
203
|
+
|
|
204
|
+
## Requirements
|
|
205
|
+
|
|
206
|
+
- Python 3.8 or higher
|
|
207
|
+
- Janet AI account ([sign up](https://tryjanet.ai))
|
|
208
|
+
|
|
209
|
+
## License
|
|
210
|
+
|
|
211
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
212
|
+
|
|
213
|
+
## Acknowledgments
|
|
214
|
+
|
|
215
|
+
Built for [Janet AI](https://tryjanet.ai) - The AI-native project management platform backed by Y Combinator.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
**Current Version:** 0.2.0
|
|
220
|
+
**Status:** Production Ready ✅
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
# Janet AI CLI
|
|
2
|
+
|
|
3
|
+
> Sync your Janet AI tickets to local markdown files for seamless integration with AI coding agents.
|
|
4
|
+
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
[](https://www.python.org/downloads/)
|
|
7
|
+
|
|
8
|
+
## What is Janet AI?
|
|
9
|
+
|
|
10
|
+
[Janet AI](https://tryjanet.ai) is an AI-native project management platform for modern software teams. The Janet CLI allows developers to sync their tickets locally as markdown files, enabling AI coding assistants like Claude Code, Cursor, and GitHub Copilot to have full project context.
|
|
11
|
+
|
|
12
|
+
## Why Use the CLI?
|
|
13
|
+
|
|
14
|
+
AI coding assistants work better when they understand your project's tickets, requirements, and priorities. By syncing Janet AI tickets to your workspace, AI agents can:
|
|
15
|
+
|
|
16
|
+
- Reference specific tickets while writing code
|
|
17
|
+
- Understand requirements and acceptance criteria
|
|
18
|
+
- Answer questions about project priorities
|
|
19
|
+
- Suggest implementations based on ticket descriptions
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install janet-cli
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### 1. Authenticate
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
janet login
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Sync Tickets
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
janet sync
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 3. Use with AI Agents
|
|
42
|
+
|
|
43
|
+
Your tickets are now available as markdown files! Point your AI coding agent to the sync directory.
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Example prompts for Claude Code, Cursor, etc:
|
|
47
|
+
"Look at ticket CS-42 and implement the authentication flow"
|
|
48
|
+
"What are the high priority tickets in the Backend project?"
|
|
49
|
+
"Implement the feature described in PROJ-15"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Basic Commands
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Authentication
|
|
58
|
+
janet login # Authenticate with Janet AI
|
|
59
|
+
janet logout # Clear credentials
|
|
60
|
+
janet auth status # Show authentication status
|
|
61
|
+
|
|
62
|
+
# Organization Management
|
|
63
|
+
janet org list # List your organizations
|
|
64
|
+
janet org select <org-id> # Switch organization
|
|
65
|
+
|
|
66
|
+
# Project Management
|
|
67
|
+
janet project list # List projects in current org
|
|
68
|
+
|
|
69
|
+
# Syncing
|
|
70
|
+
janet sync # Interactive mode
|
|
71
|
+
janet sync --all # Sync all projects (skip selection)
|
|
72
|
+
janet sync --dir ./tickets # Specify custom directory
|
|
73
|
+
|
|
74
|
+
# Status & Configuration
|
|
75
|
+
janet status # Show overall status
|
|
76
|
+
janet config show # Display configuration
|
|
77
|
+
janet --help # Show help
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Example Workflow
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
# First time setup
|
|
84
|
+
janet login
|
|
85
|
+
janet sync
|
|
86
|
+
|
|
87
|
+
# Re-sync to get updates
|
|
88
|
+
janet sync
|
|
89
|
+
|
|
90
|
+
# Sync to specific directory
|
|
91
|
+
cd /path/to/my/project
|
|
92
|
+
janet sync --dir ./janet-tickets
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## File Organization
|
|
96
|
+
|
|
97
|
+
Tickets are organized in a clear hierarchy:
|
|
98
|
+
|
|
99
|
+
```
|
|
100
|
+
janet-tickets/
|
|
101
|
+
├── README.md # Context for AI agents
|
|
102
|
+
└── My Organization/
|
|
103
|
+
├── Backend/
|
|
104
|
+
│ ├── BACK-1.md
|
|
105
|
+
│ ├── BACK-2.md
|
|
106
|
+
│ └── BACK-42.md
|
|
107
|
+
└── Frontend/
|
|
108
|
+
├── FRONT-1.md
|
|
109
|
+
└── FRONT-15.md
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Markdown Format
|
|
113
|
+
|
|
114
|
+
Each ticket is exported with complete information:
|
|
115
|
+
|
|
116
|
+
```markdown
|
|
117
|
+
# PROJ-42: Add user authentication
|
|
118
|
+
|
|
119
|
+
## Metadata
|
|
120
|
+
- **Status:** In Progress
|
|
121
|
+
- **Priority:** High
|
|
122
|
+
- **Type:** Feature
|
|
123
|
+
- **Assignees:** John Doe, Jane Smith
|
|
124
|
+
- **Created:** Jan 07, 2026 10:30 AM
|
|
125
|
+
- **Updated:** Jan 07, 2026 02:45 PM
|
|
126
|
+
- **Labels:** backend, security
|
|
127
|
+
|
|
128
|
+
## Description
|
|
129
|
+
|
|
130
|
+
We need to implement OAuth authentication...
|
|
131
|
+
|
|
132
|
+
### Requirements
|
|
133
|
+
- Support multiple auth providers
|
|
134
|
+
- Handle token refresh
|
|
135
|
+
- Secure token storage
|
|
136
|
+
|
|
137
|
+
## Comments (2)
|
|
138
|
+
|
|
139
|
+
### John Doe - Jan 07, 2026 11:00 AM
|
|
140
|
+
|
|
141
|
+
Started working on the OAuth flow.
|
|
142
|
+
|
|
143
|
+
### Jane Smith - Jan 07, 2026 01:30 PM
|
|
144
|
+
|
|
145
|
+
Looks good! Add tests when done.
|
|
146
|
+
|
|
147
|
+
## Attachments (1)
|
|
148
|
+
|
|
149
|
+
### design-mockup.png
|
|
150
|
+
- **Type:** image/png
|
|
151
|
+
- **Uploaded by:** Jane Smith
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Configuration
|
|
155
|
+
|
|
156
|
+
The CLI stores configuration at:
|
|
157
|
+
- **macOS/Linux:** `~/.config/janet-cli/config.json`
|
|
158
|
+
- **Windows:** `%APPDATA%\janet-cli\config.json`
|
|
159
|
+
|
|
160
|
+
Configuration includes authentication tokens and your selected organization.
|
|
161
|
+
|
|
162
|
+
## Requirements
|
|
163
|
+
|
|
164
|
+
- Python 3.8 or higher
|
|
165
|
+
- Janet AI account ([sign up](https://tryjanet.ai))
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
|
170
|
+
|
|
171
|
+
## Acknowledgments
|
|
172
|
+
|
|
173
|
+
Built for [Janet AI](https://tryjanet.ai) - The AI-native project management platform backed by Y Combinator.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
**Current Version:** 0.2.0
|
|
178
|
+
**Status:** Production Ready ✅
|
|
File without changes
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"""Base API client with authentication headers."""
|
|
2
|
+
|
|
3
|
+
from typing import Dict, Optional
|
|
4
|
+
|
|
5
|
+
import httpx
|
|
6
|
+
|
|
7
|
+
from janet.auth.token_manager import TokenManager
|
|
8
|
+
from janet.config.manager import ConfigManager
|
|
9
|
+
from janet.utils.errors import NetworkError, AuthenticationError, TokenExpiredError
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class APIClient:
|
|
13
|
+
"""Base API client for Janet AI."""
|
|
14
|
+
|
|
15
|
+
def __init__(self, config_manager: ConfigManager):
|
|
16
|
+
"""
|
|
17
|
+
Initialize API client.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
config_manager: Configuration manager instance
|
|
21
|
+
"""
|
|
22
|
+
self.config_manager = config_manager
|
|
23
|
+
self.token_manager = TokenManager(config_manager)
|
|
24
|
+
self.config = config_manager.get()
|
|
25
|
+
self.base_url = self.config.api.base_url
|
|
26
|
+
self.timeout = self.config.api.timeout
|
|
27
|
+
|
|
28
|
+
def _get_headers(self, include_org: bool = False) -> Dict[str, str]:
|
|
29
|
+
"""
|
|
30
|
+
Get request headers with authentication.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
include_org: Whether to include organization ID header
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
Dictionary of headers
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
access_token = self.token_manager.get_access_token()
|
|
40
|
+
except TokenExpiredError:
|
|
41
|
+
# Try to refresh token
|
|
42
|
+
from janet.auth.oauth_flow import OAuthFlow
|
|
43
|
+
|
|
44
|
+
oauth_flow = OAuthFlow(self.config_manager)
|
|
45
|
+
try:
|
|
46
|
+
oauth_flow.refresh_token()
|
|
47
|
+
access_token = self.token_manager.get_access_token()
|
|
48
|
+
except Exception:
|
|
49
|
+
raise AuthenticationError(
|
|
50
|
+
"Token expired and refresh failed. Please log in again."
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
headers = {
|
|
54
|
+
"Authorization": f"Bearer {access_token}",
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if include_org and self.config.selected_organization:
|
|
59
|
+
headers["X-Organization-ID"] = self.config.selected_organization.id
|
|
60
|
+
|
|
61
|
+
return headers
|
|
62
|
+
|
|
63
|
+
def get(self, endpoint: str, include_org: bool = False, **kwargs) -> Dict:
|
|
64
|
+
"""
|
|
65
|
+
Make GET request.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
endpoint: API endpoint (relative to base_url)
|
|
69
|
+
include_org: Whether to include organization ID header
|
|
70
|
+
**kwargs: Additional arguments for httpx.get
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
Response JSON
|
|
74
|
+
|
|
75
|
+
Raises:
|
|
76
|
+
NetworkError: If request fails
|
|
77
|
+
"""
|
|
78
|
+
url = f"{self.base_url}{endpoint}"
|
|
79
|
+
headers = self._get_headers(include_org=include_org)
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
response = httpx.get(url, headers=headers, timeout=self.timeout, **kwargs)
|
|
83
|
+
response.raise_for_status()
|
|
84
|
+
return response.json()
|
|
85
|
+
except httpx.HTTPStatusError as e:
|
|
86
|
+
if e.response.status_code == 401:
|
|
87
|
+
raise AuthenticationError("Authentication failed. Please log in again.")
|
|
88
|
+
raise NetworkError(f"API request failed: {e.response.status_code} {e.response.text}")
|
|
89
|
+
except httpx.TimeoutException:
|
|
90
|
+
raise NetworkError(f"Request timeout after {self.timeout}s")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
raise NetworkError(f"Network error: {e}")
|
|
93
|
+
|
|
94
|
+
def post(
|
|
95
|
+
self, endpoint: str, data: Optional[Dict] = None, include_org: bool = False, **kwargs
|
|
96
|
+
) -> Dict:
|
|
97
|
+
"""
|
|
98
|
+
Make POST request.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
endpoint: API endpoint (relative to base_url)
|
|
102
|
+
data: Request body data
|
|
103
|
+
include_org: Whether to include organization ID header
|
|
104
|
+
**kwargs: Additional arguments for httpx.post
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Response JSON
|
|
108
|
+
|
|
109
|
+
Raises:
|
|
110
|
+
NetworkError: If request fails
|
|
111
|
+
"""
|
|
112
|
+
url = f"{self.base_url}{endpoint}"
|
|
113
|
+
headers = self._get_headers(include_org=include_org)
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
response = httpx.post(
|
|
117
|
+
url, headers=headers, json=data, timeout=self.timeout, **kwargs
|
|
118
|
+
)
|
|
119
|
+
response.raise_for_status()
|
|
120
|
+
return response.json()
|
|
121
|
+
except httpx.HTTPStatusError as e:
|
|
122
|
+
if e.response.status_code == 401:
|
|
123
|
+
raise AuthenticationError("Authentication failed. Please log in again.")
|
|
124
|
+
raise NetworkError(f"API request failed: {e.response.status_code} {e.response.text}")
|
|
125
|
+
except httpx.TimeoutException:
|
|
126
|
+
raise NetworkError(f"Request timeout after {self.timeout}s")
|
|
127
|
+
except Exception as e:
|
|
128
|
+
raise NetworkError(f"Network error: {e}")
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""Pydantic models for API responses."""
|
|
2
|
+
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Comment(BaseModel):
|
|
9
|
+
"""Ticket comment model."""
|
|
10
|
+
|
|
11
|
+
id: str
|
|
12
|
+
content: str
|
|
13
|
+
created_by: str
|
|
14
|
+
created_at: str
|
|
15
|
+
updated_at: str
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Attachment(BaseModel):
|
|
19
|
+
"""Ticket attachment model."""
|
|
20
|
+
|
|
21
|
+
id: str
|
|
22
|
+
mapping_id: str
|
|
23
|
+
original_filename: str
|
|
24
|
+
mime_type: str
|
|
25
|
+
file_size_bytes: int
|
|
26
|
+
gcs_uri: str
|
|
27
|
+
signed_url: Optional[str] = None
|
|
28
|
+
ai_description: Optional[str] = None
|
|
29
|
+
ai_processing_status: str
|
|
30
|
+
uploaded_by: str
|
|
31
|
+
created_at: str
|
|
32
|
+
is_direct: bool
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ChildTask(BaseModel):
|
|
36
|
+
"""Child task model."""
|
|
37
|
+
|
|
38
|
+
id: str
|
|
39
|
+
childIdentifier: str
|
|
40
|
+
fullIdentifier: str
|
|
41
|
+
title: str
|
|
42
|
+
description: Optional[str] = None
|
|
43
|
+
status: Optional[str] = None
|
|
44
|
+
priority: Optional[str] = None
|
|
45
|
+
assignee: Optional[str] = None
|
|
46
|
+
displayOrder: str
|
|
47
|
+
createdBy: str
|
|
48
|
+
updatedBy: Optional[str] = None
|
|
49
|
+
createdAt: str
|
|
50
|
+
updatedAt: str
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Ticket(BaseModel):
|
|
54
|
+
"""Ticket model."""
|
|
55
|
+
|
|
56
|
+
id: str
|
|
57
|
+
ticket_identifier: str
|
|
58
|
+
ticket_key: str
|
|
59
|
+
title: str
|
|
60
|
+
description: Optional[str] = None
|
|
61
|
+
description_yjs_binary: Optional[str] = None
|
|
62
|
+
ai_summary: Optional[str] = None
|
|
63
|
+
ticket_evaluation: Optional[str] = None
|
|
64
|
+
status: str
|
|
65
|
+
priority: str
|
|
66
|
+
issue_type: str
|
|
67
|
+
assignees: List[str] = []
|
|
68
|
+
labels: List[str] = []
|
|
69
|
+
story_points: Optional[str] = None
|
|
70
|
+
due_date: Optional[str] = None
|
|
71
|
+
sprint: Optional[str] = None
|
|
72
|
+
creator: str
|
|
73
|
+
project_id: str
|
|
74
|
+
organization_id: str
|
|
75
|
+
created_at: str
|
|
76
|
+
updated_at: str
|
|
77
|
+
comments: List[Comment] = []
|
|
78
|
+
child_tasks: List[ChildTask] = []
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class OrganizationMember(BaseModel):
|
|
82
|
+
"""Organization member model."""
|
|
83
|
+
|
|
84
|
+
id: str
|
|
85
|
+
userId: str
|
|
86
|
+
email: str
|
|
87
|
+
firstName: Optional[str] = None
|
|
88
|
+
lastName: Optional[str] = None
|
|
89
|
+
profilePictureUrl: Optional[str] = None
|
|
90
|
+
role: str
|
|
91
|
+
status: str
|
|
92
|
+
joinedAt: str
|