@fancyboi999/open-tag-daemon 0.3.0 → 0.5.0
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/cli.mjs +154 -7
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -5329,6 +5329,132 @@ var cursorRuntime = {
|
|
|
5329
5329
|
}
|
|
5330
5330
|
};
|
|
5331
5331
|
|
|
5332
|
+
// src/daemon/demoRuntime.ts
|
|
5333
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
5334
|
+
var DEMO_NOTICE = "I'm a **demo agent** running on a no-op runtime \u2014 I don't call any LLM, so I can't do real work here. To get a real AI teammate, self-host open-tag and connect a runtime like Claude Code, Codex, or your own API key. See [getopentag.com](https://getopentag.com) to get started.";
|
|
5335
|
+
var GREETINGS = ["Hi there! \u{1F44B}", "Hello again! \u{1F44B}", "Hey! \u{1F44B}", "Thanks for your message! \u{1F44B}", "Received! \u{1F44B}"];
|
|
5336
|
+
function extractBody(text) {
|
|
5337
|
+
const m = /\] [^:]+: (.+)$/s.exec(text);
|
|
5338
|
+
return m ? m[1].trim() : "";
|
|
5339
|
+
}
|
|
5340
|
+
function extractTarget(text) {
|
|
5341
|
+
const m = /^\[target=(\S+)/.exec(text);
|
|
5342
|
+
return m ? m[1] : null;
|
|
5343
|
+
}
|
|
5344
|
+
function buildReply(userBody, turnIndex) {
|
|
5345
|
+
const greeting = GREETINGS[turnIndex % GREETINGS.length];
|
|
5346
|
+
const snippet = userBody.slice(0, 120);
|
|
5347
|
+
const tail = userBody.length > 120 ? "\u2026" : "";
|
|
5348
|
+
const echo = snippet ? `
|
|
5349
|
+
|
|
5350
|
+
> You said: "${snippet}${tail}"` : "";
|
|
5351
|
+
return `${greeting} ${DEMO_NOTICE}${echo}`;
|
|
5352
|
+
}
|
|
5353
|
+
function makeTransport(serverUrl2, agentToken, agentId) {
|
|
5354
|
+
const base = serverUrl2.replace(/\/$/, "");
|
|
5355
|
+
const headers = {
|
|
5356
|
+
"Authorization": `Bearer ${agentToken}`,
|
|
5357
|
+
"x-agent-id": agentId,
|
|
5358
|
+
"Content-Type": "application/json"
|
|
5359
|
+
};
|
|
5360
|
+
return {
|
|
5361
|
+
async check() {
|
|
5362
|
+
const r = await fetch(`${base}/agent-api/message/check`, { headers });
|
|
5363
|
+
const d = await r.json();
|
|
5364
|
+
return d.messages ?? [];
|
|
5365
|
+
},
|
|
5366
|
+
async send(target, content) {
|
|
5367
|
+
await fetch(`${base}/agent-api/message/send`, {
|
|
5368
|
+
method: "POST",
|
|
5369
|
+
headers,
|
|
5370
|
+
body: JSON.stringify({ target, content })
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
};
|
|
5374
|
+
}
|
|
5375
|
+
var DemoRun = class {
|
|
5376
|
+
constructor(opts, cb, transport) {
|
|
5377
|
+
this.opts = opts;
|
|
5378
|
+
this.cb = cb;
|
|
5379
|
+
this.sessionId = opts.sessionId || randomUUID2();
|
|
5380
|
+
this.transport = transport ?? makeTransport(
|
|
5381
|
+
opts.env.OPEN_TAG_SERVER_URL ?? "",
|
|
5382
|
+
opts.env.OPEN_TAG_AGENT_TOKEN ?? "",
|
|
5383
|
+
opts.env.OPEN_TAG_AGENT_ID ?? ""
|
|
5384
|
+
);
|
|
5385
|
+
cb.onSession(this.sessionId);
|
|
5386
|
+
this.enqueue(opts.initialPrompt);
|
|
5387
|
+
}
|
|
5388
|
+
opts;
|
|
5389
|
+
cb;
|
|
5390
|
+
sessionId;
|
|
5391
|
+
queue = [];
|
|
5392
|
+
turnBusy = false;
|
|
5393
|
+
stopped = false;
|
|
5394
|
+
turnIndex = 0;
|
|
5395
|
+
transport;
|
|
5396
|
+
enqueue(text) {
|
|
5397
|
+
if (this.stopped) return;
|
|
5398
|
+
this.queue.push(text);
|
|
5399
|
+
this.pump();
|
|
5400
|
+
}
|
|
5401
|
+
pump() {
|
|
5402
|
+
if (this.stopped || this.turnBusy || this.queue.length === 0) return;
|
|
5403
|
+
this.runTurn(this.queue.shift());
|
|
5404
|
+
}
|
|
5405
|
+
// Each turn: check messages → for each pending target, build + post a demo reply → mark online.
|
|
5406
|
+
// Uses setImmediate to stay non-blocking before the await chain takes over.
|
|
5407
|
+
runTurn(_prompt) {
|
|
5408
|
+
this.turnBusy = true;
|
|
5409
|
+
this.cb.onActivity("working", "turn");
|
|
5410
|
+
setImmediate(() => void this.executeTurn());
|
|
5411
|
+
}
|
|
5412
|
+
async executeTurn() {
|
|
5413
|
+
if (this.stopped) {
|
|
5414
|
+
this.turnBusy = false;
|
|
5415
|
+
return;
|
|
5416
|
+
}
|
|
5417
|
+
try {
|
|
5418
|
+
const messages = await this.transport.check();
|
|
5419
|
+
if (!messages.length) {
|
|
5420
|
+
this.cb.onActivity("online", "");
|
|
5421
|
+
this.turnBusy = false;
|
|
5422
|
+
this.pump();
|
|
5423
|
+
return;
|
|
5424
|
+
}
|
|
5425
|
+
const byTarget = /* @__PURE__ */ new Map();
|
|
5426
|
+
for (const m of messages) {
|
|
5427
|
+
const target = extractTarget(m.text);
|
|
5428
|
+
if (!target) continue;
|
|
5429
|
+
byTarget.set(target, extractBody(m.text));
|
|
5430
|
+
}
|
|
5431
|
+
for (const [target, body] of byTarget) {
|
|
5432
|
+
const reply = buildReply(body, this.turnIndex++);
|
|
5433
|
+
this.cb.onTrajectory([{ kind: "text", text: reply }]);
|
|
5434
|
+
await this.transport.send(target, reply);
|
|
5435
|
+
}
|
|
5436
|
+
} catch (e) {
|
|
5437
|
+
this.cb.log.warn("demo: turn failed", { detail: String(e?.message ?? e) });
|
|
5438
|
+
}
|
|
5439
|
+
if (!this.stopped) {
|
|
5440
|
+
this.cb.onActivity("online", "");
|
|
5441
|
+
this.turnBusy = false;
|
|
5442
|
+
this.pump();
|
|
5443
|
+
}
|
|
5444
|
+
}
|
|
5445
|
+
stop() {
|
|
5446
|
+
this.stopped = true;
|
|
5447
|
+
}
|
|
5448
|
+
};
|
|
5449
|
+
var demoRuntime = {
|
|
5450
|
+
name: "demo",
|
|
5451
|
+
experimental: true,
|
|
5452
|
+
start(opts, cb) {
|
|
5453
|
+
const run = new DemoRun(opts, cb);
|
|
5454
|
+
return { deliver: (text) => run.enqueue(text), stop: () => run.stop() };
|
|
5455
|
+
}
|
|
5456
|
+
};
|
|
5457
|
+
|
|
5332
5458
|
// src/daemon/runtimes.ts
|
|
5333
5459
|
function has(tool) {
|
|
5334
5460
|
try {
|
|
@@ -5340,9 +5466,9 @@ function has(tool) {
|
|
|
5340
5466
|
}
|
|
5341
5467
|
function detectRuntimes() {
|
|
5342
5468
|
const found = ["claude", "codex", "copilot", "kimi", "opencode", "pi", "cursor-agent"].filter(has).map((t) => t === "cursor-agent" ? "cursor" : t);
|
|
5343
|
-
return found;
|
|
5469
|
+
return [...found, "demo"];
|
|
5344
5470
|
}
|
|
5345
|
-
var REG = { claude: claudeRuntime, codex: codexRuntime, copilot: copilotRuntime, opencode: opencodeRuntime, kimi: kimiRuntime, pi: piRuntime, cursor: cursorRuntime };
|
|
5471
|
+
var REG = { claude: claudeRuntime, codex: codexRuntime, copilot: copilotRuntime, opencode: opencodeRuntime, kimi: kimiRuntime, pi: piRuntime, cursor: cursorRuntime, demo: demoRuntime };
|
|
5346
5472
|
function getRuntime(name) {
|
|
5347
5473
|
return REG[name] ?? null;
|
|
5348
5474
|
}
|
|
@@ -5649,9 +5775,28 @@ async function readSkillsDir(dir, sourcePath) {
|
|
|
5649
5775
|
}
|
|
5650
5776
|
return out;
|
|
5651
5777
|
}
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5778
|
+
var HOME = os3.homedir();
|
|
5779
|
+
var UNIVERSAL_SKILLS = { dir: path11.join(HOME, ".agents", "skills"), label: "~/.agents/skills" };
|
|
5780
|
+
var PROVIDER_HOME_SKILLS = {
|
|
5781
|
+
claude: { dir: path11.join(HOME, ".claude", "skills"), label: "~/.claude/skills" },
|
|
5782
|
+
codex: { dir: path11.join(process.env.CODEX_HOME || path11.join(HOME, ".codex"), "skills"), label: "~/.codex/skills" },
|
|
5783
|
+
copilot: { dir: path11.join(HOME, ".copilot", "skills"), label: "~/.copilot/skills" },
|
|
5784
|
+
opencode: { dir: path11.join(HOME, ".config", "opencode", "skills"), label: "~/.config/opencode/skills" },
|
|
5785
|
+
cursor: { dir: path11.join(HOME, ".cursor", "skills"), label: "~/.cursor/skills" },
|
|
5786
|
+
pi: { dir: path11.join(HOME, ".pi", "agent", "skills"), label: "~/.pi/agent/skills" }
|
|
5787
|
+
};
|
|
5788
|
+
var PROVIDER_WS_DIR = { claude: ".claude", codex: ".codex", copilot: ".copilot", opencode: ".opencode", cursor: ".cursor", pi: ".pi" };
|
|
5789
|
+
function skillRootsFor(runtime, agentId) {
|
|
5790
|
+
const home = PROVIDER_HOME_SKILLS[runtime];
|
|
5791
|
+
const global = home ? [home, UNIVERSAL_SKILLS] : [UNIVERSAL_SKILLS];
|
|
5792
|
+
const wsName = PROVIDER_WS_DIR[runtime];
|
|
5793
|
+
const workspace = wsName ? { dir: path11.join(DATA_DIR2, agentId, wsName, "skills"), label: `<workspace>/${wsName}/skills` } : null;
|
|
5794
|
+
return { global, workspace };
|
|
5795
|
+
}
|
|
5796
|
+
async function listSkills(agentId, runtime = "claude") {
|
|
5797
|
+
const roots = skillRootsFor(runtime, agentId);
|
|
5798
|
+
const global = (await Promise.all(roots.global.map((r) => readSkillsDir(r.dir, r.label)))).flat();
|
|
5799
|
+
const workspace = roots.workspace ? await readSkillsDir(roots.workspace.dir, roots.workspace.label) : [];
|
|
5655
5800
|
return { global, workspace };
|
|
5656
5801
|
}
|
|
5657
5802
|
async function readWorkspaceFile(agentId, rel) {
|
|
@@ -5848,6 +5993,8 @@ async function listModels(runtime) {
|
|
|
5848
5993
|
const models = parseCodexModels(r.stdout);
|
|
5849
5994
|
return models.length ? models : null;
|
|
5850
5995
|
}
|
|
5996
|
+
case "demo":
|
|
5997
|
+
return [{ id: "demo", label: "Demo", provider: "demo", default: true }];
|
|
5851
5998
|
default:
|
|
5852
5999
|
return null;
|
|
5853
6000
|
}
|
|
@@ -5916,7 +6063,7 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
|
|
|
5916
6063
|
void readWorkspaceFile(msg.agentId, msg.path ?? "").then((r) => conn.send({ type: "workspace:file_content", requestId: msg.requestId, agentId: msg.agentId, ...r }));
|
|
5917
6064
|
break;
|
|
5918
6065
|
case "agent:skills:list":
|
|
5919
|
-
void listSkills(msg.agentId).then((r) => conn.send({ type: "skills:list", requestId: msg.requestId, agentId: msg.agentId, ...r }));
|
|
6066
|
+
void listSkills(msg.agentId, msg.runtime).then((r) => conn.send({ type: "skills:list", requestId: msg.requestId, agentId: msg.agentId, ...r }));
|
|
5920
6067
|
break;
|
|
5921
6068
|
case "probe-models":
|
|
5922
6069
|
void listModels(msg.runtime ?? "").then((models) => conn.send({ type: "models", requestId: msg.requestId, runtime: msg.runtime, models })).catch((e) => conn.send({ type: "models", requestId: msg.requestId, runtime: msg.runtime, models: null, error: String(e?.message ?? e) }));
|
|
@@ -5935,7 +6082,7 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
|
|
|
5935
6082
|
runningAgents: mgr.running(),
|
|
5936
6083
|
hostname: os4.hostname(),
|
|
5937
6084
|
os: `${os4.platform()} ${os4.arch()}`,
|
|
5938
|
-
daemonVersion: "0.
|
|
6085
|
+
daemonVersion: "0.5.0",
|
|
5939
6086
|
machineId: readMachineId()
|
|
5940
6087
|
// Stable identity: empty on first connection; server sends it back via ready:ack for persistence.
|
|
5941
6088
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fancyboi999/open-tag-daemon",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "open-tag compute-plane daemon — connect any machine to an open-tag server so its agents run there. No repo clone needed.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|