@gajae-code/coding-agent 0.12.6 → 0.12.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 (150) hide show
  1. package/CHANGELOG.md +22 -1
  2. package/dist/types/async/job-manager.d.ts +36 -1
  3. package/dist/types/commands/notify.d.ts +4 -0
  4. package/dist/types/config/file-lock.d.ts +3 -0
  5. package/dist/types/config/model-discovery-manager.d.ts +6 -1
  6. package/dist/types/config/model-registry.d.ts +2 -0
  7. package/dist/types/config/resolve-config-value.d.ts +2 -1
  8. package/dist/types/config/settings-schema.d.ts +17 -1
  9. package/dist/types/eval/backend.d.ts +2 -2
  10. package/dist/types/exec/bash-executor.d.ts +8 -10
  11. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +0 -36
  12. package/dist/types/internal-urls/registry-helpers.d.ts +0 -18
  13. package/dist/types/main.d.ts +1 -0
  14. package/dist/types/modes/components/hook-selector.d.ts +20 -0
  15. package/dist/types/modes/components/notifications-settings-editor.d.ts +53 -4
  16. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  17. package/dist/types/modes/controllers/selector-controller.d.ts +4 -2
  18. package/dist/types/sdk/broker/broker.d.ts +5 -1
  19. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +1 -0
  20. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -3
  21. package/dist/types/sdk/bus/config.d.ts +75 -113
  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 +31 -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 +9 -4
  31. package/dist/types/sdk/client/discovery.d.ts +2 -1
  32. package/dist/types/sdk/host/host.d.ts +2 -23
  33. package/dist/types/sdk/host/query/handlers.d.ts +2 -0
  34. package/dist/types/sdk/host/reverse-leases.d.ts +4 -7
  35. package/dist/types/sdk/index.d.ts +1 -0
  36. package/dist/types/sdk/providers.d.ts +22 -0
  37. package/dist/types/sdk/session-directory.d.ts +1 -1
  38. package/dist/types/session/artifacts.d.ts +5 -8
  39. package/dist/types/session/client-bridge.d.ts +0 -14
  40. package/dist/types/session/internal/managed-session-scope.d.ts +17 -1
  41. package/dist/types/session/internal/managed-session-storage.d.ts +11 -4
  42. package/dist/types/session/internal/native-publish-outcome.d.ts +1 -0
  43. package/dist/types/session/internal/session-open-errors.d.ts +5 -0
  44. package/dist/types/session/messages.d.ts +1 -4
  45. package/dist/types/session/session-manager.d.ts +7 -6
  46. package/dist/types/session/session-storage.d.ts +2 -0
  47. package/dist/types/session/streaming-output.d.ts +0 -32
  48. package/dist/types/task/receipt.d.ts +1 -2
  49. package/dist/types/task/types.d.ts +43 -178
  50. package/dist/types/tools/bash.d.ts +1 -1
  51. package/dist/types/tools/fetch.d.ts +0 -3
  52. package/dist/types/tools/output-meta.d.ts +5 -37
  53. package/dist/types/tools/subagent.d.ts +15 -0
  54. package/dist/types/tools/todo-write.d.ts +3 -0
  55. package/dist/types/tools/tool-result.d.ts +0 -1
  56. package/package.json +10 -8
  57. package/scripts/build-sdk-package-smoke.ts +51 -0
  58. package/scripts/capture-notifications-settings-showcase.ts +1 -1
  59. package/src/async/job-manager.ts +430 -46
  60. package/src/cli/notify-cli.ts +204 -94
  61. package/src/commands/notify.ts +19 -8
  62. package/src/config/file-lock.ts +6 -0
  63. package/src/config/model-discovery-manager.ts +50 -8
  64. package/src/config/model-registry.ts +862 -75
  65. package/src/config/resolve-config-value.ts +10 -8
  66. package/src/config/settings-schema.ts +25 -15
  67. package/src/config/settings.ts +15 -15
  68. package/src/cursor.ts +13 -20
  69. package/src/defaults/gjc/skills/ultragoal/SKILL.md +2 -3
  70. package/src/eval/backend.ts +2 -2
  71. package/src/exec/bash-executor.ts +151 -425
  72. package/src/gjc-runtime/session-state-sidecar.ts +12 -2
  73. package/src/gjc-runtime/ultragoal-runtime.ts +3 -280
  74. package/src/gjc-runtime/workflow-manifest.generated.json +1 -40
  75. package/src/gjc-runtime/workflow-manifest.ts +0 -12
  76. package/src/internal-urls/agent-protocol.ts +38 -98
  77. package/src/internal-urls/artifact-protocol.ts +17 -28
  78. package/src/internal-urls/docs-index.generated.ts +7 -7
  79. package/src/internal-urls/registry-helpers.ts +0 -62
  80. package/src/main.ts +43 -7
  81. package/src/modes/DESIGN.md +11 -11
  82. package/src/modes/acp/acp-agent.ts +0 -24
  83. package/src/modes/acp/acp-client-bridge.ts +11 -154
  84. package/src/modes/components/hook-selector.ts +155 -44
  85. package/src/modes/components/model-selector.ts +242 -49
  86. package/src/modes/components/notifications-settings-editor.ts +631 -85
  87. package/src/modes/controllers/extension-ui-controller.ts +114 -15
  88. package/src/modes/controllers/selector-controller.ts +464 -50
  89. package/src/prompts/tools/bash.md +2 -2
  90. package/src/sdk/acp/adapter.ts +9 -200
  91. package/src/sdk/broker/broker.ts +54 -10
  92. package/src/sdk/broker/lifecycle-ledger.ts +34 -1
  93. package/src/sdk/broker/lifecycle.ts +47 -50
  94. package/src/sdk/bus/chat-daemon-cli.ts +12 -5
  95. package/src/sdk/bus/chat-daemon-control.ts +35 -8
  96. package/src/sdk/bus/chat-daemon-runtime.ts +16 -2
  97. package/src/sdk/bus/config.ts +534 -286
  98. package/src/sdk/bus/discord-live-provider.ts +57 -2
  99. package/src/sdk/bus/discord-provider.ts +21 -0
  100. package/src/sdk/bus/index.ts +105 -359
  101. package/src/sdk/bus/notification-orchestration.ts +371 -68
  102. package/src/sdk/bus/notification-service.ts +431 -130
  103. package/src/sdk/bus/session-control.ts +119 -44
  104. package/src/sdk/bus/slack-live-provider.ts +78 -2
  105. package/src/sdk/bus/slack-provider.ts +24 -0
  106. package/src/sdk/bus/telegram-daemon-cli.ts +9 -2
  107. package/src/sdk/bus/telegram-daemon-contract.ts +9 -4
  108. package/src/sdk/bus/telegram-daemon-control.ts +3 -3
  109. package/src/sdk/bus/telegram-daemon.ts +23 -15
  110. package/src/sdk/client/discovery.ts +10 -4
  111. package/src/sdk/host/host.ts +9 -187
  112. package/src/sdk/host/query/handlers.ts +20 -1
  113. package/src/sdk/host/reverse-leases.ts +42 -249
  114. package/src/sdk/index.ts +1 -0
  115. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  116. package/src/sdk/protocol/operation-registry.ts +5 -2
  117. package/src/sdk/providers.ts +51 -0
  118. package/src/sdk/session-directory.ts +1 -0
  119. package/src/sdk/session.ts +10 -7
  120. package/src/session/agent-session.ts +59 -202
  121. package/src/session/artifacts.ts +74 -211
  122. package/src/session/client-bridge.ts +0 -15
  123. package/src/session/internal/managed-session-scope.ts +981 -450
  124. package/src/session/internal/managed-session-storage.ts +362 -124
  125. package/src/session/internal/native-publish-outcome.ts +3 -1
  126. package/src/session/internal/session-open-errors.ts +11 -0
  127. package/src/session/messages.ts +7 -32
  128. package/src/session/session-manager.ts +48 -15
  129. package/src/session/session-storage.ts +72 -5
  130. package/src/session/streaming-output.ts +40 -198
  131. package/src/slash-commands/builtin-registry.ts +82 -4
  132. package/src/task/index.ts +237 -65
  133. package/src/task/receipt.ts +2 -4
  134. package/src/task/render.ts +0 -30
  135. package/src/task/types.ts +10 -34
  136. package/src/tools/ask.ts +1 -1
  137. package/src/tools/bash.ts +239 -818
  138. package/src/tools/eval.ts +4 -99
  139. package/src/tools/fetch.ts +15 -77
  140. package/src/tools/find.ts +3 -7
  141. package/src/tools/output-meta.ts +114 -696
  142. package/src/tools/search.ts +4 -9
  143. package/src/tools/subagent.ts +97 -75
  144. package/src/tools/telegram-send.ts +4 -2
  145. package/src/tools/todo-write.ts +47 -0
  146. package/src/tools/tool-result.ts +0 -1
  147. package/dist/types/gjc-runtime/ultragoal-review-source.d.ts +0 -83
  148. package/dist/types/utils/artifact-id.d.ts +0 -2
  149. package/src/gjc-runtime/ultragoal-review-source.ts +0 -378
  150. package/src/utils/artifact-id.ts +0 -6
