@fancyboi999/open-tag-daemon 0.2.0 → 0.4.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 +211 -5
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -5649,9 +5649,28 @@ async function readSkillsDir(dir, sourcePath) {
5649
5649
  }
5650
5650
  return out;
5651
5651
  }
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");
5652
+ var HOME = os3.homedir();
5653
+ var UNIVERSAL_SKILLS = { dir: path11.join(HOME, ".agents", "skills"), label: "~/.agents/skills" };
5654
+ var PROVIDER_HOME_SKILLS = {
5655
+ claude: { dir: path11.join(HOME, ".claude", "skills"), label: "~/.claude/skills" },
5656
+ codex: { dir: path11.join(process.env.CODEX_HOME || path11.join(HOME, ".codex"), "skills"), label: "~/.codex/skills" },
5657
+ copilot: { dir: path11.join(HOME, ".copilot", "skills"), label: "~/.copilot/skills" },
5658
+ opencode: { dir: path11.join(HOME, ".config", "opencode", "skills"), label: "~/.config/opencode/skills" },
5659
+ cursor: { dir: path11.join(HOME, ".cursor", "skills"), label: "~/.cursor/skills" },
5660
+ pi: { dir: path11.join(HOME, ".pi", "agent", "skills"), label: "~/.pi/agent/skills" }
5661
+ };
5662
+ var PROVIDER_WS_DIR = { claude: ".claude", codex: ".codex", copilot: ".copilot", opencode: ".opencode", cursor: ".cursor", pi: ".pi" };
5663
+ function skillRootsFor(runtime, agentId) {
5664
+ const home = PROVIDER_HOME_SKILLS[runtime];
5665
+ const global = home ? [home, UNIVERSAL_SKILLS] : [UNIVERSAL_SKILLS];
5666
+ const wsName = PROVIDER_WS_DIR[runtime];
5667
+ const workspace = wsName ? { dir: path11.join(DATA_DIR2, agentId, wsName, "skills"), label: `<workspace>/${wsName}/skills` } : null;
5668
+ return { global, workspace };
5669
+ }
5670
+ async function listSkills(agentId, runtime = "claude") {
5671
+ const roots = skillRootsFor(runtime, agentId);
5672
+ const global = (await Promise.all(roots.global.map((r) => readSkillsDir(r.dir, r.label)))).flat();
5673
+ const workspace = roots.workspace ? await readSkillsDir(roots.workspace.dir, roots.workspace.label) : [];
5655
5674
  return { global, workspace };
5656
5675
  }
5657
5676
  async function readWorkspaceFile(agentId, rel) {
@@ -5669,6 +5688,190 @@ async function readWorkspaceFile(agentId, rel) {
5669
5688
  }
5670
5689
  }
5671
5690
 
