@gajae-code/coding-agent 0.12.7 → 0.12.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.
Files changed (117) hide show
  1. package/CHANGELOG.md +48 -0
  2. package/dist/types/cli/notify-cli.d.ts +1 -0
  3. package/dist/types/commands/notify.d.ts +4 -0
  4. package/dist/types/commands/sdk.d.ts +23 -0
  5. package/dist/types/config/file-lock.d.ts +3 -0
  6. package/dist/types/config/model-discovery-manager.d.ts +6 -1
  7. package/dist/types/config/model-registry.d.ts +2 -0
  8. package/dist/types/config/resolve-config-value.d.ts +2 -1
  9. package/dist/types/config/settings-schema.d.ts +17 -1
  10. package/dist/types/discovery/agents-md.d.ts +11 -1
  11. package/dist/types/main.d.ts +1 -0
  12. package/dist/types/modes/components/hook-selector.d.ts +20 -0
  13. package/dist/types/modes/components/notifications-settings-editor.d.ts +53 -4
  14. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  15. package/dist/types/modes/controllers/selector-controller.d.ts +4 -2
  16. package/dist/types/modes/types.d.ts +6 -0
  17. package/dist/types/sdk/broker/broker.d.ts +5 -1
  18. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +1 -0
  19. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
  20. package/dist/types/sdk/bus/config.d.ts +75 -113
  21. package/dist/types/sdk/bus/daemon-paths.d.ts +1 -0
  22. package/dist/types/sdk/bus/discord-live-provider.d.ts +8 -2
  23. package/dist/types/sdk/bus/discord-provider.d.ts +19 -0
  24. package/dist/types/sdk/bus/index.d.ts +1 -1
  25. package/dist/types/sdk/bus/notification-orchestration.d.ts +127 -18
  26. package/dist/types/sdk/bus/notification-service.d.ts +54 -4
  27. package/dist/types/sdk/bus/session-control.d.ts +8 -3
  28. package/dist/types/sdk/bus/slack-live-provider.d.ts +9 -2
  29. package/dist/types/sdk/bus/slack-provider.d.ts +22 -0
  30. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +8 -1
  31. package/dist/types/sdk/client/discovery.d.ts +2 -1
  32. package/dist/types/sdk/host/query/handlers.d.ts +2 -0
  33. package/dist/types/sdk/index.d.ts +1 -0
  34. package/dist/types/sdk/providers.d.ts +22 -0
  35. package/dist/types/sdk/session-directory.d.ts +1 -1
  36. package/dist/types/session/internal/managed-session-scope.d.ts +17 -1
  37. package/dist/types/session/internal/managed-session-storage.d.ts +19 -1
  38. package/dist/types/session/internal/native-publish-outcome.d.ts +3 -2
  39. package/dist/types/session/internal/session-open-errors.d.ts +5 -0
  40. package/dist/types/session/session-manager.d.ts +3 -1
  41. package/dist/types/session/session-storage.d.ts +2 -0
  42. package/dist/types/system-prompt.d.ts +12 -1
  43. package/dist/types/tools/composer-bash-policy.d.ts +9 -1
  44. package/package.json +10 -8
  45. package/scripts/build-sdk-package-smoke.ts +51 -0
  46. package/scripts/capture-notifications-settings-showcase.ts +1 -1
  47. package/scripts/verify-gjc-sdk-canonicalization.ts +14 -1
  48. package/src/cli/notify-cli.ts +215 -99
  49. package/src/commands/notify.ts +19 -8
  50. package/src/commands/sdk.ts +54 -0
  51. package/src/config/file-lock.ts +6 -0
  52. package/src/config/model-discovery-manager.ts +50 -8
  53. package/src/config/model-profiles.ts +8 -0
  54. package/src/config/model-registry.ts +866 -76
  55. package/src/config/resolve-config-value.ts +10 -8
  56. package/src/config/settings-schema.ts +25 -15
  57. package/src/config/settings.ts +15 -15
  58. package/src/discovery/agents-md.ts +76 -19
  59. package/src/gjc-runtime/psmux-detect.ts +12 -16
  60. package/src/gjc-runtime/session-state-sidecar.ts +12 -2
  61. package/src/gjc-runtime/tmux-sessions.ts +8 -1
  62. package/src/internal-urls/docs-index.generated.ts +10 -9
  63. package/src/main.ts +43 -7
  64. package/src/modes/DESIGN.md +11 -11
  65. package/src/modes/components/extensions/inspector-panel.ts +9 -5
  66. package/src/modes/components/hook-selector.ts +155 -44
  67. package/src/modes/components/model-selector.ts +242 -49
  68. package/src/modes/components/notifications-settings-editor.ts +631 -85
  69. package/src/modes/controllers/extension-ui-controller.ts +114 -15
  70. package/src/modes/controllers/selector-controller.ts +525 -93
  71. package/src/modes/print-mode.ts +3 -0
  72. package/src/modes/types.ts +6 -0
  73. package/src/prompts/system/system-prompt.md +1 -0
  74. package/src/sdk/broker/broker.ts +54 -10
  75. package/src/sdk/broker/lifecycle-ledger.ts +34 -1
  76. package/src/sdk/broker/lifecycle.ts +47 -50
  77. package/src/sdk/bus/chat-daemon-cli.ts +12 -5
  78. package/src/sdk/bus/chat-daemon-control.ts +35 -6
  79. package/src/sdk/bus/chat-daemon-runtime.ts +16 -2
  80. package/src/sdk/bus/config.ts +534 -286
  81. package/src/sdk/bus/daemon-paths.ts +2 -0
  82. package/src/sdk/bus/discord-live-provider.ts +57 -2
  83. package/src/sdk/bus/discord-provider.ts +21 -0
  84. package/src/sdk/bus/index.ts +97 -35
  85. package/src/sdk/bus/notification-orchestration.ts +371 -68
  86. package/src/sdk/bus/notification-service.ts +571 -137
  87. package/src/sdk/bus/session-control.ts +119 -44
  88. package/src/sdk/bus/slack-live-provider.ts +78 -2
  89. package/src/sdk/bus/slack-provider.ts +24 -0
  90. package/src/sdk/bus/telegram-daemon-cli.ts +9 -2
  91. package/src/sdk/bus/telegram-daemon-contract.ts +8 -1
  92. package/src/sdk/bus/telegram-daemon-control.ts +3 -3
  93. package/src/sdk/bus/telegram-daemon.ts +23 -15
  94. package/src/sdk/client/discovery.ts +10 -4
  95. package/src/sdk/host/query/handlers.ts +20 -1
  96. package/src/sdk/index.ts +1 -0
  97. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  98. package/src/sdk/protocol/operation-registry.ts +5 -2
  99. package/src/sdk/providers.ts +51 -0
  100. package/src/sdk/session-directory.ts +1 -0
  101. package/src/sdk/session.ts +34 -14
  102. package/src/session/agent-session.ts +109 -37
  103. package/src/session/internal/managed-session-scope.ts +981 -450
  104. package/src/session/internal/managed-session-storage.ts +418 -47
  105. package/src/session/internal/native-publish-outcome.ts +15 -3
  106. package/src/session/internal/session-open-errors.ts +11 -0
  107. package/src/session/session-manager.ts +27 -3
  108. package/src/session/session-storage.ts +72 -5
  109. package/src/slash-commands/builtin-registry.ts +117 -15
  110. package/src/system-prompt.ts +28 -15
  111. package/src/task/index.ts +9 -3
  112. package/src/tools/ask.ts +1 -1
  113. package/src/tools/bash.ts +4 -2
  114. package/src/tools/composer-bash-policy.ts +21 -5
  115. package/src/tools/telegram-send.ts +4 -2
  116. package/src/utils/command-args.ts +19 -30
  117. package/src/utils/lang-from-path.ts +2 -4
