symbiot 0.44.0 → 0.45.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/CHANGELOG.md +450 -0
- package/README.md +63 -2
- package/adapt.mjs +222 -0
- package/agents.mjs +74 -8
- package/core.mjs +18 -1
- package/headless.mjs +8 -0
- package/home.mjs +74 -0
- package/lanes.mjs +5 -3
- package/mind.mjs +54 -14
- package/package.json +5 -2
- package/server.mjs +78 -7
- package/tasks.mjs +104 -13
- package/ui.mjs +243 -11
- package/watch.mjs +52 -21
- package/writeups.mjs +38 -11
package/writeups.mjs
CHANGED
|
@@ -8,9 +8,8 @@ import { resolveProvider, write } from "./ai.mjs";
|
|
|
8
8
|
import { detectMailSources, mailActivity } from "./mail.mjs";
|
|
9
9
|
import { waitingOn, newsSince } from "./watch.mjs";
|
|
10
10
|
import { me, authorship, authorArgs, readmeInfo, repoShape, houseRules, reportFooter, expandRoot, commits, openWork, detectFolder, repoPathMap, discoveredRepos } from "./scan.mjs";
|
|
11
|
-
import { taskType, workingChanges, workingDiff,
|
|
12
|
-
import {
|
|
13
|
-
import { converse, actNow, addToTasks } from "./mind.mjs";
|
|
11
|
+
import { taskType, workingChanges, workingDiff, changelogEntry } from "./tasks.mjs";
|
|
12
|
+
import { converse, actNow, actIn, taskIn } from "./mind.mjs";
|
|
14
13
|
|
|
15
14
|
// ---- render ---------------------------------------------------------------
|
|
16
15
|
function renderCommits(list) {
|
|
@@ -152,14 +151,12 @@ async function taskChat(id, question) {
|
|
|
152
151
|
(ctx.length ? "\n\n" + ctx.join("\n\n") : path ? "" : "\n\n(no repo attached: answer from the task text alone)");
|
|
153
152
|
// "do it" here works on the task's repo the way Send to repos does: the request
|
|
154
153
|
// joins the repo's tasks and the agent starts there; with no repo, in a run of its own
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
const e = runHandoff(path); if (!e) return { error: "Your agent didn't start. Check its command in Settings → Handoff." };
|
|
160
|
-
return e.busy ? { ok: true, note: "Your agent is already working in that repo: it takes this up when it's done." } : { ok: true, job: e.id };
|
|
154
|
+
const lanes = repoPathMap(), mine = path ? it.repo : "";
|
|
155
|
+
const agent = async (req, known, repo) => {
|
|
156
|
+
const lane = repo || mine;
|
|
157
|
+
return lane ? actIn(req, lane, { map: lanes, known, title: it.text.slice(0, 60), context: `Their task: ${it.text}` }) : actNow(req, { title: it.text.slice(0, 60), context: `Their task: ${it.text}`, known });
|
|
161
158
|
};
|
|
162
|
-
const r = await converse({ where: `Task: ${it.text.slice(0, 60)}`, role, context, history, question, act: { agent, task: (text, repo) =>
|
|
159
|
+
const r = await converse({ where: `Task: ${it.text.slice(0, 60)}`, role, context, history, question, map: lanes, act: { agent, task: (text, repo) => taskIn(text, repo || mine, { map: lanes }) } });
|
|
163
160
|
const answer = r.reply;
|
|
164
161
|
// Re-read: other requests may have changed tasks.json while the model ran.
|
|
165
162
|
const t = loadTasks(); const cur = t.find((x) => x.id === id); const now = Date.now();
|
|
@@ -273,4 +270,34 @@ async function produce(cmd, { since = 7, all: everyone = false } = {}) {
|
|
|
273
270
|
return { text: text ? withWaiting(text, line) : "(couldn't reach the model)", sub: `${cs.length} commits across ${new Set(cs.map((x) => x.repo)).size} repos${mailNote}${waitNote} · ${label}`, footer: `symbiot ${VERSION} · ${all.length} repos (same as the Map) · ${repos.length} active · ${cs.length} commits in last ${days}d${mailNote}` };
|
|
274
271
|
}
|
|
275
272
|
|
|
276
|
-
|
|
273
|
+
// ---- release notes: Approve's changelog entries, in your AI's words ------------
|
|
274
|
+
// Each approved task as a short note ("Added…", "Fixed…") from the task and the
|
|
275
|
+
// diff (input from tasks.mjs releaseInput); changes with no task, from the diff
|
|
276
|
+
// alone. null keeps the tasks' own words: no AI connected, no answer in time, or
|
|
277
|
+
// an answer that isn't one note per task.
|
|
278
|
+
const NOTES_WAIT_MS = 60000;
|
|
279
|
+
async function releaseNotes(input, ask = write) {
|
|
280
|
+
if (!input || (ask === write && !resolveProvider())) return null;
|
|
281
|
+
const { texts, files, diff } = input, n = texts.length;
|
|
282
|
+
const system =
|
|
283
|
+
`You write release notes for a changelog that everyone who updates the app reads, not only the developer. ` +
|
|
284
|
+
`Each note is one plain sentence under 25 words, starting with a past-tense verb (Added, Fixed, Changed, Removed…), saying what changed for the people who use it. ` +
|
|
285
|
+
`Use the task for what was wanted and the diff for what was actually done; claim nothing the diff doesn't show. ` +
|
|
286
|
+
`No file or function names unless a user types them (a command, a setting), no jargon, no names of people. ` +
|
|
287
|
+
`Answer with the notes only, one per line, each starting with "- ".`;
|
|
288
|
+
const prompt = (n ? `Tasks approved in this release:\n${texts.map((t, i) => `${i + 1}. ${t}`).join("\n")}\n\n` : "") +
|
|
289
|
+
`Files changed: ${files.join(", ") || "(none)"}\n\nDiff:\n${diff || "(none)"}\n\n` +
|
|
290
|
+
(n ? `Write exactly ${n} note${n === 1 ? "" : "s"}, one per task, in the same order.` : `No task covers these changes. Write 1 to 3 notes saying what they do.`);
|
|
291
|
+
let out = null;
|
|
292
|
+
try { out = await Promise.race([ask(system, prompt), new Promise((r) => setTimeout(r, NOTES_WAIT_MS, null).unref())]); } catch { return null; }
|
|
293
|
+
return parseNotes(out, n);
|
|
294
|
+
}
|
|
295
|
+
// The "- " lines of the AI's answer, as changelog entries: exactly n of them, or
|
|
296
|
+
// 1 to 3 when no task was approved; null otherwise.
|
|
297
|
+
function parseNotes(out, n) {
|
|
298
|
+
const notes = String(out || "").split("\n").map((l) => l.match(/^\s*(?:[-*•]|\d+[.)])\s+(.+)/)).filter(Boolean)
|
|
299
|
+
.map((m) => changelogEntry(m[1].replace(/^\*\*(.+)\*\*$/, "$1").replace(/^["“](.+)["”]$/, "$1"))).filter(Boolean);
|
|
300
|
+
return (n ? notes.length === n : notes.length >= 1 && notes.length <= 3) ? notes : null;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export { repoReview, repoSuggest, folderSuggest, taskChat, clearTaskChat, mailState, setMail, sentMail, arrivedOn, produce, releaseNotes, parseNotes };
|