5691
+ // src/daemon/listModels.ts
5692
+ import { spawn as spawn8 } from "node:child_process";
5693
+ var titleCase = (s) => s ? s[0].toUpperCase() + s.slice(1) : s;
5694
+ function isModelId(s) {
5695
+ return /^[A-Za-z][A-Za-z0-9\-_./]*$/.test(s);
5696
+ }
5697
+ var CLAUDE_MODELS = [
5698
+ { id: "sonnet", label: "Sonnet" },
5699
+ { id: "opus", label: "Opus" },
5700
+ { id: "haiku", label: "Haiku" }
5701
+ ];
5702
+ var CLAUDE_EFFORT_LABEL = {
5703
+ low: "Low",
5704
+ medium: "Medium",
5705
+ high: "High",
5706
+ xhigh: "Extra high",
5707
+ max: "Max"
5708
+ };
5709
+ var CLAUDE_MODEL_EFFORT_ALLOW = {
5710
+ opus: /* @__PURE__ */ new Set(["low", "medium", "high", "xhigh", "max"]),
5711
+ sonnet: /* @__PURE__ */ new Set(["low", "medium", "high", "max"]),
5712
+ haiku: /* @__PURE__ */ new Set(["low", "medium", "high"])
5713
+ };
5714
+ function parseClaudeEffortLevels(helpText) {
5715
+ const m = /--effort\s*(?:<[^>]+>)?\s*(?:Effort level[^(]*)?\(([^)]+)\)/.exec(helpText);
5716
+ if (!m) return [];
5717
+ return m[1].split(",").map((s) => s.trim()).filter((s) => /^[a-z]+$/i.test(s));
5718
+ }
5719
+ function claudeThinkingForModel(modelId, superset) {
5720
+ const allow = CLAUDE_MODEL_EFFORT_ALLOW[modelId];
5721
+ const levels = superset.filter((v) => !allow || allow.has(v)).map((v) => ({ value: v, label: CLAUDE_EFFORT_LABEL[v] ?? titleCase(v) }));
5722
+ if (!levels.length) return void 0;
5723
+ return { levels, default: levels.some((l) => l.value === "medium") ? "medium" : levels[0].value };
5724
+ }
5725
+ function parseCodexModels(jsonStr) {
5726
+ let parsed;
5727
+ try {
5728
+ parsed = JSON.parse(jsonStr);
5729
+ } catch {
5730
+ return [];
5731
+ }
5732
+ const models = Array.isArray(parsed?.models) ? parsed.models : [];
5733
+ const out = [];
5734
+ for (const m of models) {
5735
+ if (m?.visibility !== "list") continue;
5736
+ const slug = typeof m?.slug === "string" ? m.slug : "";
5737
+ if (!slug) continue;
5738
+ const raw = Array.isArray(m?.supported_reasoning_levels) ? m.supported_reasoning_levels : [];
5739
+ const levels = raw.map((l) => ({ value: String(l?.effort ?? ""), label: titleCase(String(l?.effort ?? "")), description: typeof l?.description === "string" ? l.description : void 0 })).filter((l) => l.value);
5740
+ const thinking = levels.length ? { levels, default: typeof m?.default_reasoning_level === "string" ? m.default_reasoning_level : void 0 } : void 0;
5741
+ out.push({ id: slug, label: typeof m?.display_name === "string" && m.display_name ? m.display_name : slug, provider: "openai", ...thinking ? { thinking } : {} });
5742
+ }
5743
+ return out;
5744
+ }
5745
+ function parseOpencodeModels(stdout) {
5746
+ const out = [];
5747
+ for (const raw of stdout.split("\n")) {
5748
+ const line = raw.trim();
5749
+ if (!line) continue;
5750
+ if (line.startsWith("{") || line.startsWith('"') || line.startsWith("}")) continue;
5751
+ if (line === line.toUpperCase() && /[A-Z]/.test(line)) continue;
5752
+ const id = line.split(/\s+/)[0];
5753
+ const slash = id.indexOf("/");
5754
+ if (slash <= 0 || slash >= id.length - 1) continue;
5755
+ out.push({ id, label: id, provider: id.slice(0, slash) });
5756
+ }
5757
+ return out;
5758
+ }
5759
+ function parseCursorModels(stdout) {
5760
+ const out = [];
5761
+ for (const raw of stdout.split("\n")) {
5762
+ const line = raw.trim();
5763
+ if (!line) continue;
5764
+ const sep = line.indexOf(" - ");
5765
+ if (sep < 0) continue;
5766
+ const id = line.slice(0, sep).trim();
5767
+ if (!isModelId(id)) continue;
5768
+ let label = line.slice(sep + 3).trim();
5769
+ const isDefault = /default/i.test(label);
5770
+ const paren = label.indexOf("(");
5771
+ if (paren >= 0) label = label.slice(0, paren).trim();
5772
+ out.push({ id, label: label || id, provider: "cursor", ...isDefault ? { default: true } : {} });
5773
+ }
5774
+ return out;
5775
+ }
5776
+ function parsePiModels(out) {
5777
+ const res = [];
5778
+ for (const raw of out.split("\n")) {
5779
+ const line = raw.trim();
5780
+ if (!line) continue;
5781
+ if (isPiNoise(line)) continue;
5782
+ const fields = line.split(/\s+/);
5783
+ const first = fields[0];
5784
+ if (first.toLowerCase() === "provider") continue;
5785
+ let id;
5786
+ if (first.includes(":") || first.includes("/")) id = first.replace(":", "/");
5787
+ else if (fields.length >= 2) id = `${first}/${fields[1]}`;
5788
+ else continue;
5789
+ const slash = id.indexOf("/");
5790
+ if (slash <= 0 || slash >= id.length - 1) continue;
5791
+ res.push({ id, label: id, provider: id.slice(0, slash) });
5792
+ }
5793
+ return res;
5794
+ }
5795
+ function isPiNoise(line) {
5796
+ const l = line.toLowerCase();
5797
+ return l.includes("no models match pattern") || l.startsWith("warning:") || l.startsWith("error:") || l.startsWith("info:");
5798
+ }
5799
+ var LIST_TIMEOUT_MS = 7e3;
5800
+ var OUT_CAP = 256 * 1024;
5801
+ function runList(bin, args2, timeoutMs = LIST_TIMEOUT_MS) {
5802
+ return new Promise((resolve) => {
5803
+ const env = { ...process.env };
5804
+ delete env.NODE_OPTIONS;
5805
+ let proc;
5806
+ try {
5807
+ proc = spawn8(bin, args2, { stdio: ["ignore", "pipe", "pipe"], env });
5808
+ } catch (e) {
5809
+ return resolve({ stdout: "", stderr: String(e?.message ?? e), code: 1 });
5810
+ }
5811
+ let stdout = "";
5812
+ let stderr = "";
5813
+ proc.stdout?.on("data", (c) => {
5814
+ if (stdout.length < OUT_CAP) stdout += c.toString();
5815
+ });
5816
+ proc.stderr?.on("data", (c) => {
5817
+ if (stderr.length < OUT_CAP) stderr += c.toString();
5818
+ });
5819
+ const timer = setTimeout(() => {
5820
+ try {
5821
+ proc.kill("SIGKILL");
5822
+ } catch {
5823
+ }
5824
+ }, timeoutMs);
5825
+ proc.on("error", (e) => {
5826
+ clearTimeout(timer);
5827
+ resolve({ stdout, stderr: stderr || String(e?.message ?? e), code: 1 });
5828
+ });
5829
+ proc.on("exit", (code) => {
5830
+ clearTimeout(timer);
5831
+ resolve({ stdout, stderr, code });
5832
+ });
5833
+ });
5834
+ }
5835
+ async function listModels(runtime) {
5836
+ switch (runtime) {
5837
+ case "opencode": {
5838
+ let r = await runList("opencode", ["models", "--verbose"], 5e3);
5839
+ let models = parseOpencodeModels(r.stdout);
5840
+ if (!models.length) {
5841
+ r = await runList("opencode", ["models"], 2e3);
5842
+ models = parseOpencodeModels(r.stdout);
5843
+ }
5844
+ return models.length ? models : null;
5845
+ }
5846
+ case "cursor": {
5847
+ const r = await runList("cursor-agent", ["--list-models"]);
5848
+ const models = parseCursorModels(r.stdout);
5849
+ return models.length ? models : null;
5850
+ }
5851
+ case "pi": {
5852
+ const r = await runList("pi", ["--list-models"]);
5853
+ const models = parsePiModels(r.stdout || r.stderr);
5854
+ return models.length ? models : null;
5855
+ }
5856
+ case "claude": {
5857
+ const r = await runList("claude", ["--help"]);
5858
+ const superset = parseClaudeEffortLevels(r.stdout || r.stderr);
5859
+ if (!superset.length) return null;
5860
+ return CLAUDE_MODELS.map((m) => {
5861
+ const thinking = claudeThinkingForModel(m.id, superset);
5862
+ return { ...m, provider: "anthropic", ...thinking ? { thinking } : {} };
5863
+ });
5864
+ }
5865
+ case "codex": {
5866
+ const r = await runList("codex", ["debug", "models"]);
5867
+ const models = parseCodexModels(r.stdout);
5868
+ return models.length ? models : null;
5869
+ }
5870
+ default:
5871
+ return null;
5872
+ }
5873
+ }
5874
+
5672
5875
  // src/daemon/index.ts
