@sayknow-cli/coding-agent 0.5.2 → 0.5.8

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +66 -16
  2. package/dist/types/cli/update-cli.d.ts +8 -1
  3. package/dist/types/config/atomic-yaml-patch.d.ts +20 -1
  4. package/dist/types/config/keybindings.d.ts +10 -0
  5. package/dist/types/config/model-registry.d.ts +1 -1
  6. package/dist/types/config/models-config-schema.d.ts +4 -0
  7. package/dist/types/config/settings-schema.d.ts +73 -0
  8. package/dist/types/dap/client.d.ts +1 -0
  9. package/dist/types/lsp/client.d.ts +5 -0
  10. package/dist/types/modes/components/welcome.d.ts +1 -0
  11. package/dist/types/modes/controllers/selector-controller.d.ts +3 -1
  12. package/dist/types/modes/interactive-mode.d.ts +13 -1
  13. package/dist/types/modes/types.d.ts +7 -1
  14. package/dist/types/runtime-mcp/transports/stdio.d.ts +2 -0
  15. package/dist/types/session/agent-session.d.ts +8 -0
  16. package/dist/types/session/internal/managed-session-scope.d.ts +3 -1
  17. package/dist/types/session/internal/managed-session-storage.d.ts +2 -0
  18. package/dist/types/session/session-manager.d.ts +9 -0
  19. package/dist/types/session/session-storage.d.ts +17 -0
  20. package/dist/types/session-import/claude.d.ts +26 -0
  21. package/dist/types/session-import/codex.d.ts +22 -0
  22. package/dist/types/session-import/command.d.ts +20 -0
  23. package/dist/types/session-import/detect.d.ts +22 -0
  24. package/dist/types/session-import/index.d.ts +7 -0
  25. package/dist/types/session-import/redact.d.ts +23 -0
  26. package/dist/types/session-import/service.d.ts +28 -0
  27. package/dist/types/session-import/types.d.ts +125 -0
  28. package/dist/types/skc-runtime/launch-worktree.d.ts +17 -1
  29. package/dist/types/slash-commands/builtin-registry.d.ts +4 -0
  30. package/dist/types/slash-commands/types.d.ts +5 -0
  31. package/dist/types/system-prompt.d.ts +5 -0
  32. package/dist/types/tools/ask.d.ts +5 -0
  33. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  34. package/package.json +13 -7
  35. package/scripts/compile-args.ts +8 -4
  36. package/scripts/generate-sdk-operation-inventory.ts +5 -6
  37. package/src/cli/config-cli.ts +23 -8
  38. package/src/cli/update-cli.ts +265 -21
  39. package/src/config/atomic-yaml-patch.ts +167 -30
  40. package/src/config/keybindings.ts +10 -0
  41. package/src/config/model-profiles.ts +84 -16
  42. package/src/config/model-registry.ts +60 -38
  43. package/src/config/models-config-schema.ts +1 -1
  44. package/src/config/settings-schema.ts +79 -0
  45. package/src/config/settings.ts +13 -2
  46. package/src/dap/client.ts +78 -30
  47. package/src/internal-urls/docs-index.generated.ts +5 -4
  48. package/src/lsp/client.ts +17 -29
  49. package/src/modes/action-registry.ts +2 -0
  50. package/src/modes/components/welcome.ts +5 -0
  51. package/src/modes/controllers/goal-mode-controller.ts +7 -2
  52. package/src/modes/controllers/input-controller.ts +71 -6
  53. package/src/modes/controllers/plan-mode-controller.ts +8 -1
  54. package/src/modes/controllers/runtime-mcp-command-controller.ts +14 -0
  55. package/src/modes/controllers/selector-controller.ts +47 -19
  56. package/src/modes/interactive-mode.ts +54 -4
  57. package/src/modes/types.ts +5 -1
  58. package/src/prompts/system/system-prompt.md +8 -0
  59. package/src/runtime-mcp/transports/stdio.ts +96 -33
  60. package/src/sdk/broker/lifecycle.ts +6 -5
  61. package/src/sdk/protocol/operation-inventory.generated.json +33 -0
  62. package/src/sdk/session.ts +27 -18
  63. package/src/session/agent-session.ts +155 -15
  64. package/src/session/internal/managed-session-scope.ts +41 -6
  65. package/src/session/internal/managed-session-storage.ts +14 -0
  66. package/src/session/session-manager.ts +113 -11
  67. package/src/session/session-storage.ts +70 -0
  68. package/src/session-import/claude.ts +382 -0
  69. package/src/session-import/codex.ts +458 -0
  70. package/src/session-import/command.ts +61 -0
  71. package/src/session-import/detect.ts +133 -0
  72. package/src/session-import/index.ts +27 -0
  73. package/src/session-import/redact.ts +125 -0
  74. package/src/session-import/service.ts +749 -0
  75. package/src/session-import/types.ts +163 -0
  76. package/src/skc-runtime/launch-worktree.ts +277 -4
  77. package/src/slash-commands/acp-builtins.ts +5 -1
  78. package/src/slash-commands/builtin-registry.ts +100 -1
  79. package/src/slash-commands/types.ts +5 -0
  80. package/src/system-prompt.ts +7 -0
  81. package/src/tools/ask.ts +5 -0
  82. package/src/tools/fetch.ts +7 -2
  83. package/src/utils/markit.ts +24 -2
  84. package/src/utils/mupdf-wasm.ts +26 -0
  85. package/src/export/html/template.css +0 -1060
  86. package/src/export/html/template.html +0 -47
  87. package/src/export/html/template.js +0 -2348
  88. package/vendor/insane-search/engine/tests/test_hardening.py +0 -57
  89. package/vendor/insane-search/engine/tests/test_smoke.py +0 -152
  90. package/vendor/insane-search/engine/tests/test_u1.py +0 -200
  91. package/vendor/insane-search/engine/tests/test_u4.py +0 -131
  92. package/vendor/insane-search/engine/tests/test_u5.py +0 -163
  93. package/vendor/insane-search/engine/tests/test_u7.py +0 -124
  94. package/vendor/insane-search/engine/tests/test_u8.py +0 -216
