@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.
Files changed (2) hide show
  1. package/dist/cli.mjs +154 -7
  2. 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
- async function listSkills(agentId) {
5653
- const global = await readSkillsDir(path11.join(os3.homedir(), ".claude", "skills"), "~/.claude/skills");
5654
- const workspace = await readSkillsDir(path11.join(DATA_DIR2, agentId, ".claude", "skills"), "<workspace>/.claude/skills");
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.3.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.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",