@sayknow-cli/coding-agent 0.3.8 → 0.3.10
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 +13 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/notify-cli.d.ts +5 -0
- package/dist/types/cli.d.ts +3 -0
- package/dist/types/commands/launch.d.ts +3 -0
- package/dist/types/config/model-profile-activation.d.ts +7 -7
- package/dist/types/config/model-registry.d.ts +11 -3
- package/dist/types/config/model-resolver.d.ts +2 -2
- package/dist/types/config/settings-schema.d.ts +15 -1
- package/dist/types/config/settings.d.ts +7 -0
- package/dist/types/extensibility/runtime-skill-discovery.d.ts +20 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -2
- package/dist/types/modes/components/thinking-selector.d.ts +7 -2
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +1 -3
- package/dist/types/modes/rpc/rpc-socket-security.d.ts +3 -0
- package/dist/types/modes/types.d.ts +3 -0
- package/dist/types/modes/utils/injected-user-submission.d.ts +52 -0
- package/dist/types/notifications/config-commands.d.ts +38 -0
- package/dist/types/notifications/config.d.ts +16 -0
- package/dist/types/notifications/index.d.ts +14 -1
- package/dist/types/notifications/lifecycle-commands.d.ts +1 -0
- package/dist/types/notifications/lifecycle-control-runtime.d.ts +2 -1
- package/dist/types/notifications/reply-sent-store.d.ts +53 -0
- package/dist/types/notifications/rich-draft.d.ts +68 -0
- package/dist/types/notifications/rich-render.d.ts +90 -0
- package/dist/types/notifications/telegram-daemon.d.ts +22 -0
- package/dist/types/notifications/telegram-reference.d.ts +7 -0
- package/dist/types/notifications/threaded-render.d.ts +10 -0
- package/dist/types/notifications/topic-registry.d.ts +4 -5
- package/dist/types/runtime-credential-selector.d.ts +7 -0
- package/dist/types/sdk.d.ts +7 -1
- package/dist/types/session/agent-session.d.ts +6 -3
- package/dist/types/skc-runtime/tmux-common.d.ts +1 -0
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/skill-discovery.d.ts +40 -0
- package/dist/types/utils/pasted-image-path.d.ts +30 -0
- package/package.json +7 -7
- package/src/cli/args.ts +8 -0
- package/src/cli/notify-cli.ts +38 -10
- package/src/cli.ts +5 -0
- package/src/commands/launch.ts +5 -0
- package/src/commands/notify.ts +2 -2
- package/src/config/keybindings.ts +1 -1
- package/src/config/model-profile-activation.ts +23 -7
- package/src/config/model-registry.ts +107 -11
- package/src/config/model-resolver.ts +5 -16
- package/src/config/settings-schema.ts +11 -2
- package/src/config/settings.ts +24 -1
- package/src/extensibility/runtime-skill-discovery.ts +229 -0
- package/src/internal-urls/docs-index.generated.ts +4 -4
- package/src/lsp/client.ts +1 -0
- package/src/main.ts +26 -3
- package/src/modes/components/footer.ts +7 -2
- package/src/modes/components/settings-selector.ts +3 -3
- package/src/modes/components/thinking-selector.ts +83 -20
- package/src/modes/controllers/event-controller.ts +11 -2
- package/src/modes/controllers/extension-ui-controller.ts +8 -1
- package/src/modes/controllers/input-controller.ts +62 -26
- package/src/modes/controllers/selector-controller.ts +43 -0
- package/src/modes/interactive-mode.ts +5 -0
- package/src/modes/rpc/rpc-mode.ts +3 -9
- package/src/modes/rpc/rpc-socket-security.ts +13 -1
- package/src/modes/types.ts +3 -0
- package/src/modes/utils/injected-user-submission.ts +94 -0
- package/src/modes/utils/ui-helpers.ts +48 -15
- package/src/notifications/config-commands.ts +90 -0
- package/src/notifications/config.ts +27 -0
- package/src/notifications/index.ts +184 -14
- package/src/notifications/lifecycle-commands.ts +37 -16
- package/src/notifications/lifecycle-control-runtime.ts +8 -3
- package/src/notifications/reply-sent-store.ts +134 -0
- package/src/notifications/rich-draft.ts +107 -0
- package/src/notifications/rich-render.ts +143 -0
- package/src/notifications/telegram-daemon.ts +431 -91
- package/src/notifications/telegram-reference.ts +17 -0
- package/src/notifications/threaded-render.ts +42 -1
- package/src/notifications/topic-registry.ts +9 -8
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/skill-discovery.md +13 -0
- package/src/runtime-credential-selector.ts +35 -0
- package/src/sdk.ts +104 -13
- package/src/session/agent-session.ts +48 -22
- package/src/skc-runtime/psmux-detect.ts +17 -2
- package/src/skc-runtime/tmux-common.ts +1 -0
- package/src/skc-runtime/ultragoal-runtime.ts +10 -1
- package/src/slash-commands/builtin-registry.ts +78 -1
- package/src/system-prompt.ts +4 -6
- package/src/tools/index.ts +4 -0
- package/src/tools/skill-discovery.ts +73 -0
- package/src/tools/skill.ts +15 -2
- package/src/utils/pasted-image-path.ts +170 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,19 @@ Sayknow-CLI is a rebranded fork of [gajae-code](https://github.com/Yeachan-Heo/g
|
|
|
4
4
|
This file tracks the **fork's own releases**; upstream's full feature history lives
|
|
5
5
|
in that project. Each release notes the upstream version it is built on.
|
|
6
6
|
|
|
7
|
+
## [0.3.10] — 2026-07-09
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Synced onto upstream **gajae-code v0.9.2**, carrying the 0.9.2 patch set into
|
|
12
|
+
Sayknow-CLI while preserving the SKC fork layer and release surface.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Updated the release version surfaces so `skc --version`, package metadata,
|
|
17
|
+
native sentinel exports, plugin metadata, schemas, and public sync checks report
|
|
18
|
+
**0.3.10** consistently.
|
|
19
|
+
|
|
7
20
|
## [0.3.0] — 2026-06-23
|
|
8
21
|
|
|
9
22
|
### Changed
|
package/dist/types/cli/args.d.ts
CHANGED
|
@@ -19,12 +19,17 @@ export interface NotifyCommandDeps {
|
|
|
19
19
|
setupRedact?: boolean;
|
|
20
20
|
setupInteractive?: boolean;
|
|
21
21
|
threadedModePrompt?: (message: string) => Promise<string>;
|
|
22
|
+
tokenPrompt?: () => Promise<string>;
|
|
23
|
+
setExitCode?: (code: number) => void;
|
|
24
|
+
exitProcess?: (code: number) => void;
|
|
22
25
|
}
|
|
23
26
|
export declare function parseNotifyArgs(args: string[]): NotifyCommandArgs | undefined;
|
|
24
27
|
export declare function runNotifyCommand(cmd: NotifyCommandArgs, deps?: NotifyCommandDeps): Promise<void>;
|
|
28
|
+
export declare function runNotifyCliCommand(cmd: NotifyCommandArgs, deps?: NotifyCommandDeps): Promise<void>;
|
|
25
29
|
type TokenPromptInput = NodeJS.ReadStream & {
|
|
26
30
|
isRaw?: boolean;
|
|
27
31
|
setRawMode?: (mode: boolean) => unknown;
|
|
32
|
+
pause?: () => unknown;
|
|
28
33
|
};
|
|
29
34
|
type TokenPromptOutput = Pick<NodeJS.WriteStream, "write">;
|
|
30
35
|
export declare function promptForToken(input?: TokenPromptInput, output?: TokenPromptOutput): Promise<string>;
|
package/dist/types/cli.d.ts
CHANGED
|
@@ -40,6 +40,9 @@ export declare class RootHelpCommand extends Command {
|
|
|
40
40
|
"api-key": import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
41
41
|
description: string;
|
|
42
42
|
};
|
|
43
|
+
credential: import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
44
|
+
description: string;
|
|
45
|
+
};
|
|
43
46
|
"system-prompt": import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
44
47
|
description: string;
|
|
45
48
|
};
|
|
@@ -37,6 +37,9 @@ export default class Index extends Command {
|
|
|
37
37
|
"api-key": import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
38
38
|
description: string;
|
|
39
39
|
};
|
|
40
|
+
credential: import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
41
|
+
description: string;
|
|
42
|
+
};
|
|
40
43
|
"system-prompt": import("@sayknow-cli/utils/cli").FlagDescriptor<"string"> & {
|
|
41
44
|
description: string;
|
|
42
45
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ThinkingLevel } from "@sayknow-cli/agent-core";
|
|
2
2
|
import type { Api, Model } from "@sayknow-cli/ai";
|
|
3
3
|
import type { AgentSession } from "../session/agent-session";
|
|
4
4
|
import { type ModelRegistry, type SkcModelAssignmentTargetId } from "./model-registry";
|
|
@@ -16,6 +16,10 @@ export interface PrepareModelProfileActivationOptions {
|
|
|
16
16
|
settings: Pick<Settings, "get">;
|
|
17
17
|
profileName: string;
|
|
18
18
|
}
|
|
19
|
+
export interface ApplyModelProfileActivationOptions {
|
|
20
|
+
persistDefault?: boolean;
|
|
21
|
+
thinkingLevelOverride?: ThinkingLevel;
|
|
22
|
+
}
|
|
19
23
|
export interface PreparedModelProfileActivation {
|
|
20
24
|
profileName: string;
|
|
21
25
|
session: ModelProfileActivationSession & {
|
|
@@ -55,10 +59,6 @@ export declare function materializeActiveModelProfileAssignment(options: Materia
|
|
|
55
59
|
export declare function materializeActiveModelProfileAssignments(options: MaterializeModelProfileAssignmentsOptions): boolean;
|
|
56
60
|
export declare function formatModelProfileCredentialError(profileName: string, providers: readonly string[]): string;
|
|
57
61
|
export declare function prepareModelProfileActivation(options: PrepareModelProfileActivationOptions): Promise<PreparedModelProfileActivation>;
|
|
58
|
-
export declare function applyPreparedModelProfileActivation(prepared: PreparedModelProfileActivation, options?:
|
|
59
|
-
|
|
60
|
-
}): Promise<void>;
|
|
61
|
-
export declare function activateModelProfile(options: PrepareModelProfileActivationOptions, applyOptions?: {
|
|
62
|
-
persistDefault?: boolean;
|
|
63
|
-
}): Promise<void>;
|
|
62
|
+
export declare function applyPreparedModelProfileActivation(prepared: PreparedModelProfileActivation, options?: ApplyModelProfileActivationOptions): Promise<void>;
|
|
63
|
+
export declare function activateModelProfile(options: PrepareModelProfileActivationOptions, applyOptions?: ApplyModelProfileActivationOptions): Promise<void>;
|
|
64
64
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Api, type AssistantMessageEventStream, type CacheRetention, type Context, type Model, type ModelRefreshStrategy, type ModelRequestTransform, type SimpleStreamOptions, type ThinkingConfig } from "@sayknow-cli/ai";
|
|
1
|
+
import { type Api, type AssistantMessageEventStream, type AuthCredentialSelector, type CacheRetention, type Context, type Model, type ModelRefreshStrategy, type ModelRequestTransform, type SimpleStreamOptions, type ThinkingConfig } from "@sayknow-cli/ai";
|
|
2
2
|
import type { OAuthCredentials, OAuthLoginCallbacks } from "@sayknow-cli/ai/utils/oauth/types";
|
|
3
3
|
import { type ThemeColor } from "../modes/theme/theme";
|
|
4
4
|
import type { AuthStorage } from "../session/auth-storage";
|
|
@@ -19,6 +19,8 @@ export interface ModelRoleInfo {
|
|
|
19
19
|
}
|
|
20
20
|
export declare const MODEL_ROLES: Record<ModelRole, ModelRoleInfo>;
|
|
21
21
|
export declare const MODEL_ROLE_IDS: ModelRole[];
|
|
22
|
+
export declare const MODEL_PROFILE_NAME_PATTERN: RegExp;
|
|
23
|
+
export declare const MODEL_PROFILE_NAME_PATTERN_DESCRIPTION = "lowercase letters, numbers, dots, underscores, or hyphens";
|
|
22
24
|
export type SkcModelAssignmentTargetId = "default" | "executor" | "architect" | "planner" | "critic";
|
|
23
25
|
export interface SkcModelAssignmentTargetInfo extends ModelRoleInfo {
|
|
24
26
|
id: SkcModelAssignmentTargetId;
|
|
@@ -342,6 +344,8 @@ export declare class ModelRegistry {
|
|
|
342
344
|
getModelProfile(name: string): ModelProfileDefinition | undefined;
|
|
343
345
|
getAvailableModelProfileNames(): string[];
|
|
344
346
|
saveCustomModelProfile(name: string, definition: ModelProfileConfig): Promise<ModelProfileDefinition>;
|
|
347
|
+
renameCustomModelProfile(name: string, displayName: string): Promise<ModelProfileDefinition>;
|
|
348
|
+
deleteCustomModelProfile(name: string): Promise<ModelProfileConfig>;
|
|
345
349
|
applyConfiguredModelBindings(targetSettings: Settings): void;
|
|
346
350
|
/**
|
|
347
351
|
* Get all models (built-in + custom).
|
|
@@ -382,11 +386,15 @@ export declare class ModelRegistry {
|
|
|
382
386
|
/**
|
|
383
387
|
* Get API key for a model.
|
|
384
388
|
*/
|
|
385
|
-
getApiKey(model: Model<Api>, sessionId?: string
|
|
389
|
+
getApiKey(model: Model<Api>, sessionId?: string, options?: {
|
|
390
|
+
credentialSelector?: AuthCredentialSelector;
|
|
391
|
+
}): Promise<string | undefined>;
|
|
386
392
|
/**
|
|
387
393
|
* Get API key for a provider (e.g., "openai").
|
|
388
394
|
*/
|
|
389
|
-
getApiKeyForProvider(provider: string, sessionId?: string, baseUrl?: string
|
|
395
|
+
getApiKeyForProvider(provider: string, sessionId?: string, baseUrl?: string, options?: {
|
|
396
|
+
credentialSelector?: AuthCredentialSelector;
|
|
397
|
+
}): Promise<string | undefined>;
|
|
390
398
|
/**
|
|
391
399
|
* Check if a model is using OAuth credentials (subscription).
|
|
392
400
|
*/
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Model resolution, scoping, and initial selection
|
|
3
3
|
*/
|
|
4
4
|
import { ThinkingLevel } from "@sayknow-cli/agent-core";
|
|
5
|
-
import { type Api, type
|
|
5
|
+
import { type Api, type KnownProvider, type Model } from "@sayknow-cli/ai";
|
|
6
6
|
import { type ModelRegistry, type ModelRole } from "./model-registry";
|
|
7
7
|
import type { Settings } from "./settings";
|
|
8
8
|
/** Default model IDs for each known provider */
|
|
@@ -204,7 +204,7 @@ export declare function findInitialModel(options: {
|
|
|
204
204
|
isContinuing: boolean;
|
|
205
205
|
defaultProvider?: string;
|
|
206
206
|
defaultModelId?: string;
|
|
207
|
-
defaultThinkingSelector?:
|
|
207
|
+
defaultThinkingSelector?: ThinkingLevel;
|
|
208
208
|
modelRegistry: InitialModelRegistry;
|
|
209
209
|
}): Promise<InitialModelResult>;
|
|
210
210
|
/**
|
|
@@ -130,6 +130,14 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
130
130
|
readonly type: "string";
|
|
131
131
|
readonly default: undefined;
|
|
132
132
|
};
|
|
133
|
+
readonly "notifications.telegram.rich.enabled": {
|
|
134
|
+
readonly type: "boolean";
|
|
135
|
+
readonly default: true;
|
|
136
|
+
};
|
|
137
|
+
readonly "notifications.telegram.richDraft.enabled": {
|
|
138
|
+
readonly type: "boolean";
|
|
139
|
+
readonly default: false;
|
|
140
|
+
};
|
|
133
141
|
readonly "notifications.discord.botToken": {
|
|
134
142
|
readonly type: "string";
|
|
135
143
|
readonly default: undefined;
|
|
@@ -942,7 +950,7 @@ export declare const SETTINGS_SCHEMA: {
|
|
|
942
950
|
};
|
|
943
951
|
readonly defaultThinkingLevel: {
|
|
944
952
|
readonly type: "enum";
|
|
945
|
-
readonly values: readonly Effort[];
|
|
953
|
+
readonly values: readonly ["off", ...Effort[]];
|
|
946
954
|
readonly default: Effort;
|
|
947
955
|
readonly ui: {
|
|
948
956
|
readonly tab: "model";
|
|
@@ -4102,6 +4110,12 @@ export interface NotificationsSettings {
|
|
|
4102
4110
|
telegram: {
|
|
4103
4111
|
botToken: string | undefined;
|
|
4104
4112
|
chatId: string | undefined;
|
|
4113
|
+
rich: {
|
|
4114
|
+
enabled: boolean;
|
|
4115
|
+
};
|
|
4116
|
+
richDraft: {
|
|
4117
|
+
enabled: boolean;
|
|
4118
|
+
};
|
|
4105
4119
|
};
|
|
4106
4120
|
discord: {
|
|
4107
4121
|
botToken: string | undefined;
|
|
@@ -82,6 +82,13 @@ export declare class Settings {
|
|
|
82
82
|
* Call before exit to ensure all changes are persisted.
|
|
83
83
|
*/
|
|
84
84
|
flush(): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Like {@link flush}, but rejects if the durable save fails instead of
|
|
87
|
+
* swallowing the error. Use where the caller must confirm persistence before
|
|
88
|
+
* reporting success (e.g. the Telegram `/rich` toggle). In-memory instances
|
|
89
|
+
* ({@link isolated}) short-circuit in {@link #saveNow} and never throw.
|
|
90
|
+
*/
|
|
91
|
+
flushOrThrow(): Promise<void>;
|
|
85
92
|
cloneForCwd(cwd: string): Promise<Settings>;
|
|
86
93
|
getStorage(): AgentStorage | null;
|
|
87
94
|
getCwd(): string;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SkillsSettings } from "../config/settings-schema";
|
|
2
|
+
import type { Skill } from "./skills";
|
|
3
|
+
export type RuntimeSkillDiscoverySource = "project" | "user";
|
|
4
|
+
export interface RuntimeSkillDiscoveryCandidate {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
source: RuntimeSkillDiscoverySource;
|
|
8
|
+
path: string;
|
|
9
|
+
useWhen?: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface DiscoverRuntimeSkillsOptions {
|
|
12
|
+
cwd: string;
|
|
13
|
+
home?: string;
|
|
14
|
+
query?: string;
|
|
15
|
+
limit?: number;
|
|
16
|
+
source?: RuntimeSkillDiscoverySource | "all";
|
|
17
|
+
policy?: SkillsSettings;
|
|
18
|
+
}
|
|
19
|
+
export declare function discoverRuntimeSkills(options: DiscoverRuntimeSkillsOptions): Promise<RuntimeSkillDiscoveryCandidate[]>;
|
|
20
|
+
export declare function findRuntimeSkillByName(cwd: string, name: string, policy?: SkillsSettings, home?: string): Promise<Skill | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ThinkingLevel as ThinkingLevelValue } from "@sayknow-cli/agent-core";
|
|
2
2
|
import type { Effort } from "@sayknow-cli/ai";
|
|
3
3
|
import { Container, SettingsList } from "@sayknow-cli/tui";
|
|
4
4
|
import { type SettingPath } from "../../config/settings";
|
|
@@ -13,7 +13,7 @@ export interface SettingsRuntimeContext {
|
|
|
13
13
|
/** Available thinking levels (from session) */
|
|
14
14
|
availableThinkingLevels: Effort[];
|
|
15
15
|
/** Current thinking level (from session) */
|
|
16
|
-
thinkingLevel:
|
|
16
|
+
thinkingLevel: ThinkingLevelValue | undefined;
|
|
17
17
|
/** Available themes */
|
|
18
18
|
availableThemes: string[];
|
|
19
19
|
/** Available model profile names (from the model registry) */
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type ThinkingLevel as ThinkingLevelValue } from "@sayknow-cli/agent-core";
|
|
2
2
|
import { Container, SelectList } from "@sayknow-cli/tui";
|
|
3
|
+
export interface ThinkingSelectorSelection {
|
|
4
|
+
level: ThinkingLevelValue;
|
|
5
|
+
persistDefault: boolean;
|
|
6
|
+
}
|
|
3
7
|
/**
|
|
4
8
|
* Component that renders a thinking level selector with borders
|
|
5
9
|
*/
|
|
6
10
|
export declare class ThinkingSelectorComponent extends Container {
|
|
7
11
|
#private;
|
|
8
|
-
constructor(currentLevel:
|
|
12
|
+
constructor(currentLevel: ThinkingLevelValue | undefined, availableLevels: ThinkingLevelValue[], onSelect: (selection: ThinkingSelectorSelection) => void, onCancel: () => void);
|
|
13
|
+
handleInput(data: string): void;
|
|
9
14
|
getSelectList(): SelectList;
|
|
10
15
|
}
|
|
@@ -26,6 +26,7 @@ export declare class SelectorController {
|
|
|
26
26
|
showProviderOnboarding(): void;
|
|
27
27
|
showCustomModelPresetWizard(snapshot: ModelProfileConfig): void;
|
|
28
28
|
showCustomProviderWizard(): void;
|
|
29
|
+
showEffortSelector(): void;
|
|
29
30
|
showSettingsSelector(): void;
|
|
30
31
|
showThemeSelector(): void;
|
|
31
32
|
showHistorySearch(): void;
|
|
@@ -96,6 +96,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
96
96
|
onInputCallback?: (input: SubmittedUserInput) => void;
|
|
97
97
|
optimisticUserMessageSignature: string | undefined;
|
|
98
98
|
locallySubmittedUserSignatures: Set<string>;
|
|
99
|
+
optimisticInjectedSignatures: Map<string, number>;
|
|
99
100
|
lastSigintTime: number;
|
|
100
101
|
lastEscapeTime: number;
|
|
101
102
|
lastComposerClearEscapeTime: number;
|
|
@@ -218,6 +219,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
|
|
|
218
219
|
showModelSelector(options?: {
|
|
219
220
|
temporaryOnly?: boolean;
|
|
220
221
|
}): void;
|
|
222
|
+
showEffortSelector(): void;
|
|
221
223
|
showProviderOnboarding(): void;
|
|
222
224
|
showPluginSelector(mode?: "install" | "uninstall"): void;
|
|
223
225
|
showUserMessageSelector(): void;
|
|
@@ -64,9 +64,7 @@ export declare function isFastLaneRpcCommand(type: RpcCommand["type"]): boolean;
|
|
|
64
64
|
export declare function createRpcCommandScheduler(run: (command: RpcCommand) => Promise<void>, track: (task: Promise<void>) => void): {
|
|
65
65
|
dispatch: (command: RpcCommand) => void;
|
|
66
66
|
};
|
|
67
|
-
export
|
|
68
|
-
constructor(socketPath: string);
|
|
69
|
-
}
|
|
67
|
+
export { RpcListenRefusedError } from "./rpc-socket-security";
|
|
70
68
|
/**
|
|
71
69
|
* Probe whether a unix-domain socket path has a live server accepting
|
|
72
70
|
* connections. Returns `true` when a connection succeeds (a previous owner is
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
export declare class RpcSocketSecurityError extends Error {
|
|
2
2
|
constructor(message: string);
|
|
3
3
|
}
|
|
4
|
+
export declare class RpcListenRefusedError extends Error {
|
|
5
|
+
constructor(socketPath: string);
|
|
6
|
+
}
|
|
4
7
|
export declare function prepareRpcSocketPath(socketPath: string): Promise<void>;
|
|
5
8
|
export declare function assertSafeClientSocket(socketPath: string): Promise<void>;
|
|
6
9
|
export declare function verifyRpcSocketAfterListen(socketPath: string): Promise<void>;
|
|
@@ -28,6 +28,7 @@ import type { Theme } from "./theme/theme";
|
|
|
28
28
|
export type CompactionQueuedMessage = {
|
|
29
29
|
text: string;
|
|
30
30
|
mode: "steer" | "followUp";
|
|
31
|
+
followUpQueuePolicy?: "sequential";
|
|
31
32
|
};
|
|
32
33
|
export type SubmittedUserInput = {
|
|
33
34
|
text: string;
|
|
@@ -100,6 +101,7 @@ export interface InteractiveModeContext {
|
|
|
100
101
|
onInputCallback?: (input: SubmittedUserInput) => void;
|
|
101
102
|
optimisticUserMessageSignature: string | undefined;
|
|
102
103
|
locallySubmittedUserSignatures: Set<string>;
|
|
104
|
+
optimisticInjectedSignatures: Map<string, number>;
|
|
103
105
|
lastSigintTime: number;
|
|
104
106
|
lastEscapeTime: number;
|
|
105
107
|
lastComposerClearEscapeTime: number;
|
|
@@ -223,6 +225,7 @@ export interface InteractiveModeContext {
|
|
|
223
225
|
showModelSelector(options?: {
|
|
224
226
|
temporaryOnly?: boolean;
|
|
225
227
|
}): void;
|
|
228
|
+
showEffortSelector(): void;
|
|
226
229
|
showProviderOnboarding(): void;
|
|
227
230
|
showPluginSelector(mode?: "install" | "uninstall"): void;
|
|
228
231
|
showUserMessageSelector(): void;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ImageContent, TextContent } from "@sayknow-cli/ai";
|
|
2
|
+
import type { InteractiveModeContext } from "../types";
|
|
3
|
+
/**
|
|
4
|
+
* Normalize the content passed to an extension `sendUserMessage` call into a
|
|
5
|
+
* plain text string plus its image attachments. Mirrors the normalization in
|
|
6
|
+
* `AgentSession.sendUserMessage` (text parts joined with "\n") so the resulting
|
|
7
|
+
* text matches the eventual user `message_start` payload.
|
|
8
|
+
*/
|
|
9
|
+
export declare function normalizeInjectedUserContent(content: string | (TextContent | ImageContent)[]): {
|
|
10
|
+
text: string;
|
|
11
|
+
images: ImageContent[];
|
|
12
|
+
imageCount: number;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Record a remotely/programmatically injected user message (e.g. Telegram
|
|
16
|
+
* inbound routed through the extension API) into the interactive TUI, so it is
|
|
17
|
+
* captured in prompt history and shown immediately instead of only appearing
|
|
18
|
+
* once the eventual `message_start` event lands.
|
|
19
|
+
*
|
|
20
|
+
* Local TUI submissions never reach this path (they go through
|
|
21
|
+
* `session.prompt(...)` / `startPendingSubmission`), so this cannot double-add
|
|
22
|
+
* local prompt history.
|
|
23
|
+
*
|
|
24
|
+
* - Always adds the injected text to editor prompt history.
|
|
25
|
+
* - Idle injections optimistically render the user message and record a pending
|
|
26
|
+
* injected optimistic signature (a counting Map, so multiple idle injections
|
|
27
|
+
* before the first `message_start` do not clobber each other); the later user
|
|
28
|
+
* `message_start` consumes one count and skips both the duplicate chat add and
|
|
29
|
+
* the defensive editor clear (so a locally typed draft is preserved).
|
|
30
|
+
* - Busy/queued injections refresh the pending-message display, which the
|
|
31
|
+
* caller has already populated by invoking `session.sendUserMessage(...)`
|
|
32
|
+
* before this helper.
|
|
33
|
+
*
|
|
34
|
+
* This helper never clears the editor text.
|
|
35
|
+
*/
|
|
36
|
+
export declare function applyInjectedUserSubmission(ctx: InteractiveModeContext, input: {
|
|
37
|
+
content: string | (TextContent | ImageContent)[];
|
|
38
|
+
queued: boolean;
|
|
39
|
+
}): void;
|
|
40
|
+
/**
|
|
41
|
+
* Record one pending optimistic render for an injected user message.
|
|
42
|
+
*
|
|
43
|
+
* Injected sends are fire-and-forget and multiple idle injections can be
|
|
44
|
+
* rendered before the first `message_start` arrives, so a counting Map (not a
|
|
45
|
+
* single slot) tracks how many optimistic renders are outstanding per signature.
|
|
46
|
+
*/
|
|
47
|
+
export declare function incrementInjectedOptimisticSignature(ctx: InteractiveModeContext, signature: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Consume one pending injected optimistic render for `signature`. Decrements the
|
|
50
|
+
* count (deleting the key at zero) and returns whether one was outstanding.
|
|
51
|
+
*/
|
|
52
|
+
export declare function consumeInjectedOptimisticSignature(ctx: InteractiveModeContext, signature: string): boolean;
|
|
@@ -18,9 +18,47 @@ export interface ConfigCommandChange {
|
|
|
18
18
|
verbosity?: "lean" | "verbose";
|
|
19
19
|
redact?: boolean;
|
|
20
20
|
}
|
|
21
|
+
export type TelegramControlCommandName = "reasoning" | "usage" | "context" | "compact";
|
|
22
|
+
export type TelegramControlCommand = {
|
|
23
|
+
name: "reasoning";
|
|
24
|
+
action: "cycle" | "status" | "set";
|
|
25
|
+
level?: string;
|
|
26
|
+
} | {
|
|
27
|
+
name: "usage";
|
|
28
|
+
} | {
|
|
29
|
+
name: "context";
|
|
30
|
+
} | {
|
|
31
|
+
name: "compact";
|
|
32
|
+
instructions?: string;
|
|
33
|
+
};
|
|
34
|
+
export type TelegramControlCommandParseResult = {
|
|
35
|
+
kind: "none";
|
|
36
|
+
} | {
|
|
37
|
+
kind: "ignored";
|
|
38
|
+
commandName: TelegramControlCommandName;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "command";
|
|
41
|
+
command: TelegramControlCommand;
|
|
42
|
+
} | {
|
|
43
|
+
kind: "invalid";
|
|
44
|
+
commandName: TelegramControlCommandName;
|
|
45
|
+
usage: string;
|
|
46
|
+
};
|
|
47
|
+
export declare function telegramControlCommandUsage(commandName: TelegramControlCommandName): string;
|
|
48
|
+
/** Parse deterministic Telegram session-control commands. Recognised roots fail closed. */
|
|
49
|
+
export declare function parseTelegramControlCommand(text: string, botUsername?: string): TelegramControlCommandParseResult;
|
|
21
50
|
/**
|
|
22
51
|
* Parse an in-thread config command. Returns the requested change, or
|
|
23
52
|
* `undefined` when the text is not a recognised config command (so the daemon
|
|
24
53
|
* can fall through to treating it as a free-text injection).
|
|
25
54
|
*/
|
|
26
55
|
export declare function parseInThreadConfigCommand(text: string): ConfigCommandChange | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Parse a `/rich on|off` toggle. Returns `true`/`false` for a recognised
|
|
58
|
+
* on/off argument, or `undefined` otherwise (not a `/rich` command, or `/rich`
|
|
59
|
+
* with a missing/invalid argument). This is intentionally SEPARATE from
|
|
60
|
+
* `parseInThreadConfigCommand`: `/verbose`/`/redact` are producer/session config
|
|
61
|
+
* forwarded over the WS, whereas rich is Telegram-daemon delivery policy handled
|
|
62
|
+
* daemon-locally, so it never becomes a `config_command` frame or a user turn.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseRichToggleCommand(text: string): boolean | undefined;
|
|
@@ -14,6 +14,12 @@ export interface NotificationConfig {
|
|
|
14
14
|
redact: boolean;
|
|
15
15
|
verbosity: "lean" | "verbose";
|
|
16
16
|
idleTimeoutMs: number;
|
|
17
|
+
rich: {
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
};
|
|
20
|
+
richDraft: {
|
|
21
|
+
enabled: boolean;
|
|
22
|
+
};
|
|
17
23
|
}
|
|
18
24
|
/** Read typed config from Settings. */
|
|
19
25
|
export declare function getNotificationConfig(settings: Settings): NotificationConfig;
|
|
@@ -25,6 +31,16 @@ export declare function isTelegramConfigured(cfg: NotificationConfig): cfg is No
|
|
|
25
31
|
};
|
|
26
32
|
/** Is global config sufficient for auto-on (enabled + at least one configured adapter)? */
|
|
27
33
|
export declare function isGloballyConfigured(cfg: NotificationConfig): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Per-run opt-out for completion notifications, honored before settings lookups.
|
|
36
|
+
*
|
|
37
|
+
* `SKC_NOTIFY=off` (also `0` / `false`, case-insensitive) suppresses the
|
|
38
|
+
* completion notification surface for this process only. `config.yml` is
|
|
39
|
+
* untouched and child processes inherit the env var, which lets non-interactive
|
|
40
|
+
* fleet runs (`skc -p --no-session`) stay silent even when a user-level/global
|
|
41
|
+
* completion notification configuration is enabled.
|
|
42
|
+
*/
|
|
43
|
+
export declare function completionNotifyDisabledByEnv(env: NodeJS.ProcessEnv): boolean;
|
|
28
44
|
/** Resolve whether the notifications extension should be registered at SDK startup. */
|
|
29
45
|
export declare function shouldRegisterNotificationsExtension(input: {
|
|
30
46
|
env: NodeJS.ProcessEnv;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* generated), or `SKC_NOTIFICATIONS_TOKEN`.
|
|
19
19
|
*/
|
|
20
20
|
import { Settings } from "../config/settings";
|
|
21
|
-
import type { ExtensionAPI } from "../extensibility/extensions";
|
|
21
|
+
import type { ExtensionAPI, ExtensionContext } from "../extensibility/extensions";
|
|
22
22
|
/** Where a `session_create` should run. Discriminated by `kind`. */
|
|
23
23
|
export type SessionCreateTarget = {
|
|
24
24
|
kind: "existing_path";
|
|
@@ -61,6 +61,8 @@ export interface SessionCreateFrame {
|
|
|
61
61
|
target: SessionCreateTarget;
|
|
62
62
|
/** Reference to the daemon-written, once-consumed startup-prompt file. */
|
|
63
63
|
startupPromptRef?: string;
|
|
64
|
+
/** Model profile preset to activate for the spawned session (--mpreset). */
|
|
65
|
+
modelPreset?: string;
|
|
64
66
|
}
|
|
65
67
|
/** Close (hard-kill, history preserved) a session. */
|
|
66
68
|
export interface SessionCloseFrame {
|
|
@@ -174,6 +176,17 @@ export interface SessionReadyFrame {
|
|
|
174
176
|
*/
|
|
175
177
|
export declare function readGitRepoName(cwd: string): string | undefined;
|
|
176
178
|
export declare function notificationsEnabled(): boolean;
|
|
179
|
+
interface NotificationControlCommandPayload {
|
|
180
|
+
name?: unknown;
|
|
181
|
+
action?: unknown;
|
|
182
|
+
level?: unknown;
|
|
183
|
+
instructions?: unknown;
|
|
184
|
+
}
|
|
185
|
+
export declare function executeNotificationControlCommand(command: NotificationControlCommandPayload | undefined, ctx: ExtensionContext, api: ExtensionAPI): Promise<{
|
|
186
|
+
status: "ok" | "error" | "unavailable";
|
|
187
|
+
message: string;
|
|
188
|
+
}>;
|
|
177
189
|
export declare function createNotificationsExtension(api: ExtensionAPI, options?: {
|
|
178
190
|
settings?: Settings;
|
|
179
191
|
}): void;
|
|
192
|
+
export {};
|
|
@@ -35,7 +35,8 @@ export declare function createRateLimiter(maxPerWindow: number, windowMs: number
|
|
|
35
35
|
* The launched session id is carried via `SKC_SESSION_ID` in the child env (see
|
|
36
36
|
* {@link daemonSpawnCreate}); the root `skc` launcher has no `--session-id`
|
|
37
37
|
* flag, so it must never appear in argv. Only flags the launch parser actually
|
|
38
|
-
* supports are emitted (`--worktree <branch>` for worktree targets
|
|
38
|
+
* supports are emitted (`--worktree <branch>` for worktree targets,
|
|
39
|
+
* `--mpreset <profile>` for model presets). */
|
|
39
40
|
export declare function buildCreateArgv(frame: SessionCreateFrame, _ids: {
|
|
40
41
|
intendedSessionId: string;
|
|
41
42
|
startupPromptRef?: string;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Index of rich messages the daemon sent, mapping `${chat_id}:${message_id}` to
|
|
3
|
+
* the original markdown. Telegram does not echo a `sendRichMessage` message's
|
|
4
|
+
* text in a reply's `reply_to_message`, so a user replying to a rich final
|
|
5
|
+
* answer would otherwise strand the agent without the quoted context. The daemon
|
|
6
|
+
* records the markdown on every promoted send and looks it up on inbound replies
|
|
7
|
+
* to restore that context.
|
|
8
|
+
*
|
|
9
|
+
* Fail-closed and off-path-neutral: nothing is recorded unless a send was
|
|
10
|
+
* actually promoted to rich, `record` is a no-op on any error (the in-memory map
|
|
11
|
+
* is only mutated after the atomic persist succeeds), and `lookup` returns
|
|
12
|
+
* undefined on any miss or error, so a bad index write/read never kills the
|
|
13
|
+
* daemon.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from "node:fs";
|
|
16
|
+
/**
|
|
17
|
+
* Minimal async filesystem surface the store needs. Structurally a subset of the
|
|
18
|
+
* daemon's `TelegramDaemonFs`, so the daemon can pass its own `fs` straight
|
|
19
|
+
* through and tests can inject a fake.
|
|
20
|
+
*/
|
|
21
|
+
export interface ReplySentStoreFs {
|
|
22
|
+
mkdir(path: string, opts?: fs.MakeDirectoryOptions): Promise<unknown>;
|
|
23
|
+
readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
24
|
+
writeFile(path: string, data: string, opts?: fs.WriteFileOptions): Promise<void>;
|
|
25
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
26
|
+
chmod(path: string, mode: number): Promise<void>;
|
|
27
|
+
}
|
|
28
|
+
export declare class ReplySentStore {
|
|
29
|
+
#private;
|
|
30
|
+
constructor(input: {
|
|
31
|
+
agentDir: string;
|
|
32
|
+
fs?: ReplySentStoreFs;
|
|
33
|
+
now?: () => number;
|
|
34
|
+
});
|
|
35
|
+
/** Restore the persisted index into memory. No-op on a missing or corrupt file. */
|
|
36
|
+
load(): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Record the original markdown of a rich message the daemon just sent. The
|
|
39
|
+
* text is capped at {@link MAX_TEXT_LENGTH}; the index is capped at
|
|
40
|
+
* {@link MAX_ENTRIES} (oldest-by-timestamp evicted). No-op on any failure: the
|
|
41
|
+
* in-memory map is only replaced after the atomic persist succeeds.
|
|
42
|
+
*/
|
|
43
|
+
record(input: {
|
|
44
|
+
chatId: string | number;
|
|
45
|
+
messageId: number;
|
|
46
|
+
text: string;
|
|
47
|
+
}): Promise<void>;
|
|
48
|
+
/** Look up the original markdown for a message the daemon sent. undefined on miss or failure. */
|
|
49
|
+
lookup(input: {
|
|
50
|
+
chatId: string | number;
|
|
51
|
+
messageId: number;
|
|
52
|
+
}): string | undefined;
|
|
53
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Opt-in rich-draft streaming for a turn's in-progress preview.
|
|
3
|
+
*
|
|
4
|
+
* When the operator opts in (`richDraft.enabled`) the daemon streams LIVE turn
|
|
5
|
+
* markdown to the Bot API `sendRichMessageDraft` method as a debounced preview.
|
|
6
|
+
* Every failure is a harmless no-op (warn once, keep the daemon alive), and when
|
|
7
|
+
* off no draft call is ever made — so the off-state request bodies stay
|
|
8
|
+
* byte-identical.
|
|
9
|
+
*/
|
|
10
|
+
import type { BotApi } from "./telegram-daemon";
|
|
11
|
+
import type { ThreadedSend } from "./threaded-render";
|
|
12
|
+
/** Minimum gap between two draft sends for one session (debounce floor). */
|
|
13
|
+
export declare const DRAFT_DEBOUNCE_MS = 1500;
|
|
14
|
+
/**
|
|
15
|
+
* Wrap raw markdown + a monotonic draft id in the `sendRichMessageDraft` request
|
|
16
|
+
* payload shape: mirrors `buildRichMessage`'s proven `rich_message.markdown`
|
|
17
|
+
* content wrapper, with a top-level `draft_id` selecting the draft revision to
|
|
18
|
+
* update (a routing param, like `message_thread_id`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function buildRichDraft(draftId: number, raw: string): {
|
|
21
|
+
draft_id: number;
|
|
22
|
+
rich_message: {
|
|
23
|
+
markdown: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Whether a granted send should stream a rich draft. Fail-closed: every clause
|
|
28
|
+
* must hold, otherwise no draft is sent. Mirrors `shouldPromoteRich` but targets
|
|
29
|
+
* the LIVE lane and the live-only `richDraftMarkdown` marker (set by
|
|
30
|
+
* `renderThreadedFrame` for non-finalized turn frames).
|
|
31
|
+
*/
|
|
32
|
+
export declare function shouldStreamDraft(input: {
|
|
33
|
+
enabled?: boolean;
|
|
34
|
+
send: ThreadedSend;
|
|
35
|
+
}): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Per-session debounce + monotonic draft-id state for draft streaming. Skips a
|
|
38
|
+
* draft when less than `debounceMs` has elapsed since the session's last SENT
|
|
39
|
+
* draft (the rate-limit pool already coalesces live frames to the latest, so a
|
|
40
|
+
* skipped frame is naturally superseded by the next one). `reset` clears a
|
|
41
|
+
* session's window when its turn finalizes so the next turn starts fresh.
|
|
42
|
+
*/
|
|
43
|
+
export declare class DraftStreamState {
|
|
44
|
+
#private;
|
|
45
|
+
constructor(debounceMs?: number);
|
|
46
|
+
/**
|
|
47
|
+
* If enough time has elapsed since the session's last draft, record `now` as
|
|
48
|
+
* the new last-sent time and return the next monotonic draft id; otherwise
|
|
49
|
+
* return `undefined` (debounced — the caller skips this frame).
|
|
50
|
+
*/
|
|
51
|
+
tryClaim(sessionId: string, now: number): number | undefined;
|
|
52
|
+
/** Clear a session's debounce window (called when its turn finalizes). The
|
|
53
|
+
* global draft id keeps incrementing so ids are never reused across turns. */
|
|
54
|
+
reset(sessionId: string): void;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Best-effort delivery of a rich draft. Never throws and has no HTML fallback: a
|
|
58
|
+
* draft is a purely additive preview, so on any failure (a thrown transport
|
|
59
|
+
* error or an `{ ok: false }` JSON response — the transport returns `res.json()`
|
|
60
|
+
* for JSON methods, so `ok:false` does not throw) it warns exactly once and
|
|
61
|
+
* returns; the unchanged live HTML send still carries the content.
|
|
62
|
+
*/
|
|
63
|
+
export declare function deliverDraft(botApi: BotApi, base: {
|
|
64
|
+
chat_id: string | number;
|
|
65
|
+
message_thread_id?: number;
|
|
66
|
+
}, draftId: number, raw: string, log?: {
|
|
67
|
+
warn(msg: string): void;
|
|
68
|
+
}): Promise<void>;
|