@mdrv/opencode-quota 262.0.0
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/LICENSE +21 -0
- package/README.md +189 -0
- package/bin/copilot-quota.ts +374 -0
- package/bin/glm-quota.ts +467 -0
- package/bin/install.js +439 -0
- package/bin/kimi-quota.ts +314 -0
- package/dist/bin/copilot-quota.d.ts +8 -0
- package/dist/bin/copilot-quota.d.ts.map +1 -0
- package/dist/bin/copilot-quota.js +298 -0
- package/dist/bin/copilot-quota.js.map +1 -0
- package/dist/bin/glm-quota.d.ts +8 -0
- package/dist/bin/glm-quota.d.ts.map +1 -0
- package/dist/bin/glm-quota.js +367 -0
- package/dist/bin/glm-quota.js.map +1 -0
- package/dist/bin/kimi-quota.d.ts +3 -0
- package/dist/bin/kimi-quota.d.ts.map +1 -0
- package/dist/bin/kimi-quota.js +241 -0
- package/dist/bin/kimi-quota.js.map +1 -0
- package/dist/src/api/client.d.ts +76 -0
- package/dist/src/api/client.d.ts.map +1 -0
- package/dist/src/api/client.js +203 -0
- package/dist/src/api/client.js.map +1 -0
- package/dist/src/api/endpoints.d.ts +22 -0
- package/dist/src/api/endpoints.d.ts.map +1 -0
- package/dist/src/api/endpoints.js +41 -0
- package/dist/src/api/endpoints.js.map +1 -0
- package/dist/src/api/platforms.d.ts +20 -0
- package/dist/src/api/platforms.d.ts.map +1 -0
- package/dist/src/api/platforms.js +38 -0
- package/dist/src/api/platforms.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +723 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/shared/logging.d.ts +7 -0
- package/dist/src/shared/logging.d.ts.map +1 -0
- package/dist/src/shared/logging.js +29 -0
- package/dist/src/shared/logging.js.map +1 -0
- package/dist/src/utils/box-constants.d.ts +43 -0
- package/dist/src/utils/box-constants.d.ts.map +1 -0
- package/dist/src/utils/box-constants.js +43 -0
- package/dist/src/utils/box-constants.js.map +1 -0
- package/dist/src/utils/date-formatter.d.ts +17 -0
- package/dist/src/utils/date-formatter.d.ts.map +1 -0
- package/dist/src/utils/date-formatter.js +33 -0
- package/dist/src/utils/date-formatter.js.map +1 -0
- package/dist/src/utils/error-formatter.d.ts +17 -0
- package/dist/src/utils/error-formatter.d.ts.map +1 -0
- package/dist/src/utils/error-formatter.js +60 -0
- package/dist/src/utils/error-formatter.js.map +1 -0
- package/dist/src/utils/progress-bar.d.ts +35 -0
- package/dist/src/utils/progress-bar.d.ts.map +1 -0
- package/dist/src/utils/progress-bar.js +43 -0
- package/dist/src/utils/progress-bar.js.map +1 -0
- package/dist/src/utils/reset-timer.d.ts +11 -0
- package/dist/src/utils/reset-timer.d.ts.map +1 -0
- package/dist/src/utils/reset-timer.js +32 -0
- package/dist/src/utils/reset-timer.js.map +1 -0
- package/dist/src/utils/time-window.d.ts +30 -0
- package/dist/src/utils/time-window.d.ts.map +1 -0
- package/dist/src/utils/time-window.js +34 -0
- package/dist/src/utils/time-window.js.map +1 -0
- package/dist/tests/error-handling/api-errors.test.d.ts +7 -0
- package/dist/tests/error-handling/api-errors.test.d.ts.map +1 -0
- package/dist/tests/error-handling/api-errors.test.js +110 -0
- package/dist/tests/error-handling/api-errors.test.js.map +1 -0
- package/dist/tests/error-handling/auth-errors.test.d.ts +7 -0
- package/dist/tests/error-handling/auth-errors.test.d.ts.map +1 -0
- package/dist/tests/error-handling/auth-errors.test.js +110 -0
- package/dist/tests/error-handling/auth-errors.test.js.map +1 -0
- package/dist/tests/error-handling/network-errors.test.d.ts +7 -0
- package/dist/tests/error-handling/network-errors.test.d.ts.map +1 -0
- package/dist/tests/error-handling/network-errors.test.js +94 -0
- package/dist/tests/error-handling/network-errors.test.js.map +1 -0
- package/dist/tests/error-handling/parse-errors.test.d.ts +7 -0
- package/dist/tests/error-handling/parse-errors.test.d.ts.map +1 -0
- package/dist/tests/error-handling/parse-errors.test.js +87 -0
- package/dist/tests/error-handling/parse-errors.test.js.map +1 -0
- package/dist/tests/error-handling/token-sanitization.test.d.ts +2 -0
- package/dist/tests/error-handling/token-sanitization.test.d.ts.map +1 -0
- package/dist/tests/error-handling/token-sanitization.test.js +59 -0
- package/dist/tests/error-handling/token-sanitization.test.js.map +1 -0
- package/dist/tests/functional/date-formatter.test.d.ts +5 -0
- package/dist/tests/functional/date-formatter.test.d.ts.map +1 -0
- package/dist/tests/functional/date-formatter.test.js +46 -0
- package/dist/tests/functional/date-formatter.test.js.map +1 -0
- package/dist/tests/functional/progress-bar.test.d.ts +5 -0
- package/dist/tests/functional/progress-bar.test.d.ts.map +1 -0
- package/dist/tests/functional/progress-bar.test.js +82 -0
- package/dist/tests/functional/progress-bar.test.js.map +1 -0
- package/dist/tests/functional/reset-timer.test.d.ts +6 -0
- package/dist/tests/functional/reset-timer.test.d.ts.map +1 -0
- package/dist/tests/functional/reset-timer.test.js +67 -0
- package/dist/tests/functional/reset-timer.test.js.map +1 -0
- package/dist/tests/functional/time-window.test.d.ts +5 -0
- package/dist/tests/functional/time-window.test.d.ts.map +1 -0
- package/dist/tests/functional/time-window.test.js +46 -0
- package/dist/tests/functional/time-window.test.js.map +1 -0
- package/dist/tests/integration/box-alignment.test.d.ts +8 -0
- package/dist/tests/integration/box-alignment.test.d.ts.map +1 -0
- package/dist/tests/integration/box-alignment.test.js +238 -0
- package/dist/tests/integration/box-alignment.test.js.map +1 -0
- package/dist/tests/integration/error-handling.test.d.ts +2 -0
- package/dist/tests/integration/error-handling.test.d.ts.map +1 -0
- package/dist/tests/integration/error-handling.test.js +36 -0
- package/dist/tests/integration/error-handling.test.js.map +1 -0
- package/dist/tests/integration/installer-config.test.d.ts +2 -0
- package/dist/tests/integration/installer-config.test.d.ts.map +1 -0
- package/dist/tests/integration/installer-config.test.js +65 -0
- package/dist/tests/integration/installer-config.test.js.map +1 -0
- package/dist/tests/integration/plugin-catch-block.test.d.ts +2 -0
- package/dist/tests/integration/plugin-catch-block.test.d.ts.map +1 -0
- package/dist/tests/integration/plugin-catch-block.test.js +134 -0
- package/dist/tests/integration/plugin-catch-block.test.js.map +1 -0
- package/dist/tests/integration/reset-time-display.test.d.ts +6 -0
- package/dist/tests/integration/reset-time-display.test.d.ts.map +1 -0
- package/dist/tests/integration/reset-time-display.test.js +138 -0
- package/dist/tests/integration/reset-time-display.test.js.map +1 -0
- package/dist/tests/module/http-client.test.d.ts +2 -0
- package/dist/tests/module/http-client.test.d.ts.map +1 -0
- package/dist/tests/module/http-client.test.js +49 -0
- package/dist/tests/module/http-client.test.js.map +1 -0
- package/dist/tests/module/platform-detection.test.d.ts +5 -0
- package/dist/tests/module/platform-detection.test.d.ts.map +1 -0
- package/dist/tests/module/platform-detection.test.js +48 -0
- package/dist/tests/module/platform-detection.test.js.map +1 -0
- package/integration/agents/copilot-quota-exec.md +20 -0
- package/integration/agents/glm-quota-exec.md +20 -0
- package/integration/command/copilot_quota.md +6 -0
- package/integration/command/glm_quota.md +6 -0
- package/integration/skills/copilot-quota/SKILL.md +11 -0
- package/integration/skills/glm-quota/SKILL.md +11 -0
- package/package.json +69 -0
package/bin/install.js
ADDED
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GLM Quota Plugin Installer
|
|
5
|
+
*
|
|
6
|
+
* This script installs the GLM Quota Plugin integration files into the user's
|
|
7
|
+
* OpenCode configuration directory (~/.config/opencode/).
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node bin/install.js # Interactive install (ask before overwriting)
|
|
11
|
+
* node bin/install.js --force # Force overwrite existing files
|
|
12
|
+
* node bin/install.js uninstall # Remove integration files and config
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { spawnSync } from 'child_process'
|
|
16
|
+
import * as fs from 'fs'
|
|
17
|
+
import { parse as parseJsonc } from 'jsonc-parser'
|
|
18
|
+
import * as os from 'os'
|
|
19
|
+
import * as path from 'path'
|
|
20
|
+
|
|
21
|
+
// ==========================================
|
|
22
|
+
// CONSTANTS
|
|
23
|
+
// ==========================================
|
|
24
|
+
|
|
25
|
+
const __filename = decodeURIComponent(new URL(import.meta.url).pathname)
|
|
26
|
+
const __dirname = path.dirname(__filename)
|
|
27
|
+
const SOURCE_DIR = path.join(__dirname, '..', 'integration')
|
|
28
|
+
|
|
29
|
+
// GLM Quota files
|
|
30
|
+
const COMMAND_FILE = path.join(SOURCE_DIR, 'command', 'glm_quota.md')
|
|
31
|
+
const SKILL_FILE = path.join(SOURCE_DIR, 'skills', 'glm-quota', 'SKILL.md')
|
|
32
|
+
const AGENT_FILE = path.join(SOURCE_DIR, 'agents', 'glm-quota-exec.md')
|
|
33
|
+
|
|
34
|
+
// Copilot Quota files
|
|
35
|
+
const COPILOT_COMMAND_FILE = path.join(SOURCE_DIR, 'command', 'copilot_quota.md')
|
|
36
|
+
const COPILOT_SKILL_FILE = path.join(SOURCE_DIR, 'skills', 'copilot-quota', 'SKILL.md')
|
|
37
|
+
const COPILOT_AGENT_FILE = path.join(SOURCE_DIR, 'agents', 'copilot-quota-exec.md')
|
|
38
|
+
|
|
39
|
+
const CONFIG_DIR = path.join(os.homedir(), '.config', 'opencode')
|
|
40
|
+
|
|
41
|
+
// GLM Quota targets
|
|
42
|
+
const TARGET_COMMAND = path.join(CONFIG_DIR, 'command', 'glm_quota.md')
|
|
43
|
+
const TARGET_SKILL = path.join(CONFIG_DIR, 'skills', 'glm-quota', 'SKILL.md')
|
|
44
|
+
const TARGET_AGENT = path.join(CONFIG_DIR, 'agents', 'glm-quota-exec.md')
|
|
45
|
+
|
|
46
|
+
// Copilot Quota targets
|
|
47
|
+
const TARGET_COPILOT_COMMAND = path.join(CONFIG_DIR, 'command', 'copilot_quota.md')
|
|
48
|
+
const TARGET_COPILOT_SKILL = path.join(CONFIG_DIR, 'skills', 'copilot-quota', 'SKILL.md')
|
|
49
|
+
const TARGET_COPILOT_AGENT = path.join(CONFIG_DIR, 'agents', 'copilot-quota-exec.md')
|
|
50
|
+
|
|
51
|
+
// Check which config file exists (opencode.json or opencode.jsonc)
|
|
52
|
+
const TARGET_CONFIG_JSON = path.join(CONFIG_DIR, 'opencode.json')
|
|
53
|
+
const TARGET_CONFIG_JSONC = path.join(CONFIG_DIR, 'opencode.jsonc')
|
|
54
|
+
let TARGET_CONFIG = null
|
|
55
|
+
if (fileExists(TARGET_CONFIG_JSON)) {
|
|
56
|
+
TARGET_CONFIG = TARGET_CONFIG_JSON
|
|
57
|
+
} else if (fileExists(TARGET_CONFIG_JSONC)) {
|
|
58
|
+
TARGET_CONFIG = TARGET_CONFIG_JSONC
|
|
59
|
+
} else {
|
|
60
|
+
// Default to opencode.json if neither exists
|
|
61
|
+
TARGET_CONFIG = TARGET_CONFIG_JSON
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ==========================================
|
|
65
|
+
// UTILITY FUNCTIONS
|
|
66
|
+
// ==========================================
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ensure directory exists, create if missing
|
|
70
|
+
*/
|
|
71
|
+
function ensureDirectory(dirPath) {
|
|
72
|
+
if (!fs.existsSync(dirPath)) {
|
|
73
|
+
fs.mkdirSync(dirPath, { recursive: true })
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if file exists
|
|
79
|
+
*/
|
|
80
|
+
function fileExists(filePath) {
|
|
81
|
+
return fs.existsSync(filePath)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Copy file from source to destination
|
|
86
|
+
*/
|
|
87
|
+
function copyFile(source, destination) {
|
|
88
|
+
ensureDirectory(path.dirname(destination))
|
|
89
|
+
fs.copyFileSync(source, destination)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Remove file if it exists
|
|
94
|
+
*/
|
|
95
|
+
function removeFile(filePath, label) {
|
|
96
|
+
if (fileExists(filePath)) {
|
|
97
|
+
fs.unlinkSync(filePath)
|
|
98
|
+
console.log(` ✓ Removed ${label}`)
|
|
99
|
+
} else {
|
|
100
|
+
console.log(` ⊙ Not found ${label}`)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Remove directory if it exists
|
|
106
|
+
*/
|
|
107
|
+
function removeDirectory(dirPath, label) {
|
|
108
|
+
if (fileExists(dirPath)) {
|
|
109
|
+
fs.rmSync(dirPath, { recursive: true, force: true })
|
|
110
|
+
console.log(` ✓ Removed ${label}`)
|
|
111
|
+
} else {
|
|
112
|
+
console.log(` ⊙ Not found ${label}`)
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Parse JSON or JSONC file
|
|
118
|
+
*/
|
|
119
|
+
function parseConfig(filePath) {
|
|
120
|
+
try {
|
|
121
|
+
const content = fs.readFileSync(filePath, 'utf-8')
|
|
122
|
+
return parseJsonc(content)
|
|
123
|
+
} catch (error) {
|
|
124
|
+
throw new Error(`Failed to parse ${filePath}: ${error instanceof Error ? error.message : String(error)}`)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Write JSON file
|
|
130
|
+
*/
|
|
131
|
+
function writeConfig(filePath, data) {
|
|
132
|
+
ensureDirectory(path.dirname(filePath))
|
|
133
|
+
const json = JSON.stringify(data, null, 2) + '\n'
|
|
134
|
+
fs.writeFileSync(filePath, json)
|
|
135
|
+
console.log(` ✓ Wrote ${filePath} (${json.length} bytes)`)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Deep merge objects
|
|
140
|
+
*/
|
|
141
|
+
function deepMerge(target, source) {
|
|
142
|
+
const result = { ...target }
|
|
143
|
+
|
|
144
|
+
for (const key of Object.keys(source)) {
|
|
145
|
+
if (source[key] instanceof Object && key in result && result[key] instanceof Object) {
|
|
146
|
+
result[key] = deepMerge(result[key], source[key])
|
|
147
|
+
} else {
|
|
148
|
+
result[key] = source[key]
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Prompt user for confirmation
|
|
157
|
+
*/
|
|
158
|
+
function promptConfirm(message) {
|
|
159
|
+
process.stdout.write(`${message} (y/N) `)
|
|
160
|
+
const response = process.stdin.read()
|
|
161
|
+
return response?.trim().toLowerCase() === 'y'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// ==========================================
|
|
165
|
+
// INSTALLATION FUNCTIONS
|
|
166
|
+
// ==========================================
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Install command file
|
|
170
|
+
*/
|
|
171
|
+
function installCommand(force) {
|
|
172
|
+
if (fileExists(TARGET_COMMAND) && !force) {
|
|
173
|
+
if (!promptConfirm(`Command file exists: ${TARGET_COMMAND}\nOverwrite?`)) {
|
|
174
|
+
console.log(` ⊘ Skipped ${TARGET_COMMAND}`)
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
copyFile(COMMAND_FILE, TARGET_COMMAND)
|
|
180
|
+
console.log(` ✓ Created ${TARGET_COMMAND}`)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Install skill file
|
|
185
|
+
*/
|
|
186
|
+
function installSkill(force) {
|
|
187
|
+
if (fileExists(TARGET_SKILL) && !force) {
|
|
188
|
+
if (!promptConfirm(`Skill directory exists: ${path.dirname(TARGET_SKILL)}\nOverwrite?`)) {
|
|
189
|
+
console.log(` ⊘ Skipped ${TARGET_SKILL}`)
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
copyFile(SKILL_FILE, TARGET_SKILL)
|
|
195
|
+
console.log(` ✓ Created ${path.join(path.basename(path.dirname(TARGET_SKILL)), path.basename(TARGET_SKILL))}`)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Install agent file
|
|
200
|
+
*/
|
|
201
|
+
function installAgent(force) {
|
|
202
|
+
if (fileExists(TARGET_AGENT) && !force) {
|
|
203
|
+
if (!promptConfirm(`Agent file exists: ${TARGET_AGENT}\nOverwrite?`)) {
|
|
204
|
+
console.log(` ⊘ Skipped ${TARGET_AGENT}`)
|
|
205
|
+
return
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
copyFile(AGENT_FILE, TARGET_AGENT)
|
|
210
|
+
console.log(` ✓ Created ${TARGET_AGENT}`)
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Install Copilot command file
|
|
215
|
+
*/
|
|
216
|
+
function installCopilotCommand(force) {
|
|
217
|
+
if (fileExists(TARGET_COPILOT_COMMAND) && !force) {
|
|
218
|
+
if (!promptConfirm(`Copilot command file exists: ${TARGET_COPILOT_COMMAND}\nOverwrite?`)) {
|
|
219
|
+
console.log(` ⊘ Skipped ${TARGET_COPILOT_COMMAND}`)
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
copyFile(COPILOT_COMMAND_FILE, TARGET_COPILOT_COMMAND)
|
|
225
|
+
console.log(` ✓ Created ${TARGET_COPILOT_COMMAND}`)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* Install Copilot skill file
|
|
230
|
+
*/
|
|
231
|
+
function installCopilotSkill(force) {
|
|
232
|
+
if (fileExists(TARGET_COPILOT_SKILL) && !force) {
|
|
233
|
+
if (!promptConfirm(`Copilot skill directory exists: ${path.dirname(TARGET_COPILOT_SKILL)}\nOverwrite?`)) {
|
|
234
|
+
console.log(` ⊘ Skipped ${TARGET_COPILOT_SKILL}`)
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
copyFile(COPILOT_SKILL_FILE, TARGET_COPILOT_SKILL)
|
|
240
|
+
console.log(
|
|
241
|
+
` ✓ Created ${path.join(path.basename(path.dirname(TARGET_COPILOT_SKILL)), path.basename(TARGET_COPILOT_SKILL))}`,
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Install Copilot agent file
|
|
247
|
+
*/
|
|
248
|
+
function installCopilotAgent(force) {
|
|
249
|
+
if (fileExists(TARGET_COPILOT_AGENT) && !force) {
|
|
250
|
+
if (!promptConfirm(`Copilot agent file exists: ${TARGET_COPILOT_AGENT}\nOverwrite?`)) {
|
|
251
|
+
console.log(` ⊘ Skipped ${TARGET_COPILOT_AGENT}`)
|
|
252
|
+
return
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
copyFile(COPILOT_AGENT_FILE, TARGET_COPILOT_AGENT)
|
|
257
|
+
console.log(` ✓ Created ${TARGET_COPILOT_AGENT}`)
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Update plugin configuration and cleanup old JSON agent
|
|
262
|
+
*/
|
|
263
|
+
function updatePluginConfig() {
|
|
264
|
+
// Parse existing config if it exists
|
|
265
|
+
let existingConfig = {}
|
|
266
|
+
if (fileExists(TARGET_CONFIG)) {
|
|
267
|
+
existingConfig = parseConfig(TARGET_CONFIG)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const PLUGIN_NAME = 'opencode-glm-quota'
|
|
271
|
+
|
|
272
|
+
// CLEANUP: Remove old JSON agent config if it exists (migration from v1.3.x)
|
|
273
|
+
if (existingConfig.agent && existingConfig.agent['glm-quota-exec']) {
|
|
274
|
+
delete existingConfig.agent['glm-quota-exec']
|
|
275
|
+
if (Object.keys(existingConfig.agent).length === 0) {
|
|
276
|
+
delete existingConfig.agent
|
|
277
|
+
}
|
|
278
|
+
console.log(' ✓ Removed old JSON agent config (migrated to Markdown)')
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// OpenCode config key is "plugin" (singular). Migrate legacy "plugins" entries.
|
|
282
|
+
const plugin = Array.isArray(existingConfig.plugin) ? [...existingConfig.plugin] : []
|
|
283
|
+
const legacyPlugins = Array.isArray(existingConfig.plugins) ? existingConfig.plugins : []
|
|
284
|
+
|
|
285
|
+
if (legacyPlugins.length > 0) {
|
|
286
|
+
for (const name of legacyPlugins) {
|
|
287
|
+
if (typeof name === 'string' && !plugin.includes(name)) {
|
|
288
|
+
plugin.push(name)
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
delete existingConfig.plugins
|
|
292
|
+
console.log(' ✓ Migrated legacy plugins array to plugin')
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Only add if not already present
|
|
296
|
+
if (!plugin.includes(PLUGIN_NAME)) {
|
|
297
|
+
plugin.push(PLUGIN_NAME)
|
|
298
|
+
console.log(` ✓ Added ${PLUGIN_NAME} to plugin array`)
|
|
299
|
+
} else {
|
|
300
|
+
console.log(` ⊙ Plugin ${PLUGIN_NAME} already in plugin array`)
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
existingConfig.plugin = plugin
|
|
304
|
+
|
|
305
|
+
// Write config back to same file (opencode.json or opencode.jsonc)
|
|
306
|
+
writeConfig(TARGET_CONFIG, existingConfig)
|
|
307
|
+
console.log(` ✓ Updated ${path.basename(TARGET_CONFIG)}`)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Remove plugin configuration and agent configuration
|
|
312
|
+
*/
|
|
313
|
+
function removeConfig() {
|
|
314
|
+
if (!fileExists(TARGET_CONFIG)) {
|
|
315
|
+
console.log(` ⊙ Config not found: ${TARGET_CONFIG}`)
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const PLUGIN_NAME = 'opencode-glm-quota'
|
|
320
|
+
const existingConfig = parseConfig(TARGET_CONFIG)
|
|
321
|
+
let changed = false
|
|
322
|
+
|
|
323
|
+
if (Array.isArray(existingConfig.plugin)) {
|
|
324
|
+
const next = existingConfig.plugin.filter((name) => name !== PLUGIN_NAME)
|
|
325
|
+
if (next.length !== existingConfig.plugin.length) {
|
|
326
|
+
existingConfig.plugin = next
|
|
327
|
+
changed = true
|
|
328
|
+
console.log(' ✓ Removed plugin from plugin array')
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if (Array.isArray(existingConfig.plugins)) {
|
|
333
|
+
const next = existingConfig.plugins.filter((name) => name !== PLUGIN_NAME)
|
|
334
|
+
if (next.length !== existingConfig.plugins.length) {
|
|
335
|
+
existingConfig.plugins = next
|
|
336
|
+
changed = true
|
|
337
|
+
console.log(' ✓ Removed plugin from plugins array')
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (existingConfig.agent && existingConfig.agent['glm-quota-exec']) {
|
|
342
|
+
delete existingConfig.agent['glm-quota-exec']
|
|
343
|
+
if (Object.keys(existingConfig.agent).length === 0) {
|
|
344
|
+
delete existingConfig.agent
|
|
345
|
+
}
|
|
346
|
+
changed = true
|
|
347
|
+
console.log(' ✓ Removed glm-quota-exec agent config')
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (changed) {
|
|
351
|
+
writeConfig(TARGET_CONFIG, existingConfig)
|
|
352
|
+
console.log(` ✓ Updated ${path.basename(TARGET_CONFIG)}`)
|
|
353
|
+
} else {
|
|
354
|
+
console.log(' ⊙ No config changes needed')
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Remove npm package
|
|
360
|
+
*/
|
|
361
|
+
function removePackage(globalFlag) {
|
|
362
|
+
const args = ['remove', 'opencode-glm-quota']
|
|
363
|
+
if (globalFlag) {
|
|
364
|
+
args.push('--global')
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const result = spawnSync('npm', args, { stdio: 'inherit' })
|
|
368
|
+
if (result.status !== 0) {
|
|
369
|
+
console.log(' ⊙ npm remove failed, remove manually if needed')
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Uninstall integration files and configuration
|
|
375
|
+
*/
|
|
376
|
+
function uninstall(globalFlag) {
|
|
377
|
+
// Remove GLM Quota files
|
|
378
|
+
removeFile(TARGET_COMMAND, TARGET_COMMAND)
|
|
379
|
+
removeDirectory(path.dirname(TARGET_SKILL), path.dirname(TARGET_SKILL))
|
|
380
|
+
removeFile(TARGET_AGENT, TARGET_AGENT)
|
|
381
|
+
|
|
382
|
+
// Remove Copilot Quota files
|
|
383
|
+
removeFile(TARGET_COPILOT_COMMAND, TARGET_COPILOT_COMMAND)
|
|
384
|
+
removeDirectory(path.dirname(TARGET_COPILOT_SKILL), path.dirname(TARGET_COPILOT_SKILL))
|
|
385
|
+
removeFile(TARGET_COPILOT_AGENT, TARGET_COPILOT_AGENT)
|
|
386
|
+
|
|
387
|
+
removeConfig()
|
|
388
|
+
removePackage(globalFlag)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// ==========================================
|
|
392
|
+
// MAIN INSTALLATION FUNCTION
|
|
393
|
+
// ==========================================
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Main installer function
|
|
397
|
+
*/
|
|
398
|
+
function main() {
|
|
399
|
+
try {
|
|
400
|
+
// Parse command line arguments
|
|
401
|
+
const args = process.argv.slice(2)
|
|
402
|
+
const isUninstall = args.includes('uninstall')
|
|
403
|
+
const forceFlag = args.includes('--force')
|
|
404
|
+
const globalFlag = args.includes('--global') || args.includes('-g')
|
|
405
|
+
|
|
406
|
+
if (isUninstall) {
|
|
407
|
+
console.log('✓ Uninstalling GLM Quota Plugin...\n')
|
|
408
|
+
uninstall(globalFlag)
|
|
409
|
+
console.log()
|
|
410
|
+
console.log('✓ Uninstall complete!')
|
|
411
|
+
return
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
console.log('✓ Installing GLM Quota Plugin...\n')
|
|
415
|
+
|
|
416
|
+
// Install integration files
|
|
417
|
+
installCommand(forceFlag)
|
|
418
|
+
installSkill(forceFlag)
|
|
419
|
+
installAgent(forceFlag)
|
|
420
|
+
|
|
421
|
+
// Copilot Quota installation
|
|
422
|
+
installCopilotCommand(forceFlag)
|
|
423
|
+
installCopilotSkill(forceFlag)
|
|
424
|
+
installCopilotAgent(forceFlag)
|
|
425
|
+
|
|
426
|
+
updatePluginConfig()
|
|
427
|
+
|
|
428
|
+
console.log()
|
|
429
|
+
console.log('✓ Installation complete!')
|
|
430
|
+
console.log('✓ Restart OpenCode to use /glm_quota and /copilot_quota commands')
|
|
431
|
+
} catch (error) {
|
|
432
|
+
console.error(`\n✗ Installation failed: ${error instanceof Error ? error.message : String(error)}`)
|
|
433
|
+
console.error('✗ Check file permissions and try again')
|
|
434
|
+
process.exit(1)
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Run installer
|
|
439
|
+
main()
|