@aragon-agent/cli 0.6.14 → 0.6.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +295 -238
- package/dist/agent/controller.d.ts +37 -1
- package/dist/agent/controller.js +195 -45
- package/dist/agent/plan-prompt.d.ts +1 -1
- package/dist/agent/plan-prompt.js +4 -3
- package/dist/agent/project-guidance-prompt.d.ts +4 -0
- package/dist/agent/project-guidance-prompt.js +104 -0
- package/dist/agent/reducer.d.ts +2 -0
- package/dist/agent/reducer.js +4 -0
- package/dist/agent/system-prompt.js +4 -0
- package/dist/cli.js +49 -2
- package/dist/commands/builtins.js +26 -28
- package/dist/compaction/child.d.ts +9 -1
- package/dist/compaction/child.js +39 -13
- package/dist/compaction/command.js +20 -10
- package/dist/compaction/compactor.d.ts +33 -204
- package/dist/compaction/compactor.js +311 -726
- package/dist/compaction/context-command.js +14 -3
- package/dist/compaction/digest.d.ts +15 -51
- package/dist/compaction/digest.js +113 -148
- package/dist/compaction/limits.d.ts +19 -142
- package/dist/compaction/limits.js +20 -147
- package/dist/compaction/memory-identity.d.ts +16 -0
- package/dist/compaction/memory-identity.js +63 -0
- package/dist/compaction/memory-input.d.ts +25 -0
- package/dist/compaction/memory-input.js +106 -0
- package/dist/compaction/memory-render.d.ts +4 -0
- package/dist/compaction/memory-render.js +47 -0
- package/dist/compaction/memory-validation.d.ts +21 -0
- package/dist/compaction/memory-validation.js +268 -0
- package/dist/compaction/memory.d.ts +79 -0
- package/dist/compaction/memory.js +118 -0
- package/dist/compaction/meter.d.ts +14 -10
- package/dist/compaction/meter.js +53 -19
- package/dist/compaction/operation.d.ts +18 -0
- package/dist/compaction/operation.js +68 -0
- package/dist/compaction/pressure.d.ts +5 -20
- package/dist/compaction/pressure.js +13 -23
- package/dist/compaction/summarize-call.d.ts +3 -16
- package/dist/compaction/summarize-call.js +20 -20
- package/dist/compaction/summary-prompt.d.ts +29 -66
- package/dist/compaction/summary-prompt.js +132 -178
- package/dist/compaction/types.d.ts +27 -4
- package/dist/compaction/wiring.d.ts +10 -25
- package/dist/compaction/wiring.js +56 -66
- package/dist/config/app-paths.d.ts +10 -0
- package/dist/config/app-paths.js +12 -0
- package/dist/config/env.d.ts +2 -1
- package/dist/config/env.js +13 -1
- package/dist/config/load.d.ts +9 -0
- package/dist/config/load.js +14 -0
- package/dist/config/model-windows.d.ts +91 -0
- package/dist/config/model-windows.js +181 -0
- package/dist/config/schema.d.ts +18 -1
- package/dist/config/schema.js +2 -1
- package/dist/exec/events.d.ts +8 -0
- package/dist/exec/index.js +13 -6
- package/dist/exec/runner.d.ts +8 -0
- package/dist/exec/runner.js +26 -2
- package/dist/input/csiu-keys.d.ts +66 -0
- package/dist/input/csiu-keys.js +170 -0
- package/dist/input/keyboard-enhancement.d.ts +42 -0
- package/dist/input/keyboard-enhancement.js +65 -0
- package/dist/input/stdin-filter.d.ts +9 -0
- package/dist/input/stdin-filter.js +45 -9
- package/dist/input/win32-input-mode.d.ts +61 -0
- package/dist/input/win32-input-mode.js +251 -0
- package/dist/session/persist.d.ts +3 -0
- package/dist/session/persist.js +9 -0
- package/dist/session/store.js +2 -0
- package/dist/session/validate-session.js +34 -0
- package/dist/team/subagent.js +8 -0
- package/dist/ui/App.js +218 -116
- package/dist/ui/BottomStatusRow.d.ts +5 -10
- package/dist/ui/BottomStatusRow.js +7 -11
- package/dist/ui/Composer.d.ts +4 -2
- package/dist/ui/Composer.js +2 -2
- package/dist/ui/Header.d.ts +6 -2
- package/dist/ui/Header.js +7 -6
- package/dist/ui/PromptInput.d.ts +3 -1
- package/dist/ui/PromptInput.js +32 -41
- package/dist/ui/StatusBar.d.ts +6 -0
- package/dist/ui/StatusBar.js +8 -7
- package/dist/ui/Transcript.js +1 -1
- package/dist/ui/entries/CompactionCard.d.ts +3 -1
- package/dist/ui/entries/CompactionCard.js +7 -5
- package/dist/ui/frame-differ.js +27 -0
- package/dist/ui/frame-observer.js +18 -5
- package/dist/ui/interaction-copy.d.ts +73 -73
- package/dist/ui/interaction-copy.js +30 -38
- package/dist/ui/interaction-hints.d.ts +8 -1
- package/dist/ui/interaction-hints.js +56 -69
- package/dist/ui/layout/AppShell.d.ts +6 -2
- package/dist/ui/layout/AppShell.js +2 -2
- package/dist/ui/layout/OverlayFrame.d.ts +2 -0
- package/dist/ui/layout/OverlayFrame.js +23 -14
- package/dist/ui/layout/ScrollViewport.d.ts +3 -1
- package/dist/ui/layout/ScrollViewport.js +10 -2
- package/dist/ui/layout/budget.d.ts +25 -26
- package/dist/ui/layout/budget.js +29 -22
- package/dist/ui/layout/document-layout.d.ts +2 -2
- package/dist/ui/layout/document-layout.js +2 -3
- package/dist/ui/layout/queue-layout.js +4 -4
- package/dist/ui/layout/status-detail-layout.d.ts +9 -0
- package/dist/ui/layout/status-detail-layout.js +56 -0
- package/dist/ui/layout/status-layout.d.ts +19 -2
- package/dist/ui/layout/status-layout.js +95 -84
- package/dist/ui/layout/wrap-rows.d.ts +2 -0
- package/dist/ui/layout/wrap-rows.js +21 -7
- package/dist/ui/overlays/ConfirmDialog.d.ts +2 -1
- package/dist/ui/overlays/ConfirmDialog.js +22 -3
- package/dist/ui/overlays/HelpOverlay.js +9 -2
- package/dist/ui/overlays/ModelPicker.d.ts +5 -8
- package/dist/ui/overlays/ModelPicker.js +44 -10
- package/dist/ui/overlays/ModelProfileEditor.js +2 -0
- package/dist/ui/overlays/ModelProfilePicker.d.ts +1 -0
- package/dist/ui/overlays/ModelProfilePicker.js +4 -2
- package/dist/ui/overlays/PlanReviewOverlay.d.ts +2 -1
- package/dist/ui/overlays/PlanReviewOverlay.js +7 -4
- package/dist/ui/overlays/QuestionOverlay.d.ts +2 -1
- package/dist/ui/overlays/QuestionOverlay.js +45 -32
- package/dist/ui/overlays/QueueOverlay.js +2 -2
- package/dist/ui/overlays/SettingsScreen.d.ts +1 -0
- package/dist/ui/overlays/SettingsScreen.js +10 -3
- package/dist/ui/run-metrics.d.ts +23 -0
- package/dist/ui/run-metrics.js +27 -0
- package/dist/ui/status-feedback.d.ts +33 -0
- package/dist/ui/status-feedback.js +36 -0
- package/dist/ui/stdout-frame-writer.js +28 -0
- package/package.json +2 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ModelSettingsSnapshot } from './model-profile-settings.js';
|
|
2
2
|
import type { ModelSettingsDraft, ModelSettingsPatch, ModelSettingsSaveResult } from '../config/model-profile-store.js';
|
|
3
|
+
import { type CompactionIdentity } from '../compaction/memory-identity.js';
|
|
3
4
|
/**
|
|
4
5
|
* AgentController — builds the core `Agent`, wires the built-in toolset, and
|
|
5
6
|
* exposes a small run/abort/steer surface plus the pre-flight validation that
|
|
@@ -14,6 +15,7 @@ import type { PromptOptions, PromptOutcome } from './prompt-options.js';
|
|
|
14
15
|
import { ModelRegistry, type AgentEvent, type AgentTool, type Message, type ModelInfo, type ModelRef, type ProviderRegistry, type ThinkingLevel } from '@aragon-agent/core';
|
|
15
16
|
import type { CliConfig, CompactionConfig, FastConfig, RetryConfig, TeamConfig, ThemeName, TodoConfig } from '../config/schema.js';
|
|
16
17
|
import type { ModelRole } from '../config/model-profiles.js';
|
|
18
|
+
import { ModelWindows } from '../config/model-windows.js';
|
|
17
19
|
import { type ConfirmRequest } from '../tools/index.js';
|
|
18
20
|
import type { ToolPermission } from '../exec/permission.js';
|
|
19
21
|
import { type ToolOutputListener } from '../tools/tool-output-store.js';
|
|
@@ -101,6 +103,13 @@ export interface ControllerDeps {
|
|
|
101
103
|
* once at construction and lost at the first `rebuildSystemPrompt()`.
|
|
102
104
|
*/
|
|
103
105
|
appendSystemPrompt?: string;
|
|
106
|
+
/**
|
|
107
|
+
* The per-model window table from ~/.aragon-agent/model-windows.json.
|
|
108
|
+
* Injectable so tests can hand the controller a table without writing into
|
|
109
|
+
* the shared vitest home root (app-paths.ts TEST-ISOLATION CONTRACT);
|
|
110
|
+
* production leaves it absent and the constructor builds the real one.
|
|
111
|
+
*/
|
|
112
|
+
modelWindows?: ModelWindows;
|
|
104
113
|
}
|
|
105
114
|
/** What `setAgentMode` actually adopted — see `AgentController.setAgentMode`. */
|
|
106
115
|
export interface AgentModeState {
|
|
@@ -123,6 +132,8 @@ export declare class AgentController {
|
|
|
123
132
|
private readonly agent;
|
|
124
133
|
private readonly providerRegistry;
|
|
125
134
|
private readonly modelRegistry;
|
|
135
|
+
/** Per-model user-declared context windows; see `config/model-windows.ts`. */
|
|
136
|
+
private readonly modelWindows;
|
|
126
137
|
private modelMetadataEnabled;
|
|
127
138
|
private modelMetadataGeneration;
|
|
128
139
|
private modelMetadataAbort;
|
|
@@ -188,6 +199,10 @@ export declare class AgentController {
|
|
|
188
199
|
private readonly fast;
|
|
189
200
|
private readonly compaction;
|
|
190
201
|
private settingsRevision;
|
|
202
|
+
private requestVersion;
|
|
203
|
+
private idleCompaction;
|
|
204
|
+
private restoredCompactionIdentity;
|
|
205
|
+
private readonly compactionBusyListeners;
|
|
191
206
|
private modelSettingsBlocked;
|
|
192
207
|
private preparedSystemPrompt;
|
|
193
208
|
private readonly contextMeter;
|
|
@@ -291,6 +306,7 @@ export declare class AgentController {
|
|
|
291
306
|
private waitForEngineIdle;
|
|
292
307
|
/** Prepare before clearing the plan, then enter the engine without yielding. */
|
|
293
308
|
private startPrompt;
|
|
309
|
+
private prepareUserTurn;
|
|
294
310
|
/** Cancel pending startup as well as any engine run already in progress. */
|
|
295
311
|
abort(): void;
|
|
296
312
|
private stopEngine;
|
|
@@ -379,6 +395,11 @@ export declare class AgentController {
|
|
|
379
395
|
queueUserMessage(text: string): string;
|
|
380
396
|
private enqueueSteering;
|
|
381
397
|
followUp(text: string): void;
|
|
398
|
+
/** Resume queued input without appending a duplicate user message. */
|
|
399
|
+
continue(): Promise<PromptOutcome>;
|
|
400
|
+
/** Pending user receipts survive until Core accepts or the host clears them. */
|
|
401
|
+
hasPendingUserMessages(): boolean;
|
|
402
|
+
private compactionBusyOutcome;
|
|
382
403
|
isRunning(): boolean;
|
|
383
404
|
getAgentMode(): AgentMode;
|
|
384
405
|
/**
|
|
@@ -538,6 +559,7 @@ export declare class AgentController {
|
|
|
538
559
|
isModelSettingsBusy(): boolean;
|
|
539
560
|
/** Monotonic revision protects an editor from all intervening settings changes. */
|
|
540
561
|
getSettingsRevision(): number;
|
|
562
|
+
private advanceSettingsRevision;
|
|
541
563
|
/** Read-only draft creation; no startup migration or credential copying. */
|
|
542
564
|
createModelSettingsDraft(): ModelSettingsDraft;
|
|
543
565
|
/** Save an explicit draft as a single disk/live transaction. */
|
|
@@ -596,8 +618,15 @@ export declare class AgentController {
|
|
|
596
618
|
clearMessages(): void;
|
|
597
619
|
/** Read-only view of the live system prompt (regression tests, /debug). */
|
|
598
620
|
getSystemPrompt(): string;
|
|
599
|
-
replaceMessages(messages: Message[]): void;
|
|
621
|
+
replaceMessages(messages: Message[], identity?: CompactionIdentity): void;
|
|
600
622
|
getMessages(): Message[];
|
|
623
|
+
/** Atomically capture adopted history and its host credential for serialization. */
|
|
624
|
+
getSessionSnapshot(): {
|
|
625
|
+
messages: Message[];
|
|
626
|
+
compactionIdentity?: CompactionIdentity;
|
|
627
|
+
};
|
|
628
|
+
/** Compatibility name for the documented compaction session boundary. */
|
|
629
|
+
getCompactionSessionState(): ReturnType<AgentController['getSessionSnapshot']>;
|
|
601
630
|
clearAllQueues(): void;
|
|
602
631
|
getConfig(): CliConfig;
|
|
603
632
|
getProviderRegistry(): ProviderRegistry;
|
|
@@ -759,6 +788,13 @@ export declare class AgentController {
|
|
|
759
788
|
ok: boolean;
|
|
760
789
|
reason?: string;
|
|
761
790
|
}>;
|
|
791
|
+
/** Local prepare/adopt ownership, available before any network-start event. */
|
|
792
|
+
isCompactionBusy(): boolean;
|
|
793
|
+
/** Cancel local compaction and await ownership release before a conversation switch. */
|
|
794
|
+
cancelCompaction(): Promise<void>;
|
|
795
|
+
/** Subscribe to synchronous ownership transitions; observers cannot break adoption. */
|
|
796
|
+
subscribeCompactionBusy(listener: (busy: boolean) => void): () => void;
|
|
797
|
+
private publishCompactionBusy;
|
|
762
798
|
/**
|
|
763
799
|
* Subscribe to the CLI-local compaction event stream.
|
|
764
800
|
*
|
package/dist/agent/controller.js
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { createModelSettingsDraft, saveModelSettings, reloadModelSettings, } from './model-profile-settings.js';
|
|
2
2
|
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { verifyCompactionIdentity } from '../compaction/memory-identity.js';
|
|
4
|
+
import { COMPACTION_LIMITS } from '../compaction/limits.js';
|
|
3
5
|
import { Agent, initProviders, ModelRegistry, } from '@aragon-agent/core';
|
|
4
6
|
import { clampCompactionConfig, clampFastConfig, clampRetryConfig, clampTeamConfig, clampTodoConfig, isAdapterProvider, toRetryPolicy, } from '../config/schema.js';
|
|
5
7
|
import { resolveModelProfileState } from '../config/model-profile-resolution.js';
|
|
6
8
|
import { makeGetApiKey } from '../config/load.js';
|
|
7
9
|
import { updatePersistedConfig } from '../config/store.js';
|
|
10
|
+
import { ModelWindows } from '../config/model-windows.js';
|
|
8
11
|
import { createBuiltinTools } from '../tools/index.js';
|
|
9
12
|
import { createFileChangeStore } from '../tools/file-change-store.js';
|
|
10
13
|
import { createToolOutputStore, } from '../tools/tool-output-store.js';
|
|
@@ -51,6 +54,8 @@ export class AgentController {
|
|
|
51
54
|
agent;
|
|
52
55
|
providerRegistry;
|
|
53
56
|
modelRegistry;
|
|
57
|
+
/** Per-model user-declared context windows; see `config/model-windows.ts`. */
|
|
58
|
+
modelWindows;
|
|
54
59
|
modelMetadataEnabled = false;
|
|
55
60
|
modelMetadataGeneration = 0;
|
|
56
61
|
modelMetadataAbort = new AbortController();
|
|
@@ -201,6 +206,10 @@ export class AgentController {
|
|
|
201
206
|
// and a `Set`.
|
|
202
207
|
// -----------------------------------------------------------------------
|
|
203
208
|
settingsRevision = 0;
|
|
209
|
+
requestVersion = 0;
|
|
210
|
+
idleCompaction;
|
|
211
|
+
restoredCompactionIdentity;
|
|
212
|
+
compactionBusyListeners = new Set();
|
|
204
213
|
modelSettingsBlocked = false;
|
|
205
214
|
preparedSystemPrompt;
|
|
206
215
|
contextMeter;
|
|
@@ -253,7 +262,7 @@ export class AgentController {
|
|
|
253
262
|
*/
|
|
254
263
|
abortRequested = false;
|
|
255
264
|
/** Only exact acceptance receipts release user messages from reviewer protection. */
|
|
256
|
-
pendingUserSteering = new
|
|
265
|
+
pendingUserSteering = new Map();
|
|
257
266
|
/** Session changes must not make a delayed receipt match a new message. */
|
|
258
267
|
steeringPrefix = randomUUID();
|
|
259
268
|
steeringSequence = 0;
|
|
@@ -269,6 +278,7 @@ export class AgentController {
|
|
|
269
278
|
// reuses this very registry instance.
|
|
270
279
|
this.providerRegistry = initProviders({ retryPolicy: toRetryPolicy(config.retry) });
|
|
271
280
|
this.modelRegistry = new ModelRegistry(this.providerRegistry);
|
|
281
|
+
this.modelWindows = deps.modelWindows ?? new ModelWindows();
|
|
272
282
|
this.skillsEnabled = config.skills.enabled;
|
|
273
283
|
this.onSkillsChanged = deps.onSkillsChanged;
|
|
274
284
|
this.skills = new SkillService({
|
|
@@ -530,6 +540,7 @@ export class AgentController {
|
|
|
530
540
|
// EVERY session, including one with compaction off, because that is the one
|
|
531
541
|
// whose gauge was broken (P1-4 / P0-2).
|
|
532
542
|
this.contextMeter = new ContextMeter({
|
|
543
|
+
getRequestVersion: () => this.requestVersion,
|
|
533
544
|
getMessages: () => this.agent.state.messages,
|
|
534
545
|
getSystemPrompt: () => this.agent.state.systemPrompt,
|
|
535
546
|
getModelInfo: () => this.getModelInfo(),
|
|
@@ -768,7 +779,10 @@ export class AgentController {
|
|
|
768
779
|
});
|
|
769
780
|
}
|
|
770
781
|
rebuildSystemPrompt() {
|
|
771
|
-
this.
|
|
782
|
+
const prompt = this.preparedSystemPrompt ?? this.composeSystemPrompt();
|
|
783
|
+
if (prompt !== this.agent.state.systemPrompt)
|
|
784
|
+
this.idleCompaction?.abort();
|
|
785
|
+
this.agent.setSystemPrompt(prompt);
|
|
772
786
|
}
|
|
773
787
|
/** Re-render the prompt from the current skill set and tell the UI. */
|
|
774
788
|
refreshSkills() {
|
|
@@ -799,7 +813,7 @@ export class AgentController {
|
|
|
799
813
|
* re-memoizes the palette (P1-1). Does not touch `@aragon-agent/core`.
|
|
800
814
|
*/
|
|
801
815
|
setTheme(name) {
|
|
802
|
-
this.
|
|
816
|
+
this.advanceSettingsRevision();
|
|
803
817
|
this.config = { ...this.config, theme: name };
|
|
804
818
|
}
|
|
805
819
|
/**
|
|
@@ -856,6 +870,8 @@ export class AgentController {
|
|
|
856
870
|
* never rejects, so callers must not treat resolution as success.
|
|
857
871
|
*/
|
|
858
872
|
async prompt(text, options = {}) {
|
|
873
|
+
if (this.isCompactionBusy())
|
|
874
|
+
return this.compactionBusyOutcome();
|
|
859
875
|
// Capture BEFORE stopping: synchronous abort listeners may cancel this request.
|
|
860
876
|
if (this.modelSettingsBlocked) {
|
|
861
877
|
return { status: 'not-started', reason: 'failed' };
|
|
@@ -873,6 +889,8 @@ export class AgentController {
|
|
|
873
889
|
}
|
|
874
890
|
if (this.agent.state.isRunning)
|
|
875
891
|
throw new Error('The previous run is still stopping.');
|
|
892
|
+
if (this.isCompactionBusy())
|
|
893
|
+
return this.compactionBusyOutcome();
|
|
876
894
|
return await this.startPrompt(text, options, request);
|
|
877
895
|
}
|
|
878
896
|
catch (err) {
|
|
@@ -908,10 +926,7 @@ export class AgentController {
|
|
|
908
926
|
}
|
|
909
927
|
/** Prepare before clearing the plan, then enter the engine without yielding. */
|
|
910
928
|
async startPrompt(text, options, request) {
|
|
911
|
-
|
|
912
|
-
this.skills.beginUserTurn();
|
|
913
|
-
this.askRounds = 0;
|
|
914
|
-
this.fast?.setGoal(text);
|
|
929
|
+
this.prepareUserTurn(text);
|
|
915
930
|
if (request !== this.startupSequence) {
|
|
916
931
|
return { status: 'not-started', reason: 'cancelled' };
|
|
917
932
|
}
|
|
@@ -919,9 +934,16 @@ export class AgentController {
|
|
|
919
934
|
await this.agent.prompt(text);
|
|
920
935
|
return { status: 'finished' };
|
|
921
936
|
}
|
|
937
|
+
prepareUserTurn(text) {
|
|
938
|
+
if (this.skillsEnabled)
|
|
939
|
+
this.skills.beginUserTurn();
|
|
940
|
+
this.askRounds = 0;
|
|
941
|
+
this.fast?.setGoal(text);
|
|
942
|
+
}
|
|
922
943
|
/** Cancel pending startup as well as any engine run already in progress. */
|
|
923
944
|
abort() {
|
|
924
945
|
this.startupSequence += 1;
|
|
946
|
+
this.idleCompaction?.abort();
|
|
925
947
|
this.stopEngine();
|
|
926
948
|
}
|
|
927
949
|
stopEngine() {
|
|
@@ -1066,11 +1088,11 @@ export class AgentController {
|
|
|
1066
1088
|
}
|
|
1067
1089
|
enqueueSteering(text, user) {
|
|
1068
1090
|
// Both reviewer and user guidance can activate queued skill frames.
|
|
1069
|
-
if (this.skillsEnabled)
|
|
1091
|
+
if (this.skillsEnabled && this.isRunning())
|
|
1070
1092
|
this.skills.absorbPendingFrames();
|
|
1071
1093
|
const id = user ? `${this.steeringPrefix}:${++this.steeringSequence}` : undefined;
|
|
1072
1094
|
if (id !== undefined)
|
|
1073
|
-
this.pendingUserSteering.
|
|
1095
|
+
this.pendingUserSteering.set(id, text);
|
|
1074
1096
|
try {
|
|
1075
1097
|
this.agent.steer(text, id);
|
|
1076
1098
|
}
|
|
@@ -1084,6 +1106,30 @@ export class AgentController {
|
|
|
1084
1106
|
followUp(text) {
|
|
1085
1107
|
this.agent.followUp(text);
|
|
1086
1108
|
}
|
|
1109
|
+
/** Resume queued input without appending a duplicate user message. */
|
|
1110
|
+
async continue() {
|
|
1111
|
+
if (this.isCompactionBusy())
|
|
1112
|
+
return this.compactionBusyOutcome();
|
|
1113
|
+
if (this.modelSettingsBlocked || this.isRunning()) {
|
|
1114
|
+
return { status: 'not-started', reason: 'failed' };
|
|
1115
|
+
}
|
|
1116
|
+
if (this.pendingUserSteering.size > 0) {
|
|
1117
|
+
const request = ++this.startupSequence;
|
|
1118
|
+
this.prepareUserTurn([...this.pendingUserSteering.values()].join('\n\n'));
|
|
1119
|
+
if (request !== this.startupSequence) {
|
|
1120
|
+
return { status: 'not-started', reason: 'cancelled' };
|
|
1121
|
+
}
|
|
1122
|
+
this.todos?.beginUserTurn('new-task');
|
|
1123
|
+
}
|
|
1124
|
+
await this.agent.continue();
|
|
1125
|
+
return { status: 'finished' };
|
|
1126
|
+
}
|
|
1127
|
+
/** Pending user receipts survive until Core accepts or the host clears them. */
|
|
1128
|
+
hasPendingUserMessages() { return this.pendingUserSteering.size > 0; }
|
|
1129
|
+
compactionBusyOutcome() {
|
|
1130
|
+
this.notifyHostFn?.('warn', 'Context compaction is busy; your input was not submitted.');
|
|
1131
|
+
return { status: 'not-started', reason: 'failed' };
|
|
1132
|
+
}
|
|
1087
1133
|
isRunning() {
|
|
1088
1134
|
return this.agent.state.isRunning;
|
|
1089
1135
|
}
|
|
@@ -1216,7 +1262,7 @@ export class AgentController {
|
|
|
1216
1262
|
* honestly by checking `isTeamRegistered()` first.
|
|
1217
1263
|
*/
|
|
1218
1264
|
setTeamEnabled(enabled) {
|
|
1219
|
-
this.
|
|
1265
|
+
this.advanceSettingsRevision();
|
|
1220
1266
|
this.teamEnabled = enabled;
|
|
1221
1267
|
this.rebuildSystemPrompt();
|
|
1222
1268
|
}
|
|
@@ -1230,7 +1276,7 @@ export class AgentController {
|
|
|
1230
1276
|
*/
|
|
1231
1277
|
setTeamConfig(patch) {
|
|
1232
1278
|
const team = clampTeamConfig({ ...this.config.team, ...patch });
|
|
1233
|
-
this.
|
|
1279
|
+
this.advanceSettingsRevision();
|
|
1234
1280
|
this.config = { ...this.config, team };
|
|
1235
1281
|
this.rebuildSystemPrompt();
|
|
1236
1282
|
return team;
|
|
@@ -1256,6 +1302,7 @@ export class AgentController {
|
|
|
1256
1302
|
}
|
|
1257
1303
|
/** Abort every child and clear timers. Idempotent; safe to call twice. */
|
|
1258
1304
|
dispose() {
|
|
1305
|
+
this.idleCompaction?.abort();
|
|
1259
1306
|
this.disposed = true;
|
|
1260
1307
|
this.modelMetadataGeneration += 1;
|
|
1261
1308
|
this.modelMetadataAbort.abort();
|
|
@@ -1295,7 +1342,7 @@ export class AgentController {
|
|
|
1295
1342
|
* reports that honestly by checking `isTodoRegistered()` first.
|
|
1296
1343
|
*/
|
|
1297
1344
|
setTodoEnabled(enabled) {
|
|
1298
|
-
this.
|
|
1345
|
+
this.advanceSettingsRevision();
|
|
1299
1346
|
this.todoEnabled = enabled;
|
|
1300
1347
|
this.rebuildSystemPrompt();
|
|
1301
1348
|
}
|
|
@@ -1318,7 +1365,7 @@ export class AgentController {
|
|
|
1318
1365
|
*/
|
|
1319
1366
|
setTodoConfig(patch) {
|
|
1320
1367
|
const todo = clampTodoConfig({ ...this.config.todo, ...patch });
|
|
1321
|
-
this.
|
|
1368
|
+
this.advanceSettingsRevision();
|
|
1322
1369
|
this.config = { ...this.config, todo };
|
|
1323
1370
|
this.rebuildSystemPrompt();
|
|
1324
1371
|
return todo;
|
|
@@ -1374,7 +1421,7 @@ export class AgentController {
|
|
|
1374
1421
|
*/
|
|
1375
1422
|
setRetryConfig(patch) {
|
|
1376
1423
|
const retry = clampRetryConfig({ ...this.config.retry, ...patch });
|
|
1377
|
-
this.
|
|
1424
|
+
this.advanceSettingsRevision();
|
|
1378
1425
|
this.config = { ...this.config, retry };
|
|
1379
1426
|
this.providerRegistry.setRetryPolicy(toRetryPolicy(retry));
|
|
1380
1427
|
return retry;
|
|
@@ -1384,11 +1431,16 @@ export class AgentController {
|
|
|
1384
1431
|
// -----------------------------------------------------------------------
|
|
1385
1432
|
/** True while any request can still use a model or credential snapshot. */
|
|
1386
1433
|
isModelSettingsBusy() {
|
|
1387
|
-
return this.isRunning() || this.isTeamBusy() || this.
|
|
1434
|
+
return this.isRunning() || this.isTeamBusy() || this.isCompactionBusy()
|
|
1435
|
+
|| this.getCompactionSnapshot().inFlight
|
|
1388
1436
|
|| this.getFastStatus().snapshot.inFlight;
|
|
1389
1437
|
}
|
|
1390
1438
|
/** Monotonic revision protects an editor from all intervening settings changes. */
|
|
1391
1439
|
getSettingsRevision() { return this.settingsRevision; }
|
|
1440
|
+
advanceSettingsRevision() {
|
|
1441
|
+
this.settingsRevision += 1;
|
|
1442
|
+
this.idleCompaction?.abort();
|
|
1443
|
+
}
|
|
1392
1444
|
/** Read-only draft creation; no startup migration or credential copying. */
|
|
1393
1445
|
createModelSettingsDraft() {
|
|
1394
1446
|
return createModelSettingsDraft(this.config, this.settingsRevision);
|
|
@@ -1414,10 +1466,13 @@ export class AgentController {
|
|
|
1414
1466
|
}
|
|
1415
1467
|
/** Apply prepared state synchronously, without rebuilding the controller or its history. */
|
|
1416
1468
|
applyModelSettingsSnapshot(snapshot) {
|
|
1469
|
+
const connectionChanged = this.config.provider !== snapshot.config.provider
|
|
1470
|
+
|| this.config.model !== snapshot.config.model || this.config.baseUrl !== snapshot.config.baseUrl;
|
|
1471
|
+
this.idleCompaction?.abort();
|
|
1417
1472
|
this.preparedSystemPrompt = snapshot.systemPrompt;
|
|
1418
1473
|
try {
|
|
1419
1474
|
this.config = snapshot.config;
|
|
1420
|
-
this.
|
|
1475
|
+
this.advanceSettingsRevision();
|
|
1421
1476
|
this.agent.setModel(snapshot.model);
|
|
1422
1477
|
this.agent.setThinkingLevel(snapshot.config.thinkingLevel);
|
|
1423
1478
|
this.agent.setMaxTokens(snapshot.config.maxTokens);
|
|
@@ -1429,7 +1484,12 @@ export class AgentController {
|
|
|
1429
1484
|
}
|
|
1430
1485
|
this.fast?.onConfigChanged(false, snapshot.config.fast.enabled);
|
|
1431
1486
|
this.compaction?.onConfigChanged(snapshot.config.compaction.enabled);
|
|
1432
|
-
|
|
1487
|
+
if (connectionChanged) {
|
|
1488
|
+
this.requestVersion += 1;
|
|
1489
|
+
this.contextMeter.onHistoryReplaced();
|
|
1490
|
+
}
|
|
1491
|
+
else
|
|
1492
|
+
this.contextMeter.onWindowChanged();
|
|
1433
1493
|
this.rebuildSystemPrompt();
|
|
1434
1494
|
}
|
|
1435
1495
|
finally {
|
|
@@ -1451,9 +1511,11 @@ export class AgentController {
|
|
|
1451
1511
|
setModel(provider, model, baseUrl) {
|
|
1452
1512
|
if (this.isModelSettingsBusy())
|
|
1453
1513
|
throw new Error('Model settings are busy.');
|
|
1514
|
+
const connectionChanged = this.config.provider !== provider || this.config.model !== model
|
|
1515
|
+
|| this.config.baseUrl !== baseUrl;
|
|
1454
1516
|
if (this.modelMetadataEnabled)
|
|
1455
1517
|
this.resetModelMetadataRequest();
|
|
1456
|
-
this.
|
|
1518
|
+
this.advanceSettingsRevision();
|
|
1457
1519
|
this.config = { ...this.config, provider, model, baseUrl };
|
|
1458
1520
|
this.config.modelProfileState = resolveModelProfileState(this.config);
|
|
1459
1521
|
this.agent.setModel({ providerId: provider, modelId: model, ...(baseUrl ? { baseUrl } : {}) });
|
|
@@ -1468,30 +1530,29 @@ export class AgentController {
|
|
|
1468
1530
|
// so the snapshot the chip and `/compact status` read has to be refreshed
|
|
1469
1531
|
// for the same reason and at the same moments (the RV-3 lesson).
|
|
1470
1532
|
this.compaction?.onConfigChanged();
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
this.contextMeter.onWindowChanged();
|
|
1533
|
+
if (connectionChanged) {
|
|
1534
|
+
this.requestVersion += 1;
|
|
1535
|
+
this.contextMeter.onHistoryReplaced();
|
|
1536
|
+
}
|
|
1537
|
+
else
|
|
1538
|
+
this.contextMeter.onWindowChanged();
|
|
1478
1539
|
if (this.modelMetadataEnabled)
|
|
1479
1540
|
void this.refreshModelMetadata();
|
|
1480
1541
|
}
|
|
1481
1542
|
setThinkingLevel(level) {
|
|
1482
|
-
this.
|
|
1543
|
+
this.advanceSettingsRevision();
|
|
1483
1544
|
this.config = { ...this.config, thinkingLevel: level };
|
|
1484
1545
|
this.agent.setThinkingLevel(level);
|
|
1485
1546
|
}
|
|
1486
1547
|
setMaxTokens(value) {
|
|
1487
|
-
this.
|
|
1548
|
+
this.advanceSettingsRevision();
|
|
1488
1549
|
this.config = { ...this.config, maxTokens: value };
|
|
1489
1550
|
this.agent.setMaxTokens(value);
|
|
1490
1551
|
}
|
|
1491
1552
|
setApiKey(provider, key) {
|
|
1492
1553
|
// The Agent resolves keys via `resolveKey(this.config)` at call time, so
|
|
1493
1554
|
// updating the config here is sufficient — no Agent rebuild needed.
|
|
1494
|
-
this.
|
|
1555
|
+
this.advanceSettingsRevision();
|
|
1495
1556
|
this.config = {
|
|
1496
1557
|
...this.config,
|
|
1497
1558
|
apiKeys: { ...this.config.apiKeys, [provider]: key },
|
|
@@ -1512,7 +1573,7 @@ export class AgentController {
|
|
|
1512
1573
|
}
|
|
1513
1574
|
setCwd(cwd) {
|
|
1514
1575
|
this.cwd = cwd;
|
|
1515
|
-
this.
|
|
1576
|
+
this.advanceSettingsRevision();
|
|
1516
1577
|
this.config = { ...this.config, cwd };
|
|
1517
1578
|
// The project scope moved with the cwd, so rescan BEFORE rebuilding — then
|
|
1518
1579
|
// let the single prompt entry point emit a prompt that reflects both the new
|
|
@@ -1581,6 +1642,8 @@ export class AgentController {
|
|
|
1581
1642
|
};
|
|
1582
1643
|
}
|
|
1583
1644
|
clearMessages() {
|
|
1645
|
+
this.idleCompaction?.abort();
|
|
1646
|
+
this.restoredCompactionIdentity = undefined;
|
|
1584
1647
|
this.agent.clearMessages();
|
|
1585
1648
|
this.startupSequence += 1;
|
|
1586
1649
|
// INVALIDATION SITE 3 (context-auto-compaction-hardening §3.2.3). The history
|
|
@@ -1608,7 +1671,9 @@ export class AgentController {
|
|
|
1608
1671
|
getSystemPrompt() {
|
|
1609
1672
|
return this.agent.state.systemPrompt;
|
|
1610
1673
|
}
|
|
1611
|
-
replaceMessages(messages) {
|
|
1674
|
+
replaceMessages(messages, identity) {
|
|
1675
|
+
this.idleCompaction?.abort();
|
|
1676
|
+
this.restoredCompactionIdentity = identity;
|
|
1612
1677
|
this.agent.replaceMessages(messages);
|
|
1613
1678
|
this.startupSequence += 1;
|
|
1614
1679
|
// INVALIDATION SITE 4 (§3.2.3) - `/resume`, and any future host-side rewrite.
|
|
@@ -1621,12 +1686,26 @@ export class AgentController {
|
|
|
1621
1686
|
// reading stood until the next completed turn. The DEEP reset also drops
|
|
1622
1687
|
// `estimateOffset`, because `/resume` can change the model in the same
|
|
1623
1688
|
// breath (I-8).
|
|
1624
|
-
this.compaction?.onHistoryReplaced();
|
|
1689
|
+
this.compaction?.onHistoryReplaced(identity);
|
|
1625
1690
|
this.contextMeter.onHistoryReplaced();
|
|
1626
1691
|
}
|
|
1627
1692
|
getMessages() {
|
|
1628
1693
|
return this.agent.state.messages;
|
|
1629
1694
|
}
|
|
1695
|
+
/** Atomically capture adopted history and its host credential for serialization. */
|
|
1696
|
+
getSessionSnapshot() {
|
|
1697
|
+
const messages = this.getMessages();
|
|
1698
|
+
const identity = this.compaction ? this.compaction.getIdentity() : this.restoredCompactionIdentity;
|
|
1699
|
+
if (identity && !verifyCompactionIdentity(messages, identity)) {
|
|
1700
|
+
getLogger().debug('agent', 'invalid_compaction_session_identity');
|
|
1701
|
+
}
|
|
1702
|
+
// Retain invalid evidence so damaged host memory cannot become ordinary text.
|
|
1703
|
+
return { messages, ...(identity ? { compactionIdentity: { ...identity } } : {}) };
|
|
1704
|
+
}
|
|
1705
|
+
/** Compatibility name for the documented compaction session boundary. */
|
|
1706
|
+
getCompactionSessionState() {
|
|
1707
|
+
return this.getSessionSnapshot();
|
|
1708
|
+
}
|
|
1630
1709
|
clearAllQueues() {
|
|
1631
1710
|
this.agent.clearAllQueues();
|
|
1632
1711
|
this.pendingUserSteering.clear();
|
|
@@ -1662,9 +1741,18 @@ export class AgentController {
|
|
|
1662
1741
|
const found = this.modelRegistry.getModel(ref.providerId, ref.modelId);
|
|
1663
1742
|
const baseUrl = ref.baseUrl ?? (ref.providerId === this.config.provider && ref.modelId === this.config.model
|
|
1664
1743
|
? this.config.baseUrl : undefined);
|
|
1744
|
+
const userWindow = this.modelWindows.lookup(ref.modelId);
|
|
1665
1745
|
return {
|
|
1666
1746
|
...(found ?? this.modelRegistry.buildRuntimeModel(ref.providerId, ref.modelId)),
|
|
1667
1747
|
...this.modelRegistry.getContextWindow(ref.providerId, ref.modelId, baseUrl),
|
|
1748
|
+
// A USER-DECLARED WINDOW OUTRANKS EVERY TABLE (model-windows.json): the
|
|
1749
|
+
// user asserted the number for exactly this id, while api/catalog are
|
|
1750
|
+
// what this process managed to look up about it. It still LOSES to
|
|
1751
|
+
// config.json's `contextWindow`, which `ContextMeter.resolveWindow`
|
|
1752
|
+
// consults before it ever reaches here.
|
|
1753
|
+
...(userWindow !== undefined
|
|
1754
|
+
? { contextWindow: userWindow, contextWindowSource: 'user' }
|
|
1755
|
+
: {}),
|
|
1668
1756
|
};
|
|
1669
1757
|
}
|
|
1670
1758
|
/** Best-effort metadata lookup; never block typing or a model request. */
|
|
@@ -1726,7 +1814,7 @@ export class AgentController {
|
|
|
1726
1814
|
* `/fast` reports that honestly by checking `isFastRegistered()` first.
|
|
1727
1815
|
*/
|
|
1728
1816
|
setFastEnabled(enabled) {
|
|
1729
|
-
this.
|
|
1817
|
+
this.advanceSettingsRevision();
|
|
1730
1818
|
this.fast?.setEnabled(enabled);
|
|
1731
1819
|
}
|
|
1732
1820
|
getFastConfig() {
|
|
@@ -1742,7 +1830,7 @@ export class AgentController {
|
|
|
1742
1830
|
*/
|
|
1743
1831
|
setFastConfig(patch) {
|
|
1744
1832
|
const fast = clampFastConfig({ ...this.config.fast, ...patch });
|
|
1745
|
-
this.
|
|
1833
|
+
this.advanceSettingsRevision();
|
|
1746
1834
|
this.config = { ...this.config, fast };
|
|
1747
1835
|
// `onConfigChanged` rebuilds the prompt; when there is no wiring (the tier
|
|
1748
1836
|
// was never registered) nothing has to be rebuilt, because no block is
|
|
@@ -1842,7 +1930,7 @@ export class AgentController {
|
|
|
1842
1930
|
* on purpose (§3.2).
|
|
1843
1931
|
*/
|
|
1844
1932
|
setCompactionEnabled(enabled) {
|
|
1845
|
-
this.
|
|
1933
|
+
this.advanceSettingsRevision();
|
|
1846
1934
|
this.compaction?.setEnabled(enabled);
|
|
1847
1935
|
}
|
|
1848
1936
|
getCompactionConfig() {
|
|
@@ -1857,7 +1945,7 @@ export class AgentController {
|
|
|
1857
1945
|
*/
|
|
1858
1946
|
setCompactionConfig(patch) {
|
|
1859
1947
|
const compaction = clampCompactionConfig({ ...this.config.compaction, ...patch });
|
|
1860
|
-
this.
|
|
1948
|
+
this.advanceSettingsRevision();
|
|
1861
1949
|
this.config = { ...this.config, compaction };
|
|
1862
1950
|
this.compaction?.onConfigChanged();
|
|
1863
1951
|
return compaction;
|
|
@@ -1910,18 +1998,80 @@ export class AgentController {
|
|
|
1910
1998
|
return { ok: false, reason: 'settings_restart_required' };
|
|
1911
1999
|
if (!this.compaction)
|
|
1912
2000
|
return { ok: false, reason: 'not_registered' };
|
|
2001
|
+
if (this.isCompactionBusy() || this.isRunning())
|
|
2002
|
+
return { ok: false, reason: 'busy' };
|
|
1913
2003
|
const controller = new AbortController();
|
|
1914
|
-
const
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2004
|
+
const epoch = this.startupSequence;
|
|
2005
|
+
const settings = this.settingsRevision;
|
|
2006
|
+
let adopted = false;
|
|
2007
|
+
let timedOut = false;
|
|
2008
|
+
const isCurrent = () => this.idleCompaction === controller && !controller.signal.aborted
|
|
2009
|
+
&& epoch === this.startupSequence && settings === this.settingsRevision
|
|
2010
|
+
&& !this.isRunning() && !this.disposed;
|
|
2011
|
+
this.idleCompaction = controller;
|
|
2012
|
+
this.publishCompactionBusy(true);
|
|
2013
|
+
const deadline = setTimeout(() => {
|
|
2014
|
+
timedOut = true;
|
|
2015
|
+
controller.abort();
|
|
2016
|
+
}, COMPACTION_LIMITS.operationTimeoutMs);
|
|
2017
|
+
deadline.unref?.();
|
|
2018
|
+
try {
|
|
2019
|
+
// The wiring races cancellation locally and settles before releasing ownership.
|
|
2020
|
+
const outcome = await this.compaction.compactNow({
|
|
2021
|
+
messages: this.agent.state.messages,
|
|
2022
|
+
systemPrompt: this.agent.state.systemPrompt,
|
|
2023
|
+
model: this.agent.state.model,
|
|
2024
|
+
signal: controller.signal,
|
|
2025
|
+
...(instructions ? { instructions } : {}),
|
|
2026
|
+
isCurrent,
|
|
2027
|
+
adopt: (messages) => {
|
|
2028
|
+
if (!isCurrent())
|
|
2029
|
+
throw new Error('stale_history');
|
|
2030
|
+
this.agent.replaceMessages(messages);
|
|
2031
|
+
adopted = true;
|
|
2032
|
+
},
|
|
2033
|
+
});
|
|
2034
|
+
return outcome.ok || adopted ? { ok: true }
|
|
2035
|
+
: { ok: false, reason: timedOut ? 'timeout' : outcome.reason };
|
|
2036
|
+
}
|
|
2037
|
+
finally {
|
|
2038
|
+
clearTimeout(deadline);
|
|
2039
|
+
if (this.idleCompaction === controller) {
|
|
2040
|
+
this.idleCompaction = undefined;
|
|
2041
|
+
this.publishCompactionBusy(false);
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
/** Local prepare/adopt ownership, available before any network-start event. */
|
|
2046
|
+
isCompactionBusy() { return this.idleCompaction !== undefined; }
|
|
2047
|
+
/** Cancel local compaction and await ownership release before a conversation switch. */
|
|
2048
|
+
cancelCompaction() {
|
|
2049
|
+
if (!this.idleCompaction)
|
|
2050
|
+
return Promise.resolve();
|
|
2051
|
+
return new Promise((resolve) => {
|
|
2052
|
+
const unsubscribe = this.subscribeCompactionBusy((busy) => {
|
|
2053
|
+
if (busy)
|
|
2054
|
+
return;
|
|
2055
|
+
unsubscribe();
|
|
2056
|
+
resolve();
|
|
2057
|
+
});
|
|
2058
|
+
this.abort();
|
|
1920
2059
|
});
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
2060
|
+
}
|
|
2061
|
+
/** Subscribe to synchronous ownership transitions; observers cannot break adoption. */
|
|
2062
|
+
subscribeCompactionBusy(listener) {
|
|
2063
|
+
this.compactionBusyListeners.add(listener);
|
|
2064
|
+
return () => { this.compactionBusyListeners.delete(listener); };
|
|
2065
|
+
}
|
|
2066
|
+
publishCompactionBusy(busy) {
|
|
2067
|
+
for (const listener of this.compactionBusyListeners) {
|
|
2068
|
+
try {
|
|
2069
|
+
listener(busy);
|
|
2070
|
+
}
|
|
2071
|
+
catch {
|
|
2072
|
+
getLogger().debug('agent', 'compaction_busy_listener_threw');
|
|
2073
|
+
}
|
|
2074
|
+
}
|
|
1925
2075
|
}
|
|
1926
2076
|
/**
|
|
1927
2077
|
* Subscribe to the CLI-local compaction event stream.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* ASCII ONLY — `agent/` is inside the glyph scanner's scope.
|
|
9
9
|
*/
|
|
10
10
|
/** Bump when the wording changes, so a transcript can be dated. */
|
|
11
|
-
export declare const PLAN_MODE_BLOCK_VERSION = "
|
|
11
|
+
export declare const PLAN_MODE_BLOCK_VERSION = "v2-2026-10-08";
|
|
12
12
|
export interface PlanModeBlockOptions {
|
|
13
13
|
/** False under `-p` / piped stdin: no overlay can be rendered, so no tools. */
|
|
14
14
|
interactive: boolean;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* ASCII ONLY — `agent/` is inside the glyph scanner's scope.
|
|
9
9
|
*/
|
|
10
10
|
/** Bump when the wording changes, so a transcript can be dated. */
|
|
11
|
-
export const PLAN_MODE_BLOCK_VERSION = '
|
|
11
|
+
export const PLAN_MODE_BLOCK_VERSION = 'v2-2026-10-08';
|
|
12
12
|
/**
|
|
13
13
|
* The closing paragraph of the interactive block.
|
|
14
14
|
*
|
|
@@ -75,8 +75,9 @@ export function buildPlanModeBlock(options) {
|
|
|
75
75
|
'design mode: you must not change anything on disk and must not run commands.',
|
|
76
76
|
'',
|
|
77
77
|
'Work in this order:',
|
|
78
|
-
'1.
|
|
79
|
-
'
|
|
78
|
+
'1. Follow the project-guidance protocol: read applicable guidance and index navigation',
|
|
79
|
+
' before any source search or read. Then inspect the real code with read_file,',
|
|
80
|
+
' list_dir, glob, grep and relevant skills. Never plan against unread structure.',
|
|
80
81
|
...askStep,
|
|
81
82
|
...submitStep,
|
|
82
83
|
'',
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
/** Shared workspace-orientation protocol; no local content is injected. */
|
|
2
|
+
export declare const PROJECT_GUIDANCE_BLOCK_VERSION = "v5-2026-10-08";
|
|
3
|
+
/** Return the versioned English protocol without performing discovery or IO. */
|
|
4
|
+
export declare function buildProjectGuidanceBlock(): string;
|