@gajae-code/coding-agent 0.12.7 → 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 (95) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/types/commands/notify.d.ts +4 -0
  3. package/dist/types/config/file-lock.d.ts +3 -0
  4. package/dist/types/config/model-discovery-manager.d.ts +6 -1
  5. package/dist/types/config/model-registry.d.ts +2 -0
  6. package/dist/types/config/resolve-config-value.d.ts +2 -1
  7. package/dist/types/config/settings-schema.d.ts +17 -1
  8. package/dist/types/main.d.ts +1 -0
  9. package/dist/types/modes/components/hook-selector.d.ts +20 -0
  10. package/dist/types/modes/components/notifications-settings-editor.d.ts +53 -4
  11. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  12. package/dist/types/modes/controllers/selector-controller.d.ts +4 -2
  13. package/dist/types/sdk/broker/broker.d.ts +5 -1
  14. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +1 -0
  15. package/dist/types/sdk/bus/chat-daemon-control.d.ts +11 -1
  16. package/dist/types/sdk/bus/config.d.ts +75 -113
  17. package/dist/types/sdk/bus/discord-live-provider.d.ts +8 -2
  18. package/dist/types/sdk/bus/discord-provider.d.ts +19 -0
  19. package/dist/types/sdk/bus/index.d.ts +1 -1
  20. package/dist/types/sdk/bus/notification-orchestration.d.ts +127 -18
  21. package/dist/types/sdk/bus/notification-service.d.ts +31 -4
  22. package/dist/types/sdk/bus/session-control.d.ts +8 -3
  23. package/dist/types/sdk/bus/slack-live-provider.d.ts +9 -2
  24. package/dist/types/sdk/bus/slack-provider.d.ts +22 -0
  25. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +8 -1
  26. package/dist/types/sdk/client/discovery.d.ts +2 -1
  27. package/dist/types/sdk/host/query/handlers.d.ts +2 -0
  28. package/dist/types/sdk/index.d.ts +1 -0
  29. package/dist/types/sdk/providers.d.ts +22 -0
  30. package/dist/types/sdk/session-directory.d.ts +1 -1
  31. package/dist/types/session/internal/managed-session-scope.d.ts +17 -1
  32. package/dist/types/session/internal/managed-session-storage.d.ts +11 -1
  33. package/dist/types/session/internal/native-publish-outcome.d.ts +1 -0
  34. package/dist/types/session/internal/session-open-errors.d.ts +5 -0
  35. package/dist/types/session/session-manager.d.ts +3 -1
  36. package/dist/types/session/session-storage.d.ts +2 -0
  37. package/package.json +10 -8
  38. package/scripts/build-sdk-package-smoke.ts +51 -0
  39. package/scripts/capture-notifications-settings-showcase.ts +1 -1
  40. package/src/cli/notify-cli.ts +204 -94
  41. package/src/commands/notify.ts +19 -8
  42. package/src/config/file-lock.ts +6 -0
  43. package/src/config/model-discovery-manager.ts +50 -8
  44. package/src/config/model-registry.ts +862 -75
  45. package/src/config/resolve-config-value.ts +10 -8
  46. package/src/config/settings-schema.ts +25 -15
  47. package/src/config/settings.ts +15 -15
  48. package/src/gjc-runtime/session-state-sidecar.ts +12 -2
  49. package/src/internal-urls/docs-index.generated.ts +6 -6
  50. package/src/main.ts +43 -7
  51. package/src/modes/DESIGN.md +11 -11
  52. package/src/modes/components/hook-selector.ts +155 -44
  53. package/src/modes/components/model-selector.ts +242 -49
  54. package/src/modes/components/notifications-settings-editor.ts +631 -85
  55. package/src/modes/controllers/extension-ui-controller.ts +114 -15
  56. package/src/modes/controllers/selector-controller.ts +464 -50
  57. package/src/sdk/broker/broker.ts +54 -10
  58. package/src/sdk/broker/lifecycle-ledger.ts +34 -1
  59. package/src/sdk/broker/lifecycle.ts +47 -50
  60. package/src/sdk/bus/chat-daemon-cli.ts +12 -5
  61. package/src/sdk/bus/chat-daemon-control.ts +35 -6
  62. package/src/sdk/bus/chat-daemon-runtime.ts +16 -2
  63. package/src/sdk/bus/config.ts +534 -286
  64. package/src/sdk/bus/discord-live-provider.ts +57 -2
  65. package/src/sdk/bus/discord-provider.ts +21 -0
  66. package/src/sdk/bus/index.ts +97 -35
  67. package/src/sdk/bus/notification-orchestration.ts +371 -68
  68. package/src/sdk/bus/notification-service.ts +431 -130
  69. package/src/sdk/bus/session-control.ts +119 -44
  70. package/src/sdk/bus/slack-live-provider.ts +78 -2
  71. package/src/sdk/bus/slack-provider.ts +24 -0
  72. package/src/sdk/bus/telegram-daemon-cli.ts +9 -2
  73. package/src/sdk/bus/telegram-daemon-contract.ts +8 -1
  74. package/src/sdk/bus/telegram-daemon-control.ts +3 -3
  75. package/src/sdk/bus/telegram-daemon.ts +23 -15
  76. package/src/sdk/client/discovery.ts +10 -4
  77. package/src/sdk/host/query/handlers.ts +20 -1
  78. package/src/sdk/index.ts +1 -0
  79. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  80. package/src/sdk/protocol/operation-registry.ts +5 -2
  81. package/src/sdk/providers.ts +51 -0
  82. package/src/sdk/session-directory.ts +1 -0
  83. package/src/sdk/session.ts +10 -7
  84. package/src/session/agent-session.ts +44 -24
  85. package/src/session/internal/managed-session-scope.ts +981 -450
  86. package/src/session/internal/managed-session-storage.ts +382 -45
  87. package/src/session/internal/native-publish-outcome.ts +3 -1
  88. package/src/session/internal/session-open-errors.ts +11 -0
  89. package/src/session/session-manager.ts +27 -3
  90. package/src/session/session-storage.ts +72 -5
  91. package/src/slash-commands/builtin-registry.ts +82 -4
  92. package/src/task/index.ts +9 -3
  93. package/src/tools/ask.ts +1 -1
  94. package/src/tools/bash.ts +1 -1
  95. package/src/tools/telegram-send.ts +4 -2
