symbiot 0.24.0 → 0.26.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/index.mjs +33 -17
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -646,8 +646,8 @@ function detectHandoffs() {
|
|
|
646
646
|
if (orca) {
|
|
647
647
|
const q = JSON.stringify(orca);
|
|
648
648
|
agents.unshift(
|
|
649
|
-
{ label: "Orca IDE — open repo (use your Orca agent)", tmpl:
|
|
650
|
-
{ label: "Orca IDE — run Claude in a tab", tmpl:
|
|
649
|
+
{ label: "Orca IDE — open repo (use your Orca agent)", tmpl: orcaHandoffCmd(q, ""), kind: "agent" },
|
|
650
|
+
{ label: "Orca IDE — run Claude in a tab", tmpl: orcaHandoffCmd(q, ` --command "claude {prompt}"`), kind: "agent" },
|
|
651
651
|
);
|
|
652
652
|
}
|
|
653
653
|
return { agents, editors };
|
|
@@ -656,18 +656,31 @@ const shSingle = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
|
|
656
656
|
const escDq = (s) => String(s).replace(/[\\"$`]/g, "\\$&");
|
|
657
657
|
const HANDOFF_PROMPT = "Read .symbiot/TASKS.md and implement the unchecked items in this repo. Confirm before anything destructive.";
|
|
658
658
|
function handoffCmd() { const cfg = loadConfig(); return migrateOrcaCmd(cfg.agentCmd) || (cfg.ide ? `${cfg.ide} {dir}` : ""); } // ide = legacy
|
|
659
|
-
//
|
|
660
|
-
// `
|
|
661
|
-
//
|
|
659
|
+
// Build the full Orca handoff, cold-start safe. `bin` is the quoted orca-ide
|
|
660
|
+
// path; `commandPart` is e.g. ` --command "claude {prompt}"` or "" (open only).
|
|
661
|
+
// open launches Orca & waits for the runtime to be REACHABLE, but on a cold
|
|
662
|
+
// start the workspace graph isn't ready yet (runtime.state=graph_not_ready) and
|
|
663
|
+
// `terminal create` times out — so we poll `status` until state=ready, then add
|
|
664
|
+
// the repo and create the terminal (retry: the worktree can lag a beat behind).
|
|
665
|
+
function orcaHandoffCmd(bin, commandPart) {
|
|
666
|
+
const waitReady = `for i in $(seq 1 40); do ${bin} status --json 2>/dev/null | grep -q '"state": *"ready"' && break; sleep 1; done`;
|
|
667
|
+
const mkTerm = `for j in 1 2 3; do ${bin} terminal create --worktree path:{dir}${commandPart} --focus && break; sleep 2; done`;
|
|
668
|
+
return `${bin} open; ${waitReady}; ${bin} repo add --path {dir}; ${mkTerm}`;
|
|
669
|
+
}
|
|
670
|
+
// Normalise an Orca command saved by an older version (no launch / no wait-for-
|
|
671
|
+
// ready) to the current cold-start-safe form, preserving its binary path and any
|
|
672
|
+
// custom `--command`. Idempotent: already-current commands are left untouched.
|
|
662
673
|
function migrateOrcaCmd(cmd) {
|
|
663
674
|
if (!cmd || typeof cmd !== "string") return cmd;
|
|
664
675
|
if (!/orca-ide/.test(cmd) || !/\brepo add\b/.test(cmd)) return cmd;
|
|
665
|
-
if (/
|
|
666
|
-
const
|
|
667
|
-
const bin =
|
|
668
|
-
const
|
|
669
|
-
|
|
670
|
-
|
|
676
|
+
if (/status --json/.test(cmd) && /grep -q/.test(cmd)) return cmd; // already the wait-for-ready form
|
|
677
|
+
const bm = cmd.match(/^\s*("[^"]*"|'[^']*'|\S+)/); // leading orca-ide binary token
|
|
678
|
+
const bin = bm ? bm[1] : "";
|
|
679
|
+
const cm = cmd.match(/--command\s+"([^"]*)"/); // preserve a custom agent command
|
|
680
|
+
const commandPart = cm ? ` --command "${cm[1]}"` : "";
|
|
681
|
+
const rebuilt = bin ? orcaHandoffCmd(bin, commandPart) : cmd;
|
|
682
|
+
if (rebuilt !== cmd) { try { const cfg = loadConfig(); if (cfg.agentCmd === cmd) { cfg.agentCmd = rebuilt; saveConfig(cfg); } } catch {} }
|
|
683
|
+
return rebuilt;
|
|
671
684
|
}
|
|
672
685
|
// Run a shell command as a tracked, logged background job that shows up live in
|
|
673
686
|
// the Agents tab. Shared by the agent handoff and the local-model setup.
|
|
@@ -1291,6 +1304,7 @@ a{color:var(--green);cursor:pointer}.hidden{display:none}
|
|
|
1291
1304
|
.updatebar.show{display:flex}
|
|
1292
1305
|
.updatebar.reconnect{background:var(--amber)}
|
|
1293
1306
|
.updatebar button{font:inherit;font-weight:700;border:0;border-radius:8px;padding:5px 12px;background:var(--ink);color:var(--bone);cursor:pointer}
|
|
1307
|
+
.ver{font-size:11px;color:var(--faint);background:var(--ink3);border:1px solid var(--line);border-radius:999px;padding:2px 8px;margin-left:2px;font-family:ui-monospace,Menlo,Consolas,monospace}
|
|
1294
1308
|
footer{padding:10px 18px;border-top:1px solid var(--line);display:flex}
|
|
1295
1309
|
.profile{font-size:13px;margin-bottom:8px;line-height:1.5}
|
|
1296
1310
|
.profile b{color:var(--bone)}
|
|
@@ -1356,7 +1370,7 @@ footer{padding:10px 18px;border-top:1px solid var(--line);display:flex}
|
|
|
1356
1370
|
@media(max-width:760px){.maprow{flex-direction:column}.detail{width:auto;max-height:none}}
|
|
1357
1371
|
</style></head><body>
|
|
1358
1372
|
<div id="updatebar" class="updatebar"></div>
|
|
1359
|
-
<header><span class="dot"></span><span class="brand">Symbiot</span><span class="status" id="status">...</span></header>
|
|
1373
|
+
<header><span class="dot"></span><span class="brand">Symbiot</span><span class="ver" id="ver"></span><span class="status" id="status">...</span></header>
|
|
1360
1374
|
<div class="tabs">
|
|
1361
1375
|
<button class="tab active" data-tab="map">Map</button>
|
|
1362
1376
|
<button class="tab" data-tab="drift">Drift</button>
|
|
@@ -1657,9 +1671,10 @@ document.getElementById('agentcmd').addEventListener('change',saveAgent);
|
|
|
1657
1671
|
document.getElementById('newtask').addEventListener('keydown',function(e){if(e.key==='Enter')addTaskUI();});
|
|
1658
1672
|
var SRV_STARTED=null,srvDown=false,updBusy=false;
|
|
1659
1673
|
function ubar(){return document.getElementById('updatebar');}
|
|
1660
|
-
function heartbeat(){
|
|
1661
|
-
api('/api/ping').then(function(p){
|
|
1674
|
+
function heartbeat(fresh){
|
|
1675
|
+
api('/api/ping'+(fresh?'?fresh=1':'')).then(function(p){
|
|
1662
1676
|
var b=ubar();
|
|
1677
|
+
var ve=document.getElementById('ver');if(ve&&p.version)ve.textContent='v'+p.version;
|
|
1663
1678
|
if(SRV_STARTED===null){SRV_STARTED=p.started;}
|
|
1664
1679
|
else if(p.started!==SRV_STARTED){location.reload();return;}
|
|
1665
1680
|
if(srvDown){location.reload();return;}
|
|
@@ -1672,7 +1687,8 @@ function heartbeat(){
|
|
|
1672
1687
|
}).catch(function(){srvDown=true;var b=ubar();b.className='updatebar reconnect show';b.textContent='Reconnecting to Symbiot…';});
|
|
1673
1688
|
}
|
|
1674
1689
|
function doUpdate(){updBusy=true;var b=ubar();b.className='updatebar show';b.textContent='Updating & restarting… this page will reload itself when it is back.';api('/api/update',{});}
|
|
1675
|
-
setInterval(heartbeat,4000);heartbeat();
|
|
1690
|
+
setInterval(heartbeat,4000);heartbeat(true);
|
|
1691
|
+
window.addEventListener('focus',function(){heartbeat(true);}); // re-check for updates when you come back to the window
|
|
1676
1692
|
initGraphEvents();syncP();refresh();loadMap();loadAgentCfg();loadScanRoots();
|
|
1677
1693
|
</script></body></html>`;
|
|
1678
1694
|
|
|
@@ -1762,7 +1778,7 @@ async function cmdApp() {
|
|
|
1762
1778
|
if (u.pathname === "/api/agents") return json(res, HANDOFFS.map((e) => { let tail = ""; try { tail = readFileSync(e.log, "utf8").slice(-1200); } catch {} return { id: e.id, name: e.name, path: e.path, status: e.status, elapsed: (e.endedAt || Date.now()) - e.startedAt, exitCode: e.exitCode, tail }; }));
|
|
1763
1779
|
if (u.pathname === "/api/run" && req.method === "POST") { const b = await readBody(req); const cmd = ["week", "standup", "todo"].includes(b.cmd) ? b.cmd : "week"; return json(res, await produce(cmd)); }
|
|
1764
1780
|
if (u.pathname === "/api/connect" && req.method === "POST") { return json(res, await connectProvider(await readBody(req))); }
|
|
1765
|
-
if (u.pathname === "/api/ping") return json(res, { version: VERSION, started: SERVER_STARTED, latest: LATEST_VERSION });
|
|
1781
|
+
if (u.pathname === "/api/ping") { if (u.searchParams.get("fresh") === "1") await checkLatest(); return json(res, { version: VERSION, started: SERVER_STARTED, latest: LATEST_VERSION }); }
|
|
1766
1782
|
if (u.pathname === "/api/update" && req.method === "POST") {
|
|
1767
1783
|
// Install the newest symbiot, then relaunch this same app (same port +
|
|
1768
1784
|
// token => same URL) and exit. The open page's heartbeat reconnects and
|
|
@@ -1795,7 +1811,7 @@ async function cmdApp() {
|
|
|
1795
1811
|
else { try { server.listen(0, "127.0.0.1"); } catch {} }
|
|
1796
1812
|
});
|
|
1797
1813
|
server.listen(PORT, "127.0.0.1");
|
|
1798
|
-
checkLatest(); setInterval(checkLatest,
|
|
1814
|
+
checkLatest(); setInterval(checkLatest, 2 * 60 * 1000).unref(); // background update check (every 2 min)
|
|
1799
1815
|
}
|
|
1800
1816
|
|
|
1801
1817
|
const HELP = `${c.b("symbiot")} — your week, written from your real work.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "symbiot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.0",
|
|
4
4
|
"description": "Your week, written from your real work. Reads your local git and writes it up with the AI of your choice — Claude, OpenAI, Gemini, or a local model.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|