@harbinger-ai/harbinger 0.1.0 → 0.1.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/bin/cli.js +40 -38
- package/bin/local.sh +2 -2
- package/bin/postinstall.js +8 -8
- package/config/index.js +6 -3
- package/config/instrumentation.js +11 -11
- package/lib/chat/actions.js +19 -0
- package/lib/chat/components/app-sidebar.js +17 -1
- package/lib/chat/components/app-sidebar.jsx +19 -1
- package/lib/chat/components/findings-page.js +164 -103
- package/lib/chat/components/findings-page.jsx +156 -101
- package/lib/chat/components/icons.js +22 -0
- package/lib/chat/components/icons.jsx +20 -0
- package/lib/chat/components/index.js +1 -0
- package/lib/chat/components/mission-control.js +490 -0
- package/lib/chat/components/mission-control.jsx +618 -0
- package/lib/chat/components/registry-page.js +267 -133
- package/lib/chat/components/registry-page.jsx +299 -138
- package/lib/chat/components/sidebar-user-nav.js +1 -1
- package/lib/chat/components/sidebar-user-nav.jsx +1 -1
- package/lib/chat/components/targets-page.js +269 -200
- package/lib/chat/components/targets-page.jsx +181 -111
- package/lib/chat/components/upgrade-dialog.js +2 -2
- package/lib/chat/components/upgrade-dialog.jsx +2 -2
- package/lib/cron.js +11 -7
- package/lib/db/index.js +6 -1
- package/lib/mcp/actions.js +1 -1
- package/lib/mcp/handler.js +2 -2
- package/lib/mcp/server.js +1 -1
- package/lib/paths.js +1 -1
- package/package.json +1 -1
- package/templates/.env.example +4 -4
- package/templates/.github/workflows/rebuild-event-handler.yml +20 -20
- package/templates/.github/workflows/run-job.yml +6 -6
- package/templates/.github/workflows/upgrade-event-handler.yml +12 -12
- package/templates/CLAUDE.md +3 -3
- package/templates/CLAUDE.md.template +9 -9
- package/templates/app/api/[...thepopebot]/route.js +1 -1
- package/templates/app/api/auth/[...nextauth]/route.js +1 -1
- package/templates/app/chat/[chatId]/page.js +2 -2
- package/templates/app/chats/page.js +2 -2
- package/templates/app/components/setup-form.jsx +1 -1
- package/templates/app/findings/page.js +2 -2
- package/templates/app/globals.css +1 -1
- package/templates/app/layout.js +1 -1
- package/templates/app/login/page.js +1 -1
- package/templates/app/notifications/page.js +2 -2
- package/templates/app/page.js +2 -2
- package/templates/app/settings/crons/page.js +1 -1
- package/templates/app/settings/layout.js +2 -2
- package/templates/app/settings/mcp/page.js +1 -1
- package/templates/app/settings/secrets/page.js +1 -1
- package/templates/app/settings/triggers/page.js +1 -1
- package/templates/app/stream/chat/route.js +1 -1
- package/templates/app/swarm/page.js +2 -2
- package/templates/app/targets/page.js +2 -2
- package/templates/app/toolbox/page.js +2 -2
- package/templates/config/AGENT.md +2 -2
- package/templates/config/EVENT_HANDLER.md +3 -3
- package/templates/config/SKILL_BUILDING_GUIDE.md +1 -1
- package/templates/config/SOUL.md +1 -1
- package/templates/docker/event-handler/Dockerfile +1 -1
- package/templates/docker-compose.yml +2 -2
- package/templates/instrumentation.js +1 -1
- package/templates/middleware.js +1 -1
- package/templates/next.config.mjs +2 -2
package/bin/cli.js
CHANGED
|
@@ -49,10 +49,10 @@ function templatePath(userPath, templatesDir) {
|
|
|
49
49
|
|
|
50
50
|
function printUsage() {
|
|
51
51
|
console.log(`
|
|
52
|
-
Usage:
|
|
52
|
+
Usage: harbinger <command>
|
|
53
53
|
|
|
54
54
|
Commands:
|
|
55
|
-
init Scaffold a new
|
|
55
|
+
init Scaffold a new Harbinger project
|
|
56
56
|
setup Run interactive setup wizard
|
|
57
57
|
setup-telegram Reconfigure Telegram webhook
|
|
58
58
|
reset-auth Regenerate AUTH_SECRET (invalidates all sessions)
|
|
@@ -90,7 +90,7 @@ async function init() {
|
|
|
90
90
|
const templatesDir = path.join(packageDir, 'templates');
|
|
91
91
|
const noManaged = args.includes('--no-managed');
|
|
92
92
|
|
|
93
|
-
// Guard: warn if the directory is not empty (unless it's an existing
|
|
93
|
+
// Guard: warn if the directory is not empty (unless it's an existing Harbinger project)
|
|
94
94
|
const entries = fs.readdirSync(cwd);
|
|
95
95
|
if (entries.length > 0) {
|
|
96
96
|
const pkgPath = path.join(cwd, 'package.json');
|
|
@@ -100,7 +100,7 @@ async function init() {
|
|
|
100
100
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
101
101
|
const deps = pkg.dependencies || {};
|
|
102
102
|
const devDeps = pkg.devDependencies || {};
|
|
103
|
-
if (deps.thepopebot || devDeps.thepopebot) {
|
|
103
|
+
if (deps['@harbinger-ai/harbinger'] || devDeps['@harbinger-ai/harbinger'] || deps.thepopebot || devDeps.thepopebot) {
|
|
104
104
|
isExistingProject = true;
|
|
105
105
|
}
|
|
106
106
|
} catch {}
|
|
@@ -111,7 +111,7 @@ async function init() {
|
|
|
111
111
|
const { text, isCancel } = await import('@clack/prompts');
|
|
112
112
|
const dirName = await text({
|
|
113
113
|
message: 'Project directory name:',
|
|
114
|
-
defaultValue: 'my-
|
|
114
|
+
defaultValue: 'my-agent',
|
|
115
115
|
});
|
|
116
116
|
if (isCancel(dirName)) {
|
|
117
117
|
console.log('\nCancelled.\n');
|
|
@@ -125,7 +125,7 @@ async function init() {
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
console.log('\nScaffolding
|
|
128
|
+
console.log('\nScaffolding Harbinger project...\n');
|
|
129
129
|
|
|
130
130
|
const templateFiles = getTemplateFiles(templatesDir);
|
|
131
131
|
const created = [];
|
|
@@ -168,7 +168,7 @@ async function init() {
|
|
|
168
168
|
if (!fs.existsSync(pkgPath)) {
|
|
169
169
|
const dirName = path.basename(cwd);
|
|
170
170
|
const { version } = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8'));
|
|
171
|
-
const
|
|
171
|
+
const harbingerDep = version.includes('-') ? version : '^1.0.0';
|
|
172
172
|
const pkg = {
|
|
173
173
|
name: dirName,
|
|
174
174
|
private: true,
|
|
@@ -176,12 +176,12 @@ async function init() {
|
|
|
176
176
|
dev: 'next dev --turbopack',
|
|
177
177
|
build: 'next build',
|
|
178
178
|
start: 'next start',
|
|
179
|
-
setup: '
|
|
180
|
-
'setup-telegram': '
|
|
181
|
-
'reset-auth': '
|
|
179
|
+
setup: 'harbinger setup',
|
|
180
|
+
'setup-telegram': 'harbinger setup-telegram',
|
|
181
|
+
'reset-auth': 'harbinger reset-auth',
|
|
182
182
|
},
|
|
183
183
|
dependencies: {
|
|
184
|
-
|
|
184
|
+
'@harbinger-ai/harbinger': harbingerDep,
|
|
185
185
|
next: '^15.5.12',
|
|
186
186
|
'next-auth': '5.0.0-beta.30',
|
|
187
187
|
'next-themes': '^0.4.0',
|
|
@@ -247,12 +247,12 @@ async function init() {
|
|
|
247
247
|
if (changed.length > 0) {
|
|
248
248
|
console.log('\n Updated templates available:');
|
|
249
249
|
console.log(' These files differ from the current package templates.');
|
|
250
|
-
console.log(' This may be from your edits, or from a
|
|
250
|
+
console.log(' This may be from your edits, or from a Harbinger update.\n');
|
|
251
251
|
for (const file of changed) {
|
|
252
252
|
console.log(` ${file}`);
|
|
253
253
|
}
|
|
254
|
-
console.log('\n To view differences: npx
|
|
255
|
-
console.log(' To reset to default: npx
|
|
254
|
+
console.log('\n To view differences: npx harbinger diff <file>');
|
|
255
|
+
console.log(' To reset to default: npx harbinger reset <file>');
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
// Run npm install
|
|
@@ -262,32 +262,34 @@ async function init() {
|
|
|
262
262
|
// Create or update .env with auto-generated infrastructure values
|
|
263
263
|
const envPath = path.join(cwd, '.env');
|
|
264
264
|
const { randomBytes } = await import('crypto');
|
|
265
|
-
const
|
|
266
|
-
const version =
|
|
265
|
+
const harbingerPkg = JSON.parse(fs.readFileSync(path.join(packageDir, 'package.json'), 'utf8'));
|
|
266
|
+
const version = harbingerPkg.version;
|
|
267
267
|
|
|
268
268
|
if (!fs.existsSync(envPath)) {
|
|
269
269
|
// Seed .env for new projects
|
|
270
270
|
const authSecret = randomBytes(32).toString('base64');
|
|
271
|
-
const seedEnv = `#
|
|
271
|
+
const seedEnv = `# Harbinger Configuration
|
|
272
272
|
# Run "npm run setup" to complete configuration
|
|
273
273
|
|
|
274
274
|
AUTH_SECRET=${authSecret}
|
|
275
275
|
AUTH_TRUST_HOST=true
|
|
276
|
-
|
|
276
|
+
HARBINGER_VERSION=${version}
|
|
277
277
|
`;
|
|
278
278
|
fs.writeFileSync(envPath, seedEnv);
|
|
279
|
-
console.log(` Created .env (AUTH_SECRET,
|
|
279
|
+
console.log(` Created .env (AUTH_SECRET, HARBINGER_VERSION=${version})`);
|
|
280
280
|
} else {
|
|
281
|
-
// Update
|
|
281
|
+
// Update HARBINGER_VERSION in existing .env (also migrate legacy THEPOPEBOT_VERSION key)
|
|
282
282
|
try {
|
|
283
283
|
let envContent = fs.readFileSync(envPath, 'utf8');
|
|
284
|
-
if (envContent.match(/^
|
|
285
|
-
envContent = envContent.replace(/^
|
|
284
|
+
if (envContent.match(/^HARBINGER_VERSION=.*/m)) {
|
|
285
|
+
envContent = envContent.replace(/^HARBINGER_VERSION=.*/m, `HARBINGER_VERSION=${version}`);
|
|
286
|
+
} else if (envContent.match(/^THEPOPEBOT_VERSION=.*/m)) {
|
|
287
|
+
envContent = envContent.replace(/^THEPOPEBOT_VERSION=.*/m, `HARBINGER_VERSION=${version}`);
|
|
286
288
|
} else {
|
|
287
|
-
envContent = envContent.trimEnd() + `\
|
|
289
|
+
envContent = envContent.trimEnd() + `\nHARBINGER_VERSION=${version}\n`;
|
|
288
290
|
}
|
|
289
291
|
fs.writeFileSync(envPath, envContent);
|
|
290
|
-
console.log(` Updated
|
|
292
|
+
console.log(` Updated HARBINGER_VERSION to ${version}`);
|
|
291
293
|
} catch {}
|
|
292
294
|
}
|
|
293
295
|
|
|
@@ -308,8 +310,8 @@ function reset(filePath) {
|
|
|
308
310
|
for (const file of files) {
|
|
309
311
|
console.log(` ${destPath(file)}`);
|
|
310
312
|
}
|
|
311
|
-
console.log('\nUsage:
|
|
312
|
-
console.log('Example:
|
|
313
|
+
console.log('\nUsage: harbinger reset <file>');
|
|
314
|
+
console.log('Example: harbinger reset config/SOUL.md\n');
|
|
313
315
|
return;
|
|
314
316
|
}
|
|
315
317
|
|
|
@@ -319,7 +321,7 @@ function reset(filePath) {
|
|
|
319
321
|
|
|
320
322
|
if (!fs.existsSync(src)) {
|
|
321
323
|
console.error(`\nTemplate not found: ${filePath}`);
|
|
322
|
-
console.log('Run "
|
|
324
|
+
console.log('Run "harbinger reset" to see available templates.\n');
|
|
323
325
|
process.exit(1);
|
|
324
326
|
}
|
|
325
327
|
|
|
@@ -365,8 +367,8 @@ function diff(filePath) {
|
|
|
365
367
|
if (!anyDiff) {
|
|
366
368
|
console.log(' All files match package templates.');
|
|
367
369
|
}
|
|
368
|
-
console.log('\nUsage:
|
|
369
|
-
console.log('Example:
|
|
370
|
+
console.log('\nUsage: harbinger diff <file>');
|
|
371
|
+
console.log('Example: harbinger diff config/SOUL.md\n');
|
|
370
372
|
return;
|
|
371
373
|
}
|
|
372
374
|
|
|
@@ -381,7 +383,7 @@ function diff(filePath) {
|
|
|
381
383
|
|
|
382
384
|
if (!fs.existsSync(dest)) {
|
|
383
385
|
console.log(`\n${filePath} does not exist in your project.`);
|
|
384
|
-
console.log(`Run "
|
|
386
|
+
console.log(`Run "harbinger reset ${filePath}" to create it.\n`);
|
|
385
387
|
return;
|
|
386
388
|
}
|
|
387
389
|
|
|
@@ -391,7 +393,7 @@ function diff(filePath) {
|
|
|
391
393
|
console.log('\nFiles are identical.\n');
|
|
392
394
|
} catch (e) {
|
|
393
395
|
// git diff exits with 1 when files differ (output already printed)
|
|
394
|
-
console.log(`\n To reset:
|
|
396
|
+
console.log(`\n To reset: harbinger reset ${filePath}\n`);
|
|
395
397
|
}
|
|
396
398
|
}
|
|
397
399
|
|
|
@@ -489,7 +491,7 @@ function readStdin() {
|
|
|
489
491
|
|
|
490
492
|
/**
|
|
491
493
|
* Prompt for a secret value interactively if not provided as an argument.
|
|
492
|
-
* Supports piped stdin (e.g. echo "val" |
|
|
494
|
+
* Supports piped stdin (e.g. echo "val" | harbinger set-var KEY).
|
|
493
495
|
*/
|
|
494
496
|
async function promptForValue(key) {
|
|
495
497
|
const stdin = await readStdin();
|
|
@@ -516,8 +518,8 @@ async function promptForValue(key) {
|
|
|
516
518
|
|
|
517
519
|
async function setAgentSecret(key, value) {
|
|
518
520
|
if (!key) {
|
|
519
|
-
console.error('\n Usage:
|
|
520
|
-
console.error(' Example:
|
|
521
|
+
console.error('\n Usage: harbinger set-agent-secret <KEY> [VALUE]\n');
|
|
522
|
+
console.error(' Example: harbinger set-agent-secret ANTHROPIC_API_KEY\n');
|
|
521
523
|
process.exit(1);
|
|
522
524
|
}
|
|
523
525
|
|
|
@@ -543,8 +545,8 @@ async function setAgentSecret(key, value) {
|
|
|
543
545
|
|
|
544
546
|
async function setAgentLlmSecret(key, value) {
|
|
545
547
|
if (!key) {
|
|
546
|
-
console.error('\n Usage:
|
|
547
|
-
console.error(' Example:
|
|
548
|
+
console.error('\n Usage: harbinger set-agent-llm-secret <KEY> [VALUE]\n');
|
|
549
|
+
console.error(' Example: harbinger set-agent-llm-secret BRAVE_API_KEY\n');
|
|
548
550
|
process.exit(1);
|
|
549
551
|
}
|
|
550
552
|
|
|
@@ -566,8 +568,8 @@ async function setAgentLlmSecret(key, value) {
|
|
|
566
568
|
|
|
567
569
|
async function setVar(key, value) {
|
|
568
570
|
if (!key) {
|
|
569
|
-
console.error('\n Usage:
|
|
570
|
-
console.error(' Example:
|
|
571
|
+
console.error('\n Usage: harbinger set-var <KEY> [VALUE]\n');
|
|
572
|
+
console.error(' Example: harbinger set-var LLM_MODEL claude-sonnet-4-5-20250929\n');
|
|
571
573
|
process.exit(1);
|
|
572
574
|
}
|
|
573
575
|
|
package/bin/local.sh
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
4
|
PACKAGE_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
5
|
-
DEV_DIR="${1:-/tmp/
|
|
5
|
+
DEV_DIR="${1:-/tmp/harbinger.local}"
|
|
6
6
|
ENV_BACKUP="/tmp/env.$(uuidgen)"
|
|
7
7
|
|
|
8
8
|
HAS_ENV=false
|
|
@@ -17,7 +17,7 @@ cd "$DEV_DIR"
|
|
|
17
17
|
|
|
18
18
|
node "$PACKAGE_DIR/bin/cli.js" init
|
|
19
19
|
|
|
20
|
-
sed -i '' "s|\"
|
|
20
|
+
sed -i '' "s|\"@harbinger-ai/harbinger\": \".*\"|\"@harbinger-ai/harbinger\": \"file:$PACKAGE_DIR\"|" package.json
|
|
21
21
|
|
|
22
22
|
rm -rf node_modules package-lock.json
|
|
23
23
|
npm install --install-links
|
package/bin/postinstall.js
CHANGED
|
@@ -8,20 +8,20 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
8
8
|
const __dirname = path.dirname(__filename);
|
|
9
9
|
|
|
10
10
|
// postinstall runs from the package dir inside node_modules.
|
|
11
|
-
// The user's project root is two levels up: node_modules/
|
|
12
|
-
const projectRoot = path.resolve(__dirname, '..', '..', '..');
|
|
11
|
+
// The user's project root is two levels up: node_modules/@harbinger-ai/harbinger/ -> project root
|
|
12
|
+
const projectRoot = path.resolve(__dirname, '..', '..', '..', '..');
|
|
13
13
|
const templatesDir = path.join(__dirname, '..', 'templates');
|
|
14
14
|
|
|
15
15
|
// Skip if templates dir doesn't exist (shouldn't happen, but be safe)
|
|
16
16
|
if (!fs.existsSync(templatesDir)) process.exit(0);
|
|
17
17
|
|
|
18
|
-
// Skip if this doesn't look like a user project (no package.json with
|
|
18
|
+
// Skip if this doesn't look like a user project (no package.json with harbinger dep)
|
|
19
19
|
const pkgPath = path.join(projectRoot, 'package.json');
|
|
20
20
|
if (!fs.existsSync(pkgPath)) process.exit(0);
|
|
21
21
|
try {
|
|
22
22
|
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
23
23
|
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
24
|
-
if (!deps || !deps.thepopebot) process.exit(0);
|
|
24
|
+
if (!deps || (!deps['@harbinger-ai/harbinger'] && !deps.thepopebot)) process.exit(0);
|
|
25
25
|
} catch { process.exit(0); }
|
|
26
26
|
|
|
27
27
|
function walk(dir) {
|
|
@@ -52,12 +52,12 @@ for (const relPath of walk(templatesDir)) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (changed.length > 0) {
|
|
55
|
-
console.log('\n
|
|
56
|
-
console.log(' This is normal if you\'ve customized them. If
|
|
55
|
+
console.log('\n Harbinger: these project files differ from the latest package templates.');
|
|
56
|
+
console.log(' This is normal if you\'ve customized them. If Harbinger was just');
|
|
57
57
|
console.log(' updated, new defaults may be available.\n');
|
|
58
58
|
for (const file of changed) {
|
|
59
59
|
console.log(` ${file}`);
|
|
60
60
|
}
|
|
61
|
-
console.log('\n To compare: npx
|
|
62
|
-
console.log(' To restore: npx
|
|
61
|
+
console.log('\n To compare: npx harbinger diff <file>');
|
|
62
|
+
console.log(' To restore: npx harbinger reset <file>\n');
|
|
63
63
|
}
|
package/config/index.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Next.js config wrapper for
|
|
2
|
+
* Next.js config wrapper for Harbinger.
|
|
3
3
|
* Enables instrumentation hook for cron scheduling on server start.
|
|
4
4
|
*
|
|
5
5
|
* Usage in user's next.config.mjs:
|
|
6
|
-
* import {
|
|
7
|
-
* export default
|
|
6
|
+
* import { withHarbinger } from '@harbinger-ai/harbinger/config';
|
|
7
|
+
* export default withHarbinger({});
|
|
8
|
+
*
|
|
9
|
+
* Legacy alias also available:
|
|
10
|
+
* import { withThepopebot } from '@harbinger-ai/harbinger/config';
|
|
8
11
|
*
|
|
9
12
|
* @param {Object} nextConfig - User's Next.js config
|
|
10
13
|
* @returns {Object} Enhanced Next.js config
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Next.js instrumentation hook for
|
|
2
|
+
* Next.js instrumentation hook for Harbinger.
|
|
3
3
|
* This file is loaded by Next.js on server start when instrumentationHook is enabled.
|
|
4
4
|
*
|
|
5
5
|
* Users should create an instrumentation.js in their project root that imports this:
|
|
6
6
|
*
|
|
7
|
-
* export { register } from '
|
|
7
|
+
* export { register } from '@harbinger-ai/harbinger/instrumentation';
|
|
8
8
|
*
|
|
9
9
|
* Or they can re-export and add their own logic.
|
|
10
10
|
*/
|
|
@@ -48,19 +48,19 @@ export async function register() {
|
|
|
48
48
|
const agents = discoverAgents();
|
|
49
49
|
if (agents.length > 0) {
|
|
50
50
|
const names = agents.map(a => a.codename || a.id).join(', ');
|
|
51
|
-
console.log(`
|
|
52
|
-
console.log('
|
|
51
|
+
console.log(`harbinger: ${agents.length} agent profiles loaded (${names})`);
|
|
52
|
+
console.log('harbinger: use @AGENT_NAME in chat to route to a specific agent');
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Optionally start autonomous thinking engine
|
|
56
56
|
if (process.env.AUTONOMOUS_THINKING === 'true') {
|
|
57
57
|
const { startAutonomousEngine } = await import('../lib/ai/autonomous-engine.js');
|
|
58
58
|
startAutonomousEngine({
|
|
59
|
-
agentId: '
|
|
60
|
-
agentName: '
|
|
59
|
+
agentId: 'harbinger',
|
|
60
|
+
agentName: 'HARBINGER',
|
|
61
61
|
interval: Number(process.env.AUTONOMOUS_INTERVAL) || 60000,
|
|
62
62
|
});
|
|
63
|
-
console.log('
|
|
63
|
+
console.log('harbinger: autonomous thinking engine started');
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
// Start cron scheduler
|
|
@@ -77,17 +77,17 @@ export async function register() {
|
|
|
77
77
|
const stored = getAvailableVersion();
|
|
78
78
|
if (stored) setUpdateAvailable(stored);
|
|
79
79
|
} catch (err) {
|
|
80
|
-
console.warn('
|
|
80
|
+
console.warn('harbinger: update check warm-up failed:', err.message);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
83
|
// Pre-warm MCP client (load external tools)
|
|
84
84
|
try {
|
|
85
85
|
const { loadMcpTools } = await import('../lib/mcp/client.js');
|
|
86
86
|
const mcpTools = await loadMcpTools();
|
|
87
|
-
if (mcpTools.length > 0) console.log(`
|
|
87
|
+
if (mcpTools.length > 0) console.log(`harbinger: ${mcpTools.length} MCP tools loaded`);
|
|
88
88
|
} catch (err) {
|
|
89
|
-
console.warn('
|
|
89
|
+
console.warn('harbinger: MCP tools pre-warm failed:', err.message);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
console.log('
|
|
92
|
+
console.log('harbinger initialized');
|
|
93
93
|
}
|
package/lib/chat/actions.js
CHANGED
|
@@ -202,6 +202,25 @@ export async function triggerUpgrade() {
|
|
|
202
202
|
return { success: true };
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
206
|
+
// Agent profile actions
|
|
207
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get all discovered agent profiles for Mission Control.
|
|
211
|
+
* @returns {Promise<object[]>}
|
|
212
|
+
*/
|
|
213
|
+
export async function getAgentProfiles() {
|
|
214
|
+
await requireAuth();
|
|
215
|
+
try {
|
|
216
|
+
const { discoverAgents } = await import('../agents.js');
|
|
217
|
+
return discoverAgents();
|
|
218
|
+
} catch (err) {
|
|
219
|
+
console.error('Failed to discover agents:', err);
|
|
220
|
+
return [];
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
205
224
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
206
225
|
// API Key actions
|
|
207
226
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState, useEffect } from "react";
|
|
4
|
-
import { CirclePlusIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon, ArrowUpCircleIcon, LifeBuoyIcon, CrosshairIcon, ShieldIcon, PackageIcon } from "./icons.js";
|
|
4
|
+
import { CirclePlusIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon, ArrowUpCircleIcon, LifeBuoyIcon, CrosshairIcon, ShieldIcon, PackageIcon, CommandIcon } from "./icons.js";
|
|
5
5
|
import { getUnreadNotificationCount, getAppVersion } from "../actions.js";
|
|
6
6
|
import { SidebarHistory } from "./sidebar-history.js";
|
|
7
7
|
import { SidebarUserNav } from "./sidebar-user-nav.js";
|
|
@@ -112,6 +112,22 @@ function AppSidebar({ user }) {
|
|
|
112
112
|
) }),
|
|
113
113
|
collapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Swarm" })
|
|
114
114
|
] }) }),
|
|
115
|
+
/* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
116
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
117
|
+
SidebarMenuButton,
|
|
118
|
+
{
|
|
119
|
+
className: collapsed ? "justify-center" : "",
|
|
120
|
+
onClick: () => {
|
|
121
|
+
window.location.href = "/mission-control";
|
|
122
|
+
},
|
|
123
|
+
children: [
|
|
124
|
+
/* @__PURE__ */ jsx(CommandIcon, { size: 16 }),
|
|
125
|
+
!collapsed && /* @__PURE__ */ jsx("span", { children: "Mission Control" })
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
) }),
|
|
129
|
+
collapsed && /* @__PURE__ */ jsx(TooltipContent, { side: "right", children: "Mission Control" })
|
|
130
|
+
] }) }),
|
|
115
131
|
/* @__PURE__ */ jsx(SidebarMenuItem, { children: /* @__PURE__ */ jsxs(Tooltip, { children: [
|
|
116
132
|
/* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
117
133
|
SidebarMenuButton,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect } from 'react';
|
|
4
|
-
import { CirclePlusIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon, ArrowUpCircleIcon, LifeBuoyIcon, CrosshairIcon, ShieldIcon, PackageIcon } from './icons.js';
|
|
4
|
+
import { CirclePlusIcon, PanelLeftIcon, MessageIcon, BellIcon, SwarmIcon, ArrowUpCircleIcon, LifeBuoyIcon, CrosshairIcon, ShieldIcon, PackageIcon, CommandIcon } from './icons.js';
|
|
5
5
|
import { getUnreadNotificationCount, getAppVersion } from '../actions.js';
|
|
6
6
|
import { SidebarHistory } from './sidebar-history.js';
|
|
7
7
|
import { SidebarUserNav } from './sidebar-user-nav.js';
|
|
@@ -129,6 +129,24 @@ export function AppSidebar({ user }) {
|
|
|
129
129
|
</Tooltip>
|
|
130
130
|
</SidebarMenuItem>
|
|
131
131
|
|
|
132
|
+
{/* Mission Control */}
|
|
133
|
+
<SidebarMenuItem>
|
|
134
|
+
<Tooltip>
|
|
135
|
+
<TooltipTrigger asChild>
|
|
136
|
+
<SidebarMenuButton
|
|
137
|
+
className={collapsed ? 'justify-center' : ''}
|
|
138
|
+
onClick={() => { window.location.href = '/mission-control'; }}
|
|
139
|
+
>
|
|
140
|
+
<CommandIcon size={16} />
|
|
141
|
+
{!collapsed && <span>Mission Control</span>}
|
|
142
|
+
</SidebarMenuButton>
|
|
143
|
+
</TooltipTrigger>
|
|
144
|
+
{collapsed && (
|
|
145
|
+
<TooltipContent side="right">Mission Control</TooltipContent>
|
|
146
|
+
)}
|
|
147
|
+
</Tooltip>
|
|
148
|
+
</SidebarMenuItem>
|
|
149
|
+
|
|
132
150
|
{/* Targets */}
|
|
133
151
|
<SidebarMenuItem>
|
|
134
152
|
<Tooltip>
|