@@ -11,10 +11,11 @@ import {
11
11
  } from "./chat-daemon-control";
12
12
  import { type ChatDaemonRuntimeConfig, ChatDaemonRuntime as DefaultChatDaemonRuntime } from "./chat-daemon-runtime";
13
13
  import {
14
- isDiscordConfigured,
15
- isSlackConfigured,
14
+ isDiscordComplete,
15
+ isSlackComplete,
16
16
  loadNotificationConfigFile,
17
17
  notificationConfigFromFile,
18
+ resolveNotificationProvider,
18
19
  } from "./config";
19
20
 
20
21
  export interface ChatDaemonRuntimeHandle {
@@ -60,7 +61,10 @@ async function loadConfig(agentDir: string, kind: ChatDaemonKind): Promise<ChatD
60
61
  const config = notificationConfigFromFile(loaded.value);
61
62
  if (!config.enabled) return undefined;
62
63
  if (kind === "discord") {
63
- if (!isDiscordConfigured(config)) {
64
+ const resolution = resolveNotificationProvider(config, "discord");
65
+ if (!resolution.desiredEnabled) return undefined;
66
+ if (resolution.quarantined) throw new Error("Discord notification configuration needs repair");
67
+ if (!resolution.configured || !isDiscordComplete(config)) {
64
68
  throw new Error("Discord notifications are enabled but configuration is incomplete");
65
69
  }
66
70
  const discord = config.discord;
@@ -78,7 +82,10 @@ async function loadConfig(agentDir: string, kind: ChatDaemonKind): Promise<ChatD
78
82
  presentation: { redact: config.redact, verbosity: config.verbosity },
79
83
  };
80
84
  }
81
- if (!isSlackConfigured(config)) {
85
+ const resolution = resolveNotificationProvider(config, "slack");
86
+ if (!resolution.desiredEnabled) return undefined;
87
+ if (resolution.quarantined) throw new Error("Slack notification configuration needs repair");
88
+ if (!resolution.configured || !isSlackComplete(config)) {
82
89
  throw new Error("Slack notifications are enabled but configuration is incomplete");
83
90
  }
84
91
  const slack = config.slack;
@@ -149,7 +156,7 @@ export async function runChatDaemonInternal(
149
156
 
150
157
  let incarnation: string | undefined;
151
158
  let runtime: ChatDaemonRuntimeHandle | undefined;
152
- let interval: ReturnType<typeof setInterval> | undefined;
159
+ let interval: NodeJS.Timeout | number | undefined;
153
160
  let stopping = false;
154
161
  let terminalError: unknown;
155
162
  let runtimeStop: Promise<void> | undefined;
@@ -16,7 +16,7 @@ import type {
16
16
  } from "../../daemon/control-types";
17
17
  import { resolveGjcRuntimeSpawnInfo } from "../../daemon/runtime";
18
18
  import { isProcessIncarnation, processIncarnation } from "../broker/process-incarnation";
19
- import { getNotificationConfig, isDiscordConfigured, isSlackConfigured } from "./config";
19
+ import { getNotificationConfig, isDiscordComplete, isProviderEffectivelyEnabled, isSlackComplete } from "./config";
20
20
 
21
21
  export type ChatDaemonKind = "discord" | "slack";
22
22
  export type ChatDaemonAction = "stop" | "reload";
@@ -40,13 +40,20 @@ export type ChatDaemonAction = "stop" | "reload";
40
40
  * daemon transports. Generation 16 applies Telegram sound-policy configuration
41
41
  * through shared notification parsing. Generation 17 bound managed-session
42
42
  * replacement to exact native filesystem authority; generation 18 retired that
43
- * binding, generation 19 bound exact cleanup to parent/link-count authority,
44
- * generation 20 refreshed retained cleanup semantics, and generation 21 hardens
45
- * exact Bash process-tree ownership shared by chat daemon cleanup.
43
+ * binding, and generation 19 binds exact cleanup to parent/link-count authority
44
+ * while also adding durable provider-intent admission without changing lifecycle
45
+ * behavior. Generation 20 discovers isolated chat-only session endpoints when
46
+ * Telegram identity ownership is blocked. Discord generation 21 applies rustfmt
47
+ * and clippy-equivalent cleanup to the pi-shell process-tree authority (#3682).
48
+ * Discord generation 22 / slack generation 21 refreshes retained cleanup
49
+ * semantics; discord generation 23 / slack generation 22 hardens exact Bash
50
+ * process-tree ownership shared by chat daemon cleanup.
51
+ * Discord generation 24 / slack generation 23 apply provider-completeness and
52
+ * effective-enable admission to chat daemon lifecycle controls.
46
53
  */
47
54
  export const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>> = {
48
- discord: 21,
49
- slack: 21,
55
+ discord: 24,
56
+ slack: 23,
50
57
  };
51
58
 
52
59
  export function chatDaemonGeneration(kind: ChatDaemonKind): number {
@@ -273,7 +280,7 @@ export function chatDaemonPaths(
273
280
  function identityFor(settings: Settings, kind: ChatDaemonKind): string | undefined {
274
281
  const cfg = getNotificationConfig(settings);
275
282
  if (kind === "discord") {
276
- if (!isDiscordConfigured(cfg)) return undefined;
283
+ if (!isDiscordComplete(cfg)) return undefined;
277
284
  return fingerprint([
278
285
  cfg.discord.botToken,
279
286
  cfg.discord.applicationId,
@@ -283,7 +290,7 @@ function identityFor(settings: Settings, kind: ChatDaemonKind): string | undefin
283
290
  cfg.verbosity,
284
291
  ]);
285
292
  }
286
- if (!isSlackConfigured(cfg)) return undefined;
293
+ if (!isSlackComplete(cfg)) return undefined;
287
294
  return fingerprint([
288
295
  cfg.slack.botToken,
289
296
  cfg.slack.appToken,
@@ -428,6 +435,9 @@ export class ChatDaemonController implements BuiltInDaemonController {
428
435
  private identity(): string | undefined {
429
436
  return identityFor(this.settings, this.kind);
430
437
  }
438
+ private effectivelyEnabled(): boolean {
439
+ return isProviderEffectivelyEnabled(getNotificationConfig(this.settings), this.kind);
440
+ }
431
441
  private alive(pid: number): boolean {
432
442
  return (this.deps.pidAlive ?? defaultPidAlive)(pid);
433
443
  }
@@ -455,6 +465,7 @@ export class ChatDaemonController implements BuiltInDaemonController {
455
465
  return await this.operate("reload", opts);
456
466
  }
457
467
  async ensure(): Promise<EnsureChatDaemonResult> {
468
+ if (!this.effectivelyEnabled()) return "disabled";
458
469
  const identity = this.identity();
459
470
  if (!identity) return "disabled";
460
471
  const existing = await readChatDaemonState(this.settings.getAgentDir(), this.kind);
@@ -487,6 +498,9 @@ export class ChatDaemonController implements BuiltInDaemonController {
487
498
  const warnings = before.runtime.warning ? [before.runtime.warning] : [];
488
499
  if (!before.configured)
489
500
  return this.result(action, false, `${this.kind} notifications are not configured`, before, before, warnings);
501
+ if (action === "reload" && !this.effectivelyEnabled()) {
502
+ return this.result(action, false, `${this.kind} notifications are not enabled`, before, before, warnings);
503
+ }
490
504
  const state = await readChatDaemonState(this.settings.getAgentDir(), this.kind);
491
505
  const classification = this.classify(state, this.identity());
492
506
  if (classification === "newer")
@@ -522,6 +536,8 @@ export class ChatDaemonController implements BuiltInDaemonController {
522
536
  }
523
537
  if (opts.spawnIfStopped === false)
524
538
  return this.result(action, true, `no running ${this.kind} daemon to reload`, before, before, warnings);
539
+ if (!this.effectivelyEnabled())
540
+ return this.result(action, false, `${this.kind} notifications are not enabled`, before, before, warnings);
525
541
  const spawned = await this.spawn();
526
542
  return this.result(
527
543
  action,
@@ -575,6 +591,15 @@ export class ChatDaemonController implements BuiltInDaemonController {
575
591
  await clearChatDaemonControlRequest(this.settings.getAgentDir(), this.kind, requestId);
576
592
  if (action === "stop")
577
593
  return this.result(action, true, `stopped ${this.kind} daemon`, before, await this.status(), warnings);
594
+ if (!this.effectivelyEnabled())
595
+ return this.result(
596
+ action,
597
+ false,
598
+ `${this.kind} notifications are not enabled`,
599
+ before,
600
+ await this.status(),
601
+ warnings,
602
+ );
578
603
  const spawned = await this.spawn();
579
604
  return this.result(
580
605
  action,
@@ -752,6 +777,7 @@ export class ChatDaemonController implements BuiltInDaemonController {
752
777
  return this.deps.sleep ? this.deps.sleep(ms) : new Promise(resolve => setTimeout(resolve, ms));
753
778
  }
754
779
  private async spawn(): Promise<boolean> {
780
+ if (!this.effectivelyEnabled()) return false;
755
781
  const identity = this.identity();
756
782
  if (!identity) return false;
757
783
  const paths = chatDaemonPaths(this.settings.getAgentDir(), this.kind);
@@ -768,6 +794,7 @@ export class ChatDaemonController implements BuiltInDaemonController {
768
794
  agentDir: this.settings.getAgentDir(),
769
795
  execPath: this.deps.execPath,
770
796
  });
797
+ if (!this.effectivelyEnabled() || this.identity() !== identity) return false;
771
798
  (this.deps.spawn ?? ((command, args, opts) => childProcessSpawn(command, args, opts)))(command, args, {
772
799
  detached: true,
773
800
  stdio: "ignore",
@@ -1,4 +1,6 @@
1
1
  import { randomUUID } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
2
4
  import { type IndexedSession, SessionIndex } from "../broker/session-index";
3
5
  import { SdkClient, SdkClientError } from "../client/client";
4
6
  import { readSdkBrokerDiscovery, readSdkSessionEndpoint, type SdkSessionEndpoint } from "../client/discovery";
@@ -275,8 +277,20 @@ export class ChatDaemonRuntime {
275
277
  }
276
278
 
277
279
  private async attach(indexed: IndexedSession): Promise<void> {
278
- const endpoint = await readSdkSessionEndpoint(indexed.locator.repo, indexed.sessionId);
279
- if (!endpoint) return;
280
+ const repo = path.resolve(indexed.locator.repo);
281
+ const defaultStateRoot = path.join(repo, ".gjc", "state");
282
+ const indexedStateRoot = path.resolve(indexed.locator.stateRoot);
283
+ const scope =
284
+ indexedStateRoot === defaultStateRoot
285
+ ? "default"
286
+ : indexedStateRoot === path.join(defaultStateRoot, "chat")
287
+ ? "chat"
288
+ : undefined;
289
+ if (!scope || indexed.endpointMtimeMs === undefined) return;
290
+ const endpoint = await readSdkSessionEndpoint(repo, indexed.sessionId, scope);
291
+ if (!endpoint || endpoint.stale) return;
292
+ const endpointStat = await fs.stat(endpoint.path).catch(() => undefined);
293
+ if (!endpointStat || endpointStat.mtimeMs !== indexed.endpointMtimeMs) return;
280
294
  const existing = this.#sessions.get(indexed.sessionId);
281
295
  if (
282
296
  existing &&