gemiterm 2.0.0 → 2.1.1
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 +32 -9
- package/package.json +13 -4
- package/src/cli/command-registry.ts +66 -62
- package/src/cli/commands/continue-command.ts +75 -1
- package/src/cli/commands/install-skills-command.ts +35 -0
- package/src/cli/commands/new-command.ts +62 -0
- package/src/cli/index.ts +19 -44
- package/src/cli/utils/long-arg-guard.ts +28 -0
- package/src/cli/utils/prompt-file.ts +26 -0
- package/src/infrastructure/cli-parser.ts +77 -0
- package/src/infrastructure/io.ts +9 -0
- package/src/services/skills-cli-driver.ts +58 -0
- package/src/services/skills-service.ts +52 -0
- package/.env +0 -2
- package/.github/workflows/manual-release.yml +0 -34
- package/.github/workflows/release.yml +0 -198
- package/.github/workflows/test.yml +0 -29
- package/.opencode/commands/opsx-apply.md +0 -152
- package/.opencode/commands/opsx-archive.md +0 -157
- package/.opencode/commands/opsx-explore.md +0 -169
- package/.opencode/commands/opsx-propose.md +0 -104
- package/.opencode/commands/opsx-sync.md +0 -140
- package/.opencode/commands/search-intelligently.md +0 -9
- package/.opencode/opencode.json +0 -20
- package/.opencode/skills/intellisearch/.version +0 -1
- package/.opencode/skills/intellisearch/SKILL.md +0 -84
- package/.opencode/skills/intellisearch/references/brave-search.md +0 -67
- package/.opencode/skills/intellisearch/references/ddg-search.md +0 -79
- package/.opencode/skills/intellisearch/references/deepwiki-tools.md +0 -246
- package/.opencode/skills/intellisearch/references/examples.md +0 -97
- package/.opencode/skills/intellisearch/references/gh-cli.md +0 -143
- package/.opencode/skills/intellisearch/references/google-search.md +0 -40
- package/.opencode/skills/intellisearch/references/search-workflow.md +0 -143
- package/.opencode/skills/intellisearch/references/workflow.md +0 -115
- package/.opencode/skills/openspec-apply-change/SKILL.md +0 -159
- package/.opencode/skills/openspec-archive-change/SKILL.md +0 -117
- package/.opencode/skills/openspec-explore/SKILL.md +0 -287
- package/.opencode/skills/openspec-propose/SKILL.md +0 -111
- package/.opencode/skills/openspec-sync-specs/SKILL.md +0 -147
- package/.serena/project.yml +0 -133
- package/AGENTS.md +0 -136
- package/CHANGELOG.md +0 -3
- package/bun.lock +0 -105
- package/docs/INSTALL.md +0 -185
- package/docs/PLAYWRIGHT_CLI_API.md +0 -306
- package/docs/python-release-for-reference.md +0 -175
- package/examples/sample_json_export.json +0 -32
- package/examples/sample_markdown_export.md +0 -221
- package/examples/usage_examples.sh +0 -222
- package/install.ps1 +0 -264
- package/install.sh +0 -275
- package/openspec/MAESTRO_MIGRATION.md +0 -180
- package/openspec/changes/archive/2026-06-08-command-spec-conformance/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-06-08-command-spec-conformance/design.md +0 -194
- package/openspec/changes/archive/2026-06-08-command-spec-conformance/proposal.md +0 -52
- package/openspec/changes/archive/2026-06-08-command-spec-conformance/specs/multi-profile-conversations/spec.md +0 -133
- package/openspec/changes/archive/2026-06-08-command-spec-conformance/tasks.md +0 -95
- package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/design.md +0 -28
- package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/proposal.md +0 -22
- package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/specs/interactive-prompt-loop/spec.md +0 -35
- package/openspec/changes/archive/2026-06-09-refactor-interactive-prompt-loop/tasks.md +0 -28
- package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/design.md +0 -323
- package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/proposal.md +0 -122
- package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/specs/no-capability-changes/spec.md +0 -29
- package/openspec/changes/archive/2026-06-09-replace-gemini-api-placeholder-with-gemini-reverse/tasks.md +0 -172
- package/openspec/changes/archive/2026-06-09-v2-install-migration/.openspec.yaml +0 -2
- package/openspec/changes/archive/2026-06-09-v2-install-migration/design.md +0 -241
- package/openspec/changes/archive/2026-06-09-v2-install-migration/proposal.md +0 -41
- package/openspec/changes/archive/2026-06-09-v2-install-migration/specs/v2-installer/spec.md +0 -205
- package/openspec/changes/archive/2026-06-09-v2-install-migration/tasks.md +0 -97
- package/openspec/changes/commander-cli-parser/.openspec.yaml +0 -2
- package/openspec/changes/commander-cli-parser/design.md +0 -107
- package/openspec/changes/commander-cli-parser/proposal.md +0 -31
- package/openspec/changes/commander-cli-parser/specs/cli/spec.md +0 -48
- package/openspec/changes/commander-cli-parser/tasks.md +0 -33
- package/openspec/changes/cross-platform-build-and-ci/.openspec.yaml +0 -2
- package/openspec/changes/cross-platform-build-and-ci/design.md +0 -213
- package/openspec/changes/cross-platform-build-and-ci/proposal.md +0 -50
- package/openspec/changes/cross-platform-build-and-ci/specs/path-and-file-mediation/spec.md +0 -335
- package/openspec/changes/cross-platform-build-and-ci/specs/release-pipeline/spec.md +0 -95
- package/openspec/changes/cross-platform-build-and-ci/tasks.md +0 -164
- package/openspec/config.yaml +0 -20
- package/openspec/specs/auth/spec.md +0 -394
- package/openspec/specs/cli/spec.md +0 -108
- package/openspec/specs/commands/spec.md +0 -409
- package/openspec/specs/configuration/spec.md +0 -130
- package/openspec/specs/conversations/spec.md +0 -139
- package/openspec/specs/domain-model/spec.md +0 -128
- package/openspec/specs/formatters/spec.md +0 -158
- package/openspec/specs/install-browser/spec.md +0 -146
- package/openspec/specs/interactive-prompt-loop/spec.md +0 -41
- package/openspec/specs/logger/spec.md +0 -71
- package/openspec/specs/mediator/spec.md +0 -72
- package/openspec/specs/multi-profile-conversations/spec.md +0 -145
- package/openspec/specs/path-utils/spec.md +0 -101
- package/openspec/specs/profiles/spec.md +0 -94
- package/openspec/specs/storage/spec.md +0 -198
- package/openspec/specs/testing/spec.md +0 -237
- package/openspec/specs/v2-installer/spec.md +0 -205
- package/openspec/specs/validators/spec.md +0 -65
- package/scripts/build.ts +0 -88
- package/scripts/clean-build.ps1 +0 -4
- package/scripts/clean-build.sh +0 -5
- package/scripts/install-browser.ps1 +0 -5
- package/scripts/install-browser.sh +0 -6
- package/scripts/lint-path-mediation.ps1 +0 -65
- package/scripts/lint-path-mediation.sh +0 -40
- package/tests/cli/auth-command.test.ts +0 -220
- package/tests/cli/command-registry.test.ts +0 -67
- package/tests/cli/continue-command.test.ts +0 -100
- package/tests/cli/delete-command.test.ts +0 -128
- package/tests/cli/export-all-command.test.ts +0 -375
- package/tests/cli/install-browser-command.test.ts +0 -48
- package/tests/cli/list-command.test.ts +0 -179
- package/tests/cli/new-command.test.ts +0 -139
- package/tests/cli/status-command.test.ts +0 -106
- package/tests/core/query-handlers.test.ts +0 -187
- package/tests/fixtures/auth-fixtures.ts +0 -98
- package/tests/fixtures/chat-fixtures.ts +0 -87
- package/tests/infrastructure/cli-table.test.ts +0 -107
- package/tests/infrastructure/formatters.test.ts +0 -202
- package/tests/infrastructure/io.test.ts +0 -197
- package/tests/infrastructure/logger.test.ts +0 -74
- package/tests/infrastructure/storage.test.ts +0 -335
- package/tests/infrastructure/validators.test.ts +0 -67
- package/tests/integration/commands/auth.test.ts +0 -186
- package/tests/integration/commands/continue.test.ts +0 -130
- package/tests/integration/commands/delete.test.ts +0 -140
- package/tests/integration/commands/export.test.ts +0 -266
- package/tests/integration/commands/fetch.test.ts +0 -238
- package/tests/integration/commands/list.test.ts +0 -281
- package/tests/integration/commands/profile.test.ts +0 -258
- package/tests/integration/commands/status.test.ts +0 -223
- package/tests/integration/installer-script-shape.test.ts +0 -67
- package/tests/parity/compare-outputs.ts +0 -359
- package/tests/parity/test-commands-parity.ps1 +0 -82
- package/tests/parity/test-commands-parity.sh +0 -61
- package/tests/services/auth-service.test.ts +0 -315
- package/tests/services/cookie-monitor.test.ts +0 -229
- package/tests/services/cookie-storage-service.test.ts +0 -230
- package/tests/services/gemini-client-wrapper.test.ts +0 -688
- package/tests/services/install-browser-service.test.ts +0 -83
- package/tests/services/playwright-cli-driver.test.ts +0 -468
- package/tests/services/profile-auth-manager.test.ts +0 -334
- package/tests/services/profile-service.test.ts +0 -224
- package/tests/setup.ts +0 -95
- package/tests/smoke/smoke.test.ts +0 -52
- package/tests/unit/config.test.ts +0 -159
- package/tests/unit/errors.test.ts +0 -119
- package/tests/unit/formatters.test.ts +0 -316
- package/tests/unit/mediator.test.ts +0 -152
- package/tests/unit/path-utils.test.ts +0 -289
- package/tsconfig.json +0 -16
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
<!-- conversation_id: sample_conversation_123 -->
|
|
2
|
-
---
|
|
3
|
-
title: "Python Code Review Session"
|
|
4
|
-
export_date: "2026-03-21 14:30:00"
|
|
5
|
-
message_count: 6
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Python Code Review Session
|
|
9
|
-
|
|
10
|
-
**User:**
|
|
11
|
-
|
|
12
|
-
Can you review this Python function for best practices?
|
|
13
|
-
|
|
14
|
-
```python
|
|
15
|
-
def get_data(url, params={}):
|
|
16
|
-
response = requests.get(url, params)
|
|
17
|
-
return response.json()
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
**Gemini:**
|
|
21
|
-
|
|
22
|
-
<small>2026-03-21 14:30:15</small>
|
|
23
|
-
|
|
24
|
-
I'll review your function for best practices. Here are some suggestions:
|
|
25
|
-
|
|
26
|
-
## 1. Add Type Hints
|
|
27
|
-
|
|
28
|
-
```python
|
|
29
|
-
import requests
|
|
30
|
-
from typing import Any
|
|
31
|
-
|
|
32
|
-
def get_data(url: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
33
|
-
if params is None:
|
|
34
|
-
params = {}
|
|
35
|
-
response = requests.get(url, params=params)
|
|
36
|
-
response.raise_for_status()
|
|
37
|
-
return response.json()
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
## 2. Handle Errors Gracefully
|
|
41
|
-
|
|
42
|
-
Consider catching potential exceptions:
|
|
43
|
-
|
|
44
|
-
```python
|
|
45
|
-
def get_data(url: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
46
|
-
try:
|
|
47
|
-
response = requests.get(url, params=params or {})
|
|
48
|
-
response.raise_for_status()
|
|
49
|
-
return response.json()
|
|
50
|
-
except requests.RequestException as e:
|
|
51
|
-
raise RuntimeError(f"Failed to fetch data: {e}") from e
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
## 3. Add Docstring
|
|
55
|
-
|
|
56
|
-
```python
|
|
57
|
-
def get_data(url: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
|
58
|
-
"""Fetch JSON data from a URL.
|
|
59
|
-
|
|
60
|
-
Args:
|
|
61
|
-
url: The endpoint URL to request.
|
|
62
|
-
params: Optional query parameters.
|
|
63
|
-
|
|
64
|
-
Returns:
|
|
65
|
-
The JSON response as a dictionary.
|
|
66
|
-
|
|
67
|
-
Raises:
|
|
68
|
-
RuntimeError: If the request fails.
|
|
69
|
-
"""
|
|
70
|
-
...
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Key Improvements Summary
|
|
74
|
-
|
|
75
|
-
| Issue | Original | Improved |
|
|
76
|
-
|-------|----------|----------|
|
|
77
|
-
| Mutable default | `params={}` | `params=None` |
|
|
78
|
-
| Type hints | Missing | Full type annotations |
|
|
79
|
-
| Error handling | None | raise_for_status() + try/except |
|
|
80
|
-
| Docstring | None | Google-style docstring |
|
|
81
|
-
|
|
82
|
-
**User:**
|
|
83
|
-
|
|
84
|
-
Thanks! What about adding a timeout parameter?
|
|
85
|
-
|
|
86
|
-
**Gemini:**
|
|
87
|
-
|
|
88
|
-
<small>2026-03-21 14:31:00</small>
|
|
89
|
-
|
|
90
|
-
Good idea! Here's the updated version with timeout:
|
|
91
|
-
|
|
92
|
-
```python
|
|
93
|
-
import requests
|
|
94
|
-
from typing import Any
|
|
95
|
-
|
|
96
|
-
def get_data(
|
|
97
|
-
url: str,
|
|
98
|
-
params: dict[str, Any] | None = None,
|
|
99
|
-
timeout: float | tuple[float, float] = 5.0
|
|
100
|
-
) -> dict[str, Any]:
|
|
101
|
-
"""Fetch JSON data from a URL with timeout support.
|
|
102
|
-
|
|
103
|
-
Args:
|
|
104
|
-
url: The endpoint URL to request.
|
|
105
|
-
params: Optional query parameters.
|
|
106
|
-
timeout: Request timeout in seconds. Can be a single value
|
|
107
|
-
or tuple (connect_timeout, read_timeout).
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
The JSON response as a dictionary.
|
|
111
|
-
|
|
112
|
-
Raises:
|
|
113
|
-
RuntimeError: If the request fails or times out.
|
|
114
|
-
"""
|
|
115
|
-
try:
|
|
116
|
-
response = requests.get(url, params=params or {}, timeout=timeout)
|
|
117
|
-
response.raise_for_status()
|
|
118
|
-
return response.json()
|
|
119
|
-
except requests.Timeout:
|
|
120
|
-
raise RuntimeError(f"Request timed out after {timeout}s") from None
|
|
121
|
-
except requests.RequestException as e:
|
|
122
|
-
raise RuntimeError(f"Failed to fetch data: {e}") from e
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Usage Examples:**
|
|
126
|
-
|
|
127
|
-
```python
|
|
128
|
-
# Basic usage
|
|
129
|
-
data = get_data("https://api.example.com/users")
|
|
130
|
-
|
|
131
|
-
# With query params
|
|
132
|
-
data = get_data("https://api.example.com/search", {"q": "python"})
|
|
133
|
-
|
|
134
|
-
# With custom timeout (10 seconds)
|
|
135
|
-
data = get_data("https://api.example.com/slow", timeout=10.0)
|
|
136
|
-
|
|
137
|
-
# With separate connect/read timeouts
|
|
138
|
-
data = get_data("https://api.example.com/", timeout=(2.0, 10.0))
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
The timeout parameter prevents your application from hanging indefinitely on slow or unresponsive endpoints.
|
|
142
|
-
|
|
143
|
-
**User:**
|
|
144
|
-
|
|
145
|
-
Perfect! One more question - how would you add retry logic with exponential backoff?
|
|
146
|
-
|
|
147
|
-
**Gemini:**
|
|
148
|
-
|
|
149
|
-
<small>2026-03-21 14:32:30</small>
|
|
150
|
-
|
|
151
|
-
Here's an implementation with retry logic using exponential backoff:
|
|
152
|
-
|
|
153
|
-
```python
|
|
154
|
-
import requests
|
|
155
|
-
import time
|
|
156
|
-
from typing import Any
|
|
157
|
-
|
|
158
|
-
def get_data_with_retry(
|
|
159
|
-
url: str,
|
|
160
|
-
params: dict[str, Any] | None = None,
|
|
161
|
-
max_retries: int = 3,
|
|
162
|
-
base_delay: float = 1.0,
|
|
163
|
-
max_delay: float = 30.0
|
|
164
|
-
) -> dict[str, Any]:
|
|
165
|
-
"""Fetch JSON data with automatic retry on failure.
|
|
166
|
-
|
|
167
|
-
Args:
|
|
168
|
-
url: The endpoint URL to request.
|
|
169
|
-
params: Optional query parameters.
|
|
170
|
-
max_retries: Maximum number of retry attempts.
|
|
171
|
-
base_delay: Initial delay between retries in seconds.
|
|
172
|
-
max_delay: Maximum delay cap between retries.
|
|
173
|
-
|
|
174
|
-
Returns:
|
|
175
|
-
The JSON response as a dictionary.
|
|
176
|
-
|
|
177
|
-
Raises:
|
|
178
|
-
RuntimeError: If all retry attempts fail.
|
|
179
|
-
"""
|
|
180
|
-
last_exception: Exception | None = None
|
|
181
|
-
|
|
182
|
-
for attempt in range(max_retries + 1):
|
|
183
|
-
try:
|
|
184
|
-
response = requests.get(url, params=params or {}, timeout=5.0)
|
|
185
|
-
response.raise_for_status()
|
|
186
|
-
return response.json()
|
|
187
|
-
except (requests.Timeout, requests.ConnectionError) as e:
|
|
188
|
-
last_exception = e
|
|
189
|
-
if attempt < max_retries:
|
|
190
|
-
delay = min(base_delay * (2 ** attempt), max_delay)
|
|
191
|
-
time.sleep(delay)
|
|
192
|
-
except requests.RequestException as e:
|
|
193
|
-
raise RuntimeError(f"Request failed: {e}") from e
|
|
194
|
-
|
|
195
|
-
raise RuntimeError(f"All {max_retries} retries exhausted") from last_exception
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
## Retry Strategy Visualization
|
|
199
|
-
|
|
200
|
-
```
|
|
201
|
-
Attempt 1: Immediate
|
|
202
|
-
Attempt 2: Wait 1s
|
|
203
|
-
Attempt 3: Wait 2s
|
|
204
|
-
Attempt 4: Wait 4s
|
|
205
|
-
... (capped at max_delay)
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## When to Use Retries
|
|
209
|
-
|
|
210
|
-
| Scenario | Retry? | Reason |
|
|
211
|
-
|----------|--------|--------|
|
|
212
|
-
| Connection error | Yes | Temporary network issue |
|
|
213
|
-
| Timeout | Yes | Server may be temporarily busy |
|
|
214
|
-
| 404 Not Found | No | Resource doesn't exist |
|
|
215
|
-
| 500 Server Error | Yes | Temporary server issue |
|
|
216
|
-
| 401 Unauthorized | No | Credentials are invalid |
|
|
217
|
-
|
|
218
|
-
This pattern is especially useful for:
|
|
219
|
-
- Production APIs with reliability requirements
|
|
220
|
-
- Batch operations processing many requests
|
|
221
|
-
- Microservices communicating over networks
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Usage Examples for gemiterm
|
|
3
|
-
# This script demonstrates common workflows and commands
|
|
4
|
-
|
|
5
|
-
set -e
|
|
6
|
-
|
|
7
|
-
echo "========================================"
|
|
8
|
-
echo "gemiterm Usage Examples"
|
|
9
|
-
echo "========================================"
|
|
10
|
-
|
|
11
|
-
#------------------------------------------
|
|
12
|
-
# SECTION 1: First-Time Setup
|
|
13
|
-
#------------------------------------------
|
|
14
|
-
section1() {
|
|
15
|
-
echo ""
|
|
16
|
-
echo "=== Section 1: First-Time Setup ==="
|
|
17
|
-
echo ""
|
|
18
|
-
|
|
19
|
-
# Install the CLI
|
|
20
|
-
echo "1. Install gemiterm:"
|
|
21
|
-
echo " pip install -e ."
|
|
22
|
-
echo ""
|
|
23
|
-
|
|
24
|
-
# Install browser dependencies
|
|
25
|
-
echo "2. Install Chromium for Playwright:"
|
|
26
|
-
echo " playwright install chromium"
|
|
27
|
-
echo ""
|
|
28
|
-
|
|
29
|
-
# Authenticate
|
|
30
|
-
echo "3. Authenticate with Google:"
|
|
31
|
-
echo " gemiterm auth"
|
|
32
|
-
echo " # Opens browser window for login"
|
|
33
|
-
echo ""
|
|
34
|
-
|
|
35
|
-
# Verify authentication
|
|
36
|
-
echo "4. Verify authentication status:"
|
|
37
|
-
echo " gemiterm status"
|
|
38
|
-
echo " # Shows: Authenticated: True"
|
|
39
|
-
echo ""
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
#------------------------------------------
|
|
43
|
-
# SECTION 2: Daily Usage Workflows
|
|
44
|
-
#------------------------------------------
|
|
45
|
-
section2() {
|
|
46
|
-
echo ""
|
|
47
|
-
echo "=== Section 2: Daily Usage ==="
|
|
48
|
-
echo ""
|
|
49
|
-
|
|
50
|
-
# Check status
|
|
51
|
-
echo "1. Check authentication status:"
|
|
52
|
-
echo " gemiterm status"
|
|
53
|
-
echo ""
|
|
54
|
-
|
|
55
|
-
# List recent chats
|
|
56
|
-
echo "2. List your recent chats:"
|
|
57
|
-
echo " gemiterm list"
|
|
58
|
-
echo " # Shows table of conversations"
|
|
59
|
-
echo ""
|
|
60
|
-
|
|
61
|
-
# List with limit
|
|
62
|
-
echo "3. List specific number of chats:"
|
|
63
|
-
echo " gemiterm list -n 5"
|
|
64
|
-
echo " # Shows 5 most recent chats"
|
|
65
|
-
echo ""
|
|
66
|
-
|
|
67
|
-
# Fetch a specific chat
|
|
68
|
-
echo "4. View a conversation's history:"
|
|
69
|
-
echo " gemiterm fetch <conversation_id>"
|
|
70
|
-
echo " # Example:"
|
|
71
|
-
echo " gemiterm fetch abc123xyz"
|
|
72
|
-
echo ""
|
|
73
|
-
|
|
74
|
-
# Continue a conversation
|
|
75
|
-
echo "5. Send a message to existing chat:"
|
|
76
|
-
echo " gemiterm continue <conversation_id> <message>"
|
|
77
|
-
echo " # Example:"
|
|
78
|
-
echo " gemiterm continue abc123xyz \"Continue my previous thought\""
|
|
79
|
-
echo ""
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
#------------------------------------------
|
|
83
|
-
# SECTION 3: Export for Backup
|
|
84
|
-
#------------------------------------------
|
|
85
|
-
section3() {
|
|
86
|
-
echo ""
|
|
87
|
-
echo "=== Section 3: Export for Backup ==="
|
|
88
|
-
echo ""
|
|
89
|
-
|
|
90
|
-
# Export single chat
|
|
91
|
-
echo "1. Export a single conversation to Markdown:"
|
|
92
|
-
echo " gemiterm export <conversation_id>"
|
|
93
|
-
echo " # Creates: gemini-chat-{id}-{date}.md"
|
|
94
|
-
echo ""
|
|
95
|
-
|
|
96
|
-
# Export with custom output
|
|
97
|
-
echo "2. Export with custom output path:"
|
|
98
|
-
echo " gemiterm export <conversation_id> -o my-chat.md"
|
|
99
|
-
echo ""
|
|
100
|
-
|
|
101
|
-
# Export as JSON
|
|
102
|
-
echo "3. Export as JSON format:"
|
|
103
|
-
echo " gemiterm export <conversation_id> -f json"
|
|
104
|
-
echo ""
|
|
105
|
-
|
|
106
|
-
# Export with metadata
|
|
107
|
-
echo "4. Export with full metadata:"
|
|
108
|
-
echo " gemiterm export <conversation_id> --include-metadata"
|
|
109
|
-
echo ""
|
|
110
|
-
|
|
111
|
-
# Batch export all
|
|
112
|
-
echo "5. Export all conversations:"
|
|
113
|
-
echo " gemiterm export-all"
|
|
114
|
-
echo " # Creates ./exports/ with all chats"
|
|
115
|
-
echo ""
|
|
116
|
-
|
|
117
|
-
# Export to specific directory
|
|
118
|
-
echo "6. Export to custom directory:"
|
|
119
|
-
echo " gemiterm export-all -o ./my-backups/"
|
|
120
|
-
echo ""
|
|
121
|
-
|
|
122
|
-
# Export recent only
|
|
123
|
-
echo "7. Export only recent conversations:"
|
|
124
|
-
echo " gemiterm export-all --since 2026-03-01"
|
|
125
|
-
echo ""
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
#------------------------------------------
|
|
129
|
-
# SECTION 4: Error Scenarios
|
|
130
|
-
#------------------------------------------
|
|
131
|
-
section4() {
|
|
132
|
-
echo ""
|
|
133
|
-
echo "=== Section 4: Error Handling ==="
|
|
134
|
-
echo ""
|
|
135
|
-
|
|
136
|
-
# Not authenticated
|
|
137
|
-
echo "1. If not authenticated:"
|
|
138
|
-
echo " $ gemiterm list"
|
|
139
|
-
echo " Error: Not authenticated. Run 'gemiterm auth' first."
|
|
140
|
-
echo " $ gemiterm auth"
|
|
141
|
-
echo ""
|
|
142
|
-
|
|
143
|
-
# Session expired
|
|
144
|
-
echo "2. If session expired:"
|
|
145
|
-
echo " $ gemiterm status"
|
|
146
|
-
echo " Error: Session expired. Please re-authenticate."
|
|
147
|
-
echo " $ gemiterm auth"
|
|
148
|
-
echo ""
|
|
149
|
-
|
|
150
|
-
# Conversation not found
|
|
151
|
-
echo "3. If conversation doesn't exist:"
|
|
152
|
-
echo " $ gemiterm fetch nonexistent-id"
|
|
153
|
-
echo " Error: Conversation 'nonexistent-id' not found."
|
|
154
|
-
echo " Run 'gemiterm list' to see available conversations."
|
|
155
|
-
echo ""
|
|
156
|
-
|
|
157
|
-
# Verbose debugging
|
|
158
|
-
echo "4. Debug with verbose output:"
|
|
159
|
-
echo " gemiterm -v status"
|
|
160
|
-
echo " # Shows detailed logs"
|
|
161
|
-
echo ""
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
#------------------------------------------
|
|
165
|
-
# SECTION 5: Configuration
|
|
166
|
-
#------------------------------------------
|
|
167
|
-
section5() {
|
|
168
|
-
echo ""
|
|
169
|
-
echo "=== Section 5: Configuration ==="
|
|
170
|
-
echo ""
|
|
171
|
-
|
|
172
|
-
# Custom config directory
|
|
173
|
-
echo "1. Use custom config directory:"
|
|
174
|
-
echo " export GEMITERM_CONFIG_DIR=/path/to/config"
|
|
175
|
-
echo " gemiterm auth"
|
|
176
|
-
echo ""
|
|
177
|
-
|
|
178
|
-
# Verbose mode
|
|
179
|
-
echo "2. Enable verbose logging:"
|
|
180
|
-
echo " export GEMITERM_VERBOSE=true"
|
|
181
|
-
echo " gemiterm list"
|
|
182
|
-
echo ""
|
|
183
|
-
|
|
184
|
-
# View config location
|
|
185
|
-
echo "3. Default config location:"
|
|
186
|
-
echo " ~/gemiterm/"
|
|
187
|
-
echo " Contains:"
|
|
188
|
-
echo " - storage_state.json (cookies)"
|
|
189
|
-
echo " - config (future use)"
|
|
190
|
-
echo ""
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
#------------------------------------------
|
|
194
|
-
# SECTION 6: Demo Script
|
|
195
|
-
#------------------------------------------
|
|
196
|
-
section6() {
|
|
197
|
-
echo ""
|
|
198
|
-
echo "=== Section 6: Using the Demo Script ==="
|
|
199
|
-
echo ""
|
|
200
|
-
|
|
201
|
-
echo "Run the demo script to see a complete workflow:"
|
|
202
|
-
echo " python scripts/demo.py"
|
|
203
|
-
echo ""
|
|
204
|
-
echo "Demo script:"
|
|
205
|
-
echo "1. Loads cookies"
|
|
206
|
-
echo "2. Fetches chat list"
|
|
207
|
-
echo "3. Shows 5 most recent chats"
|
|
208
|
-
echo "4. Appends message to most recent chat"
|
|
209
|
-
echo ""
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
# Run all sections
|
|
213
|
-
section1
|
|
214
|
-
section2
|
|
215
|
-
section3
|
|
216
|
-
section4
|
|
217
|
-
section5
|
|
218
|
-
section6
|
|
219
|
-
|
|
220
|
-
echo "========================================"
|
|
221
|
-
echo "For more help: gemiterm --help"
|
|
222
|
-
echo "========================================"
|
package/install.ps1
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
#Requires -Version 7.0
|
|
2
|
-
<#
|
|
3
|
-
.SYNOPSIS
|
|
4
|
-
GemiTerm v2.0.0 installer for Windows.
|
|
5
|
-
|
|
6
|
-
.DESCRIPTION
|
|
7
|
-
v1.4.1 → v2.0.0 upgrades replace the binary in place; the config dir at
|
|
8
|
-
%APPDATA%\gemiterm\ (Windows) is NEVER deleted by this installer.
|
|
9
|
-
|
|
10
|
-
.PARAMETER Tag
|
|
11
|
-
GitHub release tag to install (default: "latest").
|
|
12
|
-
|
|
13
|
-
.PARAMETER Uninstall
|
|
14
|
-
Remove GemiTerm binary and PATH entry. Preserves config dir at
|
|
15
|
-
%APPDATA%\gemiterm\.
|
|
16
|
-
|
|
17
|
-
.PARAMETER WhatIf
|
|
18
|
-
Show what the installer would do without making any changes.
|
|
19
|
-
|
|
20
|
-
.PARAMETER InstallDir
|
|
21
|
-
Override the default install directory (default: $env:LOCALAPPDATA\GemiTerm).
|
|
22
|
-
|
|
23
|
-
.EXAMPLE
|
|
24
|
-
irm https://github.com/expert-vision-software/GemiTerm/releases/latest/download/install.ps1 | iex
|
|
25
|
-
pwsh -File install.ps1 -Tag v2.0.0-rc.1
|
|
26
|
-
pwsh -File install.ps1 -Uninstall
|
|
27
|
-
pwsh -File install.ps1 -WhatIf
|
|
28
|
-
#>
|
|
29
|
-
param(
|
|
30
|
-
[string]$Tag = 'latest',
|
|
31
|
-
[switch]$Uninstall,
|
|
32
|
-
[switch]$WhatIf,
|
|
33
|
-
[string]$InstallDir = "$env:LOCALAPPDATA\GemiTerm"
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
$ErrorActionPreference = 'Stop'
|
|
37
|
-
|
|
38
|
-
$Repo = 'expert-vision-software/GemiTerm'
|
|
39
|
-
$ExePath = Join-Path $InstallDir 'GemiTerm.exe'
|
|
40
|
-
|
|
41
|
-
# --- Detect Python v1.4.1 (task 8.1) ---
|
|
42
|
-
if (Get-Command pip -ErrorAction SilentlyContinue) {
|
|
43
|
-
try {
|
|
44
|
-
$null = pip show gemiterm 2>$null
|
|
45
|
-
if ($LASTEXITCODE -eq 0) {
|
|
46
|
-
Write-Host "WARNING: Python v1.4.1 detected. Your config data at %APPDATA%\gemiterm\ is safe and will be preserved. Please run 'pip uninstall gemiterm' before re-running this installer to complete the v2.0.0 installation."
|
|
47
|
-
exit 1
|
|
48
|
-
}
|
|
49
|
-
} catch {
|
|
50
|
-
# pip show returned non-zero — gemiterm not installed via pip
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
# --- Uninstall (task 2.2) ---
|
|
55
|
-
if ($Uninstall) {
|
|
56
|
-
Write-Host "Removing GemiTerm..."
|
|
57
|
-
|
|
58
|
-
if (Test-Path $ExePath) {
|
|
59
|
-
if ($WhatIf) {
|
|
60
|
-
Write-Host "[WhatIf] Would delete $ExePath"
|
|
61
|
-
} else {
|
|
62
|
-
Remove-Item $ExePath -Force
|
|
63
|
-
Write-Host " Removed $ExePath"
|
|
64
|
-
}
|
|
65
|
-
} else {
|
|
66
|
-
Write-Host " $ExePath not found (already removed)"
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
70
|
-
if ($userPath -and $userPath.ToLower().Contains($InstallDir.ToLower())) {
|
|
71
|
-
$newPath = ($userPath -split ';' | Where-Object { $_ -and $_.ToLower() -ne $InstallDir.ToLower() }) -join ';'
|
|
72
|
-
if ($WhatIf) {
|
|
73
|
-
Write-Host "[WhatIf] Would remove $InstallDir from user PATH"
|
|
74
|
-
} else {
|
|
75
|
-
[Environment]::SetEnvironmentVariable('Path', $newPath, 'User')
|
|
76
|
-
Write-Host " Removed $InstallDir from PATH"
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
if ($WhatIf) {
|
|
81
|
-
Write-Host "[WhatIf] Would update current session PATH"
|
|
82
|
-
} else {
|
|
83
|
-
$env:Path = ($env:Path -split ';' | Where-Object { $_ -and $_.ToLower() -ne $InstallDir.ToLower() }) -join ';'
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
Write-Host "GemiTerm uninstall review complete. No changes were made." -ForegroundColor Cyan
|
|
87
|
-
exit 0
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
# --- Upgrade detection (task 2.3) ---
|
|
91
|
-
if (Test-Path $ExePath) {
|
|
92
|
-
Write-Host "Detected existing install at $ExePath; upgrading in place."
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
# --- v1.4.1 → v2.0.0 config migration (task 11.1) ---
|
|
96
|
-
# v1.4.1 wrote config to $env:USERPROFILE\.config\gemiterm\ on Windows
|
|
97
|
-
# (Python config.py:14 has no Windows branch; Path.home() returns the
|
|
98
|
-
# user profile and the literal ".config/gemiterm" is appended). v2.0.0
|
|
99
|
-
# reads from $env:APPDATA\gemiterm\. If the old path exists and the new
|
|
100
|
-
# one does not, copy the tree forward. The v1.4.1 directory is left in
|
|
101
|
-
# place as a safety net; the user can delete it manually.
|
|
102
|
-
$V14ConfigDir = Join-Path $env:USERPROFILE '.config\gemiterm'
|
|
103
|
-
$V2ConfigDir = Join-Path $env:APPDATA 'gemiterm'
|
|
104
|
-
if ((Test-Path $V14ConfigDir) -and -not (Test-Path $V2ConfigDir)) {
|
|
105
|
-
Write-Host "Detected v1.4.1 config at $V14ConfigDir; migrating to $V2ConfigDir"
|
|
106
|
-
if ($WhatIf) {
|
|
107
|
-
Write-Host "[WhatIf] Would create directory $V2ConfigDir"
|
|
108
|
-
Write-Host "[WhatIf] Would copy $V14ConfigDir\* to $V2ConfigDir"
|
|
109
|
-
} else {
|
|
110
|
-
New-Item -ItemType Directory -Path $V2ConfigDir -Force | Out-Null
|
|
111
|
-
Copy-Item -Recurse -Force -Path (Join-Path $V14ConfigDir '*') -Destination $V2ConfigDir
|
|
112
|
-
Write-Host "v1.4.1 config copied to $V2ConfigDir. The original at $V14ConfigDir is left in place as a backup."
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
# Determine package-manager executable (prefer bunx over npx)
|
|
117
|
-
$PackageManagerX = if (Get-Command bun -ErrorAction SilentlyContinue) { 'bunx' } elseif (Get-Command npm -ErrorAction SilentlyContinue) { 'npx' } else { 'bunx' }
|
|
118
|
-
|
|
119
|
-
# --- Package-manager prompt (task 11.2) ---
|
|
120
|
-
# If bun or npm is on PATH, recommend installing via the package manager
|
|
121
|
-
# (npm: `npm i -g gemiterm`; bun: `bun i -g gemiterm`) instead of this
|
|
122
|
-
# binary drop. The prompt is skipped when stdin is not a TTY (e.g. the
|
|
123
|
-
# `irm | iex` one-liner flow runs unattended and must not block).
|
|
124
|
-
if (((Get-Command bun -ErrorAction SilentlyContinue) -or (Get-Command npm -ErrorAction SilentlyContinue)) -and [Console]::IsInputRedirected -eq $false) {
|
|
125
|
-
Write-Host ""
|
|
126
|
-
Write-Host "It is recommended to install via bun or npm package manager."
|
|
127
|
-
Write-Host "Are you sure you want to continue with binary install? [y/N]"
|
|
128
|
-
$reply = Read-Host
|
|
129
|
-
if ($reply -notmatch '^[yY]([eE][sS])?$') {
|
|
130
|
-
$pm = if (Get-Command bun -ErrorAction SilentlyContinue) { 'bun i -g gemiterm' } else { 'npm i -g gemiterm' }
|
|
131
|
-
Write-Host "Aborted. Install via: $pm"
|
|
132
|
-
exit 0
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
# --- Resolve release (task 2.4 + 2.10) ---
|
|
137
|
-
$ApiUrl = if ($Tag -eq 'latest') {
|
|
138
|
-
"https://api.github.com/repos/$Repo/releases/latest"
|
|
139
|
-
} else {
|
|
140
|
-
"https://api.github.com/repos/$Repo/releases/tags/$Tag"
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
$release = $null
|
|
144
|
-
try {
|
|
145
|
-
$release = Invoke-RestMethod $ApiUrl -TimeoutSec 30
|
|
146
|
-
} catch {
|
|
147
|
-
Write-Host "Cannot reach GitHub releases. Check your network connection or use the 'build from source' instructions in docs/INSTALL.md."
|
|
148
|
-
exit 1
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (-not $release -or -not $release.assets) {
|
|
152
|
-
Write-Host "No releases found."
|
|
153
|
-
Write-Host "Build from source: git clone https://github.com/$Repo.git && cd GemiTerm && bun install && bun run build"
|
|
154
|
-
exit 1
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
$asset = $release.assets | Where-Object { $_.name -eq 'gemiterm.exe' }
|
|
158
|
-
if (-not $asset) {
|
|
159
|
-
Write-Host "No gemiterm.exe asset found in release."
|
|
160
|
-
exit 1
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
$version = $release.tag_name
|
|
164
|
-
|
|
165
|
-
# --- Download (task 2.5) ---
|
|
166
|
-
if (-not (Test-Path $InstallDir)) {
|
|
167
|
-
if ($WhatIf) {
|
|
168
|
-
Write-Host "[WhatIf] Would create directory $InstallDir"
|
|
169
|
-
} else {
|
|
170
|
-
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
$tempPath = Join-Path $InstallDir 'GemiTerm.exe.new'
|
|
175
|
-
if ($WhatIf) {
|
|
176
|
-
Write-Host "[WhatIf] Would download GemiTerm $version from $($asset.browser_download_url) to $tempPath"
|
|
177
|
-
Write-Host "[WhatIf] Would move $tempPath to $ExePath"
|
|
178
|
-
} else {
|
|
179
|
-
try {
|
|
180
|
-
Write-Host "Downloading GemiTerm $version..."
|
|
181
|
-
Invoke-WebRequest $asset.browser_download_url -OutFile $tempPath
|
|
182
|
-
Move-Item -Force $tempPath $ExePath
|
|
183
|
-
} catch {
|
|
184
|
-
if (Test-Path $tempPath) { Remove-Item $tempPath -Force -ErrorAction SilentlyContinue }
|
|
185
|
-
Write-Host "Download failed: $_"
|
|
186
|
-
exit 1
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
# --- Bootstrap package manager if needed (task 9.1 + 9.3) ---
|
|
191
|
-
if ($PackageManagerX -eq 'bunx' -and -not (Get-Command bun -ErrorAction SilentlyContinue)) {
|
|
192
|
-
if ($WhatIf) {
|
|
193
|
-
Write-Host "[WhatIf] Would install Bun from https://bun.sh/install.ps1"
|
|
194
|
-
} else {
|
|
195
|
-
Write-Host "Installing Bun..."
|
|
196
|
-
try {
|
|
197
|
-
irm https://bun.sh/install.ps1 | iex
|
|
198
|
-
} catch {
|
|
199
|
-
if (Get-Command npm -ErrorAction SilentlyContinue) {
|
|
200
|
-
Write-Host "Bun installation failed, falling back to npx."
|
|
201
|
-
$PackageManagerX = 'npx'
|
|
202
|
-
} else {
|
|
203
|
-
Write-Host "Bun installation failed and npm is not available. Install Bun from https://bun.sh or npm from https://nodejs.org and re-run this installer."
|
|
204
|
-
exit 1
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
if ($PackageManagerX -eq 'bunx' -and -not (Get-Command bun -ErrorAction SilentlyContinue)) {
|
|
208
|
-
if (Get-Command npm -ErrorAction SilentlyContinue) {
|
|
209
|
-
Write-Host "Bun installation failed, falling back to npx."
|
|
210
|
-
$PackageManagerX = 'npx'
|
|
211
|
-
} else {
|
|
212
|
-
Write-Host "Bun installation failed. Install Bun manually from https://bun.sh and re-run this installer."
|
|
213
|
-
exit 1
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
# --- Install Chromium (task 2.6) ---
|
|
220
|
-
if ($WhatIf) {
|
|
221
|
-
Write-Host "[WhatIf] Would run: $PackageManagerX @playwright/cli install chromium"
|
|
222
|
-
} else {
|
|
223
|
-
Write-Host "Installing Chromium browser for Playwright..."
|
|
224
|
-
try {
|
|
225
|
-
& $PackageManagerX @playwright/cli install chromium
|
|
226
|
-
if ($LASTEXITCODE -ne 0) {
|
|
227
|
-
throw "$PackageManagerX exited with code $LASTEXITCODE"
|
|
228
|
-
}
|
|
229
|
-
} catch {
|
|
230
|
-
Write-Host "Chromium installation failed. Re-run the installer after fixing the issue, or run '$PackageManagerX @playwright/cli install chromium' manually."
|
|
231
|
-
exit 1
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
# --- Verify Chromium (task 2.7) ---
|
|
236
|
-
$chromeExe = Get-ChildItem "$env:LOCALAPPDATA\ms-playwright\chromium-*\chrome.exe" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
237
|
-
if ($chromeExe) {
|
|
238
|
-
Write-Host "Chromium verified at $($chromeExe.FullName)"
|
|
239
|
-
} else {
|
|
240
|
-
Write-Host "Chromium installation verification failed. Re-run the installer after fixing the network, or run '$PackageManagerX @playwright/cli install chromium' manually."
|
|
241
|
-
exit 1
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
# --- PATH augmentation (task 2.8) ---
|
|
245
|
-
$userPath = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
246
|
-
if ($userPath -and -not $userPath.ToLower().Contains($InstallDir.ToLower())) {
|
|
247
|
-
if ($WhatIf) {
|
|
248
|
-
Write-Host "[WhatIf] Would add $InstallDir to user PATH"
|
|
249
|
-
} else {
|
|
250
|
-
[Environment]::SetEnvironmentVariable('Path', "$userPath;$InstallDir", 'User')
|
|
251
|
-
$env:Path = "$env:Path;$InstallDir"
|
|
252
|
-
Write-Host "Added $InstallDir to PATH"
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
# --- Success (task 2.9) ---
|
|
257
|
-
if ($WhatIf) {
|
|
258
|
-
Write-Host ""
|
|
259
|
-
Write-Host "WhatIf review complete. No changes were made." -ForegroundColor Cyan
|
|
260
|
-
Write-Host "GemiTerm $version would be installed to $ExePath using $($PackageManagerX).Chromium."
|
|
261
|
-
Write-Host "Run without -WhatIf to apply."
|
|
262
|
-
} else {
|
|
263
|
-
Write-Host "GemiTerm $version installed to $ExePath. Run 'gemiterm status' to verify, then 'gemiterm auth' to authenticate."
|
|
264
|
-
}
|