@ashlr/hub 3.7.0 → 3.9.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 +257 -0
- package/dist/build-identity.json +2 -2
- package/dist/cli/resource-profile.js +95 -21
- package/dist/cli/resource-profile.js.map +1 -1
- package/dist/core/policy/local-only.d.ts +142 -2
- package/dist/core/policy/local-only.js +204 -15
- package/dist/core/policy/local-only.js.map +1 -1
- package/dist/core/resources/native-profile.d.ts +56 -0
- package/dist/core/resources/native-profile.js +368 -6
- package/dist/core/resources/native-profile.js.map +1 -1
- package/dist/core/run/budget.d.ts +22 -8
- package/dist/core/run/budget.js +80 -12
- package/dist/core/run/budget.js.map +1 -1
- package/dist/core/run/model-catalog.js +8 -1
- package/dist/core/run/model-catalog.js.map +1 -1
- package/dist/core/run/sandboxed-engine.js +3 -3
- package/dist/core/run/sandboxed-engine.js.map +1 -1
- package/dist/core/universe/builtins/preparation/manifest.json +1 -1
- package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +69 -10
- package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +68 -9
- package/dist/core/verse/adapters/claude.d.ts +49 -2
- package/dist/core/verse/adapters/claude.js +317 -56
- package/dist/core/verse/adapters/claude.js.map +1 -1
- package/dist/core/verse/adapters/codex.d.ts +81 -5
- package/dist/core/verse/adapters/codex.js +409 -47
- package/dist/core/verse/adapters/codex.js.map +1 -1
- package/dist/core/verse/adapters/grok.d.ts +13 -1
- package/dist/core/verse/adapters/grok.js +28 -2
- package/dist/core/verse/adapters/grok.js.map +1 -1
- package/dist/core/verse/adapters/index.d.ts +32 -0
- package/dist/core/verse/adapters/index.js +2 -0
- package/dist/core/verse/adapters/index.js.map +1 -1
- package/dist/core/verse/codex-rollout.d.ts +284 -0
- package/dist/core/verse/codex-rollout.js +786 -0
- package/dist/core/verse/codex-rollout.js.map +1 -0
- package/dist/core/verse/context-fit.d.ts +63 -0
- package/dist/core/verse/context-fit.js +355 -0
- package/dist/core/verse/context-fit.js.map +1 -0
- package/dist/core/verse/context-math.d.ts +215 -0
- package/dist/core/verse/context-math.js +365 -0
- package/dist/core/verse/context-math.js.map +1 -0
- package/dist/core/verse/local-models.d.ts +137 -1
- package/dist/core/verse/local-models.js +209 -5
- package/dist/core/verse/local-models.js.map +1 -1
- package/dist/core/verse/model-windows.d.ts +217 -0
- package/dist/core/verse/model-windows.js +616 -0
- package/dist/core/verse/model-windows.js.map +1 -0
- package/dist/core/verse/preferences.d.ts +123 -0
- package/dist/core/verse/preferences.js +403 -0
- package/dist/core/verse/preferences.js.map +1 -0
- package/dist/core/verse/project-memory.d.ts +112 -0
- package/dist/core/verse/project-memory.js +295 -0
- package/dist/core/verse/project-memory.js.map +1 -0
- package/dist/core/verse/seats.d.ts +106 -4
- package/dist/core/verse/seats.js +291 -89
- package/dist/core/verse/seats.js.map +1 -1
- package/dist/core/verse/session-engine.d.ts +117 -2
- package/dist/core/verse/session-engine.js +763 -65
- package/dist/core/verse/session-engine.js.map +1 -1
- package/dist/core/verse/session-handoff.d.ts +94 -0
- package/dist/core/verse/session-handoff.js +551 -0
- package/dist/core/verse/session-handoff.js.map +1 -0
- package/dist/core/verse/session-search.d.ts +63 -0
- package/dist/core/verse/session-search.js +213 -0
- package/dist/core/verse/session-search.js.map +1 -0
- package/dist/core/verse/session-store.d.ts +16 -2
- package/dist/core/verse/session-store.js +80 -6
- package/dist/core/verse/session-store.js.map +1 -1
- package/dist/core/verse/types.d.ts +333 -1
- package/dist/core/verse/types.js +54 -2
- package/dist/core/verse/types.js.map +1 -1
- package/dist/core/verse/verse-api.d.ts +40 -5
- package/dist/core/verse/verse-api.js +724 -25
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/web/api.d.ts +14 -4
- package/dist/core/web/api.js +26 -11
- package/dist/core/web/api.js.map +1 -1
- package/dist/core/web/public/next/assets/{App-vtaHB9mp.js → App-XURmiAAp.js} +5 -5
- package/dist/core/web/public/next/assets/{App-vtaHB9mp.js.map → App-XURmiAAp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ApprovalsSection-B-bFJ0I9.js → ApprovalsSection-BriUzoZc.js} +2 -2
- package/dist/core/web/public/next/assets/{ApprovalsSection-B-bFJ0I9.js.map → ApprovalsSection-BriUzoZc.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-C4GBsQVc.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-DoqmsCjw.js.map → AutonomySection-C4GBsQVc.js.map} +1 -1
- package/dist/core/web/public/next/assets/ChatSection-BpOBOUvg.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-hlgPBRco.js +84 -0
- package/dist/core/web/public/next/assets/ChatSection-hlgPBRco.js.map +1 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-BdQYI-Ng.js +2 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-BdQYI-Ng.js.map +1 -0
- package/dist/core/web/public/next/assets/{Dialog-CPM9JxBc.js → Dialog-BxdIfmFH.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-CPM9JxBc.js.map → Dialog-BxdIfmFH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-B84qVef9.js → DiffViewer-DmeRWuc4.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-B84qVef9.js.map → DiffViewer-DmeRWuc4.js.map} +1 -1
- package/dist/core/web/public/next/assets/{McpSection-CEUpV_5X.js → McpSection-q34T7Tho.js} +2 -2
- package/dist/core/web/public/next/assets/{McpSection-CEUpV_5X.js.map → McpSection-q34T7Tho.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DA8t97XT.js → MutationTokenDialog-CFAkwOEt.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DA8t97XT.js.map → MutationTokenDialog-CFAkwOEt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-Bq7Vyud0.js → ResourcePoolConsoleApp-DHc8GFOY.js} +4 -4
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-Bq7Vyud0.js.map → ResourcePoolConsoleApp-DHc8GFOY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-Badio_uO.js → RouteErrorBoundary-ZL9F4qUn.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-Badio_uO.js.map → RouteErrorBoundary-ZL9F4qUn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-CLcr-4wS.css → Segmented-8cf0Fypn.css} +1 -1
- package/dist/core/web/public/next/assets/{Meter--h3MmZS-.js → Segmented-DbRjVye3.js} +2 -2
- package/dist/core/web/public/next/assets/Segmented-DbRjVye3.js.map +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-nJGGGYqv.js +2 -0
- package/dist/core/web/public/next/assets/{SettingsSection-BwrpQlpP.js.map → SettingsSection-nJGGGYqv.js.map} +1 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-6GJydgo4.js +2 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-_FSohAdN.js.map → UniverseConsoleApp-6GJydgo4.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-DqcXbed4.js → UniverseView-DLDtNYL8.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseView-DqcXbed4.js.map → UniverseView-DLDtNYL8.js.map} +1 -1
- package/dist/core/web/public/next/assets/UsageSection-Cf9d9iFH.js +2 -0
- package/dist/core/web/public/next/assets/UsageSection-Cf9d9iFH.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-DsdKQoTH.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-y0uOHixd.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-y0uOHixd.js.map +1 -0
- package/dist/core/web/public/next/assets/{charts-CTZJ-JrH.js → charts-CVooqJWN.js} +2 -2
- package/dist/core/web/public/next/assets/{charts-CTZJ-JrH.js.map → charts-CVooqJWN.js.map} +1 -1
- package/dist/core/web/public/next/assets/context-model-Bqv8DVuH.js +2 -0
- package/dist/core/web/public/next/assets/context-model-Bqv8DVuH.js.map +1 -0
- package/dist/core/web/public/next/assets/global-eaY9GyX3.js +2 -0
- package/dist/core/web/public/next/assets/global-eaY9GyX3.js.map +1 -0
- package/dist/core/web/public/next/assets/{icons-D9vlf85u.js → icons-vex8rclC.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-D9vlf85u.js.map → icons-vex8rclC.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-CZamKRUg.js → index-D2Eik-zt.js} +3 -3
- package/dist/core/web/public/next/assets/{index-CZamKRUg.js.map → index-D2Eik-zt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{queries-B8eBnFox.js → queries-bAYU0VNy.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-B8eBnFox.js.map → queries-bAYU0VNy.js.map} +1 -1
- package/dist/core/web/public/next/assets/use-guarded-action-C7QrP7Yp.js +2 -0
- package/dist/core/web/public/next/assets/{use-guarded-action-bzrVVAYq.js.map → use-guarded-action-C7QrP7Yp.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-model-TfDk9cky.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-TfDk9cky.js.map +1 -0
- package/dist/core/web/public/next/assets/{workspace-model-v0a1gl-C.js → workspace-model-CHol5RVp.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-v0a1gl-C.js.map → workspace-model-CHol5RVp.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/docs/README.md +1 -0
- package/package.json +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-DoqmsCjw.js +0 -2
- package/dist/core/web/public/next/assets/ChatSection-BfnLe5dT.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js +0 -80
- package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js.map +0 -1
- package/dist/core/web/public/next/assets/ConfirmDialog-Dd2APQhB.js +0 -2
- package/dist/core/web/public/next/assets/ConfirmDialog-Dd2APQhB.js.map +0 -1
- package/dist/core/web/public/next/assets/Meter--h3MmZS-.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-BwrpQlpP.js +0 -2
- package/dist/core/web/public/next/assets/UniverseConsoleApp-_FSohAdN.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-Bq6Daaby.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-Bq6Daaby.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-CMkCizvL.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js.map +0 -1
- package/dist/core/web/public/next/assets/global-D6bTxIRn.js +0 -2
- package/dist/core/web/public/next/assets/global-D6bTxIRn.js.map +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-bzrVVAYq.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js.map +0 -1
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seat-to-seat handoff: a DETERMINISTIC, ZERO-SPEND note that lets a fresh
|
|
3
|
+
* session (same seat, a larger window, or another vendor) pick up where a long
|
|
4
|
+
* one left off.
|
|
5
|
+
*
|
|
6
|
+
* Not to be confused with `handoff.ts`, which is the typed planner-to-worker
|
|
7
|
+
* contract for the local fan-out. This module reads a session's own event log
|
|
8
|
+
* and writes prose for the next agent to read as its first message.
|
|
9
|
+
*
|
|
10
|
+
* WHY DETERMINISTIC: asking the current seat to summarise itself costs a paid
|
|
11
|
+
* turn (and is refused under local-only). Everything below is assembled from
|
|
12
|
+
* `events.jsonl` plus a bounded `git diff --stat` per root, so the preview is
|
|
13
|
+
* free, instant, reproducible, and allowed in every policy mode. When the
|
|
14
|
+
* operator DOES want the agent's own summary, the UI sends a normal turn to the
|
|
15
|
+
* current session first and re-previews with `includeLastAssistant: true` — the
|
|
16
|
+
* spend is then an ordinary, visible, operator-initiated turn.
|
|
17
|
+
*
|
|
18
|
+
* NOTHING HERE STARTS A MODEL CALL. The new session's first turn is spent only
|
|
19
|
+
* when the operator presses send on the pre-filled composer.
|
|
20
|
+
*
|
|
21
|
+
* SECTIONS, highest priority first. When the note would exceed
|
|
22
|
+
* VERSE_HANDOFF_MAX_CHARS the LOWEST-priority sections are dropped, one whole
|
|
23
|
+
* section at a time, and named in `stats.truncated`:
|
|
24
|
+
*
|
|
25
|
+
* focus the operator's focus line for the new session
|
|
26
|
+
* goal the first user message (the original ask)
|
|
27
|
+
* latest-asks the last three user messages after it
|
|
28
|
+
* state the last assistant message, abridged (head + tail) — or
|
|
29
|
+
* verbatim (capped) when `includeLastAssistant`, in which
|
|
30
|
+
* case it is the reply to the canned summary request
|
|
31
|
+
*
|
|
32
|
+
* CONTROL TURNS ARE NOT ASKS. Two kinds of user message are Verse talking to
|
|
33
|
+
* the agent, not the operator stating work: the canned
|
|
34
|
+
* VERSE_HANDOFF_SUMMARY_REQUEST ("Ask this seat to summarize first") and the
|
|
35
|
+
* `/compact [focus]` that "Compact now" sends. Neither may become the goal or
|
|
36
|
+
* a latest request: the footer tells the next agent to "continue with the
|
|
37
|
+
* latest request", and a new chat told to continue with "Write the handoff
|
|
38
|
+
* note…" writes another handoff note instead of doing the work.
|
|
39
|
+
* files files the agent read or edited, from tool inputs (≤ 60)
|
|
40
|
+
* commands shell commands it ran (≤ 15, most recent)
|
|
41
|
+
* errors failures it hit (≤ 5, most recent)
|
|
42
|
+
* repositories the roots, each with a bounded `git diff --stat HEAD`
|
|
43
|
+
* compactions how often the CLI compacted (early detail is summaries)
|
|
44
|
+
*
|
|
45
|
+
* Every section is `scrubSecrets`'d before it is measured, so the cap holds on
|
|
46
|
+
* the text that is actually returned. Control characters (NUL above all) are
|
|
47
|
+
* stripped too: the note becomes the new chat's first turn, and turn text
|
|
48
|
+
* rides on the CLI's argv, where a NUL makes spawn throw. Individual sections carry their own caps
|
|
49
|
+
* too (a 64 KB first message must not evict everything else).
|
|
50
|
+
*
|
|
51
|
+
* The note PREFERS PATHS TO CONTENTS (the rule `handoff.ts` enforces for the
|
|
52
|
+
* local fan-out, for the same reason): the next agent has the filesystem, and
|
|
53
|
+
* a file it reads itself is current where a pasted copy is already stale.
|
|
54
|
+
*/
|
|
55
|
+
import { execFileSync } from 'node:child_process';
|
|
56
|
+
import { isAbsolute, relative, resolve as resolvePath, sep } from 'node:path';
|
|
57
|
+
import { scrubSecrets } from '../util/scrub.js';
|
|
58
|
+
import { estimateTokensFromChars } from './context-math.js';
|
|
59
|
+
import { gitArgs } from './context-fit.js';
|
|
60
|
+
import { isDirectoryPath } from './path-guard.js';
|
|
61
|
+
import { VerseServiceError } from './preferences.js';
|
|
62
|
+
import { stripUnsafeControlChars } from './project-memory.js';
|
|
63
|
+
import { VERSE_HANDOFF_MAX_CHARS, VERSE_HANDOFF_SUMMARY_REQUEST, verseSessionRoots, } from './types.js';
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Constants
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
/** First line of every handoff note. Also how a handoff OF a handoff is recognised. */
|
|
68
|
+
export const VERSE_HANDOFF_HEADER = '# Continuing from an earlier Verse session';
|
|
69
|
+
export const VERSE_HANDOFF_FOCUS_MAX_CHARS = 500;
|
|
70
|
+
export const HANDOFF_MAX_FILES = 60;
|
|
71
|
+
export const HANDOFF_MAX_COMMANDS = 15;
|
|
72
|
+
export const HANDOFF_MAX_ERRORS = 5;
|
|
73
|
+
export const HANDOFF_LATEST_ASKS = 3;
|
|
74
|
+
const GOAL_MAX_CHARS = 2_500;
|
|
75
|
+
const ASK_MAX_CHARS = 900;
|
|
76
|
+
const STATE_SUMMARY_HEAD_CHARS = 900;
|
|
77
|
+
const STATE_SUMMARY_TAIL_CHARS = 700;
|
|
78
|
+
const STATE_VERBATIM_MAX_CHARS = 6_000;
|
|
79
|
+
const COMMAND_MAX_CHARS = 200;
|
|
80
|
+
const ERROR_MAX_CHARS = 240;
|
|
81
|
+
/** `git diff --stat` bounds, per root and in total (the preview is a synchronous request). */
|
|
82
|
+
export const HANDOFF_GIT_TIMEOUT_MS = 3_000;
|
|
83
|
+
export const HANDOFF_GIT_MAX_BYTES = 4 * 1024;
|
|
84
|
+
const HANDOFF_GIT_TOTAL_BUDGET_MS = 6_000;
|
|
85
|
+
/** Section names, in priority order (index 0 = kept longest). Reported in `stats.truncated`. */
|
|
86
|
+
export const HANDOFF_SECTIONS = [
|
|
87
|
+
'focus',
|
|
88
|
+
'goal',
|
|
89
|
+
'latest-asks',
|
|
90
|
+
'state',
|
|
91
|
+
'files',
|
|
92
|
+
'commands',
|
|
93
|
+
'errors',
|
|
94
|
+
'repositories',
|
|
95
|
+
'compactions',
|
|
96
|
+
];
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
// Tool classification (claude / local share Claude Code's names; codex and
|
|
99
|
+
// grok have their own). Names read off real event logs and the CLIs' string
|
|
100
|
+
// tables — see the adapters for where each comes from.
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
const READ_TOOLS = new Set(['Read', 'NotebookRead', 'read_file', 'hashline_read', 'view']);
|
|
103
|
+
const EDIT_TOOLS = new Set([
|
|
104
|
+
'Edit', 'Write', 'MultiEdit', 'NotebookEdit', // Claude Code (claude + local seats)
|
|
105
|
+
'write', 'write_file', 'search_replace', 'hashline_edit', 'edit_file', 'create_file', // grok
|
|
106
|
+
]);
|
|
107
|
+
const COMMAND_TOOLS = new Set(['Bash', 'command_execution', 'run_terminal_command', 'PowerShell', 'shell']);
|
|
108
|
+
const PATH_KEYS = ['file_path', 'notebook_path', 'target_file', 'path', 'filePath', 'filename'];
|
|
109
|
+
function isObject(value) {
|
|
110
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
111
|
+
}
|
|
112
|
+
function pathFromInput(input) {
|
|
113
|
+
if (!isObject(input))
|
|
114
|
+
return null;
|
|
115
|
+
for (const key of PATH_KEYS) {
|
|
116
|
+
const value = input[key];
|
|
117
|
+
if (typeof value === 'string' && value.trim().length > 0 && !value.includes('\0'))
|
|
118
|
+
return value.trim();
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function commandFromInput(input) {
|
|
123
|
+
if (!isObject(input))
|
|
124
|
+
return null;
|
|
125
|
+
const command = input['command'];
|
|
126
|
+
if (typeof command === 'string')
|
|
127
|
+
return command;
|
|
128
|
+
if (Array.isArray(command) && command.every((part) => typeof part === 'string'))
|
|
129
|
+
return command.join(' ');
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
// ---------------------------------------------------------------------------
|
|
133
|
+
// Control turns (see the module comment)
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
function normaliseTurnText(text) {
|
|
136
|
+
return text.replace(/\r\n?/g, '\n').trim();
|
|
137
|
+
}
|
|
138
|
+
const SUMMARY_REQUEST = normaliseTurnText(VERSE_HANDOFF_SUMMARY_REQUEST);
|
|
139
|
+
/** The canned "summarize first" turn, byte-for-byte (after CRLF/whitespace trim). */
|
|
140
|
+
export function isHandoffSummaryRequest(text) {
|
|
141
|
+
return normaliseTurnText(text) === SUMMARY_REQUEST;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* A CLI control command Verse itself sends as a turn. Only `/compact` — the one
|
|
145
|
+
* verb "Compact now" emits — is recognised: a message merely STARTING with a
|
|
146
|
+
* slash ("/Users/me/app is broken") is an ordinary ask and must stay one.
|
|
147
|
+
*/
|
|
148
|
+
export function isControlCommandTurn(text) {
|
|
149
|
+
return /^\/compact(?:\s|$)/.test(normaliseTurnText(text));
|
|
150
|
+
}
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
// Text helpers
|
|
153
|
+
// ---------------------------------------------------------------------------
|
|
154
|
+
function oneLine(text, max) {
|
|
155
|
+
const collapsed = text.replace(/\s+/g, ' ').trim();
|
|
156
|
+
return collapsed.length <= max ? collapsed : `${collapsed.slice(0, max - 1).trimEnd()}…`;
|
|
157
|
+
}
|
|
158
|
+
/** Cap a multi-line block, cutting at a line boundary when that keeps most of it. */
|
|
159
|
+
function capBlock(text, max) {
|
|
160
|
+
const trimmed = text.replace(/\r\n?/g, '\n').trim();
|
|
161
|
+
if (trimmed.length <= max)
|
|
162
|
+
return trimmed;
|
|
163
|
+
const marker = '\n[… truncated]';
|
|
164
|
+
let cut = trimmed.slice(0, max - marker.length);
|
|
165
|
+
const newline = cut.lastIndexOf('\n');
|
|
166
|
+
if (newline >= cut.length * 0.7)
|
|
167
|
+
cut = cut.slice(0, newline);
|
|
168
|
+
return `${cut.trimEnd()}${marker}`;
|
|
169
|
+
}
|
|
170
|
+
/** Head + tail of a long message: agents put the verdict first or last. */
|
|
171
|
+
function abridge(text) {
|
|
172
|
+
const trimmed = text.replace(/\r\n?/g, '\n').trim();
|
|
173
|
+
if (trimmed.length <= STATE_SUMMARY_HEAD_CHARS + STATE_SUMMARY_TAIL_CHARS + 40)
|
|
174
|
+
return trimmed;
|
|
175
|
+
let head = trimmed.slice(0, STATE_SUMMARY_HEAD_CHARS);
|
|
176
|
+
const headBreak = head.lastIndexOf('\n');
|
|
177
|
+
if (headBreak >= head.length * 0.6)
|
|
178
|
+
head = head.slice(0, headBreak);
|
|
179
|
+
let tail = trimmed.slice(trimmed.length - STATE_SUMMARY_TAIL_CHARS);
|
|
180
|
+
const tailBreak = tail.indexOf('\n');
|
|
181
|
+
if (tailBreak !== -1 && tailBreak <= tail.length * 0.4)
|
|
182
|
+
tail = tail.slice(tailBreak + 1);
|
|
183
|
+
return `${head.trimEnd()}\n[… middle of the reply omitted …]\n${tail.trimStart()}`;
|
|
184
|
+
}
|
|
185
|
+
function quoteBlock(text) {
|
|
186
|
+
return text.split('\n').map((line) => (line.length > 0 ? `> ${line}` : '>')).join('\n');
|
|
187
|
+
}
|
|
188
|
+
/** A path as the next agent should read it: relative to the primary root when under it. */
|
|
189
|
+
function displayPath(raw, primary) {
|
|
190
|
+
const absolute = isAbsolute(raw) ? resolvePath(raw) : resolvePath(primary, raw);
|
|
191
|
+
const rel = relative(primary, absolute);
|
|
192
|
+
if (rel.length > 0 && !rel.startsWith('..') && !isAbsolute(rel))
|
|
193
|
+
return rel.split(sep).join('/');
|
|
194
|
+
return absolute;
|
|
195
|
+
}
|
|
196
|
+
function extract(session, events) {
|
|
197
|
+
const primary = session.projectPath;
|
|
198
|
+
const userMessages = [];
|
|
199
|
+
let turnCount = 0;
|
|
200
|
+
let lastAssistant = null;
|
|
201
|
+
// True while the most recent user message is the canned summary request.
|
|
202
|
+
let inSummaryReply = false;
|
|
203
|
+
let summaryReply = null;
|
|
204
|
+
// Insertion-ordered sets; a file edited after being read counts as edited.
|
|
205
|
+
const edited = new Map();
|
|
206
|
+
const read = new Map();
|
|
207
|
+
const commands = [];
|
|
208
|
+
const errors = [];
|
|
209
|
+
const compactions = [];
|
|
210
|
+
const toolNames = new Map();
|
|
211
|
+
const noteEdited = (raw) => {
|
|
212
|
+
const path = displayPath(raw, primary);
|
|
213
|
+
read.delete(path);
|
|
214
|
+
edited.delete(path); // re-insert so "most recent" ordering holds
|
|
215
|
+
edited.set(path, true);
|
|
216
|
+
};
|
|
217
|
+
const noteRead = (raw) => {
|
|
218
|
+
const path = displayPath(raw, primary);
|
|
219
|
+
if (edited.has(path))
|
|
220
|
+
return;
|
|
221
|
+
read.delete(path);
|
|
222
|
+
read.set(path, true);
|
|
223
|
+
};
|
|
224
|
+
for (const event of events) {
|
|
225
|
+
switch (event.type) {
|
|
226
|
+
case 'user-message':
|
|
227
|
+
if (typeof event.text === 'string' && event.text.trim().length > 0) {
|
|
228
|
+
turnCount += 1;
|
|
229
|
+
const summary = isHandoffSummaryRequest(event.text);
|
|
230
|
+
// A new user turn supersedes any earlier summary: only the reply to
|
|
231
|
+
// the LATEST message can describe where the session stands now.
|
|
232
|
+
inSummaryReply = summary;
|
|
233
|
+
summaryReply = null;
|
|
234
|
+
if (!summary && !isControlCommandTurn(event.text)) {
|
|
235
|
+
userMessages.push({ seq: event.seq, text: event.text });
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
break;
|
|
239
|
+
case 'assistant-message':
|
|
240
|
+
if (typeof event.text === 'string' && event.text.trim().length > 0) {
|
|
241
|
+
lastAssistant = event.text;
|
|
242
|
+
if (inSummaryReply)
|
|
243
|
+
summaryReply = event.text;
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
case 'tool-use': {
|
|
247
|
+
toolNames.set(event.toolUseId, event.name);
|
|
248
|
+
if (READ_TOOLS.has(event.name)) {
|
|
249
|
+
const path = pathFromInput(event.input);
|
|
250
|
+
if (path)
|
|
251
|
+
noteRead(path);
|
|
252
|
+
}
|
|
253
|
+
else if (EDIT_TOOLS.has(event.name)) {
|
|
254
|
+
const path = pathFromInput(event.input);
|
|
255
|
+
if (path)
|
|
256
|
+
noteEdited(path);
|
|
257
|
+
}
|
|
258
|
+
else if (event.name === 'file_change' && isObject(event.input) && Array.isArray(event.input['changes'])) {
|
|
259
|
+
// codex: one item can touch several files.
|
|
260
|
+
for (const change of event.input['changes']) {
|
|
261
|
+
if (isObject(change) && typeof change['path'] === 'string' && change['path'].length > 0)
|
|
262
|
+
noteEdited(change['path']);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (COMMAND_TOOLS.has(event.name)) {
|
|
266
|
+
const command = commandFromInput(event.input);
|
|
267
|
+
if (command && command.trim().length > 0) {
|
|
268
|
+
const line = oneLine(command, COMMAND_MAX_CHARS);
|
|
269
|
+
// Collapse immediate repeats (the same test run five times is one fact).
|
|
270
|
+
if (commands[commands.length - 1] !== line)
|
|
271
|
+
commands.push(line);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
276
|
+
case 'tool-result':
|
|
277
|
+
if (event.isError) {
|
|
278
|
+
const name = toolNames.get(event.toolUseId) ?? 'tool';
|
|
279
|
+
const output = typeof event.output === 'string' ? event.output : '';
|
|
280
|
+
const firstLines = output.split('\n').map((l) => l.trim()).filter((l) => l.length > 0).slice(0, 2).join(' — ');
|
|
281
|
+
errors.push(oneLine(`${name}: ${firstLines || 'failed'}`, ERROR_MAX_CHARS));
|
|
282
|
+
}
|
|
283
|
+
break;
|
|
284
|
+
case 'error':
|
|
285
|
+
if (typeof event.message === 'string' && event.message.trim().length > 0) {
|
|
286
|
+
errors.push(oneLine(event.message, ERROR_MAX_CHARS));
|
|
287
|
+
}
|
|
288
|
+
break;
|
|
289
|
+
case 'compaction':
|
|
290
|
+
compactions.push({ preTokens: event.preTokens, postTokens: event.postTokens, trigger: event.trigger });
|
|
291
|
+
break;
|
|
292
|
+
default:
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// Dedupe errors keeping the most recent occurrence of each.
|
|
297
|
+
const recentErrors = [];
|
|
298
|
+
for (let i = errors.length - 1; i >= 0 && recentErrors.length < HANDOFF_MAX_ERRORS; i -= 1) {
|
|
299
|
+
if (!recentErrors.includes(errors[i]))
|
|
300
|
+
recentErrors.unshift(errors[i]);
|
|
301
|
+
}
|
|
302
|
+
const recentCommands = [];
|
|
303
|
+
for (let i = commands.length - 1; i >= 0 && recentCommands.length < HANDOFF_MAX_COMMANDS; i -= 1) {
|
|
304
|
+
if (!recentCommands.includes(commands[i]))
|
|
305
|
+
recentCommands.unshift(commands[i]);
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
userMessages,
|
|
309
|
+
turnCount,
|
|
310
|
+
lastAssistant,
|
|
311
|
+
summaryReply,
|
|
312
|
+
edited: [...edited.keys()],
|
|
313
|
+
read: [...read.keys()],
|
|
314
|
+
commands: recentCommands,
|
|
315
|
+
errors: recentErrors,
|
|
316
|
+
compactions,
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* A session started from a handoff has the previous note as its first message.
|
|
321
|
+
* Its real goal is the "Original goal" section inside that note, not the note.
|
|
322
|
+
*/
|
|
323
|
+
function goalFrom(firstUserText) {
|
|
324
|
+
if (!firstUserText.startsWith(VERSE_HANDOFF_HEADER))
|
|
325
|
+
return firstUserText;
|
|
326
|
+
const match = /\n## Original goal\n+([\s\S]*?)(?:\n## |\n---\n|$)/.exec(firstUserText);
|
|
327
|
+
if (!match)
|
|
328
|
+
return firstUserText;
|
|
329
|
+
return match[1].split('\n').map((line) => line.replace(/^> ?/, '')).join('\n').trim() || firstUserText;
|
|
330
|
+
}
|
|
331
|
+
// ---------------------------------------------------------------------------
|
|
332
|
+
// git diff --stat
|
|
333
|
+
// ---------------------------------------------------------------------------
|
|
334
|
+
/**
|
|
335
|
+
* `git -C <root> diff --stat HEAD`, hardened and bounded: 3 s, 4 KB, no
|
|
336
|
+
* external diff drivers or textconv filters (a repo's .gitattributes can name
|
|
337
|
+
* arbitrary commands), no fsmonitor hook, no index lock. Null when the root is
|
|
338
|
+
* not a repository, has no commits, or git fails.
|
|
339
|
+
*/
|
|
340
|
+
export function defaultGitDiffStat(root) {
|
|
341
|
+
if (!isDirectoryPath(root))
|
|
342
|
+
return null;
|
|
343
|
+
try {
|
|
344
|
+
const out = execFileSync('git', gitArgs(root, ['diff', '--stat', '--no-color', '--no-ext-diff', '--no-textconv', 'HEAD']), {
|
|
345
|
+
encoding: 'utf8',
|
|
346
|
+
timeout: HANDOFF_GIT_TIMEOUT_MS,
|
|
347
|
+
maxBuffer: 1024 * 1024,
|
|
348
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
349
|
+
env: { ...process.env, GIT_OPTIONAL_LOCKS: '0', GIT_TERMINAL_PROMPT: '0', GIT_PAGER: 'cat', PAGER: 'cat' },
|
|
350
|
+
});
|
|
351
|
+
return capGitStat(out);
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
function capGitStat(raw) {
|
|
358
|
+
const text = raw.replace(/\r\n?/g, '\n').trimEnd();
|
|
359
|
+
if (text.trim().length === 0)
|
|
360
|
+
return '';
|
|
361
|
+
if (Buffer.byteLength(text, 'utf8') <= HANDOFF_GIT_MAX_BYTES)
|
|
362
|
+
return text;
|
|
363
|
+
// Keep the summary line ("N files changed, …"): it is the most informative.
|
|
364
|
+
const lines = text.split('\n');
|
|
365
|
+
const summary = lines[lines.length - 1];
|
|
366
|
+
const kept = [];
|
|
367
|
+
let bytes = Buffer.byteLength(summary, 'utf8') + 64;
|
|
368
|
+
for (const line of lines.slice(0, -1)) {
|
|
369
|
+
const size = Buffer.byteLength(line, 'utf8') + 1;
|
|
370
|
+
if (bytes + size > HANDOFF_GIT_MAX_BYTES)
|
|
371
|
+
break;
|
|
372
|
+
kept.push(line);
|
|
373
|
+
bytes += size;
|
|
374
|
+
}
|
|
375
|
+
const omitted = lines.length - 1 - kept.length;
|
|
376
|
+
return [...kept, ` … ${omitted} more file${omitted === 1 ? '' : 's'}`, summary].join('\n');
|
|
377
|
+
}
|
|
378
|
+
function header(session, turns, events) {
|
|
379
|
+
const first = events.length > 0 ? events[0].at.slice(0, 10) : session.createdAt.slice(0, 10);
|
|
380
|
+
const last = events.length > 0 ? events[events.length - 1].at.slice(0, 10) : session.updatedAt.slice(0, 10);
|
|
381
|
+
const span = first === last ? first : `${first} → ${last}`;
|
|
382
|
+
return [
|
|
383
|
+
VERSE_HANDOFF_HEADER,
|
|
384
|
+
'',
|
|
385
|
+
`This chat continues "${oneLine(session.title, 120)}" (${session.engine} · ${session.model}, ${turns} turn${turns === 1 ? '' : 's'}, ${span}).`,
|
|
386
|
+
'The notes below were assembled mechanically from that session\'s log. Treat them as leads, not ground truth: re-read any file before you change it, and check the working tree rather than trusting a summary of it.',
|
|
387
|
+
].join('\n');
|
|
388
|
+
}
|
|
389
|
+
const FOOTER = [
|
|
390
|
+
'---',
|
|
391
|
+
'Start by checking the current state of the files and repositories above, then continue with the latest request. If anything here is unclear or contradicts what you find, say so before acting.',
|
|
392
|
+
].join('\n');
|
|
393
|
+
/**
|
|
394
|
+
* Build the handoff note. Deterministic for a given (session, events, opts,
|
|
395
|
+
* git output): no clock, no randomness, no model.
|
|
396
|
+
*/
|
|
397
|
+
export function buildHandoffPreview(session, events, opts = {}) {
|
|
398
|
+
const focusRaw = typeof opts.focus === 'string' ? opts.focus.trim() : '';
|
|
399
|
+
if (focusRaw.length > VERSE_HANDOFF_FOCUS_MAX_CHARS) {
|
|
400
|
+
throw new VerseServiceError('VERSE_INVALID', `focus must be at most ${VERSE_HANDOFF_FOCUS_MAX_CHARS} characters`);
|
|
401
|
+
}
|
|
402
|
+
const gitDiffStat = opts.gitDiffStat ?? defaultGitDiffStat;
|
|
403
|
+
const data = extract(session, events);
|
|
404
|
+
const turns = data.turnCount;
|
|
405
|
+
const sections = [];
|
|
406
|
+
if (focusRaw.length > 0) {
|
|
407
|
+
sections.push({ name: 'focus', text: `## Focus for this session\n\n${focusRaw}` });
|
|
408
|
+
}
|
|
409
|
+
if (data.userMessages.length > 0) {
|
|
410
|
+
const goal = capBlock(goalFrom(data.userMessages[0].text), GOAL_MAX_CHARS);
|
|
411
|
+
sections.push({ name: 'goal', text: `## Original goal\n\n${quoteBlock(goal)}` });
|
|
412
|
+
}
|
|
413
|
+
const later = data.userMessages.slice(1).slice(-HANDOFF_LATEST_ASKS);
|
|
414
|
+
if (later.length > 0) {
|
|
415
|
+
const skipped = data.userMessages.length - 1 - later.length;
|
|
416
|
+
const lines = [`## Latest requests (oldest first${skipped > 0 ? `; ${skipped} earlier omitted` : ''})`, ''];
|
|
417
|
+
later.forEach((message, index) => {
|
|
418
|
+
// Continuation lines indented under the number so a multi-line ask stays one item.
|
|
419
|
+
lines.push(`${index + 1}. ${capBlock(message.text, ASK_MAX_CHARS).replace(/\n/g, '\n ')}`);
|
|
420
|
+
});
|
|
421
|
+
sections.push({ name: 'latest-asks', text: lines.join('\n') });
|
|
422
|
+
}
|
|
423
|
+
// With `includeLastAssistant` the operator asked the seat to summarise
|
|
424
|
+
// itself: the state section is THAT reply (the last text of the turn that
|
|
425
|
+
// answered the canned request). With no such reply on record — the request
|
|
426
|
+
// failed, or a later turn superseded it — it is the last reply, as before.
|
|
427
|
+
const stateText = opts.includeLastAssistant === true && data.summaryReply !== null ? data.summaryReply : data.lastAssistant;
|
|
428
|
+
if (stateText !== null) {
|
|
429
|
+
const verbatim = opts.includeLastAssistant === true;
|
|
430
|
+
const body = verbatim ? capBlock(stateText, STATE_VERBATIM_MAX_CHARS) : abridge(stateText);
|
|
431
|
+
// Say "abridged" only when something was actually left out.
|
|
432
|
+
const shortened = body !== stateText.replace(/\r\n?/g, '\n').trim();
|
|
433
|
+
const title = verbatim
|
|
434
|
+
? `## Where it stood (the previous agent's own summary, verbatim${shortened ? ', capped' : ''})`
|
|
435
|
+
: `## Where it stood (the previous agent's last reply${shortened ? ', abridged' : ''})`;
|
|
436
|
+
sections.push({ name: 'state', text: `${title}\n\n${quoteBlock(body)}` });
|
|
437
|
+
}
|
|
438
|
+
const touched = [...data.edited, ...data.read];
|
|
439
|
+
if (touched.length > 0) {
|
|
440
|
+
const lines = ['## Files touched', ''];
|
|
441
|
+
const editedShown = data.edited.slice(-HANDOFF_MAX_FILES);
|
|
442
|
+
const readShown = data.read.slice(-(HANDOFF_MAX_FILES - editedShown.length));
|
|
443
|
+
if (editedShown.length > 0) {
|
|
444
|
+
lines.push('Edited:');
|
|
445
|
+
for (const path of editedShown)
|
|
446
|
+
lines.push(`- ${path}`);
|
|
447
|
+
}
|
|
448
|
+
if (readShown.length > 0) {
|
|
449
|
+
if (editedShown.length > 0)
|
|
450
|
+
lines.push('');
|
|
451
|
+
lines.push('Read:');
|
|
452
|
+
for (const path of readShown)
|
|
453
|
+
lines.push(`- ${path}`);
|
|
454
|
+
}
|
|
455
|
+
const hidden = touched.length - editedShown.length - readShown.length;
|
|
456
|
+
if (hidden > 0)
|
|
457
|
+
lines.push('', `(${hidden} more not listed)`);
|
|
458
|
+
lines.push('', `Relative paths are relative to ${session.projectPath}.`);
|
|
459
|
+
sections.push({ name: 'files', text: lines.join('\n') });
|
|
460
|
+
}
|
|
461
|
+
if (data.commands.length > 0) {
|
|
462
|
+
sections.push({
|
|
463
|
+
name: 'commands',
|
|
464
|
+
text: ['## Commands run (most recent last)', '', ...data.commands.map((c) => `- \`${c.replace(/`/g, "'")}\``)].join('\n'),
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
if (data.errors.length > 0) {
|
|
468
|
+
sections.push({
|
|
469
|
+
name: 'errors',
|
|
470
|
+
text: ['## Errors seen (most recent last)', '', ...data.errors.map((e) => `- ${e}`)].join('\n'),
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
const roots = verseSessionRoots(session);
|
|
474
|
+
{
|
|
475
|
+
const lines = ['## Repositories', ''];
|
|
476
|
+
const started = Date.now();
|
|
477
|
+
roots.forEach((root, index) => {
|
|
478
|
+
lines.push(`- ${root}${index === 0 ? ' (primary)' : ''}`);
|
|
479
|
+
// The default runs git synchronously on the request thread: bound the
|
|
480
|
+
// whole loop, not just each call, so eight slow roots cannot stall it.
|
|
481
|
+
if (opts.gitDiffStat === undefined && Date.now() - started > HANDOFF_GIT_TOTAL_BUDGET_MS) {
|
|
482
|
+
lines.push(' (diff not collected: time budget spent)');
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
let stat;
|
|
486
|
+
try {
|
|
487
|
+
stat = gitDiffStat(root);
|
|
488
|
+
}
|
|
489
|
+
catch {
|
|
490
|
+
stat = null;
|
|
491
|
+
}
|
|
492
|
+
if (stat === null)
|
|
493
|
+
return;
|
|
494
|
+
const capped = capGitStat(stat);
|
|
495
|
+
if (capped === null || capped.length === 0) {
|
|
496
|
+
lines.push(' No uncommitted changes against HEAD.');
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
lines.push(' Uncommitted changes against HEAD (`git diff --stat HEAD`):', '', ' ```', ...capped.split('\n').map((l) => ` ${l}`), ' ```');
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
sections.push({ name: 'repositories', text: lines.join('\n') });
|
|
503
|
+
}
|
|
504
|
+
const compactionCount = Math.max(session.compactionCount ?? 0, data.compactions.length);
|
|
505
|
+
if (compactionCount > 0) {
|
|
506
|
+
const last = data.compactions[data.compactions.length - 1];
|
|
507
|
+
const detail = last && last.preTokens !== null && last.postTokens !== null
|
|
508
|
+
? ` The last one shrank the context from ~${Math.round(last.preTokens / 1000)}k to ~${Math.round(last.postTokens / 1000)}k tokens.`
|
|
509
|
+
: '';
|
|
510
|
+
sections.push({
|
|
511
|
+
name: 'compactions',
|
|
512
|
+
text: `## Compactions\n\nThe previous session auto-compacted ${compactionCount} time${compactionCount === 1 ? '' : 's'}, so its early turns survived only as summaries.${detail} Details from early in that session may be lost; verify rather than assume.`,
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
// Scrub every part BEFORE measuring, so the cap holds on what is returned.
|
|
516
|
+
const clean = (text) => scrubSecrets(stripUnsafeControlChars(text));
|
|
517
|
+
const head = clean(header(session, turns, events));
|
|
518
|
+
const foot = FOOTER;
|
|
519
|
+
const scrubbed = sections.map((s) => ({ name: s.name, text: clean(s.text) }));
|
|
520
|
+
const separator = '\n\n';
|
|
521
|
+
const total = (parts) => [head, ...parts.map((p) => p.text), foot].join(separator).length;
|
|
522
|
+
const kept = [...scrubbed];
|
|
523
|
+
const dropped = [];
|
|
524
|
+
while (kept.length > 0 && total(kept) > VERSE_HANDOFF_MAX_CHARS) {
|
|
525
|
+
// Drop the lowest-priority section still present.
|
|
526
|
+
let worst = 0;
|
|
527
|
+
for (let i = 1; i < kept.length; i += 1) {
|
|
528
|
+
if (HANDOFF_SECTIONS.indexOf(kept[i].name) > HANDOFF_SECTIONS.indexOf(kept[worst].name))
|
|
529
|
+
worst = i;
|
|
530
|
+
}
|
|
531
|
+
dropped.push(kept[worst].name);
|
|
532
|
+
kept.splice(worst, 1);
|
|
533
|
+
}
|
|
534
|
+
let text = [head, ...kept.map((p) => p.text), foot].join(separator);
|
|
535
|
+
// Unreachable with the per-section caps above, but the contract is a hard cap.
|
|
536
|
+
if (text.length > VERSE_HANDOFF_MAX_CHARS)
|
|
537
|
+
text = text.slice(0, VERSE_HANDOFF_MAX_CHARS);
|
|
538
|
+
return {
|
|
539
|
+
sourceSessionId: session.id,
|
|
540
|
+
sourceTitle: clean(session.title),
|
|
541
|
+
text,
|
|
542
|
+
stats: {
|
|
543
|
+
chars: text.length,
|
|
544
|
+
estTokens: estimateTokensFromChars(text.length),
|
|
545
|
+
turnsCovered: turns,
|
|
546
|
+
filesTouched: touched.length,
|
|
547
|
+
truncated: dropped,
|
|
548
|
+
},
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
//# sourceMappingURL=session-handoff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-handoff.js","sourceRoot":"","sources":["../../../src/core/verse/session-handoff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyword search over past Verse sessions — zero spend, no index, no model.
|
|
3
|
+
*
|
|
4
|
+
* The corpus is the durable event log the session store already keeps
|
|
5
|
+
* (`<id>.events.jsonl`). Only what the OPERATOR and the AGENT said is searched
|
|
6
|
+
* (`user-message`, `assistant-message`): tool inputs and outputs are huge,
|
|
7
|
+
* noisy and full of file contents that would drown every real hit, and
|
|
8
|
+
* `text-delta` / `thinking` duplicate or pre-empt the final message.
|
|
9
|
+
*
|
|
10
|
+
* MATCHING: every term must occur in ONE message (terms are AND-ed,
|
|
11
|
+
* case-insensitive; a "double-quoted phrase" is one term). A hit is a message,
|
|
12
|
+
* so the snippet shown is the place the operator actually remembers.
|
|
13
|
+
*
|
|
14
|
+
* SCORING (deterministic given `now`):
|
|
15
|
+
* term score = Σ over terms of (1 + ln(occurrences)) — repetition helps, with
|
|
16
|
+
* diminishing returns, so one message that says "migration" 40
|
|
17
|
+
* times does not bury every other
|
|
18
|
+
* title bonus = +1 when every term also appears in the session title
|
|
19
|
+
* kind weight = user messages ×1.1 (the operator's own words are what they
|
|
20
|
+
* search for), assistant ×1.0
|
|
21
|
+
* recency = × (0.35 + 0.65 · 0.5^(ageDays / 14)) — a two-week half-life
|
|
22
|
+
* that never drives an old exact match to zero
|
|
23
|
+
*
|
|
24
|
+
* BOUNDS — this runs synchronously on the API thread, so it is bounded twice:
|
|
25
|
+
* the newest ≤ VERSE_SEARCH_MAX_SESSIONS sessions (by updatedAt) and at most
|
|
26
|
+
* VERSE_SEARCH_MAX_SCAN_CHARS of message text in total. Either bound tripping
|
|
27
|
+
* sets `truncated`, so the UI can say "searched the most recent N" instead of
|
|
28
|
+
* implying the whole history was covered. At most VERSE_SEARCH_MAX_HITS_PER_SESSION
|
|
29
|
+
* hits come from one session so a single long chat cannot fill the list.
|
|
30
|
+
*
|
|
31
|
+
* Snippets are whitespace-collapsed, ≤ 240 chars, and `scrubSecrets`'d.
|
|
32
|
+
*/
|
|
33
|
+
import type { VerseEvent, VerseSearchResponse, VerseSession } from './types.js';
|
|
34
|
+
export declare const VERSE_SEARCH_MAX_SESSIONS = 200;
|
|
35
|
+
/** ~20 MB of message text (UTF-16 code units, which is what is actually scanned). */
|
|
36
|
+
export declare const VERSE_SEARCH_MAX_SCAN_CHARS: number;
|
|
37
|
+
export declare const VERSE_SEARCH_DEFAULT_LIMIT = 20;
|
|
38
|
+
export declare const VERSE_SEARCH_MAX_LIMIT = 50;
|
|
39
|
+
export declare const VERSE_SEARCH_MAX_QUERY_CHARS = 200;
|
|
40
|
+
export declare const VERSE_SEARCH_MAX_TERMS = 8;
|
|
41
|
+
export declare const VERSE_SEARCH_MAX_HITS_PER_SESSION = 3;
|
|
42
|
+
export declare const VERSE_SEARCH_SNIPPET_CHARS = 240;
|
|
43
|
+
export interface VerseSearchInput {
|
|
44
|
+
sessions: VerseSession[];
|
|
45
|
+
readEvents: (id: string) => VerseEvent[];
|
|
46
|
+
query: string;
|
|
47
|
+
limit?: number;
|
|
48
|
+
/** Injectable clock for the recency weight (tests). Default: the real clock. */
|
|
49
|
+
now?: () => Date;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Split a query into lower-cased terms. `"exact phrase"` stays one term;
|
|
53
|
+
* everything else splits on whitespace. Duplicates collapse. Throws
|
|
54
|
+
* VERSE_INVALID for an empty or oversized query.
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseSearchQuery(query: string): string[];
|
|
57
|
+
/**
|
|
58
|
+
* ≤ VERSE_SEARCH_SNIPPET_CHARS of whitespace-collapsed, secret-scrubbed text
|
|
59
|
+
* around the first match. Scrubbed BEFORE windowing so a redaction can never
|
|
60
|
+
* push the snippet over its cap or leave half a token at a window edge.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildSnippet(text: string, firstTerm: string): string;
|
|
63
|
+
export declare function searchSessions(input: VerseSearchInput): VerseSearchResponse;
|