profclaw 0.0.1-beta.1 → 0.0.1-beta.2
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 +1 -1
- package/dist/adapters/openclaw.js +1 -1
- package/dist/agents/executor.js +38 -6
- package/dist/auth/auth-service.js +8 -6
- package/dist/auth/device-identity.js +7 -5
- package/dist/auth/github-oauth.js +3 -1
- package/dist/auth/pairing-codes.js +6 -4
- package/dist/browser/service.js +5 -3
- package/dist/chat/execution/guardrails.js +3 -1
- package/dist/chat/execution/workflows/executor.js +4 -2
- package/dist/chat/memory.js +3 -1
- package/dist/chat/proactive/index.js +13 -11
- package/dist/chat/tools.js +8 -7
- package/dist/cli/commands/auth.js +22 -13
- package/dist/cli/commands/onboard.js +248 -59
- package/dist/cli/commands/setup.js +180 -104
- package/dist/cron/issue-poller.js +1 -1
- package/dist/hooks/agent-webhook.js +10 -7
- package/dist/hooks/prompt-submit.js +5 -6
- package/dist/hooks/session-end.js +10 -6
- package/dist/hooks/tool-use.js +9 -6
- package/dist/integrations/github-ticket-sync.js +8 -6
- package/dist/integrations/github.js +8 -6
- package/dist/integrations/jira.js +5 -3
- package/dist/mcp/server.js +12 -9
- package/dist/memory/experience-store.js +15 -14
- package/dist/notifications/slack.js +4 -2
- package/dist/providers/types.d.ts +2 -2
- package/dist/queue/failure-handler.js +15 -13
- package/dist/queue/index.js +6 -4
- package/dist/queue/memory-queue.js +23 -27
- package/dist/queue/task-queue.js +18 -22
- package/dist/routes/agents.js +3 -1
- package/dist/routes/auth.js +11 -9
- package/dist/routes/devices.js +17 -15
- package/dist/routes/gateway.js +3 -1
- package/dist/routes/hooks.js +7 -5
- package/dist/routes/import.js +10 -8
- package/dist/routes/labels.js +11 -9
- package/dist/routes/oobe.js +8 -6
- package/dist/routes/openapi.js +1 -1
- package/dist/routes/projects.js +27 -25
- package/dist/routes/settings.js +7 -5
- package/dist/routes/setup.js +12 -11
- package/dist/routes/slack.js +28 -27
- package/dist/routes/stats.js +6 -4
- package/dist/routes/summaries.js +4 -3
- package/dist/routes/sync.js +7 -5
- package/dist/routes/tasks.js +10 -8
- package/dist/routes/tickets.js +26 -26
- package/dist/routes/tokens.js +5 -3
- package/dist/routes/users.js +14 -12
- package/dist/routes/webhooks.js +5 -3
- package/dist/settings/index.js +3 -1
- package/dist/storage/index.d.ts +2 -1
- package/dist/storage/index.js +9 -4
- package/dist/storage/libsql.js +29 -21
- package/dist/storage/schema.d.ts +107 -46
- package/dist/summaries/storage.js +3 -1
- package/dist/tickets/index.js +10 -8
- package/dist/utils/circuit-breaker.js +10 -5
- package/dist/utils/logger.d.ts +5 -1
- package/dist/utils/logger.js +23 -7
- package/package.json +4 -3
- package/ui/dist/assets/{ActivityView-CkPgKhwm.js → ActivityView-DIPQSJ_d.js} +1 -1
- package/ui/dist/assets/{AgentList-C3SVdeEz.js → AgentList-CqyaYrcq.js} +1 -1
- package/ui/dist/assets/{AnalyticsDashboard-DVU--vlP.js → AnalyticsDashboard-C-mjuGHT.js} +1 -1
- package/ui/dist/assets/{AreaChart-B5qMEGWj.js → AreaChart-CfYWmbtr.js} +1 -1
- package/ui/dist/assets/{CartesianChart-B50bcUJi.js → CartesianChart-BaQ3It0c.js} +1 -1
- package/ui/dist/assets/{ChatView-BZFJs7w_.js → ChatView-DxxQy6pl.js} +1 -1
- package/ui/dist/assets/CostsDashboard-CDBBcGkg.js +1 -0
- package/ui/dist/assets/{EstimateSelect-CLpB4NQO.js → EstimateSelect-CDjf5qKl.js} +1 -1
- package/ui/dist/assets/{FloatingChatbot-CBzBY9a0.js → FloatingChatbot-CZHjvJIe.js} +1 -1
- package/ui/dist/assets/{InviteCodeManagement-DsbdPa6W.js → InviteCodeManagement-DTm-IPTm.js} +1 -1
- package/ui/dist/assets/{ProjectDetail-BEM3tFXg.js → ProjectDetail-DlYUcOss.js} +1 -1
- package/ui/dist/assets/{ProjectIcon-CN1FmFAk.js → ProjectIcon-BMRpnM04.js} +1 -1
- package/ui/dist/assets/{ProjectList-DSDaNhxQ.js → ProjectList-D85TN0i0.js} +1 -1
- package/ui/dist/assets/{Settings-dPVcqC_d.js → Settings-CgPqzUvj.js} +3 -3
- package/ui/dist/assets/{StatusIndicator-DA3NAo_b.js → StatusIndicator-yig0uZEA.js} +1 -1
- package/ui/dist/assets/{SummaryDetail-Bjnf9lT8.js → SummaryDetail-CwLAfHgJ.js} +1 -1
- package/ui/dist/assets/{SummaryList-ENwKDBKW.js → SummaryList-BvS5Idnu.js} +1 -1
- package/ui/dist/assets/{TaskDetail-DnwG6MzB.js → TaskDetail-zarC1fOt.js} +1 -1
- package/ui/dist/assets/{TaskList-D9Ug_HiV.js → TaskList-CyJq3ANE.js} +1 -1
- package/ui/dist/assets/{TicketBoard-CviH1571.js → TicketBoard-BlWr3-iH.js} +1 -1
- package/ui/dist/assets/{TicketDetail-8Jk8O-33.js → TicketDetail-DmqWKj2W.js} +1 -1
- package/ui/dist/assets/{TicketList-B-iV4rRA.js → TicketList-Scj4pMWa.js} +1 -1
- package/ui/dist/assets/{UserManagement-CPZ8s7s2.js → UserManagement-BH7uG7dw.js} +1 -1
- package/ui/dist/assets/{ViewSwitcher-BUyOOWDI.js → ViewSwitcher-3HzZUdWn.js} +1 -1
- package/ui/dist/assets/{alert-dialog-BOmnTkN-.js → alert-dialog-DWPb2IfQ.js} +1 -1
- package/ui/dist/assets/{archive-D5my9zOG.js → archive-CGck7gxR.js} +1 -1
- package/ui/dist/assets/{badge-B4ov81_m.js → badge-DEmc3Z_l.js} +1 -1
- package/ui/dist/assets/{brain-C53ElFLD.js → brain-CfFdLVqb.js} +1 -1
- package/ui/dist/assets/{bug-D0TJoCYn.js → bug-DqSGPUUE.js} +1 -1
- package/ui/dist/assets/{calendar-BkWIhKa1.js → calendar-BuZ4zbPW.js} +1 -1
- package/ui/dist/assets/{chevron-up-BRTtndUZ.js → chevron-up-DcJ4LL_N.js} +1 -1
- package/ui/dist/assets/{circle-x-BN89YhbS.js → circle-x-C78PNZjF.js} +1 -1
- package/ui/dist/assets/{constants-fc7TFI7u.js → constants-DhDjZe4P.js} +1 -1
- package/ui/dist/assets/{cpu-B41x1-vV.js → cpu-Ck6AoG8c.js} +1 -1
- package/ui/dist/assets/{database-D9Cnfmzj.js → database-CA2w8Lvt.js} +1 -1
- package/ui/dist/assets/{dialog-DrWB4EYD.js → dialog-BOdGWhgE.js} +1 -1
- package/ui/dist/assets/{ellipsis-NuUWekvu.js → ellipsis-FhHKRbfl.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-BueMfuCw.js → ellipsis-vertical-CO0UqE4-.js} +1 -1
- package/ui/dist/assets/{file-code-HR9829Jc.js → file-code-ChnhYYj1.js} +1 -1
- package/ui/dist/assets/{folder-open-C_7oYEqe.js → folder-open-CHwA1-ve.js} +1 -1
- package/ui/dist/assets/{funnel-B5gmNXGf.js → funnel-ByEjRFNB.js} +1 -1
- package/ui/dist/assets/{git-branch-BRMiJmV3.js → git-branch-GTOPQgU4.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-CXOUQeJI.js → git-commit-horizontal-F5M84Kut.js} +1 -1
- package/ui/dist/assets/{globe-CCspjvus.js → globe-CQWfr7hT.js} +1 -1
- package/ui/dist/assets/{hash-g3102kPC.js → hash-nKC9gtLg.js} +1 -1
- package/ui/dist/assets/{history-CNqcBBrV.js → history-DfFSA9xJ.js} +1 -1
- package/ui/dist/assets/{index-kb4AJXUB.js → index--JkIxVXb.js} +3 -3
- package/ui/dist/assets/index-Ca3vk7Gq.js +1 -0
- package/ui/dist/assets/{index-C9jNQXzL.js → index-DHGvP9mp.js} +1 -1
- package/ui/dist/assets/index-DeI8lKRR.js +1 -0
- package/ui/dist/assets/{index-DURTouJI.js → index-Z4-RtZcs.js} +1 -1
- package/ui/dist/assets/{index-CEZ6R2Uw.js → index-a4Fxq0Hb.js} +1 -1
- package/ui/dist/assets/{layers-CLXiHN6o.js → layers-DFeLExSa.js} +1 -1
- package/ui/dist/assets/{layout-dashboard-B07MFhBs.js → layout-dashboard-WmgjMhWF.js} +1 -1
- package/ui/dist/assets/{lightbulb-B2dgG5ks.js → lightbulb-Bo8hEr7B.js} +1 -1
- package/ui/dist/assets/{link-2-BxNmr9hL.js → link-2-YqrpQXBH.js} +1 -1
- package/ui/dist/assets/{markdown-renderer-CjU6hBcW.js → markdown-renderer-Croje6Xe.js} +1 -1
- package/ui/dist/assets/{message-square-Bf2-CVbt.js → message-square-CD0H5hot.js} +1 -1
- package/ui/dist/assets/{pencil-D096Ey62.js → pencil-DpFnj5dn.js} +1 -1
- package/ui/dist/assets/{play-DfdcSI3x.js → play-DVgea_jT.js} +1 -1
- package/ui/dist/assets/{popover-BV0QJDQq.js → popover-JXecfWG5.js} +1 -1
- package/ui/dist/assets/{progress-DjPEDJfI.js → progress-C1ghf1Fu.js} +1 -1
- package/ui/dist/assets/{rocket-CPsTc-5G.js → rocket-BFxPYGx9.js} +1 -1
- package/ui/dist/assets/{select-LsO16slr.js → select-MADP8m6Q.js} +1 -1
- package/ui/dist/assets/{send-BDYBZDUZ.js → send-eYnW_7n-.js} +1 -1
- package/ui/dist/assets/{server-B3k6noce.js → server-CPMaysH8.js} +1 -1
- package/ui/dist/assets/{settings-2-Cu4xTjhG.js → settings-2-scXUOuE_.js} +1 -1
- package/ui/dist/assets/{sheet-BScLnPKX.js → sheet-r6NSOxi-.js} +1 -1
- package/ui/dist/assets/{shield-check-CQqkwufI.js → shield-check-PEr7nmVw.js} +1 -1
- package/ui/dist/assets/{shield-off-ZFruH9KO.js → shield-off-CLtXio62.js} +1 -1
- package/ui/dist/assets/{skeleton-CtkIA_MU.js → skeleton-C9oEzNlU.js} +1 -1
- package/ui/dist/assets/{smartphone-DnoksVkc.js → smartphone-DusFfY0U.js} +1 -1
- package/ui/dist/assets/{square-uD9ZHMfW.js → square-e1yxB2eR.js} +1 -1
- package/ui/dist/assets/{switch-MQPnwGJK.js → switch-tNs0n-kz.js} +1 -1
- package/ui/dist/assets/{table-B8cqlywA.js → table-CXxtLicg.js} +1 -1
- package/ui/dist/assets/{tag-wEJQRWlV.js → tag-tAwMmQ9G.js} +1 -1
- package/ui/dist/assets/{textarea-D5LJCOGl.js → textarea-BjiEeIWh.js} +1 -1
- package/ui/dist/assets/{timer-mbGHegmr.js → timer-Vel1N3RP.js} +1 -1
- package/ui/dist/assets/{tooltip-Df1CunSp.js → tooltip-ZMwtfr1J.js} +1 -1
- package/ui/dist/assets/{trash-2-B4oAXsX-.js → trash-2-eM-CNwsZ.js} +1 -1
- package/ui/dist/assets/{trending-up-BGWxvlmZ.js → trending-up-BGafmjRo.js} +1 -1
- package/ui/dist/assets/{wand-sparkles-CZy4xvL3.js → wand-sparkles-DPvcd9Pi.js} +1 -1
- package/ui/dist/assets/{wrench-ByZkjO6m.js → wrench-B8s3zYVV.js} +1 -1
- package/ui/dist/index.html +1 -1
- package/ui/dist/assets/CostsDashboard-ChfH8BlG.js +0 -1
- package/ui/dist/assets/index-27mTPKuh.js +0 -1
- package/ui/dist/assets/index-BMx3fH-e.js +0 -1
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import { Command } from 'commander';
|
|
12
12
|
import chalk from 'chalk';
|
|
13
13
|
import figlet from 'figlet';
|
|
14
|
-
import {
|
|
14
|
+
import { select, input, password as passwordPrompt, confirm } from '@inquirer/prompts';
|
|
15
15
|
import { randomUUID } from 'crypto';
|
|
16
16
|
import { eq } from 'drizzle-orm';
|
|
17
17
|
import { initStorage, getDb, saveProviderConfig } from '../../storage/index.js';
|
|
@@ -28,36 +28,8 @@ function showBanner() {
|
|
|
28
28
|
console.log(chalk.cyan(banner));
|
|
29
29
|
console.log(chalk.dim(' Setup Wizard\n'));
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return answer.trim();
|
|
34
|
-
}
|
|
35
|
-
async function promptPassword(rl, question) {
|
|
36
|
-
// readline/promises doesn't natively hide input, but for a CLI wizard this is acceptable
|
|
37
|
-
const answer = await rl.question(chalk.bold(question));
|
|
38
|
-
return answer.trim();
|
|
39
|
-
}
|
|
40
|
-
async function promptChoice(rl, question, options) {
|
|
41
|
-
console.log('');
|
|
42
|
-
console.log(chalk.bold(question));
|
|
43
|
-
for (const opt of options) {
|
|
44
|
-
console.log(` ${chalk.cyan(opt.key)}) ${opt.label}`);
|
|
45
|
-
}
|
|
46
|
-
const validKeys = options.map((o) => o.key);
|
|
47
|
-
while (true) {
|
|
48
|
-
const answer = await prompt(rl, `Choice [${validKeys.join('/')}]: `);
|
|
49
|
-
if (validKeys.includes(answer))
|
|
50
|
-
return answer;
|
|
51
|
-
console.log(chalk.red(` Invalid choice. Options: ${validKeys.join(', ')}`));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
async function promptYesNo(rl, question, defaultYes = false) {
|
|
55
|
-
const hint = defaultYes ? 'Y/n' : 'y/N';
|
|
56
|
-
const answer = await prompt(rl, `${question} [${hint}]: `);
|
|
57
|
-
if (!answer)
|
|
58
|
-
return defaultYes;
|
|
59
|
-
return answer.toLowerCase().startsWith('y');
|
|
60
|
-
}
|
|
31
|
+
// Inquirer theme for consistent prefix
|
|
32
|
+
const theme = { prefix: ' ', style: { highlight: (text) => chalk.cyan.bold(text) } };
|
|
61
33
|
async function checkRedis() {
|
|
62
34
|
try {
|
|
63
35
|
const IORedis = (await import('ioredis')).default;
|
|
@@ -172,43 +144,72 @@ async function stepSystemCheck(db) {
|
|
|
172
144
|
return { redisOk, hasAdmin, hasAnthropicKey, hasOpenAIKey };
|
|
173
145
|
}
|
|
174
146
|
// Step 2: AI Provider
|
|
175
|
-
async function stepAiProvider(
|
|
147
|
+
async function stepAiProvider(status) {
|
|
176
148
|
if (status.hasAnthropicKey || status.hasOpenAIKey) {
|
|
177
149
|
const provider = status.hasAnthropicKey ? 'Anthropic' : 'OpenAI';
|
|
178
150
|
info(`AI provider already configured (${provider} from env).`);
|
|
179
|
-
|
|
180
|
-
|
|
151
|
+
try {
|
|
152
|
+
const reconfigure = await confirm({
|
|
153
|
+
message: 'Reconfigure AI provider?',
|
|
154
|
+
default: false,
|
|
155
|
+
theme,
|
|
156
|
+
});
|
|
157
|
+
if (!reconfigure)
|
|
158
|
+
return 'skip';
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
181
161
|
return 'skip';
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
let choice;
|
|
165
|
+
try {
|
|
166
|
+
choice = await select({
|
|
167
|
+
message: 'Select AI Provider',
|
|
168
|
+
choices: [
|
|
169
|
+
{ name: `Anthropic ${chalk.green('(recommended)')}`, value: 'anthropic', description: 'Claude 4.x, 3.5 Sonnet' },
|
|
170
|
+
{ name: 'OpenAI', value: 'openai', description: 'GPT-4o, o1, o3' },
|
|
171
|
+
{ name: `Ollama ${chalk.cyan('(free, local)')}`, value: 'ollama', description: 'Llama, Mistral, Qwen - runs on your machine' },
|
|
172
|
+
{ name: chalk.dim('Skip for now'), value: 'skip', description: 'Configure later in Settings' },
|
|
173
|
+
],
|
|
174
|
+
theme,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
catch {
|
|
178
|
+
return 'skip';
|
|
182
179
|
}
|
|
183
|
-
|
|
184
|
-
{ key: '1', label: 'Anthropic API Key (recommended)' },
|
|
185
|
-
{ key: '2', label: 'OpenAI API Key' },
|
|
186
|
-
{ key: '3', label: 'Ollama (free, local AI)' },
|
|
187
|
-
{ key: '4', label: 'Skip for now' },
|
|
188
|
-
]);
|
|
189
|
-
if (choice === '4') {
|
|
180
|
+
if (choice === 'skip') {
|
|
190
181
|
info('AI provider skipped. You can configure it later in Settings.');
|
|
191
182
|
return 'skip';
|
|
192
183
|
}
|
|
193
|
-
if (choice === '
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
184
|
+
if (choice === 'anthropic') {
|
|
185
|
+
try {
|
|
186
|
+
const apiKey = await input({ message: 'Anthropic API Key', theme });
|
|
187
|
+
if (!apiKey) {
|
|
188
|
+
warn('No key provided, skipping.');
|
|
189
|
+
return 'skip';
|
|
190
|
+
}
|
|
191
|
+
await saveProviderConfig({ type: 'anthropic', apiKey, enabled: true });
|
|
192
|
+
success('Anthropic provider configured.');
|
|
193
|
+
return 'anthropic';
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
197
196
|
return 'skip';
|
|
198
197
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
}
|
|
199
|
+
if (choice === 'openai') {
|
|
200
|
+
try {
|
|
201
|
+
const apiKey = await input({ message: 'OpenAI API Key', theme });
|
|
202
|
+
if (!apiKey) {
|
|
203
|
+
warn('No key provided, skipping.');
|
|
204
|
+
return 'skip';
|
|
205
|
+
}
|
|
206
|
+
await saveProviderConfig({ type: 'openai', apiKey, enabled: true });
|
|
207
|
+
success('OpenAI provider configured.');
|
|
208
|
+
return 'openai';
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
207
211
|
return 'skip';
|
|
208
212
|
}
|
|
209
|
-
await saveProviderConfig({ type: 'openai', apiKey, enabled: true });
|
|
210
|
-
success('OpenAI provider configured.');
|
|
211
|
-
return 'openai';
|
|
212
213
|
}
|
|
213
214
|
// Ollama
|
|
214
215
|
const ollamaUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434';
|
|
@@ -261,7 +262,7 @@ function showRecoveryCodes(codes) {
|
|
|
261
262
|
console.log('');
|
|
262
263
|
warn('These codes cannot be shown again!');
|
|
263
264
|
}
|
|
264
|
-
async function stepAdminAccount(
|
|
265
|
+
async function stepAdminAccount(db) {
|
|
265
266
|
if (!db) {
|
|
266
267
|
error('Database not available. Cannot create admin account.');
|
|
267
268
|
return null;
|
|
@@ -271,37 +272,58 @@ async function stepAdminAccount(rl, db) {
|
|
|
271
272
|
if (existingAdmins.length > 0) {
|
|
272
273
|
console.log(chalk.dim(' Existing admin accounts:'));
|
|
273
274
|
for (const admin of existingAdmins) {
|
|
274
|
-
console.log(` ${chalk.green('
|
|
275
|
+
console.log(` ${chalk.green('\u2022')} ${admin.name} ${chalk.dim(`<${admin.email}>`)}`);
|
|
275
276
|
}
|
|
276
277
|
console.log('');
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
278
|
+
let picked;
|
|
279
|
+
try {
|
|
280
|
+
picked = await select({
|
|
281
|
+
message: 'What would you like to do?',
|
|
282
|
+
choices: [
|
|
283
|
+
{ name: 'Keep existing - no changes', value: 'keep' },
|
|
284
|
+
{ name: 'Reset password for an existing admin', value: 'reset' },
|
|
285
|
+
{ name: 'Create an additional admin', value: 'create' },
|
|
286
|
+
],
|
|
287
|
+
theme,
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
catch {
|
|
291
|
+
return existingAdmins[0].email;
|
|
292
|
+
}
|
|
293
|
+
if (picked === 'keep') {
|
|
285
294
|
success(`Keeping ${existingAdmins.length} existing admin(s).`);
|
|
286
295
|
return existingAdmins[0].email;
|
|
287
296
|
}
|
|
288
|
-
if (picked === '
|
|
289
|
-
// Reset password for existing admin
|
|
297
|
+
if (picked === 'reset') {
|
|
290
298
|
let targetAdmin = existingAdmins[0];
|
|
291
299
|
if (existingAdmins.length > 1) {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
300
|
+
try {
|
|
301
|
+
const adminId = await select({
|
|
302
|
+
message: 'Which admin?',
|
|
303
|
+
choices: existingAdmins.map(a => ({
|
|
304
|
+
name: `${a.name} ${chalk.dim(`<${a.email}>`)}`,
|
|
305
|
+
value: a.id,
|
|
306
|
+
})),
|
|
307
|
+
theme,
|
|
308
|
+
});
|
|
309
|
+
targetAdmin = existingAdmins.find(a => a.id === adminId) || existingAdmins[0];
|
|
295
310
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if (n >= 0 && n < existingAdmins.length) {
|
|
299
|
-
targetAdmin = existingAdmins[n];
|
|
311
|
+
catch {
|
|
312
|
+
return existingAdmins[0].email;
|
|
300
313
|
}
|
|
301
314
|
}
|
|
302
315
|
let newPassword = '';
|
|
303
316
|
while (true) {
|
|
304
|
-
|
|
317
|
+
try {
|
|
318
|
+
newPassword = await passwordPrompt({
|
|
319
|
+
message: 'New password (min 8 chars, 1 letter, 1 number)',
|
|
320
|
+
mask: '*',
|
|
321
|
+
theme,
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return existingAdmins[0].email;
|
|
326
|
+
}
|
|
305
327
|
const strengthError = validatePasswordStrength(newPassword);
|
|
306
328
|
if (!strengthError)
|
|
307
329
|
break;
|
|
@@ -321,18 +343,30 @@ async function stepAdminAccount(rl, db) {
|
|
|
321
343
|
showRecoveryCodes(recoveryCodes);
|
|
322
344
|
return targetAdmin.email;
|
|
323
345
|
}
|
|
324
|
-
// picked === '
|
|
346
|
+
// picked === 'create' - fall through to create new admin
|
|
325
347
|
console.log('');
|
|
326
348
|
}
|
|
327
349
|
// Create new admin
|
|
328
|
-
|
|
350
|
+
let name;
|
|
351
|
+
try {
|
|
352
|
+
name = await input({ message: 'Name', theme });
|
|
353
|
+
}
|
|
354
|
+
catch {
|
|
355
|
+
return existingAdmins.length > 0 ? existingAdmins[0].email : null;
|
|
356
|
+
}
|
|
329
357
|
if (!name) {
|
|
330
358
|
warn('Admin account creation skipped.');
|
|
331
359
|
return existingAdmins.length > 0 ? existingAdmins[0].email : null;
|
|
332
360
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
361
|
+
let email;
|
|
362
|
+
try {
|
|
363
|
+
email = await input({
|
|
364
|
+
message: 'Email',
|
|
365
|
+
validate: (val) => val.includes('@') || 'Must be a valid email address',
|
|
366
|
+
theme,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
catch {
|
|
336
370
|
return existingAdmins.length > 0 ? existingAdmins[0].email : null;
|
|
337
371
|
}
|
|
338
372
|
// Check email uniqueness
|
|
@@ -345,10 +379,19 @@ async function stepAdminAccount(rl, db) {
|
|
|
345
379
|
error(`User with email ${email} already exists.`);
|
|
346
380
|
return existingAdmins.length > 0 ? existingAdmins[0].email : null;
|
|
347
381
|
}
|
|
348
|
-
let
|
|
382
|
+
let pw = '';
|
|
349
383
|
while (true) {
|
|
350
|
-
|
|
351
|
-
|
|
384
|
+
try {
|
|
385
|
+
pw = await passwordPrompt({
|
|
386
|
+
message: 'Password (min 8 chars, 1 letter, 1 number)',
|
|
387
|
+
mask: '*',
|
|
388
|
+
theme,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
catch {
|
|
392
|
+
return existingAdmins.length > 0 ? existingAdmins[0].email : null;
|
|
393
|
+
}
|
|
394
|
+
const strengthError = validatePasswordStrength(pw);
|
|
352
395
|
if (!strengthError)
|
|
353
396
|
break;
|
|
354
397
|
console.log(chalk.red(` ${strengthError}`));
|
|
@@ -356,7 +399,7 @@ async function stepAdminAccount(rl, db) {
|
|
|
356
399
|
// Prefer server API (avoids cross-process LibSQL issues in Docker)
|
|
357
400
|
const serverUrl = await getServerBaseUrl();
|
|
358
401
|
if (serverUrl) {
|
|
359
|
-
const apiResult = await createAdminViaApi(serverUrl, email,
|
|
402
|
+
const apiResult = await createAdminViaApi(serverUrl, email, pw, name);
|
|
360
403
|
if (apiResult) {
|
|
361
404
|
success(`Admin account created: ${apiResult.email}`);
|
|
362
405
|
showRecoveryCodes(apiResult.recoveryCodes);
|
|
@@ -364,26 +407,45 @@ async function stepAdminAccount(rl, db) {
|
|
|
364
407
|
}
|
|
365
408
|
}
|
|
366
409
|
// Fall back to direct DB
|
|
367
|
-
const result = await createAdminUser(db, name, email,
|
|
410
|
+
const result = await createAdminUser(db, name, email, pw);
|
|
368
411
|
success(`Admin account created: ${result.email}`);
|
|
369
412
|
showRecoveryCodes(result.recoveryCodes);
|
|
370
413
|
return result.email;
|
|
371
414
|
}
|
|
372
415
|
// Step 4: Registration Mode
|
|
373
|
-
async function stepRegistrationMode(
|
|
416
|
+
async function stepRegistrationMode(db) {
|
|
374
417
|
console.log(chalk.bold.white('\n Step 4: Registration Mode\n'));
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
418
|
+
let mode;
|
|
419
|
+
try {
|
|
420
|
+
mode = await select({
|
|
421
|
+
message: 'How should new users register?',
|
|
422
|
+
choices: [
|
|
423
|
+
{ name: 'Invite only (more secure)', value: 'invite', description: 'Users need an invite code to sign up' },
|
|
424
|
+
{ name: 'Open registration', value: 'open', description: 'Anyone can create an account' },
|
|
425
|
+
],
|
|
426
|
+
theme,
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
mode = 'invite';
|
|
431
|
+
}
|
|
380
432
|
await updateSettings({
|
|
381
433
|
system: { registrationMode: mode },
|
|
382
434
|
});
|
|
383
435
|
success(`Registration mode set to ${chalk.bold(mode)}.`);
|
|
384
436
|
const codes = [];
|
|
385
437
|
if (mode === 'invite' && db) {
|
|
386
|
-
|
|
438
|
+
let generate;
|
|
439
|
+
try {
|
|
440
|
+
generate = await confirm({
|
|
441
|
+
message: 'Generate 3 invite codes now?',
|
|
442
|
+
default: true,
|
|
443
|
+
theme,
|
|
444
|
+
});
|
|
445
|
+
}
|
|
446
|
+
catch {
|
|
447
|
+
generate = false;
|
|
448
|
+
}
|
|
387
449
|
if (generate) {
|
|
388
450
|
for (let i = 0; i < 3; i++) {
|
|
389
451
|
const code = generateInviteCode();
|
|
@@ -409,9 +471,19 @@ async function stepRegistrationMode(rl, db) {
|
|
|
409
471
|
return { mode, codes };
|
|
410
472
|
}
|
|
411
473
|
// Step 5: GitHub OAuth (optional)
|
|
412
|
-
async function stepGitHubOAuth(
|
|
474
|
+
async function stepGitHubOAuth() {
|
|
413
475
|
console.log(chalk.bold.white('\n Step 5: GitHub OAuth (Optional)\n'));
|
|
414
|
-
|
|
476
|
+
let configure;
|
|
477
|
+
try {
|
|
478
|
+
configure = await confirm({
|
|
479
|
+
message: 'Configure GitHub OAuth login?',
|
|
480
|
+
default: false,
|
|
481
|
+
theme,
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
catch {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
415
487
|
if (!configure) {
|
|
416
488
|
info('GitHub OAuth skipped. Configure later in Settings.');
|
|
417
489
|
return false;
|
|
@@ -421,8 +493,15 @@ async function stepGitHubOAuth(rl) {
|
|
|
421
493
|
info(`Callback URL: ${chalk.cyan(`http://localhost:${port}/api/auth/github/callback`)}`);
|
|
422
494
|
info('Create a GitHub OAuth App at: https://github.com/settings/developers');
|
|
423
495
|
console.log('');
|
|
424
|
-
|
|
425
|
-
|
|
496
|
+
let clientId;
|
|
497
|
+
let clientSecret;
|
|
498
|
+
try {
|
|
499
|
+
clientId = await input({ message: 'GitHub Client ID', theme });
|
|
500
|
+
clientSecret = await input({ message: 'GitHub Client Secret', theme });
|
|
501
|
+
}
|
|
502
|
+
catch {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
426
505
|
if (!clientId || !clientSecret) {
|
|
427
506
|
warn('Incomplete credentials, skipping GitHub OAuth.');
|
|
428
507
|
return false;
|
|
@@ -602,20 +681,17 @@ export function setupCommand() {
|
|
|
602
681
|
error('Failed to initialize database.');
|
|
603
682
|
process.exit(1);
|
|
604
683
|
}
|
|
605
|
-
// Create a single readline interface for all steps
|
|
606
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
607
684
|
// Step 1: System Check
|
|
608
685
|
const status = await stepSystemCheck(db);
|
|
609
686
|
// Step 2: AI Provider
|
|
610
687
|
console.log(chalk.bold.white('\n Step 2: AI Provider\n'));
|
|
611
|
-
const aiProvider = await stepAiProvider(
|
|
688
|
+
const aiProvider = await stepAiProvider(status);
|
|
612
689
|
// Step 3: Admin Account
|
|
613
|
-
const adminEmail = await stepAdminAccount(
|
|
690
|
+
const adminEmail = await stepAdminAccount(db);
|
|
614
691
|
// Step 4: Registration Mode
|
|
615
|
-
const regResult = await stepRegistrationMode(
|
|
692
|
+
const regResult = await stepRegistrationMode(db);
|
|
616
693
|
// Step 5: GitHub OAuth
|
|
617
|
-
const githubOAuth = await stepGitHubOAuth(
|
|
618
|
-
rl.close();
|
|
694
|
+
const githubOAuth = await stepGitHubOAuth();
|
|
619
695
|
// Step 6: Summary
|
|
620
696
|
showSummary({
|
|
621
697
|
redisOk: status.redisOk,
|
|
@@ -84,7 +84,7 @@ ${issue.body || 'No description provided.'}
|
|
|
84
84
|
|
|
85
85
|
Closes #${issue.number}
|
|
86
86
|
|
|
87
|
-
Co-Authored-By: profClaw <bot@profclaw.
|
|
87
|
+
Co-Authored-By: profClaw <bot@profclaw.ai>"
|
|
88
88
|
8. Push: git push -u origin HEAD
|
|
89
89
|
9. Create PR: gh pr create --title "<title>" --body "Closes #${issue.number}"
|
|
90
90
|
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
import { randomUUID } from 'crypto';
|
|
8
8
|
import { createHmac, timingSafeEqual } from 'crypto';
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
+
import { createContextualLogger } from '../utils/logger.js';
|
|
11
|
+
const log = createContextualLogger('AgentWebhook');
|
|
10
12
|
// Schemas
|
|
11
13
|
/**
|
|
12
14
|
* Generic agent completion payload
|
|
@@ -62,7 +64,7 @@ function verifySignature(agent, rawBody, signature) {
|
|
|
62
64
|
const secret = WEBHOOK_SECRETS[agent] || WEBHOOK_SECRETS.generic;
|
|
63
65
|
// Skip verification if no secret configured
|
|
64
66
|
if (!secret) {
|
|
65
|
-
|
|
67
|
+
log.warn('No secret configured for agent, skipping verification', { agent });
|
|
66
68
|
return true;
|
|
67
69
|
}
|
|
68
70
|
if (!signature) {
|
|
@@ -103,7 +105,7 @@ export async function handleOpenClawWebhook(c) {
|
|
|
103
105
|
}
|
|
104
106
|
const parsed = OpenClawCompletionSchema.safeParse(payload);
|
|
105
107
|
if (!parsed.success) {
|
|
106
|
-
|
|
108
|
+
log.error('OpenClaw validation failed', new Error(parsed.error.message));
|
|
107
109
|
throw new Error(`Validation failed: ${parsed.error.message}`);
|
|
108
110
|
}
|
|
109
111
|
return processAgentCompletion(parsed.data);
|
|
@@ -129,7 +131,7 @@ export async function handleGenericAgentWebhook(c) {
|
|
|
129
131
|
}
|
|
130
132
|
const parsed = AgentCompletionSchema.safeParse(payload);
|
|
131
133
|
if (!parsed.success) {
|
|
132
|
-
|
|
134
|
+
log.error('Agent validation failed', new Error(parsed.error.message));
|
|
133
135
|
throw new Error(`Validation failed: ${parsed.error.message}`);
|
|
134
136
|
}
|
|
135
137
|
return processAgentCompletion(parsed.data);
|
|
@@ -158,10 +160,11 @@ function processAgentCompletion(completion) {
|
|
|
158
160
|
taskReports.set(report.taskId, reports);
|
|
159
161
|
}
|
|
160
162
|
// Log
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
log.info('Agent reported completion', {
|
|
164
|
+
agent: completion.agent,
|
|
165
|
+
status: completion.status,
|
|
166
|
+
artifacts: completion.artifacts?.length,
|
|
167
|
+
});
|
|
165
168
|
return report;
|
|
166
169
|
}
|
|
167
170
|
// Query Functions
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { randomUUID } from 'crypto';
|
|
15
15
|
import { UserPromptSubmitPayloadSchema } from './schemas.js';
|
|
16
|
+
import { createContextualLogger } from '../utils/logger.js';
|
|
17
|
+
const log = createContextualLogger('PromptSubmit');
|
|
16
18
|
// In-memory storage for prompt events
|
|
17
19
|
const promptEvents = new Map();
|
|
18
20
|
/**
|
|
@@ -35,7 +37,7 @@ export async function handlePromptSubmit(c) {
|
|
|
35
37
|
}
|
|
36
38
|
const parsed = UserPromptSubmitPayloadSchema.safeParse(payload);
|
|
37
39
|
if (!parsed.success) {
|
|
38
|
-
|
|
40
|
+
log.error('Prompt submit validation failed', new Error(parsed.error.message));
|
|
39
41
|
return {
|
|
40
42
|
success: false,
|
|
41
43
|
eventId: '',
|
|
@@ -56,17 +58,14 @@ export async function handlePromptSubmit(c) {
|
|
|
56
58
|
storePromptEvent(event);
|
|
57
59
|
// Log for debugging
|
|
58
60
|
const promptPreview = event.prompt.slice(0, 50) + (event.prompt.length > 50 ? '...' : '');
|
|
59
|
-
|
|
60
|
-
if (event.context?.file) {
|
|
61
|
-
console.log(`[Hook] Context file: ${event.context.file}`);
|
|
62
|
-
}
|
|
61
|
+
log.info('UserPromptSubmit', { promptPreview, contextFile: event.context?.file });
|
|
63
62
|
return {
|
|
64
63
|
success: true,
|
|
65
64
|
eventId: event.id,
|
|
66
65
|
};
|
|
67
66
|
}
|
|
68
67
|
catch (error) {
|
|
69
|
-
|
|
68
|
+
log.error('Error processing prompt submit', error instanceof Error ? error : new Error(String(error)));
|
|
70
69
|
return {
|
|
71
70
|
success: false,
|
|
72
71
|
eventId: '',
|
|
@@ -8,6 +8,8 @@ import { randomUUID } from 'crypto';
|
|
|
8
8
|
import { SessionEndPayloadSchema } from './schemas.js';
|
|
9
9
|
import { getSessionEvents, clearSessionEvents, getSessionSummary } from './tool-use.js';
|
|
10
10
|
import { aggregateInferences } from '../intelligence/rules.js';
|
|
11
|
+
import { createContextualLogger } from '../utils/logger.js';
|
|
12
|
+
const log = createContextualLogger('SessionEnd');
|
|
11
13
|
// Session aggregates storage
|
|
12
14
|
const sessionAggregates = new Map();
|
|
13
15
|
/**
|
|
@@ -30,7 +32,7 @@ export async function handleSessionEnd(c) {
|
|
|
30
32
|
}
|
|
31
33
|
const parsed = SessionEndPayloadSchema.safeParse(payload);
|
|
32
34
|
if (!parsed.success) {
|
|
33
|
-
|
|
35
|
+
log.error('Session end validation failed', new Error(parsed.error.message));
|
|
34
36
|
return {
|
|
35
37
|
success: false,
|
|
36
38
|
eventId: '',
|
|
@@ -67,10 +69,12 @@ export async function handleSessionEnd(c) {
|
|
|
67
69
|
// Store aggregate
|
|
68
70
|
sessionAggregates.set(sessionId, aggregate);
|
|
69
71
|
// Log session summary
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
log.info('Session ended', {
|
|
73
|
+
sessionId,
|
|
74
|
+
filesModified: aggregate.filesModified.length,
|
|
75
|
+
filesCreated: aggregate.filesCreated.length,
|
|
76
|
+
totalToolUses: Object.values(summary.toolUseCounts).reduce((a, b) => a + b, 0),
|
|
77
|
+
});
|
|
74
78
|
// Clear in-memory events (we have the aggregate now)
|
|
75
79
|
clearSessionEvents(sessionId);
|
|
76
80
|
return {
|
|
@@ -80,7 +84,7 @@ export async function handleSessionEnd(c) {
|
|
|
80
84
|
};
|
|
81
85
|
}
|
|
82
86
|
catch (error) {
|
|
83
|
-
|
|
87
|
+
log.error('Error processing session end', error instanceof Error ? error : new Error(String(error)));
|
|
84
88
|
return {
|
|
85
89
|
success: false,
|
|
86
90
|
eventId: '',
|
package/dist/hooks/tool-use.js
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
import { randomUUID } from 'crypto';
|
|
15
15
|
import { PostToolUsePayloadSchema } from './schemas.js';
|
|
16
16
|
import { inferFromToolUse } from '../intelligence/rules.js';
|
|
17
|
+
import { createContextualLogger } from '../utils/logger.js';
|
|
18
|
+
const log = createContextualLogger('ToolUse');
|
|
17
19
|
// In-memory storage for hook events (will be replaced with DB later)
|
|
18
20
|
const hookEvents = new Map();
|
|
19
21
|
const sessionEvents = new Map();
|
|
@@ -42,7 +44,7 @@ export async function handlePostToolUse(c) {
|
|
|
42
44
|
// Validate payload
|
|
43
45
|
const parsed = PostToolUsePayloadSchema.safeParse(payload);
|
|
44
46
|
if (!parsed.success) {
|
|
45
|
-
|
|
47
|
+
log.error('Validation failed', new Error(parsed.error.message));
|
|
46
48
|
return {
|
|
47
49
|
success: false,
|
|
48
50
|
eventId: '',
|
|
@@ -67,10 +69,11 @@ export async function handlePostToolUse(c) {
|
|
|
67
69
|
// Store event
|
|
68
70
|
storeEvent(event);
|
|
69
71
|
// Log for debugging
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
log.info('PostToolUse', {
|
|
73
|
+
tool: hookPayload.tool,
|
|
74
|
+
filePath: eventData.filePath || 'N/A',
|
|
75
|
+
inference: inference.confidence > 0 ? inference : undefined,
|
|
76
|
+
});
|
|
74
77
|
return {
|
|
75
78
|
success: true,
|
|
76
79
|
eventId: event.id,
|
|
@@ -78,7 +81,7 @@ export async function handlePostToolUse(c) {
|
|
|
78
81
|
};
|
|
79
82
|
}
|
|
80
83
|
catch (error) {
|
|
81
|
-
|
|
84
|
+
log.error('Error processing PostToolUse', error instanceof Error ? error : new Error(String(error)));
|
|
82
85
|
return {
|
|
83
86
|
success: false,
|
|
84
87
|
eventId: '',
|