@bendyline/gezel-service 1.0.4 → 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 +16929 -6105
- 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 +4 -7
- 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 +1165 -253
- package/dist/index.js +16922 -6098
- package/dist/providers/mlx/python/gezel_mlx_server.py +126 -11
- package/dist/ui/assets/{TerminalCodeEditor-BuMcfTS4.js → TerminalCodeEditor-BUHpk3pJ.js} +2 -2
- package/dist/ui/assets/{_.contribution-CZO2XAKt.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-BJzhk0Zj.js → cpp.contribution-CvG4GFxL.js} +1 -1
- package/dist/ui/assets/{csharp.contribution-BR9K2qKj.js → csharp.contribution-DekWAPj3.js} +1 -1
- package/dist/ui/assets/{css.contribution-CfkVmdah.js → css.contribution-CDuF4Xjo.js} +1 -1
- package/dist/ui/assets/{cssMode-MMeGUmV2.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-IZMl57B5.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-BxCBwhZs.js → go.contribution-D_1myt_B.js} +1 -1
- package/dist/ui/assets/{handlebars-CreIkams.js → handlebars-Mxcy9PWv.js} +1 -1
- package/dist/ui/assets/{handlebars.contribution-BGlyL-dm.js → handlebars.contribution-DYF5z0XX.js} +2 -2
- package/dist/ui/assets/{html-BSrz1IKi.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-CucOMFQ_.js → html.contribution-C0xFTPDL.js} +2 -2
- package/dist/ui/assets/{htmlMode-DRG7XY5Z.js → htmlMode-BVtBWJQM.js} +1 -1
- package/dist/ui/assets/{index-Bqu-32S3.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-CGX5OdXM.js → ini.contribution-BqUQ8Oa0.js} +1 -1
- package/dist/ui/assets/{java.contribution-CVhfJ_us.js → java.contribution-u4QvI2UZ.js} +1 -1
- package/dist/ui/assets/{javascript-QelFp9t5.js → javascript-BVm8fvMk.js} +1 -1
- package/dist/ui/assets/javascript.contribution-BtlENuoy.js +2 -0
- package/dist/ui/assets/{jsonMode-T4Ss3lDu.js → jsonMode-DcoSB4Jg.js} +1 -1
- package/dist/ui/assets/{kotlin.contribution-DxFbGDYA.js → kotlin.contribution-D1ZfW5lW.js} +1 -1
- package/dist/ui/assets/{less.contribution-g9R8XRZf.js → less.contribution-BBWek5Gc.js} +1 -1
- package/dist/ui/assets/{lua.contribution-YqDsEy8Z.js → lua.contribution-DJEpMduq.js} +1 -1
- package/dist/ui/assets/mapTheme-4TWH25FT-C2uLgUhs.js +1 -0
- package/dist/ui/assets/{markdown.contribution-DboXnPnx.js → markdown.contribution-CsVCTE0K.js} +1 -1
- package/dist/ui/assets/{monaco-BdFw56DI.js → monaco-DcZAEsIZ.js} +3 -3
- package/dist/ui/assets/{monaco-base-DrP3D13F.js → monaco-base-C-UMfHa9.js} +1 -1
- package/dist/ui/assets/{monaco-setup-QyF22y9h.js → monaco-setup-Dy_kv6Gv.js} +1 -1
- package/dist/ui/assets/{monaco.contribution-FA_ESP-W.js → monaco.contribution-BpJqoa65.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-XEpc63ty.js → monaco.contribution-BujOhotZ.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-BkqIxESv.js → monaco.contribution-DW4-UIJp.js} +2 -2
- package/dist/ui/assets/{monaco.contribution-CMzPFHtO.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-rnpik0Kk.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-CF7X5t9Q.js → python-CCiWacbd.js} +1 -1
- package/dist/ui/assets/{python.contribution-CyJGCfSq.js → python.contribution-3CThbaoI.js} +2 -2
- package/dist/ui/assets/{ruby.contribution-4ZyPGu2E.js → ruby.contribution-D3g6EADN.js} +1 -1
- package/dist/ui/assets/{rust.contribution-Cl_B3X2G.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-BO02gVLZ.js → scss.contribution-mQ_vuYxE.js} +1 -1
- package/dist/ui/assets/{shell.contribution-Dn9Y0uHs.js → shell.contribution-BLQSLx3H.js} +1 -1
- package/dist/ui/assets/{sql.contribution-Bog_5Rc8.js → sql.contribution-GScL7Mrt.js} +1 -1
- package/dist/ui/assets/{swift.contribution-CfiAr7AX.js → swift.contribution-DG__yqNr.js} +1 -1
- package/dist/ui/assets/{terminal-monaco-setup-B-EnkGiy.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-B2WuLuPL.js → tsMode-B5nM5MR7.js} +1 -1
- package/dist/ui/assets/{typescript-Bv_J1tKT.js → typescript-xiOVha1M.js} +1 -1
- package/dist/ui/assets/{typescript.contribution-CM0XQCYi.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-DMV-f4tm.js → xml-m3MSnvuD.js} +1 -1
- package/dist/ui/assets/{xml.contribution-QqmOB9gT.js → xml.contribution-bOoaS55N.js} +2 -2
- package/dist/ui/assets/{yaml-Bb6mZXY5.js → yaml-DOtMVgbb.js} +1 -1
- package/dist/ui/assets/{yaml.contribution-DCDnWhHR.js → yaml.contribution-CNCYEtwk.js} +2 -2
- package/dist/ui/index.html +14 -14
- package/package.json +13 -12
- package/dist/ui/assets/dist-8uH4DcHx.js +0 -2
- package/dist/ui/assets/dist-CFOmf7nD.js +0 -222
- package/dist/ui/assets/index-DTicLc4o.css +0 -1
- package/dist/ui/assets/javascript.contribution--no0ijCu.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:
|
|
@@ -1766,115 +2095,22 @@ declare class ChannelManager {
|
|
|
1766
2095
|
private readonly history;
|
|
1767
2096
|
private readonly debug;
|
|
1768
2097
|
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
|
-
* The early `fail()` path in `ChatManager.send` (when `ensureState` itself
|
|
1812
|
-
* fails before we have a record) doesn't know the gezelId/projectId, so it
|
|
1813
|
-
* publishes session-scoped only via `publishSessionOnly`. Project + global
|
|
1814
|
-
* subscribers don't see those failures — only the session's SSE listener
|
|
1815
|
-
* does, which is the only listener that cares about that scope.
|
|
1816
|
-
*/
|
|
1817
|
-
declare class ChatEventBus {
|
|
1818
|
-
private readonly sessionBuses;
|
|
1819
|
-
private readonly projectListeners;
|
|
1820
|
-
private readonly gezelListeners;
|
|
1821
|
-
private readonly globalListeners;
|
|
1822
|
-
publish(scope: PublishScope, event: ChatEvent): void;
|
|
1823
|
-
/**
|
|
1824
|
-
* Publish to the session bus only. Used when the manager's early-fail path
|
|
1825
|
-
* doesn't know the gezel/project to envelope (the session record itself
|
|
1826
|
-
* couldn't be loaded). Project + global subscribers never see these.
|
|
1827
|
-
*/
|
|
1828
|
-
publishSessionOnly(sessionId: string, event: ChatEvent): void;
|
|
1829
|
-
/**
|
|
1830
|
-
* Publish a project-scoped lifecycle event that has no originating
|
|
1831
|
-
* turn — e.g. `project_created`. Fans out to the project's listeners
|
|
1832
|
-
* and all global listeners, but is deliberately NOT recorded in any
|
|
1833
|
-
* session history: these are one-shot signals, not part of a
|
|
1834
|
-
* replayable transcript, so a subscriber that reconnects later must
|
|
1835
|
-
* not see them re-fired (unlike `publish`, which seeds `deliverToSession`
|
|
1836
|
-
* history that replays until the turn's `done`). `sessionId`/`gezelId`
|
|
1837
|
-
* are empty — the consumers that care (the sidebar refresh bridge)
|
|
1838
|
-
* key off the event payload, not the envelope scope.
|
|
1839
|
-
*/
|
|
1840
|
-
publishProjectEvent(projectId: string, event: ChatEvent): void;
|
|
1841
|
-
/**
|
|
1842
|
-
* Publish a project-less global lifecycle event — e.g. `night_shift`.
|
|
1843
|
-
* Reaches only the global listeners (the Meester timeline SSE the UI
|
|
1844
|
-
* subscribes to via `subscribeAll`); like `publishProjectEvent` it is
|
|
1845
|
-
* not recorded in any session history, so reconnecting subscribers do
|
|
1846
|
-
* not see it re-fired. The envelope scope fields are all empty;
|
|
1847
|
-
* consumers key off the event payload.
|
|
1848
|
-
*/
|
|
1849
|
-
publishGlobalEvent(event: ChatEvent): void;
|
|
1850
|
-
subscribe(sessionId: string, listener: SessionListener): () => void;
|
|
1851
|
-
subscribeProject(projectId: string, listener: EnvelopeListener): () => void;
|
|
1852
|
-
subscribeGezel(gezelId: string, listener: EnvelopeListener): () => void;
|
|
1853
|
-
subscribeAll(listener: EnvelopeListener): () => void;
|
|
1854
|
-
private deliverToSession;
|
|
1855
|
-
/**
|
|
1856
|
-
* Append an event to a session's replay history, keeping the buffer
|
|
1857
|
-
* lossless for the content that matters. Two rules:
|
|
1858
|
-
*
|
|
1859
|
-
* 1. Transient status pulses (`heartbeat`, `wire_pulse`) are delivered
|
|
1860
|
-
* live but never recorded — they carry no replayable content, and a
|
|
1861
|
-
* reasoning-heavy local-model turn emits enough of them to evict
|
|
1862
|
-
* real deltas out of the 500-event cap.
|
|
1863
|
-
* 2. Adjacent `delta` events coalesce into one entry. A five-minute
|
|
1864
|
-
* thinking turn streams thousands of per-token deltas; stored
|
|
1865
|
-
* individually they blow past the cap and the earliest thinking is
|
|
1866
|
-
* silently dropped on replay. Merged, a text run costs one slot no
|
|
1867
|
-
* matter how long it streamed. The stored entry is a fresh object —
|
|
1868
|
-
* the original event was already handed to live listeners and must
|
|
1869
|
-
* not be mutated.
|
|
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.
|
|
1870
2106
|
*/
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
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;
|
|
1878
2114
|
}
|
|
1879
2115
|
|
|
1880
2116
|
/**
|
|
@@ -1987,6 +2223,18 @@ type HookRunner = (hook: ActiveHook, ctx: {
|
|
|
1987
2223
|
type McpServerSpec = StdioMcpServerSpec | HttpMcpServerSpec;
|
|
1988
2224
|
interface StdioMcpServerSpec {
|
|
1989
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;
|
|
1990
2238
|
command: string;
|
|
1991
2239
|
args: string[];
|
|
1992
2240
|
env: Record<string, string>;
|
|
@@ -1995,6 +2243,8 @@ interface StdioMcpServerSpec {
|
|
|
1995
2243
|
}
|
|
1996
2244
|
interface HttpMcpServerSpec {
|
|
1997
2245
|
kind: 'http';
|
|
2246
|
+
/** Catalog toolset id — see {@link StdioMcpServerSpec.toolsetId}. */
|
|
2247
|
+
toolsetId?: string;
|
|
1998
2248
|
/**
|
|
1999
2249
|
* `streamable-http` is the current MCP HTTP transport (one URL,
|
|
2000
2250
|
* POST for messages, optional GET for SSE stream + auto-reconnect).
|
|
@@ -2283,6 +2533,20 @@ interface PromptCtx extends ModelCtx {
|
|
|
2283
2533
|
isMeester: boolean;
|
|
2284
2534
|
/** The gezel's about.md content (already loaded). */
|
|
2285
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>;
|
|
2286
2550
|
}
|
|
2287
2551
|
/**
|
|
2288
2552
|
* Context for per-turn hooks: {@link Behavior.userPromptPrelude} and
|
|
@@ -2312,6 +2576,17 @@ interface TurnCtx extends ModelCtx {
|
|
|
2312
2576
|
assistantContent: string;
|
|
2313
2577
|
/** How many continuation nudges have already fired in this user-initiated send. */
|
|
2314
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
|
+
}>;
|
|
2315
2590
|
}
|
|
2316
2591
|
/**
|
|
2317
2592
|
* Verdict returned by {@link Behavior.postTurnDetector} when a
|
|
@@ -2656,6 +2931,18 @@ interface QuotaBucket {
|
|
|
2656
2931
|
overage: number;
|
|
2657
2932
|
resetDate?: string;
|
|
2658
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
|
+
}
|
|
2659
2946
|
interface ProviderUsage {
|
|
2660
2947
|
/** Non-empty only for providers that report account quota windows. */
|
|
2661
2948
|
quotaBuckets: QuotaBucket[];
|
|
@@ -2686,8 +2973,30 @@ interface ProviderUsage {
|
|
|
2686
2973
|
* "n/a" rather than zero.
|
|
2687
2974
|
*/
|
|
2688
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;
|
|
2689
2990
|
lastUpdated: string | null;
|
|
2690
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
|
+
}
|
|
2691
3000
|
interface UsageSummary {
|
|
2692
3001
|
providers: {
|
|
2693
3002
|
copilot?: ProviderUsage;
|
|
@@ -2716,6 +3025,8 @@ declare class UsageTracker {
|
|
|
2716
3025
|
* those windows without inventing a zero-token turn or skewing totals.
|
|
2717
3026
|
*/
|
|
2718
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[];
|
|
2719
3030
|
summary(): UsageSummary;
|
|
2720
3031
|
private ensure;
|
|
2721
3032
|
}
|
|
@@ -2768,7 +3079,7 @@ type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];
|
|
|
2768
3079
|
* — no wasted work. Already-running entries abort normally via the
|
|
2769
3080
|
* same signal.
|
|
2770
3081
|
*
|
|
2771
|
-
* ## Ambient admission control (
|
|
3082
|
+
* ## Ambient admission control (foreground-capacity protection)
|
|
2772
3083
|
*
|
|
2773
3084
|
* On a local engine, a housekeeping turn (scheduler nudge, memory
|
|
2774
3085
|
* extraction, icon/about generation) occupies the GPU for minutes.
|
|
@@ -2778,17 +3089,19 @@ type CodexReasoningEffort = (typeof CODEX_REASONING_EFFORTS)[number];
|
|
|
2778
3089
|
* engine is idle while the user READS, ambient work sneaks in, and
|
|
2779
3090
|
* the user's move then waits out a 3-minute nudge turn).
|
|
2780
3091
|
*
|
|
2781
|
-
* When
|
|
2782
|
-
*
|
|
2783
|
-
*
|
|
2784
|
-
*
|
|
2785
|
-
*
|
|
2786
|
-
*
|
|
2787
|
-
*
|
|
2788
|
-
*
|
|
2789
|
-
*
|
|
2790
|
-
*
|
|
2791
|
-
*
|
|
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.
|
|
2792
3105
|
*/
|
|
2793
3106
|
type Lane = 'interactive' | 'background';
|
|
2794
3107
|
interface EnqueueRequest {
|
|
@@ -2797,9 +3110,10 @@ interface EnqueueRequest {
|
|
|
2797
3110
|
* Marks truly-deferrable housekeeping (scheduler nudges, memory
|
|
2798
3111
|
* extraction, icon/about generation, digests, night-shift chores).
|
|
2799
3112
|
* When the queue was built with {@link ProviderQueueOptions.ambientQuietMs},
|
|
2800
|
-
* ambient entries
|
|
2801
|
-
* NON-ambient activity — see "Ambient
|
|
2802
|
-
* 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
|
|
2803
3117
|
* covers anything that shouldn't cut in front of a typed chat turn,
|
|
2804
3118
|
* which includes user-facing work (checkers page reactions, mid-turn
|
|
2805
3119
|
* compaction a foreground turn awaits) that must NEVER be held.
|
|
@@ -2906,10 +3220,12 @@ interface ProviderQueueOptions {
|
|
|
2906
3220
|
maxWaitMs?: number;
|
|
2907
3221
|
/**
|
|
2908
3222
|
* Quiet window for ambient admission control — see the class header.
|
|
2909
|
-
*
|
|
2910
|
-
*
|
|
2911
|
-
*
|
|
2912
|
-
*
|
|
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
|
|
2913
3229
|
* {@link defaultAmbientQuietMs}; cloud queues leave it off.
|
|
2914
3230
|
*/
|
|
2915
3231
|
ambientQuietMs?: number;
|
|
@@ -2975,6 +3291,14 @@ declare class ProviderQueue {
|
|
|
2975
3291
|
*/
|
|
2976
3292
|
describe(): {
|
|
2977
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;
|
|
2978
3302
|
queuedInteractive: number;
|
|
2979
3303
|
queuedBackground: number;
|
|
2980
3304
|
/** Pending ambient entries currently held by the admission gate. */
|
|
@@ -3038,9 +3362,15 @@ declare class ProviderQueue {
|
|
|
3038
3362
|
*/
|
|
3039
3363
|
private maybeScheduleAmbientRecheck;
|
|
3040
3364
|
/**
|
|
3041
|
-
* True when ambient entries may dispatch
|
|
3042
|
-
*
|
|
3043
|
-
*
|
|
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.
|
|
3044
3374
|
*/
|
|
3045
3375
|
private ambientGateOpen;
|
|
3046
3376
|
/**
|
|
@@ -3818,9 +4148,10 @@ interface LLMSession {
|
|
|
3818
4148
|
onDelta(handler: (chunk: string) => void): () => void;
|
|
3819
4149
|
/**
|
|
3820
4150
|
* Subscribe to live private-reasoning deltas, streamed separately from
|
|
3821
|
-
* the visible reply so they never enter the committed body
|
|
3822
|
-
*
|
|
3823
|
-
*
|
|
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.
|
|
3824
4155
|
*/
|
|
3825
4156
|
onReasoningDelta?(handler: (chunk: string) => void): () => void;
|
|
3826
4157
|
onUsage(handler: (usage: TurnUsage) => void): () => void;
|
|
@@ -3845,7 +4176,7 @@ interface LLMSession {
|
|
|
3845
4176
|
* calls arrive whole (Ollama) or run server-side (Copilot, OpenAI)
|
|
3846
4177
|
* leave it undefined.
|
|
3847
4178
|
*/
|
|
3848
|
-
onToolArgsDelta?(handler: (name: string, chunk: string) => void): () => void;
|
|
4179
|
+
onToolArgsDelta?(handler: (name: string, chunk: string, meta?: ToolArgsDeltaMeta) => void): () => void;
|
|
3849
4180
|
/**
|
|
3850
4181
|
* Optional: subscribe to phase-announcement events. Currently only
|
|
3851
4182
|
* `CopilotSession` emits these (SDK `assistant.intent` events from
|
|
@@ -3972,6 +4303,13 @@ interface ExternalToolCall {
|
|
|
3972
4303
|
name: string;
|
|
3973
4304
|
arguments: string;
|
|
3974
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
|
+
}
|
|
3975
4313
|
/**
|
|
3976
4314
|
* Context describing one would-be batch member, passed to
|
|
3977
4315
|
* {@link BatchCapability.admit} so an engine can make a live headroom
|
|
@@ -4400,11 +4738,14 @@ declare class CapacityBroker {
|
|
|
4400
4738
|
/**
|
|
4401
4739
|
* Fallback estimate when a catalog entry lacks `residentBytes`.
|
|
4402
4740
|
* Used by callers building reservation requests from
|
|
4403
|
-
* `approxSizeBytes`.
|
|
4404
|
-
*
|
|
4741
|
+
* `approxSizeBytes`. Reflects the working-set footprint vs. on-disk
|
|
4742
|
+
* size WITHOUT any KV — every caller prices KV explicitly on top.
|
|
4405
4743
|
*
|
|
4406
|
-
* llama.cpp
|
|
4407
|
-
*
|
|
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.
|
|
4408
4749
|
*
|
|
4409
4750
|
* ds4 is special: it streams MoE experts from SSD, so its resident
|
|
4410
4751
|
* working set is bounded by the configured expert-cache budget + KV +
|
|
@@ -4413,7 +4754,9 @@ declare class CapacityBroker {
|
|
|
4413
4754
|
* conservative streaming working set so a 64GB box is never told an
|
|
4414
4755
|
* 87GB DeepSeek-V4 model "can't fit" (which is the whole point of ds4).
|
|
4415
4756
|
*/
|
|
4416
|
-
static estimateResidentBytes(engine: LocalProviderName, approxSizeBytes: number
|
|
4757
|
+
static estimateResidentBytes(engine: LocalProviderName, approxSizeBytes: number, opts?: {
|
|
4758
|
+
mmprojBytes?: number;
|
|
4759
|
+
}): number;
|
|
4417
4760
|
}
|
|
4418
4761
|
|
|
4419
4762
|
/**
|
|
@@ -4582,6 +4925,9 @@ interface PoolSnapshot {
|
|
|
4582
4925
|
*/
|
|
4583
4926
|
interface PooledQueueSummary {
|
|
4584
4927
|
running: number;
|
|
4928
|
+
/** See {@link ProviderQueue.describe}. Summed across replicas like `running`. */
|
|
4929
|
+
runningInteractive: number;
|
|
4930
|
+
runningBackground: number;
|
|
4585
4931
|
queuedInteractive: number;
|
|
4586
4932
|
queuedBackground: number;
|
|
4587
4933
|
/** Pending ambient entries held by the admission gate across replicas. */
|
|
@@ -4664,6 +5010,18 @@ declare class ProviderPool {
|
|
|
4664
5010
|
* Returns false when the engine has already gone away.
|
|
4665
5011
|
*/
|
|
4666
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[]>;
|
|
4667
5025
|
/**
|
|
4668
5026
|
* Evict a specific entry. Awaits the provider's `shutdown` so the
|
|
4669
5027
|
* disk-cache flush (Tier 1 prior plan) completes before the broker
|
|
@@ -5192,6 +5550,17 @@ declare class ContentIndex {
|
|
|
5192
5550
|
stale: number;
|
|
5193
5551
|
pending: number;
|
|
5194
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>;
|
|
5195
5564
|
/** One file's boekwachter review (`file_review` tool). */
|
|
5196
5565
|
fileReview(projectId: string, relPath: string): Promise<FileReviewResponse>;
|
|
5197
5566
|
/** Flat issue query across current-hash reviews (`list_file_issues` tool). */
|
|
@@ -5206,6 +5575,28 @@ declare class ContentIndex {
|
|
|
5206
5575
|
settleBoekwachterIssuesForTask(projectId: string, taskRef: string, outcome: 'complete' | 'canceled'): Promise<number>;
|
|
5207
5576
|
private boekwachterIssuesForPath;
|
|
5208
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>>;
|
|
5209
5600
|
readDocAsMarkdown(projectId: string, relPath: string): Promise<ReadDocAsMarkdownResponse>;
|
|
5210
5601
|
/**
|
|
5211
5602
|
* Schedule a rebuild of the project's artifacts-corpus index. Debounced per
|
|
@@ -5788,6 +6179,19 @@ interface GateCheckOutcome {
|
|
|
5788
6179
|
detail: string;
|
|
5789
6180
|
/** Machine evidence preserved from the rich CheckResults (arrays sliced to ≤10). */
|
|
5790
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;
|
|
5791
6195
|
}
|
|
5792
6196
|
interface GateCheckResult {
|
|
5793
6197
|
pass: boolean;
|
|
@@ -5875,11 +6279,17 @@ declare function gateCheckLabel(c: GateCheck): string;
|
|
|
5875
6279
|
* stage 3 — stop: pause with the full attempt trail as diagnosis.
|
|
5876
6280
|
*
|
|
5877
6281
|
* The plateau signature hashes failing-check IDENTITY (GateCheckOutcome
|
|
5878
|
-
* labels)
|
|
5879
|
-
*
|
|
5880
|
-
* lesson), while clearing
|
|
5881
|
-
*
|
|
5882
|
-
*
|
|
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.
|
|
5883
6293
|
*/
|
|
5884
6294
|
|
|
5885
6295
|
type EscalationStage = 0 | 1 | 2 | 3;
|
|
@@ -6437,14 +6847,18 @@ declare class TaskManager {
|
|
|
6437
6847
|
*/
|
|
6438
6848
|
private runCompletionGate;
|
|
6439
6849
|
/**
|
|
6440
|
-
*
|
|
6441
|
-
* workspace
|
|
6442
|
-
*
|
|
6443
|
-
*
|
|
6444
|
-
*
|
|
6445
|
-
*
|
|
6446
|
-
*
|
|
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.
|
|
6447
6860
|
*/
|
|
6861
|
+
allActiveStepsBlockedByWorkspaceWrites(projectId: string, tasks: Task[]): Promise<boolean>;
|
|
6448
6862
|
/**
|
|
6449
6863
|
* The workspace files a step must produce that no assignee is able to
|
|
6450
6864
|
* write. The proactive twin of {@link unsatisfiableWorkspaceGateFiles}:
|
|
@@ -6465,6 +6879,22 @@ declare class TaskManager {
|
|
|
6465
6879
|
* must skip the handoff — dispatching a gezel here cannot succeed.
|
|
6466
6880
|
*/
|
|
6467
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
|
+
*/
|
|
6468
6898
|
private unsatisfiableWorkspaceGateFiles;
|
|
6469
6899
|
/**
|
|
6470
6900
|
* Gate-driven loop-back: re-activate `targetId` WITHOUT completing the
|
|
@@ -6472,6 +6902,11 @@ declare class TaskManager {
|
|
|
6472
6902
|
* hook even when the target IS the gated step itself — `onReject:
|
|
6473
6903
|
* <self>` deliberately produces a fresh activation + handoff session
|
|
6474
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}.
|
|
6475
6910
|
*/
|
|
6476
6911
|
private reactivateStepForGate;
|
|
6477
6912
|
/**
|
|
@@ -6848,6 +7283,12 @@ declare class EngineRouter {
|
|
|
6848
7283
|
* Provider is fixed to the caller's chosen engine.
|
|
6849
7284
|
*/
|
|
6850
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[]>;
|
|
6851
7292
|
/** Unload one resident replica immediately, provided it is still idle. */
|
|
6852
7293
|
unloadIdle(provider: LocalProviderName, modelId: string, replicaIdx: number): Promise<boolean>;
|
|
6853
7294
|
snapshot(): PoolSnapshot;
|
|
@@ -7610,6 +8051,35 @@ interface ModelBundleSource {
|
|
|
7610
8051
|
catalogVersion?: string;
|
|
7611
8052
|
}
|
|
7612
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
|
+
|
|
7613
8083
|
interface IncompleteModelDownload {
|
|
7614
8084
|
id: string;
|
|
7615
8085
|
/** Total bytes on disk across the directory (payload + `.partial`). */
|
|
@@ -7712,6 +8182,19 @@ interface InstalledMlxModel {
|
|
|
7712
8182
|
* Delete that can only fail.
|
|
7713
8183
|
*/
|
|
7714
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;
|
|
7715
8198
|
}
|
|
7716
8199
|
/**
|
|
7717
8200
|
* Snapshot of an in-flight MLX install — same shape as
|
|
@@ -7831,6 +8314,19 @@ declare class MlxModelManager {
|
|
|
7831
8314
|
constructor(opts: MlxModelManagerOptions);
|
|
7832
8315
|
getActiveInstalls(): MlxActiveInstallSnapshot[];
|
|
7833
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;
|
|
7834
8330
|
/**
|
|
7835
8331
|
* List incomplete MLX downloads — directories that hold bytes but no
|
|
7836
8332
|
* `manifest.json`, so they never surface in {@link listInstalled}. Tagged
|
|
@@ -7878,6 +8374,14 @@ declare class MlxModelManager {
|
|
|
7878
8374
|
* worker owns the error.
|
|
7879
8375
|
*/
|
|
7880
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;
|
|
7881
8385
|
/** Warn once per model directory per process, then stay quiet. */
|
|
7882
8386
|
private warnSkip;
|
|
7883
8387
|
private loadInstalled;
|
|
@@ -8059,6 +8563,15 @@ interface InstalledLlamaCppModel {
|
|
|
8059
8563
|
* video inputs on llama-server. Absent → text-only model.
|
|
8060
8564
|
*/
|
|
8061
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;
|
|
8062
8575
|
/**
|
|
8063
8576
|
* Absolute path to a speculative-decoding companion GGUF, when the
|
|
8064
8577
|
* catalog ships one. The launcher forwards it as
|
|
@@ -8097,15 +8610,20 @@ interface InstalledLlamaCppModel {
|
|
|
8097
8610
|
*/
|
|
8098
8611
|
readOnly?: boolean;
|
|
8099
8612
|
/**
|
|
8100
|
-
* True when the catalog now
|
|
8101
|
-
*
|
|
8102
|
-
*
|
|
8103
|
-
*
|
|
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
|
|
8104
8620
|
* {@link LlamaCppModelManager.listInstalled} against the live catalog.
|
|
8105
8621
|
*/
|
|
8106
8622
|
updateAvailable?: boolean;
|
|
8107
8623
|
/** The catalog's current version, when it differs from the installed one. */
|
|
8108
8624
|
availableVersion?: string;
|
|
8625
|
+
/** What changed, in one sentence, for the model manager's tooltip. */
|
|
8626
|
+
updateReason?: string;
|
|
8109
8627
|
}
|
|
8110
8628
|
type InstallEvent = {
|
|
8111
8629
|
type: 'progress';
|
|
@@ -8301,6 +8819,19 @@ declare class LlamaCppModelManager {
|
|
|
8301
8819
|
* needs the `contextWindow` to set `--ctx-size` correctly.
|
|
8302
8820
|
*/
|
|
8303
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;
|
|
8304
8835
|
delete(id: string): Promise<void>;
|
|
8305
8836
|
/** Provider-owned snapshot used by the streaming `.gezmodel` exporter. */
|
|
8306
8837
|
getModelBundleSource(id: string): Promise<ModelBundleSource>;
|
|
@@ -8336,6 +8867,19 @@ declare class LlamaCppModelManager {
|
|
|
8336
8867
|
* cleanup with each early `return` and silently rot.
|
|
8337
8868
|
*/
|
|
8338
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;
|
|
8339
8883
|
/** Warn once per model directory per process, then stay quiet. */
|
|
8340
8884
|
private warnSkip;
|
|
8341
8885
|
private loadInstalled;
|
|
@@ -8437,6 +8981,55 @@ interface RemotesRegistry {
|
|
|
8437
8981
|
touch(remoteId: string): void;
|
|
8438
8982
|
}
|
|
8439
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
|
+
|
|
8440
9033
|
/**
|
|
8441
9034
|
* In-memory per-session progress telemetry. Counts the live signals the
|
|
8442
9035
|
* chat layer already observes — streamed deltas, wire pulses, heartbeats,
|
|
@@ -8524,6 +9117,17 @@ interface TaskBudgetSnapshot {
|
|
|
8524
9117
|
inputTokens: number;
|
|
8525
9118
|
}
|
|
8526
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
|
+
|
|
8527
9131
|
type TurnMessageOrigin = 'direct-user' | 'question-answer' | 'cross-gezel' | 'background-nudge' | 'system';
|
|
8528
9132
|
interface GateScriptDiagnostic {
|
|
8529
9133
|
scriptName: string;
|
|
@@ -8820,10 +9424,12 @@ declare class ChatManager {
|
|
|
8820
9424
|
*/
|
|
8821
9425
|
private readonly afterSessionIdle;
|
|
8822
9426
|
/**
|
|
8823
|
-
* One live async file handoff per sender/target/project/path. Models can
|
|
9427
|
+
* One live async file handoff per sender/target/project/path/intent. Models can
|
|
8824
9428
|
* emit the same `message_gezel` call several times while the sender turn
|
|
8825
9429
|
* is still active; joining that work prevents a parked-send burst from
|
|
8826
|
-
* replaying the same assignment into the recipient session.
|
|
9430
|
+
* replaying the same assignment into the recipient session. A later
|
|
9431
|
+
* validator repair for a file that was originally missing is distinct work
|
|
9432
|
+
* and must never join the older create request.
|
|
8827
9433
|
*/
|
|
8828
9434
|
private readonly inflightFileHandoffs;
|
|
8829
9435
|
/** Set once {@link shutdown} starts so deferred watchdogs don't fire into a tearing-down manager. */
|
|
@@ -8993,6 +9599,7 @@ declare class ChatManager {
|
|
|
8993
9599
|
private readonly activeMemoryExtractions;
|
|
8994
9600
|
private readonly store;
|
|
8995
9601
|
private readonly events;
|
|
9602
|
+
private readonly externalConversations;
|
|
8996
9603
|
private readonly memory;
|
|
8997
9604
|
private readonly historyManager?;
|
|
8998
9605
|
private readonly catalog;
|
|
@@ -9064,6 +9671,22 @@ declare class ChatManager {
|
|
|
9064
9671
|
*/
|
|
9065
9672
|
setContentIndex(index: ContentIndex): void;
|
|
9066
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;
|
|
9067
9690
|
/**
|
|
9068
9691
|
* Wire the Keurmeester supervision engine. Set by `service.ts` after
|
|
9069
9692
|
* both exist (the KeurmeesterManager needs `oneShotCompletion`, so
|
|
@@ -9111,6 +9734,39 @@ declare class ChatManager {
|
|
|
9111
9734
|
*/
|
|
9112
9735
|
private resolveEffectiveContextWindow;
|
|
9113
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;
|
|
9114
9770
|
/**
|
|
9115
9771
|
* List the chat models a paired server offers, namespaced for A
|
|
9116
9772
|
* (`remote:<remoteId>/<model>`). Used by the model picker. Returns [] if the
|
|
@@ -9205,10 +9861,19 @@ declare class ChatManager {
|
|
|
9205
9861
|
projectId: string;
|
|
9206
9862
|
createdAt: string;
|
|
9207
9863
|
title: string;
|
|
9208
|
-
providerName: "
|
|
9864
|
+
providerName: "mlx" | "ds4" | "llama-cpp" | "ollama" | "copilot" | "openai" | "anthropic" | "anthropic-cli" | "codex-cli" | "remote";
|
|
9209
9865
|
lastActivityAt: string;
|
|
9210
9866
|
taskRef?: string | undefined;
|
|
9211
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;
|
|
9212
9877
|
model?: string | undefined;
|
|
9213
9878
|
archived?: boolean | undefined;
|
|
9214
9879
|
lastTurnError?: string | undefined;
|
|
@@ -9460,6 +10125,13 @@ declare class ChatManager {
|
|
|
9460
10125
|
*/
|
|
9461
10126
|
interruptWithMessage(sessionId: string, userText: string): Promise<ChatMessage>;
|
|
9462
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>;
|
|
9463
10135
|
/**
|
|
9464
10136
|
* The set of tool names a session's active craftbook pre-authorizes
|
|
9465
10137
|
* (its `autoAllow` toolsets' tools). The Claude-CLI permission broker
|
|
@@ -9488,11 +10160,10 @@ declare class ChatManager {
|
|
|
9488
10160
|
* effort). Surfaced via `GET /api/sessions/:id/debug` and consumed
|
|
9489
10161
|
* by the UI's debug-mode "copy debug bundle" button.
|
|
9490
10162
|
*
|
|
9491
|
-
*
|
|
9492
|
-
*
|
|
9493
|
-
*
|
|
9494
|
-
*
|
|
9495
|
-
* 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.
|
|
9496
10167
|
*
|
|
9497
10168
|
* `atMessageTimestamp`: when set (ISO string from `ChatMessage.at`),
|
|
9498
10169
|
* slice messages whose `at <= atMessageTimestamp` so the bundle
|
|
@@ -9511,8 +10182,26 @@ declare class ChatManager {
|
|
|
9511
10182
|
* test teardown (or a graceful process exit) races them.
|
|
9512
10183
|
*/
|
|
9513
10184
|
trackBackground(promise: Promise<unknown>): void;
|
|
9514
|
-
/**
|
|
9515
|
-
|
|
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>;
|
|
9516
10205
|
createSession(args: {
|
|
9517
10206
|
gezelId: string;
|
|
9518
10207
|
projectId?: string;
|
|
@@ -9692,6 +10381,8 @@ declare class ChatManager {
|
|
|
9692
10381
|
toGezelIdOrName: string;
|
|
9693
10382
|
projectId?: string;
|
|
9694
10383
|
text: string;
|
|
10384
|
+
/** One-way feedback that must not wake the sender with the recipient's reply. */
|
|
10385
|
+
suppressReply?: boolean;
|
|
9695
10386
|
/** Internal task context for scheduler re-drives. */
|
|
9696
10387
|
taskRef?: string;
|
|
9697
10388
|
/** Exact step paired with taskRef when re-driving task work. */
|
|
@@ -10359,9 +11050,22 @@ declare class ChatManager {
|
|
|
10359
11050
|
* Tear down cached sessions, tool bridges, and provider engines so the
|
|
10360
11051
|
* next session picks up new config.
|
|
10361
11052
|
*
|
|
10362
|
-
* Default (hard) mode
|
|
10363
|
-
* credential / provider / endpoint
|
|
10364
|
-
*
|
|
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.
|
|
10365
11069
|
*
|
|
10366
11070
|
* `deferBusy` mode is for pure model-preference changes (default chat
|
|
10367
11071
|
* model, reasoning effort), where the only thing that needs to flow
|
|
@@ -10379,6 +11083,8 @@ declare class ChatManager {
|
|
|
10379
11083
|
resetClient(opts?: {
|
|
10380
11084
|
deferBusy?: boolean;
|
|
10381
11085
|
restoreSeededProviders?: boolean;
|
|
11086
|
+
/** See method doc. Defaults to `'release-idle'` — never severs a live turn. */
|
|
11087
|
+
engines?: 'release-idle' | 'force';
|
|
10382
11088
|
}): Promise<void>;
|
|
10383
11089
|
/**
|
|
10384
11090
|
* Stop admitting work and actively unwind every live turn while the HTTP
|
|
@@ -10478,6 +11184,8 @@ declare class ChatManager {
|
|
|
10478
11184
|
* expansion) — those must keep today's plain-background behavior.
|
|
10479
11185
|
*/
|
|
10480
11186
|
ambient?: boolean;
|
|
11187
|
+
/** Override the background default for explicitly user-awaited utility work. */
|
|
11188
|
+
lane?: Lane;
|
|
10481
11189
|
/**
|
|
10482
11190
|
* Live streaming hooks for callers that surface progress (the
|
|
10483
11191
|
* transform dialog's metacommentary feed). `onDelta` is the
|
|
@@ -10565,6 +11273,12 @@ declare class ChatManager {
|
|
|
10565
11273
|
* immediately). No-op when the session isn't mid-turn.
|
|
10566
11274
|
*/
|
|
10567
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;
|
|
10568
11282
|
/**
|
|
10569
11283
|
* Whether the post-turn memory extraction should fire now. The
|
|
10570
11284
|
* cadence depends on how heavyweight the provider's one-shot path
|
|
@@ -10663,6 +11377,20 @@ declare class ChatManager {
|
|
|
10663
11377
|
* a test seam) and is deliberately left alone.
|
|
10664
11378
|
*/
|
|
10665
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;
|
|
10666
11394
|
/**
|
|
10667
11395
|
* Resolve (or build) the router. Returns `null` only when no local
|
|
10668
11396
|
* provider is wired up at all (cloud-only installs); production
|
|
@@ -10889,8 +11617,17 @@ declare class ChatManager {
|
|
|
10889
11617
|
* pool replica. This is the broker-side half of remote admission: focusing a
|
|
10890
11618
|
* chat needs the live memory clamp so the user daemon can size its prompt,
|
|
10891
11619
|
* but it must not load the model or evict somebody else's resident engine.
|
|
10892
|
-
|
|
10893
|
-
|
|
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>;
|
|
10894
11631
|
/**
|
|
10895
11632
|
* Reservations held by models OTHER than the one being previewed.
|
|
10896
11633
|
*
|
|
@@ -11022,6 +11759,20 @@ declare class ChatManager {
|
|
|
11022
11759
|
* could do — so the launch config, not the catalog tag, is the source.
|
|
11023
11760
|
*/
|
|
11024
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;
|
|
11025
11776
|
private resolveUserPromptPrelude;
|
|
11026
11777
|
/**
|
|
11027
11778
|
* Get or build the live state for a session. On first use after process
|
|
@@ -12070,6 +12821,23 @@ declare class GitManager {
|
|
|
12070
12821
|
private withLock;
|
|
12071
12822
|
}
|
|
12072
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
|
+
|
|
12073
12841
|
/**
|
|
12074
12842
|
* TaskRunner
|
|
12075
12843
|
*
|
|
@@ -12154,8 +12922,12 @@ interface PendingHandoff {
|
|
|
12154
12922
|
* activated during the day is filed as scheduled work immediately,
|
|
12155
12923
|
* rather than counting as a backlog item for the up-to-one-tick window
|
|
12156
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.
|
|
12157
12929
|
*/
|
|
12158
|
-
heldFor?: 'night-shift' | 'provider-busy';
|
|
12930
|
+
heldFor?: 'night-shift' | 'night-quota' | 'provider-busy';
|
|
12159
12931
|
}
|
|
12160
12932
|
/** One side of the pending split — see {@link TaskRunner.snapshot}. */
|
|
12161
12933
|
interface TaskHandoffBucket {
|
|
@@ -12259,6 +13031,13 @@ interface TaskRunnerOptions {
|
|
|
12259
13031
|
* the engine. Defaults to never-active.
|
|
12260
13032
|
*/
|
|
12261
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>;
|
|
12262
13041
|
}
|
|
12263
13042
|
declare class TaskRunner {
|
|
12264
13043
|
private readonly store;
|
|
@@ -12268,6 +13047,7 @@ declare class TaskRunner {
|
|
|
12268
13047
|
private readonly isNightShiftActive;
|
|
12269
13048
|
private readonly isNightShiftPending;
|
|
12270
13049
|
private readonly isIndexCatchUpActive;
|
|
13050
|
+
private readonly nightQuotaHold;
|
|
12271
13051
|
private readonly pending;
|
|
12272
13052
|
private readonly activeDispatches;
|
|
12273
13053
|
private nextId;
|
|
@@ -12335,6 +13115,11 @@ declare class TaskRunner {
|
|
|
12335
13115
|
};
|
|
12336
13116
|
/** Run one serialized dispatch pass now, sharing the interval's overlap guard. */
|
|
12337
13117
|
wake(): Promise<void>;
|
|
13118
|
+
/**
|
|
13119
|
+
* Public test/operator entry point. Keep it serialized with the interval:
|
|
13120
|
+
* callers may drive a real, already-started service whose ticker is active.
|
|
13121
|
+
*/
|
|
13122
|
+
tick(): Promise<void>;
|
|
12338
13123
|
/**
|
|
12339
13124
|
* Scan every `active` task and enqueue a handoff for any whose
|
|
12340
13125
|
* current step has an effective gezel owner. Call on service boot and
|
|
@@ -12352,9 +13137,9 @@ declare class TaskRunner {
|
|
|
12352
13137
|
/**
|
|
12353
13138
|
* One dispatch pass. Walks pending in FIFO order; dispatches any
|
|
12354
13139
|
* whose target provider has a free slot; skips items for tasks
|
|
12355
|
-
* that are no longer active.
|
|
13140
|
+
* that are no longer active.
|
|
12356
13141
|
*/
|
|
12357
|
-
|
|
13142
|
+
private tickOnce;
|
|
12358
13143
|
private pruneActiveDispatches;
|
|
12359
13144
|
}
|
|
12360
13145
|
|
|
@@ -12395,6 +13180,14 @@ declare class WorkspaceIndexManager {
|
|
|
12395
13180
|
/** Per-project promise chain so two concurrent scans on the same
|
|
12396
13181
|
* project serialize rather than racing on the disk. */
|
|
12397
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;
|
|
12398
13191
|
private startupTimer;
|
|
12399
13192
|
private tickTimer;
|
|
12400
13193
|
constructor(opts: WorkspaceIndexManagerOptions);
|
|
@@ -12432,7 +13225,7 @@ declare class WorkspaceIndexManager {
|
|
|
12432
13225
|
* autocomplete. The index stores files only, so directories are derived:
|
|
12433
13226
|
* each match collapses to its next path segment after the prefix — a
|
|
12434
13227
|
* directory (trailing `/`, so the user can descend) or the full file path.
|
|
12435
|
-
* Reads the cached file list (capped at
|
|
13228
|
+
* Reads the cached file list (capped at 20,000 files by the indexer).
|
|
12436
13229
|
* Case-insensitive prefix; deduped; capped.
|
|
12437
13230
|
*/
|
|
12438
13231
|
searchWorkspaceFiles(projectId: string, prefix: string, limit?: number): Promise<string[]>;
|
|
@@ -12478,6 +13271,7 @@ declare class WorkspaceIndexManager {
|
|
|
12478
13271
|
private readMetaFromDisk;
|
|
12479
13272
|
private isStale;
|
|
12480
13273
|
private mruIndex;
|
|
13274
|
+
private isSharedLibrary;
|
|
12481
13275
|
/**
|
|
12482
13276
|
* Missing preserves the historical indexed-by-default behavior. Reads the
|
|
12483
13277
|
* live project each time so toggling the setting takes effect without a
|
|
@@ -13077,6 +13871,7 @@ declare class IndexEnrichmentManager {
|
|
|
13077
13871
|
* awaited) and then wakes the TaskRunner still gets the dispatch hold.
|
|
13078
13872
|
*/
|
|
13079
13873
|
catchUpAll(): Promise<void>;
|
|
13874
|
+
private isSharedLibrary;
|
|
13080
13875
|
private runDrive;
|
|
13081
13876
|
/** Exposed for tests: run one batch ignoring the timers (still idle-gated). */
|
|
13082
13877
|
tick(): Promise<void>;
|
|
@@ -13096,17 +13891,11 @@ interface SessionSearchHit {
|
|
|
13096
13891
|
lastActivityAt: string;
|
|
13097
13892
|
archived: boolean;
|
|
13098
13893
|
}
|
|
13099
|
-
interface DocumentSearchHit {
|
|
13100
|
-
path: string;
|
|
13101
|
-
lineStart: number;
|
|
13102
|
-
snippet: string;
|
|
13103
|
-
}
|
|
13104
13894
|
interface GlobalIndexStatus {
|
|
13105
13895
|
available: boolean;
|
|
13106
13896
|
sessions: number;
|
|
13107
13897
|
history: number;
|
|
13108
13898
|
historyBackfilledAt: string | null;
|
|
13109
|
-
documents: number;
|
|
13110
13899
|
}
|
|
13111
13900
|
declare class GlobalIndex {
|
|
13112
13901
|
private readonly home;
|
|
@@ -13122,7 +13911,6 @@ declare class GlobalIndex {
|
|
|
13122
13911
|
* falls back to the JSONL scan.
|
|
13123
13912
|
*/
|
|
13124
13913
|
searchHistory(filter?: HistoryFilter): Promise<HistoryEvent[] | null>;
|
|
13125
|
-
searchDocuments(q: string, maxResults?: number): Promise<DocumentSearchHit[]>;
|
|
13126
13914
|
status(): Promise<GlobalIndexStatus>;
|
|
13127
13915
|
}
|
|
13128
13916
|
|
|
@@ -13143,44 +13931,6 @@ declare class IndexingJobControl {
|
|
|
13143
13931
|
private noteAuthor;
|
|
13144
13932
|
}
|
|
13145
13933
|
|
|
13146
|
-
interface ActivityTrackerOptions {
|
|
13147
|
-
store: Store;
|
|
13148
|
-
history: HistoryManager;
|
|
13149
|
-
chatEvents: ChatEventBus;
|
|
13150
|
-
now?: () => number;
|
|
13151
|
-
persistThresholdMs?: number;
|
|
13152
|
-
}
|
|
13153
|
-
declare class ActivityTracker {
|
|
13154
|
-
private readonly store;
|
|
13155
|
-
private readonly history;
|
|
13156
|
-
private readonly chatEvents;
|
|
13157
|
-
private readonly now;
|
|
13158
|
-
private readonly persistThresholdMs;
|
|
13159
|
-
/** Newest observed stamp per project (ms epoch). */
|
|
13160
|
-
private readonly latest;
|
|
13161
|
-
/** Stamp last written to (or read from) disk per project. */
|
|
13162
|
-
private readonly persisted;
|
|
13163
|
-
/** Projects whose on-disk stamp has been loaded into `persisted`. */
|
|
13164
|
-
private readonly loads;
|
|
13165
|
-
private readonly writing;
|
|
13166
|
-
private unsubs;
|
|
13167
|
-
constructor(opts: ActivityTrackerOptions);
|
|
13168
|
-
start(): void;
|
|
13169
|
-
stop(): Promise<void>;
|
|
13170
|
-
stamp(projectId: string, atMs: number): void;
|
|
13171
|
-
/**
|
|
13172
|
-
* Newest known activity for a project — max of the in-memory stamp
|
|
13173
|
-
* and the on-disk one (loaded once). Null when the project has never
|
|
13174
|
-
* been observed.
|
|
13175
|
-
*/
|
|
13176
|
-
lastActivityAt(projectId: string): Promise<string | null>;
|
|
13177
|
-
/** Persist every stamp that is newer than its on-disk value. */
|
|
13178
|
-
flush(): Promise<void>;
|
|
13179
|
-
private maybePersist;
|
|
13180
|
-
private write;
|
|
13181
|
-
private ensureLoaded;
|
|
13182
|
-
}
|
|
13183
|
-
|
|
13184
13934
|
type StatusOneShot = (prompt: string, timeoutMs: number, opts: {
|
|
13185
13935
|
gezelId: string;
|
|
13186
13936
|
jobLabel: string;
|
|
@@ -13417,6 +14167,8 @@ declare class ChatModelInstallRegistry<E extends ChatInstallEventBase, O> {
|
|
|
13417
14167
|
interface GgufInstallOpts {
|
|
13418
14168
|
skipSha: boolean;
|
|
13419
14169
|
includeMmproj: boolean;
|
|
14170
|
+
/** Whether a text-only chat install should also pull the default image reader. */
|
|
14171
|
+
installCompanion: boolean;
|
|
13420
14172
|
}
|
|
13421
14173
|
interface MlxInstallOpts {
|
|
13422
14174
|
skipSha: boolean;
|
|
@@ -13429,6 +14181,26 @@ interface ChatModelInstallRegistries {
|
|
|
13429
14181
|
mlx: MlxChatInstallRegistry;
|
|
13430
14182
|
}
|
|
13431
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
|
+
|
|
13432
14204
|
/**
|
|
13433
14205
|
* AudioProvider — service-side abstractions for speech-to-text (STT)
|
|
13434
14206
|
* and text-to-speech (TTS).
|
|
@@ -14135,6 +14907,11 @@ interface InstalledVideoModelInfo {
|
|
|
14135
14907
|
name: string;
|
|
14136
14908
|
approxSizeBytes: number;
|
|
14137
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;
|
|
14138
14915
|
}
|
|
14139
14916
|
/**
|
|
14140
14917
|
* Multi-file pull progress. Mirrors `MlxInstallEvent` (video models are
|
|
@@ -14582,6 +15359,36 @@ declare class SearchService {
|
|
|
14582
15359
|
private merge;
|
|
14583
15360
|
}
|
|
14584
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
|
+
|
|
14585
15392
|
/**
|
|
14586
15393
|
* The pinned system-toolset list.
|
|
14587
15394
|
*
|
|
@@ -14870,6 +15677,24 @@ interface NightShiftManagerOptions {
|
|
|
14870
15677
|
intervalMs?: number;
|
|
14871
15678
|
/** Clock override for tests. */
|
|
14872
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[];
|
|
14873
15698
|
}
|
|
14874
15699
|
/**
|
|
14875
15700
|
* Owns the Night Shift ON/OFF state. Lifecycle mirrors `TaskScheduler` /
|
|
@@ -14883,6 +15708,12 @@ interface NightShiftManagerOptions {
|
|
|
14883
15708
|
* pending night-shift tasks remain, then reverts to scheduled logic.
|
|
14884
15709
|
* - SCHEDULED: outside the window → off (latch cleared); window open but
|
|
14885
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.
|
|
14886
15717
|
*
|
|
14887
15718
|
* Consumers read `isActive()` synchronously: `TaskRunner` (dispatch gating
|
|
14888
15719
|
* + priority), `TaskScheduler` (cron-spawn gating), `IndexEnrichmentManager`
|
|
@@ -14894,10 +15725,14 @@ declare class NightShiftManager {
|
|
|
14894
15725
|
private readonly events;
|
|
14895
15726
|
private readonly intervalMs;
|
|
14896
15727
|
private readonly now;
|
|
15728
|
+
private readonly quotaGate?;
|
|
15729
|
+
private readonly resolveProviderName?;
|
|
14897
15730
|
private timer;
|
|
14898
15731
|
private ticking;
|
|
14899
15732
|
private active;
|
|
14900
15733
|
private src;
|
|
15734
|
+
/** When the running shift began; null while nothing is running. */
|
|
15735
|
+
private startedAt;
|
|
14901
15736
|
/** Window key we've drained-and-latched off for; cleared next window. */
|
|
14902
15737
|
private latchedOffForWindowKey;
|
|
14903
15738
|
/** Whether a manual ("go to lunch") shift has been requested. */
|
|
@@ -14910,11 +15745,44 @@ declare class NightShiftManager {
|
|
|
14910
15745
|
private enabled;
|
|
14911
15746
|
/** Window config from the last tick — drives the synchronous day-key. */
|
|
14912
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;
|
|
14913
15752
|
constructor(opts: NightShiftManagerOptions);
|
|
14914
15753
|
start(): void;
|
|
14915
15754
|
stop(): void;
|
|
14916
15755
|
isActive(): boolean;
|
|
14917
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>;
|
|
14918
15786
|
/**
|
|
14919
15787
|
* Whether the configured nightly window is open right now — used by the
|
|
14920
15788
|
* scheduler to confine a night-shift cron host's spawning to the window
|
|
@@ -14985,8 +15853,15 @@ declare class NightShiftManager {
|
|
|
14985
15853
|
* exposes the same set for the UI's "what's the shift doing?" panel.
|
|
14986
15854
|
*/
|
|
14987
15855
|
listPendingTasks(): Promise<Task[]>;
|
|
14988
|
-
/**
|
|
14989
|
-
|
|
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;
|
|
14990
15865
|
/** Active night-shift tasks pending `todayKey`, in `manager.list` order. */
|
|
14991
15866
|
private pendingNightShiftTasks;
|
|
14992
15867
|
/** Single transition chokepoint: diff, broadcast, log. */
|
|
@@ -15499,6 +16374,14 @@ declare class TerminalManager {
|
|
|
15499
16374
|
private collectListingFileReferences;
|
|
15500
16375
|
}
|
|
15501
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
|
+
|
|
15502
16385
|
interface OllamaEmulationStatus {
|
|
15503
16386
|
listening: boolean;
|
|
15504
16387
|
port?: number;
|
|
@@ -15540,6 +16423,12 @@ interface ServiceContext {
|
|
|
15540
16423
|
* manual run.
|
|
15541
16424
|
*/
|
|
15542
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;
|
|
15543
16432
|
scriptRunner: ScriptRunner;
|
|
15544
16433
|
catalog: CatalogService;
|
|
15545
16434
|
/**
|
|
@@ -15703,6 +16592,12 @@ interface ServiceContext {
|
|
|
15703
16592
|
ollamaEmulation: OllamaEmulationController;
|
|
15704
16593
|
/** Gezel-owned Codex profile, credential, and loopback bridge lifecycle. */
|
|
15705
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;
|
|
15706
16601
|
/**
|
|
15707
16602
|
* Hex SHA-256 of the daemon's current TLS cert DER, when serving HTTPS.
|
|
15708
16603
|
* `/v1/identity` signs this with the device identity key so a paired client
|
|
@@ -15733,6 +16628,13 @@ interface ServiceContext {
|
|
|
15733
16628
|
* (the worker writes a sentinel file so the next boot can detect a
|
|
15734
16629
|
* crashed mid-move). */
|
|
15735
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;
|
|
15736
16638
|
/** Background workspace indexer: commands + files + token index. */
|
|
15737
16639
|
workspaceIndex: WorkspaceIndexManager;
|
|
15738
16640
|
/** Content index (code/doc intelligence) backing the code-intel MCP tools. */
|
|
@@ -15837,6 +16739,16 @@ interface StartServiceOptions {
|
|
|
15837
16739
|
codexHome?: string;
|
|
15838
16740
|
/** Exact Codex bridge port override (`0` = ephemeral); production derives one from `home`. */
|
|
15839
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;
|
|
15840
16752
|
}
|
|
15841
16753
|
interface RunningService {
|
|
15842
16754
|
context: ServiceContext;
|