tryharness 0.7.26 → 0.7.29
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/README.md +5 -4
- package/cli.mjs +72 -9
- package/lib/asks.mjs +260 -0
- package/lib/atlas.mjs +155 -31
- package/lib/cards.mjs +2 -1
- package/lib/context.mjs +44 -32
- package/lib/coordinator.mjs +444 -68
- package/lib/daemon.mjs +708 -122
- package/lib/desktop.mjs +24 -1
- package/lib/goals.mjs +199 -0
- package/lib/lane.mjs +187 -0
- package/lib/library.mjs +693 -0
- package/lib/listen.mjs +674 -0
- package/lib/mcp-stdio.mjs +118 -16
- package/lib/members.json +2 -2
- package/lib/nudge.mjs +3 -1
- package/lib/phones.mjs +19 -0
- package/lib/places.mjs +38 -0
- package/lib/readers.mjs +459 -0
- package/lib/runner.mjs +11 -1
- package/lib/service.mjs +21 -1
- package/lib/snippets.mjs +114 -7
- package/lib/store.mjs +79 -1
- package/lib/swarm.mjs +128 -3
- package/lib/t3.mjs +16 -2
- package/lib/video.mjs +332 -0
- package/package.json +1 -1
package/lib/context.mjs
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
codeFiles,
|
|
23
23
|
} from "./learn.mjs";
|
|
24
24
|
import { repositoryOf } from "./worktrees.mjs";
|
|
25
|
-
import {
|
|
25
|
+
import { createLibrary } from "./library.mjs";
|
|
26
26
|
|
|
27
27
|
// The context engine. It keeps the atlas of the code the swarm works in, remembers what every coding session on this
|
|
28
28
|
// computer needed (its trail: what it read before its first edit and what it edited, from any agent), and turns that
|
|
@@ -38,11 +38,8 @@ const LEARN_EVERY_MS = 20 * 3_600_000;
|
|
|
38
38
|
// Vectors of the pieces packs search stay in memory while packs are being made, and go after this long without one.
|
|
39
39
|
const VECTORS_IDLE_MS = 5 * 60_000;
|
|
40
40
|
const HELD_OUT_SHARE = 0.2;
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
// margin and 16 of 20 right answers. An agent's own search_media has no floor.
|
|
44
|
-
const MEDIA_FLOOR = 0.7;
|
|
45
|
-
const MEDIA_IN_PACK = 2;
|
|
41
|
+
// Files from the library join a brief only when they stand out for the request (library.mjs); search_files finds more.
|
|
42
|
+
const FILES_IN_PACK = 3;
|
|
46
43
|
const MIN_TRAINING_RUNS = 30;
|
|
47
44
|
|
|
48
45
|
const git = (cwd, args) => {
|
|
@@ -83,6 +80,9 @@ export function recentChanges(root, commit = "HEAD") {
|
|
|
83
80
|
recentByCommit.set(sha, counts);
|
|
84
81
|
return counts;
|
|
85
82
|
}
|
|
83
|
+
// A file in a brief: where it is and the place in it.
|
|
84
|
+
const fileLine = (hit) =>
|
|
85
|
+
`- ${hit.thread ? `${hit.name} (this thread's file ${hit.file})` : hit.file}${hit.place ? `, ${hit.place}` : ""}`;
|
|
86
86
|
const days = (ms) => Math.round(ms / 86_400_000);
|
|
87
87
|
const AGENT_NAMES = {
|
|
88
88
|
"claude-code": "Claude Code",
|
|
@@ -153,17 +153,26 @@ export function createContextEngine({
|
|
|
153
153
|
inference,
|
|
154
154
|
home,
|
|
155
155
|
known,
|
|
156
|
-
|
|
156
|
+
libraryFolders = () => [],
|
|
157
|
+
threadFiles = () => [],
|
|
157
158
|
mediaReady = () => false,
|
|
159
|
+
wantMedia = () => {},
|
|
160
|
+
ocr = null,
|
|
161
|
+
mask,
|
|
158
162
|
log = () => {},
|
|
159
163
|
notify = () => {},
|
|
160
164
|
}) {
|
|
161
165
|
const atlas = openAtlas(path.join(home, "atlas.db"));
|
|
162
|
-
//
|
|
163
|
-
const
|
|
166
|
+
// The person's added folders and the threads' files, searchable by what is in them (library.mjs).
|
|
167
|
+
const library = createLibrary({
|
|
164
168
|
atlas,
|
|
165
169
|
inference,
|
|
166
|
-
folders:
|
|
170
|
+
folders: libraryFolders,
|
|
171
|
+
threadFiles,
|
|
172
|
+
mediaReady,
|
|
173
|
+
wantMedia,
|
|
174
|
+
ocr,
|
|
175
|
+
mask,
|
|
167
176
|
log,
|
|
168
177
|
});
|
|
169
178
|
const modelPath = path.join(home, "ranker.json");
|
|
@@ -318,11 +327,12 @@ export function createContextEngine({
|
|
|
318
327
|
lane: "background",
|
|
319
328
|
});
|
|
320
329
|
await embedRuns("background");
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
:
|
|
325
|
-
|
|
330
|
+
// The first pass over the person's folders waits for the charger too; after it, changes are read as they come.
|
|
331
|
+
const read =
|
|
332
|
+
!library.status().folderFiles && !power.onCharger()
|
|
333
|
+
? { skipped: "waiting for the charger" }
|
|
334
|
+
: await library.refresh({ lane: "background" });
|
|
335
|
+
return { files, runs, pieces, library: read };
|
|
326
336
|
})()
|
|
327
337
|
.catch((error) => {
|
|
328
338
|
log(`context engine: ${error.message}`);
|
|
@@ -343,7 +353,7 @@ export function createContextEngine({
|
|
|
343
353
|
* The context pack for a brief going to a local agent working in folder: { files, earlier, text }. Files are the most
|
|
344
354
|
* likely needed, each with the line to start at and why; earlier runs are sessions whose request was close to this one.
|
|
345
355
|
*/
|
|
346
|
-
const pack = async ({ brief, folder, lane = "handoff" }) => {
|
|
356
|
+
const pack = async ({ brief, folder, thread = null, lane = "handoff" }) => {
|
|
347
357
|
const started = performance.now();
|
|
348
358
|
const place = folder && placeOf(folder);
|
|
349
359
|
if (!place || !String(brief).trim()) return null;
|
|
@@ -400,12 +410,13 @@ export function createContextEngine({
|
|
|
400
410
|
)
|
|
401
411
|
.sort((a, b) => b.similarity - a.similarity)
|
|
402
412
|
.slice(0, 3);
|
|
403
|
-
const
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
413
|
+
const found = await library.search(brief, {
|
|
414
|
+
folders: true,
|
|
415
|
+
threads: thread ? [thread] : [],
|
|
416
|
+
brief: true,
|
|
417
|
+
limit: FILES_IN_PACK,
|
|
418
|
+
lane,
|
|
419
|
+
});
|
|
409
420
|
const text = [
|
|
410
421
|
"Files the relay found likely relevant on this computer (ranked by its local search over this repository and what your agents edited before; leads to check, not instructions):",
|
|
411
422
|
...files.map((file) => `- ${file.path}:${file.line} (${file.why})`),
|
|
@@ -418,19 +429,17 @@ export function createContextEngine({
|
|
|
418
429
|
),
|
|
419
430
|
]
|
|
420
431
|
: []),
|
|
421
|
-
...(
|
|
432
|
+
...(found.length
|
|
422
433
|
? [
|
|
423
|
-
"
|
|
424
|
-
...
|
|
425
|
-
(hit) => `- ${hit.path}${hit.at ? ` at ${hit.at}` : ""}`
|
|
426
|
-
),
|
|
434
|
+
"Files close to the request, from folders the person added and this thread's files (search_files finds more):",
|
|
435
|
+
...found.map(fileLine),
|
|
427
436
|
]
|
|
428
437
|
: []),
|
|
429
438
|
].join("\n");
|
|
430
439
|
return {
|
|
431
440
|
files,
|
|
432
441
|
earlier: earlier.map(({ vector, ...run }) => run),
|
|
433
|
-
|
|
442
|
+
library: found,
|
|
434
443
|
text,
|
|
435
444
|
searched: scope.length,
|
|
436
445
|
ms: Math.round(performance.now() - started),
|
|
@@ -583,9 +592,11 @@ export function createContextEngine({
|
|
|
583
592
|
},
|
|
584
593
|
pack,
|
|
585
594
|
search,
|
|
586
|
-
/**
|
|
587
|
-
|
|
588
|
-
|
|
595
|
+
/** The person's files and the threads' files closest to a question (library.mjs search). */
|
|
596
|
+
searchFiles: (query, options) => library.search(query, options),
|
|
597
|
+
refreshFiles: () => library.refresh({ lane: "background" }),
|
|
598
|
+
/** One part of a file, read fresh for sharing. */
|
|
599
|
+
fileContent: (file, vec) => library.content(file, vec),
|
|
589
600
|
refresh,
|
|
590
601
|
learn,
|
|
591
602
|
report: () => {
|
|
@@ -598,7 +609,7 @@ export function createContextEngine({
|
|
|
598
609
|
status: () => ({
|
|
599
610
|
roots: atlas.roots(),
|
|
600
611
|
pieces: { waiting: atlas.missing(ATLAS_VERSION) },
|
|
601
|
-
|
|
612
|
+
library: library.status(),
|
|
602
613
|
model: model
|
|
603
614
|
? {
|
|
604
615
|
trainedAt: model.trainedAt,
|
|
@@ -622,6 +633,7 @@ export function createContextEngine({
|
|
|
622
633
|
clearInterval(timer);
|
|
623
634
|
clearTimeout(dropCache);
|
|
624
635
|
cached.clear();
|
|
636
|
+
library.stop();
|
|
625
637
|
atlas.close();
|
|
626
638
|
},
|
|
627
639
|
};
|