package/CHANGELOG.md CHANGED
@@ -1,15 +1,65 @@
1
1
  # Changelog
2
2
 
3
- Sayknow-CLI is a rebranded fork of [gajae-code](https://github.com/Yeachan-Heo/gajae-code).
3
+ ## [Unreleased]
4
+
5
+ ## [0.5.8] - 2026-09-10
6
+
7
+ ## [0.5.7] - 2026-09-10
8
+
9
+ ### Added
10
+
11
+ - Added opt-in `reasoningLanguage: english`. Model reasoning quality on technical work is generally better in English, but that previously meant answering in English too. With the setting on, the system prompt gains a `<reasoning-language>` block asking the agent to reason in English while keeping user-facing answers in the language the user used; correctness, safety, and communication requirements are explicitly unchanged. The default `off` adds nothing to the prompt.
12
+ - Added opt-in `compaction.adaptive.*` settings — `enabled`, `baseThresholdPercent`, `aggression`, `turnWindow`, and `minThresholdPercent` — and wired a per-session call-rate tracker into the auto-compaction threshold decision. Adaptive mode is disabled by default and the existing fixed `compaction.thresholdTokens` / `compaction.thresholdPercent` precedence is preserved. `getGroup("compaction")` flattens dotted keys, so the nested options object is assembled explicitly at the decision site rather than inferred, and a completed compaction resets the tracker in exactly one place.
13
+
14
+ ### Fixed
15
+
16
+ - Restored PDF conversion in standalone binaries (ported from upstream #5433). Compiled releases kept mupdf `--external`, but compiled-Bun module resolution cannot satisfy markit's bare `import("mupdf")`, and mupdf's Emscripten loader cannot find `mupdf-wasm.wasm` inside the bunfs — so every standalone PDF read fell back to raw bytes behind a generic "PDF support requires 'mupdf'" note while the real cause was discarded. mupdf is now bundled: the wasm is embedded via `with { type: "file" }` and routed to the loader through a `locateFile` hook seeded before the first mupdf import, markit-ai's bundler-hostile `require("mupdf")` image-render call is patched to a dynamic import (`patches/markit-ai@0.5.3.patch`), and conversion failures re-run the import so diagnostics carry the actual error. The fetch tool also accepts any non-empty markit conversion instead of discarding short documents (e.g. the 14-character W3C dummy.pdf) into a raw-bytes fallback.
17
+
18
+ ## [0.5.4] - 2026-08-28
19
+
20
+ Sayknow-CLI descends from an upstream MIT agent harness; see [`NOTICE.md`](../../NOTICE.md).
4
21
  This file tracks the **fork's own releases**; upstream's full feature history lives
5
22
  in that project. Each release notes the upstream version it is built on.
6
23
 
7
24
 
8
- ## [Unreleased]
25
+ ## [0.5.3] - 2026-08-28
26
+
27
+ ### Added
28
+
29
+ - Added zero-configuration oMLX and loopback-safe SGLang discovery through the shared OpenAI-compatible registry, including reviewed oMLX model profiles, thinking-effort preservation, schemas, and local-provider tests.
30
+ - Added explicit-file `/import-session` support for Codex rollout JSONL, Claude Code JSONL, and claude.ai exports with bounded redacted context, quarantined unmappable records, durable provenance, workspace-scoped idempotent native publication, and ACP isolation for path-bearing import, export, and move commands.
31
+ ### Fixed
32
+
33
+ - Imported-session targets activate only through an idle-only session transition; a response or turn that wins the activation race leaves the reused or newly published target intact for later resume instead of interrupting active work.
34
+
35
+ - LSP, DAP, and stdio MCP protocol writes now serialize complete write/flush transactions, await sink backpressure, propagate peer-close failures, and terminalize stale transports on fatal writes or stdout EOF instead of leaving delayed unhandled EPIPE errors or timeout-bound pending requests.
36
+ - Managed sessions now sample transcript size proactively only through a retained exact-file authority, treat unavailable sampling as unknown, and recover an authority-bound `content_too_large` append by atomically rewriting the exact live entry set; failed rewrites latch persistence and roll back volatile branch mutation before later appends.
37
+ - Explicit empty tool selections such as `--no-tools` now remain authoritative across goal/workflow restoration, session branching, and plan-mode transitions instead of silently reactivating built-in tools.
38
+ - `config set` and `config reset` now report success only after durable persistence; atomic YAML writes retain their original resolved target and fail closed on symlink or target-identity retargeting.
39
+ - `skc --worktree` now installs Bun, npm, or pnpm dependencies from the worktree's own matching lockfile instead of linking a package checkout to the source tree's `node_modules`; nested package roots keep their cwd, legacy owned links are migrated, unrelated links are refused, and repeated launches reuse the local install location.
40
+ - Release publication now emits Sayknow-owned SHA-256 manifests, and standalone installers plus `skc update` verify the selected platform binary before replacing an installation; missing or mismatched integrity metadata and concurrent installers fail closed.
41
+
42
+ ### Changed
43
+
44
+ - The command palette now exposes availability-gated follow-up, queue editing, immediate-send, and transcript-turn actions; their default keybindings remain unchanged, while user remaps dispatch through the shared action registry.
45
+ - Korean and emoji escapes in `ask` question text and option labels now recover as display-only content while ids and workflow metadata remain fail-closed.
46
+ - The todo HUD can be expanded from its action/keybinding, startup can skip the logo sweep, and provider or MCP OAuth URLs copy only through an explicit remappable action.
47
+ - **Upstream independence.** Retired the upstream sync/regeneration pipeline
48
+ (`rebrand/` layer plus the generation scripts); this tree is now the single
49
+ source of truth and upstream fixes are ported by cherry-pick only. See
50
+ `docs/FORK_MAINTENANCE.md`.
51
+ - `bun run release` now enforces the fork policy end to end: runs from the
52
+ `sayknow-fork` branch, tags `sayknow-vX.Y.Z`, checks monotonicity against the
53
+ fork tag series only, refuses same-version plain `v` tags on origin, and the
54
+ release attaches both release-evidence JSONs for the daily public-sync live
55
+ check.
56
+ - Scrubbed upstream brand references from public docs, the embedded docs
57
+ index, and test fixtures (also fixing two fixture assertions the original
58
+ rename had broken). MIT attribution remains in `LICENSE` and `NOTICE.md`.
9
59
 
10
60
  ## [0.5.2] — 2026-08-14
11
61
 
12
- Built on upstream **gajae-code v0.12.0**.
62
+ Built on upstream **v0.12.0**.
13
63
 
14
64
  ### Fixed (unattended workflow gates were unanswerable through the control plane)
15
65
 
@@ -139,7 +189,7 @@ real cell metrics (16x34) replace the 9x18 default.
139
189
 
140
190
  ## [0.5.1] — 2026-07-29
141
191
 
142
- Built on upstream **gajae-code v0.12.0**.
192
+ Built on upstream **v0.12.0**.
143
193
 
144
194
  ### Fixed (Sayknow Pet still left sixel residue under tmux)
145
195
 
@@ -164,7 +214,7 @@ exactly the people who already had a session open.
164
214
 
165
215
  ## [0.5.0] — 2026-07-28
166
216
 
167
- Built on upstream **gajae-code v0.12.0** (previous fork release tracked v0.11.6).
217
+ Built on upstream **v0.12.0** (previous fork release tracked v0.11.6).
168
218
 
169
219
  ### Security (inherited from upstream v0.12.0)
170
220
 
@@ -221,11 +271,11 @@ and that summary is injected into every later session.
221
271
 
222
272
  ### Fixed (rebrand leakage)
223
273
 
224
- - **Stop creating `.gjc-*` paths.** `recovery_fs` and `path_identity` still wrote
225
- `.gjc-recovery`, `.gjc-managed-remove-*`, and `.gjc-exact-unlink-*` on disk: the
226
- rename never reached them, so recovery state landed under an upstream-branded
227
- directory name. 24 residual tokens are gone and the sync pipeline now fails the
228
- build instead of shipping them.
274
+ - **Stop creating legacy-branded recovery paths.** `recovery_fs` and
275
+ `path_identity` still wrote legacy-branded recovery and removal marker
276
+ directories on disk: the rename never reached them, so recovery state landed
277
+ under an upstream-branded directory name. 24 residual tokens are gone and the
278
+ build now fails instead of shipping them.
229
279
 
230
280
  ### Fixed (fork pipeline)
231
281
 
@@ -389,7 +439,7 @@ platform subpackages publish from a single CI run.
389
439
 
390
440
  ### Changed
391
441
 
392
- - Synced onto upstream **gajae-code v0.11.6** (from v0.6.0), a 5-minor-version jump
442
+ - Synced onto upstream **v0.11.6** (from v0.6.0), a 5-minor-version jump
393
443
  bringing v0.7–v0.11 evolution: managed chat daemon (#2782, #2785, #2786), Telegram
394
444
  lock auto-reconciliation (#2781), compiled startup import-cycle fix (#2779), legacy
395
445
  daemon tombstone reclamation (#2780), nextest CI hardening (#2777), and the new
@@ -440,7 +490,7 @@ platform subpackages publish from a single CI run.
440
490
 
441
491
  ### Changed
442
492
 
443
- - Synced onto upstream **gajae-code v0.7.1** (from v0.6.5), bringing 0.7.0's mobile
493
+ - Synced onto upstream **v0.7.1** (from v0.6.5), bringing 0.7.0's mobile
444
494
  notifications SDK + managed Telegram daemon and 0.7.1's fixes (assistant
445
495
  notification lead-in, stale tmux session reuse, packaged native imports, and the
446
496
  glm-zcode Z.AI provider) while preserving the Sayknow-CLI brand.
@@ -480,7 +530,7 @@ platform subpackages publish from a single CI run.
480
530
 
481
531
  ### Changed
482
532
 
483
- - Synced onto upstream **gajae-code v0.6.5** (from v0.6.0), bringing its latest
533
+ - Synced onto upstream **v0.6.5** (from v0.6.0), bringing its latest
484
534
  features and fixes while preserving the Sayknow-CLI brand. The new welcome
485
535
  logo-mode support renders the blue **SAYKNOW** wordmark in every mode.
486
536
 
@@ -544,7 +594,7 @@ platform subpackages publish from a single CI run.
544
594
 
545
595
  ### Changed
546
596
 
547
- - Synced onto upstream **gajae-code v0.6.0** (52 commits, +27k lines), bringing its
597
+ - Synced onto upstream **v0.6.0** (52 commits, +27k lines), bringing its
548
598
  new features and fixes — including the opt-in `skc rlm` research mode, the goal
549
599
  `pause` operation, steer-by-default while busy, and the experimental
550
600
  desktop-control tool surface — while preserving the Sayknow-CLI brand and the
@@ -552,7 +602,7 @@ platform subpackages publish from a single CI run.
552
602
 
553
603
  ## [0.1.0] — 2026-06-17
554
604
 
555
- Initial Sayknow-CLI release, forked from gajae-code v0.5.4.
605
+ Initial Sayknow-CLI release, forked from upstream v0.5.4.
556
606
 
557
607
  ### Added
558
608
 
@@ -570,7 +620,7 @@ Initial Sayknow-CLI release, forked from gajae-code v0.5.4.
570
620
 
571
621
  ### Changed
572
622
 
573
- - Rebranded `gajae-code` → **Sayknow-CLI** (`skc`, `@sayknow-cli/*`) and reset the
623
+ - Rebranded the upstream harness → **Sayknow-CLI** (`skc`, `@sayknow-cli/*`) and reset the
574
624
  version to 0.1.0.
575
625
  - The model selector now starts OAuth login directly when you pick an
576
626
  unauthenticated preset, instead of only printing a hint.
@@ -56,10 +56,14 @@ type PathPlatform = NodeJS.Platform;
56
56
  type PackageExists = (packageName: string, packageRoot: string) => boolean;
57
57
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined): "bun" | "npm" | "binary";
58
58
  export declare function resolveNpmManagedTargetForTest(ompPath: string, platform: PathPlatform, packageExists: PackageExists): PackageManagerTarget | undefined;
59
+ export declare function getBinaryNameForTest(platform?: NodeJS.Platform, arch?: string): string;
60
+ export declare function fetchExpectedBinaryDigest(version: string, assetName: string, fetchImpl?: (url: string) => Promise<Response>): Promise<string>;
61
+ export declare function verifyReleaseBinaryIntegrity(filePath: string, version: string, assetName: string, fetchImpl?: (url: string) => Promise<Response>): Promise<void>;
59
62
  export declare function formatBinaryDownloadFailureMessageForTest(binaryName: string, url: string, status: string | number, platform?: NodeJS.Platform): string;
60
63
  export declare function buildReleaseBinaryUrlForTest(version: string, platform?: NodeJS.Platform, arch?: string): string;
61
64
  export declare function formatManualUpdateInstructionsForTest(platform?: NodeJS.Platform): string;
62
65
  export declare function formatVerificationFailureForTest(result: InstalledVersionVerification, expectedVersion: string): string;
66
+ export declare function withBinaryUpdateLock<T>(targetPath: string, operation: () => Promise<T>): Promise<T>;
63
67
  /**
64
68
  * Atomically replace the installed binary and roll back if version verification fails.
65
69
  */
@@ -69,16 +73,19 @@ export declare function fsyncFileForTest(filePath: string): Promise<void>;
69
73
  /** Injectable steps of the binary update flow (seams for testing ordering). */
70
74
  export interface BinaryUpdateFlow {
71
75
  download(url: string, tempPath: string): Promise<void>;
76
+ verifyIntegrity(filePath: string): Promise<void>;
72
77
  fsync(filePath: string): Promise<void>;
73
78
  replace(options: BinaryReplacementOptions): Promise<InstalledVersionVerification>;
74
79
  verifyInstalledVersion(expectedVersion: string): Promise<InstalledVersionVerification>;
75
80
  /** Best-effort cleanup of the temp file when the flow aborts before replace. */
76
81
  removeTemp?(filePath: string): Promise<void>;
82
+ /** Stable suffix for focused tests; production uses a process-unique staging path. */
83
+ transactionId?: string;
77
84
  /** Called once fsync has succeeded, right before replacement begins. */
78
85
  beforeReplace?(): void;
79
86
  }
80
87
  /**
81
- * Orchestrate download → fsync → replace → verify with a strict ordering
88
+ * Orchestrate download → integrity verification → fsync → replace → version/smoke verification.
82
89
  * contract: the downloaded temp binary MUST be flushed to stable storage
83
90
  * before it is published (renamed into place) or exec'd for verification.
84
91
  *
@@ -72,6 +72,24 @@ export declare class AtomicYamlReplaceError extends Error {
72
72
  readonly code = "ATOMIC_YAML_REPLACE_FAILED";
73
73
  constructor(configPath: string, attempts: number, cause: unknown);
74
74
  }
75
+ /** Raised when the configured lexical route no longer resolves to its original target. */
76
+ export declare class AtomicYamlRetargetError extends Error {
77
+ readonly code = "ATOMIC_YAML_RETARGETED";
78
+ constructor();
79
+ }
80
+ /** Test-only coordination hooks for deterministic target-authority races. */
81
+ export declare const AtomicYamlTestHooks: {
82
+ afterTargetBound?: (canonicalPath: string) => Promise<void> | void;
83
+ };
84
+ type AtomicYamlTargetIdentity = {
85
+ device: bigint;
86
+ inode: bigint;
87
+ };
88
+ type AtomicYamlTarget = {
89
+ canonicalPath: string;
90
+ resolvedPath: string;
91
+ identity: AtomicYamlTargetIdentity | undefined;
92
+ };
75
93
  /** Set a dotted YAML path, creating object intermediates as needed. */
76
94
  export declare function setByPath(value: Record<string, unknown>, segments: readonly string[], nextValue: unknown): void;
77
95
  /** Delete a dotted YAML path without disturbing sibling keys or parent objects. */
@@ -85,7 +103,7 @@ export declare function applyAtomicYamlPatchesWithCurrent(configPath: string, bu
85
103
  * only when this operation reaches the front of the in-process queue, which lets
86
104
  * Settings debounce/coalesce inside its already-reserved causal slot.
87
105
  */
88
- export declare function enqueueAtomicYamlOperation<T>(configPath: string, operation: (canonicalConfigPath: string) => Promise<T>): Promise<T>;
106
+ export declare function enqueueAtomicYamlOperation<T>(configPath: string, operation: (canonicalConfigPath: string, target: AtomicYamlTarget) => Promise<T>): Promise<T>;
89
107
  /**
90
108
  * Reserve an atomic patch slot now, producing patches only after earlier slots
91
109
  * complete. Writers with state-aware merges use {@link reserveAtomicYamlUpdateSlot}.
@@ -101,3 +119,4 @@ export declare function reserveAtomicYamlUpdateSlot<T>(configPath: string, updat
101
119
  * cross-process file lock. Success means the temp file was fsynced and renamed.
102
120
  */
103
121
  export declare function applyAtomicYamlPatches(configPath: string, patches: readonly AtomicYamlPatch[], options?: AtomicYamlPatchOptions): Promise<CasReceipt>;
122
+ export {};
@@ -16,6 +16,7 @@ interface AppKeybindings {
16
16
  "app.model.select": true;
17
17
  "app.model.selectTemporary": true;
18
18
  "app.tools.expand": true;
19
+ "app.todo.toggle": true;
19
20
  "app.tool.backgroundFold": true;
20
21
  "app.editor.external": true;
21
22
  "app.message.followUp": true;
@@ -24,6 +25,7 @@ interface AppKeybindings {
24
25
  "app.clipboard.pasteImage": true;
25
26
  "app.clipboard.copyLine": true;
26
27
  "app.clipboard.copyPrompt": true;
28
+ "app.oauth.copyUrl": true;
27
29
  "app.session.new": true;
28
30
  "app.session.tree": true;
29
31
  "app.session.fork": true;
@@ -109,6 +111,10 @@ export declare const KEYBINDINGS: {
109
111
  readonly defaultKeys: "ctrl+o";
110
112
  readonly description: "Expand tools";
111
113
  };
114
+ readonly "app.todo.toggle": {
115
+ readonly defaultKeys: "alt+shift+t";
116
+ readonly description: "Toggle todo list expansion";
117
+ };
112
118
  readonly "app.tool.backgroundFold": {
113
119
  readonly defaultKeys: "ctrl+b";
114
120
  readonly description: "Fold/background supported foreground tool";
@@ -141,6 +147,10 @@ export declare const KEYBINDINGS: {
141
147
  readonly defaultKeys: "alt+shift+c";
142
148
  readonly description: "Copy prompt";
143
149
  };
150
+ readonly "app.oauth.copyUrl": {
151
+ readonly defaultKeys: "alt+shift+u";
152
+ readonly description: "Copy OAuth authorization URL";
153
+ };
144
154
  readonly "app.session.new": {
145
155
  readonly defaultKeys: "ctrl+n";
146
156
  readonly description: "Start a new session";
@@ -96,7 +96,7 @@ export declare const ModelsConfigFile: ConfigFile<{
96
96
  authHeader?: boolean | undefined;
97
97
  auth?: "none" | "apiKey" | "oauth" | undefined;
98
98
  discovery?: {
99
- type: "ollama" | "lm-studio" | "llama.cpp" | "openai-models-list";
99
+ type: "ollama" | "lm-studio" | "omlx" | "sglang" | "llama.cpp" | "openai-models-list";
100
100
  } | undefined;
101
101
  requestTransform?: {
102
102
  profile?: "openai-proxy" | undefined;
@@ -260,6 +260,8 @@ export declare const ProviderDiscoverySchema: z.ZodObject<{
260
260
  type: z.ZodEnum<{
261
261
  ollama: "ollama";
262
262
  "lm-studio": "lm-studio";
263
+ omlx: "omlx";
264
+ sglang: "sglang";
263
265
  "llama.cpp": "llama.cpp";
264
266
  "openai-models-list": "openai-models-list";
265
267
  }>;
@@ -368,6 +370,8 @@ export declare const ModelsConfigSchema: z.ZodObject<{
368
370
  type: z.ZodEnum<{
369
371
  ollama: "ollama";
370
372
  "lm-studio": "lm-studio";
373
+ omlx: "omlx";
374
+ sglang: "sglang";
371
375
  "llama.cpp": "llama.cpp";
372
376
  "openai-models-list": "openai-models-list";
373
377
  }>;
@@ -523,6 +523,25 @@ export declare const SETTINGS_SCHEMA: {
523
523
  }];
524
524
  };
525
525
  };
526
+ readonly reasoningLanguage: {
527
+ readonly type: "enum";
528
+ readonly values: readonly ["off", "english"];
529
+ readonly default: "off";
530
+ readonly ui: {
531
+ readonly tab: "appearance";
532
+ readonly label: "Reasoning Language";
533
+ readonly description: "Reason through technical work in English while answering in your own language";
534
+ readonly options: readonly [{
535
+ readonly value: "off";
536
+ readonly label: "Off";
537
+ readonly description: "Do not add reasoning-language guidance";
538
+ }, {
539
+ readonly value: "english";
540
+ readonly label: "English";
541
+ readonly description: "Reason in English and answer in the language you used";
542
+ }];
543
+ };
544
+ };
526
545
  readonly colorBlindMode: {
527
546
  readonly type: "boolean";
528
547
  readonly default: false;
@@ -1663,6 +1682,15 @@ export declare const SETTINGS_SCHEMA: {
1663
1682
  }];
1664
1683
  };
1665
1684
  };
1685
+ readonly "startup.skipLogoAnimation": {
1686
+ readonly type: "boolean";
1687
+ readonly default: false;
1688
+ readonly ui: {
1689
+ readonly tab: "interaction";
1690
+ readonly label: "Skip Logo Animation";
1691
+ readonly description: "Show the final welcome logo immediately";
1692
+ };
1693
+ };
1666
1694
  readonly "startup.checkUpdate": {
1667
1695
  readonly type: "boolean";
1668
1696
  readonly default: true;
@@ -1949,6 +1977,51 @@ export declare const SETTINGS_SCHEMA: {
1949
1977
  }];
1950
1978
  };
1951
1979
  };
1980
+ readonly "compaction.adaptive.enabled": {
1981
+ readonly type: "boolean";
1982
+ readonly default: false;
1983
+ readonly ui: {
1984
+ readonly tab: "context";
1985
+ readonly label: "Adaptive Compaction";
1986
+ readonly description: "Adjust compaction frequency by context size and call rate";
1987
+ };
1988
+ };
1989
+ readonly "compaction.adaptive.baseThresholdPercent": {
1990
+ readonly type: "number";
1991
+ readonly default: 85;
1992
+ readonly ui: {
1993
+ readonly tab: "context";
1994
+ readonly label: "Adaptive Base Threshold %";
1995
+ readonly description: "Base context percentage used when adaptive compaction is enabled";
1996
+ };
1997
+ };
1998
+ readonly "compaction.adaptive.aggression": {
1999
+ readonly type: "number";
2000
+ readonly default: 0.15;
2001
+ readonly ui: {
2002
+ readonly tab: "context";
2003
+ readonly label: "Adaptive Aggression";
2004
+ readonly description: "How strongly call rate lowers the compaction threshold; use 0 to 1";
2005
+ };
2006
+ };
2007
+ readonly "compaction.adaptive.turnWindow": {
2008
+ readonly type: "number";
2009
+ readonly default: 15;
2010
+ readonly ui: {
2011
+ readonly tab: "context";
2012
+ readonly label: "Call-Rate Window";
2013
+ readonly description: "Minutes of recent calls considered by adaptive compaction";
2014
+ };
2015
+ };
2016
+ readonly "compaction.adaptive.minThresholdPercent": {
2017
+ readonly type: "number";
2018
+ readonly default: 50;
2019
+ readonly ui: {
2020
+ readonly tab: "context";
2021
+ readonly label: "Adaptive Floor %";
2022
+ readonly description: "Lowest context percentage adaptive compaction may lower the threshold to";
2023
+ };
2024
+ };
1952
2025
  readonly "compaction.handoffSaveToDisk": {
1953
2026
  readonly type: "boolean";
1954
2027
  readonly default: false;
@@ -35,5 +35,6 @@ export declare class DapClient {
35
35
  sendRequest<TBody = unknown>(command: string, args?: unknown, signal?: AbortSignal, timeoutMs?: number): Promise<TBody>;
36
36
  sendResponse(request: DapRequestMessage, success: boolean, body?: unknown, message?: string): Promise<void>;
37
37
  dispose(): Promise<void>;
38
+ startMessageReader(): Promise<void>;
38
39
  }
39
40
  export {};
@@ -5,6 +5,11 @@ import type { LspClient, ServerConfig } from "./types";
5
5
  */
6
6
  export declare function setIdleTimeout(ms: number | null | undefined): void;
7
7
  export declare function isIdleCheckerActiveForTests(): boolean;
8
+ /**
9
+ * Start background message reader for a client.
10
+ * Routes responses to pending requests and handles notifications.
11
+ */
12
+ export declare function startMessageReader(client: LspClient): Promise<void>;
8
13
  /** Timeout for warmup initialize requests (5 seconds) */
9
14
  export declare const WARMUP_TIMEOUT_MS = 5000;
10
15
  /**
@@ -18,6 +18,7 @@ export interface WelcomeComponentOptions {
18
18
  collapseChangelog?: boolean;
19
19
  buildLabel?: string;
20
20
  keyDisplayContext?: KeyDisplayContext;
21
+ skipLogoAnimation?: boolean;
21
22
  }
22
23
  /**
23
24
  * Sayknow-CLI launch surface: a blue-gradient SAYKNOW wordmark, compact
@@ -110,7 +110,9 @@ export declare class SelectorController {
110
110
  showUserMessageSelector(): void;
111
111
  showTreeSelector(): void;
112
112
  showSessionSelector(): Promise<void>;
113
- handleResumeSession(sessionPath: string): Promise<void>;
113
+ handleResumeSession(sessionPath: string, options?: {
114
+ requireIdle?: boolean;
115
+ }, onSwitched?: () => void): Promise<boolean>;
114
116
  handleSessionDeleteCommand(): Promise<void>;
115
117
  showOAuthSelector(mode: "login" | "logout", providerId?: string, options?: OAuthSelectorOptions): Promise<void>;
116
118
  showDebugSelector(): void;
@@ -57,6 +57,12 @@ export interface InteractiveModeOptions {
57
57
  initialMessages?: string[];
58
58
  }
59
59
  export declare function selectShutdownDraft(editorText: string, hasActiveBtw: boolean): string;
60
+ export declare class OAuthAuthorizationUrlState {
61
+ #private;
62
+ set(url: string): number;
63
+ clear(lease: number): void;
64
+ get current(): string | undefined;
65
+ }
60
66
  export declare class InteractiveMode implements InteractiveModeContext {
61
67
  #private;
62
68
  session: AgentSession;
@@ -243,6 +249,10 @@ export declare class InteractiveMode implements InteractiveModeContext {
243
249
  handleContributionPrepCommand(customInstructions?: string): Promise<void>;
244
250
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
245
251
  openInBrowser(urlOrPath: string): void;
252
+ setOAuthAuthorizationUrl(url: string): number;
253
+ clearOAuthAuthorizationUrl(lease: number): void;
254
+ hasOAuthAuthorizationUrl(): boolean;
255
+ copyOAuthAuthorizationUrl(): Promise<void>;
246
256
  showCommandPalette(commands: SlashCommand[], actions: CommandPaletteAction[], executeSlashCommand: (name: string) => Promise<void>): void;
247
257
  showSettingsSelector(): void;
248
258
  showThemeSelector(): void;
@@ -259,7 +269,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
259
269
  showUserMessageSelector(): void;
260
270
  showTreeSelector(): void;
261
271
  showSessionSelector(): void;
262
- handleResumeSession(sessionPath: string): Promise<void>;
272
+ handleResumeSession(sessionPath: string, options?: {
273
+ requireIdle?: boolean;
274
+ }): Promise<boolean>;
263
275
  handleSessionDeleteCommand(): Promise<void>;
264
276
  showOAuthSelector(mode: "login" | "logout", providerId?: string, options?: import("./types").OAuthSelectorOptions): Promise<void>;
265
277
  showHookConfirm(title: string, message: string): Promise<boolean>;
@@ -261,6 +261,10 @@ export interface InteractiveModeContext {
261
261
  handleSTTToggle(): Promise<void>;
262
262
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
263
263
  openInBrowser(urlOrPath: string): void;
264
+ setOAuthAuthorizationUrl(url: string): number;
265
+ hasOAuthAuthorizationUrl(): boolean;
266
+ clearOAuthAuthorizationUrl(lease: number): void;
267
+ copyOAuthAuthorizationUrl(): Promise<void>;
264
268
  /** Resolved source of truth for slash autocomplete and command palette entries. */
265
269
  getSlashCommands?(): readonly SlashCommand[];
266
270
  refreshSlashCommandState(cwd?: string): Promise<void>;
@@ -281,7 +285,9 @@ export interface InteractiveModeContext {
281
285
  showTreeSelector(): void;
282
286
  showSessionSelector(): void;
283
287
  showSessionsDashboard(): void;
284
- handleResumeSession(sessionPath: string): Promise<void>;
288
+ handleResumeSession(sessionPath: string, options?: {
289
+ requireIdle?: boolean;
290
+ }): Promise<boolean>;
285
291
  handleSessionDeleteCommand(): Promise<void>;
286
292
  showOAuthSelector(mode: "login" | "logout", providerId?: string, options?: OAuthSelectorOptions): Promise<void>;
287
293
  showHookConfirm(title: string, message: string): Promise<boolean>;
@@ -5,6 +5,8 @@
5
5
  * Messages are newline-delimited JSON.
6
6
  */
7
7
  import type { MCPRequestOptions, MCPStdioServerConfig, MCPTransport } from "../../runtime-mcp/types";
8
+ /** Write one JSONL frame while honoring Bun FileSink backpressure and flush failures. */
9
+ export declare function writeStdioFrame(stdin: Bun.FileSink, message: string): Promise<void>;
8
10
  export declare class StdioTransport implements MCPTransport {
9
11
  #private;
10
12
  private config;
@@ -244,6 +244,8 @@ export interface AgentSessionConfig {
244
244
  /** Rebuild the SSH tool from current capability discovery results. */
245
245
  reloadSshTool?: () => Promise<AgentTool | null>;
246
246
  requestedToolNames?: ReadonlySet<string>;
247
+ /** True only when the caller explicitly selected no tools. */
248
+ explicitlyDisabledTools?: boolean;
247
249
  /** Optional per-session allowlist for tools exposed through search_tool_bm25. */
248
250
  discoverableToolAllowedNames?: readonly string[];
249
251
  /** Optional accessor for live MCP server instructions, injected as untrusted user-role request data. */
@@ -758,6 +760,8 @@ export declare class AgentSession {
758
760
  refreshSshTool(options?: {
759
761
  activateIfAvailable?: boolean;
760
762
  }): Promise<void>;
763
+ /** Whether the caller explicitly selected no tools for this session. */
764
+ hasExplicitlyDisabledTools(): boolean;
761
765
  /**
762
766
  * Set active tools by name.
763
767
  * Only tools in the registry can be enabled. Unknown tool names are ignored.
@@ -1209,6 +1213,8 @@ export declare class AgentSession {
1209
1213
  prepareContributionPrep(options?: ContributionPrepOptions): Promise<ContributionPrepResult>;
1210
1214
  /** Test seam: override the emergency-compaction resource sampler so tests never read real RSS. */
1211
1215
  setResourceSampler(sampler: () => EmergencyCompactionSample): void;
1216
+ /** Test seam: drive the pre-prompt emergency/threshold check directly. */
1217
+ runPrePromptContextCheckForTests(pendingMessages?: readonly AgentMessage[]): Promise<void>;
1212
1218
  setRetainedMemorySampler(sampler: (() => RetainedMemorySample) | undefined): void;
1213
1219
  /**
1214
1220
  * Toggle auto-compaction setting.
@@ -1347,10 +1353,12 @@ export declare class AgentSession {
1347
1353
  * Switch to a different session file.
1348
1354
  * Aborts current operation, loads messages, restores model/thinking.
1349
1355
  * Listeners are preserved and will continue receiving events.
1356
+ * `requireIdle` rejects an active turn and fences new admissions for the transition.
1350
1357
  * @returns true if switch completed, false if cancelled by hook
1351
1358
  */
1352
1359
  switchSession(sessionPath: string, options?: {
1353
1360
  transition?: SessionSwitchEvent["transition"];
1361
+ requireIdle?: boolean;
1354
1362
  }): Promise<boolean>;
1355
1363
  /**
1356
1364
  * Create a branch from a specific entry.
@@ -120,7 +120,9 @@ export declare function fsyncCanonicalBinding(bindingPath: string, expected: str
120
120
  export declare function ensureManagedScope(scope: ManagedScope, policy?: ManagedSessionSecurityPolicy): Promise<ManagedScopeResolution>;
121
121
  /** Synchronously create and validate the v2 binding before a default session writer exists. */
122
122
  export declare function prepareManagedSessionScopeForWriteSync(scope: ManagedScope, policy?: ManagedSessionSecurityPolicy, authority?: ManagedCandidateWriteAuthority): ManagedScopeResolution;
123
- export declare function listManagedCandidates(scope: ManagedScope): ManagedCandidateListing;
123
+ export declare function listManagedCandidates(scope: ManagedScope, options?: {
124
+ maxCandidates?: number;
125
+ }): ManagedCandidateListing;
124
126
  type DetachedArtifactRoot = {
125
127
  originalPath: string;
126
128
  detachedPath: string;
@@ -74,6 +74,8 @@ export declare class ManagedSessionDescendantStore {
74
74
  appendSync(relativePath: string, bytes: Uint8Array): void;
75
75
  /** Read an exact managed file without exposing its pathname as authority. */
76
76
  readExpected(relativePath: string): ManagedFileSnapshot | null;
77
+ /** Read only the exact managed file size through the retained root authority. */
78
+ sizeSync(relativePath: string): number | null;
77
79
  /** Remove an exact captured file without reopening its pathname as authority. */
78
80
  removeExpected(relativePath: string, expected: ManagedFileSnapshot): void;
79
81
  /** Read and remove one managed descendant through retained authority. */
@@ -705,6 +705,12 @@ export declare class SessionManager {
705
705
  listForResumePickerReadOnly(): Promise<SessionInfo[]>;
706
706
  getSessionId(): string;
707
707
  getSessionFile(): string | undefined;
708
+ /**
709
+ * Managed on-disk transcript size in bytes. Returns undefined when the
710
+ * destination is explicit, the file does not exist yet, or its identity
711
+ * cannot be verified.
712
+ */
713
+ getTranscriptFileBytes(): number | undefined;
708
714
  acquireMemoryGuardParticipantIngressLease(): MemoryGuardParticipantIngressLease;
709
715
  createMemoryGuardCheckpoint(input: MemoryGuardCreateCheckpointInput): Promise<MemoryGuardSessionManagerCheckpointV1>;
710
716
  /**
@@ -1048,6 +1054,9 @@ export declare class SessionManager {
1048
1054
  sessionDir?: string;
1049
1055
  storage?: SessionStorage;
1050
1056
  destination?: SessionDestination;
1057
+ maxCandidates?: number;
1058
+ maxTotalBytes?: number;
1059
+ filterOtherWorkspaces?: boolean;
1051
1060
  }): StrictInventoryResult;
1052
1061
  /**
1053
1062
  * Propagate the storage-layer verified hard delete bound to exact identity evidence.
@@ -110,6 +110,8 @@ export interface SessionStorage {
110
110
  readBytesSync?(path: string): Uint8Array;
111
111
  /** Exact bytes and descriptor-bound identity captured from one opened regular file. */
112
112
  readSnapshotSync?(path: string): SessionStorageSnapshot;
113
+ /** Exact descriptor-bound bytes, refusing growth or allocation beyond maxBytes. */
114
+ readSnapshotBoundedSync?(path: string, maxBytes: number): SessionStorageSnapshot;
113
115
  statSync(path: string): SessionStorageStat;
114
116
  listFilesSync(dir: string, pattern: string): string[];
115
117
  /** List matching files with mtimes without issuing one JavaScript stat call per path. */
@@ -122,6 +124,11 @@ export interface SessionStorage {
122
124
  * authorization inventory; the forgiving {@link listFilesSync} stays display-only.
123
125
  */
124
126
  listFilesStrictSync?(dir: string, pattern: string): string[];
127
+ /** Strict bounded scan; `truncated` means completeness was not granted. */
128
+ listFilesStrictBoundedSync?(dir: string, pattern: string, maxFiles: number): {
129
+ files: string[];
130
+ truncated: boolean;
131
+ };
125
132
  exists(path: string): Promise<boolean>;
126
133
  readText(path: string): Promise<string>;
127
134
  readTextPrefix(path: string, maxBytes: number): Promise<string>;
@@ -270,6 +277,7 @@ export declare class FileSessionStorage implements SessionStorage {
270
277
  readTextSync(fpath: string): string;
271
278
  readBytesSync(fpath: string): Uint8Array;
272
279
  readSnapshotSync(fpath: string): SessionStorageSnapshot;
280
+ readSnapshotBoundedSync(fpath: string, maxBytes: number): SessionStorageSnapshot;
273
281
  statSync(path: string): SessionStorageStat;
274
282
  listFilesSync(dir: string, pattern: string): string[];
275
283
  listFilesByMtime(dir: string, pattern: string): Promise<Array<{
@@ -277,6 +285,10 @@ export declare class FileSessionStorage implements SessionStorage {
277
285
  mtimeMs: number;
278
286
  }>>;
279
287
  listFilesStrictSync(dir: string, pattern: string): string[];
288
+ listFilesStrictBoundedSync(dir: string, pattern: string, maxFiles: number): {
289
+ files: string[];
290
+ truncated: boolean;
291
+ };
280
292
  exists(path: string): Promise<boolean>;
281
293
  readText(path: string): Promise<string>;
282
294
  readTextPrefix(path: string, maxBytes: number): Promise<string>;
@@ -306,6 +318,7 @@ export declare class MemorySessionStorage implements SessionStorage {
306
318
  readTextSync(path: string): string;
307
319
  readBytesSync(path: string): Uint8Array;
308
320
  readSnapshotSync(path: string): SessionStorageSnapshot;
321
+ readSnapshotBoundedSync(path: string, maxBytes: number): SessionStorageSnapshot;
309
322
  statSync(path: string): SessionStorageStat;
310
323
  listFilesSync(dir: string, pattern: string): string[];
311
324
  listFilesByMtime(dir: string, pattern: string): Promise<Array<{
@@ -313,6 +326,10 @@ export declare class MemorySessionStorage implements SessionStorage {
313
326
  mtimeMs: number;
314
327
  }>>;
315
328
  listFilesStrictSync(dir: string, pattern: string): string[];
329
+ listFilesStrictBoundedSync(dir: string, pattern: string, maxFiles: number): {
330
+ files: string[];
331
+ truncated: boolean;
332
+ };
316
333
  exists(path: string): Promise<boolean>;
317
334
  readText(path: string): Promise<string>;
318
335
  readTextPrefix(path: string, maxBytes: number): Promise<string>;