@@ -1,4 +1,4 @@
1
- import { type NotificationConfig } from "./config";
1
+ import { type GenericNotificationSessionSource, type NotificationConfig } from "./config";
2
2
  /** Minimal session-manager surface shared by extension, TUI, and headless hosts. */
3
3
  export interface NotificationSessionContext {
4
4
  sessionManager: {
@@ -29,6 +29,8 @@ export interface NotificationSessionRuntime<Context extends NotificationSessionC
29
29
  * emit a frame. `blocked_identity` is fail-closed and starts nothing.
30
30
  */
31
31
  ensureTelegramDaemon?(binding: BoundNotificationSession<Context>): Promise<TelegramDaemonPreflightResult>;
32
+ /** Rotates a running/default endpoint into Telegram-isolated chat scope. */
33
+ isolateTelegram?(binding: BoundNotificationSession<Context>): Promise<NotificationEndpointStartResult>;
32
34
  /** Refresh mutable delivery policy from the same configuration snapshot used for reconciliation. */
33
35
  refreshPolicy?(binding: BoundNotificationSession<Context>, policy: NotificationRuntimePolicy): void;
34
36
  /** Enables delivery only after the controller has committed a stable policy. */
@@ -37,9 +39,9 @@ export interface NotificationSessionRuntime<Context extends NotificationSessionC
37
39
  export interface NotificationSessionStatus {
38
40
  eligible: boolean;
39
41
  locallyEnabled: boolean;
40
- effectiveEnabled: boolean;
42
+ genericSessionEnabled: boolean;
43
+ genericEligibilitySource: GenericNotificationSessionSource;
41
44
  running: boolean;
42
- environment: "off" | "explicit" | "token" | "default";
43
45
  }
44
46
  export interface NotificationSessionReconcileResult {
45
47
  outcome: NotificationEndpointStartResult | "stopped";
@@ -48,6 +50,7 @@ export interface NotificationSessionReconcileResult {
48
50
  export interface NotificationRuntimePolicy {
49
51
  redact: boolean;
50
52
  verbosity: NotificationConfig["verbosity"];
53
+ /** Generic live-frame delivery policy; never proof of provider effectiveness. */
51
54
  stream: boolean;
52
55
  mode: "provisional" | "committed";
53
56
  }
@@ -58,6 +61,8 @@ export interface NotificationSessionControllerOptions {
58
61
  getConfig(): NotificationConfig;
59
62
  /** Kept as a reference so test and embedding hosts can supply their own environment. */
60
63
  env?: NodeJS.ProcessEnv;
64
+ /** This process was launched by a marked GJC child spawn site. */
65
+ spawnedByGjc?: boolean;
61
66
  }
62
67
  export declare class NotificationSessionController {
63
68
  #private;
@@ -1,4 +1,4 @@
1
- import type { SlackMessageSearchResult, SlackPostedMessage, SlackProviderClient, SlackSocketEnvelope } from "./slack-provider";
1
+ import type { SlackConfigurationProbeResult, SlackDiagnosticProvider, SlackMessageSearchResult, SlackOneShotTestResult, SlackPostedMessage, SlackProviderClient, SlackSocketEnvelope } from "./slack-provider";
2
2
  export type SlackProviderErrorCode = "connection" | "protocol" | "web_api" | "rate_limited";
3
3
  /** A Slack transport failure whose fields are safe to surface without credentials. */
4
4
  export declare class SlackProviderError extends Error {
@@ -38,10 +38,17 @@ export interface SlackLiveProviderOptions {
38
38
  * Production Socket Mode and Web API client. It keeps all connection state in
39
39
  * memory and deliberately never maintains a Slack cursor.
40
40
  */
41
- export declare class SlackLiveProvider implements SlackProviderClient {
41
+ export declare class SlackLiveProvider implements SlackProviderClient, SlackDiagnosticProvider {
42
42
  #private;
43
43
  get transportHealthy(): boolean;
44
44
  constructor(options: SlackLiveProviderOptions);
45
+ probeConfiguration(signal?: AbortSignal): Promise<SlackConfigurationProbeResult>;
46
+ sendOneShotTest(input: {
47
+ channel: string;
48
+ message: string;
49
+ idempotencyKey: string;
50
+ signal?: AbortSignal;
51
+ }): Promise<SlackOneShotTestResult>;
45
52
  start(onEnvelope: (envelope: SlackSocketEnvelope) => void | Promise<void>): Promise<void>;
46
53
  stop(): Promise<void>;
47
54
  ack(envelopeId: string): Promise<void>;
@@ -12,6 +12,28 @@ export interface SlackMessageSearchResult {
12
12
  ts: string;
13
13
  client_msg_id?: string;
14
14
  }
15
+ export interface SlackConfigurationProbeResult {
16
+ ok: boolean;
17
+ detail: string;
18
+ teamId?: string;
19
+ userId?: string;
20
+ }
21
+ export interface SlackOneShotTestResult {
22
+ ok: boolean;
23
+ detail: string;
24
+ channel?: string;
25
+ timestamp?: string;
26
+ uncertain?: boolean;
27
+ }
28
+ export interface SlackDiagnosticProvider {
29
+ probeConfiguration(signal?: AbortSignal): Promise<SlackConfigurationProbeResult>;
30
+ sendOneShotTest(input: {
31
+ channel: string;
32
+ message: string;
33
+ idempotencyKey: string;
34
+ signal?: AbortSignal;
35
+ }): Promise<SlackOneShotTestResult>;
36
+ }
15
37
  /** Minimal Socket Mode + Web API seam. Implementations may wrap the official Slack SDK. */
16
38
  export interface SlackProviderClient {
17
39
  start(onEnvelope: (envelope: SlackSocketEnvelope) => void | Promise<void>): Promise<void>;
@@ -48,8 +48,15 @@ export declare const NOTIFICATION_PROTOCOL_VERSION = 3;
48
48
  * managed-session replacement to exact native filesystem authority; generation
49
49
  * 37 retires that binding (revert of #3489, which stalled POSIX artifact
50
50
  * cleanup); generation 38 binds exact cleanup to parent and link-count authority.
51
+ * Generation 39 applies rustfmt and clippy-equivalent cleanup to the pi-shell
52
+ * process-tree authority (#3682); generation 40 hardens exact Bash process-tree
53
+ * ownership, settlement, and descendant cleanup authority. Generation 38 also
54
+ * adds durable provider-intent admission without changing owner, reclaim,
55
+ * signal, or spawn authority.
56
+ * Generation 41 applies first-class provider-settings admission to Telegram
57
+ * lifecycle controls.
51
58
  */
52
- export declare const DAEMON_GENERATION = 38;
59
+ export declare const DAEMON_GENERATION = 41;
53
60
  /**
54
61
  * Serving-compatibility boundary for daemon lifecycle requests. Epoch 1 covers
55
62
  * all builds published before this field existed; epoch 2 covered generation 29;
@@ -21,9 +21,10 @@ export declare class SdkDiscoveryError extends Error {
21
21
  readonly code = "discovery_error";
22
22
  constructor(path: string, message: string);
23
23
  }
24
+ export type SdkSessionEndpointScope = "default" | "chat";
24
25
  /** Lists endpoint files and returns individual malformed or unreadable records as warnings. */
25
26
  export declare function listSdkSessionEndpoints(repo: string): Promise<SdkSessionEndpointList>;
26
27
  /** Resolves one per-session SDK endpoint discovery file. */
27
- export declare function readSdkSessionEndpoint(repo: string, sessionId: string): Promise<SdkSessionEndpoint | null>;
28
+ export declare function readSdkSessionEndpoint(repo: string, sessionId: string, scope?: SdkSessionEndpointScope): Promise<SdkSessionEndpoint | null>;
28
29
  /** Reads the agent-global broker discovery record. */
29
30
  export declare function readSdkBrokerDiscovery(agentDir: string): Promise<BrokerDiscovery | null>;
@@ -1,3 +1,4 @@
1
+ import type { ActiveProviderDescriptor } from "../../providers.js";
1
2
  import { type CursorRegistry } from "./cursor.js";
2
3
  import type { RevisionStore } from "./revision-store.js";
3
4
  export declare const TARGET_PAGE_BYTES: number;
@@ -11,6 +12,7 @@ export interface SessionSurface {
11
12
  getUsage(): unknown | Promise<unknown>;
12
13
  getModels(): unknown | Promise<unknown>;
13
14
  getSkillState(): unknown | Promise<unknown>;
15
+ getActiveProviders?(): ActiveProviderDescriptor[] | Promise<ActiveProviderDescriptor[]>;
14
16
  /** Q12 rows preserve workflow gate fields and include stable durable gate metadata. */
15
17
  getGates(): unknown | Promise<unknown>;
16
18
  getConfigItems(): unknown | Promise<unknown>;
@@ -5,5 +5,6 @@ export * as host from "./host";
5
5
  export * as mcp from "./mcp";
6
6
  export type { Q10CurrentThinkingLevel, Q10Model, Q10SettableThinkingLevel, Q10ThinkingCapabilities, Q10ThinkingEffort, Q10ThinkingMode, } from "./models";
7
7
  export * from "./prompt-status";
8
+ export type { ActiveProviderConnectionKind, ActiveProviderDescriptor } from "./providers";
8
9
  export * from "./session";
9
10
  export * from "./session-directory";
@@ -0,0 +1,22 @@
1
+ export type ActiveProviderConnectionKind = "credential" | "credentialless";
2
+ export interface ActiveProviderDescriptor {
3
+ provider: string;
4
+ connectionKind: ActiveProviderConnectionKind;
5
+ }
6
+ /**
7
+ * Project active-provider inputs to the exact public DTO shape.
8
+ *
9
+ * Connection credentials take precedence when the same provider is reported
10
+ * more than once. Provider IDs are sorted by their UTF-8 bytes without
11
+ * normalization.
12
+ */
13
+ export declare function projectActiveProviderDescriptors(descriptors: readonly {
14
+ provider: string;
15
+ connectionKind: unknown;
16
+ }[]): ActiveProviderDescriptor[];
17
+ export declare const ACTIVE_PROVIDER_RESOLUTION_ERROR_CODE: "internal";
18
+ export declare const ACTIVE_PROVIDER_RESOLUTION_ERROR_MESSAGE = "Unable to resolve active providers.";
19
+ export declare class ActiveProviderResolutionError extends Error {
20
+ readonly code: "internal";
21
+ constructor();
22
+ }
@@ -20,7 +20,7 @@ export type ResolveManagedSessionScopeResult = {
20
20
  scope: ManagedSessionScope;
21
21
  } | {
22
22
  kind: "error";
23
- code: "cwd_missing" | "cwd_not_directory" | "identity_unavailable" | "network_unsupported" | "sessions_root_unavailable" | "binding_conflict" | "binding_invalid" | "atomic_unavailable" | "durability_not_provable" | "durability_failed" | "invalid_request";
23
+ code: "cwd_missing" | "cwd_not_directory" | "identity_unavailable" | "network_unsupported" | "sessions_root_unavailable" | "binding_conflict" | "binding_invalid" | "migration_busy" | "atomic_unavailable" | "durability_not_provable" | "durability_failed" | "invalid_request";
24
24
  message: string;
25
25
  };
26
26
  export interface LogicalSessionCandidate {
@@ -34,7 +34,7 @@ export declare function managedDirectoryIdentityForScope(scope: ManagedScope): {
34
34
  };
35
35
  export declare function managedRootForScope(scope: ManagedScope): ManagedDirectoryRoot;
36
36
  export type ManagedMigrationPolicy = "copy-retain" | "disabled";
37
- export type ManagedScopeErrorCode = "cwd_missing" | "cwd_not_directory" | "identity_unavailable" | "network_unsupported" | "sessions_root_unavailable" | "binding_conflict" | "binding_invalid" | "atomic_unavailable" | "invalid_request" | "durability_failed" | "durability_not_provable";
37
+ export type ManagedScopeErrorCode = "cwd_missing" | "cwd_not_directory" | "identity_unavailable" | "network_unsupported" | "sessions_root_unavailable" | "binding_conflict" | "binding_invalid" | "migration_busy" | "atomic_unavailable" | "invalid_request" | "durability_failed" | "durability_not_provable";
38
38
  export type ManagedScopeResolution = {
39
39
  kind: "resolved";
40
40
  scope: ManagedScope;
@@ -95,6 +95,19 @@ export type ManagedDeleteCandidateResult = {
95
95
  code: ManagedOpenFailure;
96
96
  message: string;
97
97
  };
98
+ export interface ManagedVerifiedDeleteTestEvent {
99
+ readonly flow: "direct" | "reconcile";
100
+ readonly stage: "initial" | "artifact-finalization" | "transcript-after-artifacts-removed";
101
+ }
102
+ export interface ManagedLockReleaseTestEvent {
103
+ readonly path: string;
104
+ readonly attemptId: string;
105
+ }
106
+ /** Test-only ordering seams for verified deletion and managed-lock release. */
107
+ export declare const ManagedSessionScopeTestHooks: {
108
+ beforeVerifiedDelete?: (event: ManagedVerifiedDeleteTestEvent) => void | Promise<void>;
109
+ beforeManagedLockRelease?: (event: ManagedLockReleaseTestEvent) => void | Promise<void>;
110
+ };
98
111
  declare function scopeDigest(platform: "posix" | "win32", canonicalPath: string): string;
99
112
  export declare const computeManagedScopeDigest: typeof scopeDigest;
100
113
  /**
@@ -121,6 +134,7 @@ export declare function ensureManagedScope(scope: ManagedScope, policy?: Managed
121
134
  /** Synchronously create and validate the v2 binding before a default session writer exists. */
122
135
  export declare function prepareManagedSessionScopeForWriteSync(scope: ManagedScope, policy?: ManagedSessionSecurityPolicy, authority?: ManagedCandidateWriteAuthority): ManagedScopeResolution;
123
136
  export declare function listManagedCandidates(scope: ManagedScope): ManagedCandidateListing;
137
+ export declare function artifactTreeReplayCompatible(observed: NativeDirectoryTreeSnapshot, expected: NativeDirectoryTreeSnapshot): boolean;
124
138
  type DetachedArtifactRoot = {
125
139
  originalPath: string;
126
140
  detachedPath: string;
@@ -129,6 +143,8 @@ type DetachedArtifactRoot = {
129
143
  ino: bigint;
130
144
  size: bigint;
131
145
  mtimeNs: bigint;
146
+ parentDev: bigint;
147
+ parentIno: bigint;
132
148
  };
133
149
  tree: NativeDirectoryTreeSnapshot;
134
150
  };
@@ -25,6 +25,7 @@ export interface ManagedFileSnapshot {
25
25
  identity: {
26
26
  dev: bigint;
27
27
  ino: bigint;
28
+ nlink: bigint;
28
29
  size: number;
29
30
  mtimeNs: bigint;
30
31
  ctimeNs: bigint;
@@ -32,6 +33,14 @@ export interface ManagedFileSnapshot {
32
33
  };
33
34
  }
34
35
  export declare function validateNativeSecurityResult(value: unknown, operation: "apply" | "verify", kind: "directory" | "file"): NativeOwnerOnlySecurityResult;
36
+ export interface ManagedLockRetirementTestEvent {
37
+ readonly path: string;
38
+ readonly attemptId: string;
39
+ }
40
+ /** Test-only seam immediately before exact retirement of one observed lock identity. */
41
+ export declare const ManagedLockTestHooks: {
42
+ beforeObservedRetirement?: (event: ManagedLockRetirementTestEvent) => void;
43
+ };
35
44
  /** Captured configured-root authority for managed paths only. */
36
45
  export interface ManagedDirectoryRoot {
37
46
  readonly canonicalPath: string;
@@ -77,6 +86,7 @@ export declare class ManagedSessionDescendantStore {
77
86
  publishNoReplace(relativePath: string, bytes: Uint8Array): Promise<void>;
78
87
  publishNoReplaceSync(relativePath: string, bytes: Uint8Array): void;
79
88
  replace(relativePath: string, bytes: Uint8Array): Promise<void>;
89
+ replaceExpected(relativePath: string, bytes: Uint8Array, expected: ManagedFileSnapshot): void;
80
90
  replaceSync(relativePath: string, bytes: Uint8Array): void;
81
91
  appendSync(relativePath: string, bytes: Uint8Array): void;
82
92
  /** Read an exact managed file without exposing its pathname as authority. */
@@ -106,7 +116,7 @@ export declare function captureManagedFileNoFollow(pathname: string): ManagedFil
106
116
  export declare function publishManagedFileNoReplace(destination: string, bytes: Uint8Array, assertOwned?: () => void, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
107
117
  export declare function publishManagedFileNoReplaceSync(destination: string, bytes: Uint8Array, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
108
118
  /** Replace one managed regular file while retaining the secured staging fd through publication. */
109
- export declare function replaceManagedFileSync(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
119
+ export declare function replaceManagedFileSync(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy, assertFence?: () => void, expectedDestination?: ManagedFileSnapshot["identity"]): void;
110
120
  export declare function replaceManagedFile(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
111
121
  /** Copy the exact bytes captured from one no-follow source descriptor. */
112
122
  export declare function copyManagedFileNoReplace(source: string, destination: string, snapshot?: ManagedFileSnapshot, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
@@ -20,6 +20,7 @@ export type NativePublishIdentity = {
20
20
  readonly dev: string;
21
21
  readonly ino: string;
22
22
  readonly size: string;
23
+ readonly nlink?: string;
23
24
  readonly mtimeNs: string;
24
25
  readonly ctimeNs: string;
25
26
  readonly sha256?: string;
@@ -0,0 +1,5 @@
1
+ export declare const SESSION_MIGRATION_BUSY_MESSAGE = "Another session migration is still active. Wait for it to finish, then retry.";
2
+ export declare class SessionMigrationBusyError extends Error {
3
+ readonly code = "migration_busy";
4
+ constructor();
5
+ }
@@ -357,6 +357,7 @@ export declare class SessionMigrationPolicyError extends Error {
357
357
  constructor();
358
358
  }
359
359
  export declare class SessionArtifactCapacityError extends Error {
360
+ readonly code = "artifact_capacity_exceeded";
360
361
  constructor(message: string);
361
362
  }
362
363
  export type ResumeTailInspection = ResumeTailResumable | ResumeTailTerminal | ResumeTailError;
@@ -366,7 +367,7 @@ export interface StrictSessionOpenSuccess {
366
367
  }
367
368
  export interface StrictSessionOpenFailure {
368
369
  kind: "error";
369
- reason: ResumeTailError["reason"] | "identity-mismatch" | "migration-required" | "artifact_capacity_exceeded";
370
+ reason: ResumeTailError["reason"] | "identity-mismatch" | "migration-required" | "artifact_capacity_exceeded" | "migration_busy";
370
371
  message?: string;
371
372
  }
372
373
  /** Exact transcript bytes and authority captured from one descriptor-bound read. */
@@ -613,6 +614,7 @@ export declare const MATERIALIZED_CACHE_MAX_BYTES: number;
613
614
  export declare const SessionManagerTestHooks: {
614
615
  materializedCacheMaxBytesOverride?: number;
615
616
  beforeResidentTransitionIndexBuild?: () => void;
617
+ afterForkSnapshot?: () => void | Promise<void>;
616
618
  };
617
619
  export declare class SessionManager {
618
620
  #private;
@@ -239,6 +239,7 @@ export type VerifiedSessionDeleteResult = {
239
239
  artifactsIdentity: SessionStorageFileIdentity | undefined;
240
240
  /** Identity-bound quarantine path retained when recursive cleanup failed. */
241
241
  detachedArtifactsPath: string;
242
+ artifactsPayloadDurable?: true;
242
243
  /** Native snapshot required for an identity-bound recursive retry. */
243
244
  artifactsTree: NativeDirectoryTreeSnapshot;
244
245
  /** Transcript identity (unchanged) for retry binding. */
@@ -254,6 +255,7 @@ export type VerifiedSessionDeleteResult = {
254
255
  transcriptIdentity: SessionStorageFileIdentity;
255
256
  /** Optional identity-bound transcript quarantine path for restart cleanup. */
256
257
  detachedTranscriptPath?: string;
258
+ transcriptPayloadDurable?: true;
257
259
  retainedSuccessorPath?: string;
258
260
  retainedPlaceholderPath?: string;
259
261
  retainedUnknownPath?: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.12.7",
4
+ "version": "0.12.8",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gajae-code.com",
7
7
  "author": "Yeachan-Heo and Gajae Code Contributors",
@@ -53,13 +53,13 @@
53
53
  "@agentclientprotocol/sdk": "1.3.0",
54
54
  "@babel/parser": "^7.29.3",
55
55
  "@mozilla/readability": "^0.6.0",
56
- "@gajae-code/stats": "0.12.7",
57
- "@gajae-code/agent-core": "0.12.7",
58
- "@gajae-code/ai": "0.12.7",
59
- "@gajae-code/bridge-client": "0.12.7",
60
- "@gajae-code/natives": "0.12.7",
61
- "@gajae-code/tui": "0.12.7",
62
- "@gajae-code/utils": "0.12.7",
56
+ "@gajae-code/stats": "0.12.8",
57
+ "@gajae-code/agent-core": "0.12.8",
58
+ "@gajae-code/ai": "0.12.8",
59
+ "@gajae-code/bridge-client": "0.12.8",
60
+ "@gajae-code/natives": "0.12.8",
61
+ "@gajae-code/tui": "0.12.8",
62
+ "@gajae-code/utils": "0.12.8",
63
63
  "@puppeteer/browsers": "^2.13.0",
64
64
  "@types/turndown": "5.0.6",
65
65
  "@xterm/headless": "^6.0.0",
@@ -132,6 +132,8 @@
132
132
  },
133
133
  "./sdk/models": null,
134
134
  "./sdk/models.js": null,
135
+ "./sdk/providers": null,
136
+ "./sdk/providers.js": null,
135
137
  "./sdk/lifecycle-session": null,
136
138
  "./sdk/lifecycle-session.js": null,
137
139
  "./sdk/startup-capability": null,
@@ -9,6 +9,7 @@ const packageName = "@gajae-code/coding-agent";
9
9
  const aiPackageDir = path.resolve(packageDir, "../ai");
10
10
  const bridgeClientPackageDir = path.resolve(packageDir, "../bridge-client");
11
11
  const tuiPackageDir = path.resolve(packageDir, "../tui");
12
+ const agentPackageDir = path.resolve(packageDir, "../agent");
12
13
  const nativesPackageDir = path.resolve(packageDir, "../natives");
13
14
  const linuxX64PackageDir = path.resolve(packageDir, "../natives-linux-x64");
14
15
  const manifestsDir = path.join(packageDir, "test/manifests");
@@ -41,6 +42,7 @@ async function runSmoke(): Promise<Surface> {
41
42
  await fs.copyFile(path.join(nativesPackageDir, "native", entry), path.join(stagedNativeDir, entry));
42
43
  }
43
44
  }
45
+ const agentTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], agentPackageDir);
44
46
  const aiTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], aiPackageDir);
45
47
  const bridgeClientTarball = run(
46
48
  ["bun", "pm", "pack", "--destination", tempDir, "--quiet"],
@@ -49,6 +51,7 @@ async function runSmoke(): Promise<Surface> {
49
51
  const tuiTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], tuiPackageDir);
50
52
  const nativesTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], nativesPackageDir);
51
53
  const linuxX64Tarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], stagedLinuxX64Dir);
54
+ const agentTarballPath = path.isAbsolute(agentTarball) ? agentTarball : path.join(agentPackageDir, agentTarball);
52
55
  const codingAgentTarball = run(["bun", "pm", "pack", "--destination", tempDir, "--quiet"], packageDir);
53
56
  const aiTarballPath = path.isAbsolute(aiTarball) ? aiTarball : path.join(aiPackageDir, aiTarball);
54
57
  const bridgeClientTarballPath = path.isAbsolute(bridgeClientTarball)
@@ -71,6 +74,7 @@ async function runSmoke(): Promise<Surface> {
71
74
  name: "sdk-smoke",
72
75
  private: true,
73
76
  dependencies: {
77
+ "@gajae-code/agent-core": `file:${agentTarballPath}`,
74
78
  "@gajae-code/ai": `file:${aiTarballPath}`,
75
79
  "@gajae-code/bridge-client": `file:${bridgeClientTarballPath}`,
76
80
  [packageName]: `file:${codingAgentTarballPath}`,
@@ -79,6 +83,7 @@ async function runSmoke(): Promise<Surface> {
79
83
  "@gajae-code/natives-linux-x64": `file:${linuxX64TarballPath}`,
80
84
  },
81
85
  overrides: {
86
+ "@gajae-code/agent-core": `file:${agentTarballPath}`,
82
87
  "@gajae-code/ai": `file:${aiTarballPath}`,
83
88
  "@gajae-code/bridge-client": `file:${bridgeClientTarballPath}`,
84
89
  "@gajae-code/tui": `file:${tuiTarballPath}`,
@@ -96,6 +101,52 @@ async function runSmoke(): Promise<Surface> {
96
101
  const installedPackage = JSON.parse(
97
102
  await fs.readFile(path.join(tempDir, "node_modules", packageName, "package.json"), "utf8"),
98
103
  ) as { exports?: Record<string, unknown> };
104
+ const installedAgentPackagePath = path.join(tempDir, "node_modules", "@gajae-code", "agent-core");
105
+ const installedAgentPackageJsonPath = path.join(installedAgentPackagePath, "package.json");
106
+ const installedAgentPackage = JSON.parse(await fs.readFile(installedAgentPackageJsonPath, "utf8")) as {
107
+ name?: string;
108
+ version?: string;
109
+ };
110
+ const expectedAgentPackage = JSON.parse(
111
+ await fs.readFile(path.join(agentPackageDir, "package.json"), "utf8"),
112
+ ) as {
113
+ name?: string;
114
+ version?: string;
115
+ };
116
+ const installedAgentRealpath = await fs.realpath(installedAgentPackagePath);
117
+ const tempRealpath = await fs.realpath(tempDir);
118
+ const sourceAgentRealpath = await fs.realpath(agentPackageDir);
119
+ if (
120
+ !installedAgentRealpath.startsWith(`${tempRealpath}${path.sep}`) ||
121
+ installedAgentRealpath.startsWith(`${sourceAgentRealpath}${path.sep}`)
122
+ ) {
123
+ throw new Error("packed smoke resolved agent-core outside the temporary packed installation");
124
+ }
125
+ const packedAgentInspectDir = path.join(tempDir, "packed-agent-inspect");
126
+ await fs.mkdir(packedAgentInspectDir);
127
+ const extract = Bun.spawnSync(["tar", "xzf", agentTarballPath, "-C", packedAgentInspectDir], {
128
+ stdout: "pipe",
129
+ stderr: "pipe",
130
+ });
131
+ if (extract.exitCode !== 0)
132
+ throw new Error(`could not inspect packed agent-core tarball: ${extract.stderr.toString()}`);
133
+ const packedAgentPackageJson = await fs.readFile(
134
+ path.join(packedAgentInspectDir, "package", "package.json"),
135
+ "utf8",
136
+ );
137
+ const installedAgentPackageJson = await fs.readFile(installedAgentPackageJsonPath, "utf8");
138
+ if (installedAgentPackageJson !== packedAgentPackageJson) {
139
+ throw new Error("packed smoke installed agent-core content different from the packed tarball");
140
+ }
141
+ if (
142
+ installedAgentPackage.name !== expectedAgentPackage.name ||
143
+ installedAgentPackage.version !== expectedAgentPackage.version
144
+ ) {
145
+ throw new Error("packed smoke installed a mismatched agent-core package");
146
+ }
147
+ if (installedAgentPackage.name !== "@gajae-code/agent-core") {
148
+ throw new Error("packed smoke agent-core package identity is invalid");
149
+ }
99
150
  if (installedPackage.exports?.["./session/internal/*"] !== null) {
100
151
  throw new Error("packed package must explicitly block ./session/internal/*");
101
152
  }
@@ -11,7 +11,7 @@ import {
11
11
  } from "../test/fixtures/tui/notifications-settings-showcase";
12
12
 
13
13
  const CANONICAL_COMMAND =
14
- "bun packages/coding-agent/scripts/capture-notifications-settings-showcase.ts --output .gjc/qa/issue-2050-notifications";
14
+ "bun packages/coding-agent/scripts/capture-notifications-settings-showcase.ts --output .gjc/qa/issue-3570-notifications";
15
15
  const DETERMINISTIC_CAPTURE_TIMESTAMP = "1970-01-01T00:00:00.000Z";
16
16
  const CAPTURE_TOOL_VERSION = "notifications-settings-showcase-live-settings-selector-v3";
17
17