@agent-relay/dashboard-server 2.0.66-beta.0 → 2.0.66-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +24 -102
- package/dist/server.js.map +1 -1
- package/out/404.html +1 -1
- package/out/_next/static/chunks/118-b821e49d30a9f6af.js +1 -0
- package/out/_next/static/chunks/{202-fc0763dd7488e58f.js → 202-6cfbf8339f05e5ef.js} +1 -1
- package/out/_next/static/chunks/259-141fb39611979082.js +1 -0
- package/out/_next/static/chunks/535-cecb00f34c2ed9ba.js +1 -0
- package/out/_next/static/chunks/722-af84568996237c02.js +1 -0
- package/out/_next/static/chunks/994-e927457424324a78.js +1 -0
- package/out/_next/static/chunks/app/app/[[...slug]]/page-bba8842697e6192c.js +1 -0
- package/out/_next/static/chunks/app/{page-5c60a00d938ac40a.js → page-ba281b017e148cd6.js} +1 -1
- package/out/_next/static/chunks/app/providers/page-59e92abba4f8d895.js +1 -0
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-c667546c4902f1b0.js +1 -0
- package/out/_next/static/css/{71615414d8909a44.css → fd373f99378195fc.css} +1 -1
- package/out/about.html +2 -2
- package/out/about.txt +1 -1
- package/out/app/onboarding.html +1 -1
- package/out/app/onboarding.txt +1 -1
- package/out/app.html +1 -1
- package/out/app.txt +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.html +2 -2
- package/out/blog/go-to-bed-wake-up-to-a-finished-product.txt +1 -1
- package/out/blog/let-them-cook-multi-agent-orchestration.html +2 -2
- package/out/blog/let-them-cook-multi-agent-orchestration.txt +1 -1
- package/out/blog.html +2 -2
- package/out/blog.txt +1 -1
- package/out/careers.html +2 -2
- package/out/careers.txt +1 -1
- package/out/changelog.html +2 -2
- package/out/changelog.txt +1 -1
- package/out/cloud/link.html +1 -1
- package/out/cloud/link.txt +2 -2
- package/out/complete-profile.html +2 -2
- package/out/complete-profile.txt +1 -1
- package/out/connect-repos.html +1 -1
- package/out/connect-repos.txt +2 -2
- package/out/contact.html +2 -2
- package/out/contact.txt +1 -1
- package/out/docs.html +2 -2
- package/out/docs.txt +1 -1
- package/out/history.html +1 -1
- package/out/history.txt +2 -2
- package/out/index.html +1 -1
- package/out/index.txt +2 -2
- package/out/login.html +2 -2
- package/out/login.txt +2 -2
- package/out/metrics.html +1 -1
- package/out/metrics.txt +2 -2
- package/out/pricing.html +2 -2
- package/out/pricing.txt +1 -1
- package/out/privacy.html +2 -2
- package/out/privacy.txt +1 -1
- package/out/providers/setup/claude.html +1 -1
- package/out/providers/setup/claude.txt +2 -2
- package/out/providers/setup/codex.html +1 -1
- package/out/providers/setup/codex.txt +2 -2
- package/out/providers/setup/cursor.html +1 -1
- package/out/providers/setup/cursor.txt +2 -2
- package/out/providers.html +1 -1
- package/out/providers.txt +2 -2
- package/out/security.html +2 -2
- package/out/security.txt +1 -1
- package/out/signup.html +2 -2
- package/out/signup.txt +2 -2
- package/out/terms.html +2 -2
- package/out/terms.txt +1 -1
- package/package.json +1 -1
- package/out/_next/static/chunks/118-4c8241b0218335de.js +0 -1
- package/out/_next/static/chunks/259-3bbaad41b2550936.js +0 -1
- package/out/_next/static/chunks/285-1cb1c0ed74f31c6c.js +0 -1
- package/out/_next/static/chunks/722-85011b58b9caf88b.js +0 -1
- package/out/_next/static/chunks/994-0ce5f1d759089504.js +0 -1
- package/out/_next/static/chunks/app/app/[[...slug]]/page-589620c567f85400.js +0 -1
- package/out/_next/static/chunks/app/providers/page-394875a22b5ba7ce.js +0 -1
- package/out/_next/static/chunks/app/providers/setup/[provider]/page-f058bf6696242d7b.js +0 -1
- /package/out/_next/static/{CRgdkwuTcA6Bt0A5Fx1wC → g8CQjGCOpPwFcSToizDmH}/_buildManifest.js +0 -0
- /package/out/_next/static/{CRgdkwuTcA6Bt0A5Fx1wC → g8CQjGCOpPwFcSToizDmH}/_ssgManifest.js +0 -0
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA8DA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AA8DA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAkYzD,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AACvH,wBAAsB,cAAc,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import path from 'path';
|
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import os from 'os';
|
|
7
7
|
import crypto from 'crypto';
|
|
8
|
-
import { exec
|
|
8
|
+
import { exec } from 'child_process';
|
|
9
9
|
import { fileURLToPath } from 'url';
|
|
10
10
|
import { createStorageAdapter } from '@agent-relay/storage/adapter';
|
|
11
11
|
import { RelayClient } from '@agent-relay/sdk';
|
|
@@ -642,9 +642,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
642
642
|
clearInterval(bridgePingInterval);
|
|
643
643
|
});
|
|
644
644
|
const onlineUsers = new Map();
|
|
645
|
-
// Track cwd per spawned agent (name -> cwd)
|
|
646
|
-
// This is set when /api/spawn is called and included in /api/spawned responses
|
|
647
|
-
const agentCwdMap = new Map();
|
|
648
645
|
// Validation helpers for presence
|
|
649
646
|
const isValidUsername = (username) => {
|
|
650
647
|
if (typeof username !== 'string')
|
|
@@ -1837,7 +1834,7 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1837
1834
|
// Ignore errors reading processing state - it's optional
|
|
1838
1835
|
}
|
|
1839
1836
|
}
|
|
1840
|
-
// Mark spawned agents with isSpawned flag, team,
|
|
1837
|
+
// Mark spawned agents with isSpawned flag, team, and model
|
|
1841
1838
|
if (spawnReader) {
|
|
1842
1839
|
const activeWorkers = spawnReader.getActiveWorkers();
|
|
1843
1840
|
for (const worker of activeWorkers) {
|
|
@@ -1847,12 +1844,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1847
1844
|
if (worker.team) {
|
|
1848
1845
|
agent.team = worker.team;
|
|
1849
1846
|
}
|
|
1850
|
-
// Inject cwd from agentCwdMap (set during /api/spawn) or from worker info
|
|
1851
|
-
// (set by SpawnManager for relay-protocol spawns that bypass /api/spawn)
|
|
1852
|
-
const workerCwd = agentCwdMap.get(worker.name) || worker.cwd;
|
|
1853
|
-
if (workerCwd) {
|
|
1854
|
-
agent.cwd = workerCwd;
|
|
1855
|
-
}
|
|
1856
1847
|
// Extract model from spawn command (e.g., "codex --model gpt-5.2-codex" → "gpt-5.2-codex")
|
|
1857
1848
|
if (worker.cli) {
|
|
1858
1849
|
// Support both `--model foo` and `--model=foo`
|
|
@@ -1881,21 +1872,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
1881
1872
|
// Ignore errors reading workers.json
|
|
1882
1873
|
}
|
|
1883
1874
|
}
|
|
1884
|
-
// Mark relay-protocol spawned agents (spawned by other agents, not via dashboard /api/spawn)
|
|
1885
|
-
// These agents have log files in the team directory but aren't tracked by agentCwdMap
|
|
1886
|
-
if (spawnReader) {
|
|
1887
|
-
for (const [name, agent] of agentsMap) {
|
|
1888
|
-
if (agent.isSpawned)
|
|
1889
|
-
continue;
|
|
1890
|
-
if (onlineUsers.has(name) || name === 'Dashboard')
|
|
1891
|
-
continue;
|
|
1892
|
-
// Check if there's a log file for this agent (indicates it was spawned)
|
|
1893
|
-
const logPath = path.join(teamDir, `${name}.log`);
|
|
1894
|
-
if (fs.existsSync(logPath)) {
|
|
1895
|
-
agent.isSpawned = true;
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
}
|
|
1899
1875
|
// Set team from teams.json for agents that don't have a team yet
|
|
1900
1876
|
// This ensures agents defined in teams.json are associated with their team
|
|
1901
1877
|
// even if they weren't spawned via auto-spawn
|
|
@@ -4191,9 +4167,26 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4191
4167
|
});
|
|
4192
4168
|
}
|
|
4193
4169
|
}
|
|
4194
|
-
//
|
|
4195
|
-
|
|
4196
|
-
|
|
4170
|
+
// Also check agents.json for registered agents that may not be spawned
|
|
4171
|
+
const agentsPath = path.join(teamDir, 'agents.json');
|
|
4172
|
+
if (fs.existsSync(agentsPath)) {
|
|
4173
|
+
const data = JSON.parse(fs.readFileSync(agentsPath, 'utf-8'));
|
|
4174
|
+
const registeredAgents = data.agents || [];
|
|
4175
|
+
for (const agent of registeredAgents) {
|
|
4176
|
+
if (!agents.find(a => a.name === agent.name)) {
|
|
4177
|
+
// Check if recently active (within 30 seconds)
|
|
4178
|
+
const lastSeen = agent.lastSeen ? new Date(agent.lastSeen).getTime() : 0;
|
|
4179
|
+
const isActive = Date.now() - lastSeen < 30000;
|
|
4180
|
+
if (isActive) {
|
|
4181
|
+
agents.push({
|
|
4182
|
+
name: agent.name,
|
|
4183
|
+
status: 'active',
|
|
4184
|
+
alertLevel: 'normal',
|
|
4185
|
+
});
|
|
4186
|
+
}
|
|
4187
|
+
}
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4197
4190
|
res.json({
|
|
4198
4191
|
agents,
|
|
4199
4192
|
system: {
|
|
@@ -4671,20 +4664,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4671
4664
|
const online = isAgentOnline(name);
|
|
4672
4665
|
res.json({ name, online });
|
|
4673
4666
|
});
|
|
4674
|
-
/**
|
|
4675
|
-
* PUT /api/agents/:name/cwd - Register an agent's working directory
|
|
4676
|
-
* Used by relay-pty-orchestrator after daemon socket spawns (which bypass /api/spawn).
|
|
4677
|
-
*/
|
|
4678
|
-
app.put('/api/agents/:name/cwd', (req, res) => {
|
|
4679
|
-
const { name } = req.params;
|
|
4680
|
-
const { cwd } = req.body || {};
|
|
4681
|
-
if (!cwd || typeof cwd !== 'string') {
|
|
4682
|
-
return res.status(400).json({ error: 'Missing required field: cwd' });
|
|
4683
|
-
}
|
|
4684
|
-
agentCwdMap.set(name, cwd);
|
|
4685
|
-
broadcastData().catch(() => { });
|
|
4686
|
-
res.json({ success: true, name, cwd });
|
|
4687
|
-
});
|
|
4688
4667
|
// ===== Agent Spawn API =====
|
|
4689
4668
|
/**
|
|
4690
4669
|
* POST /api/spawn - Spawn a new agent
|
|
@@ -4704,8 +4683,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4704
4683
|
error: 'Missing required field: name',
|
|
4705
4684
|
});
|
|
4706
4685
|
}
|
|
4707
|
-
// Inherit spawner's cwd if no explicit cwd provided (for nested/agent-to-agent spawns)
|
|
4708
|
-
const effectiveCwd = cwd || (spawnerName ? agentCwdMap.get(spawnerName) : undefined);
|
|
4709
4686
|
try {
|
|
4710
4687
|
let result;
|
|
4711
4688
|
if (useExternalSpawnManager) {
|
|
@@ -4725,7 +4702,7 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4725
4702
|
cli,
|
|
4726
4703
|
task,
|
|
4727
4704
|
team: team || undefined,
|
|
4728
|
-
cwd:
|
|
4705
|
+
cwd: cwd || undefined,
|
|
4729
4706
|
interactive,
|
|
4730
4707
|
shadowMode,
|
|
4731
4708
|
shadowAgent,
|
|
@@ -4745,7 +4722,7 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4745
4722
|
task,
|
|
4746
4723
|
team: team || undefined,
|
|
4747
4724
|
spawnerName: spawnerName || undefined,
|
|
4748
|
-
cwd:
|
|
4725
|
+
cwd: cwd || undefined,
|
|
4749
4726
|
interactive,
|
|
4750
4727
|
shadowMode,
|
|
4751
4728
|
shadowAgent,
|
|
@@ -4758,10 +4735,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4758
4735
|
result = await spawner.spawn(request);
|
|
4759
4736
|
}
|
|
4760
4737
|
if (result.success) {
|
|
4761
|
-
// Track cwd for this agent so /api/spawned can return it
|
|
4762
|
-
if (effectiveCwd) {
|
|
4763
|
-
agentCwdMap.set(name, effectiveCwd);
|
|
4764
|
-
}
|
|
4765
4738
|
// Broadcast update to WebSocket clients
|
|
4766
4739
|
broadcastData().catch(() => { });
|
|
4767
4740
|
// Broadcast agent_spawned event to activity feed
|
|
@@ -4785,55 +4758,6 @@ export async function startDashboard(portOrOptions, dataDirArg, teamDirArg, dbPa
|
|
|
4785
4758
|
});
|
|
4786
4759
|
}
|
|
4787
4760
|
});
|
|
4788
|
-
/**
|
|
4789
|
-
* POST /api/repos/clone - Clone a repo into the workspace directory
|
|
4790
|
-
* Body: { fullName: "Owner/RepoName" }
|
|
4791
|
-
* Used by cloud API to hot-clone repos added to a running workspace.
|
|
4792
|
-
*/
|
|
4793
|
-
app.post('/api/repos/clone', async (req, res) => {
|
|
4794
|
-
const { fullName } = req.body;
|
|
4795
|
-
if (!fullName || typeof fullName !== 'string' || !fullName.includes('/')) {
|
|
4796
|
-
return res.status(400).json({ success: false, error: 'fullName is required (e.g., "Owner/RepoName")' });
|
|
4797
|
-
}
|
|
4798
|
-
// Validate format: "Owner/RepoName" with safe characters only
|
|
4799
|
-
if (!/^[a-zA-Z0-9._-]+\/[a-zA-Z0-9._-]+$/.test(fullName)) {
|
|
4800
|
-
return res.status(400).json({ success: false, error: 'Invalid repository name format' });
|
|
4801
|
-
}
|
|
4802
|
-
const repoName = fullName.split('/').pop();
|
|
4803
|
-
const workspaceDir = process.env.WORKSPACE_DIR || path.dirname(projectRoot || dataDir);
|
|
4804
|
-
const targetDir = path.join(workspaceDir, repoName);
|
|
4805
|
-
// Idempotent: skip if already cloned
|
|
4806
|
-
if (fs.existsSync(targetDir)) {
|
|
4807
|
-
return res.json({ success: true, message: 'Already cloned', path: targetDir });
|
|
4808
|
-
}
|
|
4809
|
-
const githubToken = process.env.GITHUB_TOKEN;
|
|
4810
|
-
if (!githubToken) {
|
|
4811
|
-
return res.status(500).json({ success: false, error: 'GITHUB_TOKEN not available' });
|
|
4812
|
-
}
|
|
4813
|
-
const cloneUrl = `https://x-access-token:${githubToken}@github.com/${fullName}.git`;
|
|
4814
|
-
try {
|
|
4815
|
-
// Use execFile to avoid shell injection
|
|
4816
|
-
await new Promise((resolve, reject) => {
|
|
4817
|
-
execFile('git', ['clone', cloneUrl, targetDir], { timeout: 120000 }, (error, _stdout, stderr) => {
|
|
4818
|
-
if (error) {
|
|
4819
|
-
reject(new Error(stderr || error.message));
|
|
4820
|
-
}
|
|
4821
|
-
else {
|
|
4822
|
-
resolve();
|
|
4823
|
-
}
|
|
4824
|
-
});
|
|
4825
|
-
});
|
|
4826
|
-
// Mark directory as safe for git
|
|
4827
|
-
execFile('git', ['config', '--global', '--add', 'safe.directory', targetDir], () => { });
|
|
4828
|
-
res.json({ success: true, path: targetDir });
|
|
4829
|
-
}
|
|
4830
|
-
catch (err) {
|
|
4831
|
-
// Sanitize error message to avoid leaking GITHUB_TOKEN embedded in the clone URL
|
|
4832
|
-
const safeMessage = (err.message || 'Clone failed').replace(/https:\/\/[^@]+@/g, 'https://***@');
|
|
4833
|
-
console.error('[api/repos/clone] Clone failed:', safeMessage);
|
|
4834
|
-
res.status(500).json({ success: false, error: safeMessage });
|
|
4835
|
-
}
|
|
4836
|
-
});
|
|
4837
4761
|
/**
|
|
4838
4762
|
* POST /api/spawn/architect - Spawn an Architect agent for bridge mode
|
|
4839
4763
|
* Body: { cli?: string }
|
|
@@ -4984,7 +4908,6 @@ Start by greeting the project leads and asking for status updates.`;
|
|
|
4984
4908
|
spawnedAt: worker.spawnedAt,
|
|
4985
4909
|
task: worker.task,
|
|
4986
4910
|
team: worker.team,
|
|
4987
|
-
cwd: agentCwdMap.get(worker.name) || worker.cwd,
|
|
4988
4911
|
source: 'spawner',
|
|
4989
4912
|
});
|
|
4990
4913
|
}
|
|
@@ -5055,7 +4978,6 @@ Start by greeting the project leads and asking for status updates.`;
|
|
|
5055
4978
|
released = await spawner.release(name);
|
|
5056
4979
|
}
|
|
5057
4980
|
if (released) {
|
|
5058
|
-
agentCwdMap.delete(name);
|
|
5059
4981
|
broadcastData().catch(() => { });
|
|
5060
4982
|
// Broadcast agent_released event to activity feed
|
|
5061
4983
|
broadcastPresence({
|