@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
|
@@ -43,11 +43,90 @@ export interface VerseSeat {
|
|
|
43
43
|
* at all — `health.state` says what it does know.
|
|
44
44
|
*/
|
|
45
45
|
capacity?: VerseSeatCapacity;
|
|
46
|
+
/**
|
|
47
|
+
* V3.9 ADDITIVE. The version of the CLI binary this seat is PINNED to (its
|
|
48
|
+
* native-profile launcher execs one exact file). Absent when unknown and on
|
|
49
|
+
* local seats. A pinned binary never updates itself, so a model that needs a
|
|
50
|
+
* newer CLI is listed with `unavailableReason` rather than silently failing.
|
|
51
|
+
*/
|
|
52
|
+
cliVersion?: string;
|
|
53
|
+
/**
|
|
54
|
+
* V3.9 ADDITIVE. Plain-language facts about this seat's context setup the UI
|
|
55
|
+
* must show rather than imply (binary skew, catalog not yet fetched, …).
|
|
56
|
+
* Absent when there is nothing to say, so ordinary seats keep their shape.
|
|
57
|
+
*/
|
|
58
|
+
notes?: string[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Where a context-window figure came from, so nothing on screen implies more
|
|
62
|
+
* certainty than it has (docs/VERSE-CONTEXT.md §1).
|
|
63
|
+
*
|
|
64
|
+
* - `runtime` — the CLI reported it for THIS turn (claude/grok
|
|
65
|
+
* `result.modelUsage.<m>.contextWindow`, codex rollout
|
|
66
|
+
* `token_count.info.model_context_window`, Ollama
|
|
67
|
+
* `/api/ps`). Wins over everything else.
|
|
68
|
+
* - `provider-catalog` — the seat's own served catalog on disk (codex/grok
|
|
69
|
+
* `native-state/models_cache.json`).
|
|
70
|
+
* - `cli-catalog` — read out of the pinned CLI binary's embedded catalog
|
|
71
|
+
* and recorded here with the version it was read from.
|
|
72
|
+
* - `documented` — the provider's published model table.
|
|
73
|
+
* - `fallback` — a named default; the UI marks it as an estimate.
|
|
74
|
+
*/
|
|
75
|
+
export type VerseWindowSource = 'runtime' | 'provider-catalog' | 'cli-catalog' | 'documented' | 'fallback';
|
|
76
|
+
/**
|
|
77
|
+
* How much context a session is allowed to accumulate before the CLI compacts.
|
|
78
|
+
*
|
|
79
|
+
* - `standard` — the default. Evidence-based budget per engine: Claude 1M
|
|
80
|
+
* models compact near 400k instead of ~967k; Codex, Grok and
|
|
81
|
+
* local run their native windows.
|
|
82
|
+
* - `expansive` — opt-in. Claude runs its full native window (CLI `auto`),
|
|
83
|
+
* Codex raises `model_context_window` to the model's catalog
|
|
84
|
+
* maximum (872k on GPT-6 / GPT-5.6). Costs more usage per turn,
|
|
85
|
+
* buys simultaneous visibility for coupled, cross-cutting work.
|
|
86
|
+
*
|
|
87
|
+
* A mode that does not exist for a model (Grok, local, 200k Claude models,
|
|
88
|
+
* GPT-5.5) is simply absent from that model's option — never faked.
|
|
89
|
+
*/
|
|
90
|
+
export type VerseContextMode = 'standard' | 'expansive';
|
|
91
|
+
export declare const VERSE_CONTEXT_MODES: readonly VerseContextMode[];
|
|
92
|
+
/** One mode's budget for a model on a seat. */
|
|
93
|
+
export interface VerseContextBudget {
|
|
94
|
+
/** The window the CLI measures against in this mode (the meter's denominator). */
|
|
95
|
+
contextWindow: number;
|
|
96
|
+
/** Token count at which the CLI auto-compacts in this mode; null when unknown. */
|
|
97
|
+
autoCompactAt: number | null;
|
|
98
|
+
/**
|
|
99
|
+
* The RAW window value the CLI must be TOLD to reach this budget, when that
|
|
100
|
+
* differs from `contextWindow` — codex measures against 95% of the window it
|
|
101
|
+
* is configured with, so expansive GPT-6 is `providerWindow: 872_000`
|
|
102
|
+
* (`-c model_context_window=872000`) but `contextWindow: 828_400`.
|
|
103
|
+
*/
|
|
104
|
+
providerWindow?: number | null;
|
|
46
105
|
}
|
|
47
106
|
export interface VerseModelOption {
|
|
48
107
|
id: string;
|
|
49
108
|
label: string;
|
|
109
|
+
/** Standard-mode window the CLI measures against (codex: the 95% effective window). */
|
|
50
110
|
contextWindow: number | null;
|
|
111
|
+
/**
|
|
112
|
+
* V3.9 ADDITIVE — every field below is optional so records and fixtures
|
|
113
|
+
* written before it keep validating. Absent means "not known", never zero.
|
|
114
|
+
*/
|
|
115
|
+
/** Standard-mode auto-compaction point. */
|
|
116
|
+
autoCompactAt?: number | null;
|
|
117
|
+
/** Present ONLY when this model on this seat has a real expansive mode. */
|
|
118
|
+
expansive?: VerseContextBudget | null;
|
|
119
|
+
/** The CLI's default max output for this model, when known. */
|
|
120
|
+
maxOutputTokens?: number | null;
|
|
121
|
+
windowSource?: VerseWindowSource;
|
|
122
|
+
/** Minimum CLI version that knows this model id (e.g. '2.1.280'); null when any. */
|
|
123
|
+
minCliVersion?: string | null;
|
|
124
|
+
/**
|
|
125
|
+
* Why this model cannot run on this seat right now, in plain language (e.g.
|
|
126
|
+
* "needs Claude Code 2.1.280; this seat runs 2.1.257"). Null/absent = runnable.
|
|
127
|
+
* Listed rather than hidden so the operator learns WHY a model is missing.
|
|
128
|
+
*/
|
|
129
|
+
unavailableReason?: string | null;
|
|
51
130
|
}
|
|
52
131
|
export interface VerseSeatHealth {
|
|
53
132
|
state: 'ready' | 'degraded' | 'unavailable' | 'unknown';
|
|
@@ -324,9 +403,23 @@ export interface VerseUsage {
|
|
|
324
403
|
outputTokens: number;
|
|
325
404
|
cacheReadTokens: number;
|
|
326
405
|
cacheCreationTokens: number;
|
|
327
|
-
/**
|
|
406
|
+
/**
|
|
407
|
+
* Prompt size of the most recent assistant call = live context occupancy.
|
|
408
|
+
* Stored UNCLAMPED: a reading above the window is information (the CLI is
|
|
409
|
+
* about to compact or overflow), and only the UI decides how to draw it.
|
|
410
|
+
*/
|
|
328
411
|
contextTokens: number;
|
|
329
412
|
contextWindow: number | null;
|
|
413
|
+
/** V3.9 ADDITIVE. Where `contextWindow` came from; absent on old records. */
|
|
414
|
+
contextWindowSource?: VerseWindowSource;
|
|
415
|
+
/** V3.9 ADDITIVE. Auto-compaction point for the session's current mode. */
|
|
416
|
+
autoCompactAt?: number | null;
|
|
417
|
+
/**
|
|
418
|
+
* V3.9 ADDITIVE. False when `contextTokens` is an UPPER BOUND rather than a
|
|
419
|
+
* measurement (codex before its rollout is readable: the turn total sums
|
|
420
|
+
* every model call). Absent means exact.
|
|
421
|
+
*/
|
|
422
|
+
contextTokensExact?: boolean;
|
|
330
423
|
}
|
|
331
424
|
export interface VerseSession {
|
|
332
425
|
id: string;
|
|
@@ -365,6 +458,30 @@ export interface VerseSession {
|
|
|
365
458
|
turnCount: number;
|
|
366
459
|
usage: VerseUsage;
|
|
367
460
|
lastError: string | null;
|
|
461
|
+
/**
|
|
462
|
+
* V3.9 ADDITIVE. The session's context budget. Every record written by 3.9+
|
|
463
|
+
* carries it explicitly, so ABSENT means a pre-3.9 record: the engine
|
|
464
|
+
* materializes it on first touch — `expansive` for a Claude 1M model (that
|
|
465
|
+
* is the native ~967k compaction those chats always ran with, so upgrading
|
|
466
|
+
* never forces a paid compaction), `standard` otherwise (= native).
|
|
467
|
+
* Changeable mid-session (POST /sessions/:id/context-mode): it changes CLI
|
|
468
|
+
* flags, not prompt content — but switching DOWN below the current
|
|
469
|
+
* occupancy makes the CLI compact on its next turn.
|
|
470
|
+
*/
|
|
471
|
+
contextMode?: VerseContextMode;
|
|
472
|
+
/** V3.9 ADDITIVE. Native compactions observed so far (claude/grok compact_boundary, codex rollout `compacted`). */
|
|
473
|
+
compactionCount?: number;
|
|
474
|
+
/** V3.9 ADDITIVE. Set when this session was started as a handoff from another. */
|
|
475
|
+
handoffFrom?: {
|
|
476
|
+
sessionId: string;
|
|
477
|
+
title: string;
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* V3.9 ADDITIVE. Shared project memory was offered to this session's CLI at
|
|
481
|
+
* creation. Pinned, like the roots: a conversation must not silently gain a
|
|
482
|
+
* writable directory because a preference moved underneath it.
|
|
483
|
+
*/
|
|
484
|
+
memoryEnabled?: boolean;
|
|
368
485
|
}
|
|
369
486
|
/** Normalized event stream. `seq` is monotonic per session and is the SSE id. */
|
|
370
487
|
export type VerseEvent = {
|
|
@@ -438,6 +555,48 @@ export type VerseEvent = {
|
|
|
438
555
|
at: string;
|
|
439
556
|
type: 'cancelled';
|
|
440
557
|
turnId: string;
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* V3.9. The CLI compacted its own conversation. Token counts are the CLI's
|
|
561
|
+
* own (`compact_metadata.pre_tokens/post_tokens` on claude/grok). Codex
|
|
562
|
+
* rollouts mark only THAT a compaction happened, so its counts are the last
|
|
563
|
+
* `token_count` reading before the marker and the first one after it —
|
|
564
|
+
* measured, but by Verse, not stated by the CLI; its `durationMs` is null.
|
|
565
|
+
* Any count may be null when no reading brackets the compaction.
|
|
566
|
+
*/
|
|
567
|
+
| {
|
|
568
|
+
seq: number;
|
|
569
|
+
at: string;
|
|
570
|
+
type: 'compaction';
|
|
571
|
+
turnId: string | null;
|
|
572
|
+
trigger: 'auto' | 'manual';
|
|
573
|
+
preTokens: number | null;
|
|
574
|
+
postTokens: number | null;
|
|
575
|
+
durationMs: number | null;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* V3.9. A context-occupancy READING that is not a usage delta — e.g. codex's
|
|
579
|
+
* rollout `token_count` (exact last-call prompt size and the window the CLI
|
|
580
|
+
* measured it against), polled mid-turn and read again after it. Replaces
|
|
581
|
+
* the session's `contextTokens`; never summed. The engine fills
|
|
582
|
+
* `autoCompactAt` for the window in force.
|
|
583
|
+
*/
|
|
584
|
+
| {
|
|
585
|
+
seq: number;
|
|
586
|
+
at: string;
|
|
587
|
+
type: 'context';
|
|
588
|
+
turnId: string | null;
|
|
589
|
+
contextTokens: number;
|
|
590
|
+
contextWindow: number | null;
|
|
591
|
+
exact: boolean;
|
|
592
|
+
autoCompactAt?: number | null;
|
|
593
|
+
/**
|
|
594
|
+
* Where `contextWindow` came from. A CLI reading is `runtime`; the event
|
|
595
|
+
* the engine writes after a MODE SWITCH carries the new budget's catalog
|
|
596
|
+
* source, so a client never relabels a catalog figure as a measurement.
|
|
597
|
+
* Absent on events from before this field existed (treat as `runtime`).
|
|
598
|
+
*/
|
|
599
|
+
contextWindowSource?: VerseWindowSource;
|
|
441
600
|
};
|
|
442
601
|
export type VerseEventType = VerseEvent['type'];
|
|
443
602
|
/**
|
|
@@ -529,6 +688,18 @@ export interface VerseCreateSessionRequest {
|
|
|
529
688
|
* from.
|
|
530
689
|
*/
|
|
531
690
|
workspaceName?: string;
|
|
691
|
+
/**
|
|
692
|
+
* V3.9 ADDITIVE. Absent → the seat's preferred mode (preferences.json), else
|
|
693
|
+
* `standard`. `expansive` on a model with no expansive budget is rejected.
|
|
694
|
+
*/
|
|
695
|
+
contextMode?: VerseContextMode;
|
|
696
|
+
/**
|
|
697
|
+
* V3.9 ADDITIVE. Start this session as a handoff from an existing one. The
|
|
698
|
+
* server resolves the source's title itself (never from the body) and pins
|
|
699
|
+
* `handoffFrom`; the handoff TEXT is sent by the client as turn 1, after the
|
|
700
|
+
* operator has read it — nothing is spent on their behalf.
|
|
701
|
+
*/
|
|
702
|
+
handoffFromSessionId?: string;
|
|
532
703
|
}
|
|
533
704
|
/** POST /api/verse/sessions/:id/turns */
|
|
534
705
|
export interface VerseTurnRequest {
|
|
@@ -555,4 +726,165 @@ export interface VerseTurnLaunch {
|
|
|
555
726
|
export declare const VERSE_MAX_TURN_TEXT_BYTES: number;
|
|
556
727
|
export declare const VERSE_MAX_EVENTS_PER_SESSION = 20000;
|
|
557
728
|
export declare const VERSE_TURN_TIMEOUT_MS: number;
|
|
729
|
+
/**
|
|
730
|
+
* LAST-RESORT fallbacks, used only when neither the runtime, the seat's own
|
|
731
|
+
* catalog, nor the verified per-model table (core/verse/model-windows.ts) knows
|
|
732
|
+
* the model. Each mirrors what the CLI ITSELF assumes for an unknown id, so the
|
|
733
|
+
* meter never claims more than the CLI will allow:
|
|
734
|
+
*
|
|
735
|
+
* - claude 200_000 — Claude Code's `Mg()` default for an unrecognized model.
|
|
736
|
+
* Every KNOWN Claude id carries its real window (1M for the 5.x family,
|
|
737
|
+
* Opus 4.8 and Sonnet 5) in the per-model table instead.
|
|
738
|
+
* - codex 258_400 — 272_000 × the 95% `effective_context_window_percent`
|
|
739
|
+
* every codex catalog entry carries; the figure codex's own rollouts report
|
|
740
|
+
* as `model_context_window` (65,440 of 65,440 observed events).
|
|
741
|
+
* - grok 500_000 — `context_window` for every grok-4.x id in the seat catalog.
|
|
742
|
+
* - local 65_536 — the num_ctx the default local tag pins.
|
|
743
|
+
*/
|
|
558
744
|
export declare const VERSE_DEFAULT_CONTEXT_WINDOWS: Record<string, number>;
|
|
745
|
+
/** GET /api/verse/preferences — the operator's standing context choices. */
|
|
746
|
+
export interface VersePreferences {
|
|
747
|
+
version: 1;
|
|
748
|
+
/** Per-seat default context mode for NEW sessions. Absent = `standard`. */
|
|
749
|
+
seats: Record<string, {
|
|
750
|
+
contextMode?: VerseContextMode;
|
|
751
|
+
}>;
|
|
752
|
+
/** Shared project memory. On by default; listed canonical paths opt out. */
|
|
753
|
+
memory: {
|
|
754
|
+
enabled: boolean;
|
|
755
|
+
disabledProjects: string[];
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* POST /api/verse/preferences — exactly ONE of the three forms per request, so
|
|
760
|
+
* a body can never change more than the operator clicked.
|
|
761
|
+
*/
|
|
762
|
+
export type VersePreferencesUpdate = {
|
|
763
|
+
seatId: string;
|
|
764
|
+
contextMode: VerseContextMode;
|
|
765
|
+
} | {
|
|
766
|
+
memoryEnabled: boolean;
|
|
767
|
+
} | {
|
|
768
|
+
projectPath: string;
|
|
769
|
+
memoryEnabled: boolean;
|
|
770
|
+
};
|
|
771
|
+
/** POST /api/verse/sessions/:id/context-mode */
|
|
772
|
+
export interface VerseContextModeRequest {
|
|
773
|
+
mode: VerseContextMode;
|
|
774
|
+
}
|
|
775
|
+
/** POST /api/verse/sessions/:id/handoff-preview */
|
|
776
|
+
export interface VerseHandoffPreviewRequest {
|
|
777
|
+
/**
|
|
778
|
+
* Include the latest assistant message verbatim (capped) as the agent's own
|
|
779
|
+
* summary — used after "Ask this seat to summarize" produced one.
|
|
780
|
+
*/
|
|
781
|
+
includeLastAssistant?: boolean;
|
|
782
|
+
/** Optional operator focus line, e.g. "finish the migration of X". ≤ 500 chars. */
|
|
783
|
+
focus?: string;
|
|
784
|
+
}
|
|
785
|
+
/** Deterministic, zero-spend handoff note built from the session's event log. */
|
|
786
|
+
export interface VerseHandoffPreview {
|
|
787
|
+
sourceSessionId: string;
|
|
788
|
+
sourceTitle: string;
|
|
789
|
+
/** The exact text to send as turn 1 of the new session. ≤ VERSE_HANDOFF_MAX_CHARS. */
|
|
790
|
+
text: string;
|
|
791
|
+
stats: {
|
|
792
|
+
chars: number;
|
|
793
|
+
/** chars / 4, rounded up — the same estimator the fit badges use. */
|
|
794
|
+
estTokens: number;
|
|
795
|
+
turnsCovered: number;
|
|
796
|
+
filesTouched: number;
|
|
797
|
+
/** Sections dropped to respect the cap, by name; empty when nothing was cut. */
|
|
798
|
+
truncated: string[];
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
export declare const VERSE_HANDOFF_MAX_CHARS = 12000;
|
|
802
|
+
/**
|
|
803
|
+
* The canned turn behind "Ask this seat to summarize first". Shared by the UI
|
|
804
|
+
* (which sends it as an ordinary turn through the normal spend chokepoint) and
|
|
805
|
+
* the handoff builder (which must NOT carry it into the new session as the
|
|
806
|
+
* operator's "latest ask" — the new chat would otherwise be told to write a
|
|
807
|
+
* handoff note instead of continuing the work).
|
|
808
|
+
*
|
|
809
|
+
* Written so the reply is useful as turn 1 of a session that has NONE of this
|
|
810
|
+
* context. It asks for no tool use on purpose: a summary that starts editing
|
|
811
|
+
* files is not a summary, and a read-only turn is also the cheapest one.
|
|
812
|
+
*/
|
|
813
|
+
export declare const VERSE_HANDOFF_SUMMARY_REQUEST: string;
|
|
814
|
+
/** GET /api/verse/context-fit — how big the reachable code is, in tokens. */
|
|
815
|
+
export interface VerseContextFitRoot {
|
|
816
|
+
path: string;
|
|
817
|
+
/** Tracked text files counted (git ls-files, binaries and >1 MB files skipped). */
|
|
818
|
+
files: number;
|
|
819
|
+
bytes: number;
|
|
820
|
+
estTokens: number;
|
|
821
|
+
/** True when the scan hit its file or time cap; estTokens is then a floor. */
|
|
822
|
+
truncated: boolean;
|
|
823
|
+
}
|
|
824
|
+
export interface VerseContextFit {
|
|
825
|
+
roots: VerseContextFitRoot[];
|
|
826
|
+
totalEstTokens: number;
|
|
827
|
+
/** Always 'bytes/4' today; named so a better estimator can be introduced honestly. */
|
|
828
|
+
estimator: 'bytes/4';
|
|
829
|
+
sampledAt: string;
|
|
830
|
+
}
|
|
831
|
+
/**
|
|
832
|
+
* Per-model verdict for a working set (see context-math.ts `fitVerdict`):
|
|
833
|
+
* fits in standard, tight in standard, fits only in expansive, or too big for
|
|
834
|
+
* any single context (split the work).
|
|
835
|
+
*/
|
|
836
|
+
export type VerseFitVerdict = 'fits' | 'tight' | 'expansive' | 'split';
|
|
837
|
+
/** GET /api/verse/search?q=&limit= — keyword search over past sessions. Zero spend. */
|
|
838
|
+
export interface VerseSearchHit {
|
|
839
|
+
sessionId: string;
|
|
840
|
+
title: string;
|
|
841
|
+
projectPath: string;
|
|
842
|
+
engine: VerseEngine;
|
|
843
|
+
seq: number;
|
|
844
|
+
at: string;
|
|
845
|
+
kind: 'user' | 'assistant';
|
|
846
|
+
/** ≤ 240 chars around the first match, whitespace-collapsed. */
|
|
847
|
+
snippet: string;
|
|
848
|
+
score: number;
|
|
849
|
+
}
|
|
850
|
+
export interface VerseSearchResponse {
|
|
851
|
+
query: string;
|
|
852
|
+
hits: VerseSearchHit[];
|
|
853
|
+
/** Sessions actually scanned (the scan is bounded; see session-search.ts). */
|
|
854
|
+
scannedSessions: number;
|
|
855
|
+
truncated: boolean;
|
|
856
|
+
}
|
|
857
|
+
/** GET/POST /api/verse/memory — shared project memory for one project. */
|
|
858
|
+
export interface VerseProjectMemory {
|
|
859
|
+
projectPath: string;
|
|
860
|
+
enabled: boolean;
|
|
861
|
+
/** Contents of MEMORY.md ('' when absent). */
|
|
862
|
+
content: string;
|
|
863
|
+
bytes: number;
|
|
864
|
+
updatedAt: string | null;
|
|
865
|
+
/** Other files the agents created in the memory directory (names only). */
|
|
866
|
+
files: string[];
|
|
867
|
+
/**
|
|
868
|
+
* Present (true) only when `content` as SENT differs from the bytes on disk:
|
|
869
|
+
* the public-JSON sanitizer rewrote the home path to `~` or replaced a
|
|
870
|
+
* secret-looking value with `[REDACTED]`. The file itself is untouched; a
|
|
871
|
+
* save that would write placeholders over real values is refused (409
|
|
872
|
+
* VERSE_MEMORY_REDACTED), so the editor must say so before the operator types.
|
|
873
|
+
*/
|
|
874
|
+
contentSanitized?: boolean;
|
|
875
|
+
}
|
|
876
|
+
/** POST /api/verse/memory */
|
|
877
|
+
export interface VerseProjectMemoryWrite {
|
|
878
|
+
projectPath: string;
|
|
879
|
+
content: string;
|
|
880
|
+
}
|
|
881
|
+
export declare const VERSE_MEMORY_MAX_BYTES: number;
|
|
882
|
+
/**
|
|
883
|
+
* POST /api/verse/memory's own JSON body cap: JSON escaping can double the
|
|
884
|
+
* content (every newline becomes `\\n`), plus room for the other fields. Every
|
|
885
|
+
* other route keeps the 64 KiB default. Shared so the browser's pre-check can
|
|
886
|
+
* never refuse a save the server would accept.
|
|
887
|
+
*/
|
|
888
|
+
export declare const VERSE_MEMORY_BODY_MAX_BYTES: number;
|
|
889
|
+
/** Cap on the memory block appended to each session's system prompt. */
|
|
890
|
+
export declare const VERSE_MEMORY_BLOCK_MAX_BYTES: number;
|
package/dist/core/verse/types.js
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* Nothing in this module reads secrets. Account identity is pinned by the
|
|
16
16
|
* launcher command recorded in ~/.ashlr/account-connections/connections.json.
|
|
17
17
|
*/
|
|
18
|
+
export const VERSE_CONTEXT_MODES = ['standard', 'expansive'];
|
|
18
19
|
export const VERSE_ROOT_PRIORITIES = ['critical', 'high', 'normal', 'low'];
|
|
19
20
|
export const VERSE_DEFAULT_ROOT_PRIORITY = 'normal';
|
|
20
21
|
/** Sort weight; lower sorts first. Never a budget, never a multiplier. */
|
|
@@ -44,10 +45,61 @@ export function verseSessionRoots(session) {
|
|
|
44
45
|
export const VERSE_MAX_TURN_TEXT_BYTES = 64 * 1024;
|
|
45
46
|
export const VERSE_MAX_EVENTS_PER_SESSION = 20_000;
|
|
46
47
|
export const VERSE_TURN_TIMEOUT_MS = 30 * 60 * 1000;
|
|
48
|
+
/**
|
|
49
|
+
* LAST-RESORT fallbacks, used only when neither the runtime, the seat's own
|
|
50
|
+
* catalog, nor the verified per-model table (core/verse/model-windows.ts) knows
|
|
51
|
+
* the model. Each mirrors what the CLI ITSELF assumes for an unknown id, so the
|
|
52
|
+
* meter never claims more than the CLI will allow:
|
|
53
|
+
*
|
|
54
|
+
* - claude 200_000 — Claude Code's `Mg()` default for an unrecognized model.
|
|
55
|
+
* Every KNOWN Claude id carries its real window (1M for the 5.x family,
|
|
56
|
+
* Opus 4.8 and Sonnet 5) in the per-model table instead.
|
|
57
|
+
* - codex 258_400 — 272_000 × the 95% `effective_context_window_percent`
|
|
58
|
+
* every codex catalog entry carries; the figure codex's own rollouts report
|
|
59
|
+
* as `model_context_window` (65,440 of 65,440 observed events).
|
|
60
|
+
* - grok 500_000 — `context_window` for every grok-4.x id in the seat catalog.
|
|
61
|
+
* - local 65_536 — the num_ctx the default local tag pins.
|
|
62
|
+
*/
|
|
47
63
|
export const VERSE_DEFAULT_CONTEXT_WINDOWS = {
|
|
48
64
|
claude: 200_000,
|
|
49
|
-
codex:
|
|
50
|
-
grok:
|
|
65
|
+
codex: 258_400,
|
|
66
|
+
grok: 500_000,
|
|
51
67
|
local: 65_536,
|
|
52
68
|
};
|
|
69
|
+
export const VERSE_HANDOFF_MAX_CHARS = 12_000;
|
|
70
|
+
/**
|
|
71
|
+
* The canned turn behind "Ask this seat to summarize first". Shared by the UI
|
|
72
|
+
* (which sends it as an ordinary turn through the normal spend chokepoint) and
|
|
73
|
+
* the handoff builder (which must NOT carry it into the new session as the
|
|
74
|
+
* operator's "latest ask" — the new chat would otherwise be told to write a
|
|
75
|
+
* handoff note instead of continuing the work).
|
|
76
|
+
*
|
|
77
|
+
* Written so the reply is useful as turn 1 of a session that has NONE of this
|
|
78
|
+
* context. It asks for no tool use on purpose: a summary that starts editing
|
|
79
|
+
* files is not a summary, and a read-only turn is also the cheapest one.
|
|
80
|
+
*/
|
|
81
|
+
export const VERSE_HANDOFF_SUMMARY_REQUEST = [
|
|
82
|
+
'This conversation is about to continue in a fresh session that has none of its context.',
|
|
83
|
+
'Write the handoff note that new session should start from. Do not edit files or run commands for this — only write the note.',
|
|
84
|
+
'',
|
|
85
|
+
'Cover, concretely:',
|
|
86
|
+
'- The goal, and what "done" looks like.',
|
|
87
|
+
'- Decisions made so far, each with the reason it was made.',
|
|
88
|
+
'- Current state: what is finished, what is half-done, what is untested.',
|
|
89
|
+
'- Files changed and anything not yet committed.',
|
|
90
|
+
'- How to verify the work (exact commands).',
|
|
91
|
+
'- Open questions, risks, and approaches already tried that did not work.',
|
|
92
|
+
'',
|
|
93
|
+
'Keep it under 600 words. Prefer file paths and commands over prose.',
|
|
94
|
+
].join('\n');
|
|
95
|
+
export const VERSE_MEMORY_MAX_BYTES = 64 * 1024;
|
|
96
|
+
/**
|
|
97
|
+
* POST /api/verse/memory's own JSON body cap: JSON escaping can double the
|
|
98
|
+
* content (every newline becomes `\\n`), plus room for the other fields. Every
|
|
99
|
+
* other route keeps the 64 KiB default. Shared so the browser's pre-check can
|
|
100
|
+
* never refuse a save the server would accept.
|
|
101
|
+
*/
|
|
102
|
+
export const VERSE_MEMORY_BODY_MAX_BYTES = 2 * VERSE_MEMORY_MAX_BYTES + 8 * 1024;
|
|
103
|
+
/** Cap on the memory block appended to each session's system prompt. */
|
|
104
|
+
export const VERSE_MEMORY_BLOCK_MAX_BYTES = 6 * 1024;
|
|
53
105
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/verse/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/core/verse/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAgFH,MAAM,CAAC,MAAM,mBAAmB,GAAgC,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;AA4N1F,MAAM,CAAC,MAAM,qBAAqB,GAChC,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;AAExC,MAAM,CAAC,MAAM,2BAA2B,GAAsB,QAAQ,CAAC;AAEvE,0EAA0E;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAsC;IACzE,QAAQ,EAAE,CAAC;IACX,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,GAAG,EAAE,CAAC;CACP,CAAC;AA2HF,wEAAwE;AACxE,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAyD;IAEzD,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAC5C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AA6QD,MAAM,CAAC,MAAM,yBAAyB,GAAG,EAAE,GAAG,IAAI,CAAC;AACnD,MAAM,CAAC,MAAM,4BAA4B,GAAG,MAAM,CAAC;AACnD,MAAM,CAAC,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AACpD;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAA2B;IACnE,MAAM,EAAE,OAAO;IACf,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,OAAO;IACb,KAAK,EAAE,MAAM;CACd,CAAC;AAyDF,MAAM,CAAC,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,6BAA6B,GAAG;IAC3C,yFAAyF;IACzF,8HAA8H;IAC9H,EAAE;IACF,oBAAoB;IACpB,yCAAyC;IACzC,4DAA4D;IAC5D,yEAAyE;IACzE,iDAAiD;IACjD,4CAA4C;IAC5C,0EAA0E;IAC1E,EAAE;IACF,qEAAqE;CACtE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AA4Eb,MAAM,CAAC,MAAM,sBAAsB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEhD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,GAAG,sBAAsB,GAAG,CAAC,GAAG,IAAI,CAAC;AAEjF,wEAAwE;AACxE,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,GAAG,IAAI,CAAC"}
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* - GETs sit behind the read-session boundary in server.ts.
|
|
7
7
|
* - POSTs are 404 unless ctx.allowDispatch, then passesMutationGate()
|
|
8
8
|
* (constant-time x-ashlr-token + JSON Content-Type), then readBody()
|
|
9
|
-
* (64 KB cap).
|
|
9
|
+
* (64 KB cap; POST /memory alone gets VERSE_MEMORY_BODY_MAX_BYTES).
|
|
10
10
|
* - Every response goes through sendJson() → sanitizePublicJson().
|
|
11
11
|
*
|
|
12
|
-
* Routes (see docs/VERSE-CONTRACT-V1.md):
|
|
12
|
+
* Routes (see docs/VERSE-CONTRACT-V1.md, docs/VERSE-CONTEXT.md for V3.9):
|
|
13
13
|
* GET /api/verse/bootstrap → VerseBootstrap
|
|
14
14
|
* GET /api/verse/seats → VerseSeatsResponse (pollable)
|
|
15
15
|
* GET /api/verse/sessions → VerseSession[]
|
|
@@ -20,26 +20,48 @@
|
|
|
20
20
|
* POST /api/verse/sessions/:id/delete → { ok: true }
|
|
21
21
|
* POST /api/verse/sessions/:id/rename → VerseSession
|
|
22
22
|
* GET /api/verse/sessions/:id/events → SSE (verse-stream.ts)
|
|
23
|
+
* V3.9 context orchestration — every one of these is ZERO SPEND: none starts
|
|
24
|
+
* a model call; the only way a token is spent is still POST .../turns.
|
|
25
|
+
* POST /api/verse/sessions/:id/context-mode → VerseSession
|
|
26
|
+
* POST /api/verse/sessions/:id/handoff-preview → VerseHandoffPreview
|
|
27
|
+
* GET /api/verse/preferences → VersePreferences
|
|
28
|
+
* POST /api/verse/preferences → VersePreferences
|
|
29
|
+
* GET /api/verse/context-fit → VerseContextFit
|
|
30
|
+
* GET /api/verse/search → VerseSearchResponse
|
|
31
|
+
* GET /api/verse/memory → VerseProjectMemory (+ contentSanitized?)
|
|
32
|
+
* POST /api/verse/memory → VerseProjectMemory (+ contentSanitized?)
|
|
23
33
|
*
|
|
24
34
|
* Errors: { error, code? } with VERSE_SESSION_NOT_FOUND 404,
|
|
25
|
-
* VERSE_SESSION_BUSY 409, VERSE_INVALID 400, VERSE_TOO_LARGE 413
|
|
35
|
+
* VERSE_SESSION_BUSY 409, VERSE_INVALID 400, VERSE_TOO_LARGE 413, and two
|
|
36
|
+
* route-local 409s: VERSE_MODEL_UNAVAILABLE (turns: the session's model is
|
|
37
|
+
* listed but unrunnable on its seat) and VERSE_MEMORY_REDACTED (memory: the
|
|
38
|
+
* content would write redaction placeholders over real values).
|
|
39
|
+
*
|
|
40
|
+
* STRICT BODIES AND QUERIES (V3.9 routes and POST /sessions): an unknown body
|
|
41
|
+
* key or query parameter is a 400, never silently ignored — a misspelt
|
|
42
|
+
* `contextMode` would otherwise create a session in a mode nobody asked for.
|
|
26
43
|
*
|
|
27
44
|
* ENGINE LIFETIME: one engine handle per server process — a module-level
|
|
28
45
|
* lazy singleton (`getVerseEngine()`), with `resetVerseEngine()` for tests to
|
|
29
46
|
* inject a fake or force re-creation under a relocated HOME. The engine
|
|
30
47
|
* module is loaded lazily (dynamic import) so this file has no load-time
|
|
31
|
-
* dependency on it; tests that inject a fake never touch it.
|
|
48
|
+
* dependency on it; tests that inject a fake never touch it. The V3.9 service
|
|
49
|
+
* modules keep that property: they report bad input with their own
|
|
50
|
+
* `VerseServiceError` (same `code` vocabulary, mapped by duck type below)
|
|
51
|
+
* rather than importing the engine's `VerseError`.
|
|
32
52
|
*
|
|
33
53
|
* PRIVACY: seat launchers (the native-profile commands) come from seats.ts's
|
|
34
54
|
* private `launches` map and go straight to engine.createSession(). They are
|
|
35
55
|
* never part of any response, log line, or session record this file writes.
|
|
56
|
+
* The same holds for the shared-memory snapshot (`VerseCreateOptions.memory`):
|
|
57
|
+
* its directory and prompt block go into the private launch record only.
|
|
36
58
|
*/
|
|
37
59
|
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
38
60
|
import type { AshlrConfig } from '../types.js';
|
|
39
61
|
import { expandHomePrefix } from './path-guard.js';
|
|
40
62
|
import { type VerseWorkspaceStore } from './workspaces.js';
|
|
41
63
|
import type { VerseEngineHandle } from './session-engine.js';
|
|
42
|
-
import { type VerseSession } from './types.js';
|
|
64
|
+
import { type VerseSession, VERSE_MEMORY_BODY_MAX_BYTES } from './types.js';
|
|
43
65
|
export declare const VERSE_API_PREFIX = "/api/verse";
|
|
44
66
|
export declare function isVerseApiPath(path: string): boolean;
|
|
45
67
|
export interface VerseApiContext {
|
|
@@ -92,6 +114,19 @@ export declare function verseSessionsSnapshot(): VerseSession[];
|
|
|
92
114
|
* caller and test already uses.
|
|
93
115
|
*/
|
|
94
116
|
export { expandHomePrefix };
|
|
117
|
+
/**
|
|
118
|
+
* The body cap for POST /api/verse/memory ONLY.
|
|
119
|
+
*
|
|
120
|
+
* The memory file may be VERSE_MEMORY_MAX_BYTES of content, and JSON escaping
|
|
121
|
+
* can roughly double that (every `"`, `\` and newline becomes two bytes; a
|
|
122
|
+
* control character becomes six, but a memory file is prose). Under the shared
|
|
123
|
+
* 65,536-byte cap a file anywhere near the documented limit could never be
|
|
124
|
+
* saved: 64 KiB of content made a 65,711-byte body. 2× plus 8 KiB for the
|
|
125
|
+
* envelope (`projectPath`, keys) admits any realistic file at the limit while
|
|
126
|
+
* staying a bounded, small read. The CONTENT itself is still held to
|
|
127
|
+
* VERSE_MEMORY_MAX_BYTES (413) after parsing.
|
|
128
|
+
*/
|
|
129
|
+
export { VERSE_MEMORY_BODY_MAX_BYTES };
|
|
95
130
|
/**
|
|
96
131
|
* Handle one /api/verse/* request. Returns true when a response was written
|
|
97
132
|
* (including error responses); false when `path` is not a verse route so
|