@sayknow-cli/coding-agent 0.3.11 → 0.3.12
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 +0 -21
- package/dist/types/build-metadata.d.ts +7 -0
- package/dist/types/capability/mcp.d.ts +3 -1
- package/dist/types/commands/mcp.d.ts +1 -1
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/modes/acp/acp-event-mapper.d.ts +2 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -0
- package/dist/types/modes/components/status-line/types.d.ts +6 -0
- package/dist/types/modes/components/status-line.d.ts +1 -0
- package/dist/types/modes/components/welcome.d.ts +1 -0
- package/dist/types/modes/rpc/rpc-client.d.ts +7 -2
- package/dist/types/modes/utils/ui-helpers.d.ts +12 -0
- package/dist/types/notifications/telegram-daemon.d.ts +2 -0
- package/dist/types/runtime-mcp/config-writer.d.ts +4 -3
- package/dist/types/runtime-mcp/types.d.ts +4 -3
- package/dist/types/session/agent-session.d.ts +16 -0
- package/dist/types/session/session-manager.d.ts +1 -0
- package/dist/types/tools/skill.d.ts +9 -8
- package/dist/types/utils/linkedom.d.ts +4 -0
- package/dist/types/utils/pasted-image-path.d.ts +5 -3
- package/package.json +7 -7
- package/scripts/build-binary.ts +2 -43
- package/scripts/compile-args.ts +106 -0
- package/scripts/generate-docs-index.ts +1 -0
- package/src/build-metadata.ts +104 -0
- package/src/capability/mcp.ts +3 -1
- package/src/cli/mcp-cli.ts +108 -26
- package/src/cli.ts +21 -0
- package/src/commands/mcp.ts +8 -8
- package/src/commands/stats.ts +6 -2
- package/src/config/keybindings.ts +2 -2
- package/src/config/mcp-schema.json +21 -17
- package/src/config/model-profiles.ts +23 -23
- package/src/discovery/builtin.ts +14 -0
- package/src/discovery/mcp-json.ts +14 -0
- package/src/eval/js/executor.ts +7 -1
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/skc-protocol.ts +14 -1
- package/src/modes/acp/acp-agent.ts +72 -16
- package/src/modes/acp/acp-client-bridge.ts +27 -5
- package/src/modes/acp/acp-event-mapper.ts +39 -1
- package/src/modes/components/assistant-message.ts +1 -1
- package/src/modes/components/hook-selector.ts +4 -0
- package/src/modes/components/model-selector.ts +17 -6
- package/src/modes/components/session-selector.ts +2 -2
- package/src/modes/components/status-line/presets.ts +5 -19
- package/src/modes/components/status-line/segments.ts +14 -0
- package/src/modes/components/status-line/types.ts +6 -0
- package/src/modes/components/status-line.ts +13 -6
- package/src/modes/components/tool-execution.ts +1 -1
- package/src/modes/components/welcome.ts +4 -1
- package/src/modes/controllers/command-controller.ts +1 -1
- package/src/modes/controllers/event-controller.ts +9 -9
- package/src/modes/controllers/input-controller.ts +8 -2
- package/src/modes/controllers/selector-controller.ts +7 -3
- package/src/modes/interactive-mode.ts +12 -4
- package/src/modes/rpc/rpc-client.ts +30 -6
- package/src/modes/utils/ui-helpers.ts +154 -32
- package/src/notifications/telegram-daemon.ts +28 -2
- package/src/prompts/tools/skill.md +2 -2
- package/src/runtime-mcp/config-writer.ts +4 -3
- package/src/runtime-mcp/config.ts +1 -0
- package/src/runtime-mcp/types.ts +4 -3
- package/src/session/agent-session.ts +117 -3
- package/src/session/session-manager.ts +68 -40
- package/src/skc-runtime/state-runtime.ts +105 -12
- package/src/skc-runtime/workflow-manifest.generated.json +4 -28
- package/src/skc-runtime/workflow-manifest.ts +1 -7
- package/src/slash-commands/builtin-registry.ts +9 -4
- package/src/tools/bash-interactive.ts +9 -4
- package/src/tools/browser/readable.ts +2 -2
- package/src/tools/fetch.ts +5 -5
- package/src/tools/skill.ts +14 -11
- package/src/utils/linkedom.ts +14 -0
- package/src/utils/pasted-image-path.ts +23 -9
- package/src/web/scrapers/arxiv.ts +2 -2
- package/src/web/scrapers/go-pkg.ts +2 -2
- package/src/web/scrapers/iacr.ts +2 -2
- package/src/web/scrapers/readthedocs.ts +2 -2
- package/src/web/scrapers/twitter.ts +3 -2
- package/src/web/scrapers/wikipedia.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,27 +4,6 @@ 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.11] — 2026-07-09
|
|
8
|
-
|
|
9
|
-
### Fixed
|
|
10
|
-
|
|
11
|
-
- Restored npm source-install native loading by probing the platform optional
|
|
12
|
-
package (`@sayknow-cli/natives-<platform>`) when the stable native loader package
|
|
13
|
-
no longer carries `.node` binaries directly.
|
|
14
|
-
|
|
15
|
-
## [0.3.10] — 2026-07-09
|
|
16
|
-
|
|
17
|
-
### Changed
|
|
18
|
-
|
|
19
|
-
- Synced onto upstream **gajae-code v0.9.2**, carrying the 0.9.2 patch set into
|
|
20
|
-
Sayknow-CLI while preserving the SKC fork layer and release surface.
|
|
21
|
-
|
|
22
|
-
### Fixed
|
|
23
|
-
|
|
24
|
-
- Updated the release version surfaces so `skc --version`, package metadata,
|
|
25
|
-
native sentinel exports, plugin metadata, schemas, and public sync checks report
|
|
26
|
-
**0.3.10** consistently.
|
|
27
|
-
|
|
28
7
|
## [0.3.0] — 2026-06-23
|
|
29
8
|
|
|
30
9
|
### Changed
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type BuildChannel = "release" | "dev" | "local-source" | "package-install" | "compiled" | "unknown";
|
|
2
|
+
export interface BuildMetadata {
|
|
3
|
+
channel: BuildChannel;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function resolveBuildMetadata(moduleDir?: string): BuildMetadata;
|
|
7
|
+
export declare function formatBuildLabel(metadata?: BuildMetadata): string;
|
|
@@ -7,7 +7,7 @@ export interface MCPServer {
|
|
|
7
7
|
name: string;
|
|
8
8
|
/** Whether this server is enabled (default: true) */
|
|
9
9
|
enabled?: boolean;
|
|
10
|
-
/** Whether
|
|
10
|
+
/** Whether explicit runtime MCP consumers should connect automatically (default: true) */
|
|
11
11
|
autoload?: boolean;
|
|
12
12
|
/** Connection timeout in milliseconds */
|
|
13
13
|
timeout?: number;
|
|
@@ -17,6 +17,8 @@ export interface MCPServer {
|
|
|
17
17
|
args?: string[];
|
|
18
18
|
/** Environment variables */
|
|
19
19
|
env?: Record<string, string>;
|
|
20
|
+
/** Whether explicit stdio runtime consumers should avoid inheriting host environment */
|
|
21
|
+
noInheritEnv?: boolean;
|
|
20
22
|
/** Working directory for stdio transport */
|
|
21
23
|
cwd?: string;
|
|
22
24
|
/** URL (for HTTP/SSE transport) */
|
|
@@ -297,11 +297,11 @@ export declare const KEYBINDINGS: {
|
|
|
297
297
|
};
|
|
298
298
|
readonly "app.session.delete": {
|
|
299
299
|
readonly defaultKeys: "ctrl+d";
|
|
300
|
-
readonly description: "Delete session";
|
|
300
|
+
readonly description: "Delete current session transcript/artifacts";
|
|
301
301
|
};
|
|
302
302
|
readonly "app.session.deleteNoninvasive": {
|
|
303
303
|
readonly defaultKeys: "ctrl+backspace";
|
|
304
|
-
readonly description: "Delete session (non-invasive)";
|
|
304
|
+
readonly description: "Delete selected session transcript/artifacts (non-invasive)";
|
|
305
305
|
};
|
|
306
306
|
readonly "app.tree.foldOrUp": {
|
|
307
307
|
readonly defaultKeys: ["ctrl+left", "alt+left"];
|
|
@@ -16,6 +16,8 @@ interface AcpEventMapperOptions {
|
|
|
16
16
|
* before emitting `ToolCallLocation` entries.
|
|
17
17
|
*/
|
|
18
18
|
cwd?: string;
|
|
19
|
+
/** Phase to expose after compaction ends. Prompt-bound compaction resumes responding; idle maintenance returns idle. */
|
|
20
|
+
compactionEndPhase?: "responding" | "idle";
|
|
19
21
|
}
|
|
20
22
|
export declare function mapToolKind(toolName: string): ToolKind;
|
|
21
23
|
export declare function mapAgentWireEventPayloadToAcpSessionUpdates(payload: AgentWireEventPayload, sessionId: string, options?: AcpEventMapperOptions): SessionNotification[];
|
|
@@ -48,6 +48,7 @@ export interface HookSelectorOptions {
|
|
|
48
48
|
export declare class HookSelectorComponent extends Container {
|
|
49
49
|
#private;
|
|
50
50
|
constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void, opts?: HookSelectorOptions);
|
|
51
|
+
hasActiveInlineInput(): boolean;
|
|
51
52
|
handleInput(keyData: string): void;
|
|
52
53
|
dispose(): void;
|
|
53
54
|
}
|
|
@@ -27,6 +27,12 @@ export interface SegmentContext {
|
|
|
27
27
|
};
|
|
28
28
|
contextPercent: number;
|
|
29
29
|
contextWindow: number;
|
|
30
|
+
/**
|
|
31
|
+
* True when a standalone `context_pct` segment is also part of the active
|
|
32
|
+
* layout. The model segment suppresses its inline percentage in that case to
|
|
33
|
+
* avoid showing the same value twice.
|
|
34
|
+
*/
|
|
35
|
+
contextPctSegmentActive?: boolean;
|
|
30
36
|
autoCompactEnabled: boolean;
|
|
31
37
|
subagentCount: number;
|
|
32
38
|
jobs: JobsSnapshot;
|
|
@@ -14,6 +14,7 @@ export interface WelcomeComponentOptions {
|
|
|
14
14
|
getReservedBottomRows?: (termWidth: number) => number;
|
|
15
15
|
changelogMarkdown?: string;
|
|
16
16
|
collapseChangelog?: boolean;
|
|
17
|
+
buildLabel?: string;
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Sayknow-CLI launch surface: a blue-gradient SAYKNOW wordmark, compact
|
|
@@ -7,7 +7,7 @@ import type { AgentEvent, AgentMessage, AgentToolResult, ThinkingLevel } from "@
|
|
|
7
7
|
import type { CompactionResult } from "@sayknow-cli/agent-core/compaction";
|
|
8
8
|
import type { ImageContent, Model } from "@sayknow-cli/ai";
|
|
9
9
|
import type { BashResult } from "../../exec/bash-executor";
|
|
10
|
-
import type { SessionStats } from "../../session/agent-session";
|
|
10
|
+
import type { AgentSessionEvent, SessionStats } from "../../session/agent-session";
|
|
11
11
|
import type { RpcExtensionUIRequest, RpcGetStateInclude, RpcHandoffResult, RpcHostToolDefinition, RpcSessionState, RpcUnattendedAccepted, RpcUnattendedDeclaration, RpcWorkflowGate, RpcWorkflowGateResolution } from "./rpc-types";
|
|
12
12
|
export interface RpcClientOptions {
|
|
13
13
|
/** Dial an existing Unix-domain socket instead of spawning a stdio child. */
|
|
@@ -37,6 +37,7 @@ export interface RpcClientOptions {
|
|
|
37
37
|
}
|
|
38
38
|
export type ModelInfo = Pick<Model, "provider" | "id" | "contextWindow" | "reasoning" | "thinking">;
|
|
39
39
|
export type RpcEventListener = (event: AgentEvent) => void;
|
|
40
|
+
export type RpcSessionEventListener = (event: AgentSessionEvent) => void;
|
|
40
41
|
export interface RpcClientToolContext<TDetails = unknown> {
|
|
41
42
|
toolCallId: string;
|
|
42
43
|
signal: AbortSignal;
|
|
@@ -72,9 +73,13 @@ export declare class RpcClient {
|
|
|
72
73
|
*/
|
|
73
74
|
[Symbol.dispose](): void;
|
|
74
75
|
/**
|
|
75
|
-
* Subscribe to
|
|
76
|
+
* Subscribe to the legacy core AgentEvent subset.
|
|
76
77
|
*/
|
|
77
78
|
onEvent(listener: RpcEventListener): () => void;
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to all renderer-facing agent session events.
|
|
81
|
+
*/
|
|
82
|
+
onSessionEvent(listener: RpcSessionEventListener): () => void;
|
|
78
83
|
/**
|
|
79
84
|
* Subscribe to workflow lifecycle gates emitted by RPC mode.
|
|
80
85
|
*/
|
|
@@ -7,6 +7,18 @@ interface RenderInitialMessagesOptions {
|
|
|
7
7
|
preserveExistingChat?: boolean;
|
|
8
8
|
}
|
|
9
9
|
export declare function argsWithPartialJson(args: unknown, partialJson: unknown): unknown;
|
|
10
|
+
export declare class CollapsedChatHistoryComponent implements Component {
|
|
11
|
+
readonly isCollapsedChatHistory = true;
|
|
12
|
+
count: number;
|
|
13
|
+
startTime: number;
|
|
14
|
+
endTime: number;
|
|
15
|
+
constructor(count: number, startTime: number, endTime: number);
|
|
16
|
+
merge(count: number, startTime: number, endTime: number): void;
|
|
17
|
+
render(_width: number): string[];
|
|
18
|
+
invalidate(): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function addChatChild(ctx: InteractiveModeContext, component: Component): void;
|
|
21
|
+
export declare function trimChatChildren(ctx: InteractiveModeContext): void;
|
|
10
22
|
export declare class UiHelpers {
|
|
11
23
|
#private;
|
|
12
24
|
private ctx;
|
|
@@ -375,6 +375,8 @@ export declare class TelegramNotificationDaemon {
|
|
|
375
375
|
private rememberPendingThreadedFrame;
|
|
376
376
|
private flushPendingThreadedFrames;
|
|
377
377
|
private ensureTopic;
|
|
378
|
+
private topicPastOrphanGrace;
|
|
379
|
+
private deleteOrphanedTopic;
|
|
378
380
|
private deleteTopic;
|
|
379
381
|
private persistTopics;
|
|
380
382
|
loadTopics(): Promise<void>;
|
|
@@ -70,10 +70,11 @@ export declare function getMCPServer(filePath: string, name: string): Promise<MC
|
|
|
70
70
|
*/
|
|
71
71
|
export declare function listMCPServers(filePath: string): Promise<string[]>;
|
|
72
72
|
/**
|
|
73
|
-
* Set a server's autoload flag
|
|
73
|
+
* Set a server's autoload flag for explicit runtime MCP consumers.
|
|
74
74
|
*
|
|
75
|
-
* Autoload defaults to true, so turning it on
|
|
76
|
-
* config file free of redundant fields; turning it
|
|
75
|
+
* Autoload defaults to true for consumers that honor it, so turning it on
|
|
76
|
+
* removes the key to keep the config file free of redundant fields; turning it
|
|
77
|
+
* off writes `autoload: false`.
|
|
77
78
|
*
|
|
78
79
|
* @throws Error if the server doesn't exist
|
|
79
80
|
*/
|
|
@@ -46,9 +46,10 @@ interface MCPServerConfigBase {
|
|
|
46
46
|
/** Whether this server is enabled (default: true) */
|
|
47
47
|
enabled?: boolean;
|
|
48
48
|
/**
|
|
49
|
-
* Whether
|
|
50
|
-
*
|
|
51
|
-
*
|
|
49
|
+
* Whether an explicit runtime MCP consumer should connect this server
|
|
50
|
+
* automatically when that consumer starts (default: true). Normal standalone
|
|
51
|
+
* `skc`, `skc --tmux`, and print-mode sessions do not consume `skc mcp`
|
|
52
|
+
* registrations today.
|
|
52
53
|
*/
|
|
53
54
|
autoload?: boolean;
|
|
54
55
|
/** Connection timeout in milliseconds (default: 30000) */
|
|
@@ -156,6 +156,10 @@ export interface AsyncJobSnapshot {
|
|
|
156
156
|
recent: AsyncJobSnapshotItem[];
|
|
157
157
|
delivery: AsyncJobDeliveryState;
|
|
158
158
|
}
|
|
159
|
+
export interface RetainedMemorySample {
|
|
160
|
+
tuiChatChildren?: number;
|
|
161
|
+
tuiCachedRenderBytes?: number;
|
|
162
|
+
}
|
|
159
163
|
export interface AgentSessionConfig {
|
|
160
164
|
agent: Agent;
|
|
161
165
|
sessionManager: SessionManager;
|
|
@@ -237,6 +241,8 @@ export interface AgentSessionConfig {
|
|
|
237
241
|
* **MUST NOT** dispose it on their own teardown.
|
|
238
242
|
*/
|
|
239
243
|
ownedAsyncJobManager?: AsyncJobManager;
|
|
244
|
+
/** Cheap TUI retained-memory counters; absent for headless sessions. */
|
|
245
|
+
retainedMemorySampler?: () => RetainedMemorySample;
|
|
240
246
|
/**
|
|
241
247
|
* MCPManager whose lifecycle this session owns (top-level sessions that
|
|
242
248
|
* connected plugin-bundle MCP servers). Only the owned manager is
|
|
@@ -368,6 +374,15 @@ export declare const __agentSessionPerfCounters: {
|
|
|
368
374
|
reset(): void;
|
|
369
375
|
};
|
|
370
376
|
export declare function buildContextInjectionSignature(kind: string, parts: readonly string[]): string;
|
|
377
|
+
export declare class StreamingEditFileCache {
|
|
378
|
+
#private;
|
|
379
|
+
get(path: string): string | undefined;
|
|
380
|
+
set(path: string, content: string): void;
|
|
381
|
+
delete(path: string): void;
|
|
382
|
+
clear(): void;
|
|
383
|
+
has(path: string): boolean;
|
|
384
|
+
get totalBytes(): number;
|
|
385
|
+
}
|
|
371
386
|
export declare class AgentSession {
|
|
372
387
|
#private;
|
|
373
388
|
readonly agent: Agent;
|
|
@@ -935,6 +950,7 @@ export declare class AgentSession {
|
|
|
935
950
|
prepareContributionPrep(options?: ContributionPrepOptions): Promise<ContributionPrepResult>;
|
|
936
951
|
/** Test seam: override the emergency-compaction resource sampler so tests never read real RSS. */
|
|
937
952
|
setResourceSampler(sampler: () => EmergencyCompactionSample): void;
|
|
953
|
+
setRetainedMemorySampler(sampler: (() => RetainedMemorySample) | undefined): void;
|
|
938
954
|
/**
|
|
939
955
|
* Toggle auto-compaction setting.
|
|
940
956
|
*/
|
|
@@ -535,6 +535,7 @@ export declare class SessionManager {
|
|
|
535
535
|
getInjectedTtsrRules(): string[];
|
|
536
536
|
getLeafId(): string | null;
|
|
537
537
|
getLeafEntry(): SessionEntry | undefined;
|
|
538
|
+
getResidentImageBytes(): number;
|
|
538
539
|
/**
|
|
539
540
|
* Get the most recent model role from the current session path.
|
|
540
541
|
* Returns undefined if no model change has been recorded.
|
|
@@ -4,15 +4,16 @@
|
|
|
4
4
|
* Lets the agent hand off to another available skill in the current turn. The
|
|
5
5
|
* callee's SKILL.md is dispatched through the same custom-message path used by
|
|
6
6
|
* `/skill:<name>` typing, as a user-attribution message delivered same-turn
|
|
7
|
-
* (without `deliverAs: "nextTurn"`).
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* (without `deliverAs: "nextTurn"`). When the caller is one of the canonical
|
|
8
|
+
* workflow skills, the tool first runs the native state handoff so workflow
|
|
9
|
+
* mode-state and `skill-active-state.json` transition atomically. Runtime
|
|
10
|
+
* project/user skills have no native workflow mode-state, so they are dispatched
|
|
11
|
+
* directly and tracked by the prompt observer instead.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
* `{complete, completed, handoff, failed, cancelled, canceled, inactive}`.
|
|
14
|
-
* agent declares readiness either by writing `current_phase: "handoff"` to
|
|
15
|
-
* mode-state or by running the handoff verb directly.
|
|
13
|
+
* Canonical workflow chaining is refused unless the caller's `current_phase` is
|
|
14
|
+
* in `{complete, completed, handoff, failed, cancelled, canceled, inactive}`.
|
|
15
|
+
* The agent declares readiness either by writing `current_phase: "handoff"` to
|
|
16
|
+
* its mode-state or by running the handoff verb directly.
|
|
16
17
|
*/
|
|
17
18
|
import type { AgentTool, AgentToolResult } from "@sayknow-cli/agent-core";
|
|
18
19
|
import * as z from "zod/v4";
|
|
@@ -23,8 +23,10 @@ export interface ResolvePastedImagePathOptions extends DecodePastedPathOptions {
|
|
|
23
23
|
*/
|
|
24
24
|
export declare function decodePastedPathCandidate(text: string, options?: DecodePastedPathOptions): string | undefined;
|
|
25
25
|
/**
|
|
26
|
-
* Returns the resolved path when the whole pasted text is a
|
|
27
|
-
* existing image file
|
|
28
|
-
*
|
|
26
|
+
* Returns the resolved path when the whole pasted text is a recognized clipboard
|
|
27
|
+
* temp path to an existing image file, otherwise `undefined` (the paste is
|
|
28
|
+
* inserted as text). Arbitrary saved image paths are not auto-attached here;
|
|
29
|
+
* users attach them explicitly with `@path/to/image.png`.
|
|
29
30
|
*/
|
|
30
31
|
export declare function resolvePastedImagePath(text: string, options?: ResolvePastedImagePathOptions): string | undefined;
|
|
32
|
+
export declare function formatPastedImageReference(placeholder: string, imagePath: string): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@sayknow-cli/coding-agent",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.12",
|
|
5
5
|
"description": "Sayknow-CLI CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://sayknow-cli.com",
|
|
7
7
|
"author": "jaybeyond",
|
|
@@ -52,12 +52,12 @@
|
|
|
52
52
|
"@agentclientprotocol/sdk": "0.21.0",
|
|
53
53
|
"@babel/parser": "^7.29.3",
|
|
54
54
|
"@mozilla/readability": "^0.6.0",
|
|
55
|
-
"@sayknow-cli/stats": "0.3.
|
|
56
|
-
"@sayknow-cli/agent-core": "0.3.
|
|
57
|
-
"@sayknow-cli/ai": "0.3.
|
|
58
|
-
"@sayknow-cli/natives": "0.3.
|
|
59
|
-
"@sayknow-cli/tui": "0.3.
|
|
60
|
-
"@sayknow-cli/utils": "0.3.
|
|
55
|
+
"@sayknow-cli/stats": "0.3.12",
|
|
56
|
+
"@sayknow-cli/agent-core": "0.3.12",
|
|
57
|
+
"@sayknow-cli/ai": "0.3.12",
|
|
58
|
+
"@sayknow-cli/natives": "0.3.12",
|
|
59
|
+
"@sayknow-cli/tui": "0.3.12",
|
|
60
|
+
"@sayknow-cli/utils": "0.3.12",
|
|
61
61
|
"@puppeteer/browsers": "^2.13.0",
|
|
62
62
|
"@types/turndown": "5.0.6",
|
|
63
63
|
"@xterm/headless": "^6.0.0",
|
package/scripts/build-binary.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
|
+
import { buildDevCompileArgs } from "./compile-args";
|
|
4
5
|
|
|
5
6
|
const packageDir = path.join(import.meta.dir, "..");
|
|
6
7
|
const outputPath = path.join(packageDir, "dist", "skc");
|
|
@@ -34,49 +35,7 @@ async function main(): Promise<void> {
|
|
|
34
35
|
await runCommand(["bun", "--cwd=../natives", "run", "embed:native"]);
|
|
35
36
|
try {
|
|
36
37
|
const buildEnv = shouldAdhocSignDarwinBinary() ? { ...Bun.env, BUN_NO_CODESIGN_MACHO_BINARY: "1" } : Bun.env;
|
|
37
|
-
await runCommand(
|
|
38
|
-
[
|
|
39
|
-
"bun",
|
|
40
|
-
"build",
|
|
41
|
-
"--compile",
|
|
42
|
-
// Minify shrinks the bundled JS the compiled binary must parse at
|
|
43
|
-
// startup (302MB → ~114MB --help RSS measured on darwin-arm64).
|
|
44
|
-
// --keep-names below preserves identifiers for error reports.
|
|
45
|
-
"--minify",
|
|
46
|
-
"--no-compile-autoload-bunfig",
|
|
47
|
-
"--no-compile-autoload-dotenv",
|
|
48
|
-
"--no-compile-autoload-tsconfig",
|
|
49
|
-
"--no-compile-autoload-package-json",
|
|
50
|
-
"--keep-names",
|
|
51
|
-
"--define",
|
|
52
|
-
'process.env.PI_COMPILED="true"',
|
|
53
|
-
"--external",
|
|
54
|
-
"mupdf",
|
|
55
|
-
"--root",
|
|
56
|
-
"../..",
|
|
57
|
-
"./src/cli.ts",
|
|
58
|
-
// Worker entrypoints. Bun's `--compile` discovers the literal in
|
|
59
|
-
// `new Worker("…", …)` at each spawn site, but only actually
|
|
60
|
-
// emits the worker into the bunfs root when it is listed here as
|
|
61
|
-
// an explicit additional entry. Paths are relative to this
|
|
62
|
-
// script's cwd (packages/coding-agent) and the `--root` above
|
|
63
|
-
// (../..) makes them appear inside the binary at
|
|
64
|
-
// `/$bunfs/root/packages/<pkg>/src/<worker>.js`, which is
|
|
65
|
-
// exactly what the literals at the spawn sites resolve to.
|
|
66
|
-
"../stats/src/sync-worker.ts",
|
|
67
|
-
"./src/tools/browser/tab-worker-entry.ts",
|
|
68
|
-
"./src/eval/js/worker-entry.ts",
|
|
69
|
-
// Hidden notify daemon CLI (loaded via dynamic import from notify-cli); list it
|
|
70
|
-
// explicitly so Bun standalone keeps `skc notify daemon-internal` usable.
|
|
71
|
-
"./src/notifications/telegram-daemon-cli.ts",
|
|
72
|
-
// Hidden Telegram Remote gateway entrypoint. `skc telegram start` self-spawns
|
|
73
|
-
// `skc telegram __gateway`, which dynamic-imports this bundled entry.
|
|
74
|
-
"../telegram-remote/src/index.ts",
|
|
75
|
-
"--outfile",
|
|
76
|
-
"dist/skc",
|
|
77
|
-
],
|
|
78
|
-
buildEnv,
|
|
79
|
-
);
|
|
38
|
+
await runCommand(buildDevCompileArgs(), buildEnv);
|
|
80
39
|
|
|
81
40
|
await stageWorkspaceNativeAddons();
|
|
82
41
|
// Bun 1.3.12 emits a truncated Mach-O signature on darwin builds.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export interface CompileArgOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
entrypoints: string[];
|
|
4
|
+
outfile: string;
|
|
5
|
+
target?: string;
|
|
6
|
+
defines?: string[];
|
|
7
|
+
externals?: string[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const compileAutoloadDisableFlags = [
|
|
11
|
+
"--no-compile-autoload-bunfig",
|
|
12
|
+
"--no-compile-autoload-dotenv",
|
|
13
|
+
"--no-compile-autoload-tsconfig",
|
|
14
|
+
"--no-compile-autoload-package-json",
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const compiledDefineFlags = ['process.env.PI_COMPILED="true"'];
|
|
18
|
+
const releaseDefineFlags = [...compiledDefineFlags, 'process.env.SKC_BUILD_CHANNEL="release"'];
|
|
19
|
+
const devDefineFlags = [...compiledDefineFlags, 'process.env.SKC_BUILD_CHANNEL="dev"'];
|
|
20
|
+
|
|
21
|
+
export const compiledExternalPackages = ["mupdf"];
|
|
22
|
+
|
|
23
|
+
export const releaseEntrypoints = [
|
|
24
|
+
"./packages/coding-agent/src/cli.ts",
|
|
25
|
+
"./packages/stats/src/sync-worker.ts",
|
|
26
|
+
"./packages/coding-agent/src/tools/browser/tab-worker-entry.ts",
|
|
27
|
+
"./packages/coding-agent/src/eval/js/worker-entry.ts",
|
|
28
|
+
"./packages/natives/native/index.js",
|
|
29
|
+
"./packages/coding-agent/src/notifications/telegram-daemon-cli.ts",
|
|
30
|
+
// Hidden Telegram Remote gateway entrypoint. `skc telegram start` self-spawns
|
|
31
|
+
// `skc telegram __gateway`, which dynamic-imports this bundled entry.
|
|
32
|
+
"./packages/telegram-remote/src/index.ts",
|
|
33
|
+
// NOTE: models.json must NOT be listed here — `bun build --compile` does not
|
|
34
|
+
// emit `.json` extra entrypoints into the bunfs. It is embedded via the
|
|
35
|
+
// `with { type: "file" }` import in packages/ai/src/models.ts instead.
|
|
36
|
+
// NOTE: handlebars must NOT be listed here either — the extra entrypoint
|
|
37
|
+
// silently vanished from minified bundles and crashed v0.9.3–v0.9.6
|
|
38
|
+
// releases at startup (#1939). It is bundled via the statically-traceable
|
|
39
|
+
// `require("handlebars")` in packages/utils/src/prompt.ts instead.
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
export const devEntrypoints = [
|
|
43
|
+
"./src/cli.ts",
|
|
44
|
+
"../stats/src/sync-worker.ts",
|
|
45
|
+
"./src/tools/browser/tab-worker-entry.ts",
|
|
46
|
+
"./src/eval/js/worker-entry.ts",
|
|
47
|
+
"./src/notifications/telegram-daemon-cli.ts",
|
|
48
|
+
"../telegram-remote/src/index.ts",
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
export function buildReleaseCompileArgs(target: string, outfile: string): string[] {
|
|
52
|
+
return buildCompileArgs({
|
|
53
|
+
root: ".",
|
|
54
|
+
entrypoints: releaseEntrypoints,
|
|
55
|
+
outfile,
|
|
56
|
+
target,
|
|
57
|
+
defines: releaseDefineFlags,
|
|
58
|
+
|
|
59
|
+
externals: compiledExternalPackages,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function buildDevCompileArgs(outfile = "dist/skc"): string[] {
|
|
64
|
+
return buildCompileArgs({
|
|
65
|
+
root: "../..",
|
|
66
|
+
entrypoints: devEntrypoints,
|
|
67
|
+
outfile,
|
|
68
|
+
defines: devDefineFlags,
|
|
69
|
+
externals: compiledExternalPackages,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function buildCompileArgs(options: CompileArgOptions): string[] {
|
|
74
|
+
const args = [
|
|
75
|
+
"bun",
|
|
76
|
+
"build",
|
|
77
|
+
"--compile",
|
|
78
|
+
// Minify shrinks the bundled JS the compiled binary must parse at
|
|
79
|
+
// startup (302MB → ~114MB --help RSS measured on darwin-arm64).
|
|
80
|
+
// --keep-names below preserves identifiers for error reports.
|
|
81
|
+
// SAFE with handlebars since #1939: the module is bundled via a
|
|
82
|
+
// statically-traceable require in packages/utils/src/prompt.ts, not a
|
|
83
|
+
// bunfs extra entrypoint (which --minify silently dropped, crashing
|
|
84
|
+
// v0.9.3–v0.9.6 releases at startup).
|
|
85
|
+
"--minify",
|
|
86
|
+
...compileAutoloadDisableFlags,
|
|
87
|
+
"--keep-names",
|
|
88
|
+
];
|
|
89
|
+
|
|
90
|
+
for (const define of options.defines ?? []) {
|
|
91
|
+
args.push("--define", define);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
args.push("--root", options.root);
|
|
95
|
+
|
|
96
|
+
for (const external of options.externals ?? []) {
|
|
97
|
+
args.push("--external", external);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (options.target) {
|
|
101
|
+
args.push("--target", options.target);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
args.push(...options.entrypoints, "--outfile", options.outfile);
|
|
105
|
+
return args;
|
|
106
|
+
}
|
|
@@ -58,6 +58,7 @@ const mapEntries = docsWithContent
|
|
|
58
58
|
.join("\n");
|
|
59
59
|
const output = [
|
|
60
60
|
"// Auto-generated by scripts/generate-docs-index.ts - DO NOT EDIT",
|
|
61
|
+
`Reflect.set(globalThis, Symbol.for("skc.docs-index.generated.loaded"), true);`,
|
|
61
62
|
"",
|
|
62
63
|
`export const EMBEDDED_DOC_FILENAMES: readonly string[] = ${filenamesLiteral};`,
|
|
63
64
|
"",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { isCompiledBinary } from "@sayknow-cli/utils/env";
|
|
4
|
+
|
|
5
|
+
export type BuildChannel = "release" | "dev" | "local-source" | "package-install" | "compiled" | "unknown";
|
|
6
|
+
|
|
7
|
+
export interface BuildMetadata {
|
|
8
|
+
channel: BuildChannel;
|
|
9
|
+
label: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const REPO_MARKERS = [".git", "bun.lock"];
|
|
13
|
+
const SOURCE_REPO_PACKAGE_NAME = "sayknow-cli";
|
|
14
|
+
|
|
15
|
+
export function resolveBuildMetadata(moduleDir: string = import.meta.dir): BuildMetadata {
|
|
16
|
+
const explicitChannel = normalizeBuildChannel(process.env.SKC_BUILD_CHANNEL);
|
|
17
|
+
if (explicitChannel) {
|
|
18
|
+
return metadataForChannel(explicitChannel);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (isCompiledBinary()) {
|
|
22
|
+
return metadataForChannel("compiled");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (isLocalSourceTree(moduleDir)) {
|
|
26
|
+
return metadataForChannel("local-source");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return metadataForChannel("package-install");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function formatBuildLabel(metadata: BuildMetadata = resolveBuildMetadata()): string {
|
|
33
|
+
return metadata.label;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function normalizeBuildChannel(value: string | undefined): BuildChannel | undefined {
|
|
37
|
+
const normalized = value?.trim().toLowerCase();
|
|
38
|
+
if (!normalized) return undefined;
|
|
39
|
+
switch (normalized) {
|
|
40
|
+
case "release":
|
|
41
|
+
case "stable":
|
|
42
|
+
return "release";
|
|
43
|
+
case "dev":
|
|
44
|
+
case "development":
|
|
45
|
+
return "dev";
|
|
46
|
+
case "local-source":
|
|
47
|
+
case "source":
|
|
48
|
+
case "local":
|
|
49
|
+
return "local-source";
|
|
50
|
+
case "package-install":
|
|
51
|
+
case "package":
|
|
52
|
+
case "npm":
|
|
53
|
+
return "package-install";
|
|
54
|
+
case "compiled":
|
|
55
|
+
return "compiled";
|
|
56
|
+
case "unknown":
|
|
57
|
+
return "unknown";
|
|
58
|
+
default:
|
|
59
|
+
return "unknown";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function metadataForChannel(channel: BuildChannel): BuildMetadata {
|
|
64
|
+
switch (channel) {
|
|
65
|
+
case "release":
|
|
66
|
+
return { channel, label: "release build" };
|
|
67
|
+
case "dev":
|
|
68
|
+
return { channel, label: "dev build" };
|
|
69
|
+
case "local-source":
|
|
70
|
+
return { channel, label: "local source" };
|
|
71
|
+
case "package-install":
|
|
72
|
+
return { channel, label: "package install" };
|
|
73
|
+
case "compiled":
|
|
74
|
+
return { channel, label: "compiled build" };
|
|
75
|
+
case "unknown":
|
|
76
|
+
return { channel, label: "build unknown" };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function isLocalSourceTree(startDir: string): boolean {
|
|
81
|
+
let current = path.resolve(startDir);
|
|
82
|
+
while (true) {
|
|
83
|
+
if (hasRepoMarkers(current)) return true;
|
|
84
|
+
const parent = path.dirname(current);
|
|
85
|
+
if (parent === current) return false;
|
|
86
|
+
current = parent;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function hasRepoMarkers(dir: string): boolean {
|
|
91
|
+
if (!REPO_MARKERS.every(marker => fs.existsSync(path.join(dir, marker)))) return false;
|
|
92
|
+
return readPackageName(path.join(dir, "package.json")) === SOURCE_REPO_PACKAGE_NAME;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function readPackageName(packageJsonPath: string): string | undefined {
|
|
96
|
+
try {
|
|
97
|
+
const parsed: unknown = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
98
|
+
if (typeof parsed !== "object" || parsed === null || !("name" in parsed)) return undefined;
|
|
99
|
+
const name = parsed.name;
|
|
100
|
+
return typeof name === "string" ? name : undefined;
|
|
101
|
+
} catch {
|
|
102
|
+
return undefined;
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/capability/mcp.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface MCPServer {
|
|
|
15
15
|
name: string;
|
|
16
16
|
/** Whether this server is enabled (default: true) */
|
|
17
17
|
enabled?: boolean;
|
|
18
|
-
/** Whether
|
|
18
|
+
/** Whether explicit runtime MCP consumers should connect automatically (default: true) */
|
|
19
19
|
autoload?: boolean;
|
|
20
20
|
/** Connection timeout in milliseconds */
|
|
21
21
|
timeout?: number;
|
|
@@ -25,6 +25,8 @@ export interface MCPServer {
|
|
|
25
25
|
args?: string[];
|
|
26
26
|
/** Environment variables */
|
|
27
27
|
env?: Record<string, string>;
|
|
28
|
+
/** Whether explicit stdio runtime consumers should avoid inheriting host environment */
|
|
29
|
+
noInheritEnv?: boolean;
|
|
28
30
|
/** Working directory for stdio transport */
|
|
29
31
|
cwd?: string;
|
|
30
32
|
/** URL (for HTTP/SSE transport) */
|