package/CHANGELOG.md CHANGED
@@ -2,6 +2,49 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.12.10] - 2026-08-03
6
+
7
+ ## [0.12.9] - 2026-08-03
8
+
9
+ ### Added
10
+
11
+ - `/login anthropic --manual` pairs by pasting the authorization code Anthropic shows in the browser instead of waiting on a `localhost:54545` callback the browser cannot reach. Complete it with `/login <code>`. Use it when gjc runs over SSH, in a container, or on a headless host; the default `/login anthropic` still uses the loopback callback. The flag is resolved before the paste fallback, so it is never mistaken for an authorization code, and providers without a paste-a-code redirect reject it explicitly instead of silently falling back.
12
+
13
+ ### Fixed
14
+
15
+ - Composer Bash policy rejections now identify the active provider surface and direct Cursor Composer models to their native repository tools, enabling the agent runtime's bounded automatic recovery instead of leaving a blocked shell attempt as a terminal turn.
16
+ - The `AgentSession retry fallback > invalidates an auth-failed managed credential` test now uses a stored credential instead of a runtime-key override, matching the pin-guard behavior added in #3724 where `--api-key`/`--credential` pinned keys are never invalidated; the shared test fixture installed runtime keys as plumbing, which silently tripped the new guard and blocked the auth invalidation path.
17
+ - The Extension Control Center inspector no longer crashes when a narrow two-column layout leaves its preview pane fewer than two columns wide.
18
+ - Prompt-template positional arguments now preserve literal `$@` and `$ARGUMENTS` text instead of recursively expanding it during placeholder substitution.
19
+ - Native Windows session and GC commands now report the searched `psmux` / `pmux` / `tmux` provider set when no compatible multiplexer is available instead of leaking a literal `tmux` spawn error (#3688).
20
+ - Managed-session recovery now preserves committed mutation state and the actual Linux fallback primitive in native publish receipts, preventing unsafe retry classification after a post-link staging unlink failure (#3746).
21
+ - The system prompt now requires non-ASCII tool-input text to be written as literal UTF-8 rather than hand-spelled `\uXXXX` escapes, including JSON serialized into a string field, while leaving escapes that are intended source syntax alone. Models that hand-spell hex codepoints for CJK mis-type them, and each mis-typed escape decodes to a valid-but-wrong syllable, so Korean text in tool parameters silently arrives corrupted (anthropics/claude-code#83033).
22
+ - The `models.yml` validation error for a custom provider without a credential source now explains that `auth` selects only the auth scheme and lists the three corrective forms (`apiKeyEnv`, literal `apiKey`, or `auth: none`) instead of restating the rule that was already misread. `docs/models.md` documents the same contract in a table (#3738).
23
+ - Credential rotation no longer mutates a pinned credential, and no longer reports a rotation that did not happen. `#markFailedCredential` now applies its pin guard first and for every trigger class, consulting both the `--api-key` runtime override and the `--credential` runtime selector — previously the guard existed only on the quota path and checked only the API-key override, so a `--credential` pin could be rotated away from and the `auth` path could invalidate a pinned credential outright. Both paths now also require the re-resolved credential to actually differ before reporting a rotation: `invalidateCredentialMatching` reports that a row was matched and blocked, which is not the same as the session having moved to a different credential, and with a single-row pool it was true while nothing rotated. A terminal `forbidden` failure is now excluded from retry admission and makes no credential-state change at all. Finally, a rotation is only converted into a same-model retry when the fallback controller could actually be rewound; `restorePreviousEntryForRetry()` refuses once an entry's restore budget is spent, and ignoring that refusal left `activeIndex` on the next entry while the session still requested the previous model.
24
+ - Dead-owner notification recovery now preserves a machine-readable transition block, marker-age diagnostics, and safe force-recovery guidance without weakening ownership proofs (#3762).
25
+ - Detached SDK session hosts no longer outlive the broker that spawned them. A host whose broker died without teardown (crash, `SIGKILL`, restart without `--close-session-hosts`) previously stayed resident forever, holding its session's memory — hundreds of MB per orphan. Each host now polls the broker discovery publication and, after a bounded grace period with no live broker, disposes itself through the same graceful teardown a `SIGTERM` takes. A replacement broker resets the window, so hosts still survive ordinary broker restarts, and a transient discovery read failure is treated as ambiguity rather than proof of orphanhood.
26
+ - Syntax highlighting now recognizes special filenames such as `CMakeLists.txt`, `Dockerfile.*`, `Makefile`, and `.env.*` before generic filename extensions.
27
+
28
+ ## [0.12.8] - 2026-08-02
29
+ ### Added
30
+
31
+ - Added the paginated public SDK query `providers.list/active` (Q29), returning deterministic, deduplicated `{ provider, connectionKind }` descriptors for locally eligible providers without exposing credentials or performing remote health probes.
32
+ - Added the opt-in Alibaba Token Plan Pro profile with `deepseek-v4-flash-0731:max` for execution and `glm-5.2:xhigh` for independent criticism, preserving the existing Balanced profile unchanged.
33
+
34
+ ### Added
35
+
36
+ - Notification settings now expose first-class Telegram, Discord, and Slack configuration, desired-intent toggles, provider-local quarantine and repair guidance, explicit `keep | replace | remove` secret actions, provider-specific health/test diagnostics, and truthful saved-but-runtime-degraded outcomes. The global master preserves provider credentials and intent, `GJC_NOTIFICATIONS=0` suppresses only automatic generic-session admission, and blocked Telegram ownership uses an isolated chat-only endpoint so verified Discord or Slack siblings can continue without exposing the shared endpoint.
37
+
38
+ ### Fixed
39
+
40
+ - Windows automatic tmux resolution now selects `psmux` then `pmux` by canonical command order without rejecting distinct lower-priority aliases; it probes `tmux` only when neither named provider is available (#3725).
41
+ - CI failure extraction now aggregates Bun failure and suite-error summaries across every test invocation in a job log instead of silently using only the first summary.
42
+ - Ordinary `ask` selectors now bound long question premises and page through every premise row without skipping rows hidden by overflow indicators (#3675).
43
+ - First-event timeout retries now require a typed, content-free failure from the current clean attempt scope, preventing prior or stale extension activity from suppressing or admitting a later request (#3553).
44
+ - The issue-1979 Korean prose wrap test now cleans up inherited multiplexer env vars (`TMUX`, `TMUX_PANE`, etc.) so it deterministically exercises the plain-terminal render path regardless of the CI runner's terminal session (#1979).
45
+ - The model selector's assignment menu now shows the model each role currently resolves to (`Set as EXECUTOR (Executor) — now: anthropic/claude-haiku-4-5`), distinguishing an unset default, a role that inherits the default, and a configured-but-unresolvable selector. Previously the role rows were unlabeled, so the only way to learn a role's model was to scan the whole 800+ entry model list for role badges.
46
+ - Standalone `AGENTS.md` ancestor discovery now bounds directory traversal, per-file reads, and aggregate instruction bytes while surfacing content-free omission warnings (#3722).
47
+
5
48
  ## [0.12.7] - 2026-07-31
6
49
 
7
50
  ## [0.12.6] - 2026-07-31
@@ -11,6 +54,7 @@
11
54
 
12
55
  ### Fixed
13
56
 
57
+ - Managed session publication now works on filesystems that implement no `renameat2` rename flags at all. NFS rejects both `RENAME_NOREPLACE` and `RENAME_EXCHANGE` with `EINVAL`, so publishing a migration receipt failed the whole resume with `Could not open managed session: invalid_request`. The no-replace publish now falls back to `linkat(2)`, which fails with `EEXIST` on an occupied destination and therefore carries the identical no-overwrite guarantee; the fallback is authorized only by a pre-mutation missing-primitive outcome, so a publish that may have committed is never retried under a second primitive. The staged descriptor is retained across publication and the staging link is removed only after it is released, because unlinking a still-open name on NFS silly-renames it and would leave a second link on the published inode.
14
58
  - Settings now requests a repaint after asynchronous GJC bundle and plugin views rebuild, so loaded content and mutation results appear without an extra keypress (#3643).
15
59
  - `todo_write` now rejects unsupported operation keys and treats a bare `done` or `drop` as an error instead of completing or abandoning every task (#3640).
16
60
  - Deferred `agent_end` publication again settles public session readiness before slow extension handlers finish, while retaining exact cancellation leases through queued extension delivery and draining that delivery before session shutdown.
@@ -28,6 +72,10 @@
28
72
 
29
73
  - Canonical wrapped first-event timeouts now continue the same clean turn through bounded retries and configured fallback rotation, while preserving replay-safety, cancellation, provider-terminal policies, exact attempt diagnostics, and task/subagent retry-status truth (#3553).
30
74
  - Runtime skill discovery now preserves a candidate when its exact skill name appears as a query token, so additional task-specific terms no longer discard an explicitly named skill.
75
+ ### Fixed
76
+
77
+ - Managed-session deletion now immediately continues a descriptor-authorized POSIX artifact detach through exact payload scrubbing before retiring the transcript. Durable direct and replay cleanup preserve substituted successors, while fork regressions use an explicit snapshot barrier instead of scheduler timing.
78
+ - Managed-session migration keeps a definitely live holder exclusive beyond the 60-second lease without timer-dependent self-fencing, permits immediate successor acquisition only after explicit release or proven process death, and surfaces capacity/busy startup failures through fixed path/content-redacted guidance (#3508).
31
79
 
32
80
  ## [0.12.5] - 2026-07-30
33
81
  ### Fixed
@@ -21,6 +21,7 @@ export interface NotifyCommandArgs {
21
21
  slackChannelId?: string;
22
22
  slackAuthorizedUserId?: string;
23
23
  redact?: boolean;
24
+ forceDaemonLock?: boolean;
24
25
  probe?: boolean;
25
26
  message?: string;
26
27
  }
@@ -55,6 +55,10 @@ export default class Notify extends Command {
55
55
  redact: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
56
56
  description: string;
57
57
  };
58
+ provider: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
59
+ description: string;
60
+ options: string[];
61
+ };
58
62
  probe: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
59
63
  description: string;
60
64
  };
@@ -3,6 +3,29 @@ import type { Args as ParsedArgs } from "../cli/args";
3
3
  import { type SessionLifecycleLaunchRequest } from "../sdk/broker/lifecycle";
4
4
  import { SessionManager } from "../session/session-manager";
5
5
  export declare function lifecycleArgs(request: SessionLifecycleLaunchRequest, cwd: string, agentDir: string): Promise<ParsedArgs>;
6
+ /**
7
+ * How long a session host tolerates the complete absence of a live broker
8
+ * publication before treating itself as orphaned. Hosts intentionally survive
9
+ * broker restarts (a replacement broker republishes discovery within seconds),
10
+ * so this must comfortably exceed a restart window while still bounding the
11
+ * lifetime of hosts whose broker is gone for good — otherwise every crashed or
12
+ * torn-down broker leaks a detached multi-hundred-megabyte host forever.
13
+ */
14
+ export declare const SESSION_HOST_BROKER_ABSENCE_GRACE_MS: number;
15
+ /**
16
+ * Resolves only once no live broker publication has been observable in
17
+ * `agentDir` for the full grace window. A reappearing broker (including a
18
+ * replacement with a different pid) resets the window; an unreadable
19
+ * publication is not proof of orphanhood but accrues against the same bound.
20
+ */
21
+ export declare function watchSessionHostBrokerLiveness(deps: {
22
+ agentDir: string;
23
+ now?: () => number;
24
+ sleep?: (ms: number) => Promise<void>;
25
+ readDiscovery?: (agentDir: string) => Promise<unknown>;
26
+ graceMs?: number;
27
+ pollMs?: number;
28
+ }): Promise<void>;
6
29
  /** Opens lifecycle-authorized history without letting replacement content reach readiness. */
7
30
  export declare function openLifecycleSessionManager(request: SessionLifecycleLaunchRequest, cwd: string, agentDir: string): Promise<{
8
31
  parsed: ParsedArgs;
@@ -3,6 +3,9 @@ export interface FileLockOptions {
3
3
  retries?: number;
4
4
  retryDelayMs?: number;
5
5
  }
6
+ export declare const FileLockTestHooks: {
7
+ afterParentMkdir?: (lockPath: string) => void | Promise<void>;
8
+ };
6
9
  /**
7
10
  * Returns the OS-provided process start timestamp for PID-reuse detection.
8
11
  * `ps` is available on the supported Unix hosts (macOS and Linux), unlike
@@ -25,13 +25,17 @@ export interface DiscoveryMergeInput {
25
25
  models: readonly Model<Api>[];
26
26
  state: ProviderDiscoveryState;
27
27
  warning?: string;
28
+ authGeneration?: string;
29
+ fetched?: boolean;
28
30
  }
29
31
  export interface ProviderDiscoveryCallbacks<TProvider extends DiscoveryProvider> {
30
32
  cacheDbPath?: string;
31
33
  requiresAuth: (provider: TProvider) => boolean;
32
34
  peekApiKey: (provider: TProvider) => Promise<string | undefined>;
33
35
  isAuthenticated: (apiKey: string | undefined) => boolean;
34
- fetchModels: (provider: TProvider) => Promise<Model<Api>[]>;
36
+ fetchModels: (provider: TProvider, apiKey: string | undefined) => Promise<Model<Api>[]>;
37
+ getEvidenceGeneration?: (provider: TProvider) => string;
38
+ canPublishCache?: (provider: TProvider) => boolean;
35
39
  }
36
40
  /** Owns configured discovery inputs, status, cache lifecycle, and refresh generations. */
37
41
  export declare class ModelDiscoveryManager<TProvider extends DiscoveryProvider> {
@@ -42,6 +46,7 @@ export declare class ModelDiscoveryManager<TProvider extends DiscoveryProvider>
42
46
  get providers(): readonly TProvider[];
43
47
  providerIds(): Set<string>;
44
48
  getState(provider: string): ProviderDiscoveryState | undefined;
49
+ invalidate(provider: string): void;
45
50
  loadCached(provider: TProvider, cacheDbPath?: string): readonly Model<Api>[];
46
51
  beginRefresh(provider: string): DiscoveryRefreshToken;
47
52
  isCurrent(token: DiscoveryRefreshToken): boolean;
@@ -1,6 +1,7 @@
1
1
  import { type Api, type AssistantMessageEventStream, type AuthCredentialSelector, type CacheRetention, type Context, type Model, type ModelRefreshStrategy, type ModelRequestTransform, type SimpleStreamOptions, type ThinkingConfig } from "@gajae-code/ai";
2
2
  import type { OAuthCredentials, OAuthLoginCallbacks } from "@gajae-code/ai/utils/oauth/types";
3
3
  import { type ThemeColor } from "../modes/theme/theme";
4
+ import { type ActiveProviderDescriptor } from "../sdk/providers";
4
5
  import type { AuthStorage } from "../session/auth-storage";
5
6
  import type { ActiveSearchModelContext, WebSearchMode } from "../web/search/types";
6
7
  import { type ConfigError, ConfigFile } from "./config-file";
@@ -360,6 +361,7 @@ export declare class ModelRegistry {
360
361
  * This is a fast check that doesn't refresh OAuth tokens.
361
362
  */
362
363
  getAvailable(): Model<Api>[];
364
+ getActiveProviders(): ActiveProviderDescriptor[];
363
365
  /**
364
366
  * Check whether auth is configured for a model's provider.
365
367
  *
@@ -7,8 +7,9 @@
7
7
  * Resolve a config value (API key, header value, etc.) to an actual value.
8
8
  * - If starts with "!", executes the rest as a shell command and uses stdout (cached)
9
9
  * - Otherwise checks environment variable first, then treats as literal (not cached)
10
+ * - `cacheScope` isolates command-cache entries when a caller rotates its config
10
11
  */
11
- export declare function resolveConfigValue(config: string): Promise<string | undefined>;
12
+ export declare function resolveConfigValue(config: string, cacheScope?: string): Promise<string | undefined>;
12
13
  /**
13
14
  * Resolve all header values using the same resolution logic as API keys.
14
15
  */
@@ -69,7 +69,7 @@ export type AnyUiMetadata = UiBase & {
69
69
  };
70
70
  interface BooleanDef {
71
71
  type: "boolean";
72
- default: boolean;
72
+ default?: boolean;
73
73
  ui?: UiBoolean;
74
74
  }
75
75
  interface StringDef {
@@ -143,6 +143,9 @@ export declare const SETTINGS_SCHEMA: {
143
143
  readonly type: "boolean";
144
144
  readonly default: false;
145
145
  };
146
+ readonly "notifications.telegram.enabled": {
147
+ readonly type: "boolean";
148
+ };
146
149
  readonly "notifications.telegram.botToken": {
147
150
  readonly type: "string";
148
151
  readonly default: undefined;
@@ -209,6 +212,9 @@ export declare const SETTINGS_SCHEMA: {
209
212
  readonly type: "string";
210
213
  readonly default: undefined;
211
214
  };
215
+ readonly "notifications.discord.enabled": {
216
+ readonly type: "boolean";
217
+ };
212
218
  readonly "notifications.discord.botToken": {
213
219
  readonly type: "string";
214
220
  readonly default: undefined;
@@ -225,6 +231,9 @@ export declare const SETTINGS_SCHEMA: {
225
231
  readonly type: "string";
226
232
  readonly default: undefined;
227
233
  };
234
+ readonly "notifications.slack.enabled": {
235
+ readonly type: "boolean";
236
+ };
228
237
  readonly "notifications.slack.botToken": {
229
238
  readonly type: "string";
230
239
  readonly default: undefined;
@@ -4186,7 +4195,10 @@ export type SettingPath = keyof Schema;
4186
4195
  /** Infer the value type for a setting path */
4187
4196
  export type SettingValue<P extends SettingPath> = Schema[P] extends {
4188
4197
  type: "boolean";
4198
+ default: boolean;
4189
4199
  } ? boolean : Schema[P] extends {
4200
+ type: "boolean";
4201
+ } ? boolean | undefined : Schema[P] extends {
4190
4202
  type: "string";
4191
4203
  } ? string | undefined : Schema[P] extends {
4192
4204
  type: "number";
@@ -4365,6 +4377,7 @@ export interface MemoryGuardSettings {
4365
4377
  export interface NotificationsSettings {
4366
4378
  enabled: boolean;
4367
4379
  telegram: {
4380
+ enabled?: boolean;
4368
4381
  botToken: string | undefined;
4369
4382
  chatId: string | undefined;
4370
4383
  sound: "all" | "important" | "none";
@@ -4388,16 +4401,19 @@ export interface NotificationsSettings {
4388
4401
  };
4389
4402
  };
4390
4403
  discord: {
4404
+ enabled?: boolean;
4391
4405
  botToken: string | undefined;
4392
4406
  applicationId: string | undefined;
4393
4407
  guildId: string | undefined;
4394
4408
  parentChannelId: string | undefined;
4395
4409
  };
4396
4410
  slack: {
4411
+ enabled?: boolean;
4397
4412
  botToken: string | undefined;
4398
4413
  appToken: string | undefined;
4399
4414
  workspaceId: string | undefined;
4400
4415
  channelId: string | undefined;
4416
+ authorizedUserId: string | undefined;
4401
4417
  };
4402
4418
  redact: boolean;
4403
4419
  verbosity: "lean" | "verbose";
@@ -1 +1,11 @@
1
- export {};
1
+ import { type ContextFile } from "../capability/context-file";
2
+ import type { LoadContext, LoadResult } from "../capability/types";
3
+ export type AgentsMdReader = (filePath: string, maxBytes: number) => Promise<{
4
+ content: string | null;
5
+ byteLength: number;
6
+ tooLarge: boolean;
7
+ }>;
8
+ /**
9
+ * Load standalone AGENTS.md files.
10
+ */
11
+ export declare function loadAgentsMd(ctx: LoadContext, readCandidate?: AgentsMdReader): Promise<LoadResult<ContextFile>>;
@@ -110,6 +110,7 @@ export interface RlmPreset {
110
110
  type RunPrintMode = (session: AgentSession, options: PrintModeOptions) => Promise<void>;
111
111
  export interface RunRootCommandDependencies {
112
112
  createAgentSession?: typeof createAgentSession;
113
+ createSessionManager?: typeof createSessionManager;
113
114
  discoverAuthStorage?: typeof discoverAuthStorage;
114
115
  runAcpMode?: (options?: {
115
116
  agentDir?: string;
@@ -22,6 +22,21 @@ export interface HookSelectorOptions {
22
22
  */
23
23
  wrapFocused?: boolean;
24
24
  scrollTitleRows?: number;
25
+ /**
26
+ * Maximum visible rows for the inline editor in bounded scroll-title selectors.
27
+ * The editor keeps the full draft and scrolls within this height.
28
+ */
29
+ inlineEditorMaxHeight?: number;
30
+ /**
31
+ * Maximum visible autocomplete rows for the inline editor in a bounded selector.
32
+ * The Editor retains its normal minimum and scroll indicator behavior.
33
+ */
34
+ inlineAutocompleteMaxVisible?: number;
35
+ /**
36
+ * Compact bounded-selector chrome while the inline editor is active.
37
+ * Used only when the terminal cannot fit the normal editor and dropdown rows.
38
+ */
39
+ compactInlineInput?: boolean;
25
40
  /**
26
41
  * Inline free-text entry for the option with this label (e.g. the ask
27
42
  * tool's "Other (type your own)"). Selecting it keeps the title and option
@@ -54,6 +69,11 @@ export declare class HookSelectorComponent extends Container {
54
69
  #private;
55
70
  constructor(title: string, options: string[], onSelect: (option: string) => void, onCancel: () => void, opts?: HookSelectorOptions);
56
71
  hasActiveInlineInput(): boolean;
72
+ /**
73
+ * Update the bounded selector's title/list row budgets after a terminal resize.
74
+ * The existing title scroll offset, option focus, and inline editor remain intact.
75
+ */
76
+ setLayoutBudget(maxVisible: number, scrollTitleRows: number, inlineEditorMaxHeight?: number | undefined, inlineAutocompleteMaxVisible?: number | undefined, compactInlineInput?: boolean): void;
57
77
  handleInput(keyData: string): void;
58
78
  dispose(): void;
59
79
  }
@@ -1,5 +1,6 @@
1
1
  import { type Component, type Focusable, type SecretValue } from "@gajae-code/tui";
2
2
  import type { CasReceipt } from "../../config/atomic-yaml-patch";
3
+ import type { NotificationProvider, ProviderSecretDisposition } from "../../sdk/bus/config";
3
4
  import type { BlockedTelegramRestoreResult, ProposedTelegramIdentity, TelegramDaemonReconnectOutcome } from "../../sdk/bus/notification-orchestration";
4
5
  import type { NotificationHealthReport, NotificationRecoveryReport, NotificationStatusReport, NotificationTestResult } from "../../sdk/bus/notification-service";
5
6
  import type { NotificationSessionReconcileResult, NotificationSessionStatus } from "../../sdk/bus/session-control";
@@ -45,6 +46,40 @@ export interface PreparedTelegramConfiguration {
45
46
  richDraftEnabled: boolean;
46
47
  streamingEnabled: boolean;
47
48
  }
49
+ export interface ProviderSecretActionInput {
50
+ action: ProviderSecretDisposition;
51
+ value?: SecretValue;
52
+ }
53
+ export interface NotificationsProviderSetupInput {
54
+ provider: "discord" | "slack";
55
+ botToken: ProviderSecretActionInput;
56
+ appToken?: ProviderSecretActionInput;
57
+ applicationId?: string;
58
+ guildId?: string;
59
+ parentChannelId?: string;
60
+ workspaceId?: string;
61
+ channelId?: string;
62
+ authorizedUserId?: string;
63
+ }
64
+ export interface PreparedNotificationProviderConfiguration {
65
+ provider: "discord" | "slack";
66
+ botTokenDisposition: ProviderSecretDisposition;
67
+ botTokenMask: string;
68
+ appTokenDisposition?: ProviderSecretDisposition;
69
+ appTokenMask?: string;
70
+ applicationId?: string;
71
+ guildId?: string;
72
+ parentChannelId?: string;
73
+ workspaceId?: string;
74
+ channelId?: string;
75
+ authorizedUserId?: string;
76
+ applicationIdDisplay?: string;
77
+ guildIdDisplay?: string;
78
+ parentChannelIdDisplay?: string;
79
+ workspaceIdDisplay?: string;
80
+ channelIdDisplay?: string;
81
+ authorizedUserIdDisplay?: string;
82
+ }
48
83
  export interface NotificationsPreflightResult {
49
84
  status: "ready" | "aborted" | "cancelled" | "error";
50
85
  identity: ProposedTelegramIdentity;
@@ -57,6 +92,10 @@ export type NotificationsConfigureCommitResult = {
57
92
  status: "saved";
58
93
  receipt: CasReceipt;
59
94
  message: string;
95
+ } | {
96
+ status: "activation_failed" | "observer_failed";
97
+ receipt: CasReceipt;
98
+ message: string;
60
99
  } | {
61
100
  status: "blocked_identity";
62
101
  receipt: CasReceipt;
@@ -67,11 +106,16 @@ export type NotificationsConfigureCommitResult = {
67
106
  export interface NotificationsMutationResult {
68
107
  message: string;
69
108
  receipt?: CasReceipt;
109
+ outcome?: "success" | "degraded" | "failed";
70
110
  }
71
111
  export type NotificationsSaveInactiveResult = {
72
112
  status: "saved_inactive";
73
113
  receipt: CasReceipt;
74
114
  message: string;
115
+ } | {
116
+ status: "observer_failed";
117
+ receipt: CasReceipt;
118
+ message: string;
75
119
  } | {
76
120
  status: "unavailable";
77
121
  guidance: string;
@@ -85,12 +129,13 @@ export type NotificationsSaveInactiveResult = {
85
129
  export interface NotificationsEditorOperations {
86
130
  /** Combines a buildNotificationStatusReport-shaped status snapshot with the current session-control query. */
87
131
  loadState(): Promise<NotificationsEditorState>;
88
- /** Performs offline health refreshes and a non-cancellable reachability probe when requested. */
132
+ /** Performs offline or selected REST-only health refresh. */
89
133
  refreshHealth(input: {
90
134
  probe: boolean;
135
+ provider?: NotificationProvider;
91
136
  signal?: AbortSignal;
92
137
  }): Promise<NotificationHealthReport>;
93
- sendTest(): Promise<NotificationTestResult>;
138
+ sendTest(provider?: NotificationProvider): Promise<NotificationTestResult>;
94
139
  recover(): Promise<NotificationRecoveryReport>;
95
140
  reconnect(): Promise<TelegramDaemonReconnectOutcome>;
96
141
  /** Validates/discovers a Telegram destination and returns a secret-safe prepared draft. */
@@ -101,6 +146,11 @@ export interface NotificationsEditorOperations {
101
146
  saveInactive(draft: PreparedTelegramConfiguration): Promise<NotificationsSaveInactiveResult>;
102
147
  /** Clears adapter-local ephemeral credential material for a prepared setup draft. Idempotent. */
103
148
  discardConfigureDraft(draft: PreparedTelegramConfiguration): void;
149
+ prepareProviderConfiguration(input: NotificationsProviderSetupInput): Promise<PreparedNotificationProviderConfiguration>;
150
+ commitProviderConfiguration(draft: PreparedNotificationProviderConfiguration): Promise<NotificationsMutationResult>;
151
+ discardProviderConfiguration(draft: PreparedNotificationProviderConfiguration): void;
152
+ setProviderDesired(provider: NotificationProvider, enabled: boolean): Promise<NotificationsMutationResult>;
153
+ removeProvider(provider: NotificationProvider): Promise<NotificationsMutationResult>;
104
154
  /** Enables globally without requesting or exposing a credential. */
105
155
  enableGlobally(): Promise<NotificationsMutationResult>;
106
156
  disableGlobally(): Promise<NotificationsMutationResult>;
@@ -117,7 +167,7 @@ export interface NotificationsEditorOperations {
117
167
  export interface NotificationsSettingsEditorCallbacks {
118
168
  onCancel?: () => void;
119
169
  }
120
- type EditorMode = "home" | "provider-selection" | "chat-entry" | "token-entry" | "pairing" | "review" | "preferences" | "confirmation";
170
+ export type EditorMode = "home" | "provider-selection" | "provider-actions" | "provider-form" | "provider-review" | "chat-entry" | "token-entry" | "pairing" | "review" | "preferences" | "confirmation";
121
171
  /**
122
172
  * Direct tab content for notification setup and operations. It is deliberately
123
173
  * independent of Settings and notification services; WI7b injects the adapter.
@@ -137,4 +187,3 @@ export declare class NotificationsSettingsEditorComponent implements Component,
137
187
  render(width: number): string[];
138
188
  handleInput(data: string): void;
139
189
  }
140
- export {};
@@ -1,4 +1,4 @@
1
- import type { Component, TUI } from "@gajae-code/tui";
1
+ import { type Component, type TUI } from "@gajae-code/tui";
2
2
  import { KeybindingsManager } from "../../config/keybindings";
3
3
  import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionWidgetContent, ExtensionWidgetOptions, TerminalInputHandler } from "../../extensibility/extensions";
4
4
  import { type Theme } from "../../modes/theme/theme";
@@ -2,8 +2,8 @@ import type { Component, SlashCommand } from "@gajae-code/tui";
2
2
  import type { ModelProfileConfig } from "../../config/models-config-schema";
3
3
  import { type Settings } from "../../config/settings";
4
4
  import { type InteractiveModeContext, type OAuthSelectorOptions } from "../../modes/types";
5
- import { getNotificationConfig, maskToken } from "../../sdk/bus/config";
6
- import { proposedTelegramIdentity, reconcileCommittedTelegramConfiguration, removeTelegramConfiguration, saveTelegramInactive } from "../../sdk/bus/notification-orchestration";
5
+ import { getCurrentTelegramActivationMarker, getNotificationConfig, maskToken } from "../../sdk/bus/config";
6
+ import { type NotificationProviderRuntimeAuthority, proposedTelegramIdentity, reconcileCommittedTelegramConfiguration, removeTelegramConfiguration, saveTelegramInactive } from "../../sdk/bus/notification-orchestration";
7
7
  import { buildNotificationStatusReport, checkNotificationHealth, recoverNotifications, sanitizeDiagnostic, sendNotificationTest } from "../../sdk/bus/notification-service";
8
8
  import { ensureTelegramDaemonRunningDetailed, readNotificationRootRegistration, resolveTelegramSetupPreflight, unregisterNotificationRoot } from "../../sdk/bus/telegram-daemon";
9
9
  import { runTelegramSetup } from "../../sdk/bus/telegram-setup";
@@ -37,6 +37,7 @@ type TelegramDaemonStopResult = {
37
37
  };
38
38
  export interface NotificationsEditorOperationDependencies {
39
39
  getNotificationConfig: typeof getNotificationConfig;
40
+ getCurrentTelegramActivationMarker: typeof getCurrentTelegramActivationMarker;
40
41
  maskToken: typeof maskToken;
41
42
  buildNotificationStatusReport: typeof buildNotificationStatusReport;
42
43
  checkNotificationHealth: typeof checkNotificationHealth;
@@ -66,6 +67,7 @@ export interface NotificationsEditorOperationDependencies {
66
67
  message: string;
67
68
  }>;
68
69
  stopTelegramDaemon(settings: Settings): Promise<TelegramDaemonStopResult>;
70
+ providerRuntime?: NotificationProviderRuntimeAuthority;
69
71
  }
70
72
  /**
71
73
  * Concrete service adapter for the direct Notifications settings tab. Secrets remain in this closure's
@@ -374,5 +374,11 @@ export interface OAuthSelectorOptions {
374
374
  allowExternalCredentialDiscovery?: boolean;
375
375
  trigger?: "bare-login";
376
376
  externalCredentialDiscover?: CredentialAutoImportOptions["discover"];
377
+ /**
378
+ * Pair by pasting the code the provider displays instead of waiting on the
379
+ * loopback callback. Set by `/login <provider> --manual` for browsers that
380
+ * cannot reach this machine.
381
+ */
382
+ manualCode?: boolean;
377
383
  }
378
384
  export {};
@@ -1,7 +1,7 @@
1
1
  import type { NativeDirectoryTreeSnapshot } from "@gajae-code/natives";
2
2
  import type { ModelProfileErrorDetails } from "../../config/model-profile-contract";
3
3
  import { type DirectoryMigrationPolicy } from "../session-directory";
4
- import { type BrokerDiscovery, type RedactedBrokerDiscovery } from "./discovery";
4
+ import { type BrokerDiscovery, type BrokerPublicationObservation, type RedactedBrokerDiscovery } from "./discovery";
5
5
  import { type LifecycleDurableEffectsReceipt, LifecycleLedger, type LifecycleStartupFailureReceipt } from "./lifecycle-ledger";
6
6
  import { SessionIndex } from "./session-index";
7
7
  export interface BrokerSettings {
@@ -137,4 +137,8 @@ export declare class Broker {
137
137
  }
138
138
  /** Test-only hook for simulating a process crash after terminal persistence verification. */
139
139
  export declare function setTerminalPersistenceHookForTest(broker: Broker, hook: (() => void) | undefined): void;
140
+ /** Test-only hook for shortening the bounded ambiguity deadline. */
141
+ export declare function setAmbiguityGraceForTest(broker: Broker, graceMs: number | undefined): void;
142
+ /** Test-only hook for forcing the observation the publication watchdog sees. */
143
+ export declare function setPublicationObservationForTest(broker: Broker, observation: BrokerPublicationObservation | undefined): void;
140
144
  export {};
@@ -119,4 +119,5 @@ export declare class LifecycleLedger {
119
119
  findCleanupPendingBySessionId(sessionId: string, excludingIdentity: string): LifecycleLedgerEntry | undefined;
120
120
  hasUncertainCleanupForSession(sessionId: string, excludingIdentity: string): boolean;
121
121
  get(identity: string): LifecycleLedgerEntry | undefined;
122
+ findPendingCleanupByTarget(sessionId: string, cwd: string, transcriptPath: string): LifecycleLedgerEntry | undefined;
122
123
  }
@@ -21,7 +21,16 @@ export type ChatDaemonAction = "stop" | "reload";
21
21
  * daemon transports. Generation 16 applies Telegram sound-policy configuration
22
22
  * through shared notification parsing. Generation 17 bound managed-session
23
23
  * replacement to exact native filesystem authority; generation 18 retired that
24
- * binding, and generation 19 binds exact cleanup to parent/link-count authority.
24
+ * binding, and generation 19 binds exact cleanup to parent/link-count authority
25
+ * while also adding durable provider-intent admission without changing lifecycle
26
+ * behavior. Generation 20 discovers isolated chat-only session endpoints when
27
+ * Telegram identity ownership is blocked. Discord generation 21 applies rustfmt
28
+ * and clippy-equivalent cleanup to the pi-shell process-tree authority (#3682).
29
+ * Discord generation 22 / slack generation 21 refreshes retained cleanup
30
+ * semantics; discord generation 23 / slack generation 22 hardens exact Bash
31
+ * process-tree ownership shared by chat daemon cleanup.
32
+ * Discord generation 24 / slack generation 23 apply provider-completeness and
33
+ * effective-enable admission to chat daemon lifecycle controls.
25
34
  */
26
35
  export declare const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>>;
27
36
  export declare function chatDaemonGeneration(kind: ChatDaemonKind): number;
@@ -102,6 +111,7 @@ export declare class ChatDaemonController implements BuiltInDaemonController {
102
111
  readonly kind: ChatDaemonKind;
103
112
  constructor(settings: Settings, kind: ChatDaemonKind, deps?: ChatDaemonControlDeps);
104
113
  private identity;
114
+ private effectivelyEnabled;
105
115
  private alive;
106
116
  status(): Promise<DaemonStatus>;
107
117
  stop(opts?: DaemonOperationOptions): Promise<DaemonOperationResult>;