5673
5876
  var log = createLogger("daemon");
5674
5877
  var args = process.argv.slice(2);
@@ -5732,7 +5935,10 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
5732
5935
  void readWorkspaceFile(msg.agentId, msg.path ?? "").then((r) => conn.send({ type: "workspace:file_content", requestId: msg.requestId, agentId: msg.agentId, ...r }));
5733
5936
  break;
5734
5937
  case "agent:skills:list":
5735
- void listSkills(msg.agentId).then((r) => conn.send({ type: "skills:list", requestId: msg.requestId, agentId: msg.agentId, ...r }));
5938
+ void listSkills(msg.agentId, msg.runtime).then((r) => conn.send({ type: "skills:list", requestId: msg.requestId, agentId: msg.agentId, ...r }));
5939
+ break;
5940
+ case "probe-models":
5941
+ 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) }));
5736
5942
  break;
5737
5943
  case "ping":
5738
5944
  conn.send({ type: "pong" });
@@ -5748,7 +5954,7 @@ conn = new Connection(serverUrl, apiKey, (msg) => {
5748
5954
  runningAgents: mgr.running(),
5749
5955
  hostname: os4.hostname(),
5750
5956
  os: `${os4.platform()} ${os4.arch()}`,
5751
- daemonVersion: "0.1.0",
5957
+ daemonVersion: "0.4.0",
5752
5958
  machineId: readMachineId()
5753
5959
  // Stable identity: empty on first connection; server sends it back via ready:ack for persistence.
5754
5960
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fancyboi999/open-tag-daemon",
3
- "version": "0.2.0",
3
+ "version": "0.4.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",