@sulala/agent-os 0.1.23 → 0.1.24
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/dashboard-dist/assets/index-CVI9FAmG.css +1 -0
- package/dashboard-dist/assets/index-DdMu_Z6v.js +75 -0
- package/dashboard-dist/index.html +2 -2
- package/data/agents/crm_hubspot_agent.json +11 -0
- package/data/agents/research_agent.json +1 -1
- package/data/agents/social_media_agent.json +1 -1
- package/data/agents/source_verify_agent.json +10 -0
- package/data/agents/writer_agent.json +1 -1
- package/data/skills/content-writing/SKILL.md +32 -0
- package/dist/cli.js +123 -46
- package/dist/index.js +113 -35
- package/package.json +1 -1
- package/data/skills/gmail/SKILL.md +0 -55
- package/data/skills/gmail/references/send-email.md +0 -54
- package/data/skills/gmail/scripts/send_email.py +0 -94
- package/data/skills/youtube/SKILL.md +0 -91
- package/data/skills/youtube/config.schema.json +0 -11
- package/data/skills/youtube/package.json +0 -8
- package/data/skills/youtube/references/youtube-upload.md +0 -65
- package/data/skills/youtube/requirements.txt +0 -3
- package/data/skills/youtube/scripts/youtube_upload.js +0 -200
- package/data/skills/youtube/scripts/youtube_upload.py +0 -125
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/png" href="/logo_dark.png" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Sulala Agent Dashboard</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DdMu_Z6v.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-CVI9FAmG.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "crm_hubspot_agent",
|
|
3
|
+
"name": "HubSpot CRM Agent",
|
|
4
|
+
"description": "Updates HubSpot from pipeline output: creates and updates contacts and deals using the crm-hubspot skill. Use as the last node in a sales graph to sync follow-up and lead status to HubSpot. Configure HUBSPOT_ACCESS_TOKEN in Skills → crm-hubspot.",
|
|
5
|
+
"model": "gpt-4o-mini",
|
|
6
|
+
"skills": ["memory", "crm-hubspot"],
|
|
7
|
+
"personality": "Concise and factual. Parse the input, call the crm-hubspot scripts via exec with skill_id 'crm-hubspot', then return only a short summary of what was created or updated in HubSpot.",
|
|
8
|
+
"limits": {
|
|
9
|
+
"max_turns": 15
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "research_agent",
|
|
3
3
|
"name": "Research Assistant",
|
|
4
|
-
"description": "Search the web, fetch and summarize URLs, and follow RSS feeds. Use when the user asks to search for something, read a page, or get updates from a feed. Configure web-search API key in the skill if required.",
|
|
4
|
+
"description": "Search the web, fetch and summarize URLs, and follow RSS feeds. Use when the user asks to search for something, read a page, or get updates from a feed. In a graph/pipeline, only output your finding (e.g. the news summary); do not post to social media or delegate to other agents. Configure web-search API key in the skill if required.",
|
|
5
5
|
"model": "gpt-4o-mini",
|
|
6
6
|
"skills": ["memory", "web-search", "fetch", "rss"],
|
|
7
7
|
"limits": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "social_media_agent",
|
|
3
3
|
"name": "Social Media Assistant",
|
|
4
|
-
"description": "Post to social networks (e.g. Bluesky), read your timeline, and reply to posts. Configure credentials in the skill (Agents → Edit → Skills, or Settings). Currently supports Bluesky.",
|
|
4
|
+
"description": "Post to social networks (e.g. Bluesky), read your timeline, and reply to posts. When used as the last node in a graph, post the text you receive to Bluesky. Configure credentials in the skill (Agents → Edit → Skills, or Settings). Currently supports Bluesky.",
|
|
5
5
|
"model": "gpt-4o-mini",
|
|
6
6
|
"skills": ["memory", "bluesky"],
|
|
7
7
|
"limits": {
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "source_verify_agent",
|
|
3
|
+
"name": "Source Verify Agent",
|
|
4
|
+
"description": "Verify and summarize sources for news or claims. Use when the user or a pipeline asks to verify a source or fact-check. In a graph/pipeline, only output your verification result; do not post to social media or delegate to other agents.",
|
|
5
|
+
"model": "gpt-4o-mini",
|
|
6
|
+
"skills": ["memory", "web-search", "fetch"],
|
|
7
|
+
"limits": {
|
|
8
|
+
"max_turns": 15
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "writer_agent",
|
|
3
3
|
"name": "Writer Assistant",
|
|
4
|
-
"description": "Draft and send email (Gmail) and translate text. Use when the user wants to send an email or translate content. Gmail requires connection via Portal or skill config.",
|
|
4
|
+
"description": "Draft and send email (Gmail) and translate text. Use when the user wants to send an email or translate content. In a graph/pipeline, only rewrite or draft the content you are given; do not post to social media or delegate to other agents. Gmail requires connection via Portal or skill config.",
|
|
5
5
|
"model": "gpt-4o-mini",
|
|
6
6
|
"skills": ["memory", "gmail", "translate"],
|
|
7
7
|
"limits": {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: content-writing
|
|
3
|
+
description: Guidelines for writing articles and summaries. Use when the agent is the Writer in a newsroom pipeline, or when the user asks for an article, summary, or post draft.
|
|
4
|
+
metadata:
|
|
5
|
+
clawdbot:
|
|
6
|
+
emoji: "✍️"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Content writing
|
|
10
|
+
|
|
11
|
+
Use this when you are the **Writer** agent: you receive topics, claims, or bullet points from other agents (e.g. News, Fact) and produce an article or summary.
|
|
12
|
+
|
|
13
|
+
## Output types
|
|
14
|
+
|
|
15
|
+
- **Summary** — Short (2–4 sentences or bullets). Key facts only, neutral tone.
|
|
16
|
+
- **Article** — Headline + 2–5 short paragraphs. Clear structure: lead, key points, closing.
|
|
17
|
+
- **Social post** — One short paragraph or 1–3 sentences, ready for Bluesky or similar (e.g. under 300 characters if needed).
|
|
18
|
+
|
|
19
|
+
## Guidelines
|
|
20
|
+
|
|
21
|
+
1. **Tone:** Neutral and factual for news; avoid speculation unless labeled as such.
|
|
22
|
+
2. **Structure:** Lead with the main point; then supporting details; end with implication or next step if relevant.
|
|
23
|
+
3. **Attribution:** When facts come from a specific source, mention it (e.g. "According to …", "Source: …").
|
|
24
|
+
4. **Length:** Match the requested format (summary vs article vs post). If not specified, default to a short article (3–5 paragraphs).
|
|
25
|
+
5. **No fabrication:** Only state facts that were provided or that you can infer from the given context; do not invent quotes or statistics.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
1. Take the input (topic, verified facts, headlines, or bullet points).
|
|
30
|
+
2. Choose the right output type (summary / article / post).
|
|
31
|
+
3. Draft the content following the guidelines above.
|
|
32
|
+
4. Optionally output in Markdown; if the pipeline needs HTML, the next step can use markdown-to-html.
|
package/dist/cli.js
CHANGED
|
@@ -23180,8 +23180,8 @@ function formatLLMErrorForUser(err) {
|
|
|
23180
23180
|
}
|
|
23181
23181
|
function runAgentInner(options) {
|
|
23182
23182
|
return (async () => {
|
|
23183
|
-
const { task, agent, conversationHistory = [] } = options;
|
|
23184
|
-
const maxTurns = agent.limits?.max_turns ?? 10;
|
|
23183
|
+
const { task, agent, conversationHistory = [], maxTurnsOverride } = options;
|
|
23184
|
+
const maxTurns = maxTurnsOverride ?? agent.limits?.max_turns ?? 10;
|
|
23185
23185
|
const maxTokens = agent.limits?.max_tokens;
|
|
23186
23186
|
await ensureWorkspace(agent.id);
|
|
23187
23187
|
await loadSkillsForAgent(agent);
|
|
@@ -23415,8 +23415,8 @@ async function runAgent(options) {
|
|
|
23415
23415
|
return runAgentInner(options);
|
|
23416
23416
|
}
|
|
23417
23417
|
async function runAgentStream(options, onEvent) {
|
|
23418
|
-
const { task, agent, conversationHistory = [] } = options;
|
|
23419
|
-
const maxTurns = agent.limits?.max_turns ?? 10;
|
|
23418
|
+
const { task, agent, conversationHistory = [], maxTurnsOverride } = options;
|
|
23419
|
+
const maxTurns = maxTurnsOverride ?? agent.limits?.max_turns ?? 10;
|
|
23420
23420
|
const maxTokens = agent.limits?.max_tokens;
|
|
23421
23421
|
await ensureWorkspace(agent.id);
|
|
23422
23422
|
await loadSkillsForAgent(agent);
|
|
@@ -25375,44 +25375,87 @@ var require_node_cron = __commonJS((exports) => {
|
|
|
25375
25375
|
});
|
|
25376
25376
|
|
|
25377
25377
|
// src/core/graphs.ts
|
|
25378
|
-
import { readFile as readFile7, readdir as readdir4, writeFile as writeFile4, mkdir as mkdir5 } from "fs/promises";
|
|
25378
|
+
import { readFile as readFile7, readdir as readdir4, writeFile as writeFile4, mkdir as mkdir5, copyFile, unlink as unlink2 } from "fs/promises";
|
|
25379
25379
|
import { join as join9 } from "path";
|
|
25380
|
+
import { existsSync as existsSync3 } from "fs";
|
|
25380
25381
|
function getGraphsDir() {
|
|
25381
25382
|
return process.env.AGENT_OS_GRAPHS_DIR || DEFAULT_GRAPHS_DIR;
|
|
25382
25383
|
}
|
|
25384
|
+
function getSeedGraphsDir() {
|
|
25385
|
+
if (process.env.AGENT_OS_SEED_GRAPHS_DIR)
|
|
25386
|
+
return process.env.AGENT_OS_SEED_GRAPHS_DIR;
|
|
25387
|
+
const fromDist = join9(import.meta.dir, "..", "data", "graphs");
|
|
25388
|
+
const fromSrc = join9(import.meta.dir, "..", "..", "data", "graphs");
|
|
25389
|
+
if (existsSync3(fromDist))
|
|
25390
|
+
return fromDist;
|
|
25391
|
+
if (existsSync3(fromSrc))
|
|
25392
|
+
return fromSrc;
|
|
25393
|
+
return join9(process.cwd(), "data", "graphs");
|
|
25394
|
+
}
|
|
25383
25395
|
async function listGraphs() {
|
|
25384
25396
|
const dir = getGraphsDir();
|
|
25397
|
+
let entries;
|
|
25385
25398
|
try {
|
|
25386
|
-
|
|
25387
|
-
|
|
25388
|
-
|
|
25389
|
-
|
|
25390
|
-
|
|
25391
|
-
|
|
25392
|
-
|
|
25399
|
+
entries = await readdir4(dir);
|
|
25400
|
+
} catch (err) {
|
|
25401
|
+
if (err.code !== "ENOENT")
|
|
25402
|
+
throw err;
|
|
25403
|
+
entries = [];
|
|
25404
|
+
}
|
|
25405
|
+
if (entries.length === 0) {
|
|
25406
|
+
const seedDir = getSeedGraphsDir();
|
|
25407
|
+
try {
|
|
25408
|
+
const seedEntries = await readdir4(seedDir);
|
|
25409
|
+
await mkdir5(dir, { recursive: true });
|
|
25410
|
+
for (const name of seedEntries) {
|
|
25411
|
+
if (name.endsWith(".json")) {
|
|
25412
|
+
await copyFile(join9(seedDir, name), join9(dir, name));
|
|
25413
|
+
}
|
|
25393
25414
|
}
|
|
25415
|
+
entries = await readdir4(dir);
|
|
25416
|
+
} catch {}
|
|
25417
|
+
}
|
|
25418
|
+
const summaries = [];
|
|
25419
|
+
for (const name of entries) {
|
|
25420
|
+
if (name.endsWith(".json")) {
|
|
25421
|
+
const id = name.replace(/\.graph\.json$/, "").replace(/\.json$/, "");
|
|
25422
|
+
if (id)
|
|
25423
|
+
summaries.push({ id });
|
|
25394
25424
|
}
|
|
25395
|
-
return summaries;
|
|
25396
|
-
} catch (err) {
|
|
25397
|
-
if (err.code === "ENOENT")
|
|
25398
|
-
return [];
|
|
25399
|
-
throw err;
|
|
25400
25425
|
}
|
|
25426
|
+
return summaries;
|
|
25401
25427
|
}
|
|
25402
25428
|
async function loadGraph(id) {
|
|
25403
25429
|
const dir = getGraphsDir();
|
|
25404
25430
|
try {
|
|
25405
|
-
|
|
25431
|
+
let entries;
|
|
25432
|
+
try {
|
|
25433
|
+
entries = await readdir4(dir);
|
|
25434
|
+
} catch (e) {
|
|
25435
|
+
if (e.code !== "ENOENT")
|
|
25436
|
+
throw e;
|
|
25437
|
+
entries = [];
|
|
25438
|
+
}
|
|
25406
25439
|
const file = entries.find((name) => name === `${id}.json` || name === `${id}.graph.json`);
|
|
25407
|
-
if (
|
|
25440
|
+
if (file) {
|
|
25441
|
+
const raw = await readFile7(join9(dir, file), "utf-8");
|
|
25442
|
+
const parsed = JSON.parse(raw);
|
|
25443
|
+
validateGraph(parsed);
|
|
25444
|
+
return parsed;
|
|
25445
|
+
}
|
|
25446
|
+
const seedDir = getSeedGraphsDir();
|
|
25447
|
+
const seedFile = `${id}.json`;
|
|
25448
|
+
try {
|
|
25449
|
+
const raw = await readFile7(join9(seedDir, seedFile), "utf-8");
|
|
25450
|
+
const parsed = JSON.parse(raw);
|
|
25451
|
+
validateGraph(parsed);
|
|
25452
|
+
await mkdir5(dir, { recursive: true });
|
|
25453
|
+
await writeFile4(join9(dir, seedFile), raw, "utf-8");
|
|
25454
|
+
return parsed;
|
|
25455
|
+
} catch {
|
|
25408
25456
|
return null;
|
|
25409
|
-
|
|
25410
|
-
const parsed = JSON.parse(raw);
|
|
25411
|
-
validateGraph(parsed);
|
|
25412
|
-
return parsed;
|
|
25457
|
+
}
|
|
25413
25458
|
} catch (err) {
|
|
25414
|
-
if (err.code === "ENOENT")
|
|
25415
|
-
return null;
|
|
25416
25459
|
console.error("[graphs] Failed to load graph:", err);
|
|
25417
25460
|
return null;
|
|
25418
25461
|
}
|
|
@@ -25424,6 +25467,22 @@ async function saveGraph(graph) {
|
|
|
25424
25467
|
const path = join9(dir, `${graph.id}.json`);
|
|
25425
25468
|
await writeFile4(path, JSON.stringify(graph, null, 2), "utf-8");
|
|
25426
25469
|
}
|
|
25470
|
+
async function deleteGraph(id) {
|
|
25471
|
+
if (!id || typeof id !== "string")
|
|
25472
|
+
throw new Error("Graph id required");
|
|
25473
|
+
const dir = getGraphsDir();
|
|
25474
|
+
let entries;
|
|
25475
|
+
try {
|
|
25476
|
+
entries = await readdir4(dir);
|
|
25477
|
+
} catch (err) {
|
|
25478
|
+
if (err.code !== "ENOENT")
|
|
25479
|
+
throw err;
|
|
25480
|
+
return;
|
|
25481
|
+
}
|
|
25482
|
+
const file = entries.find((name) => name === `${id}.json` || name === `${id}.graph.json`);
|
|
25483
|
+
if (file)
|
|
25484
|
+
await unlink2(join9(dir, file));
|
|
25485
|
+
}
|
|
25427
25486
|
function validateGraph(graph) {
|
|
25428
25487
|
if (!graph || typeof graph !== "object") {
|
|
25429
25488
|
throw new Error("Graph must be an object");
|
|
@@ -25490,7 +25549,7 @@ function getPredecessors(graph) {
|
|
|
25490
25549
|
return pred;
|
|
25491
25550
|
}
|
|
25492
25551
|
async function runGraph(options) {
|
|
25493
|
-
const { graph, input } = options;
|
|
25552
|
+
const { graph, input, max_turns_per_node = DEFAULT_GRAPH_MAX_TURNS_PER_NODE } = options;
|
|
25494
25553
|
const levels = topologicalLevels(graph);
|
|
25495
25554
|
const predecessors = getPredecessors(graph);
|
|
25496
25555
|
const outputs = new Map;
|
|
@@ -25515,7 +25574,11 @@ async function runGraph(options) {
|
|
|
25515
25574
|
const taskInput = preds.length === 0 ? input : preds.map((p) => outputs.get(p) ?? "").filter(Boolean).join(`
|
|
25516
25575
|
|
|
25517
25576
|
`) || input;
|
|
25518
|
-
const result = await runAgent({
|
|
25577
|
+
const result = await runAgent({
|
|
25578
|
+
agent,
|
|
25579
|
+
task: taskInput,
|
|
25580
|
+
maxTurnsOverride: max_turns_per_node
|
|
25581
|
+
});
|
|
25519
25582
|
outputs.set(node.id, result.output || "");
|
|
25520
25583
|
return {
|
|
25521
25584
|
node_id: node.id,
|
|
@@ -25538,7 +25601,7 @@ async function runGraph(options) {
|
|
|
25538
25601
|
};
|
|
25539
25602
|
}
|
|
25540
25603
|
async function runGraphStream(options, onEvent) {
|
|
25541
|
-
const { graph, input } = options;
|
|
25604
|
+
const { graph, input, max_turns_per_node = DEFAULT_GRAPH_MAX_TURNS_PER_NODE } = options;
|
|
25542
25605
|
const levels = topologicalLevels(graph);
|
|
25543
25606
|
const predecessors = getPredecessors(graph);
|
|
25544
25607
|
const outputs = new Map;
|
|
@@ -25564,7 +25627,11 @@ async function runGraphStream(options, onEvent) {
|
|
|
25564
25627
|
const taskInput = preds.length === 0 ? input : preds.map((p) => outputs.get(p) ?? "").filter(Boolean).join(`
|
|
25565
25628
|
|
|
25566
25629
|
`) || input;
|
|
25567
|
-
const result = await runAgent({
|
|
25630
|
+
const result = await runAgent({
|
|
25631
|
+
agent,
|
|
25632
|
+
task: taskInput,
|
|
25633
|
+
maxTurnsOverride: max_turns_per_node
|
|
25634
|
+
});
|
|
25568
25635
|
outputs.set(node.id, result.output || "");
|
|
25569
25636
|
const payload = {
|
|
25570
25637
|
node_id: node.id,
|
|
@@ -25592,7 +25659,7 @@ async function runGraphStream(options, onEvent) {
|
|
|
25592
25659
|
throw err;
|
|
25593
25660
|
}
|
|
25594
25661
|
}
|
|
25595
|
-
var DEFAULT_GRAPHS_DIR;
|
|
25662
|
+
var DEFAULT_GRAPHS_DIR, DEFAULT_GRAPH_MAX_TURNS_PER_NODE = 5;
|
|
25596
25663
|
var init_graphs = __esm(() => {
|
|
25597
25664
|
init_agent_registry();
|
|
25598
25665
|
init_runtime();
|
|
@@ -29609,7 +29676,7 @@ __export(exports_server, {
|
|
|
29609
29676
|
startServer: () => startServer
|
|
29610
29677
|
});
|
|
29611
29678
|
import { join as join13, dirname as dirname2, resolve as resolve4 } from "path";
|
|
29612
|
-
import { mkdirSync, existsSync as
|
|
29679
|
+
import { mkdirSync, existsSync as existsSync4 } from "fs";
|
|
29613
29680
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
29614
29681
|
function isAuthExempt(pathname, method) {
|
|
29615
29682
|
if (method === "OPTIONS")
|
|
@@ -29683,7 +29750,7 @@ function broadcastEvent(event) {
|
|
|
29683
29750
|
}
|
|
29684
29751
|
}
|
|
29685
29752
|
function serveDashboard(pathname) {
|
|
29686
|
-
if (!
|
|
29753
|
+
if (!existsSync4(DASHBOARD_DIST) || !existsSync4(join13(DASHBOARD_DIST, "index.html"))) {
|
|
29687
29754
|
return null;
|
|
29688
29755
|
}
|
|
29689
29756
|
const decoded = decodeURIComponent(pathname);
|
|
@@ -29692,7 +29759,7 @@ function serveDashboard(pathname) {
|
|
|
29692
29759
|
}
|
|
29693
29760
|
const subpath = decoded === "/" ? "index.html" : decoded.slice(1);
|
|
29694
29761
|
const filePath = join13(DASHBOARD_DIST, subpath);
|
|
29695
|
-
if (
|
|
29762
|
+
if (existsSync4(filePath)) {
|
|
29696
29763
|
const file = Bun.file(filePath);
|
|
29697
29764
|
const ext = subpath.split(".").pop() ?? "";
|
|
29698
29765
|
const mime = {
|
|
@@ -29713,7 +29780,7 @@ function serveDashboard(pathname) {
|
|
|
29713
29780
|
});
|
|
29714
29781
|
}
|
|
29715
29782
|
const indexPath = join13(DASHBOARD_DIST, "index.html");
|
|
29716
|
-
if (
|
|
29783
|
+
if (existsSync4(indexPath)) {
|
|
29717
29784
|
return new Response(Bun.file(indexPath), {
|
|
29718
29785
|
headers: { "Content-Type": "text/html" }
|
|
29719
29786
|
});
|
|
@@ -29930,6 +29997,16 @@ function createRoutes() {
|
|
|
29930
29997
|
const msg = e instanceof Error ? e.message : String(e);
|
|
29931
29998
|
return jsonResponse({ error: msg }, 400);
|
|
29932
29999
|
}
|
|
30000
|
+
},
|
|
30001
|
+
DELETE: async (req) => {
|
|
30002
|
+
const id = decodeURIComponent(req.params.id);
|
|
30003
|
+
try {
|
|
30004
|
+
await deleteGraph(id);
|
|
30005
|
+
return Response.json({ ok: true }, { headers: CORS_HEADERS });
|
|
30006
|
+
} catch (e) {
|
|
30007
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
30008
|
+
return jsonResponse({ error: msg }, 400);
|
|
30009
|
+
}
|
|
29933
30010
|
}
|
|
29934
30011
|
},
|
|
29935
30012
|
"/api/memory/write": {
|
|
@@ -30150,7 +30227,7 @@ async function startServer() {
|
|
|
30150
30227
|
await loadPlugins();
|
|
30151
30228
|
await seedAgentsIfEmpty();
|
|
30152
30229
|
const dashboardSecret = await getDashboardSecret();
|
|
30153
|
-
const dashboardMissing = !
|
|
30230
|
+
const dashboardMissing = !existsSync4(DASHBOARD_DIST) || !existsSync4(join13(DASHBOARD_DIST, "index.html"));
|
|
30154
30231
|
if (dashboardMissing) {
|
|
30155
30232
|
console.warn(`[sulala] Dashboard not found at ${DASHBOARD_DIST}. From package root run: cd dashboard && npm run build. If using a global install, reinstall: bun install -g @sulala/agent-os@latest`);
|
|
30156
30233
|
}
|
|
@@ -30239,7 +30316,7 @@ var init_server = __esm(() => {
|
|
|
30239
30316
|
const root = join13(import.meta.dir, "..");
|
|
30240
30317
|
const a = resolve4(join13(root, "dashboard-dist"));
|
|
30241
30318
|
const b = resolve4(join13(root, "dashboard", "dist"));
|
|
30242
|
-
if (
|
|
30319
|
+
if (existsSync4(a) && existsSync4(join13(a, "index.html")))
|
|
30243
30320
|
return a;
|
|
30244
30321
|
return b;
|
|
30245
30322
|
})();
|
|
@@ -30272,8 +30349,8 @@ init_loader();
|
|
|
30272
30349
|
init_agent_registry();
|
|
30273
30350
|
init_runtime();
|
|
30274
30351
|
import { join as join14, dirname as dirname3 } from "path";
|
|
30275
|
-
import { readFile as readFile10, writeFile as writeFile6, mkdir as mkdir8, unlink as
|
|
30276
|
-
import { existsSync as
|
|
30352
|
+
import { readFile as readFile10, writeFile as writeFile6, mkdir as mkdir8, unlink as unlink3 } from "fs/promises";
|
|
30353
|
+
import { existsSync as existsSync5, readFileSync } from "fs";
|
|
30277
30354
|
var PID_FILE = join14(getAgentOsHome(), "sulala.pid");
|
|
30278
30355
|
var DEFAULT_PORT = 3010;
|
|
30279
30356
|
function openDashboard() {
|
|
@@ -30336,7 +30413,7 @@ async function cmdStart(args) {
|
|
|
30336
30413
|
await mkdir8(getAgentOsHome(), { recursive: true });
|
|
30337
30414
|
const projectRoot = join14(import.meta.dir, "..");
|
|
30338
30415
|
const distEntry = join14(projectRoot, "dist", "index.js");
|
|
30339
|
-
const serverEntry =
|
|
30416
|
+
const serverEntry = existsSync5(distEntry) ? "dist/index.js" : "src/index.ts";
|
|
30340
30417
|
const child = Bun.spawn(["bun", "run", serverEntry], {
|
|
30341
30418
|
cwd: projectRoot,
|
|
30342
30419
|
stdout: "ignore",
|
|
@@ -30353,7 +30430,7 @@ async function cmdStart(args) {
|
|
|
30353
30430
|
await startServer2();
|
|
30354
30431
|
}
|
|
30355
30432
|
async function cmdStop() {
|
|
30356
|
-
if (!
|
|
30433
|
+
if (!existsSync5(PID_FILE)) {
|
|
30357
30434
|
console.error("No PID file found. Is the server running with 'sulala start --daemon'?");
|
|
30358
30435
|
process.exit(1);
|
|
30359
30436
|
}
|
|
@@ -30374,11 +30451,11 @@ async function cmdStop() {
|
|
|
30374
30451
|
process.exit(1);
|
|
30375
30452
|
}
|
|
30376
30453
|
}
|
|
30377
|
-
await
|
|
30454
|
+
await unlink3(PID_FILE).catch(() => {});
|
|
30378
30455
|
console.log("Sulala server stopped.");
|
|
30379
30456
|
}
|
|
30380
30457
|
async function startServerDaemonIfNeeded() {
|
|
30381
|
-
if (
|
|
30458
|
+
if (existsSync5(PID_FILE)) {
|
|
30382
30459
|
try {
|
|
30383
30460
|
const pidStr = await readFile10(PID_FILE, "utf-8");
|
|
30384
30461
|
const pid = parseInt(pidStr.trim(), 10);
|
|
@@ -30391,7 +30468,7 @@ async function startServerDaemonIfNeeded() {
|
|
|
30391
30468
|
await mkdir8(getAgentOsHome(), { recursive: true });
|
|
30392
30469
|
const projectRoot = join14(import.meta.dir, "..");
|
|
30393
30470
|
const distEntry = join14(projectRoot, "dist", "index.js");
|
|
30394
|
-
const serverEntry =
|
|
30471
|
+
const serverEntry = existsSync5(distEntry) ? "dist/index.js" : "src/index.ts";
|
|
30395
30472
|
const child = Bun.spawn(["bun", "run", serverEntry], {
|
|
30396
30473
|
cwd: projectRoot,
|
|
30397
30474
|
stdout: "ignore",
|
|
@@ -30408,7 +30485,7 @@ async function cmdOnboard() {
|
|
|
30408
30485
|
await mkdir8(home, { recursive: true });
|
|
30409
30486
|
await mkdir8(dirname3(getMemoryDbPath()), { recursive: true });
|
|
30410
30487
|
const configPath = join14(home, "config.json");
|
|
30411
|
-
if (!
|
|
30488
|
+
if (!existsSync5(configPath)) {
|
|
30412
30489
|
const dashboardSecret = generateDashboardSecret();
|
|
30413
30490
|
await writeFile6(configPath, JSON.stringify({
|
|
30414
30491
|
provider: null,
|
|
@@ -30471,7 +30548,7 @@ async function cmdUpdate() {
|
|
|
30471
30548
|
console.warn("Could not update package from npm (run 'bun install -g @sulala/agent-os@latest' manually):", err.trim() || out.trim());
|
|
30472
30549
|
}
|
|
30473
30550
|
const dbPath = getMemoryDbPath();
|
|
30474
|
-
if (!
|
|
30551
|
+
if (!existsSync5(dbPath)) {
|
|
30475
30552
|
console.log("No database found. Run 'sulala onboard' to set up agents and skills.");
|
|
30476
30553
|
return;
|
|
30477
30554
|
}
|
|
@@ -30511,7 +30588,7 @@ async function cmdRun(args) {
|
|
|
30511
30588
|
process.exit(1);
|
|
30512
30589
|
}
|
|
30513
30590
|
const dbPath = getMemoryDbPath();
|
|
30514
|
-
if (
|
|
30591
|
+
if (existsSync5(dbPath)) {
|
|
30515
30592
|
setAgentStore(new MemoryStore(dbPath));
|
|
30516
30593
|
}
|
|
30517
30594
|
const agent = await getAgent(agentId);
|