@sapiom/harness 0.1.6 → 0.2.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 +90 -0
- package/dist/cli/args.d.ts +16 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +80 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/bin.js +12 -65
- package/dist/cli/bin.js.map +1 -1
- package/dist/cli/settings.d.ts.map +1 -1
- package/dist/cli/settings.js +33 -1
- package/dist/cli/settings.js.map +1 -1
- package/dist/core/adapters/claude-code.d.ts +60 -2
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +119 -32
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/codex.d.ts +21 -2
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +53 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/adapters/detect.d.ts +9 -0
- package/dist/core/adapters/detect.d.ts.map +1 -1
- package/dist/core/adapters/detect.js +9 -0
- package/dist/core/adapters/detect.js.map +1 -1
- package/dist/core/canvas-body.d.ts +28 -28
- package/dist/core/canvas-body.d.ts.map +1 -1
- package/dist/core/canvas-body.js +117 -55
- package/dist/core/canvas-body.js.map +1 -1
- package/dist/core/canvas-derive.d.ts +43 -0
- package/dist/core/canvas-derive.d.ts.map +1 -0
- package/dist/core/canvas-derive.js +95 -0
- package/dist/core/canvas-derive.js.map +1 -0
- package/dist/core/canvas-enrichment.d.ts +52 -127
- package/dist/core/canvas-enrichment.d.ts.map +1 -1
- package/dist/core/canvas-enrichment.js +17 -178
- package/dist/core/canvas-enrichment.js.map +1 -1
- package/dist/core/canvas-graph.d.ts +40 -1
- package/dist/core/canvas-graph.d.ts.map +1 -1
- package/dist/core/canvas-graph.js +71 -9
- package/dist/core/canvas-graph.js.map +1 -1
- package/dist/core/canvas-interconnections.d.ts +26 -8
- package/dist/core/canvas-interconnections.d.ts.map +1 -1
- package/dist/core/canvas-interconnections.js +132 -24
- package/dist/core/canvas-interconnections.js.map +1 -1
- package/dist/core/canvas-manifest-check.d.ts.map +1 -1
- package/dist/core/canvas-manifest-check.js +15 -2
- package/dist/core/canvas-manifest-check.js.map +1 -1
- package/dist/core/canvas-render.d.ts +8 -15
- package/dist/core/canvas-render.d.ts.map +1 -1
- package/dist/core/canvas-render.js +29 -41
- package/dist/core/canvas-render.js.map +1 -1
- package/dist/core/canvas-run-state.d.ts +41 -0
- package/dist/core/canvas-run-state.d.ts.map +1 -1
- package/dist/core/canvas-run-state.js +136 -0
- package/dist/core/canvas-run-state.js.map +1 -1
- package/dist/core/canvas-svg.d.ts +9 -4
- package/dist/core/canvas-svg.d.ts.map +1 -1
- package/dist/core/canvas-svg.js +84 -13
- package/dist/core/canvas-svg.js.map +1 -1
- package/dist/core/canvas-template.d.ts +9 -10
- package/dist/core/canvas-template.d.ts.map +1 -1
- package/dist/core/canvas-template.js +57 -20
- package/dist/core/canvas-template.js.map +1 -1
- package/dist/core/canvas-watcher.d.ts +22 -1
- package/dist/core/canvas-watcher.d.ts.map +1 -1
- package/dist/core/canvas-watcher.js +111 -30
- package/dist/core/canvas-watcher.js.map +1 -1
- package/dist/core/collector/normalizer.d.ts +8 -0
- package/dist/core/collector/normalizer.d.ts.map +1 -1
- package/dist/core/collector/normalizer.js +8 -0
- package/dist/core/collector/normalizer.js.map +1 -1
- package/dist/core/collector/store.d.ts +75 -1
- package/dist/core/collector/store.d.ts.map +1 -1
- package/dist/core/collector/store.js +334 -2
- package/dist/core/collector/store.js.map +1 -1
- package/dist/core/errors.d.ts +10 -4
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +11 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/example-seed.d.ts +8 -0
- package/dist/core/example-seed.d.ts.map +1 -1
- package/dist/core/example-seed.js +47 -10
- package/dist/core/example-seed.js.map +1 -1
- package/dist/core/inject/system-prompt.d.ts +8 -0
- package/dist/core/inject/system-prompt.d.ts.map +1 -1
- package/dist/core/inject/system-prompt.js +3 -1
- package/dist/core/inject/system-prompt.js.map +1 -1
- package/dist/core/macros.d.ts.map +1 -1
- package/dist/core/macros.js +5 -6
- package/dist/core/macros.js.map +1 -1
- package/dist/core/paths.d.ts +1 -0
- package/dist/core/paths.d.ts.map +1 -1
- package/dist/core/paths.js +1 -0
- package/dist/core/paths.js.map +1 -1
- package/dist/core/record-archive.d.ts +187 -0
- package/dist/core/record-archive.d.ts.map +1 -0
- package/dist/core/record-archive.js +465 -0
- package/dist/core/record-archive.js.map +1 -0
- package/dist/core/rehydration.d.ts +72 -0
- package/dist/core/rehydration.d.ts.map +1 -0
- package/dist/core/rehydration.js +72 -0
- package/dist/core/rehydration.js.map +1 -0
- package/dist/core/resume-brief.d.ts +130 -0
- package/dist/core/resume-brief.d.ts.map +1 -0
- package/dist/core/resume-brief.js +404 -0
- package/dist/core/resume-brief.js.map +1 -0
- package/dist/core/rolling-summary.d.ts +130 -0
- package/dist/core/rolling-summary.d.ts.map +1 -0
- package/dist/core/rolling-summary.js +227 -0
- package/dist/core/rolling-summary.js.map +1 -0
- package/dist/core/session-manager.d.ts +11 -3
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +56 -7
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-record.d.ts +165 -0
- package/dist/core/session-record.d.ts.map +1 -0
- package/dist/core/session-record.js +470 -0
- package/dist/core/session-record.js.map +1 -0
- package/dist/core/spawn-target.d.ts +12 -0
- package/dist/core/spawn-target.d.ts.map +1 -0
- package/dist/core/spawn-target.js +187 -0
- package/dist/core/spawn-target.js.map +1 -0
- package/dist/core/task-manager.d.ts.map +1 -1
- package/dist/core/task-manager.js +9 -1
- package/dist/core/task-manager.js.map +1 -1
- package/dist/core/template-catalog.d.ts +48 -0
- package/dist/core/template-catalog.d.ts.map +1 -0
- package/dist/core/template-catalog.js +338 -0
- package/dist/core/template-catalog.js.map +1 -0
- package/dist/core/workflow-registry.d.ts.map +1 -1
- package/dist/core/workflow-registry.js +2 -2
- package/dist/core/workflow-registry.js.map +1 -1
- package/dist/core/workspace-watcher.d.ts.map +1 -1
- package/dist/core/workspace-watcher.js +4 -3
- package/dist/core/workspace-watcher.js.map +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -1
- package/dist/profiles/default.d.ts.map +1 -1
- package/dist/profiles/default.js +9 -14
- package/dist/profiles/default.js.map +1 -1
- package/dist/server/canvas.d.ts.map +1 -1
- package/dist/server/canvas.js +7 -7
- package/dist/server/canvas.js.map +1 -1
- package/dist/server/fs.d.ts.map +1 -1
- package/dist/server/fs.js +17 -1
- package/dist/server/fs.js.map +1 -1
- package/dist/server/index.d.ts +12 -3
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +321 -50
- package/dist/server/index.js.map +1 -1
- package/dist/server/ingest.d.ts +11 -0
- package/dist/server/ingest.d.ts.map +1 -1
- package/dist/server/ingest.js +1 -0
- package/dist/server/ingest.js.map +1 -1
- package/dist/server/macros.d.ts +4 -6
- package/dist/server/macros.d.ts.map +1 -1
- package/dist/server/macros.js.map +1 -1
- package/dist/server/rest.d.ts +18 -6
- package/dist/server/rest.d.ts.map +1 -1
- package/dist/server/rest.js +185 -48
- package/dist/server/rest.js.map +1 -1
- package/dist/server/templates.d.ts +24 -0
- package/dist/server/templates.d.ts.map +1 -0
- package/dist/server/templates.js +54 -0
- package/dist/server/templates.js.map +1 -0
- package/dist/shared/types.d.ts +477 -29
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +19 -11
- package/dist/shared/types.js.map +1 -1
- package/dist/web/assets/index-DC65cskq.js +446 -0
- package/dist/web/assets/index-xtD-3FFa.css +32 -0
- package/dist/web/index.html +2 -2
- package/package.json +5 -4
- package/dist/core/canvas-enrich.d.ts +0 -115
- package/dist/core/canvas-enrich.d.ts.map +0 -1
- package/dist/core/canvas-enrich.js +0 -186
- package/dist/core/canvas-enrich.js.map +0 -1
- package/dist/profiles/canvas-guidelines.d.ts +0 -20
- package/dist/profiles/canvas-guidelines.d.ts.map +0 -1
- package/dist/profiles/canvas-guidelines.js +0 -48
- package/dist/profiles/canvas-guidelines.js.map +0 -1
- package/dist/web/assets/index-DCtyI4VW.css +0 -32
- package/dist/web/assets/index-WSw5RvYR.js +0 -445
- package/dist/web/welcome-hero-dark.png +0 -0
- package/dist/web/welcome-hero-light.png +0 -0
|
@@ -9,11 +9,72 @@
|
|
|
9
9
|
* never overlap with an in-flight append and no appended line can be lost
|
|
10
10
|
* in a sweep's read window. Overhead is negligible — appends are low-frequency
|
|
11
11
|
* (one per hook event), and the queue never holds more than O(sessions) entries.
|
|
12
|
+
*
|
|
13
|
+
* Reads (`read`, `index`) run deliberately OUTSIDE that queue: an append is a
|
|
14
|
+
* single `appendFile` of one line, so a reader can never be left waiting out a
|
|
15
|
+
* half-written record it would otherwise have to skip — the worst case is a
|
|
16
|
+
* torn final line from a crash, which the parser drops. Blocking writers
|
|
17
|
+
* behind a 50 MB scan to buy nothing would be the wrong trade.
|
|
18
|
+
*
|
|
19
|
+
* Index: reading one session's events must not rescan the whole file (capped
|
|
20
|
+
* at 50 MB — see store-retention.ts). The index maps each harnessSessionId to
|
|
21
|
+
* the byte spans its lines occupy. It is built lazily on the first read and
|
|
22
|
+
* maintained incrementally after that: each subsequent read scans only the
|
|
23
|
+
* bytes appended since the last one — by this process or by a second harness
|
|
24
|
+
* boot writing to the same file, which is why the trigger is the file's size
|
|
25
|
+
* rather than our own append path. A shrink or an inode change means the file
|
|
26
|
+
* was rewritten underneath us (a retention sweep), which invalidates every
|
|
27
|
+
* offset, so the index is rebuilt from scratch.
|
|
12
28
|
*/
|
|
29
|
+
import { createReadStream } from "node:fs";
|
|
13
30
|
import * as fs from "node:fs/promises";
|
|
14
31
|
import * as path from "node:path";
|
|
15
|
-
import
|
|
32
|
+
import * as readline from "node:readline";
|
|
33
|
+
import { StringDecoder } from "node:string_decoder";
|
|
34
|
+
import { HARNESS_PATHS, } from "../../shared/types.js";
|
|
16
35
|
import { expandHome } from "../paths.js";
|
|
36
|
+
/** Bytes read per positioned read when walking a span (see readSpanLines). */
|
|
37
|
+
const SPAN_CHUNK_BYTES = 1024 * 1024;
|
|
38
|
+
/** Parse one ndjson line into an event, or null when it isn't one. */
|
|
39
|
+
function parseEventLine(line) {
|
|
40
|
+
if (!line.trim())
|
|
41
|
+
return null;
|
|
42
|
+
let parsed;
|
|
43
|
+
try {
|
|
44
|
+
parsed = JSON.parse(line);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
50
|
+
return null;
|
|
51
|
+
const candidate = parsed;
|
|
52
|
+
// harnessSessionId keys the index and ts orders the fold — a line missing
|
|
53
|
+
// either can't be placed in a record, so it isn't an event as far as
|
|
54
|
+
// readers are concerned.
|
|
55
|
+
if (typeof candidate.harnessSessionId !== "string")
|
|
56
|
+
return null;
|
|
57
|
+
if (typeof candidate.ts !== "string" || typeof candidate.type !== "string")
|
|
58
|
+
return null;
|
|
59
|
+
return candidate;
|
|
60
|
+
}
|
|
61
|
+
function matchesFilter(event, sessionIds, types) {
|
|
62
|
+
if (sessionIds && !sessionIds.has(event.harnessSessionId))
|
|
63
|
+
return false;
|
|
64
|
+
if (types && !types.has(event.type))
|
|
65
|
+
return false;
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
/** Append a span, merging into the previous one when contiguous — keeps a
|
|
69
|
+
* single-session file at one span instead of one per line. */
|
|
70
|
+
function pushSpan(spans, start, end) {
|
|
71
|
+
const last = spans[spans.length - 1];
|
|
72
|
+
if (last && last.end >= start) {
|
|
73
|
+
last.end = Math.max(last.end, end);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
spans.push({ start, end });
|
|
77
|
+
}
|
|
17
78
|
/**
|
|
18
79
|
* @param filePath Defaults to `HARNESS_PATHS.events`
|
|
19
80
|
* (`~/.sapiom/harness/events.ndjson`). Override in tests.
|
|
@@ -36,15 +97,286 @@ export function createEventStore(filePath = HARNESS_PATHS.events) {
|
|
|
36
97
|
queue = next.then(() => { }, () => { });
|
|
37
98
|
return next;
|
|
38
99
|
}
|
|
100
|
+
// ── Reading ─────────────────────────────────────────────────────────────
|
|
101
|
+
/** Line-by-line over `[start, end]` — inclusive `end`, as fs streams take it. */
|
|
102
|
+
async function* readLines(start, end) {
|
|
103
|
+
const stream = createReadStream(resolvedPath, { start, end });
|
|
104
|
+
const lines = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
105
|
+
try {
|
|
106
|
+
for await (const line of lines)
|
|
107
|
+
yield line;
|
|
108
|
+
}
|
|
109
|
+
finally {
|
|
110
|
+
lines.close();
|
|
111
|
+
stream.destroy();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Line-by-line over a set of byte spans, through ONE file handle and
|
|
116
|
+
* positioned reads.
|
|
117
|
+
*
|
|
118
|
+
* Not `createReadStream` per span, deliberately: a session interleaved with
|
|
119
|
+
* others across the file has one span per contiguous run of its lines —
|
|
120
|
+
* hundreds of them for a busy machine — and standing up a stream plus a
|
|
121
|
+
* readline interface for each costs far more than the bytes do. A span is
|
|
122
|
+
* still read in bounded chunks (never all at once) so a session that owns the
|
|
123
|
+
* whole 50 MB file can't be pulled into memory in one buffer, and a
|
|
124
|
+
* StringDecoder carries multi-byte characters across chunk boundaries.
|
|
125
|
+
*/
|
|
126
|
+
async function* readSpanLines(spans) {
|
|
127
|
+
if (spans.length === 0)
|
|
128
|
+
return;
|
|
129
|
+
let handle;
|
|
130
|
+
try {
|
|
131
|
+
handle = await fs.open(resolvedPath, "r");
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (err.code === "ENOENT")
|
|
135
|
+
return;
|
|
136
|
+
throw err;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
for (const span of spans) {
|
|
140
|
+
const decoder = new StringDecoder("utf8");
|
|
141
|
+
let carry = "";
|
|
142
|
+
let position = span.start;
|
|
143
|
+
while (position < span.end) {
|
|
144
|
+
const length = Math.min(SPAN_CHUNK_BYTES, span.end - position);
|
|
145
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
146
|
+
const { bytesRead } = await handle.read(buffer, 0, length, position);
|
|
147
|
+
// A short read means the file shrank under us (a sweep landed
|
|
148
|
+
// mid-read): stop this span rather than looping on a stale offset.
|
|
149
|
+
if (bytesRead <= 0)
|
|
150
|
+
break;
|
|
151
|
+
position += bytesRead;
|
|
152
|
+
const chunk = carry + decoder.write(buffer.subarray(0, bytesRead));
|
|
153
|
+
const lines = chunk.split("\n");
|
|
154
|
+
carry = lines.pop() ?? "";
|
|
155
|
+
for (const line of lines)
|
|
156
|
+
yield line;
|
|
157
|
+
}
|
|
158
|
+
// Whatever is left has no trailing newline — the file's last line, or
|
|
159
|
+
// a torn one. Either way it's the caller's parser that decides.
|
|
160
|
+
const tail = carry + decoder.end();
|
|
161
|
+
if (tail)
|
|
162
|
+
yield tail;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
await handle.close().catch(() => { });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
async function statFile() {
|
|
170
|
+
try {
|
|
171
|
+
const stat = await fs.stat(resolvedPath);
|
|
172
|
+
return { size: stat.size, ino: stat.ino };
|
|
173
|
+
}
|
|
174
|
+
catch (err) {
|
|
175
|
+
if (err.code === "ENOENT")
|
|
176
|
+
return null;
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// ── Index ───────────────────────────────────────────────────────────────
|
|
181
|
+
let state = null;
|
|
182
|
+
// Serializes index work so two concurrent reads never scan the same tail
|
|
183
|
+
// twice, nor interleave partial updates into the same maps.
|
|
184
|
+
let indexWork = Promise.resolve();
|
|
185
|
+
function entryFor(current, harnessSessionId) {
|
|
186
|
+
const existing = current.bySession.get(harnessSessionId);
|
|
187
|
+
if (existing)
|
|
188
|
+
return existing;
|
|
189
|
+
const created = {
|
|
190
|
+
harnessSessionId,
|
|
191
|
+
spans: [],
|
|
192
|
+
eventCount: 0,
|
|
193
|
+
turnCount: 0,
|
|
194
|
+
agentSessionIds: [],
|
|
195
|
+
harness: null,
|
|
196
|
+
firstTs: null,
|
|
197
|
+
lastTs: null,
|
|
198
|
+
};
|
|
199
|
+
current.bySession.set(harnessSessionId, created);
|
|
200
|
+
return created;
|
|
201
|
+
}
|
|
202
|
+
function recordEvent(current, event, start, end) {
|
|
203
|
+
const entry = entryFor(current, event.harnessSessionId);
|
|
204
|
+
pushSpan(entry.spans, start, end);
|
|
205
|
+
entry.eventCount += 1;
|
|
206
|
+
if (event.type === "prompt.submitted")
|
|
207
|
+
entry.turnCount += 1;
|
|
208
|
+
if (entry.harness === null && typeof event.harness === "string")
|
|
209
|
+
entry.harness = event.harness;
|
|
210
|
+
if (entry.firstTs === null)
|
|
211
|
+
entry.firstTs = event.ts;
|
|
212
|
+
entry.lastTs = event.ts;
|
|
213
|
+
if (typeof event.agentSessionId === "string" && event.agentSessionId) {
|
|
214
|
+
if (!entry.agentSessionIds.includes(event.agentSessionId)) {
|
|
215
|
+
entry.agentSessionIds.push(event.agentSessionId);
|
|
216
|
+
}
|
|
217
|
+
const siblings = current.byAgentSession.get(event.agentSessionId);
|
|
218
|
+
if (!siblings) {
|
|
219
|
+
current.byAgentSession.set(event.agentSessionId, [event.harnessSessionId]);
|
|
220
|
+
}
|
|
221
|
+
else if (!siblings.includes(event.harnessSessionId)) {
|
|
222
|
+
siblings.push(event.harnessSessionId);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Fold `[from, to)` of the file into `current`. Offsets advance by the BYTE
|
|
228
|
+
* length of each line, not its character count — a multi-byte prompt would
|
|
229
|
+
* otherwise skew every subsequent span.
|
|
230
|
+
*
|
|
231
|
+
* A final line with no trailing newline (a crash mid-append, or a read that
|
|
232
|
+
* caught an append in flight) rewinds `indexedBytes` to that line's start
|
|
233
|
+
* rather than claiming it as indexed: the next reconcile re-reads it, so a
|
|
234
|
+
* line that was merely incomplete at scan time still lands in the index once
|
|
235
|
+
* it's whole. A line that stays torn forever costs one re-parse per read.
|
|
236
|
+
*/
|
|
237
|
+
async function scanInto(current, from, to) {
|
|
238
|
+
if (to <= from)
|
|
239
|
+
return;
|
|
240
|
+
let offset = from;
|
|
241
|
+
let lastLineStart = from;
|
|
242
|
+
let lastLineWasEvent = false;
|
|
243
|
+
for await (const line of readLines(from, to - 1)) {
|
|
244
|
+
lastLineStart = offset;
|
|
245
|
+
// +1 for the newline readline consumed.
|
|
246
|
+
offset += Buffer.byteLength(line, "utf8") + 1;
|
|
247
|
+
const event = parseEventLine(line);
|
|
248
|
+
lastLineWasEvent = event !== null;
|
|
249
|
+
// min(): the last line may have had no newline to count.
|
|
250
|
+
if (event)
|
|
251
|
+
recordEvent(current, event, lastLineStart, Math.min(offset, to));
|
|
252
|
+
}
|
|
253
|
+
// `offset > to` means the last line's counted newline wasn't there. Rewind
|
|
254
|
+
// only if that line also failed to parse — a complete final event without a
|
|
255
|
+
// trailing newline is indexed, and re-reading it would double-count it.
|
|
256
|
+
current.indexedBytes = offset > to && !lastLineWasEvent ? lastLineStart : to;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Bring the index in line with the file on disk, building it if needed.
|
|
260
|
+
* Grown file → scan only the new tail. Shrunk file or a new inode → the
|
|
261
|
+
* offsets we hold describe a file that no longer exists (retention sweep),
|
|
262
|
+
* so rebuild. Unchanged → no I/O beyond the stat.
|
|
263
|
+
*/
|
|
264
|
+
async function reconcile() {
|
|
265
|
+
const stat = await statFile();
|
|
266
|
+
if (!stat) {
|
|
267
|
+
// No file yet: an empty index is the honest answer, and it must not be
|
|
268
|
+
// cached as "indexed" — the next call has to look again.
|
|
269
|
+
state = null;
|
|
270
|
+
return { bySession: new Map(), byAgentSession: new Map(), indexedBytes: 0, ino: -1 };
|
|
271
|
+
}
|
|
272
|
+
const current = state;
|
|
273
|
+
if (current && current.ino === stat.ino && stat.size >= current.indexedBytes) {
|
|
274
|
+
if (stat.size > current.indexedBytes)
|
|
275
|
+
await scanInto(current, current.indexedBytes, stat.size);
|
|
276
|
+
return current;
|
|
277
|
+
}
|
|
278
|
+
const fresh = {
|
|
279
|
+
bySession: new Map(),
|
|
280
|
+
byAgentSession: new Map(),
|
|
281
|
+
indexedBytes: 0,
|
|
282
|
+
ino: stat.ino,
|
|
283
|
+
};
|
|
284
|
+
await scanInto(fresh, 0, stat.size);
|
|
285
|
+
state = fresh;
|
|
286
|
+
return fresh;
|
|
287
|
+
}
|
|
288
|
+
/** Serialize reconciliation; concurrent readers queue behind one scan. */
|
|
289
|
+
function withIndex() {
|
|
290
|
+
const next = indexWork.then(reconcile, reconcile);
|
|
291
|
+
indexWork = next.catch(() => { });
|
|
292
|
+
return next;
|
|
293
|
+
}
|
|
39
294
|
return {
|
|
40
295
|
append(event) {
|
|
41
296
|
return enqueue(async () => {
|
|
42
297
|
await ensureDir();
|
|
43
298
|
await fs.appendFile(resolvedPath, `${JSON.stringify(event)}\n`, "utf8");
|
|
299
|
+
// The index is deliberately NOT written to here. reconcile() is the one
|
|
300
|
+
// writer, and it absorbs this line by scanning from `indexedBytes` to
|
|
301
|
+
// the current size — the appended bytes only, never the whole file.
|
|
302
|
+
//
|
|
303
|
+
// Writing the entry from this side as well is the obvious optimization
|
|
304
|
+
// and it is wrong: a reader's reconcile() can stat a size that already
|
|
305
|
+
// includes this line while its scan is still in flight, so both paths
|
|
306
|
+
// record the same event and every offset after it shifts by a line. One
|
|
307
|
+
// writer, serialized, no window. The cost is a tail read on the next
|
|
308
|
+
// index() call, which is bounded by what was appended since the last
|
|
309
|
+
// one — a few hundred bytes in practice.
|
|
44
310
|
});
|
|
45
311
|
},
|
|
46
312
|
runExclusive(fn) {
|
|
47
|
-
return enqueue(
|
|
313
|
+
return enqueue(() => {
|
|
314
|
+
// A sweep rewrites the file (temp + rename): every offset the index
|
|
315
|
+
// holds points into the old inode. Drop it and let the next read
|
|
316
|
+
// rebuild, rather than trying to predict what the sweep kept.
|
|
317
|
+
state = null;
|
|
318
|
+
return fn();
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
read(filter = {}) {
|
|
322
|
+
const requested = filter.harnessSessionId === undefined
|
|
323
|
+
? null
|
|
324
|
+
: typeof filter.harnessSessionId === "string"
|
|
325
|
+
? [filter.harnessSessionId]
|
|
326
|
+
: [...filter.harnessSessionId];
|
|
327
|
+
const sessionIds = requested ? new Set(requested) : null;
|
|
328
|
+
const types = filter.types ? new Set(filter.types) : null;
|
|
329
|
+
return {
|
|
330
|
+
async *[Symbol.asyncIterator]() {
|
|
331
|
+
if (!requested) {
|
|
332
|
+
// Unfiltered: a full scan IS the answer the caller asked for.
|
|
333
|
+
const stat = await statFile();
|
|
334
|
+
if (!stat || stat.size === 0)
|
|
335
|
+
return;
|
|
336
|
+
for await (const line of readLines(0, stat.size - 1)) {
|
|
337
|
+
const event = parseEventLine(line);
|
|
338
|
+
if (event && matchesFilter(event, null, types))
|
|
339
|
+
yield event;
|
|
340
|
+
}
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const index = await withIndex();
|
|
344
|
+
// Merge the requested sessions' spans and walk them in file order,
|
|
345
|
+
// so a record spanning several sessions still reads sequentially.
|
|
346
|
+
const collected = [];
|
|
347
|
+
for (const id of requested) {
|
|
348
|
+
const entry = index.bySession.get(id);
|
|
349
|
+
if (entry)
|
|
350
|
+
collected.push(...entry.spans.map((span) => ({ ...span })));
|
|
351
|
+
}
|
|
352
|
+
collected.sort((a, b) => a.start - b.start);
|
|
353
|
+
const spans = [];
|
|
354
|
+
for (const span of collected)
|
|
355
|
+
pushSpan(spans, span.start, span.end);
|
|
356
|
+
for await (const line of readSpanLines(spans)) {
|
|
357
|
+
const event = parseEventLine(line);
|
|
358
|
+
if (event && matchesFilter(event, sessionIds, types))
|
|
359
|
+
yield event;
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
async index() {
|
|
365
|
+
const current = await withIndex();
|
|
366
|
+
// A snapshot, not the live maps. reconcile() mutates entries IN PLACE as
|
|
367
|
+
// the file grows, so handing out the internals would let a caller's
|
|
368
|
+
// `turnCount` or `lastTs` change under it between two reads of the same
|
|
369
|
+
// object — and let a caller corrupt the index by writing to a span. The
|
|
370
|
+
// copy is one small object per session; the alternative is a data race
|
|
371
|
+
// dressed up as a `ReadonlyMap`.
|
|
372
|
+
const bySession = new Map();
|
|
373
|
+
for (const [id, entry] of current.bySession) {
|
|
374
|
+
bySession.set(id, { ...entry, spans: entry.spans.map((span) => ({ ...span })), agentSessionIds: [...entry.agentSessionIds] });
|
|
375
|
+
}
|
|
376
|
+
const byAgentSession = new Map();
|
|
377
|
+
for (const [id, sessionIds] of current.byAgentSession)
|
|
378
|
+
byAgentSession.set(id, [...sessionIds]);
|
|
379
|
+
return { bySession, byAgentSession };
|
|
48
380
|
},
|
|
49
381
|
};
|
|
50
382
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/core/collector/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAuB,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAgBzC;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAAmB,aAAa,CAAC,MAAM;IACtE,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,QAAQ,GAAyB,IAAI,CAAC;IAE1C,SAAS,SAAS;QAChB,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,QAAQ,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,gEAAgE;IAChE,gEAAgE;IAChE,oDAAoD;IACpD,IAAI,KAAK,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAE7C,SAAS,OAAO,CAAI,GAAqB;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,KAAK,GAAG,IAAI,CAAC,IAAI,CACf,GAAG,EAAE,GAAE,CAAC,EACR,GAAG,EAAE,GAAE,CAAC,CACT,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO;QACL,MAAM,CAAC,KAAqB;YAC1B,OAAO,OAAO,CAAC,KAAK,IAAI,EAAE;gBACxB,MAAM,SAAS,EAAE,CAAC;gBAClB,MAAM,EAAE,CAAC,UAAU,CAAC,YAAY,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC1E,CAAC,CAAC,CAAC;QACL,CAAC;QAED,YAAY,CAAI,EAAoB;YAClC,OAAO,OAAO,CAAC,EAAE,CAAC,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/core/collector/store.ts"],"names":[],"mappings":"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"}
|
package/dist/core/errors.d.ts
CHANGED
|
@@ -34,12 +34,18 @@ export declare class SessionNotReadyError extends HarnessError {
|
|
|
34
34
|
constructor(id: string);
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Thrown by `resume()` when the session
|
|
38
|
-
*
|
|
39
|
-
*
|
|
37
|
+
* Thrown by `resume()` when the session cannot be handed back to its agent.
|
|
38
|
+
* Two causes, both 409:
|
|
39
|
+
*
|
|
40
|
+
* 1. No `agentSessionId` at all — never fully started (the default message).
|
|
41
|
+
* 2. An `agentSessionId` the agent's own store no longer holds, caught by
|
|
42
|
+
* `resume()`'s `canResume` pre-flight. Pass `reason` for these: the
|
|
43
|
+
* message reaches the user as a toast, and "why" is the whole point —
|
|
44
|
+
* the old behaviour spawned a doomed pty and left them with a bare
|
|
45
|
+
* "exit code 1" and a Resume button that would fail again.
|
|
40
46
|
*/
|
|
41
47
|
export declare class SessionNotResumeableError extends HarnessError {
|
|
42
|
-
constructor(id: string);
|
|
48
|
+
constructor(id: string, reason?: string);
|
|
43
49
|
}
|
|
44
50
|
/**
|
|
45
51
|
* Thrown by `resume()` when the session already has a live pty — double-resume
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+CAA+C;AAC/C,qBAAa,YAAa,SAAQ,KAAK;IACrC,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAQ3D;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,EAAE,EAAE,MAAM;CAGvB;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,EAAE,EAAE,MAAM;CAMvB;AAED
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+CAA+C;AAC/C,qBAAa,YAAa,SAAQ,KAAK;IACrC,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;gBAEb,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,OAAO;CAQ3D;AAED;;;GAGG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;gBACvC,EAAE,EAAE,MAAM;CAGvB;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,EAAE,EAAE,MAAM;CAMvB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,yBAA0B,SAAQ,YAAY;gBAC7C,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAGxC;AAED;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,YAAY;gBAC3C,EAAE,EAAE,MAAM;CAGvB;AAED;;;GAGG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;gBACxC,OAAO,EAAE,MAAM;CAG5B;AAED;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,SAAQ,YAAY;IACpD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBAEb,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAO3C"}
|
package/dist/core/errors.js
CHANGED
|
@@ -41,13 +41,19 @@ export class SessionNotReadyError extends HarnessError {
|
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
43
|
/**
|
|
44
|
-
* Thrown by `resume()` when the session
|
|
45
|
-
*
|
|
46
|
-
*
|
|
44
|
+
* Thrown by `resume()` when the session cannot be handed back to its agent.
|
|
45
|
+
* Two causes, both 409:
|
|
46
|
+
*
|
|
47
|
+
* 1. No `agentSessionId` at all — never fully started (the default message).
|
|
48
|
+
* 2. An `agentSessionId` the agent's own store no longer holds, caught by
|
|
49
|
+
* `resume()`'s `canResume` pre-flight. Pass `reason` for these: the
|
|
50
|
+
* message reaches the user as a toast, and "why" is the whole point —
|
|
51
|
+
* the old behaviour spawned a doomed pty and left them with a bare
|
|
52
|
+
* "exit code 1" and a Resume button that would fail again.
|
|
47
53
|
*/
|
|
48
54
|
export class SessionNotResumeableError extends HarnessError {
|
|
49
|
-
constructor(id) {
|
|
50
|
-
super("SESSION_NOT_RESUMEABLE", `Session "${id}" has no agentSessionId to resume from`);
|
|
55
|
+
constructor(id, reason) {
|
|
56
|
+
super("SESSION_NOT_RESUMEABLE", reason ?? `Session "${id}" has no agentSessionId to resume from`);
|
|
51
57
|
}
|
|
52
58
|
}
|
|
53
59
|
/**
|
package/dist/core/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+CAA+C;AAC/C,MAAM,OAAO,YAAa,SAAQ,KAAK;IAMrC,YAAY,IAAY,EAAE,OAAe,EAAE,KAAe;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,sEAAsE;QACtE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnD,YAAY,EAAU;QACpB,KAAK,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD,YAAY,EAAU;QACpB,KAAK,CACH,mBAAmB,EACnB,YAAY,EAAE,gFAAgF,CAC/F,CAAC;IACJ,CAAC;CACF;AAED
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+CAA+C;AAC/C,MAAM,OAAO,YAAa,SAAQ,KAAK;IAMrC,YAAY,IAAY,EAAE,OAAe,EAAE,KAAe;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,sEAAsE;QACtE,IAAI,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QAC5B,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,mBAAoB,SAAQ,YAAY;IACnD,YAAY,EAAU;QACpB,KAAK,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,CAAC,CAAC;IACtD,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD,YAAY,EAAU;QACpB,KAAK,CACH,mBAAmB,EACnB,YAAY,EAAE,gFAAgF,CAC/F,CAAC;IACJ,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,yBAA0B,SAAQ,YAAY;IACzD,YAAY,EAAU,EAAE,MAAe;QACrC,KAAK,CAAC,wBAAwB,EAAE,MAAM,IAAI,YAAY,EAAE,wCAAwC,CAAC,CAAC;IACpG,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,uBAAwB,SAAQ,YAAY;IACvD,YAAY,EAAU;QACpB,KAAK,CAAC,sBAAsB,EAAE,YAAY,EAAE,0BAA0B,CAAC,CAAC;IAC1E,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IACpD,YAAY,OAAe;QACzB,KAAK,CAAC,mBAAmB,EAAE,sCAAsC,OAAO,GAAG,CAAC,CAAC;IAC/E,CAAC;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,OAAO,oBAAqB,SAAQ,YAAY;IAGpD,YAAY,OAAe,EAAE,KAAa;QACxC,KAAK,CACH,kBAAkB,EAClB,GAAG,KAAK,gCAAgC,KAAK,0CAA0C,CACxF,CAAC;QACF,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF"}
|
|
@@ -11,6 +11,10 @@ export interface SeedExampleProjectOptions {
|
|
|
11
11
|
versions?: ResolvedVersions;
|
|
12
12
|
/** Overrides where the scaffold templates live (tests). */
|
|
13
13
|
templatesDir?: string;
|
|
14
|
+
/** Run `npm install` in the freshly-scaffolded project so the Canvas can
|
|
15
|
+
* bundle it on first render. Defaults to true; set false in tests to keep
|
|
16
|
+
* them offline/fast. Ignored on reuse (nothing is re-scaffolded). */
|
|
17
|
+
installDependencies?: boolean;
|
|
14
18
|
}
|
|
15
19
|
export interface SeedExampleProjectResult {
|
|
16
20
|
/** == options.targetRoot, resolved — the directory to open a session in. */
|
|
@@ -21,6 +25,10 @@ export interface SeedExampleProjectResult {
|
|
|
21
25
|
created: boolean;
|
|
22
26
|
/** Whether a git repo with an initial commit was created (false on reuse or when `git` is unavailable). */
|
|
23
27
|
gitInitialized: boolean;
|
|
28
|
+
/** Whether `npm install` succeeded for the freshly-scaffolded project (false
|
|
29
|
+
* on reuse, or when npm is missing/offline — the Canvas then degrades to its
|
|
30
|
+
* "ask your agent to fix it" prompt on first render). */
|
|
31
|
+
dependenciesInstalled: boolean;
|
|
24
32
|
}
|
|
25
33
|
/**
|
|
26
34
|
* Seeds (or reuses) the example project under `options.targetRoot`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"example-seed.d.ts","sourceRoot":"","sources":["../../src/core/example-seed.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"example-seed.d.ts","sourceRoot":"","sources":["../../src/core/example-seed.ts"],"names":[],"mappings":"AAyCA,OAAO,EAA0C,KAAK,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAMnG,eAAO,MAAM,mBAAmB,iBAAiB,CAAC;AA2NlD,MAAM,WAAW,yBAAyB;IACxC;sFACkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB;mEAC+D;IAC/D,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,2DAA2D;IAC3D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;0EAEsE;IACtE,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,wBAAwB;IACvC,4EAA4E;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,UAAU,EAAE,MAAM,CAAC;IACnB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,2GAA2G;IAC3G,cAAc,EAAE,OAAO,CAAC;IACxB;;8DAE0D;IAC1D,qBAAqB,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA0D9G"}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Seeds the bundled example project — a directory the harness opens
|
|
3
|
-
* beautifully on first run.
|
|
3
|
+
* beautifully on first run.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* ONE caller today: `scripts/seed-example.mjs` (demo prep), which seeds with
|
|
6
|
+
* `force: true` — wipe and regenerate from scratch.
|
|
7
|
+
*
|
|
8
|
+
* There was a second: `POST /api/sample-project`, behind the welcome panel's
|
|
9
|
+
* "Sample project" action, which seeded `~/.sapiom/harness/sample-project`
|
|
10
|
+
* lazily and idempotently. Both the route and the action were removed because
|
|
11
|
+
* the in-app flow did not work; this module was kept because the demo script
|
|
12
|
+
* still needs it. So an existing `~/.sapiom/harness/sample-project/` on a
|
|
13
|
+
* machine is leftover output, not state the app maintains — nothing in the
|
|
14
|
+
* running Studio reads or writes it.
|
|
11
15
|
*
|
|
12
16
|
* Produces:
|
|
13
17
|
* <targetRoot>/order-triage/ — a real scaffolded agent project
|
|
@@ -41,7 +45,12 @@ export const SAMPLE_PROJECT_NAME = "order-triage";
|
|
|
41
45
|
/** Locate @sapiom/agent-core's bundled templates dir (no `__dirname` in ESM). */
|
|
42
46
|
function agentCoreTemplatesDir() {
|
|
43
47
|
const entry = nodeRequire.resolve("@sapiom/agent-core");
|
|
44
|
-
|
|
48
|
+
const dir = path.resolve(path.dirname(entry), "..", "..", "templates");
|
|
49
|
+
// Embedded in Electron, require.resolve reports the app.asar (virtual) path;
|
|
50
|
+
// scaffold()'s cpSync can't opendir inside the asar archive (ENOTDIR), so
|
|
51
|
+
// point at the unpacked twin. No-op under the CLI (real filesystem path).
|
|
52
|
+
// The desktop host must asarUnpack node_modules (it unpacks all of them).
|
|
53
|
+
return dir.replace(/([\\/])app\.asar([\\/])/, "$1app.asar.unpacked$2");
|
|
45
54
|
}
|
|
46
55
|
function tryGit(cwd, args) {
|
|
47
56
|
try {
|
|
@@ -52,6 +61,31 @@ function tryGit(cwd, args) {
|
|
|
52
61
|
return false;
|
|
53
62
|
}
|
|
54
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* Best-effort `npm install` in the freshly-scaffolded project. The Canvas
|
|
66
|
+
* step-graph extraction esbuild-bundles the project, so without its declared
|
|
67
|
+
* deps (`@sapiom/agent`, `zod`, …) installed the very first render fails with
|
|
68
|
+
* "Could not resolve …". Installing here means a freshly-seeded project opens
|
|
69
|
+
* with a working Canvas instead of an error the user has to ask the agent to
|
|
70
|
+
* fix. Non-fatal: if npm is missing or offline, seeding still succeeds and the
|
|
71
|
+
* Canvas falls back to its existing "ask your agent to fix it" prompt.
|
|
72
|
+
* `shell: true` lets Windows resolve the `npm.cmd` shim; cwd (which may contain
|
|
73
|
+
* spaces) is passed via options, not the command line, so it stays safe.
|
|
74
|
+
*/
|
|
75
|
+
function tryInstallDependencies(projectDir) {
|
|
76
|
+
try {
|
|
77
|
+
execFileSync("npm", ["install", "--no-audit", "--no-fund", "--loglevel=error"], {
|
|
78
|
+
cwd: projectDir,
|
|
79
|
+
stdio: "ignore",
|
|
80
|
+
shell: process.platform === "win32",
|
|
81
|
+
timeout: 120000,
|
|
82
|
+
});
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
55
89
|
/** Fold the demo customizations (index.ts, sapiom.json) into the scaffold's initial commit. */
|
|
56
90
|
function commitCustomizations(projectDir) {
|
|
57
91
|
if (!existsSync(path.join(projectDir, ".git")))
|
|
@@ -251,7 +285,7 @@ export async function seedExampleProject(options) {
|
|
|
251
285
|
};
|
|
252
286
|
if (alreadySeeded && !options.force) {
|
|
253
287
|
await writeCanvasPair(false);
|
|
254
|
-
return { root, projectDir, created: false, gitInitialized: false };
|
|
288
|
+
return { root, projectDir, created: false, gitInitialized: false, dependenciesInstalled: false };
|
|
255
289
|
}
|
|
256
290
|
// Wipe a stale copy before rescaffolding — scaffold() refuses a non-empty dir.
|
|
257
291
|
await fs.rm(projectDir, { recursive: true, force: true });
|
|
@@ -270,8 +304,11 @@ export async function seedExampleProject(options) {
|
|
|
270
304
|
});
|
|
271
305
|
await fs.writeFile(path.join(projectDir, "index.ts"), ORDER_TRIAGE_INDEX_TS, "utf8");
|
|
272
306
|
writeConfig(projectDir, { name: SAMPLE_PROJECT_NAME });
|
|
307
|
+
// Install deps BEFORE the initial commit so the (gitignored) node_modules is
|
|
308
|
+
// present for the Canvas's first bundle, while staying out of git history.
|
|
309
|
+
const dependenciesInstalled = (options.installDependencies ?? true) ? tryInstallDependencies(projectDir) : false;
|
|
273
310
|
commitCustomizations(projectDir);
|
|
274
311
|
await writeCanvasPair(true);
|
|
275
|
-
return { root, projectDir, created: true, gitInitialized: result.gitInitialized };
|
|
312
|
+
return { root, projectDir, created: true, gitInitialized: result.gitInitialized, dependenciesInstalled };
|
|
276
313
|
}
|
|
277
314
|
//# sourceMappingURL=example-seed.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"example-seed.js","sourceRoot":"","sources":["../../src/core/example-seed.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"example-seed.js","sourceRoot":"","sources":["../../src/core/example-seed.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,14 @@ export interface GenerateSystemPromptFileOptions {
|
|
|
4
4
|
generatedRoot?: string;
|
|
5
5
|
/** Defaults to the harness's default profile (DEFAULT_SYSTEM_PROMPT). */
|
|
6
6
|
prompt?: string;
|
|
7
|
+
/**
|
|
8
|
+
* Extra text appended after the prompt, separated by a blank line — today
|
|
9
|
+
* the portable-continue brief (core/rehydration.ts). Kept distinct from
|
|
10
|
+
* `prompt` so a caller that only wants to *add* context doesn't have to
|
|
11
|
+
* re-import and re-compose the default profile (and can't accidentally
|
|
12
|
+
* replace it). Empty/whitespace appendices are ignored.
|
|
13
|
+
*/
|
|
14
|
+
appendix?: string;
|
|
7
15
|
}
|
|
8
16
|
/** Writes `<generated>/<harnessSessionId>/system-prompt.txt`. Returns its
|
|
9
17
|
* absolute path (LaunchOpts.systemPromptFile). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../src/core/inject/system-prompt.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,+BAA+B;IAC9C;iFAC6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"system-prompt.d.ts","sourceRoot":"","sources":["../../../src/core/inject/system-prompt.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,+BAA+B;IAC9C;iFAC6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;mDACmD;AACnD,wBAAsB,wBAAwB,CAC5C,gBAAgB,EAAE,MAAM,EACxB,OAAO,GAAE,+BAAoC,GAC5C,OAAO,CAAC,MAAM,CAAC,CAUjB"}
|
|
@@ -15,8 +15,10 @@ export async function generateSystemPromptFile(harnessSessionId, options = {}) {
|
|
|
15
15
|
const root = expandHome(options.generatedRoot ?? HARNESS_PATHS.generated);
|
|
16
16
|
const dir = path.join(root, harnessSessionId);
|
|
17
17
|
await fs.mkdir(dir, { recursive: true });
|
|
18
|
+
const base = options.prompt ?? DEFAULT_SYSTEM_PROMPT;
|
|
19
|
+
const appendix = options.appendix?.trim();
|
|
18
20
|
const filePath = path.join(dir, "system-prompt.txt");
|
|
19
|
-
await fs.writeFile(filePath,
|
|
21
|
+
await fs.writeFile(filePath, appendix ? `${base}\n\n${appendix}\n` : base, "utf8");
|
|
20
22
|
return filePath;
|
|
21
23
|
}
|
|
22
24
|
//# sourceMappingURL=system-prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../../src/core/inject/system-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../../../src/core/inject/system-prompt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACvC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAkBlE;mDACmD;AACnD,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,gBAAwB,EACxB,UAA2C,EAAE;IAE7C,MAAM,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,IAAI,aAAa,CAAC,SAAS,CAAC,CAAC;IAC1E,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IAC9C,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,IAAI,qBAAqB,CAAC;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,mBAAmB,CAAC,CAAC;IACrD,MAAM,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,OAAO,QAAQ,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACnF,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|