@bendyline/gezel-service 1.0.5 → 1.0.6
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/dist/bin/gezeld.js +16725 -6029
- package/dist/handboek-content/conceptual/connected-apps.md +64 -2
- package/dist/handboek-content/conceptual/night-shift.md +22 -2
- package/dist/handboek-content/conceptual/welcome.md +2 -0
- package/dist/handboek-content/technical/where-files-live.md +3 -1
- package/dist/handboek-content/whats-new/1.26226.md +3 -6
- package/dist/handboek-content/whats-new/1.26230.md +100 -0
- package/dist/handboek.js +19 -9
- package/dist/index-store/static-index-worker.js +116 -27
- package/dist/index.d.ts +1154 -252
- package/dist/index.js +16718 -6022
- package/dist/providers/mlx/python/gezel_mlx_server.py +126 -11
- package/dist/ui/assets/{TerminalCodeEditor-C_Mvaxqz.js → TerminalCodeEditor-BUHpk3pJ.js} +2 -2
- package/dist/ui/assets/{_.contribution-fOcpgyNy.js → _.contribution-B34uMeM2.js} +1 -1
- package/dist/ui/assets/{chunk-2JJ5RFDZ-Ckbzd10a.js → chunk-2JJ5RFDZ-B2-BFNXu.js} +1 -1
- package/dist/ui/assets/{chunk-BAOV476U-yPHu-ECL.js → chunk-BAOV476U-CEOFYt8X.js} +1 -1
- package/dist/ui/assets/{chunk-GAZKTT4R-BUf32614.js → chunk-GAZKTT4R-BkP6-w3z.js} +1 -1
- package/dist/ui/assets/{chunk-USU6HTKB-B-ElCUQS.js → chunk-USU6HTKB-htGRNErW.js} +1 -1
- package/dist/ui/assets/{cpp.contribution-Cx5HvoW7.js → cpp.contribution-CvG4GFxL.js} +1 -1
- package/dist/ui/assets/{csharp.contribution-DMuCSvzf.js → csharp.contribution-DekWAPj3.js} +1 -1
- package/dist/ui/assets/{css.contribution-BPXcRoVK.js → css.contribution-CDuF4Xjo.js} +1 -1
- package/dist/ui/assets/{cssMode-BHAnHChA.js → cssMode-D848zTHU.js} +1 -1
- package/dist/ui/assets/{csv-RAgECoUg.js → csv-PublMwG8.js} +1 -1
- package/dist/ui/assets/dist-CJRsJTdk.js +222 -0
- package/dist/ui/assets/dist-Cg3Ab49q.js +2 -0
- package/dist/ui/assets/{doc-B7NXSLxH.js → doc-Bq50ED-X.js} +41 -41
- package/dist/ui/assets/{dockerfile.contribution-DQAHazBI.js → dockerfile.contribution-ChT95Kbh.js} +1 -1
- package/dist/ui/assets/{docx-BEJpkI6I.js → docx-BSDeP5Eu.js} +1 -1
- package/dist/ui/assets/{epub-00L2M424.js → epub-D8zTSe9-.js} +1 -1
- package/dist/ui/assets/{go.contribution-Jq5pYI7r.js → go.contribution-D_1myt_B.js} +1 -1
- package/dist/ui/assets/{handlebars-BWC7ZXbe.js → handlebars-Mxcy9PWv.js} +1 -1
- package/dist/ui/assets/{handlebars.contribution-BSmxDPeT.js → handlebars.contribution-DYF5z0XX.js} +2 -2
- package/dist/ui/assets/{html-BzC9B_Os.js → html-HXzM-WGZ.js} +1 -1
- package/dist/ui/assets/{html-Cgejr9YM.js → html-X72kRvXT.js} +1 -1
- package/dist/ui/assets/{html.contribution-CEvtdKHG.js → html.contribution-C0xFTPDL.js} +2 -2
- package/dist/ui/assets/{htmlMode-1qtmM5J4.js → htmlMode-BVtBWJQM.js} +1 -1
- package/dist/ui/assets/{index-JGn32C5f.js → index-DUf4wIj5.js} +207 -200
- package/dist/ui/assets/index-udlcniNf.css +1 -0
- package/dist/ui/assets/{infer-D6e75m-s.js → infer-Be4Xn3O1.js} +1 -1
- package/dist/ui/assets/{ini.contribution-BQpzdQzE.js → ini.contribution-BqUQ8Oa0.js} +1 -1
- package/dist/ui/assets/{java.contribution-r3T-8LYE.js → java.contribution-u4QvI2UZ.js} +1 -1
- package/dist/ui/assets/{javascript-DlipM3VT.js → javascript-BVm8fvMk.js} +1 -1
- package/dist/ui/assets/javascript.contribution-BtlENuoy.js +2 -0
- package/dist/ui/assets/{jsonMode-DSXTaEG9.js → jsonMode-DcoSB4Jg.js} +1 -1
- package/dist/ui/assets/{kotlin.contribution-NI_YvQPr.js → kotlin.contribution-D1ZfW5lW.js} +1 -1
- package/dist/ui/assets/{less.contribution-BDz7g6GS.js → less.contribution-BBWek5Gc.js} +1 -1
- package/dist/ui/assets/{lua.contribution-Cr_f17YF.js → lua.contribution-DJEpMduq.js} +1 -1
- package/dist/ui/assets/mapTheme-4TWH25FT-C2uLgUhs.js +1 -0
- package/dist/ui/assets/{markdown.contribution-CeJFrLN_.js → markdown.contribution-CsVCTE0K.js} +1 -1
- package/dist/ui/assets/{monaco-Bv9TxWl_.js → monaco-DcZAEsIZ.js} +3 -3
- package/dist/ui/assets/{monaco-base-DD1Wr24S.js → monaco-base-C-UMfHa9.js} +1 -1
- package/dist/ui/assets/{monaco-setup-CSa3_fbr.js → monaco-setup-Dy_kv6Gv.js} +1 -1
- package/dist/ui/assets/{monaco.contribution-tTvEzZ5l.js → monaco.contribution-BpJqoa65.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-QFH9z5g8.js → monaco.contribution-BujOhotZ.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-ZD-wInG3.js → monaco.contribution-DW4-UIJp.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-DKCJArGP.js → monaco.contribution-ypbCAEx4.js} +2 -2
- package/dist/ui/assets/{pdf-66KslaXf.js → pdf-BZeBurJI.js} +1 -1
- package/dist/ui/assets/{php.contribution-B310cs3S.js → php.contribution-B6Atm_xI.js} +1 -1
- package/dist/ui/assets/{pptx-DZdEoDP9.js → pptx-BbAcnlML.js} +4 -4
- package/dist/ui/assets/{python-CcCNDnkj.js → python-CCiWacbd.js} +1 -1
- package/dist/ui/assets/{python.contribution-ZHL594qQ.js → python.contribution-3CThbaoI.js} +2 -2
- package/dist/ui/assets/{ruby.contribution-CRsX2xPw.js → ruby.contribution-D3g6EADN.js} +1 -1
- package/dist/ui/assets/{rust.contribution-CfwWiQxD.js → rust.contribution-CSdjIX0R.js} +1 -1
- package/dist/ui/assets/{schemas-Drh23Boe.js → schemas-JY4jmLbC.js} +1 -1
- package/dist/ui/assets/{scss.contribution-CJaLNKeq.js → scss.contribution-mQ_vuYxE.js} +1 -1
- package/dist/ui/assets/{shell.contribution-DLPinQHD.js → shell.contribution-BLQSLx3H.js} +1 -1
- package/dist/ui/assets/{sql.contribution-DsZSLfVg.js → sql.contribution-GScL7Mrt.js} +1 -1
- package/dist/ui/assets/{swift.contribution-DFBOOFKs.js → swift.contribution-DG__yqNr.js} +1 -1
- package/dist/ui/assets/{terminal-monaco-setup-B8Xv2NV9.js → terminal-monaco-setup-x6piH1Un.js} +1 -1
- package/dist/ui/assets/{transform-MBfVXq54.js → transform-ywncQECB.js} +1 -1
- package/dist/ui/assets/{tsMode-DqT2Dz4k.js → tsMode-B5nM5MR7.js} +1 -1
- package/dist/ui/assets/{typescript-_R5MS0Lp.js → typescript-xiOVha1M.js} +1 -1
- package/dist/ui/assets/{typescript.contribution-CHnXQvfG.js → typescript.contribution-BU2V4Vz8.js} +2 -2
- package/dist/ui/assets/worker-BzdDEeh7.js +1 -0
- package/dist/ui/assets/{xlsx-DDBRN-IU.js → xlsx-f9AYHB2W.js} +1 -1
- package/dist/ui/assets/{xml-CQVIKNxb.js → xml-m3MSnvuD.js} +1 -1
- package/dist/ui/assets/{xml.contribution-HY4GvlWC.js → xml.contribution-bOoaS55N.js} +2 -2
- package/dist/ui/assets/{yaml-Nt3uLkWC.js → yaml-DOtMVgbb.js} +1 -1
- package/dist/ui/assets/{yaml.contribution-C7dllTyY.js → yaml.contribution-CNCYEtwk.js} +2 -2
- package/dist/ui/index.html +14 -14
- package/package.json +10 -10
- package/dist/ui/assets/dist-DRDFuw7G.js +0 -222
- package/dist/ui/assets/dist-DYn91eSO.js +0 -2
- package/dist/ui/assets/index-DTicLc4o.css +0 -1
- package/dist/ui/assets/javascript.contribution-D4MU3K0o.js +0 -2
- package/dist/ui/assets/mapTheme-4TWH25FT-B5nAKRmb.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _bendyline_gezel from '@bendyline/gezel';
|
|
2
|
-
import { HistoryEvent, HistoryFilter, HistoryEntry, GezelGender, Poppetje,
|
|
2
|
+
import { ChatSessionSource, ChatEvent, ChatEventEnvelope, HistoryEvent, HistoryFilter, HistoryEntry, ProjectFileEntry, GezelGender, Poppetje, GezelDetail, GezelConfig, GezelSummary, ProviderName, ChatModelTuning, GezelTrait, ProjectLocalConfig, ImportProvenance, PendingImports, GezelFrontmatter, Project, ProjectIconId, ProjectDetail, FileReviewIssue, BoekwachterIssueStatus, BoekwachterIssueDismissalReason, ProjectManagedWorkspaceWritePolicy, ProjectNudgeConfig, ProjectTabVisibility, ProjectActivity, MeesterStatusReport, MeesterStatusState, ProjectGitHub, ChatSession, ChatSessionSummary, TimelineMessage, TerminalTimelineEntry, TerminalThread, TerminalThreadSummary, TerminalMessage, GezelGrowthState, Task, Question, TaskNote, ToolsetsScope, InstalledToolset, ToolsetConfig, CraftbookSummary, Craftbook, ProjectCraftbookProvenance, AmbientDashboardResolution, AmbientDashboardTheme, AmbientDashboardDisplayTarget, AmbientDashboardStyle, AmbientDashboardState, ChannelStatus, ChannelName, HookSpec, HookPhase, HookResult, ModelTier, ModelStyle, BehaviorId, ModelFamily, ChatMessageToolCall, SamplingBlock, CodexPermissionModeCompat, ModelFitnessTrigger, ModelFitnessRecord, OutlineFileResponse, FileContextResponse, FindSymbolResponse, ReadSymbolResponse, MapRepoResponse, SecurityScanResponse, ScanFindingsRequest, ScanFindingsResponse, SecurityFindingWire, MapAttackSurfaceResponse, ListDependenciesResponse, SecurityOverviewResponse, TraceTaintResponse, FileMapRequest, FileMapResponse, SearchCodeResponse, FileReviewResponse, ListFileIssuesRequest, ListFileIssuesResponse, BoekwachterIssue, SearchDocsResponse, SearchDocumentsResponse, ReadDocAsMarkdownResponse, SearchImagesResponse, FindSimilarImagesResponse, DescribeFolderResponse, FindEntityResponse, ListEntityMentionsResponse, KeurmeesterCaseRecord, TaskStatus, KeurmeesterTriggerKind, KeurmeesterAction, KeurmeesterCaseOutcome, GateCheck, TaskCraftbookStep, TaskCraftbookSource, CraftbookConnectorNeed, CreateTaskRequest, UpdateTaskRequest, TaskAssignee, NewCraftbookStep, StepPosition, UpdateTaskStepRequest, TaskNoteAuthor, TaskVariation, ScriptCapability, ScriptScope, ScriptRunTrigger, ScriptRun, NativeEngineResolveEvent, NativeEngineName, ImageRecognition, RecognitionMode, RecognitionHealth, PreviewLogEntry, SessionGpuTask, SessionTelemetry, AIEngagementMode, ChatMessage, SessionDebugSnapshot, ExpectedDeliverable, CodexSetupStatusResponse, ConfigureCodexRequest, ProjectConnectorBinding, GildeUpdateStatusResponse, GitWorkingChange, GitFileDiffResponse, CodeReviewKind, GitLogEntry, GitCommitDetailResponse, GitSyncResponse, GitConflictFile, GitConflictVersionsResponse, WorkspaceIndexStatus, WorkspaceCommandIndex, WorkspaceSkillIndex, WorkspaceInstructionIndex, CodeReviewRecord, CodeReview, GitHubPullSummary, GitHubPullDetail, GitHubPullFile, GitHubPullComment, OpenCodeSetupStatusResponse, ConfigureOpenCodeRequest, InstallOpenCodePluginRequest, PiSetupStatusResponse, ConfigurePiRequest, InstallPiExtensionRequest, ImageModelPullEvent as ImageModelPullEvent$1, VideoAccelerator, RenderImageRequest, ReportActionsResponse, FireReportActionResponse, ReportActionRecord, UnifiedSearchResult, StorageJobKind, StorageJob, StorageJobPhase, SystemToolsetInstallEvent, SystemToolsetInstallSnapshot, NightShiftWindow, TerminalEventEnvelope, DiscoveredCommand, VSCodeSetupStatusResponse, ConfigureVSCodeRequest, ServiceRole, ScriptMeta } from '@bendyline/gezel';
|
|
3
3
|
import { ServerType } from '@hono/node-server';
|
|
4
4
|
import { CatalogService } from '@bendyline/gezel-catalog';
|
|
5
5
|
import { ExternalFolders } from '@bendyline/gezel/paths';
|
|
@@ -38,21 +38,97 @@ interface LoopbackCert {
|
|
|
38
38
|
fingerprintBase64: string;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
type SessionListener = (event: ChatEvent) => void;
|
|
42
|
+
type EnvelopeListener = (envelope: ChatEventEnvelope) => void;
|
|
43
|
+
interface PublishScope {
|
|
44
|
+
sessionId: string;
|
|
45
|
+
gezelId: string;
|
|
46
|
+
projectId: string;
|
|
47
|
+
sessionSource?: ChatSessionSource;
|
|
48
|
+
}
|
|
41
49
|
/**
|
|
42
|
-
*
|
|
50
|
+
* Per-session chat event bus, plus project-scoped and global fan-out for the
|
|
51
|
+
* interleaved timeline UI. Each `publish` reaches three subscriber sets:
|
|
43
52
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
53
|
+
* 1. Listeners on this session — bare `ChatEvent`. Get the recent history
|
|
54
|
+
* replayed when they subscribe (so a late session-scoped subscriber can
|
|
55
|
+
* catch up on the in-flight message). Cleared on `done`.
|
|
56
|
+
* 2. Listeners on this project — `ChatEventEnvelope` with sessionId/
|
|
57
|
+
* gezelId/projectId. Also get the history replayed for any in-flight
|
|
58
|
+
* sessions in this project, so a user who tabs away mid-stream and back
|
|
59
|
+
* doesn't lose the partial text + tools accumulated during the gap.
|
|
60
|
+
* 3. Global listeners — `ChatEventEnvelope`. Same replay semantics across
|
|
61
|
+
* every in-flight session anywhere.
|
|
62
|
+
*
|
|
63
|
+
* History is bus-side only: cleared on `done` so completed turns don't get
|
|
64
|
+
* re-delivered when a new subscriber connects after the fact.
|
|
65
|
+
*
|
|
66
|
+
* If a send truly cannot resolve its session record, it does not know the
|
|
67
|
+
* gezelId/projectId and publishes session-scoped via `publishSessionOnly`.
|
|
68
|
+
* Once a record is known, even provider-start failures use `publish` so
|
|
69
|
+
* project/global clients receive the error.
|
|
50
70
|
*/
|
|
51
|
-
declare class
|
|
52
|
-
private
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
declare class ChatEventBus {
|
|
72
|
+
private readonly sessionBuses;
|
|
73
|
+
private readonly projectListeners;
|
|
74
|
+
private readonly gezelListeners;
|
|
75
|
+
private readonly globalListeners;
|
|
76
|
+
publish(scope: PublishScope, event: ChatEvent): void;
|
|
77
|
+
/**
|
|
78
|
+
* Publish to the session bus only. Used when the manager's early-fail path
|
|
79
|
+
* doesn't know the gezel/project to envelope (the session record itself
|
|
80
|
+
* couldn't be loaded). Project + global subscribers never see these.
|
|
81
|
+
*/
|
|
82
|
+
publishSessionOnly(sessionId: string, event: ChatEvent): void;
|
|
83
|
+
/**
|
|
84
|
+
* Publish a project-scoped lifecycle event that has no originating
|
|
85
|
+
* turn — e.g. `project_created`. Fans out to the project's listeners
|
|
86
|
+
* and all global listeners, but is deliberately NOT recorded in any
|
|
87
|
+
* session history: these are one-shot signals, not part of a
|
|
88
|
+
* replayable transcript, so a subscriber that reconnects later must
|
|
89
|
+
* not see them re-fired (unlike `publish`, which seeds `deliverToSession`
|
|
90
|
+
* history that replays until the turn's `done`). `sessionId`/`gezelId`
|
|
91
|
+
* are empty — the consumers that care (the sidebar refresh bridge)
|
|
92
|
+
* key off the event payload, not the envelope scope.
|
|
93
|
+
*/
|
|
94
|
+
publishProjectEvent(projectId: string, event: ChatEvent): void;
|
|
95
|
+
/**
|
|
96
|
+
* Publish a project-less global lifecycle event — e.g. `night_shift`.
|
|
97
|
+
* Reaches only the global listeners (the Meester timeline SSE the UI
|
|
98
|
+
* subscribes to via `subscribeAll`); like `publishProjectEvent` it is
|
|
99
|
+
* not recorded in any session history, so reconnecting subscribers do
|
|
100
|
+
* not see it re-fired. The envelope scope fields are all empty;
|
|
101
|
+
* consumers key off the event payload.
|
|
102
|
+
*/
|
|
103
|
+
publishGlobalEvent(event: ChatEvent): void;
|
|
104
|
+
subscribe(sessionId: string, listener: SessionListener): () => void;
|
|
105
|
+
subscribeProject(projectId: string, listener: EnvelopeListener): () => void;
|
|
106
|
+
subscribeGezel(gezelId: string, listener: EnvelopeListener): () => void;
|
|
107
|
+
subscribeAll(listener: EnvelopeListener): () => void;
|
|
108
|
+
private deliverToSession;
|
|
109
|
+
/**
|
|
110
|
+
* Append an event to a session's replay history, keeping the buffer
|
|
111
|
+
* lossless for the content that matters. Two rules:
|
|
112
|
+
*
|
|
113
|
+
* 1. Transient status pulses (`heartbeat`, `wire_pulse`) are delivered
|
|
114
|
+
* live but never recorded — they carry no replayable content, and a
|
|
115
|
+
* reasoning-heavy local-model turn emits enough of them to evict
|
|
116
|
+
* real deltas out of the 500-event cap.
|
|
117
|
+
* 2. Adjacent `delta` events coalesce into one entry. A five-minute
|
|
118
|
+
* thinking turn streams thousands of per-token deltas; stored
|
|
119
|
+
* individually they blow past the cap and the earliest thinking is
|
|
120
|
+
* silently dropped on replay. Merged, a text run costs one slot no
|
|
121
|
+
* matter how long it streamed. The stored entry is a fresh object —
|
|
122
|
+
* the original event was already handed to live listeners and must
|
|
123
|
+
* not be mutated.
|
|
124
|
+
*/
|
|
125
|
+
private recordInHistory;
|
|
126
|
+
private ensureSession;
|
|
127
|
+
private cleanupSession;
|
|
128
|
+
private pruneIdleSessions;
|
|
129
|
+
private safeDeliver;
|
|
130
|
+
/** Lightweight observability hook used by tests and diagnostics. */
|
|
131
|
+
activeSessionCount(): number;
|
|
56
132
|
}
|
|
57
133
|
|
|
58
134
|
/**
|
|
@@ -123,6 +199,18 @@ declare class HistoryManager {
|
|
|
123
199
|
private sessionMatchesQuery;
|
|
124
200
|
}
|
|
125
201
|
|
|
202
|
+
interface WalkDirResult {
|
|
203
|
+
entries: ProjectFileEntry[];
|
|
204
|
+
/** True when `maxEntries` or `maxDepth` dropped part of the tree. */
|
|
205
|
+
truncated: boolean;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Who is writing. Absent means the person, editing in the app. */
|
|
209
|
+
interface DocumentWriteActor {
|
|
210
|
+
gezelId?: string;
|
|
211
|
+
sessionId?: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
126
214
|
/**
|
|
127
215
|
* Shared format + parser for the daily memory markdown files
|
|
128
216
|
* (`memories/daily/YYYY-MM-DD.md`). These files are the memory system's
|
|
@@ -224,12 +312,6 @@ interface JournalContext {
|
|
|
224
312
|
sessionId?: string;
|
|
225
313
|
}
|
|
226
314
|
|
|
227
|
-
interface WalkDirResult {
|
|
228
|
-
entries: ProjectFileEntry[];
|
|
229
|
-
/** True when `maxEntries` or `maxDepth` dropped part of the tree. */
|
|
230
|
-
truncated: boolean;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
315
|
type ProjectArtifactResolveResult = {
|
|
234
316
|
kind: 'found';
|
|
235
317
|
content: string;
|
|
@@ -327,6 +409,11 @@ interface StoreOptions {
|
|
|
327
409
|
* history can construct a bare Store.
|
|
328
410
|
*/
|
|
329
411
|
history?: HistoryManager;
|
|
412
|
+
/**
|
|
413
|
+
* Test seam: shorten the document-edit audit's quiet window so a test can
|
|
414
|
+
* observe a sitting close without waiting minutes.
|
|
415
|
+
*/
|
|
416
|
+
auditQuietWindowMs?: number;
|
|
330
417
|
/**
|
|
331
418
|
* Per-scope external roots, captured at boot from
|
|
332
419
|
* `config.json#externalFolders`. When set, the Store routes reads/
|
|
@@ -365,7 +452,8 @@ interface SessionChangeEvent {
|
|
|
365
452
|
sessionId: string;
|
|
366
453
|
}
|
|
367
454
|
interface DocumentChangeEvent {
|
|
368
|
-
|
|
455
|
+
/** `mkdir` carries no content — listeners that index files skip it. */
|
|
456
|
+
type: 'write' | 'delete' | 'mkdir';
|
|
369
457
|
path: string;
|
|
370
458
|
}
|
|
371
459
|
interface GezelChangeEvent {
|
|
@@ -396,8 +484,8 @@ declare class Store {
|
|
|
396
484
|
* enqueue-only and never throw work back into the write path.
|
|
397
485
|
*/
|
|
398
486
|
private readonly sessionListeners;
|
|
399
|
-
/** Notified on every document write/delete, including overwrites
|
|
400
|
-
*
|
|
487
|
+
/** Notified on every document write/delete, including overwrites. Same
|
|
488
|
+
* enqueue-only contract as session listeners. */
|
|
401
489
|
private readonly documentListeners;
|
|
402
490
|
/** Notified after a shared gezel has been fully created and is listable.
|
|
403
491
|
* Project-local gezels use a separate Store path and intentionally do not
|
|
@@ -535,6 +623,37 @@ declare class Store {
|
|
|
535
623
|
*/
|
|
536
624
|
private migrateLegacyTemperatureField;
|
|
537
625
|
ensureDefaultProject(): Promise<void>;
|
|
626
|
+
/**
|
|
627
|
+
* Ensure the canonical `shared` project exists and points at the resolved
|
|
628
|
+
* documents root. Its workspace IS the shared document library, so every
|
|
629
|
+
* per-project service (content index, shadow conversion, enrichment,
|
|
630
|
+
* watcher, search) reaches the library without a parallel pipeline.
|
|
631
|
+
*
|
|
632
|
+
* The library folder is user-owned and possibly cloud-synced, so nothing
|
|
633
|
+
* here writes into it beyond the one starter document on a first run.
|
|
634
|
+
*
|
|
635
|
+
* Returns whether it created the project, so boot can do the one-shot
|
|
636
|
+
* roster wiring (Boekwachter) exactly once.
|
|
637
|
+
*/
|
|
638
|
+
ensureSharedProject(): Promise<{
|
|
639
|
+
id: string;
|
|
640
|
+
created: boolean;
|
|
641
|
+
}>;
|
|
642
|
+
/**
|
|
643
|
+
* Id of the shared library project, or null when it does not exist yet
|
|
644
|
+
* (machine-engine role, or a boot that has not reached the ensure).
|
|
645
|
+
* Callers that need the library's index — document search, recall — go
|
|
646
|
+
* through this rather than assuming the default id.
|
|
647
|
+
*/
|
|
648
|
+
sharedProjectId(): Promise<string | null>;
|
|
649
|
+
private createSharedProject;
|
|
650
|
+
/**
|
|
651
|
+
* One starter document, and only when the library is empty — an explanation
|
|
652
|
+
* a first-run user can read and edit, not a file we re-create after they
|
|
653
|
+
* delete it.
|
|
654
|
+
*/
|
|
655
|
+
private seedSharedLibraryStarterDoc;
|
|
656
|
+
private backfillSharedProjectDocs;
|
|
538
657
|
/**
|
|
539
658
|
* Seed the curated catch-all docs on installs whose `default` project
|
|
540
659
|
* predates them. Only writes a doc that is genuinely absent — an existing
|
|
@@ -545,9 +664,18 @@ declare class Store {
|
|
|
545
664
|
/**
|
|
546
665
|
* Ensure `config.meesterGezelId` points at a valid gezel. Order of preference:
|
|
547
666
|
* 1. Existing pointer → a live gezel: no-op.
|
|
548
|
-
* 2.
|
|
549
|
-
* 3.
|
|
667
|
+
* 2. A gezel whose role is already Meester: designate it.
|
|
668
|
+
* 3. Any other gezels exist: auto-pick the first alphabetically.
|
|
669
|
+
* 4. No gezels at all: create a fresh Meester with a random name and the
|
|
550
670
|
* curated about.md from packages/service/src/meester/prompt.ts.
|
|
671
|
+
*
|
|
672
|
+
* Step 2 exists because the roster is sorted by name, so taking the first
|
|
673
|
+
* entry crowned whoever sorted earliest — a Klerk named Ilse ahead of a real
|
|
674
|
+
* Meester named Ulrike. The badge is only half the job: a Meester's power is
|
|
675
|
+
* its curated about.md teaching the team-management tools, which a Klerk
|
|
676
|
+
* does not have, so the front door silently lost its abilities. Reachable
|
|
677
|
+
* whenever the pointer goes stale (a deleted gezel, a restored backup) and
|
|
678
|
+
* on any install that mounts a machine-shared roster.
|
|
551
679
|
*/
|
|
552
680
|
ensureDefaultMeester(): Promise<void>;
|
|
553
681
|
/**
|
|
@@ -835,6 +963,8 @@ declare class Store {
|
|
|
835
963
|
createProject(input: {
|
|
836
964
|
name: string;
|
|
837
965
|
description?: string;
|
|
966
|
+
/** Explicit maker's-mark override; missing inherits from the project type. */
|
|
967
|
+
icon?: ProjectIconId;
|
|
838
968
|
/** Written to documents/about.md at creation. */
|
|
839
969
|
about?: string;
|
|
840
970
|
/** Written to documents/missionObjectives.md at creation. */
|
|
@@ -916,6 +1046,8 @@ declare class Store {
|
|
|
916
1046
|
updateProject(id: string, patch: {
|
|
917
1047
|
name?: string;
|
|
918
1048
|
description?: string;
|
|
1049
|
+
/** Explicit maker's-mark override; null resumes type inheritance. */
|
|
1050
|
+
icon?: ProjectIconId | null;
|
|
919
1051
|
workingDir?: string | null;
|
|
920
1052
|
voormanGezelId?: string | null;
|
|
921
1053
|
voormanAutoAssignedAt?: string;
|
|
@@ -1071,14 +1203,21 @@ declare class Store {
|
|
|
1071
1203
|
writeProjectDoc(id: string, name: string, content: string): Promise<void>;
|
|
1072
1204
|
private tryGetProjectMeta;
|
|
1073
1205
|
projectArtifactsDir(id: string): string;
|
|
1074
|
-
listProjectArtifacts(id: string, subpath?: string
|
|
1206
|
+
listProjectArtifacts(id: string, subpath?: string, opts?: {
|
|
1207
|
+
includeHidden?: boolean;
|
|
1208
|
+
}): Promise<ProjectFileEntry[]>;
|
|
1075
1209
|
listProjectArtifactsRecursive(id: string, opts?: {
|
|
1076
1210
|
withStats?: boolean;
|
|
1211
|
+
includeHidden?: boolean;
|
|
1212
|
+
subpath?: string;
|
|
1077
1213
|
}): Promise<ProjectFileEntry[]>;
|
|
1078
1214
|
listProjectArtifactsRecursiveDetailed(id: string, opts?: {
|
|
1079
1215
|
withStats?: boolean;
|
|
1216
|
+
includeHidden?: boolean;
|
|
1217
|
+
subpath?: string;
|
|
1080
1218
|
}): Promise<WalkDirResult>;
|
|
1081
1219
|
readProjectArtifact(id: string, filePath: string): Promise<string | null>;
|
|
1220
|
+
projectArtifactSize(id: string, filePath: string): Promise<number | null>;
|
|
1082
1221
|
/**
|
|
1083
1222
|
* Read an artifact as raw bytes plus a MIME type guess (from the file
|
|
1084
1223
|
* extension). Used by binary consumers — e.g. the image-layer resolver
|
|
@@ -1166,6 +1305,11 @@ declare class Store {
|
|
|
1166
1305
|
createOnly?: boolean;
|
|
1167
1306
|
}): Promise<string>;
|
|
1168
1307
|
deleteProjectArtifact(id: string, filePath: string): Promise<void>;
|
|
1308
|
+
createProjectArtifactFolder(id: string, folderPath: string): Promise<string>;
|
|
1309
|
+
renameProjectArtifactPath(id: string, fromPath: string, toPath: string): Promise<{
|
|
1310
|
+
fromPath: string;
|
|
1311
|
+
toPath: string;
|
|
1312
|
+
}>;
|
|
1169
1313
|
private sessionImagesDir;
|
|
1170
1314
|
/** Relative path used inside chat-message markdown, e.g. "images/abc.png". */
|
|
1171
1315
|
private sessionImageRelPath;
|
|
@@ -1224,11 +1368,28 @@ declare class Store {
|
|
|
1224
1368
|
*/
|
|
1225
1369
|
private resolveWorkspaceDir;
|
|
1226
1370
|
projectWorkspaceDir(id: string): Promise<string>;
|
|
1227
|
-
listProjectWorkspace(id: string, subpath?: string
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1371
|
+
listProjectWorkspace(id: string, subpath?: string, opts?: {
|
|
1372
|
+
includeHidden?: boolean;
|
|
1373
|
+
}): Promise<ProjectFileEntry[]>;
|
|
1374
|
+
listProjectWorkspaceRecursive(id: string, opts?: {
|
|
1375
|
+
withStats?: boolean;
|
|
1376
|
+
includeHidden?: boolean;
|
|
1377
|
+
subpath?: string;
|
|
1378
|
+
}): Promise<ProjectFileEntry[]>;
|
|
1379
|
+
/**
|
|
1380
|
+
* Recursive listing plus the truncation flag, for surfaces that must tell
|
|
1381
|
+
* the user/model when the walker's entry cap dropped files.
|
|
1382
|
+
*
|
|
1383
|
+
* `subpath` roots the walk instead of post-filtering it, so a caller asking
|
|
1384
|
+
* for one folder is not competing with the whole workspace for the entry
|
|
1385
|
+
* budget — the same contract as the artifacts twin. Entry paths stay
|
|
1386
|
+
* workspace-root-relative, so results remain directly readable.
|
|
1387
|
+
*/
|
|
1388
|
+
listProjectWorkspaceRecursiveDetailed(id: string, opts?: {
|
|
1389
|
+
withStats?: boolean;
|
|
1390
|
+
includeHidden?: boolean;
|
|
1391
|
+
subpath?: string;
|
|
1392
|
+
}): Promise<WalkDirResult>;
|
|
1232
1393
|
listProjectWorkspaceHtmlPages(id: string): Promise<ProjectFileEntry[]>;
|
|
1233
1394
|
readProjectWorkspaceFile(id: string, filePath: string): Promise<string | null>;
|
|
1234
1395
|
/**
|
|
@@ -1397,7 +1558,18 @@ declare class Store {
|
|
|
1397
1558
|
documentsDir(): string;
|
|
1398
1559
|
listDocuments(subpath?: string): Promise<ProjectFileEntry[]>;
|
|
1399
1560
|
listDocumentsRecursive(): Promise<ProjectFileEntry[]>;
|
|
1561
|
+
/** Close any in-flight document-edit audit windows (service shutdown). */
|
|
1562
|
+
flushDocumentAudit(): Promise<void>;
|
|
1563
|
+
readDocumentAsMarkdown(filePath: string): Promise<{
|
|
1564
|
+
content: string;
|
|
1565
|
+
converted: boolean;
|
|
1566
|
+
} | null>;
|
|
1567
|
+
listDocumentsRecursiveDetailed(opts?: {
|
|
1568
|
+
withStats?: boolean;
|
|
1569
|
+
includeHidden?: boolean;
|
|
1570
|
+
}): Promise<WalkDirResult>;
|
|
1400
1571
|
readDocument(filePath: string): Promise<string | null>;
|
|
1572
|
+
documentSize(filePath: string): Promise<number | null>;
|
|
1401
1573
|
/**
|
|
1402
1574
|
* Read a shared-library document sidecar as raw bytes. Native document
|
|
1403
1575
|
* media export uses this for images, narration, and embedded clips while
|
|
@@ -1407,7 +1579,7 @@ declare class Store {
|
|
|
1407
1579
|
data: Buffer;
|
|
1408
1580
|
mimeType: string;
|
|
1409
1581
|
} | null>;
|
|
1410
|
-
writeDocument(filePath: string, content: string): Promise<void>;
|
|
1582
|
+
writeDocument(filePath: string, content: string, actor?: DocumentWriteActor): Promise<void>;
|
|
1411
1583
|
/**
|
|
1412
1584
|
* Binary sibling of `writeDocument` — same dir, same path-traversal
|
|
1413
1585
|
* guard, but writes raw bytes. Powers the squisq editor's Files panel
|
|
@@ -1415,7 +1587,7 @@ declare class Store {
|
|
|
1415
1587
|
* document.
|
|
1416
1588
|
*/
|
|
1417
1589
|
writeDocumentBinary(filePath: string, data: Uint8Array): Promise<void>;
|
|
1418
|
-
deleteDocument(filePath: string): Promise<void>;
|
|
1590
|
+
deleteDocument(filePath: string, actor?: DocumentWriteActor): Promise<void>;
|
|
1419
1591
|
createDocumentFolder(folderPath: string): Promise<void>;
|
|
1420
1592
|
renameDocument(fromPath: string, toPath: string): Promise<void>;
|
|
1421
1593
|
writeSession(session: ChatSession): Promise<void>;
|
|
@@ -1477,6 +1649,13 @@ declare class Store {
|
|
|
1477
1649
|
limit: number;
|
|
1478
1650
|
before?: string;
|
|
1479
1651
|
includeArchived?: boolean;
|
|
1652
|
+
/**
|
|
1653
|
+
* Indexed workspace paths for a project, used to recognize workspace
|
|
1654
|
+
* files an assistant reply named in prose. Supplied by the caller
|
|
1655
|
+
* because the listing's owner (`WorkspaceIndexManager`) is built on top
|
|
1656
|
+
* of this Store. Omit it and the backfill sees artifacts only.
|
|
1657
|
+
*/
|
|
1658
|
+
workspaceFiles?: (projectId: string) => Promise<readonly string[]>;
|
|
1480
1659
|
}): Promise<{
|
|
1481
1660
|
messages: TimelineMessage[];
|
|
1482
1661
|
hasMore: boolean;
|
|
@@ -1695,6 +1874,156 @@ declare class Store {
|
|
|
1695
1874
|
writeProjectCraftbookProvenance(projectId: string, id: string, prov: ProjectCraftbookProvenance): Promise<void>;
|
|
1696
1875
|
}
|
|
1697
1876
|
|
|
1877
|
+
interface ActivityTrackerOptions {
|
|
1878
|
+
store: Store;
|
|
1879
|
+
history: HistoryManager;
|
|
1880
|
+
chatEvents: ChatEventBus;
|
|
1881
|
+
now?: () => number;
|
|
1882
|
+
persistThresholdMs?: number;
|
|
1883
|
+
}
|
|
1884
|
+
declare class ActivityTracker {
|
|
1885
|
+
private readonly store;
|
|
1886
|
+
private readonly history;
|
|
1887
|
+
private readonly chatEvents;
|
|
1888
|
+
private readonly now;
|
|
1889
|
+
private readonly persistThresholdMs;
|
|
1890
|
+
/** Newest observed stamp per project (ms epoch). */
|
|
1891
|
+
private readonly latest;
|
|
1892
|
+
/** Stamp last written to (or read from) disk per project. */
|
|
1893
|
+
private readonly persisted;
|
|
1894
|
+
/** Projects whose on-disk stamp has been loaded into `persisted`. */
|
|
1895
|
+
private readonly loads;
|
|
1896
|
+
private readonly writing;
|
|
1897
|
+
private unsubs;
|
|
1898
|
+
constructor(opts: ActivityTrackerOptions);
|
|
1899
|
+
start(): void;
|
|
1900
|
+
stop(): Promise<void>;
|
|
1901
|
+
stamp(projectId: string, atMs: number): void;
|
|
1902
|
+
/**
|
|
1903
|
+
* Newest known activity for a project — max of the in-memory stamp
|
|
1904
|
+
* and the on-disk one (loaded once). Null when the project has never
|
|
1905
|
+
* been observed.
|
|
1906
|
+
*/
|
|
1907
|
+
lastActivityAt(projectId: string): Promise<string | null>;
|
|
1908
|
+
/** Persist every stamp that is newer than its on-disk value. */
|
|
1909
|
+
flush(): Promise<void>;
|
|
1910
|
+
private maybePersist;
|
|
1911
|
+
private write;
|
|
1912
|
+
private ensureLoaded;
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
/**
|
|
1916
|
+
* Render an LLM-authored squisq dashboard document to a PNG via
|
|
1917
|
+
* squisq-cli's canonical dashboard renderer, on the service's managed
|
|
1918
|
+
* Chromium. The doc is pure markdown from the meester — no media — so
|
|
1919
|
+
* the content container is an empty read-only stub.
|
|
1920
|
+
*/
|
|
1921
|
+
interface RenderAmbientDashboardOptions {
|
|
1922
|
+
home: string;
|
|
1923
|
+
markdown: string;
|
|
1924
|
+
outputPath: string;
|
|
1925
|
+
resolution: AmbientDashboardResolution;
|
|
1926
|
+
/** User-selected Squisq theme; overrides any model-authored frontmatter. */
|
|
1927
|
+
themeId: AmbientDashboardTheme;
|
|
1928
|
+
/** Full primary-display canvas plus its OS-chrome-safe content rectangle. */
|
|
1929
|
+
displayTarget?: AmbientDashboardDisplayTarget;
|
|
1930
|
+
style: AmbientDashboardStyle;
|
|
1931
|
+
/** Title-band fallback when the doc's frontmatter has none. */
|
|
1932
|
+
documentTitle: string;
|
|
1933
|
+
signal?: AbortSignal;
|
|
1934
|
+
}
|
|
1935
|
+
interface RenderAmbientDashboardResult {
|
|
1936
|
+
outputPath: string;
|
|
1937
|
+
width: number;
|
|
1938
|
+
height: number;
|
|
1939
|
+
/** Top-level block count of the parsed doc — the cell count. */
|
|
1940
|
+
blocks: number;
|
|
1941
|
+
}
|
|
1942
|
+
type AmbientDashboardRenderer = (opts: RenderAmbientDashboardOptions) => Promise<RenderAmbientDashboardResult>;
|
|
1943
|
+
|
|
1944
|
+
type DashboardOneShot = (prompt: string, timeoutMs: number, opts: {
|
|
1945
|
+
gezelId: string;
|
|
1946
|
+
jobLabel: string;
|
|
1947
|
+
tuningProfileId: 'instruct';
|
|
1948
|
+
lane: 'interactive' | 'background';
|
|
1949
|
+
ambient: boolean;
|
|
1950
|
+
}) => Promise<string>;
|
|
1951
|
+
interface AmbientDashboardGeneratorOptions {
|
|
1952
|
+
home: string;
|
|
1953
|
+
store: Store;
|
|
1954
|
+
history: HistoryManager;
|
|
1955
|
+
activity: ActivityTracker;
|
|
1956
|
+
oneShot: DashboardOneShot;
|
|
1957
|
+
renderer?: AmbientDashboardRenderer;
|
|
1958
|
+
/** Night shift counts as "scheduled work allowed". */
|
|
1959
|
+
isNightShiftActive?: () => boolean;
|
|
1960
|
+
isChatActive?: () => boolean;
|
|
1961
|
+
events?: Pick<ChatEventBus, 'publishGlobalEvent'>;
|
|
1962
|
+
intervalMs?: number;
|
|
1963
|
+
startupDelayMs?: number;
|
|
1964
|
+
now?: () => Date;
|
|
1965
|
+
}
|
|
1966
|
+
declare class AmbientDashboardGenerator {
|
|
1967
|
+
private readonly home;
|
|
1968
|
+
private readonly store;
|
|
1969
|
+
private readonly history;
|
|
1970
|
+
private readonly activity;
|
|
1971
|
+
private readonly oneShot;
|
|
1972
|
+
private readonly renderer;
|
|
1973
|
+
private readonly isNightShiftActive;
|
|
1974
|
+
private readonly isChatActive;
|
|
1975
|
+
private readonly events?;
|
|
1976
|
+
private readonly intervalMs;
|
|
1977
|
+
private readonly startupDelayMs;
|
|
1978
|
+
private readonly now;
|
|
1979
|
+
private startupTimer;
|
|
1980
|
+
private sweepTimer;
|
|
1981
|
+
private running;
|
|
1982
|
+
constructor(opts: AmbientDashboardGeneratorOptions);
|
|
1983
|
+
start(): void;
|
|
1984
|
+
stop(): void;
|
|
1985
|
+
isRunning(): boolean;
|
|
1986
|
+
readState(): Promise<AmbientDashboardState>;
|
|
1987
|
+
/** One automatic pass through the full gating chain. Exposed for tests. */
|
|
1988
|
+
sweep(): Promise<boolean>;
|
|
1989
|
+
/**
|
|
1990
|
+
* User-requested run. Bypasses the throttle and change gates — only
|
|
1991
|
+
* the enabled/meester/engagement floor applies.
|
|
1992
|
+
*/
|
|
1993
|
+
runNow(): Promise<boolean>;
|
|
1994
|
+
private generate;
|
|
1995
|
+
/**
|
|
1996
|
+
* A failed run still advances `lastRunAt` — a chronically-failing
|
|
1997
|
+
* model must not retry every sweep. The input hash only advances on
|
|
1998
|
+
* success, so the next allowed run retries the same input.
|
|
1999
|
+
*/
|
|
2000
|
+
private writeState;
|
|
2001
|
+
private collectCandidates;
|
|
2002
|
+
/**
|
|
2003
|
+
* Keep the newest `keep` dated PNGs. Only `dashboard-*.png` files are
|
|
2004
|
+
* eligible — never `latest.png`, the applier's `applied-*.png` slots,
|
|
2005
|
+
* or the state files. Stray temp files from a crashed render go too.
|
|
2006
|
+
*/
|
|
2007
|
+
private prune;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
/**
|
|
2011
|
+
* Process-wide debug flag.
|
|
2012
|
+
*
|
|
2013
|
+
* Subsystems hold a shared reference and read `isEnabled()` at the
|
|
2014
|
+
* point of logging so a config flip — via `PUT /api/config` —
|
|
2015
|
+
* propagates instantly without re-spawning anything. The flag never
|
|
2016
|
+
* touches disk itself; the source of truth is `GezelConfig.debugMode`
|
|
2017
|
+
* in `~/.gezel/config.json`, re-read on service boot and on every
|
|
2018
|
+
* config PUT.
|
|
2019
|
+
*/
|
|
2020
|
+
declare class DebugFlag {
|
|
2021
|
+
private _enabled;
|
|
2022
|
+
constructor(initial?: boolean);
|
|
2023
|
+
isEnabled(): boolean;
|
|
2024
|
+
set(next: boolean): void;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
1698
2027
|
/**
|
|
1699
2028
|
* SecretStore — the one place secrets (API tokens, webhook keys, OAuth
|
|
1700
2029
|
* access tokens) live at rest. Two implementations ship:
|
|
@@ -1762,118 +2091,26 @@ interface SendOptions {
|
|
|
1762
2091
|
*/
|
|
1763
2092
|
declare class ChannelManager {
|
|
1764
2093
|
private readonly store;
|
|
1765
|
-
private readonly secrets;
|
|
1766
|
-
private readonly history;
|
|
1767
|
-
private readonly debug;
|
|
1768
|
-
private readonly channels;
|
|
1769
|
-
private started;
|
|
1770
|
-
constructor(opts: ChannelManagerOpts);
|
|
1771
|
-
start(): Promise<void>;
|
|
1772
|
-
stop(): Promise<void>;
|
|
1773
|
-
/**
|
|
1774
|
-
* Called by the config PUT handler when `channels.*` changed. Tears
|
|
1775
|
-
* down every channel and rebuilds from the new config — cheap while
|
|
1776
|
-
* only webhook (stateless) lives here.
|
|
1777
|
-
*/
|
|
1778
|
-
reconfigure(): Promise<void>;
|
|
1779
|
-
list(): Promise<ChannelStatus[]>;
|
|
1780
|
-
send(message: string, opts?: SendOptions): Promise<SendResult & {
|
|
1781
|
-
channel?: ChannelName;
|
|
1782
|
-
}>;
|
|
1783
|
-
private defaultChannel;
|
|
1784
|
-
private applyConfig;
|
|
1785
|
-
}
|
|
1786
|
-
|
|
1787
|
-
type SessionListener = (event: ChatEvent) => void;
|
|
1788
|
-
type EnvelopeListener = (envelope: ChatEventEnvelope) => void;
|
|
1789
|
-
interface PublishScope {
|
|
1790
|
-
sessionId: string;
|
|
1791
|
-
gezelId: string;
|
|
1792
|
-
projectId: string;
|
|
1793
|
-
}
|
|
1794
|
-
/**
|
|
1795
|
-
* Per-session chat event bus, plus project-scoped and global fan-out for the
|
|
1796
|
-
* interleaved timeline UI. Each `publish` reaches three subscriber sets:
|
|
1797
|
-
*
|
|
1798
|
-
* 1. Listeners on this session — bare `ChatEvent`. Get the recent history
|
|
1799
|
-
* replayed when they subscribe (so a late session-scoped subscriber can
|
|
1800
|
-
* catch up on the in-flight message). Cleared on `done`.
|
|
1801
|
-
* 2. Listeners on this project — `ChatEventEnvelope` with sessionId/
|
|
1802
|
-
* gezelId/projectId. Also get the history replayed for any in-flight
|
|
1803
|
-
* sessions in this project, so a user who tabs away mid-stream and back
|
|
1804
|
-
* doesn't lose the partial text + tools accumulated during the gap.
|
|
1805
|
-
* 3. Global listeners — `ChatEventEnvelope`. Same replay semantics across
|
|
1806
|
-
* every in-flight session anywhere.
|
|
1807
|
-
*
|
|
1808
|
-
* History is bus-side only: cleared on `done` so completed turns don't get
|
|
1809
|
-
* re-delivered when a new subscriber connects after the fact.
|
|
1810
|
-
*
|
|
1811
|
-
* If a send truly cannot resolve its session record, it does not know the
|
|
1812
|
-
* gezelId/projectId and publishes session-scoped via `publishSessionOnly`.
|
|
1813
|
-
* Once a record is known, even provider-start failures use `publish` so
|
|
1814
|
-
* project/global clients receive the error.
|
|
1815
|
-
*/
|
|
1816
|
-
declare class ChatEventBus {
|
|
1817
|
-
private readonly sessionBuses;
|
|
1818
|
-
private readonly projectListeners;
|
|
1819
|
-
private readonly gezelListeners;
|
|
1820
|
-
private readonly globalListeners;
|
|
1821
|
-
publish(scope: PublishScope, event: ChatEvent): void;
|
|
1822
|
-
/**
|
|
1823
|
-
* Publish to the session bus only. Used when the manager's early-fail path
|
|
1824
|
-
* doesn't know the gezel/project to envelope (the session record itself
|
|
1825
|
-
* couldn't be loaded). Project + global subscribers never see these.
|
|
1826
|
-
*/
|
|
1827
|
-
publishSessionOnly(sessionId: string, event: ChatEvent): void;
|
|
1828
|
-
/**
|
|
1829
|
-
* Publish a project-scoped lifecycle event that has no originating
|
|
1830
|
-
* turn — e.g. `project_created`. Fans out to the project's listeners
|
|
1831
|
-
* and all global listeners, but is deliberately NOT recorded in any
|
|
1832
|
-
* session history: these are one-shot signals, not part of a
|
|
1833
|
-
* replayable transcript, so a subscriber that reconnects later must
|
|
1834
|
-
* not see them re-fired (unlike `publish`, which seeds `deliverToSession`
|
|
1835
|
-
* history that replays until the turn's `done`). `sessionId`/`gezelId`
|
|
1836
|
-
* are empty — the consumers that care (the sidebar refresh bridge)
|
|
1837
|
-
* key off the event payload, not the envelope scope.
|
|
1838
|
-
*/
|
|
1839
|
-
publishProjectEvent(projectId: string, event: ChatEvent): void;
|
|
1840
|
-
/**
|
|
1841
|
-
* Publish a project-less global lifecycle event — e.g. `night_shift`.
|
|
1842
|
-
* Reaches only the global listeners (the Meester timeline SSE the UI
|
|
1843
|
-
* subscribes to via `subscribeAll`); like `publishProjectEvent` it is
|
|
1844
|
-
* not recorded in any session history, so reconnecting subscribers do
|
|
1845
|
-
* not see it re-fired. The envelope scope fields are all empty;
|
|
1846
|
-
* consumers key off the event payload.
|
|
1847
|
-
*/
|
|
1848
|
-
publishGlobalEvent(event: ChatEvent): void;
|
|
1849
|
-
subscribe(sessionId: string, listener: SessionListener): () => void;
|
|
1850
|
-
subscribeProject(projectId: string, listener: EnvelopeListener): () => void;
|
|
1851
|
-
subscribeGezel(gezelId: string, listener: EnvelopeListener): () => void;
|
|
1852
|
-
subscribeAll(listener: EnvelopeListener): () => void;
|
|
1853
|
-
private deliverToSession;
|
|
1854
|
-
/**
|
|
1855
|
-
* Append an event to a session's replay history, keeping the buffer
|
|
1856
|
-
* lossless for the content that matters. Two rules:
|
|
1857
|
-
*
|
|
1858
|
-
* 1. Transient status pulses (`heartbeat`, `wire_pulse`) are delivered
|
|
1859
|
-
* live but never recorded — they carry no replayable content, and a
|
|
1860
|
-
* reasoning-heavy local-model turn emits enough of them to evict
|
|
1861
|
-
* real deltas out of the 500-event cap.
|
|
1862
|
-
* 2. Adjacent `delta` events coalesce into one entry. A five-minute
|
|
1863
|
-
* thinking turn streams thousands of per-token deltas; stored
|
|
1864
|
-
* individually they blow past the cap and the earliest thinking is
|
|
1865
|
-
* silently dropped on replay. Merged, a text run costs one slot no
|
|
1866
|
-
* matter how long it streamed. The stored entry is a fresh object —
|
|
1867
|
-
* the original event was already handed to live listeners and must
|
|
1868
|
-
* not be mutated.
|
|
2094
|
+
private readonly secrets;
|
|
2095
|
+
private readonly history;
|
|
2096
|
+
private readonly debug;
|
|
2097
|
+
private readonly channels;
|
|
2098
|
+
private started;
|
|
2099
|
+
constructor(opts: ChannelManagerOpts);
|
|
2100
|
+
start(): Promise<void>;
|
|
2101
|
+
stop(): Promise<void>;
|
|
2102
|
+
/**
|
|
2103
|
+
* Called by the config PUT handler when `channels.*` changed. Tears
|
|
2104
|
+
* down every channel and rebuilds from the new config — cheap while
|
|
2105
|
+
* only webhook (stateless) lives here.
|
|
1869
2106
|
*/
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
2107
|
+
reconfigure(): Promise<void>;
|
|
2108
|
+
list(): Promise<ChannelStatus[]>;
|
|
2109
|
+
send(message: string, opts?: SendOptions): Promise<SendResult & {
|
|
2110
|
+
channel?: ChannelName;
|
|
2111
|
+
}>;
|
|
2112
|
+
private defaultChannel;
|
|
2113
|
+
private applyConfig;
|
|
1877
2114
|
}
|
|
1878
2115
|
|
|
1879
2116
|
/**
|
|
@@ -1986,6 +2223,18 @@ type HookRunner = (hook: ActiveHook, ctx: {
|
|
|
1986
2223
|
type McpServerSpec = StdioMcpServerSpec | HttpMcpServerSpec;
|
|
1987
2224
|
interface StdioMcpServerSpec {
|
|
1988
2225
|
kind?: 'stdio';
|
|
2226
|
+
/**
|
|
2227
|
+
* Catalog toolset id this bridge speaks to, when it was spawned for an
|
|
2228
|
+
* installed toolset. Wrappers select on this rather than sniffing the
|
|
2229
|
+
* command line, because a managed system install spawns
|
|
2230
|
+
* `node <home>/system-toolsets/@playwright__mcp@0.0.78/package/cli.js` —
|
|
2231
|
+
* `installDirName` has slugified the `/` away, so the package name never
|
|
2232
|
+
* appears in `command`/`args`. Sniffing there left every Playwright
|
|
2233
|
+
* wrapper inert against the exact copy Gezel manages: the `file:`-URL
|
|
2234
|
+
* rewrite never fired, and the local-preview posture advertised a browser
|
|
2235
|
+
* surface nothing had pruned.
|
|
2236
|
+
*/
|
|
2237
|
+
toolsetId?: string;
|
|
1989
2238
|
command: string;
|
|
1990
2239
|
args: string[];
|
|
1991
2240
|
env: Record<string, string>;
|
|
@@ -1994,6 +2243,8 @@ interface StdioMcpServerSpec {
|
|
|
1994
2243
|
}
|
|
1995
2244
|
interface HttpMcpServerSpec {
|
|
1996
2245
|
kind: 'http';
|
|
2246
|
+
/** Catalog toolset id — see {@link StdioMcpServerSpec.toolsetId}. */
|
|
2247
|
+
toolsetId?: string;
|
|
1997
2248
|
/**
|
|
1998
2249
|
* `streamable-http` is the current MCP HTTP transport (one URL,
|
|
1999
2250
|
* POST for messages, optional GET for SSE stream + auto-reconnect).
|
|
@@ -2282,6 +2533,20 @@ interface PromptCtx extends ModelCtx {
|
|
|
2282
2533
|
isMeester: boolean;
|
|
2283
2534
|
/** The gezel's about.md content (already loaded). */
|
|
2284
2535
|
about: string;
|
|
2536
|
+
/**
|
|
2537
|
+
* Tool names actually wired for this session (post-allowlist).
|
|
2538
|
+
*
|
|
2539
|
+
* A behavior whose whole point is "reach for tool X instead of tool Y"
|
|
2540
|
+
* must gate on this and return null when X is absent. The rendered block
|
|
2541
|
+
* is also passed through `filterPromptToolDirectives`, but that pass is
|
|
2542
|
+
* lexical: it drops a line only when the line reads as a directive, and
|
|
2543
|
+
* "write a small Node script and execute it — `derive_file(...)`" does
|
|
2544
|
+
* not match, so the block survived intact on a roster with no execution
|
|
2545
|
+
* tool at all and prescribed a remedy the session could not perform.
|
|
2546
|
+
* Positive gating here is the reliable half; the lexical filter is the
|
|
2547
|
+
* backstop for phrasings a behavior author did not anticipate.
|
|
2548
|
+
*/
|
|
2549
|
+
availableToolNames: ReadonlySet<string>;
|
|
2285
2550
|
}
|
|
2286
2551
|
/**
|
|
2287
2552
|
* Context for per-turn hooks: {@link Behavior.userPromptPrelude} and
|
|
@@ -2311,6 +2576,17 @@ interface TurnCtx extends ModelCtx {
|
|
|
2311
2576
|
assistantContent: string;
|
|
2312
2577
|
/** How many continuation nudges have already fired in this user-initiated send. */
|
|
2313
2578
|
continuationCount: number;
|
|
2579
|
+
/**
|
|
2580
|
+
* Shared-library documents matching THIS turn's message, resolved before
|
|
2581
|
+
* the prelude hooks run (they are synchronous; the search is not).
|
|
2582
|
+
* Populated only for user-origin turns, and only with matches strong
|
|
2583
|
+
* enough to be worth the tokens — usually absent.
|
|
2584
|
+
*/
|
|
2585
|
+
libraryRecall?: ReadonlyArray<{
|
|
2586
|
+
path: string;
|
|
2587
|
+
snippet: string;
|
|
2588
|
+
score: number;
|
|
2589
|
+
}>;
|
|
2314
2590
|
}
|
|
2315
2591
|
/**
|
|
2316
2592
|
* Verdict returned by {@link Behavior.postTurnDetector} when a
|
|
@@ -2655,6 +2931,18 @@ interface QuotaBucket {
|
|
|
2655
2931
|
overage: number;
|
|
2656
2932
|
resetDate?: string;
|
|
2657
2933
|
}
|
|
2934
|
+
interface UsageTurn {
|
|
2935
|
+
model: string;
|
|
2936
|
+
inputTokens: number;
|
|
2937
|
+
/** Portion of `inputTokens` served from the provider's prompt cache; absent when unreported. */
|
|
2938
|
+
cachedInputTokens?: number;
|
|
2939
|
+
outputTokens: number;
|
|
2940
|
+
cost: number;
|
|
2941
|
+
durationMs: number;
|
|
2942
|
+
/** Engine-reported decode rate for this turn; absent when unreported. */
|
|
2943
|
+
outputTokensPerSec?: number;
|
|
2944
|
+
at: string;
|
|
2945
|
+
}
|
|
2658
2946
|
interface ProviderUsage {
|
|
2659
2947
|
/** Non-empty only for providers that report account quota windows. */
|
|
2660
2948
|
quotaBuckets: QuotaBucket[];
|
|
@@ -2685,8 +2973,30 @@ interface ProviderUsage {
|
|
|
2685
2973
|
* "n/a" rather than zero.
|
|
2686
2974
|
*/
|
|
2687
2975
|
medianOutputTokensPerSec: number | null;
|
|
2976
|
+
/**
|
|
2977
|
+
* The same median decode rate split per model, for the turns that reported
|
|
2978
|
+
* one. A 27B and a 4B averaged together is a number describing nothing, and
|
|
2979
|
+
* the question a user actually asks — "how fast is this model on my machine"
|
|
2980
|
+
* — is per model. Sorted fastest first; empty for providers that report no
|
|
2981
|
+
* throughput at all.
|
|
2982
|
+
*
|
|
2983
|
+
* This is the durable half of the speed story: it spans every session the
|
|
2984
|
+
* daemon has served, so it is still there when a page reloads mid-turn and
|
|
2985
|
+
* the client-side rolling window is empty.
|
|
2986
|
+
*/
|
|
2987
|
+
modelSpeeds: ModelSpeed[];
|
|
2988
|
+
/** Most recently completed turn, retained independently of the UI's rolling window. */
|
|
2989
|
+
lastTurn: UsageTurn | null;
|
|
2688
2990
|
lastUpdated: string | null;
|
|
2689
2991
|
}
|
|
2992
|
+
/** Per-model decode-rate rollup inside {@link ProviderUsage}. */
|
|
2993
|
+
interface ModelSpeed {
|
|
2994
|
+
model: string;
|
|
2995
|
+
/** Median engine-reported decode rate across this model's turns. */
|
|
2996
|
+
medianOutputTokensPerSec: number;
|
|
2997
|
+
/** Turns that contributed a rate — not the model's total turn count. */
|
|
2998
|
+
turns: number;
|
|
2999
|
+
}
|
|
2690
3000
|
interface UsageSummary {
|
|
2691
3001
|
providers: {
|
|
2692
3002
|
copilot?: ProviderUsage;
|
|
@@ -2715,6 +3025,8 @@ declare class UsageTracker {
|
|
|
2715
3025
|
* those windows without inventing a zero-token turn or skewing totals.
|
|
2716
3026
|
*/
|
|
2717
3027
|
recordQuotaBuckets(provider: ProviderName, buckets: QuotaBucket[], at?: string): void;
|
|
3028
|
+
/** Latest quota buckets recorded for `provider`; empty when never reported. */
|
|
3029
|
+
quotaBucketsFor(provider: ProviderName): QuotaBucket[];
|
|
2718
3030
|
summary(): UsageSummary;
|
|
2719
3031
|
private ensure;
|
|
2720
3032
|
}
|
|
@@ -2767,7 +3079,7 @@ type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];
|
|
|
2767
3079
|
* — no wasted work. Already-running entries abort normally via the
|
|
2768
3080
|
* same signal.
|
|
2769
3081
|
*
|
|
2770
|
-
* ## Ambient admission control (
|
|
3082
|
+
* ## Ambient admission control (foreground-capacity protection)
|
|
2771
3083
|
*
|
|
2772
3084
|
* On a local engine, a housekeeping turn (scheduler nudge, memory
|
|
2773
3085
|
* extraction, icon/about generation) occupies the GPU for minutes.
|
|
@@ -2777,17 +3089,19 @@ type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];
|
|
|
2777
3089
|
* engine is idle while the user READS, ambient work sneaks in, and
|
|
2778
3090
|
* the user's move then waits out a 3-minute nudge turn).
|
|
2779
3091
|
*
|
|
2780
|
-
* When
|
|
2781
|
-
*
|
|
2782
|
-
*
|
|
2783
|
-
*
|
|
2784
|
-
*
|
|
2785
|
-
*
|
|
2786
|
-
*
|
|
2787
|
-
*
|
|
2788
|
-
*
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
3092
|
+
* When an engine has more than one interactive slot, ambient work may
|
|
3093
|
+
* use otherwise-idle capacity immediately, but only while at least one
|
|
3094
|
+
* physical slot stays free for a newly-arriving foreground chat. On a
|
|
3095
|
+
* single-slot engine — or once a multi-slot engine reaches that protected
|
|
3096
|
+
* headroom — entries marked `ambient: true` dispatch only when BOTH hold:
|
|
3097
|
+
* no non-ambient work is running or pending, and no non-ambient activity
|
|
3098
|
+
* (enqueue, dispatch, or release, any lane) happened within the last
|
|
3099
|
+
* `ambientQuietMs`. Reading time counts as engagement: page reactions and
|
|
3100
|
+
* tool-loop turns are non-ambient, so an active game holds the gate closed
|
|
3101
|
+
* between moves when there is no safe spare capacity. Ambient entries are
|
|
3102
|
+
* exempt from the anti-starvation guard while gated. The gate never touches
|
|
3103
|
+
* non-ambient work, so mid-turn compaction (which a foreground turn awaits)
|
|
3104
|
+
* and user-facing background turns are unaffected.
|
|
2791
3105
|
*/
|
|
2792
3106
|
type Lane = 'interactive' | 'background';
|
|
2793
3107
|
interface EnqueueRequest {
|
|
@@ -2796,9 +3110,10 @@ interface EnqueueRequest {
|
|
|
2796
3110
|
* Marks truly-deferrable housekeeping (scheduler nudges, memory
|
|
2797
3111
|
* extraction, icon/about generation, digests, night-shift chores).
|
|
2798
3112
|
* When the queue was built with {@link ProviderQueueOptions.ambientQuietMs},
|
|
2799
|
-
* ambient entries
|
|
2800
|
-
* NON-ambient activity — see "Ambient
|
|
2801
|
-
* class header. Distinct from `lane:
|
|
3113
|
+
* ambient entries use safe spare capacity immediately, or otherwise
|
|
3114
|
+
* wait for a quiet window with no NON-ambient activity — see "Ambient
|
|
3115
|
+
* admission control" in the class header. Distinct from `lane:
|
|
3116
|
+
* 'background'`: background
|
|
2802
3117
|
* covers anything that shouldn't cut in front of a typed chat turn,
|
|
2803
3118
|
* which includes user-facing work (checkers page reactions, mid-turn
|
|
2804
3119
|
* compaction a foreground turn awaits) that must NEVER be held.
|
|
@@ -2905,10 +3220,12 @@ interface ProviderQueueOptions {
|
|
|
2905
3220
|
maxWaitMs?: number;
|
|
2906
3221
|
/**
|
|
2907
3222
|
* Quiet window for ambient admission control — see the class header.
|
|
2908
|
-
*
|
|
2909
|
-
*
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
3223
|
+
* On a multi-slot engine, entries marked `ambient: true` may dispatch
|
|
3224
|
+
* sooner while one physical foreground slot remains protected. Once
|
|
3225
|
+
* that headroom is reached, they wait for this many ms with no
|
|
3226
|
+
* non-ambient activity (and none running or pending). 0 or unset
|
|
3227
|
+
* disables the gate (ambient entries behave like plain background).
|
|
3228
|
+
* Local single-GPU engines pass
|
|
2912
3229
|
* {@link defaultAmbientQuietMs}; cloud queues leave it off.
|
|
2913
3230
|
*/
|
|
2914
3231
|
ambientQuietMs?: number;
|
|
@@ -2974,6 +3291,14 @@ declare class ProviderQueue {
|
|
|
2974
3291
|
*/
|
|
2975
3292
|
describe(): {
|
|
2976
3293
|
running: number;
|
|
3294
|
+
/**
|
|
3295
|
+
* In-flight slots split by lane. `running` alone cannot answer "how
|
|
3296
|
+
* many conversations are live right now?" — a queue holding nothing
|
|
3297
|
+
* but index-enrichment one-shots still reports `running: 1`, which
|
|
3298
|
+
* the pill used to render as "1 running" beside a chat-shaped noun.
|
|
3299
|
+
*/
|
|
3300
|
+
runningInteractive: number;
|
|
3301
|
+
runningBackground: number;
|
|
2977
3302
|
queuedInteractive: number;
|
|
2978
3303
|
queuedBackground: number;
|
|
2979
3304
|
/** Pending ambient entries currently held by the admission gate. */
|
|
@@ -3037,9 +3362,15 @@ declare class ProviderQueue {
|
|
|
3037
3362
|
*/
|
|
3038
3363
|
private maybeScheduleAmbientRecheck;
|
|
3039
3364
|
/**
|
|
3040
|
-
* True when ambient entries may dispatch
|
|
3041
|
-
*
|
|
3042
|
-
*
|
|
3365
|
+
* True when ambient entries may dispatch.
|
|
3366
|
+
*
|
|
3367
|
+
* A multi-slot engine may spend spare capacity immediately while keeping
|
|
3368
|
+
* one of its physical interactive slots unused. `running` is deliberately
|
|
3369
|
+
* compared with `interactiveConcurrency - 1`, rather than with the queue's
|
|
3370
|
+
* total `concurrency`: local queues carry one extra logical background lane
|
|
3371
|
+
* for deadlock-breaking one-shots, but that lane is not another native KV
|
|
3372
|
+
* slot. Once protected headroom is exhausted, the ordinary quiet-window
|
|
3373
|
+
* rule applies.
|
|
3043
3374
|
*/
|
|
3044
3375
|
private ambientGateOpen;
|
|
3045
3376
|
/**
|
|
@@ -3817,9 +4148,10 @@ interface LLMSession {
|
|
|
3817
4148
|
onDelta(handler: (chunk: string) => void): () => void;
|
|
3818
4149
|
/**
|
|
3819
4150
|
* Subscribe to live private-reasoning deltas, streamed separately from
|
|
3820
|
-
* the visible reply so they never enter the committed body
|
|
3821
|
-
*
|
|
3822
|
-
*
|
|
4151
|
+
* the visible reply so they never enter the committed body. API-compat
|
|
4152
|
+
* forwarders omit this private channel unless their client contract opts
|
|
4153
|
+
* in explicitly. Optional — only providers with a distinct reasoning
|
|
4154
|
+
* channel (llama-cpp/ds4) fire it.
|
|
3823
4155
|
*/
|
|
3824
4156
|
onReasoningDelta?(handler: (chunk: string) => void): () => void;
|
|
3825
4157
|
onUsage(handler: (usage: TurnUsage) => void): () => void;
|
|
@@ -3844,7 +4176,7 @@ interface LLMSession {
|
|
|
3844
4176
|
* calls arrive whole (Ollama) or run server-side (Copilot, OpenAI)
|
|
3845
4177
|
* leave it undefined.
|
|
3846
4178
|
*/
|
|
3847
|
-
onToolArgsDelta?(handler: (name: string, chunk: string) => void): () => void;
|
|
4179
|
+
onToolArgsDelta?(handler: (name: string, chunk: string, meta?: ToolArgsDeltaMeta) => void): () => void;
|
|
3848
4180
|
/**
|
|
3849
4181
|
* Optional: subscribe to phase-announcement events. Currently only
|
|
3850
4182
|
* `CopilotSession` emits these (SDK `assistant.intent` events from
|
|
@@ -3971,6 +4303,13 @@ interface ExternalToolCall {
|
|
|
3971
4303
|
name: string;
|
|
3972
4304
|
arguments: string;
|
|
3973
4305
|
}
|
|
4306
|
+
/** Identity attached to a live structured tool-argument fragment. */
|
|
4307
|
+
interface ToolArgsDeltaMeta {
|
|
4308
|
+
/** OpenAI-compatible position within the assistant's tool_calls array. */
|
|
4309
|
+
index?: number;
|
|
4310
|
+
/** Provider-supplied call id, normally present on the first fragment. */
|
|
4311
|
+
id?: string;
|
|
4312
|
+
}
|
|
3974
4313
|
/**
|
|
3975
4314
|
* Context describing one would-be batch member, passed to
|
|
3976
4315
|
* {@link BatchCapability.admit} so an engine can make a live headroom
|
|
@@ -4399,11 +4738,14 @@ declare class CapacityBroker {
|
|
|
4399
4738
|
/**
|
|
4400
4739
|
* Fallback estimate when a catalog entry lacks `residentBytes`.
|
|
4401
4740
|
* Used by callers building reservation requests from
|
|
4402
|
-
* `approxSizeBytes`.
|
|
4403
|
-
*
|
|
4741
|
+
* `approxSizeBytes`. Reflects the working-set footprint vs. on-disk
|
|
4742
|
+
* size WITHOUT any KV — every caller prices KV explicitly on top.
|
|
4404
4743
|
*
|
|
4405
|
-
* llama.cpp
|
|
4406
|
-
*
|
|
4744
|
+
* llama.cpp: see {@link estimateLlamaCppResidentBytes}. Pass `mmprojBytes`
|
|
4745
|
+
* for a multimodal model — `approxSizeBytes` counts the weights alone, and
|
|
4746
|
+
* the projector plus its vision buffers is 1.7 GB on a 30B.
|
|
4747
|
+
* MLX: see {@link estimateMlxResidentBytes}. MLX needs no equivalent — its
|
|
4748
|
+
* vision tower is inside the same safetensors set `approxSizeBytes` sums.
|
|
4407
4749
|
*
|
|
4408
4750
|
* ds4 is special: it streams MoE experts from SSD, so its resident
|
|
4409
4751
|
* working set is bounded by the configured expert-cache budget + KV +
|
|
@@ -4412,7 +4754,9 @@ declare class CapacityBroker {
|
|
|
4412
4754
|
* conservative streaming working set so a 64GB box is never told an
|
|
4413
4755
|
* 87GB DeepSeek-V4 model "can't fit" (which is the whole point of ds4).
|
|
4414
4756
|
*/
|
|
4415
|
-
static estimateResidentBytes(engine: LocalProviderName, approxSizeBytes: number
|
|
4757
|
+
static estimateResidentBytes(engine: LocalProviderName, approxSizeBytes: number, opts?: {
|
|
4758
|
+
mmprojBytes?: number;
|
|
4759
|
+
}): number;
|
|
4416
4760
|
}
|
|
4417
4761
|
|
|
4418
4762
|
/**
|
|
@@ -4581,6 +4925,9 @@ interface PoolSnapshot {
|
|
|
4581
4925
|
*/
|
|
4582
4926
|
interface PooledQueueSummary {
|
|
4583
4927
|
running: number;
|
|
4928
|
+
/** See {@link ProviderQueue.describe}. Summed across replicas like `running`. */
|
|
4929
|
+
runningInteractive: number;
|
|
4930
|
+
runningBackground: number;
|
|
4584
4931
|
queuedInteractive: number;
|
|
4585
4932
|
queuedBackground: number;
|
|
4586
4933
|
/** Pending ambient entries held by the admission gate across replicas. */
|
|
@@ -4663,6 +5010,18 @@ declare class ProviderPool {
|
|
|
4663
5010
|
* Returns false when the engine has already gone away.
|
|
4664
5011
|
*/
|
|
4665
5012
|
unloadIdle(key: string): Promise<boolean>;
|
|
5013
|
+
/**
|
|
5014
|
+
* Unload every resident engine that is idle right now, leaving busy ones
|
|
5015
|
+
* running. Returns the keys that stayed resident because they were serving
|
|
5016
|
+
* a turn — the caller reports them; the ordinary LRU / idle-retention path
|
|
5017
|
+
* collects them once they go quiet.
|
|
5018
|
+
*
|
|
5019
|
+
* This is what a live config reset uses. {@link shutdown} is the other
|
|
5020
|
+
* shape — it force-evicts busy engines too — and is only correct when the
|
|
5021
|
+
* process is going away (service shutdown, emergency stop), because a
|
|
5022
|
+
* forced eviction kills whatever turn is streaming.
|
|
5023
|
+
*/
|
|
5024
|
+
releaseIdle(): Promise<string[]>;
|
|
4666
5025
|
/**
|
|
4667
5026
|
* Evict a specific entry. Awaits the provider's `shutdown` so the
|
|
4668
5027
|
* disk-cache flush (Tier 1 prior plan) completes before the broker
|
|
@@ -5191,6 +5550,17 @@ declare class ContentIndex {
|
|
|
5191
5550
|
stale: number;
|
|
5192
5551
|
pending: number;
|
|
5193
5552
|
} | null>;
|
|
5553
|
+
/**
|
|
5554
|
+
* Indexing work this project recorded in `[since, until)` — summaries,
|
|
5555
|
+
* reviews, and AI shadows, from the tiers' own stamps. Null when the
|
|
5556
|
+
* project has no index (or it's momentarily unavailable); callers tally
|
|
5557
|
+
* across projects and treat that as "nothing to add", never as zero work.
|
|
5558
|
+
*/
|
|
5559
|
+
workCountsSince(projectId: string, since: string, until: string): Promise<{
|
|
5560
|
+
summarized: number;
|
|
5561
|
+
reviewed: number;
|
|
5562
|
+
described: number;
|
|
5563
|
+
} | null>;
|
|
5194
5564
|
/** One file's boekwachter review (`file_review` tool). */
|
|
5195
5565
|
fileReview(projectId: string, relPath: string): Promise<FileReviewResponse>;
|
|
5196
5566
|
/** Flat issue query across current-hash reviews (`list_file_issues` tool). */
|
|
@@ -5205,6 +5575,28 @@ declare class ContentIndex {
|
|
|
5205
5575
|
settleBoekwachterIssuesForTask(projectId: string, taskRef: string, outcome: 'complete' | 'canceled'): Promise<number>;
|
|
5206
5576
|
private boekwachterIssuesForPath;
|
|
5207
5577
|
searchDocs(projectId: string, query: string, maxResults?: number): Promise<SearchDocsResponse>;
|
|
5578
|
+
/**
|
|
5579
|
+
* Content search over the shared document library.
|
|
5580
|
+
*
|
|
5581
|
+
* The library is a project, so this is the ordinary hybrid searcher
|
|
5582
|
+
* (embeddings + keyword) reshaped to document identity: callers name a
|
|
5583
|
+
* document by the path the user filed it under, never by the converted
|
|
5584
|
+
* markdown the snippet happened to come from. That mapping is why this
|
|
5585
|
+
* exists rather than callers using `searchCode` directly.
|
|
5586
|
+
*/
|
|
5587
|
+
searchLibrary(projectId: string, query: string, opts?: {
|
|
5588
|
+
maxResults?: number;
|
|
5589
|
+
queryVector?: number[];
|
|
5590
|
+
}): Promise<SearchDocumentsResponse>;
|
|
5591
|
+
/**
|
|
5592
|
+
* One-line descriptions for library documents, keyed by path.
|
|
5593
|
+
*
|
|
5594
|
+
* Two sources, in precedence order: the document's own frontmatter
|
|
5595
|
+
* `description`/`title` — the user said what this is, so nothing should
|
|
5596
|
+
* outrank it — then the Boekwachter's generated summary. Absent entries
|
|
5597
|
+
* simply have no description; a listing renders the bare path.
|
|
5598
|
+
*/
|
|
5599
|
+
libraryDescriptions(projectId: string): Promise<Map<string, string>>;
|
|
5208
5600
|
readDocAsMarkdown(projectId: string, relPath: string): Promise<ReadDocAsMarkdownResponse>;
|
|
5209
5601
|
/**
|
|
5210
5602
|
* Schedule a rebuild of the project's artifacts-corpus index. Debounced per
|
|
@@ -5787,6 +6179,19 @@ interface GateCheckOutcome {
|
|
|
5787
6179
|
detail: string;
|
|
5788
6180
|
/** Machine evidence preserved from the rich CheckResults (arrays sliced to ≤10). */
|
|
5789
6181
|
evidence?: Record<string, unknown>;
|
|
6182
|
+
/**
|
|
6183
|
+
* Discrete items this check still wants, for checks that count in items
|
|
6184
|
+
* at all (unread corpus records, uncovered paths). Folded into the
|
|
6185
|
+
* plateau signature, which is what lets a gate a craftbook is DESIGNED
|
|
6186
|
+
* to fail repeatedly — a bounded batch loop — read as progress instead
|
|
6187
|
+
* of a stall while the count falls.
|
|
6188
|
+
*
|
|
6189
|
+
* Only set this where the count is deterministic for a given
|
|
6190
|
+
* deliverable: a number that jitters on identical content would reset
|
|
6191
|
+
* the ladder forever and hide a real plateau. Leaving it unset keeps
|
|
6192
|
+
* the legacy identity-only behavior exactly.
|
|
6193
|
+
*/
|
|
6194
|
+
remaining?: number;
|
|
5790
6195
|
}
|
|
5791
6196
|
interface GateCheckResult {
|
|
5792
6197
|
pass: boolean;
|
|
@@ -5874,11 +6279,17 @@ declare function gateCheckLabel(c: GateCheck): string;
|
|
|
5874
6279
|
* stage 3 — stop: pause with the full attempt trail as diagnosis.
|
|
5875
6280
|
*
|
|
5876
6281
|
* The plateau signature hashes failing-check IDENTITY (GateCheckOutcome
|
|
5877
|
-
* labels)
|
|
5878
|
-
*
|
|
5879
|
-
* lesson), while clearing
|
|
5880
|
-
*
|
|
5881
|
-
*
|
|
6282
|
+
* labels) plus any outstanding-item count those checks report, not prose
|
|
6283
|
+
* and not content bytes: byte churn with an unmoved failure set IS the
|
|
6284
|
+
* plateau (the eval harness's retryLoopSniffKey lesson), while clearing a
|
|
6285
|
+
* check — or covering more of what a counting check still wants — changes
|
|
6286
|
+
* the signature and resets the ladder. The count matters because some
|
|
6287
|
+
* craftbooks are DESIGNED to fail a gate repeatedly (bounded batch loops
|
|
6288
|
+
* over a corpus too large for one context); identity alone cannot tell
|
|
6289
|
+
* those from a stall, and calling them a stall pushes the assignee toward
|
|
6290
|
+
* the smallest edit that clears the check rather than the work.
|
|
6291
|
+
* Kill-switch: GEZEL_DISABLE_GATE_ESCALATION=1 restores the legacy
|
|
6292
|
+
* quiet-damper behavior.
|
|
5882
6293
|
*/
|
|
5883
6294
|
|
|
5884
6295
|
type EscalationStage = 0 | 1 | 2 | 3;
|
|
@@ -6436,14 +6847,18 @@ declare class TaskManager {
|
|
|
6436
6847
|
*/
|
|
6437
6848
|
private runCompletionGate;
|
|
6438
6849
|
/**
|
|
6439
|
-
*
|
|
6440
|
-
* workspace
|
|
6441
|
-
*
|
|
6442
|
-
*
|
|
6443
|
-
*
|
|
6444
|
-
*
|
|
6445
|
-
*
|
|
6850
|
+
* True when EVERY one of `tasks` is parked on a step that owes a
|
|
6851
|
+
* workspace file managed writes can't produce. Lets the ambient nudger
|
|
6852
|
+
* tell a genuinely stuck writes-off project from one doing artifact-only
|
|
6853
|
+
* work — the drawer is exempt from the writes-off policy, so a nightly
|
|
6854
|
+
* report or a review still completes there and its voorman still wants
|
|
6855
|
+
* the check-in.
|
|
6856
|
+
*
|
|
6857
|
+
* Conservative by construction: an empty list, a task with no active
|
|
6858
|
+
* step, or any step whose deliverable is satisfiable all answer `false`.
|
|
6859
|
+
* We only claim "blocked" on positive evidence for every task.
|
|
6446
6860
|
*/
|
|
6861
|
+
allActiveStepsBlockedByWorkspaceWrites(projectId: string, tasks: Task[]): Promise<boolean>;
|
|
6447
6862
|
/**
|
|
6448
6863
|
* The workspace files a step must produce that no assignee is able to
|
|
6449
6864
|
* write. The proactive twin of {@link unsatisfiableWorkspaceGateFiles}:
|
|
@@ -6464,6 +6879,22 @@ declare class TaskManager {
|
|
|
6464
6879
|
* must skip the handoff — dispatching a gezel here cannot succeed.
|
|
6465
6880
|
*/
|
|
6466
6881
|
private pauseIfStepUnsatisfiable;
|
|
6882
|
+
/**
|
|
6883
|
+
* A rejected gate is unsatisfiable when a FAILING check reads the
|
|
6884
|
+
* workspace tree while gezel workspace writes are off for the project.
|
|
6885
|
+
* Returns the workspace files the failing checks name (possibly empty),
|
|
6886
|
+
* or null when the gate is repairable. Drawer-only failures stay
|
|
6887
|
+
* repairable — the artifacts drawer is deliberately exempt from the
|
|
6888
|
+
* writes-off policy.
|
|
6889
|
+
*
|
|
6890
|
+
* A gate SCRIPT names no file, so it is judged by what the step itself
|
|
6891
|
+
* owes: unwinnable only when the step's own deliverable is a workspace
|
|
6892
|
+
* file nobody can write. Counting every script rejection as a
|
|
6893
|
+
* workspace-write failure misread the note-only gate on Pull Request
|
|
6894
|
+
* Review's scope step — the note was written correctly and the real
|
|
6895
|
+
* fault was elsewhere, but the task paused telling the user to enable
|
|
6896
|
+
* workspace writes, which would have changed nothing.
|
|
6897
|
+
*/
|
|
6467
6898
|
private unsatisfiableWorkspaceGateFiles;
|
|
6468
6899
|
/**
|
|
6469
6900
|
* Gate-driven loop-back: re-activate `targetId` WITHOUT completing the
|
|
@@ -6471,6 +6902,11 @@ declare class TaskManager {
|
|
|
6471
6902
|
* hook even when the target IS the gated step itself — `onReject:
|
|
6472
6903
|
* <self>` deliberately produces a fresh activation + handoff session
|
|
6473
6904
|
* each rejection (the loop shape that carries small models).
|
|
6905
|
+
*
|
|
6906
|
+
* A fresh SESSION is not a fresh BUDGET, though: when the route points
|
|
6907
|
+
* back at the gated step, the rejection count has to survive the
|
|
6908
|
+
* re-activation or `maxAttempts` is unreachable and the loop never
|
|
6909
|
+
* escalates. See the self-loop carve-out in {@link bumpStepActivation}.
|
|
6474
6910
|
*/
|
|
6475
6911
|
private reactivateStepForGate;
|
|
6476
6912
|
/**
|
|
@@ -6847,6 +7283,12 @@ declare class EngineRouter {
|
|
|
6847
7283
|
* Provider is fixed to the caller's chosen engine.
|
|
6848
7284
|
*/
|
|
6849
7285
|
reconcileClones(provider: LocalProviderName, target: Record<string, number>): Promise<void>;
|
|
7286
|
+
/**
|
|
7287
|
+
* Unload every resident replica that is not mid-turn. Returns the keys left
|
|
7288
|
+
* resident because they were busy. Used by a live config reset, which needs
|
|
7289
|
+
* the memory back but must not sever work in flight.
|
|
7290
|
+
*/
|
|
7291
|
+
releaseIdle(): Promise<string[]>;
|
|
6850
7292
|
/** Unload one resident replica immediately, provided it is still idle. */
|
|
6851
7293
|
unloadIdle(provider: LocalProviderName, modelId: string, replicaIdx: number): Promise<boolean>;
|
|
6852
7294
|
snapshot(): PoolSnapshot;
|
|
@@ -7609,6 +8051,35 @@ interface ModelBundleSource {
|
|
|
7609
8051
|
catalogVersion?: string;
|
|
7610
8052
|
}
|
|
7611
8053
|
|
|
8054
|
+
/**
|
|
8055
|
+
* "Is a newer build of this model available?" — asked of the payload, not of
|
|
8056
|
+
* the version string.
|
|
8057
|
+
*
|
|
8058
|
+
* Both engine managers (llama.cpp/ds4 and MLX) and the chat manager's
|
|
8059
|
+
* per-session staleness notice used to answer this by comparing the installed
|
|
8060
|
+
* `catalogVersion` to the catalog's current one. That flags every catalog
|
|
8061
|
+
* edit, including the metadata-only ones the runtime has already picked up,
|
|
8062
|
+
* and the only remedy any surface offers is a multi-gigabyte re-download. Here
|
|
8063
|
+
* the version difference is the *trigger* for a check, and
|
|
8064
|
+
* {@link comparePayloadIdentity} is the answer.
|
|
8065
|
+
*
|
|
8066
|
+
* When the payload turns out to be unchanged we record that finding in the
|
|
8067
|
+
* install manifest (a `payloadFingerprint`) so later checks are a string
|
|
8068
|
+
* compare. `catalogVersion` is deliberately left alone: it means "the version
|
|
8069
|
+
* whose description these bytes were downloaded against", which is what the
|
|
8070
|
+
* `.gezmodel` exporter pins and what model-fitness records compare, and
|
|
8071
|
+
* rewriting it would silently invalidate both.
|
|
8072
|
+
*/
|
|
8073
|
+
|
|
8074
|
+
interface ModelUpdateStatus {
|
|
8075
|
+
/** True only when the catalog's payload differs from the copy on disk. */
|
|
8076
|
+
updateAvailable: boolean;
|
|
8077
|
+
/** The catalog's current version, when it differs from the installed one. */
|
|
8078
|
+
availableVersion?: string;
|
|
8079
|
+
/** Why, in one sentence — surfaced in the model manager's tooltip. */
|
|
8080
|
+
reason?: string;
|
|
8081
|
+
}
|
|
8082
|
+
|
|
7612
8083
|
interface IncompleteModelDownload {
|
|
7613
8084
|
id: string;
|
|
7614
8085
|
/** Total bytes on disk across the directory (payload + `.partial`). */
|
|
@@ -7711,6 +8182,19 @@ interface InstalledMlxModel {
|
|
|
7711
8182
|
* Delete that can only fail.
|
|
7712
8183
|
*/
|
|
7713
8184
|
readOnly?: boolean;
|
|
8185
|
+
/**
|
|
8186
|
+
* True when the catalog now describes a different PAYLOAD than the one on
|
|
8187
|
+
* disk — different repo, file list, or hashes. A version bump that only
|
|
8188
|
+
* edits metadata (tuning, sizing hints, wording) deliberately does not set
|
|
8189
|
+
* this: the runtime resolves that live from the catalog, so there is nothing
|
|
8190
|
+
* for the user to download. Computed server-side in
|
|
8191
|
+
* {@link MlxModelManager.listInstalled} so every surface agrees.
|
|
8192
|
+
*/
|
|
8193
|
+
updateAvailable?: boolean;
|
|
8194
|
+
/** The catalog's current version, when it differs from the installed one. */
|
|
8195
|
+
availableVersion?: string;
|
|
8196
|
+
/** What changed, in one sentence, for the model manager's tooltip. */
|
|
8197
|
+
updateReason?: string;
|
|
7714
8198
|
}
|
|
7715
8199
|
/**
|
|
7716
8200
|
* Snapshot of an in-flight MLX install — same shape as
|
|
@@ -7830,6 +8314,19 @@ declare class MlxModelManager {
|
|
|
7830
8314
|
constructor(opts: MlxModelManagerOptions);
|
|
7831
8315
|
getActiveInstalls(): MlxActiveInstallSnapshot[];
|
|
7832
8316
|
listInstalled(): Promise<InstalledMlxModel[]>;
|
|
8317
|
+
/**
|
|
8318
|
+
* Whether a genuinely newer build of one installed model exists. Null when
|
|
8319
|
+
* the id isn't installed for MLX. Shared with the chat manager's
|
|
8320
|
+
* per-session staleness notice so a user is never told to re-download for a
|
|
8321
|
+
* change that only touched metadata.
|
|
8322
|
+
*/
|
|
8323
|
+
getUpdateStatus(id: string): Promise<ModelUpdateStatus | null>;
|
|
8324
|
+
/**
|
|
8325
|
+
* Compare one installed copy against the live catalog. The catalog lookup
|
|
8326
|
+
* runs for every model on every inventory poll; the manifest re-read only
|
|
8327
|
+
* happens for the few whose version actually moved.
|
|
8328
|
+
*/
|
|
8329
|
+
private evaluateDrift;
|
|
7833
8330
|
/**
|
|
7834
8331
|
* List incomplete MLX downloads — directories that hold bytes but no
|
|
7835
8332
|
* `manifest.json`, so they never surface in {@link listInstalled}. Tagged
|
|
@@ -7877,6 +8374,14 @@ declare class MlxModelManager {
|
|
|
7877
8374
|
* worker owns the error.
|
|
7878
8375
|
*/
|
|
7879
8376
|
private downloadFileConcurrent;
|
|
8377
|
+
/**
|
|
8378
|
+
* Files the plan asks for that are already on disk as exactly the bytes the
|
|
8379
|
+
* catalog pins, keyed by filename with the digest to carry forward. See
|
|
8380
|
+
* {@link LlamaCppModelManager.planReusableFiles} — same trust model: a
|
|
8381
|
+
* digest this install recorded after verifying it, plus a file still at its
|
|
8382
|
+
* pinned length, is identity.
|
|
8383
|
+
*/
|
|
8384
|
+
private planReusableFiles;
|
|
7880
8385
|
/** Warn once per model directory per process, then stay quiet. */
|
|
7881
8386
|
private warnSkip;
|
|
7882
8387
|
private loadInstalled;
|
|
@@ -8058,6 +8563,15 @@ interface InstalledLlamaCppModel {
|
|
|
8058
8563
|
* video inputs on llama-server. Absent → text-only model.
|
|
8059
8564
|
*/
|
|
8060
8565
|
mmprojPath?: string;
|
|
8566
|
+
/**
|
|
8567
|
+
* On-disk size of {@link mmprojPath}, read from the file rather than the
|
|
8568
|
+
* manifest. `approxSizeBytes` does NOT include the projector — the value
|
|
8569
|
+
* recorded at install time is the weights alone whenever the payload was
|
|
8570
|
+
* adopted or resumed rather than freshly downloaded — so every memory
|
|
8571
|
+
* estimate has to add this explicitly or it under-reserves a vision model
|
|
8572
|
+
* by the projector plus its compute buffers (1.7 GB on muse-glimmer).
|
|
8573
|
+
*/
|
|
8574
|
+
mmprojSizeBytes?: number;
|
|
8061
8575
|
/**
|
|
8062
8576
|
* Absolute path to a speculative-decoding companion GGUF, when the
|
|
8063
8577
|
* catalog ships one. The launcher forwards it as
|
|
@@ -8096,15 +8610,20 @@ interface InstalledLlamaCppModel {
|
|
|
8096
8610
|
*/
|
|
8097
8611
|
readOnly?: boolean;
|
|
8098
8612
|
/**
|
|
8099
|
-
* True when the catalog now
|
|
8100
|
-
*
|
|
8101
|
-
*
|
|
8102
|
-
*
|
|
8613
|
+
* True when the catalog now describes a different PAYLOAD than the one on
|
|
8614
|
+
* disk — a newer build whose bytes this copy does not have. Lets the model
|
|
8615
|
+
* manager offer "Update" (fetch what differs, replace in place) instead of
|
|
8616
|
+
* forcing the user to delete and re-fetch. A catalog version bump that
|
|
8617
|
+
* leaves the files alone (retuning, sizing hints, wording) deliberately
|
|
8618
|
+
* does not set this: the runtime resolves that metadata live, so there is
|
|
8619
|
+
* nothing for the user to download. Computed in
|
|
8103
8620
|
* {@link LlamaCppModelManager.listInstalled} against the live catalog.
|
|
8104
8621
|
*/
|
|
8105
8622
|
updateAvailable?: boolean;
|
|
8106
8623
|
/** The catalog's current version, when it differs from the installed one. */
|
|
8107
8624
|
availableVersion?: string;
|
|
8625
|
+
/** What changed, in one sentence, for the model manager's tooltip. */
|
|
8626
|
+
updateReason?: string;
|
|
8108
8627
|
}
|
|
8109
8628
|
type InstallEvent = {
|
|
8110
8629
|
type: 'progress';
|
|
@@ -8300,6 +8819,19 @@ declare class LlamaCppModelManager {
|
|
|
8300
8819
|
* needs the `contextWindow` to set `--ctx-size` correctly.
|
|
8301
8820
|
*/
|
|
8302
8821
|
resolveModel(id: string): Promise<InstalledLlamaCppModel | null>;
|
|
8822
|
+
/**
|
|
8823
|
+
* Whether a genuinely newer build of one installed model exists. Null when
|
|
8824
|
+
* the id isn't installed for this engine. Shared with the chat manager's
|
|
8825
|
+
* per-session staleness notice so a user is never told to re-download for a
|
|
8826
|
+
* change that only touched metadata.
|
|
8827
|
+
*/
|
|
8828
|
+
getUpdateStatus(id: string): Promise<ModelUpdateStatus | null>;
|
|
8829
|
+
/**
|
|
8830
|
+
* Compare one installed copy against the live catalog. The catalog lookup
|
|
8831
|
+
* runs for every model on every inventory poll; the manifest re-read only
|
|
8832
|
+
* happens for the few whose version actually moved.
|
|
8833
|
+
*/
|
|
8834
|
+
private evaluateDrift;
|
|
8303
8835
|
delete(id: string): Promise<void>;
|
|
8304
8836
|
/** Provider-owned snapshot used by the streaming `.gezmodel` exporter. */
|
|
8305
8837
|
getModelBundleSource(id: string): Promise<ModelBundleSource>;
|
|
@@ -8335,6 +8867,19 @@ declare class LlamaCppModelManager {
|
|
|
8335
8867
|
* cleanup with each early `return` and silently rot.
|
|
8336
8868
|
*/
|
|
8337
8869
|
private runInstall;
|
|
8870
|
+
/**
|
|
8871
|
+
* Files the plan asks for that are already on disk as exactly the bytes the
|
|
8872
|
+
* catalog pins, keyed by filename with the digest to carry forward.
|
|
8873
|
+
*
|
|
8874
|
+
* An update usually rotates one thing — a quant, one shard, an added draft
|
|
8875
|
+
* companion — and re-fetching the rest is pure waste. The install manifest
|
|
8876
|
+
* records a sha256 for every file it published, each verified against the
|
|
8877
|
+
* catalog when it landed; where that digest equals the pin we are about to
|
|
8878
|
+
* download and the file is still its full length, the bytes on disk ARE the
|
|
8879
|
+
* bytes we would fetch. Same trust model as the shared-store adoption cache:
|
|
8880
|
+
* a recorded digest plus an unchanged stat is identity.
|
|
8881
|
+
*/
|
|
8882
|
+
private planReusableFiles;
|
|
8338
8883
|
/** Warn once per model directory per process, then stay quiet. */
|
|
8339
8884
|
private warnSkip;
|
|
8340
8885
|
private loadInstalled;
|
|
@@ -8436,6 +8981,55 @@ interface RemotesRegistry {
|
|
|
8436
8981
|
touch(remoteId: string): void;
|
|
8437
8982
|
}
|
|
8438
8983
|
|
|
8984
|
+
interface ExternalTranscriptToolCall {
|
|
8985
|
+
id: string;
|
|
8986
|
+
name: string;
|
|
8987
|
+
arguments: string;
|
|
8988
|
+
}
|
|
8989
|
+
interface ExternalTranscriptMessage {
|
|
8990
|
+
role: 'system' | 'developer' | 'user' | 'assistant' | 'tool';
|
|
8991
|
+
content: string;
|
|
8992
|
+
toolCalls?: ExternalTranscriptToolCall[];
|
|
8993
|
+
toolCallId?: string;
|
|
8994
|
+
}
|
|
8995
|
+
interface BeginExternalConversationInput {
|
|
8996
|
+
sourceId: string;
|
|
8997
|
+
sourceName: string;
|
|
8998
|
+
externalConversationId: string;
|
|
8999
|
+
workingDirectory?: string;
|
|
9000
|
+
projectHint?: string;
|
|
9001
|
+
gezelId: string;
|
|
9002
|
+
providerName: ProviderName;
|
|
9003
|
+
model?: string;
|
|
9004
|
+
messages: ExternalTranscriptMessage[];
|
|
9005
|
+
/** Effective prompt and tool roster that were actually supplied this request. */
|
|
9006
|
+
effectiveSystemMessage: string;
|
|
9007
|
+
toolNames: string[];
|
|
9008
|
+
/** Receipt block injected into the model-facing final tool result, when any. */
|
|
9009
|
+
actionLedger?: string;
|
|
9010
|
+
}
|
|
9011
|
+
interface ResolveExternalConversationInput {
|
|
9012
|
+
sourceId: string;
|
|
9013
|
+
gezelId: string;
|
|
9014
|
+
messages: ExternalTranscriptMessage[];
|
|
9015
|
+
/** Unique id for a genuinely new thread, normally the caller's request id. */
|
|
9016
|
+
fallbackExternalConversationId: string;
|
|
9017
|
+
}
|
|
9018
|
+
interface ExternalConversationFinish {
|
|
9019
|
+
content: string;
|
|
9020
|
+
reasoning?: string;
|
|
9021
|
+
finishReason: 'stop' | 'tool_calls' | 'length';
|
|
9022
|
+
}
|
|
9023
|
+
interface ExternalConversationTurn {
|
|
9024
|
+
sessionId: string;
|
|
9025
|
+
projectId: string;
|
|
9026
|
+
onContentDelta(content: string): void;
|
|
9027
|
+
onReasoningDelta(content: string): void;
|
|
9028
|
+
onToolArgsDelta(name: string, content: string): void;
|
|
9029
|
+
finish(result: ExternalConversationFinish): Promise<void>;
|
|
9030
|
+
fail(error: unknown): Promise<void>;
|
|
9031
|
+
}
|
|
9032
|
+
|
|
8439
9033
|
/**
|
|
8440
9034
|
* In-memory per-session progress telemetry. Counts the live signals the
|
|
8441
9035
|
* chat layer already observes — streamed deltas, wire pulses, heartbeats,
|
|
@@ -8523,6 +9117,17 @@ interface TaskBudgetSnapshot {
|
|
|
8523
9117
|
inputTokens: number;
|
|
8524
9118
|
}
|
|
8525
9119
|
|
|
9120
|
+
/**
|
|
9121
|
+
* The slice of `WorkspaceIndexManager` the reference parser needs. Narrowed
|
|
9122
|
+
* to a structural type so the dependency stays one-way — the indexer already
|
|
9123
|
+
* takes this manager, and importing its class here would close the loop.
|
|
9124
|
+
*/
|
|
9125
|
+
interface WorkspaceFileSource {
|
|
9126
|
+
readFiles(projectId: string): Promise<Array<{
|
|
9127
|
+
path: string;
|
|
9128
|
+
}>>;
|
|
9129
|
+
}
|
|
9130
|
+
|
|
8526
9131
|
type TurnMessageOrigin = 'direct-user' | 'question-answer' | 'cross-gezel' | 'background-nudge' | 'system';
|
|
8527
9132
|
interface GateScriptDiagnostic {
|
|
8528
9133
|
scriptName: string;
|
|
@@ -8994,6 +9599,7 @@ declare class ChatManager {
|
|
|
8994
9599
|
private readonly activeMemoryExtractions;
|
|
8995
9600
|
private readonly store;
|
|
8996
9601
|
private readonly events;
|
|
9602
|
+
private readonly externalConversations;
|
|
8997
9603
|
private readonly memory;
|
|
8998
9604
|
private readonly historyManager?;
|
|
8999
9605
|
private readonly catalog;
|
|
@@ -9065,6 +9671,22 @@ declare class ChatManager {
|
|
|
9065
9671
|
*/
|
|
9066
9672
|
setContentIndex(index: ContentIndex): void;
|
|
9067
9673
|
private contentIndexRef?;
|
|
9674
|
+
/**
|
|
9675
|
+
* Workspace file index, used to recognize workspace paths an assistant
|
|
9676
|
+
* reply named in prose. Injected by `service.ts` after both exist (the
|
|
9677
|
+
* indexer takes this manager as a dependency, so the wiring points both
|
|
9678
|
+
* ways). When unset — unit tests, and any project the indexer has not
|
|
9679
|
+
* reached — the reference parser sees artifacts only, which is exactly
|
|
9680
|
+
* its pre-workspace behavior.
|
|
9681
|
+
*/
|
|
9682
|
+
setWorkspaceIndex(index: WorkspaceFileSource): void;
|
|
9683
|
+
private workspaceIndexRef?;
|
|
9684
|
+
/**
|
|
9685
|
+
* The project's indexed workspace paths. Reads the indexer's persisted
|
|
9686
|
+
* listing rather than walking the tree — a turn must never pay for a
|
|
9687
|
+
* recursive stat of a repo checkout just to linkify a filename.
|
|
9688
|
+
*/
|
|
9689
|
+
private workspaceInventory;
|
|
9068
9690
|
/**
|
|
9069
9691
|
* Wire the Keurmeester supervision engine. Set by `service.ts` after
|
|
9070
9692
|
* both exist (the KeurmeesterManager needs `oneShotCompletion`, so
|
|
@@ -9112,6 +9734,39 @@ declare class ChatManager {
|
|
|
9112
9734
|
*/
|
|
9113
9735
|
private resolveEffectiveContextWindow;
|
|
9114
9736
|
private resolveEffectiveSessionModel;
|
|
9737
|
+
/** The on-device model store backing a local provider, when one is wired. */
|
|
9738
|
+
private localModelStore;
|
|
9739
|
+
/** Dead pins already repinned this process, keyed `provider\0deadModelId`. */
|
|
9740
|
+
private readonly repinnedDeadDefaults;
|
|
9741
|
+
/**
|
|
9742
|
+
* Substitute an installed model for a local model id the engine cannot
|
|
9743
|
+
* serve.
|
|
9744
|
+
*
|
|
9745
|
+
* A `config.defaultModel` pin can name weights that never landed — first-run
|
|
9746
|
+
* pins the hardware recommendation *before* the download, so an abandoned
|
|
9747
|
+
* multi-gigabyte fetch leaves the install pointing at a phantom model. The
|
|
9748
|
+
* pooled-router path catches that with `ModelNotInstalledError`, but the
|
|
9749
|
+
* machine-engine path forwards whatever string it is handed straight to the
|
|
9750
|
+
* broker, which answers `model_not_loaded` on every turn including the
|
|
9751
|
+
* background one-shots. Chat is then dead until someone edits config.json by
|
|
9752
|
+
* hand, because the Settings picker that would fix it stays hidden while
|
|
9753
|
+
* fewer than two models are installed.
|
|
9754
|
+
*
|
|
9755
|
+
* Deliberately additive: with nothing installed to fall back to, the id
|
|
9756
|
+
* passes through unchanged so the existing downstream errors (and the
|
|
9757
|
+
* first-run download banner) behave exactly as before. We only intervene
|
|
9758
|
+
* when we have something strictly better to offer.
|
|
9759
|
+
*/
|
|
9760
|
+
private ensureServableLocalModel;
|
|
9761
|
+
/**
|
|
9762
|
+
* Persist a substitution when the dead id was the install default, so the
|
|
9763
|
+
* repair outlives the turn and Settings, the engine pill, and the session
|
|
9764
|
+
* switcher stop disagreeing about which model is in play. A dead value that
|
|
9765
|
+
* came from gezel frontmatter or a capability route is substituted for this
|
|
9766
|
+
* turn but left in place — rewriting someone's explicit pin is a bigger
|
|
9767
|
+
* decision than keeping chat alive.
|
|
9768
|
+
*/
|
|
9769
|
+
private repinDeadDefaultModel;
|
|
9115
9770
|
/**
|
|
9116
9771
|
* List the chat models a paired server offers, namespaced for A
|
|
9117
9772
|
* (`remote:<remoteId>/<model>`). Used by the model picker. Returns [] if the
|
|
@@ -9206,10 +9861,19 @@ declare class ChatManager {
|
|
|
9206
9861
|
projectId: string;
|
|
9207
9862
|
createdAt: string;
|
|
9208
9863
|
title: string;
|
|
9209
|
-
providerName: "
|
|
9864
|
+
providerName: "mlx" | "ds4" | "llama-cpp" | "ollama" | "copilot" | "openai" | "anthropic" | "anthropic-cli" | "codex-cli" | "remote";
|
|
9210
9865
|
lastActivityAt: string;
|
|
9211
9866
|
taskRef?: string | undefined;
|
|
9212
9867
|
stepId?: string | undefined;
|
|
9868
|
+
source?: {
|
|
9869
|
+
kind: "external";
|
|
9870
|
+
appId: string;
|
|
9871
|
+
appName: string;
|
|
9872
|
+
externalConversationId: string;
|
|
9873
|
+
readOnly: true;
|
|
9874
|
+
workingDirectory?: string | undefined;
|
|
9875
|
+
projectHint?: string | undefined;
|
|
9876
|
+
} | undefined;
|
|
9213
9877
|
model?: string | undefined;
|
|
9214
9878
|
archived?: boolean | undefined;
|
|
9215
9879
|
lastTurnError?: string | undefined;
|
|
@@ -9461,6 +10125,13 @@ declare class ChatManager {
|
|
|
9461
10125
|
*/
|
|
9462
10126
|
interruptWithMessage(sessionId: string, userText: string): Promise<ChatMessage>;
|
|
9463
10127
|
getSessionRecord(sessionId: string): Promise<ChatSession | null>;
|
|
10128
|
+
/**
|
|
10129
|
+
* Begin one request in a caller-owned conversation loop (Pi, OpenCode, or VS Code).
|
|
10130
|
+
* The recorder reconciles the caller's authoritative transcript into a
|
|
10131
|
+
* read-only Gezel session and returns live-event hooks for this response.
|
|
10132
|
+
*/
|
|
10133
|
+
beginExternalConversation(input: BeginExternalConversationInput): Promise<ExternalConversationTurn>;
|
|
10134
|
+
resolveExternalConversationId(input: ResolveExternalConversationInput): Promise<string>;
|
|
9464
10135
|
/**
|
|
9465
10136
|
* The set of tool names a session's active craftbook pre-authorizes
|
|
9466
10137
|
* (its `autoAllow` toolsets' tools). The Claude-CLI permission broker
|
|
@@ -9489,11 +10160,10 @@ declare class ChatManager {
|
|
|
9489
10160
|
* effort). Surfaced via `GET /api/sessions/:id/debug` and consumed
|
|
9490
10161
|
* by the UI's debug-mode "copy debug bundle" button.
|
|
9491
10162
|
*
|
|
9492
|
-
*
|
|
9493
|
-
*
|
|
9494
|
-
*
|
|
9495
|
-
*
|
|
9496
|
-
* or local-model-tuning rules show up immediately.
|
|
10163
|
+
* Native sessions re-run `buildSessionOpts` because the *current* prompt
|
|
10164
|
+
* matters when investigating "why did the model do X right now". External
|
|
10165
|
+
* mirrors instead surface the latest captured caller-owned request; a native
|
|
10166
|
+
* Gezel prompt reconstructed later is not execution evidence for that loop.
|
|
9497
10167
|
*
|
|
9498
10168
|
* `atMessageTimestamp`: when set (ISO string from `ChatMessage.at`),
|
|
9499
10169
|
* slice messages whose `at <= atMessageTimestamp` so the bundle
|
|
@@ -9512,8 +10182,26 @@ declare class ChatManager {
|
|
|
9512
10182
|
* test teardown (or a graceful process exit) races them.
|
|
9513
10183
|
*/
|
|
9514
10184
|
trackBackground(promise: Promise<unknown>): void;
|
|
9515
|
-
/**
|
|
9516
|
-
|
|
10185
|
+
/**
|
|
10186
|
+
* Await every currently-tracked background promise, then return.
|
|
10187
|
+
*
|
|
10188
|
+
* Bounded, because every caller is a shutdown path and the work being
|
|
10189
|
+
* awaited can legitimately take minutes. A first run creates the Meester
|
|
10190
|
+
* and kicks off its about.md + icon generation; if the configured provider
|
|
10191
|
+
* cannot answer — no credential, a cold cloud session — those one-shots sit
|
|
10192
|
+
* on their own 120s budget while this loop waits. Unbounded, that stalls
|
|
10193
|
+
* `service.stop()`, and neither the Electron quit coordinator nor an
|
|
10194
|
+
* embedded caller imposes a deadline of its own, so the window simply hangs.
|
|
10195
|
+
* Wild-caught as an intermittent 60s teardown timeout in
|
|
10196
|
+
* `security-compliance.spec.ts` once its home stopped inheriting a
|
|
10197
|
+
* machine-shared roster and started genuinely provisioning a Meester.
|
|
10198
|
+
*
|
|
10199
|
+
* Abandoning a task is safe here: these are fire-and-forget writes whose
|
|
10200
|
+
* own error handling already runs independently of this await. The warning
|
|
10201
|
+
* names the count so a real shutdown stall stays diagnosable instead of
|
|
10202
|
+
* looking like a clean exit.
|
|
10203
|
+
*/
|
|
10204
|
+
drainBackground(timeoutMs?: number): Promise<void>;
|
|
9517
10205
|
createSession(args: {
|
|
9518
10206
|
gezelId: string;
|
|
9519
10207
|
projectId?: string;
|
|
@@ -10362,9 +11050,22 @@ declare class ChatManager {
|
|
|
10362
11050
|
* Tear down cached sessions, tool bridges, and provider engines so the
|
|
10363
11051
|
* next session picks up new config.
|
|
10364
11052
|
*
|
|
10365
|
-
* Default (hard) mode
|
|
10366
|
-
* credential / provider / endpoint
|
|
10367
|
-
*
|
|
11053
|
+
* Default (hard) mode disconnects every session and disposes every tool
|
|
11054
|
+
* bridge immediately — correct for credential / provider / endpoint /
|
|
11055
|
+
* security-boundary changes, where the old session state and the old MCP
|
|
11056
|
+
* children are unusable and must go now.
|
|
11057
|
+
*
|
|
11058
|
+
* What it does NOT do is kill resident local engines. A pooled engine is
|
|
11059
|
+
* a model process keyed by (provider, modelId, replica): it carries no
|
|
11060
|
+
* credentials and no tool surface, so no config change makes the *process*
|
|
11061
|
+
* unsafe — only the sessions and bridges around it. `engines: 'force'`
|
|
11062
|
+
* (service shutdown, emergency stop) force-evicts the pool without waiting
|
|
11063
|
+
* for in-flight turns; the default `'release-idle'` frees every engine
|
|
11064
|
+
* that is not mid-turn and leaves busy ones to the pool's ordinary
|
|
11065
|
+
* LRU/idle lifecycle. Wild-caught: flipping the security posture in
|
|
11066
|
+
* Settings force-killed both resident 27B models, and a background
|
|
11067
|
+
* craftbook turn four minutes into its first step died with "the
|
|
11068
|
+
* on-device engine dropped the connection", which reads as a crash.
|
|
10368
11069
|
*
|
|
10369
11070
|
* `deferBusy` mode is for pure model-preference changes (default chat
|
|
10370
11071
|
* model, reasoning effort), where the only thing that needs to flow
|
|
@@ -10382,6 +11083,8 @@ declare class ChatManager {
|
|
|
10382
11083
|
resetClient(opts?: {
|
|
10383
11084
|
deferBusy?: boolean;
|
|
10384
11085
|
restoreSeededProviders?: boolean;
|
|
11086
|
+
/** See method doc. Defaults to `'release-idle'` — never severs a live turn. */
|
|
11087
|
+
engines?: 'release-idle' | 'force';
|
|
10385
11088
|
}): Promise<void>;
|
|
10386
11089
|
/**
|
|
10387
11090
|
* Stop admitting work and actively unwind every live turn while the HTTP
|
|
@@ -10481,6 +11184,8 @@ declare class ChatManager {
|
|
|
10481
11184
|
* expansion) — those must keep today's plain-background behavior.
|
|
10482
11185
|
*/
|
|
10483
11186
|
ambient?: boolean;
|
|
11187
|
+
/** Override the background default for explicitly user-awaited utility work. */
|
|
11188
|
+
lane?: Lane;
|
|
10484
11189
|
/**
|
|
10485
11190
|
* Live streaming hooks for callers that surface progress (the
|
|
10486
11191
|
* transform dialog's metacommentary feed). `onDelta` is the
|
|
@@ -10568,6 +11273,12 @@ declare class ChatManager {
|
|
|
10568
11273
|
* immediately). No-op when the session isn't mid-turn.
|
|
10569
11274
|
*/
|
|
10570
11275
|
recordSessionIntent(scope: PublishScope, label: string): void;
|
|
11276
|
+
/**
|
|
11277
|
+
* External sessions never enter `states`, so the ordinary post-send memory
|
|
11278
|
+
* hook cannot see them. Re-read their durable transcript and use the same
|
|
11279
|
+
* cadence, ambient lane, cursor, and debounce policy as first-party chats.
|
|
11280
|
+
*/
|
|
11281
|
+
private scheduleExternalMemoryExtraction;
|
|
10571
11282
|
/**
|
|
10572
11283
|
* Whether the post-turn memory extraction should fire now. The
|
|
10573
11284
|
* cadence depends on how heavyweight the provider's one-shot path
|
|
@@ -10666,6 +11377,20 @@ declare class ChatManager {
|
|
|
10666
11377
|
* a test seam) and is deliberately left alone.
|
|
10667
11378
|
*/
|
|
10668
11379
|
private shutdownOwnedEngineRouter;
|
|
11380
|
+
/**
|
|
11381
|
+
* Free the memory a live reset can free without severing anything: evict
|
|
11382
|
+
* every resident engine that is idle right now and leave the rest to the
|
|
11383
|
+
* pool's ordinary lifecycle. The router itself stays — dropping it while an
|
|
11384
|
+
* engine is still serving a turn would orphan that process outside the
|
|
11385
|
+
* broker's accounting, which is the reason the old path force-killed
|
|
11386
|
+
* everything instead.
|
|
11387
|
+
*
|
|
11388
|
+
* An explicitly injected {@link engineRouter} remains caller-owned and is
|
|
11389
|
+
* left alone, same rule as {@link shutdownOwnedEngineRouter}. A router
|
|
11390
|
+
* whose construction is still in flight owns no resident engines yet, so
|
|
11391
|
+
* this deliberately does not await it.
|
|
11392
|
+
*/
|
|
11393
|
+
private releaseIdleOwnedEngines;
|
|
10669
11394
|
/**
|
|
10670
11395
|
* Resolve (or build) the router. Returns `null` only when no local
|
|
10671
11396
|
* provider is wired up at all (cloud-only installs); production
|
|
@@ -10892,8 +11617,17 @@ declare class ChatManager {
|
|
|
10892
11617
|
* pool replica. This is the broker-side half of remote admission: focusing a
|
|
10893
11618
|
* chat needs the live memory clamp so the user daemon can size its prompt,
|
|
10894
11619
|
* but it must not load the model or evict somebody else's resident engine.
|
|
10895
|
-
|
|
10896
|
-
|
|
11620
|
+
*
|
|
11621
|
+
* `standalone` is for callers writing the answer somewhere durable rather
|
|
11622
|
+
* than spending it on one turn. Live pricing charges the model for whatever
|
|
11623
|
+
* else happens to be resident, so a preview taken while another engine is
|
|
11624
|
+
* warm collapses to the local context floor — fine for a decision
|
|
11625
|
+
* made and discarded in the same second, wrong for a config file read back
|
|
11626
|
+
* days later. See {@link previewLocalEnginePlan}'s `standalone` note.
|
|
11627
|
+
*/
|
|
11628
|
+
previewContextWindowForModel(name: LocalProviderName, modelId: string, opts?: {
|
|
11629
|
+
standalone?: boolean;
|
|
11630
|
+
}): Promise<number | undefined>;
|
|
10897
11631
|
/**
|
|
10898
11632
|
* Reservations held by models OTHER than the one being previewed.
|
|
10899
11633
|
*
|
|
@@ -11025,6 +11759,20 @@ declare class ChatManager {
|
|
|
11025
11759
|
* could do — so the launch config, not the catalog tag, is the source.
|
|
11026
11760
|
*/
|
|
11027
11761
|
private resolveTurnVisionContext;
|
|
11762
|
+
/**
|
|
11763
|
+
* Shared-library documents bearing on THIS message.
|
|
11764
|
+
*
|
|
11765
|
+
* The turn-1 recall snapshot is frozen for the session (per the KV-cache
|
|
11766
|
+
* rationale on `record.recall`), so a topic that arrives later — "what's
|
|
11767
|
+
* our refund policy" on turn eight — would otherwise reach the model with
|
|
11768
|
+
* no retrieval at all. This runs on the user-message channel instead,
|
|
11769
|
+
* where per-turn content belongs.
|
|
11770
|
+
*
|
|
11771
|
+
* Quiet by construction: real user turns only, a high score floor, and a
|
|
11772
|
+
* per-session dedupe so the same document is offered once and then left
|
|
11773
|
+
* alone. No hits means no prelude and no tokens.
|
|
11774
|
+
*/
|
|
11775
|
+
private resolveTurnLibraryRecall;
|
|
11028
11776
|
private resolveUserPromptPrelude;
|
|
11029
11777
|
/**
|
|
11030
11778
|
* Get or build the live state for a session. On first use after process
|
|
@@ -12073,6 +12821,23 @@ declare class GitManager {
|
|
|
12073
12821
|
private withLock;
|
|
12074
12822
|
}
|
|
12075
12823
|
|
|
12824
|
+
type QuotaReserveRule = 'overall' | 'per-day';
|
|
12825
|
+
/** Why one bucket failed the reserve check (provider attached by the gate). */
|
|
12826
|
+
interface QuotaReserveViolation {
|
|
12827
|
+
/** Provider bucket id that tripped the reserve (e.g. "premium_interactions"). */
|
|
12828
|
+
bucket: string;
|
|
12829
|
+
/** Derived remaining, 0-100, one decimal. */
|
|
12830
|
+
remainingPercent: number;
|
|
12831
|
+
/** Effective floor that triggered the hold, 0-100, one decimal. */
|
|
12832
|
+
floorPercent: number;
|
|
12833
|
+
/** Which enabled rule produced the winning floor ('overall' on ties). */
|
|
12834
|
+
rule: QuotaReserveRule;
|
|
12835
|
+
resetDate?: string;
|
|
12836
|
+
}
|
|
12837
|
+
interface QuotaReserveHold extends QuotaReserveViolation {
|
|
12838
|
+
provider: ProviderName;
|
|
12839
|
+
}
|
|
12840
|
+
|
|
12076
12841
|
/**
|
|
12077
12842
|
* TaskRunner
|
|
12078
12843
|
*
|
|
@@ -12157,8 +12922,12 @@ interface PendingHandoff {
|
|
|
12157
12922
|
* activated during the day is filed as scheduled work immediately,
|
|
12158
12923
|
* rather than counting as a backlog item for the up-to-one-tick window
|
|
12159
12924
|
* before the first `tick` reads it back off disk.
|
|
12925
|
+
*
|
|
12926
|
+
* `'night-quota'` — the shift is ON but this handoff's resolved provider
|
|
12927
|
+
* is inside the configured cloud quota reserve; re-checked every tick so
|
|
12928
|
+
* a mid-window quota reset releases it.
|
|
12160
12929
|
*/
|
|
12161
|
-
heldFor?: 'night-shift' | 'provider-busy';
|
|
12930
|
+
heldFor?: 'night-shift' | 'night-quota' | 'provider-busy';
|
|
12162
12931
|
}
|
|
12163
12932
|
/** One side of the pending split — see {@link TaskRunner.snapshot}. */
|
|
12164
12933
|
interface TaskHandoffBucket {
|
|
@@ -12262,6 +13031,13 @@ interface TaskRunnerOptions {
|
|
|
12262
13031
|
* the engine. Defaults to never-active.
|
|
12263
13032
|
*/
|
|
12264
13033
|
isIndexCatchUpActive?: () => boolean;
|
|
13034
|
+
/**
|
|
13035
|
+
* Quota-reserve verdict for a night handoff's resolved provider. A
|
|
13036
|
+
* non-null hold keeps the handoff on the queue (`heldFor: 'night-quota'`)
|
|
13037
|
+
* without touching in-flight turns — admission-only, like every other
|
|
13038
|
+
* gate here. Defaults to always-allow.
|
|
13039
|
+
*/
|
|
13040
|
+
nightQuotaHold?: (provider: ProviderName) => Promise<QuotaReserveHold | null>;
|
|
12265
13041
|
}
|
|
12266
13042
|
declare class TaskRunner {
|
|
12267
13043
|
private readonly store;
|
|
@@ -12271,6 +13047,7 @@ declare class TaskRunner {
|
|
|
12271
13047
|
private readonly isNightShiftActive;
|
|
12272
13048
|
private readonly isNightShiftPending;
|
|
12273
13049
|
private readonly isIndexCatchUpActive;
|
|
13050
|
+
private readonly nightQuotaHold;
|
|
12274
13051
|
private readonly pending;
|
|
12275
13052
|
private readonly activeDispatches;
|
|
12276
13053
|
private nextId;
|
|
@@ -12403,6 +13180,14 @@ declare class WorkspaceIndexManager {
|
|
|
12403
13180
|
/** Per-project promise chain so two concurrent scans on the same
|
|
12404
13181
|
* project serialize rather than racing on the disk. */
|
|
12405
13182
|
private readonly locks;
|
|
13183
|
+
/**
|
|
13184
|
+
* Parsed `files.json` per project, revalidated against the file's own
|
|
13185
|
+
* mtime + size so it can never go stale. `files.json` runs to megabytes
|
|
13186
|
+
* on a real checkout and its readers are all hot — terminal path
|
|
13187
|
+
* autocomplete on every keystroke, the chat reference parser on every
|
|
13188
|
+
* turn, the timeline backfill on every page.
|
|
13189
|
+
*/
|
|
13190
|
+
private readonly filesCache;
|
|
12406
13191
|
private startupTimer;
|
|
12407
13192
|
private tickTimer;
|
|
12408
13193
|
constructor(opts: WorkspaceIndexManagerOptions);
|
|
@@ -12440,7 +13225,7 @@ declare class WorkspaceIndexManager {
|
|
|
12440
13225
|
* autocomplete. The index stores files only, so directories are derived:
|
|
12441
13226
|
* each match collapses to its next path segment after the prefix — a
|
|
12442
13227
|
* directory (trailing `/`, so the user can descend) or the full file path.
|
|
12443
|
-
* Reads the cached file list (capped at
|
|
13228
|
+
* Reads the cached file list (capped at 20,000 files by the indexer).
|
|
12444
13229
|
* Case-insensitive prefix; deduped; capped.
|
|
12445
13230
|
*/
|
|
12446
13231
|
searchWorkspaceFiles(projectId: string, prefix: string, limit?: number): Promise<string[]>;
|
|
@@ -12486,6 +13271,7 @@ declare class WorkspaceIndexManager {
|
|
|
12486
13271
|
private readMetaFromDisk;
|
|
12487
13272
|
private isStale;
|
|
12488
13273
|
private mruIndex;
|
|
13274
|
+
private isSharedLibrary;
|
|
12489
13275
|
/**
|
|
12490
13276
|
* Missing preserves the historical indexed-by-default behavior. Reads the
|
|
12491
13277
|
* live project each time so toggling the setting takes effect without a
|
|
@@ -13085,6 +13871,7 @@ declare class IndexEnrichmentManager {
|
|
|
13085
13871
|
* awaited) and then wakes the TaskRunner still gets the dispatch hold.
|
|
13086
13872
|
*/
|
|
13087
13873
|
catchUpAll(): Promise<void>;
|
|
13874
|
+
private isSharedLibrary;
|
|
13088
13875
|
private runDrive;
|
|
13089
13876
|
/** Exposed for tests: run one batch ignoring the timers (still idle-gated). */
|
|
13090
13877
|
tick(): Promise<void>;
|
|
@@ -13104,17 +13891,11 @@ interface SessionSearchHit {
|
|
|
13104
13891
|
lastActivityAt: string;
|
|
13105
13892
|
archived: boolean;
|
|
13106
13893
|
}
|
|
13107
|
-
interface DocumentSearchHit {
|
|
13108
|
-
path: string;
|
|
13109
|
-
lineStart: number;
|
|
13110
|
-
snippet: string;
|
|
13111
|
-
}
|
|
13112
13894
|
interface GlobalIndexStatus {
|
|
13113
13895
|
available: boolean;
|
|
13114
13896
|
sessions: number;
|
|
13115
13897
|
history: number;
|
|
13116
13898
|
historyBackfilledAt: string | null;
|
|
13117
|
-
documents: number;
|
|
13118
13899
|
}
|
|
13119
13900
|
declare class GlobalIndex {
|
|
13120
13901
|
private readonly home;
|
|
@@ -13130,7 +13911,6 @@ declare class GlobalIndex {
|
|
|
13130
13911
|
* falls back to the JSONL scan.
|
|
13131
13912
|
*/
|
|
13132
13913
|
searchHistory(filter?: HistoryFilter): Promise<HistoryEvent[] | null>;
|
|
13133
|
-
searchDocuments(q: string, maxResults?: number): Promise<DocumentSearchHit[]>;
|
|
13134
13914
|
status(): Promise<GlobalIndexStatus>;
|
|
13135
13915
|
}
|
|
13136
13916
|
|
|
@@ -13151,44 +13931,6 @@ declare class IndexingJobControl {
|
|
|
13151
13931
|
private noteAuthor;
|
|
13152
13932
|
}
|
|
13153
13933
|
|
|
13154
|
-
interface ActivityTrackerOptions {
|
|
13155
|
-
store: Store;
|
|
13156
|
-
history: HistoryManager;
|
|
13157
|
-
chatEvents: ChatEventBus;
|
|
13158
|
-
now?: () => number;
|
|
13159
|
-
persistThresholdMs?: number;
|
|
13160
|
-
}
|
|
13161
|
-
declare class ActivityTracker {
|
|
13162
|
-
private readonly store;
|
|
13163
|
-
private readonly history;
|
|
13164
|
-
private readonly chatEvents;
|
|
13165
|
-
private readonly now;
|
|
13166
|
-
private readonly persistThresholdMs;
|
|
13167
|
-
/** Newest observed stamp per project (ms epoch). */
|
|
13168
|
-
private readonly latest;
|
|
13169
|
-
/** Stamp last written to (or read from) disk per project. */
|
|
13170
|
-
private readonly persisted;
|
|
13171
|
-
/** Projects whose on-disk stamp has been loaded into `persisted`. */
|
|
13172
|
-
private readonly loads;
|
|
13173
|
-
private readonly writing;
|
|
13174
|
-
private unsubs;
|
|
13175
|
-
constructor(opts: ActivityTrackerOptions);
|
|
13176
|
-
start(): void;
|
|
13177
|
-
stop(): Promise<void>;
|
|
13178
|
-
stamp(projectId: string, atMs: number): void;
|
|
13179
|
-
/**
|
|
13180
|
-
* Newest known activity for a project — max of the in-memory stamp
|
|
13181
|
-
* and the on-disk one (loaded once). Null when the project has never
|
|
13182
|
-
* been observed.
|
|
13183
|
-
*/
|
|
13184
|
-
lastActivityAt(projectId: string): Promise<string | null>;
|
|
13185
|
-
/** Persist every stamp that is newer than its on-disk value. */
|
|
13186
|
-
flush(): Promise<void>;
|
|
13187
|
-
private maybePersist;
|
|
13188
|
-
private write;
|
|
13189
|
-
private ensureLoaded;
|
|
13190
|
-
}
|
|
13191
|
-
|
|
13192
13934
|
type StatusOneShot = (prompt: string, timeoutMs: number, opts: {
|
|
13193
13935
|
gezelId: string;
|
|
13194
13936
|
jobLabel: string;
|
|
@@ -13439,6 +14181,26 @@ interface ChatModelInstallRegistries {
|
|
|
13439
14181
|
mlx: MlxChatInstallRegistry;
|
|
13440
14182
|
}
|
|
13441
14183
|
|
|
14184
|
+
interface OpenCodeSetupManager {
|
|
14185
|
+
status(): Promise<OpenCodeSetupStatusResponse>;
|
|
14186
|
+
configure(input: ConfigureOpenCodeRequest): Promise<OpenCodeSetupStatusResponse>;
|
|
14187
|
+
installPlugin(input: InstallOpenCodePluginRequest): Promise<OpenCodeSetupStatusResponse>;
|
|
14188
|
+
removePlugin(): Promise<OpenCodeSetupStatusResponse>;
|
|
14189
|
+
remove(): Promise<OpenCodeSetupStatusResponse>;
|
|
14190
|
+
reconcile(): Promise<void>;
|
|
14191
|
+
stop(): Promise<void>;
|
|
14192
|
+
}
|
|
14193
|
+
|
|
14194
|
+
interface PiSetupManager {
|
|
14195
|
+
status(): Promise<PiSetupStatusResponse>;
|
|
14196
|
+
configure(input: ConfigurePiRequest): Promise<PiSetupStatusResponse>;
|
|
14197
|
+
installExtension(input: InstallPiExtensionRequest): Promise<PiSetupStatusResponse>;
|
|
14198
|
+
removeExtension(): Promise<PiSetupStatusResponse>;
|
|
14199
|
+
remove(): Promise<PiSetupStatusResponse>;
|
|
14200
|
+
reconcile(): Promise<void>;
|
|
14201
|
+
stop(): Promise<void>;
|
|
14202
|
+
}
|
|
14203
|
+
|
|
13442
14204
|
/**
|
|
13443
14205
|
* AudioProvider — service-side abstractions for speech-to-text (STT)
|
|
13444
14206
|
* and text-to-speech (TTS).
|
|
@@ -14145,6 +14907,11 @@ interface InstalledVideoModelInfo {
|
|
|
14145
14907
|
name: string;
|
|
14146
14908
|
approxSizeBytes: number;
|
|
14147
14909
|
installedAt: string;
|
|
14910
|
+
/**
|
|
14911
|
+
* True when the model lives in the read-only machine asset store, so
|
|
14912
|
+
* `deleteModel` would refuse it and the UI must not offer Delete.
|
|
14913
|
+
*/
|
|
14914
|
+
readOnly?: boolean;
|
|
14148
14915
|
}
|
|
14149
14916
|
/**
|
|
14150
14917
|
* Multi-file pull progress. Mirrors `MlxInstallEvent` (video models are
|
|
@@ -14592,6 +15359,36 @@ declare class SearchService {
|
|
|
14592
15359
|
private merge;
|
|
14593
15360
|
}
|
|
14594
15361
|
|
|
15362
|
+
/**
|
|
15363
|
+
* Tracks the one storage operation allowed to run at a time.
|
|
15364
|
+
*
|
|
15365
|
+
* Cleanup, backup, and restore all walk and rewrite the same directories, so
|
|
15366
|
+
* running two at once means one job measuring or archiving a tree the other
|
|
15367
|
+
* is deleting. The HTTP layer rejects a second start rather than trying to
|
|
15368
|
+
* interleave them, matching how the folder-move worker guards itself.
|
|
15369
|
+
*/
|
|
15370
|
+
declare class StorageJobManager {
|
|
15371
|
+
private readonly jobs;
|
|
15372
|
+
create(kind: StorageJobKind, totals?: {
|
|
15373
|
+
totalItems?: number;
|
|
15374
|
+
totalBytes?: number;
|
|
15375
|
+
}): StorageJob;
|
|
15376
|
+
get(id: string): StorageJob | undefined;
|
|
15377
|
+
hasActive(): boolean;
|
|
15378
|
+
/**
|
|
15379
|
+
* Ask the worker to stop at its next item boundary. Deletion is not undone
|
|
15380
|
+
* — whatever already went is gone — so this bounds the damage rather than
|
|
15381
|
+
* reversing it, and the job still reports what it freed.
|
|
15382
|
+
*/
|
|
15383
|
+
requestCancel(id: string): boolean;
|
|
15384
|
+
update(id: string, patch: Partial<StorageJob>): void;
|
|
15385
|
+
setPhase(id: string, phase: StorageJobPhase, currentLabel?: string): void;
|
|
15386
|
+
finish(id: string, outcome: {
|
|
15387
|
+
error?: string;
|
|
15388
|
+
cancelled?: boolean;
|
|
15389
|
+
}): void;
|
|
15390
|
+
}
|
|
15391
|
+
|
|
14595
15392
|
/**
|
|
14596
15393
|
* The pinned system-toolset list.
|
|
14597
15394
|
*
|
|
@@ -14880,6 +15677,24 @@ interface NightShiftManagerOptions {
|
|
|
14880
15677
|
intervalMs?: number;
|
|
14881
15678
|
/** Clock override for tests. */
|
|
14882
15679
|
now?: () => Date;
|
|
15680
|
+
/** Quota-reserve verdicts (NightShiftQuotaGate); absent = never hold. */
|
|
15681
|
+
quotaGate?: {
|
|
15682
|
+
holdFor(provider: ProviderName): Promise<QuotaReserveHold | null>;
|
|
15683
|
+
};
|
|
15684
|
+
/**
|
|
15685
|
+
* Night-aware provider resolution — the same `chat.providerForGezel`
|
|
15686
|
+
* closure the runner's dispatcher uses, so classification here and
|
|
15687
|
+
* admission there cannot disagree. Absent = the gate never applies.
|
|
15688
|
+
*/
|
|
15689
|
+
resolveProviderName?: (gezelId: string, opts?: {
|
|
15690
|
+
nightShift?: boolean;
|
|
15691
|
+
}) => Promise<ProviderName>;
|
|
15692
|
+
}
|
|
15693
|
+
/** Why pending night work is parked, summarized for status surfaces. */
|
|
15694
|
+
interface NightShiftQuotaHoldStatus {
|
|
15695
|
+
heldTaskCount: number;
|
|
15696
|
+
/** One reason per affected provider. */
|
|
15697
|
+
reasons: QuotaReserveHold[];
|
|
14883
15698
|
}
|
|
14884
15699
|
/**
|
|
14885
15700
|
* Owns the Night Shift ON/OFF state. Lifecycle mirrors `TaskScheduler` /
|
|
@@ -14893,6 +15708,12 @@ interface NightShiftManagerOptions {
|
|
|
14893
15708
|
* pending night-shift tasks remain, then reverts to scheduled logic.
|
|
14894
15709
|
* - SCHEDULED: outside the window → off (latch cleared); window open but
|
|
14895
15710
|
* no pending work → latch off for the rest of THIS window; otherwise on.
|
|
15711
|
+
* - QUOTA-HELD: pending work whose resolved provider is inside the cloud
|
|
15712
|
+
* quota reserve doesn't keep a shift alive. All pending work held →
|
|
15713
|
+
* off WITHOUT latching (parked, not drained) so a mid-window quota
|
|
15714
|
+
* reset re-activates on a later tick; a manual request survives the
|
|
15715
|
+
* hold and resumes by itself. `quotaHoldStatus()` names the parked
|
|
15716
|
+
* state for the UI.
|
|
14896
15717
|
*
|
|
14897
15718
|
* Consumers read `isActive()` synchronously: `TaskRunner` (dispatch gating
|
|
14898
15719
|
* + priority), `TaskScheduler` (cron-spawn gating), `IndexEnrichmentManager`
|
|
@@ -14904,10 +15725,14 @@ declare class NightShiftManager {
|
|
|
14904
15725
|
private readonly events;
|
|
14905
15726
|
private readonly intervalMs;
|
|
14906
15727
|
private readonly now;
|
|
15728
|
+
private readonly quotaGate?;
|
|
15729
|
+
private readonly resolveProviderName?;
|
|
14907
15730
|
private timer;
|
|
14908
15731
|
private ticking;
|
|
14909
15732
|
private active;
|
|
14910
15733
|
private src;
|
|
15734
|
+
/** When the running shift began; null while nothing is running. */
|
|
15735
|
+
private startedAt;
|
|
14911
15736
|
/** Window key we've drained-and-latched off for; cleared next window. */
|
|
14912
15737
|
private latchedOffForWindowKey;
|
|
14913
15738
|
/** Whether a manual ("go to lunch") shift has been requested. */
|
|
@@ -14920,11 +15745,44 @@ declare class NightShiftManager {
|
|
|
14920
15745
|
private enabled;
|
|
14921
15746
|
/** Window config from the last tick — drives the synchronous day-key. */
|
|
14922
15747
|
private window;
|
|
15748
|
+
/** Quota-reserve hold summary from the last tick; null when nothing is held. */
|
|
15749
|
+
private quotaHold;
|
|
15750
|
+
/** Refs of pending night tasks the quota reserve is holding, per last tick. */
|
|
15751
|
+
private quotaHeldRefs;
|
|
14923
15752
|
constructor(opts: NightShiftManagerOptions);
|
|
14924
15753
|
start(): void;
|
|
14925
15754
|
stop(): void;
|
|
14926
15755
|
isActive(): boolean;
|
|
14927
15756
|
source(): NightShiftSource;
|
|
15757
|
+
/**
|
|
15758
|
+
* When the running shift began, or null when nothing is running. This is
|
|
15759
|
+
* the ON edge, not the window's opening hour: a scheduled shift starts on
|
|
15760
|
+
* the tick that turned it on, which is later than `startHour` whenever the
|
|
15761
|
+
* machine was asleep or the work only arrived mid-window. A shift that
|
|
15762
|
+
* changes source mid-run (a scheduled window taking over from a manual
|
|
15763
|
+
* one) keeps its original start — it never stopped running.
|
|
15764
|
+
*/
|
|
15765
|
+
startedAtIso(): string | null;
|
|
15766
|
+
/**
|
|
15767
|
+
* The scheduled window status surfaces name: the one open right now, else
|
|
15768
|
+
* the next one due. Null while the feature is switched off — nothing is
|
|
15769
|
+
* scheduled, so there is no window to name. Uses the window config cached
|
|
15770
|
+
* from the last tick.
|
|
15771
|
+
*/
|
|
15772
|
+
windowBounds(): {
|
|
15773
|
+
start: string;
|
|
15774
|
+
end: string;
|
|
15775
|
+
open: boolean;
|
|
15776
|
+
} | null;
|
|
15777
|
+
/**
|
|
15778
|
+
* Why pending night work is parked by the cloud quota reserve, as of the
|
|
15779
|
+
* last tick — null when nothing is held. Non-null both while the shift
|
|
15780
|
+
* runs with a subset held (mixed providers) and while it sits fully
|
|
15781
|
+
* parked (active=false, no latch) waiting for a quota window to reset.
|
|
15782
|
+
*/
|
|
15783
|
+
quotaHoldStatus(): NightShiftQuotaHoldStatus | null;
|
|
15784
|
+
/** Refs of the pending night tasks currently held by the quota reserve. */
|
|
15785
|
+
quotaHeldTaskRefs(): ReadonlySet<string>;
|
|
14928
15786
|
/**
|
|
14929
15787
|
* Whether the configured nightly window is open right now — used by the
|
|
14930
15788
|
* scheduler to confine a night-shift cron host's spawning to the window
|
|
@@ -14995,8 +15853,15 @@ declare class NightShiftManager {
|
|
|
14995
15853
|
* exposes the same set for the UI's "what's the shift doing?" panel.
|
|
14996
15854
|
*/
|
|
14997
15855
|
listPendingTasks(): Promise<Task[]>;
|
|
14998
|
-
/**
|
|
14999
|
-
|
|
15856
|
+
/**
|
|
15857
|
+
* Partition pending night tasks into dispatchable vs quota-held using
|
|
15858
|
+
* the same provider resolution the runner's dispatcher applies (night
|
|
15859
|
+
* override included). Optimistic on every failure path: a task whose
|
|
15860
|
+
* owner or provider can't resolve counts dispatchable — the runner
|
|
15861
|
+
* drops it later, and counting it held would wrongly deactivate the
|
|
15862
|
+
* shift. Verdicts are memoized per provider per pass.
|
|
15863
|
+
*/
|
|
15864
|
+
private classifyPending;
|
|
15000
15865
|
/** Active night-shift tasks pending `todayKey`, in `manager.list` order. */
|
|
15001
15866
|
private pendingNightShiftTasks;
|
|
15002
15867
|
/** Single transition chokepoint: diff, broadcast, log. */
|
|
@@ -15509,6 +16374,14 @@ declare class TerminalManager {
|
|
|
15509
16374
|
private collectListingFileReferences;
|
|
15510
16375
|
}
|
|
15511
16376
|
|
|
16377
|
+
interface VSCodeSetupManager {
|
|
16378
|
+
status(): Promise<VSCodeSetupStatusResponse>;
|
|
16379
|
+
configure(input: ConfigureVSCodeRequest): Promise<VSCodeSetupStatusResponse>;
|
|
16380
|
+
remove(): Promise<VSCodeSetupStatusResponse>;
|
|
16381
|
+
reconcile(): Promise<void>;
|
|
16382
|
+
stop(): Promise<void>;
|
|
16383
|
+
}
|
|
16384
|
+
|
|
15512
16385
|
interface OllamaEmulationStatus {
|
|
15513
16386
|
listening: boolean;
|
|
15514
16387
|
port?: number;
|
|
@@ -15550,6 +16423,12 @@ interface ServiceContext {
|
|
|
15550
16423
|
* manual run.
|
|
15551
16424
|
*/
|
|
15552
16425
|
meesterStatus: MeesterStatusGenerator;
|
|
16426
|
+
/**
|
|
16427
|
+
* The meester's ambient dashboard (PNG workshop snapshots under
|
|
16428
|
+
* `~/.gezel/ambient/`). In context so `/api/ambient-dashboard` can
|
|
16429
|
+
* report status and kick manual runs.
|
|
16430
|
+
*/
|
|
16431
|
+
ambientDashboard: AmbientDashboardGenerator;
|
|
15553
16432
|
scriptRunner: ScriptRunner;
|
|
15554
16433
|
catalog: CatalogService;
|
|
15555
16434
|
/**
|
|
@@ -15713,6 +16592,12 @@ interface ServiceContext {
|
|
|
15713
16592
|
ollamaEmulation: OllamaEmulationController;
|
|
15714
16593
|
/** Gezel-owned Codex profile, credential, and loopback bridge lifecycle. */
|
|
15715
16594
|
codexSetup: CodexSetupManager;
|
|
16595
|
+
/** Gezel-owned OpenCode config, credential, and loopback bridge lifecycle. */
|
|
16596
|
+
opencodeSetup: OpenCodeSetupManager;
|
|
16597
|
+
/** Gezel-owned pi extension, model list, credential, and loopback bridge lifecycle. */
|
|
16598
|
+
piSetup: PiSetupManager;
|
|
16599
|
+
/** VS Code custom endpoint, scoped credential, profile merge, and bridge lifecycle. */
|
|
16600
|
+
vscodeSetup: VSCodeSetupManager;
|
|
15716
16601
|
/**
|
|
15717
16602
|
* Hex SHA-256 of the daemon's current TLS cert DER, when serving HTTPS.
|
|
15718
16603
|
* `/v1/identity` signs this with the device identity key so a paired client
|
|
@@ -15743,6 +16628,13 @@ interface ServiceContext {
|
|
|
15743
16628
|
* (the worker writes a sentinel file so the next boot can detect a
|
|
15744
16629
|
* crashed mid-move). */
|
|
15745
16630
|
folderJobs: JobManager;
|
|
16631
|
+
/** In-memory tracker for the one storage cleanup/backup/restore job that
|
|
16632
|
+
* may run at a time. Same lifetime as `folderJobs`, and mutually
|
|
16633
|
+
* exclusive with it — both rewrite the same directories. */
|
|
16634
|
+
storageJobs: StorageJobManager;
|
|
16635
|
+
/** Drop the cached model inventory after cleanup deletes model files, so
|
|
16636
|
+
* listings stop advertising models that are no longer on disk. */
|
|
16637
|
+
invalidateModelsCache?: (provider?: ProviderName) => void;
|
|
15746
16638
|
/** Background workspace indexer: commands + files + token index. */
|
|
15747
16639
|
workspaceIndex: WorkspaceIndexManager;
|
|
15748
16640
|
/** Content index (code/doc intelligence) backing the code-intel MCP tools. */
|
|
@@ -15847,6 +16739,16 @@ interface StartServiceOptions {
|
|
|
15847
16739
|
codexHome?: string;
|
|
15848
16740
|
/** Exact Codex bridge port override (`0` = ephemeral); production derives one from `home`. */
|
|
15849
16741
|
codexBridgePort?: number;
|
|
16742
|
+
/** Exact OpenCode bridge port override (`0` = ephemeral); production derives one from `home`. */
|
|
16743
|
+
opencodeBridgePort?: number;
|
|
16744
|
+
/** Override pi's fixed loopback bridge port. Tests bind ephemeral ports. */
|
|
16745
|
+
piBridgePort?: number;
|
|
16746
|
+
/** Override pi's own agent directory. Tests must never write to a real one. */
|
|
16747
|
+
piAgentDir?: string;
|
|
16748
|
+
/** Override VS Code's fixed loopback bridge port. Tests bind ephemeral ports. */
|
|
16749
|
+
vscodeBridgePort?: number;
|
|
16750
|
+
/** Override VS Code's User/profile directory. Tests must never write to a real one. */
|
|
16751
|
+
vscodeUserDir?: string;
|
|
15850
16752
|
}
|
|
15851
16753
|
interface RunningService {
|
|
15852
16754
|
context: ServiceContext;
|