@simonyea/holysheep-cli 2.1.40 → 2.1.42

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.
Files changed (45) hide show
  1. package/dist/configure-worker.js +4510 -0
  2. package/dist/index.js +9610 -0
  3. package/dist/process-proxy-inject.js +117 -0
  4. package/package.json +19 -6
  5. package/.gitea/workflows/sanity.yml +0 -125
  6. package/scripts/check-tarball-size.js +0 -44
  7. package/src/commands/balance.js +0 -57
  8. package/src/commands/claude-proxy.js +0 -248
  9. package/src/commands/claude.js +0 -135
  10. package/src/commands/doctor.js +0 -282
  11. package/src/commands/login.js +0 -211
  12. package/src/commands/openclaw.js +0 -258
  13. package/src/commands/reset.js +0 -53
  14. package/src/commands/setup.js +0 -493
  15. package/src/commands/upgrade.js +0 -168
  16. package/src/commands/webui.js +0 -622
  17. package/src/index.js +0 -226
  18. package/src/tools/aider.js +0 -78
  19. package/src/tools/antigravity.js +0 -42
  20. package/src/tools/claude-code.js +0 -228
  21. package/src/tools/claude-process-proxy.js +0 -1030
  22. package/src/tools/codex.js +0 -254
  23. package/src/tools/continue.js +0 -146
  24. package/src/tools/cursor.js +0 -71
  25. package/src/tools/droid.js +0 -281
  26. package/src/tools/env-config.js +0 -185
  27. package/src/tools/gemini-cli.js +0 -82
  28. package/src/tools/hermes.js +0 -354
  29. package/src/tools/index.js +0 -13
  30. package/src/tools/openclaw-bridge.js +0 -987
  31. package/src/tools/openclaw.js +0 -925
  32. package/src/tools/opencode.js +0 -227
  33. package/src/tools/process-proxy-inject.js +0 -142
  34. package/src/utils/config.js +0 -54
  35. package/src/utils/shell.js +0 -342
  36. package/src/utils/which.js +0 -176
  37. package/src/webui/aionui-runtime-fetcher.js +0 -429
  38. package/src/webui/aionui-runtime.js +0 -139
  39. package/src/webui/aionui-wrapper.js +0 -734
  40. package/src/webui/configure-worker.js +0 -67
  41. package/src/webui/server.js +0 -1572
  42. package/src/webui/workspace-runtime.js +0 -288
  43. package/src/webui/workspace-store.js +0 -325
  44. /package/{src/webui → dist}/index.html +0 -0
  45. /package/{src/tools → dist}/pty-hermes-wrapper.py +0 -0
