symbiot 0.11.0 → 0.13.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 +85 -14
- package/package.json +1 -1
package/index.mjs
CHANGED
|
@@ -103,6 +103,20 @@ function addTask(text, repo) {
|
|
|
103
103
|
}
|
|
104
104
|
function toggleTask(id) { const t = loadTasks(); const it = t.find((x) => x.id === id); if (it) { it.done = !it.done; saveTasks(t); } return it || { error: "not found" }; }
|
|
105
105
|
function removeTask(id) { saveTasks(loadTasks().filter((x) => x.id !== id)); return { ok: true }; }
|
|
106
|
+
// Deterministic task classification (no model) so tasks batch by kind instead
|
|
107
|
+
// of arriving as a flat, mixed pile. Order matters (most specific first).
|
|
108
|
+
const TASK_ORDER = ["Fixes", "Tests & CI", "Security", "Performance", "Refactor", "UI/UX", "Docs", "Features & other"];
|
|
109
|
+
function taskType(text) {
|
|
110
|
+
const s = String(text || "").toLowerCase();
|
|
111
|
+
if (/\b(test|tests|spec|coverage|smoke|fixture|ci\b)/.test(s)) return "Tests & CI";
|
|
112
|
+
if (/\b(secur|auth|token|secret|vulnerab|permission|sanitiz|escap|injection)/.test(s)) return "Security";
|
|
113
|
+
if (/\b(readme|docs?|document|changelog|comment|guide)/.test(s)) return "Docs";
|
|
114
|
+
if (/\b(perf|performance|slow|optimi|latency|throughput|speed up|memory leak)/.test(s)) return "Performance";
|
|
115
|
+
if (/\b(refactor|simplify|split|extract|clean ?up|consolidat|dedupe|modular|rename)/.test(s)) return "Refactor";
|
|
116
|
+
if (/\b(bug|fix|broken|error|crash|regress|hang|race|leak)/.test(s)) return "Fixes";
|
|
117
|
+
if (/\b(ui|ux|design|layout|style|button|screen|view\b|page\b|responsive)/.test(s)) return "UI/UX";
|
|
118
|
+
return "Features & other";
|
|
119
|
+
}
|
|
106
120
|
// Push tasks into the repos as an agent-readable brief (.symbiot/TASKS.md):
|
|
107
121
|
// a checklist plus the deterministic context an agent needs to get oriented.
|
|
108
122
|
function buildTasksMd(name, ctx, list) {
|
|
@@ -115,8 +129,10 @@ function buildTasksMd(name, ctx, list) {
|
|
|
115
129
|
if (ctx.open && ctx.open.length) { L.push("- **Open markers (TODO/FIXME + uncommitted):**"); for (const o of ctx.open) L.push(` - ${o}`); }
|
|
116
130
|
if (ctx.drift && ctx.drift.length) { L.push("- **Current drift / risk:**"); for (const d of ctx.drift) L.push(` - ${d}`); }
|
|
117
131
|
L.push("", "## Tasks");
|
|
118
|
-
for (const t of list)
|
|
119
|
-
|
|
132
|
+
const byType = {}; for (const t of list) { const ty = taskType(t.text); (byType[ty] = byType[ty] || []).push(t); }
|
|
133
|
+
const keys = Object.keys(byType).sort((a, b) => TASK_ORDER.indexOf(a) - TASK_ORDER.indexOf(b));
|
|
134
|
+
for (const ty of keys) { L.push(`### ${ty}`); for (const t of byType[ty]) L.push(`- [ ] ${t.text}`); L.push(""); }
|
|
135
|
+
L.push("---", 'To action these, tell your coding agent: "Read `.symbiot/TASKS.md` and implement the unchecked items in this repo, using the context above. Confirm with me before anything destructive."');
|
|
120
136
|
return L.join("\n") + "\n";
|
|
121
137
|
}
|
|
122
138
|
function pushTasks() {
|
|
@@ -147,17 +163,22 @@ function pushTasks() {
|
|
|
147
163
|
const dir = join(path, ".symbiot"); mkdirSync(dir, { recursive: true });
|
|
148
164
|
const file = join(dir, "TASKS.md");
|
|
149
165
|
writeFileSync(file, buildTasksMd(name, { branch: st.branch, commits, open, drift: risk, stack }, list));
|
|
150
|
-
written.push({ name, file, count: list.length });
|
|
166
|
+
written.push({ name, file, path, count: list.length });
|
|
151
167
|
} catch (e) { unresolved.push({ name, count: list.length, error: String((e && e.message) || e) }); }
|
|
152
168
|
}
|
|
153
|
-
return { empty: false, written, unresolved };
|
|
169
|
+
return { empty: false, written, unresolved, handoff: handoffCmd() };
|
|
154
170
|
}
|
|
155
171
|
function cmdPush() {
|
|
156
172
|
const r = pushTasks();
|
|
157
173
|
if (r.empty) { console.log(c.y("No open tasks to push.") + c.d(" Add some in `symbiot app` — a repo review's ideas, or the Tasks tab.")); return; }
|
|
158
174
|
if (r.written.length) { console.log("\n" + c.g("●") + " " + c.b("Pushed tasks into repos:")); for (const w of r.written) console.log(` ${c.g("✓")} ${w.name} ${c.d(w.file + " (" + w.count + " task" + (w.count > 1 ? "s" : "") + ")")}`); }
|
|
159
175
|
if (r.unresolved.length) { console.log("\n" + c.y(`Not written (repo not found under ${BASE}):`)); for (const u of r.unresolved) console.log(` · ${u.name} (${u.count})`); }
|
|
160
|
-
|
|
176
|
+
if (has("open")) {
|
|
177
|
+
if (!r.handoff) console.log("\n" + c.y("No agent command set.") + c.d(" Set one in `symbiot app` Settings, or `agentCmd` in ~/.config/symbiot/config.json (use {dir} and {prompt})."));
|
|
178
|
+
else { for (const w of r.written) runHandoff(w.path); console.log("\n" + c.g("→ ") + `Handed ${r.written.length} repo(s) to your agent (${r.handoff}).`); }
|
|
179
|
+
} else {
|
|
180
|
+
console.log("\n" + c.d("Point your agent at .symbiot/TASKS.md in each repo. (add --open to run your configured agent command)"));
|
|
181
|
+
}
|
|
161
182
|
}
|
|
162
183
|
function envKey(provider) {
|
|
163
184
|
for (const e of (PROVIDERS[provider].env || [])) if (process.env[e]) return process.env[e];
|
|
@@ -515,6 +536,31 @@ function recommendModels(hw) {
|
|
|
515
536
|
const best = (local.slice().reverse().find((m) => m.fits) || local[0]).model;
|
|
516
537
|
return { local, paid, best };
|
|
517
538
|
}
|
|
539
|
+
// ---- hand a repo (+ its tasks) to the user's agent — generic, settings-based
|
|
540
|
+
// The handoff is a command TEMPLATE the user configures, with {dir} (repo path)
|
|
541
|
+
// and {prompt} (the task instruction). Works for any agent/editor:
|
|
542
|
+
// claude -p "{prompt}" · aider --message "{prompt}" · code {dir}
|
|
543
|
+
// gnome-terminal --working-directory={dir} -- claude "{prompt}"
|
|
544
|
+
// Not tied to any one tool — you decide what runs.
|
|
545
|
+
const IDE_LIST = [["code", "VS Code"], ["cursor", "Cursor"], ["windsurf", "Windsurf"], ["zed", "Zed"], ["subl", "Sublime Text"], ["idea", "IntelliJ IDEA"], ["nvim", "Neovim"]];
|
|
546
|
+
const AGENT_LIST = [["claude", "Claude Code", 'claude -p "{prompt}"'], ["aider", "Aider", 'aider --message "{prompt}"'], ["cursor-agent", "Cursor agent", 'cursor-agent -p "{prompt}"']];
|
|
547
|
+
function detectHandoffs() {
|
|
548
|
+
const editors = IDE_LIST.filter(([cmd]) => sh(`command -v ${cmd} 2>/dev/null`).trim()).map(([cmd, label]) => ({ label, tmpl: `${cmd} {dir}`, kind: "editor" }));
|
|
549
|
+
const agents = AGENT_LIST.filter(([cmd]) => sh(`command -v ${cmd} 2>/dev/null`).trim()).map(([cmd, label, tmpl]) => ({ label, tmpl, kind: "agent" }));
|
|
550
|
+
return { agents, editors };
|
|
551
|
+
}
|
|
552
|
+
const shSingle = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
|
|
553
|
+
const escDq = (s) => String(s).replace(/[\\"$`]/g, "\\$&");
|
|
554
|
+
const HANDOFF_PROMPT = "Read .symbiot/TASKS.md and implement the unchecked items in this repo. Confirm before anything destructive.";
|
|
555
|
+
function handoffCmd() { const cfg = loadConfig(); return cfg.agentCmd || (cfg.ide ? `${cfg.ide} {dir}` : ""); } // ide = legacy
|
|
556
|
+
function runHandoff(repoPath) {
|
|
557
|
+
try {
|
|
558
|
+
const tmpl = handoffCmd(); if (!tmpl || !repoPath) return false;
|
|
559
|
+
const cmd = tmpl.replace(/\{dir\}/g, shSingle(repoPath)).replace(/\{prompt\}/g, escDq(HANDOFF_PROMPT));
|
|
560
|
+
spawn(cmd, { shell: true, cwd: repoPath, detached: true, stdio: "ignore" }).unref();
|
|
561
|
+
return true;
|
|
562
|
+
} catch { return false; }
|
|
563
|
+
}
|
|
518
564
|
function cmdModels() {
|
|
519
565
|
const hw = detectHardware(); const rec = recommendModels(hw);
|
|
520
566
|
const pad = (s, n) => String(s).padEnd(n);
|
|
@@ -1042,6 +1088,8 @@ footer{padding:10px 18px;border-top:1px solid var(--line);display:flex}
|
|
|
1042
1088
|
.task .rp{font-size:11px;color:var(--faint);background:var(--ink3);border:1px solid var(--line);border-radius:999px;padding:2px 8px}
|
|
1043
1089
|
.task .rm{background:none;border:0;color:var(--faint);cursor:pointer;font-size:18px;line-height:1}
|
|
1044
1090
|
.task .rm:hover{color:var(--amber)}
|
|
1091
|
+
.tgroup{margin:14px 0 4px;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--green);font-weight:700}
|
|
1092
|
+
.tcount{color:var(--faint);font-weight:400}
|
|
1045
1093
|
.drift{border:1px solid var(--line);border-radius:10px;margin-top:10px;padding:12px 14px;background:var(--ink2)}
|
|
1046
1094
|
.drift .dh{display:flex;gap:8px;align-items:center}
|
|
1047
1095
|
.drift .dn{color:var(--bone);font-weight:600}
|
|
@@ -1122,6 +1170,12 @@ footer{padding:10px 18px;border-top:1px solid var(--line);display:flex}
|
|
|
1122
1170
|
<div class="row" style="margin-top:16px"><button class="act" id="save">Save & connect</button>
|
|
1123
1171
|
<span class="note" id="saveMsg"></span></div>
|
|
1124
1172
|
<div style="margin-top:20px;border-top:1px solid var(--line);padding-top:16px">
|
|
1173
|
+
<label>Hand off to your agent when you "Send to repos"</label>
|
|
1174
|
+
<input id="agentcmd" type="text" placeholder="e.g. claude -p "{prompt}" · code {dir} · leave blank to just write the file">
|
|
1175
|
+
<div class="note muted">Runs in each repo after tasks are written. Use <b>{dir}</b> = repo path, <b>{prompt}</b> = the task instruction. Works with any agent or editor — it's your command.</div>
|
|
1176
|
+
<div id="agentpresets" style="margin-top:8px"></div>
|
|
1177
|
+
</div>
|
|
1178
|
+
<div style="margin-top:20px;border-top:1px solid var(--line);padding-top:16px">
|
|
1125
1179
|
<button class="ghost" id="recbtn">Recommend models for my machine</button>
|
|
1126
1180
|
<div id="recout" style="margin-top:12px"></div>
|
|
1127
1181
|
</div>
|
|
@@ -1210,12 +1264,16 @@ el.innerHTML="<h4>AI review · <span class='rname'>"+esc(name)+"</span></h
|
|
|
1210
1264
|
Promise.all([api('/api/review',{path:path}),api('/api/tasks')]).then(function(res){var r=res[0]||{},tasks=res[1]||[];
|
|
1211
1265
|
if(r.error==='not-connected'){el.innerHTML="<h4>AI review · <span class='rname'>"+esc(name)+"</span></h4><div class='body'>Connect a model in Settings to get a review - Ollama is free and runs locally.</div>"+(r.footer?"<div class='rfoot'>"+esc(r.footer)+"</div>":"");return;}
|
|
1212
1266
|
var body=r.text||'(no output)';reviewCache[path]={text:body,verdict:r.verdict||"",ideas:r.ideas||[],footer:r.footer};el.innerHTML=reviewHtml(name,body,r.verdict||"",r.ideas||[],tasks,r.footer);wireIdeas();});}
|
|
1213
|
-
function
|
|
1214
|
-
|
|
1215
|
-
el.innerHTML=h;
|
|
1216
|
-
el.querySelectorAll('.task').forEach(function(row){var id=row.getAttribute('data-id');
|
|
1267
|
+
function taskRow(t){return "<div class='task"+(t.done?" done":"")+"' data-id='"+esc(t.id)+"'><input type='checkbox' class='taskchk'"+(t.done?" checked":"")+"><span class='t'>"+esc(t.text)+"</span>"+(t.repo?"<span class='rp'>"+esc(t.repo)+"</span>":"")+"<button class='rm' title='remove'>×</button></div>";}
|
|
1268
|
+
function wireTaskRows(el){el.querySelectorAll('.task').forEach(function(row){var id=row.getAttribute('data-id');
|
|
1217
1269
|
row.querySelector('.taskchk').addEventListener('change',function(){api('/api/tasks/toggle',{id:id}).then(function(){row.classList.toggle('done');});});
|
|
1218
1270
|
row.querySelector('.rm').addEventListener('click',function(){api('/api/tasks/remove',{id:id}).then(function(){row.remove();if(!el.querySelector('.task'))renderTasks([]);});});});}
|
|
1271
|
+
function renderTasks(list){var el=document.getElementById('tasklist');if(!list||!list.length){el.innerHTML="<div class='muted' style='margin-top:12px'>No tasks yet. Tick an idea in a repo's review, or add one above.</div>";return;}
|
|
1272
|
+
var order=['Fixes','Tests & CI','Security','Performance','Refactor','UI/UX','Docs','Features & other'];
|
|
1273
|
+
var groups={};list.forEach(function(t){var ty=t.type||'Features & other';(groups[ty]=groups[ty]||[]).push(t);});
|
|
1274
|
+
var keys=Object.keys(groups).sort(function(a,b){var ia=order.indexOf(a),ib=order.indexOf(b);return (ia<0?99:ia)-(ib<0?99:ib);});
|
|
1275
|
+
var h="";keys.forEach(function(ty){h+="<div class='tgroup'>"+esc(ty)+" <span class='tcount'>"+groups[ty].length+"</span></div>";groups[ty].forEach(function(t){h+=taskRow(t);});});
|
|
1276
|
+
el.innerHTML=h;wireTaskRows(el);}
|
|
1219
1277
|
function loadTasks(){api('/api/tasks').then(renderTasks);}
|
|
1220
1278
|
function loadDrift(){var out=document.getElementById('driftout');out.innerHTML="<div class='muted' style='margin-top:12px'>Reading your repos…</div>";
|
|
1221
1279
|
var ci=document.getElementById('driftci').checked?'1':'0';var ft=document.getElementById('driftfetch').checked?'1':'0';
|
|
@@ -1237,8 +1295,17 @@ if(r.empty){o.innerHTML="<div class='muted' style='margin-top:10px'>No open task
|
|
|
1237
1295
|
var n=(r.written||[]).length;var h="<div class='drift' style='margin-top:10px'><div class='dh'><span class='dot-c'></span><span class='dn'>Done — wrote "+n+" file"+(n===1?"":"s")+"</span></div>";
|
|
1238
1296
|
if(n){h+="<ul>";r.written.forEach(function(w){h+="<li class='info'>✓ <b>"+esc(w.name)+"</b> <span class='ev'>"+esc(w.file)+" ("+w.count+" task"+(w.count===1?"":"s")+")</span></li>";});h+="</ul>";}
|
|
1239
1297
|
if(r.unresolved&&r.unresolved.length){h+="<div class='dd' style='margin-top:6px'>⚠ not written (repo not found under your home folder): "+esc(r.unresolved.map(function(u){return u.name;}).join(", "))+"</div>";}
|
|
1240
|
-
h+="<div class='dd' style='margin-top:8px'
|
|
1298
|
+
if(r.handoff&&r.written&&r.written.length){r.written.forEach(function(w){api('/api/open',{path:w.path});});h+="<div class='dd' style='margin-top:8px'>🤖 Handing "+n+" repo(s) to your agent (<b>"+esc(r.handoff)+"</b>)…</div>";}
|
|
1299
|
+
else{h+="<div class='dd' style='margin-top:8px'>Set an <b>agent command</b> in Settings to auto-run it on send. For now, tell your agent: <b>“Read .symbiot/TASKS.md and implement the unchecked items.”</b></div>";}
|
|
1300
|
+
h+="</div>";
|
|
1241
1301
|
o.innerHTML=h;}).catch(function(e){btn.disabled=false;o.innerHTML="<div class='err' style='margin-top:10px'>Couldn't write tasks: "+esc(String((e&&e.message)||e))+"</div>";});}
|
|
1302
|
+
function loadAgentCfg(){api('/api/agentcfg').then(function(d){document.getElementById('agentcmd').value=d.cmd||'';
|
|
1303
|
+
var chips=[];(d.agents||[]).forEach(function(a){chips.push(a);});(d.editors||[]).forEach(function(e){chips.push(e);});
|
|
1304
|
+
var box=document.getElementById('agentpresets');
|
|
1305
|
+
if(!chips.length){box.innerHTML="<span class='muted' style='font-size:12px'>Nothing detected on PATH — type your own command above.</span>";return;}
|
|
1306
|
+
box.innerHTML="<span class='muted' style='font-size:12px'>Detected — click to use:</span><br>"+chips.map(function(c,i){return "<button class='ghost preset' data-i='"+i+"' style='padding:4px 10px;font-size:12px;margin:5px 5px 0 0'>"+esc(c.label)+"</button>";}).join("");
|
|
1307
|
+
box.querySelectorAll('.preset').forEach(function(btn){btn.addEventListener('click',function(){document.getElementById('agentcmd').value=chips[+btn.getAttribute('data-i')].tmpl;saveAgent();});});});}
|
|
1308
|
+
function saveAgent(){api('/api/agentcmd',{cmd:document.getElementById('agentcmd').value});}
|
|
1242
1309
|
function selectNode(id){sel=id;render();updateBar(id);var n=nodeById(id);api('/api/node?id='+encodeURIComponent(id)).then(showDetail);
|
|
1243
1310
|
if(n&&n.type==='repo'&&n.meta&&n.meta.path){loadReview(n.label,n.meta.path);}else{hideReview();}}
|
|
1244
1311
|
function screenToGraph(el,ev){var rc=el.getBoundingClientRect();var mx=(ev.clientX-rc.left)/rc.width*GW;var my=(ev.clientY-rc.top)/rc.height*GH;return {x:(mx-view.x)/view.k,y:(my-view.y)/view.k};}
|
|
@@ -1270,8 +1337,9 @@ document.getElementById('recbtn').addEventListener('click',loadRec);
|
|
|
1270
1337
|
document.getElementById('driftrun').addEventListener('click',function(){driftLoaded=false;loadDrift();});
|
|
1271
1338
|
document.getElementById('addtask').addEventListener('click',addTaskUI);
|
|
1272
1339
|
document.getElementById('pushtasks').addEventListener('click',pushTasksUI);
|
|
1340
|
+
document.getElementById('agentcmd').addEventListener('change',saveAgent);
|
|
1273
1341
|
document.getElementById('newtask').addEventListener('keydown',function(e){if(e.key==='Enter')addTaskUI();});
|
|
1274
|
-
initGraphEvents();syncP();refresh();loadMap();
|
|
1342
|
+
initGraphEvents();syncP();refresh();loadMap();loadAgentCfg();
|
|
1275
1343
|
</script></body></html>`;
|
|
1276
1344
|
|
|
1277
1345
|
function readBody(req) {
|
|
@@ -1330,11 +1398,14 @@ async function cmdApp() {
|
|
|
1330
1398
|
if (u.pathname === "/api/node") return json(res, nodeDetail(u.searchParams.get("id") || "")); // local
|
|
1331
1399
|
if (u.pathname === "/api/suggest" && req.method === "POST") { const b = await readBody(req); return json(res, await repoSuggest(String(b.path || ""))); }
|
|
1332
1400
|
if (u.pathname === "/api/review" && req.method === "POST") { const b = await readBody(req); return json(res, await repoReview(String(b.path || ""))); }
|
|
1333
|
-
if (u.pathname === "/api/tasks" && req.method !== "POST") return json(res, loadTasks());
|
|
1401
|
+
if (u.pathname === "/api/tasks" && req.method !== "POST") return json(res, loadTasks().map((t) => ({ ...t, type: taskType(t.text) })));
|
|
1334
1402
|
if (u.pathname === "/api/tasks/add" && req.method === "POST") { const b = await readBody(req); return json(res, addTask(b.text, b.repo)); }
|
|
1335
1403
|
if (u.pathname === "/api/tasks/toggle" && req.method === "POST") { const b = await readBody(req); return json(res, toggleTask(String(b.id || ""))); }
|
|
1336
1404
|
if (u.pathname === "/api/tasks/remove" && req.method === "POST") { const b = await readBody(req); return json(res, removeTask(String(b.id || ""))); }
|
|
1337
1405
|
if (u.pathname === "/api/tasks/push" && req.method === "POST") return json(res, pushTasks());
|
|
1406
|
+
if (u.pathname === "/api/agentcfg") { const d = detectHandoffs(); return json(res, { cmd: handoffCmd(), agents: d.agents, editors: d.editors }); }
|
|
1407
|
+
if (u.pathname === "/api/agentcmd" && req.method === "POST") { const b = await readBody(req); const cfg = loadConfig(); const v = String(b.cmd || "").trim(); if (v) cfg.agentCmd = v; else delete cfg.agentCmd; delete cfg.ide; saveConfig(cfg); return json(res, { ok: true, cmd: cfg.agentCmd || "" }); }
|
|
1408
|
+
if (u.pathname === "/api/open" && req.method === "POST") { const b = await readBody(req); return json(res, { opened: runHandoff(String(b.path || "")) }); }
|
|
1338
1409
|
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)); }
|
|
1339
1410
|
if (u.pathname === "/api/connect" && req.method === "POST") { return json(res, await connectProvider(await readBody(req))); }
|
|
1340
1411
|
if (u.pathname === "/api/quit") { res.writeHead(200); res.end("bye"); setTimeout(() => process.exit(0), 150); return; }
|
|
@@ -1358,7 +1429,7 @@ ${c.b("Usage")}
|
|
|
1358
1429
|
symbiot todo what's still on your plate
|
|
1359
1430
|
symbiot app open the visual app in your browser
|
|
1360
1431
|
symbiot drift what's out of sync / at risk across repos
|
|
1361
|
-
symbiot push
|
|
1432
|
+
symbiot push [--open] write tasks into each repo (and open your IDE)
|
|
1362
1433
|
symbiot models recommend AI models for your hardware
|
|
1363
1434
|
symbiot login connect it to an AI (once)
|
|
1364
1435
|
symbiot whoami show how it's connected
|
|
@@ -1406,4 +1477,4 @@ const isMain = (() => {
|
|
|
1406
1477
|
})();
|
|
1407
1478
|
if (isMain) main();
|
|
1408
1479
|
|
|
1409
|
-
export { authorship, repoState, readmeInfo, repoShape, houseRules, findAllRepos, buildMap, reportFooter, detectHardware, recommendModels, computeDrift, driftRepo, gitDefaultBranch, buildTasksMd, EMBEDDED_UI };
|
|
1480
|
+
export { authorship, repoState, readmeInfo, repoShape, houseRules, findAllRepos, buildMap, reportFooter, detectHardware, recommendModels, computeDrift, driftRepo, gitDefaultBranch, buildTasksMd, taskType, EMBEDDED_UI };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "symbiot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.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": {
|