@@ -1,288 +0,0 @@
1
- 'use strict'
2
-
3
- const fetch = require('node-fetch')
4
- const {
5
- addMessage,
6
- createConversation,
7
- ensureConversation,
8
- getConversation,
9
- getHolySheepApiConfig,
10
- listTasks,
11
- updateConversation,
12
- updateTaskRun,
13
- } = require('./workspace-store')
14
- const { getApiKey, BASE_URL_OPENAI } = require('../utils/config')
15
-
16
- const schedulerHandles = new Map()
17
-
18
- function normalizeRuntimeConfig(config = {}) {
19
- const saved = getHolySheepApiConfig()
20
- const apiKey = String(config.apiKey || saved.apiKey || getApiKey() || '').trim()
21
- const baseUrl = String(config.baseUrl || saved.baseUrl || BASE_URL_OPENAI).replace(/\/+$/, '')
22
- const model = String(config.model || saved.model || '').trim()
23
- return { apiKey, baseUrl, model }
24
- }
25
-
26
- function assertRuntimeConfig(config) {
27
- if (!config.apiKey || !config.apiKey.startsWith('cr_')) {
28
- throw new Error('HolySheep API Key is required')
29
- }
30
- if (!config.baseUrl) {
31
- throw new Error('HolySheep API Base URL is required')
32
- }
33
- if (!config.model) {
34
- throw new Error('HolySheep API model is required')
35
- }
36
- }
37
-
38
- function buildSystemPrompt(toolId) {
39
- const toolName = String(toolId || 'codex')
40
- return [
41
- `You are operating inside HolySheep Workspace.`,
42
- `The selected coding tool is "${toolName}".`,
43
- `Respond with concise, implementation-focused guidance suitable for a coding assistant workspace.`,
44
- `When you mention commands, prefer copy-paste-ready shell commands.`,
45
- ].join(' ')
46
- }
47
-
48
- async function requestCompletion(messages, config) {
49
- const controller = new AbortController()
50
- const timeout = setTimeout(() => controller.abort(), 20_000)
51
- let response
52
- try {
53
- response = await fetch(`${config.baseUrl}/chat/completions`, {
54
- method: 'POST',
55
- headers: {
56
- Authorization: `Bearer ${config.apiKey}`,
57
- 'Content-Type': 'application/json',
58
- },
59
- body: JSON.stringify({
60
- model: config.model,
61
- temperature: 0.2,
62
- messages,
63
- }),
64
- signal: controller.signal,
65
- })
66
- } catch (error) {
67
- if (error.name === 'AbortError') {
68
- throw new Error('HolySheep API request timed out')
69
- }
70
- throw error
71
- } finally {
72
- clearTimeout(timeout)
73
- }
74
-
75
- const payload = await response.json().catch(() => null)
76
- if (!response.ok) {
77
- const reason = payload?.error?.message || payload?.message || `HTTP ${response.status}`
78
- throw new Error(reason)
79
- }
80
-
81
- const content = payload?.choices?.[0]?.message?.content
82
- if (typeof content === 'string' && content.trim()) return content.trim()
83
- if (Array.isArray(content)) {
84
- const text = content
85
- .map((part) => {
86
- if (typeof part === 'string') return part
87
- if (typeof part?.text === 'string') return part.text
88
- if (typeof part?.content === 'string') return part.content
89
- return ''
90
- })
91
- .filter(Boolean)
92
- .join('\n')
93
- .trim()
94
- if (text) return text
95
- }
96
- const fallbacks = [
97
- payload?.choices?.[0]?.text,
98
- payload?.output_text,
99
- payload?.response,
100
- payload?.message,
101
- ]
102
- for (const item of fallbacks) {
103
- if (typeof item === 'string' && item.trim()) return item.trim()
104
- }
105
- if (Array.isArray(payload?.output)) {
106
- const text = payload.output
107
- .map((part) => {
108
- if (typeof part?.content === 'string') return part.content
109
- if (typeof part?.text === 'string') return part.text
110
- if (Array.isArray(part?.content)) {
111
- return part.content.map((child) => child?.text || child?.content || '').join('\n')
112
- }
113
- return ''
114
- })
115
- .filter(Boolean)
116
- .join('\n')
117
- .trim()
118
- if (text) return text
119
- }
120
- return 'No response content returned.'
121
- }
122
-
123
- async function sendConversationMessage(conversationId, input, options = {}) {
124
- const conversation = ensureConversation(conversationId)
125
- const config = normalizeRuntimeConfig(options)
126
- assertRuntimeConfig(config)
127
-
128
- const userMessage = addMessage(conversationId, {
129
- role: 'user',
130
- content: String(input || ''),
131
- meta: {
132
- source: 'workspace',
133
- },
134
- })
135
-
136
- try {
137
- const messages = [
138
- { role: 'system', content: buildSystemPrompt(conversation.toolId) },
139
- ...conversation.messages
140
- .concat(userMessage)
141
- .map((message) => ({
142
- role: message.role,
143
- content: message.content,
144
- })),
145
- ]
146
- const reply = await requestCompletion(messages, config)
147
- const assistantMessage = addMessage(conversationId, {
148
- role: 'assistant',
149
- content: reply,
150
- meta: {
151
- model: config.model,
152
- source: 'holysheep-api',
153
- },
154
- })
155
- updateConversation(conversationId, {
156
- summary: reply.slice(0, 240),
157
- })
158
- return { userMessage, assistantMessage }
159
- } catch (error) {
160
- const assistantMessage = addMessage(conversationId, {
161
- role: 'assistant',
162
- content: `Error: ${error.message}`,
163
- status: 'error',
164
- meta: {
165
- model: config.model,
166
- source: 'holysheep-api',
167
- },
168
- })
169
- updateConversation(conversationId, {
170
- summary: assistantMessage.content.slice(0, 240),
171
- })
172
- throw error
173
- }
174
- }
175
-
176
- function parseScheduleToMs(schedule) {
177
- const value = String(schedule || '').trim().toLowerCase()
178
- const match = value.match(/^(\d+)\s*([smhd])$/)
179
- if (!match) throw new Error('Schedule must use format like 30s, 5m, 1h, 1d')
180
- const amount = Number(match[1])
181
- const unit = match[2]
182
- if (!Number.isFinite(amount) || amount <= 0) throw new Error('Invalid schedule amount')
183
- const factors = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }
184
- return amount * factors[unit]
185
- }
186
-
187
- async function runTask(taskId, options = {}) {
188
- const task = listTasks().find((item) => item.id === taskId)
189
- if (!task) throw new Error('Task not found')
190
-
191
- const config = normalizeRuntimeConfig({
192
- ...options,
193
- model: task.modelOverride || options.model,
194
- })
195
- assertRuntimeConfig(config)
196
- updateTaskRun(taskId, {
197
- lastStatus: 'running',
198
- })
199
-
200
- let conversationId = task.conversationId
201
- if (!conversationId) {
202
- const conversation = createConversation({
203
- title: task.title,
204
- toolId: 'codex',
205
- })
206
- conversationId = conversation.id
207
- updateTaskRun(taskId, { conversationId })
208
- }
209
-
210
- try {
211
- const { assistantMessage } = await sendConversationMessage(conversationId, task.prompt, config)
212
- updateTaskRun(taskId, {
213
- lastRunAt: new Date().toISOString(),
214
- lastStatus: 'ok',
215
- lastResult: assistantMessage.content,
216
- conversationId,
217
- })
218
- return assistantMessage
219
- } catch (error) {
220
- updateTaskRun(taskId, {
221
- lastRunAt: new Date().toISOString(),
222
- lastStatus: 'error',
223
- lastResult: error.message,
224
- conversationId,
225
- })
226
- throw error
227
- }
228
- }
229
-
230
- function clearTaskHandle(taskId) {
231
- const existing = schedulerHandles.get(taskId)
232
- if (!existing) return
233
- clearInterval(existing)
234
- schedulerHandles.delete(taskId)
235
- }
236
-
237
- function scheduleTask(task) {
238
- clearTaskHandle(task.id)
239
- if (!task.active) return
240
-
241
- let intervalMs
242
- try {
243
- intervalMs = parseScheduleToMs(task.schedule)
244
- } catch {
245
- return
246
- }
247
-
248
- const handle = setInterval(() => {
249
- void runTask(task.id).catch(() => {})
250
- }, intervalMs)
251
- schedulerHandles.set(task.id, handle)
252
- }
253
-
254
- function rescheduleAllTasks() {
255
- const tasks = listTasks()
256
- const seen = new Set(tasks.map((task) => task.id))
257
- for (const taskId of schedulerHandles.keys()) {
258
- if (!seen.has(taskId)) {
259
- clearTaskHandle(taskId)
260
- }
261
- }
262
- for (const task of tasks) {
263
- scheduleTask(task)
264
- }
265
- }
266
-
267
- function stopScheduler() {
268
- for (const taskId of schedulerHandles.keys()) {
269
- clearTaskHandle(taskId)
270
- }
271
- }
272
-
273
- function startScheduler() {
274
- rescheduleAllTasks()
275
- }
276
-
277
- module.exports = {
278
- normalizeRuntimeConfig,
279
- assertRuntimeConfig,
280
- sendConversationMessage,
281
- parseScheduleToMs,
282
- runTask,
283
- startScheduler,
284
- stopScheduler,
285
- rescheduleAllTasks,
286
- createConversation,
287
- getConversation,
288
- }
@@ -1,325 +0,0 @@
1
- 'use strict'
2
-
3
- const fs = require('fs')
4
- const path = require('path')
5
- const crypto = require('crypto')
6
- const { CONFIG_DIR } = require('../utils/config')
7
-
8
- const STATE_FILE = path.join(CONFIG_DIR, 'workspace-state.json')
9
- const STATE_VERSION = 1
10
-
11
- function now() {
12
- return new Date().toISOString()
13
- }
14
-
15
- function createDefaultState() {
16
- return {
17
- version: STATE_VERSION,
18
- updatedAt: now(),
19
- holySheepApi: {
20
- apiKey: '',
21
- baseUrl: '',
22
- model: '',
23
- },
24
- conversations: [],
25
- scheduledTasks: [],
26
- }
27
- }
28
-
29
- function ensureDir() {
30
- fs.mkdirSync(CONFIG_DIR, { recursive: true })
31
- }
32
-
33
- function clone(value) {
34
- return JSON.parse(JSON.stringify(value))
35
- }
36
-
37
- function normalizeConversation(item = {}) {
38
- const createdAt = item.createdAt || now()
39
- const messages = Array.isArray(item.messages)
40
- ? item.messages.map((message) => ({
41
- id: message.id || crypto.randomUUID(),
42
- role: message.role === 'assistant' ? 'assistant' : 'user',
43
- content: String(message.content || ''),
44
- status: message.status || 'done',
45
- createdAt: message.createdAt || createdAt,
46
- meta: typeof message.meta === 'object' && message.meta ? message.meta : {},
47
- }))
48
- : []
49
-
50
- const lastMessage = messages[messages.length - 1] || null
51
-
52
- return {
53
- id: item.id || crypto.randomUUID().slice(0, 8),
54
- title: String(item.title || 'New Conversation'),
55
- toolId: String(item.toolId || 'codex'),
56
- createdAt,
57
- updatedAt: item.updatedAt || lastMessage?.createdAt || createdAt,
58
- pinned: Boolean(item.pinned),
59
- summary: String(item.summary || lastMessage?.content || '').slice(0, 240),
60
- messages,
61
- }
62
- }
63
-
64
- function normalizeTask(item = {}) {
65
- return {
66
- id: item.id || crypto.randomUUID().slice(0, 8),
67
- title: String(item.title || 'Untitled Task'),
68
- prompt: String(item.prompt || ''),
69
- schedule: String(item.schedule || '1h'),
70
- active: item.active !== false,
71
- createdAt: item.createdAt || now(),
72
- updatedAt: item.updatedAt || now(),
73
- lastRunAt: item.lastRunAt || null,
74
- lastStatus: item.lastStatus || 'idle',
75
- lastResult: String(item.lastResult || ''),
76
- conversationId: item.conversationId || null,
77
- modelOverride: item.modelOverride ? String(item.modelOverride) : '',
78
- }
79
- }
80
-
81
- function normalizeState(raw = {}) {
82
- const state = createDefaultState()
83
- state.holySheepApi = {
84
- ...state.holySheepApi,
85
- ...(typeof raw.holySheepApi === 'object' && raw.holySheepApi ? raw.holySheepApi : {}),
86
- }
87
- state.conversations = Array.isArray(raw.conversations) ? raw.conversations.map(normalizeConversation) : []
88
- state.scheduledTasks = Array.isArray(raw.scheduledTasks) ? raw.scheduledTasks.map(normalizeTask) : []
89
- state.updatedAt = raw.updatedAt || now()
90
- return state
91
- }
92
-
93
- function loadState() {
94
- ensureDir()
95
- try {
96
- if (!fs.existsSync(STATE_FILE)) {
97
- return createDefaultState()
98
- }
99
- return normalizeState(JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')))
100
- } catch {
101
- return createDefaultState()
102
- }
103
- }
104
-
105
- function saveState(next) {
106
- ensureDir()
107
- const normalized = normalizeState(next)
108
- normalized.updatedAt = now()
109
- fs.writeFileSync(STATE_FILE, JSON.stringify(normalized, null, 2), 'utf8')
110
- return normalized
111
- }
112
-
113
- function updateState(mutator) {
114
- const current = loadState()
115
- const draft = clone(current)
116
- const result = mutator(draft) || draft
117
- return saveState(result)
118
- }
119
-
120
- function sortConversations(items) {
121
- return [...items].sort((a, b) => {
122
- if (a.pinned !== b.pinned) return a.pinned ? -1 : 1
123
- return Date.parse(b.updatedAt) - Date.parse(a.updatedAt)
124
- })
125
- }
126
-
127
- function listConversations() {
128
- return sortConversations(loadState().conversations).map((item) => ({
129
- id: item.id,
130
- title: item.title,
131
- toolId: item.toolId,
132
- pinned: item.pinned,
133
- summary: item.summary,
134
- createdAt: item.createdAt,
135
- updatedAt: item.updatedAt,
136
- messageCount: item.messages.length,
137
- }))
138
- }
139
-
140
- function getConversation(id) {
141
- return loadState().conversations.find((item) => item.id === id) || null
142
- }
143
-
144
- function ensureConversation(id) {
145
- const conversation = getConversation(id)
146
- if (!conversation) throw new Error('Conversation not found')
147
- return conversation
148
- }
149
-
150
- function createConversation(payload = {}) {
151
- const conversation = normalizeConversation({
152
- title: payload.title || 'New Conversation',
153
- toolId: payload.toolId || 'codex',
154
- pinned: Boolean(payload.pinned),
155
- })
156
- updateState((state) => {
157
- state.conversations.unshift(conversation)
158
- })
159
- return conversation
160
- }
161
-
162
- function updateConversation(id, patch = {}) {
163
- let updated = null
164
- updateState((state) => {
165
- const index = state.conversations.findIndex((item) => item.id === id)
166
- if (index === -1) throw new Error('Conversation not found')
167
- const current = state.conversations[index]
168
- updated = normalizeConversation({
169
- ...current,
170
- ...patch,
171
- messages: patch.messages || current.messages,
172
- updatedAt: now(),
173
- })
174
- state.conversations[index] = updated
175
- })
176
- return updated
177
- }
178
-
179
- function addMessage(conversationId, payload = {}) {
180
- let updated = null
181
- updateState((state) => {
182
- const conversation = state.conversations.find((item) => item.id === conversationId)
183
- if (!conversation) throw new Error('Conversation not found')
184
- const message = {
185
- id: payload.id || crypto.randomUUID(),
186
- role: payload.role === 'assistant' ? 'assistant' : 'user',
187
- content: String(payload.content || ''),
188
- status: payload.status || 'done',
189
- createdAt: payload.createdAt || now(),
190
- meta: typeof payload.meta === 'object' && payload.meta ? payload.meta : {},
191
- }
192
- conversation.messages.push(message)
193
- conversation.updatedAt = message.createdAt
194
- if (!conversation.summary || message.role === 'assistant') {
195
- conversation.summary = message.content.slice(0, 240)
196
- }
197
- updated = clone(message)
198
- })
199
- return updated
200
- }
201
-
202
- function searchWorkspace(query) {
203
- const needle = String(query || '').trim().toLowerCase()
204
- if (!needle) return { conversations: [], tasks: [] }
205
-
206
- const state = loadState()
207
- const conversations = state.conversations
208
- .filter((item) => {
209
- if (item.title.toLowerCase().includes(needle)) return true
210
- if (String(item.summary || '').toLowerCase().includes(needle)) return true
211
- return item.messages.some((message) => String(message.content || '').toLowerCase().includes(needle))
212
- })
213
- .map((item) => ({
214
- id: item.id,
215
- title: item.title,
216
- summary: item.summary,
217
- updatedAt: item.updatedAt,
218
- toolId: item.toolId,
219
- }))
220
-
221
- const tasks = state.scheduledTasks
222
- .filter((item) => {
223
- return item.title.toLowerCase().includes(needle) || item.prompt.toLowerCase().includes(needle)
224
- })
225
- .map((item) => ({
226
- id: item.id,
227
- title: item.title,
228
- prompt: item.prompt.slice(0, 180),
229
- schedule: item.schedule,
230
- active: item.active,
231
- updatedAt: item.updatedAt,
232
- }))
233
-
234
- return { conversations, tasks }
235
- }
236
-
237
- function listTasks() {
238
- return [...loadState().scheduledTasks].sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt))
239
- }
240
-
241
- function getTask(id) {
242
- return loadState().scheduledTasks.find((item) => item.id === id) || null
243
- }
244
-
245
- function saveTask(payload = {}) {
246
- let result = null
247
- updateState((state) => {
248
- if (payload.id) {
249
- const index = state.scheduledTasks.findIndex((item) => item.id === payload.id)
250
- if (index === -1) throw new Error('Task not found')
251
- result = normalizeTask({
252
- ...state.scheduledTasks[index],
253
- ...payload,
254
- updatedAt: now(),
255
- })
256
- state.scheduledTasks[index] = result
257
- return
258
- }
259
- result = normalizeTask({
260
- ...payload,
261
- createdAt: now(),
262
- updatedAt: now(),
263
- })
264
- state.scheduledTasks.unshift(result)
265
- })
266
- return result
267
- }
268
-
269
- function deleteTask(id) {
270
- updateState((state) => {
271
- state.scheduledTasks = state.scheduledTasks.filter((item) => item.id !== id)
272
- })
273
- }
274
-
275
- function updateTaskRun(id, patch = {}) {
276
- let result = null
277
- updateState((state) => {
278
- const index = state.scheduledTasks.findIndex((item) => item.id === id)
279
- if (index === -1) throw new Error('Task not found')
280
- result = normalizeTask({
281
- ...state.scheduledTasks[index],
282
- ...patch,
283
- updatedAt: now(),
284
- })
285
- state.scheduledTasks[index] = result
286
- })
287
- return result
288
- }
289
-
290
- function getHolySheepApiConfig() {
291
- return loadState().holySheepApi
292
- }
293
-
294
- function saveHolySheepApiConfig(config = {}) {
295
- let result = null
296
- updateState((state) => {
297
- state.holySheepApi = {
298
- apiKey: String(config.apiKey || state.holySheepApi.apiKey || ''),
299
- baseUrl: String(config.baseUrl || state.holySheepApi.baseUrl || ''),
300
- model: String(config.model || state.holySheepApi.model || ''),
301
- }
302
- result = clone(state.holySheepApi)
303
- })
304
- return result
305
- }
306
-
307
- module.exports = {
308
- STATE_FILE,
309
- loadState,
310
- saveState,
311
- listConversations,
312
- getConversation,
313
- createConversation,
314
- updateConversation,
315
- addMessage,
316
- searchWorkspace,
317
- listTasks,
318
- getTask,
319
- saveTask,
320
- deleteTask,
321
- updateTaskRun,
322
- getHolySheepApiConfig,
323
- saveHolySheepApiConfig,
324
- ensureConversation,
325
- }
File without changes
File without changes