@gajae-code/coding-agent 0.12.10 → 0.12.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,9 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
- ## [0.12.10] - 2026-08-03
5
+ ## [0.12.11] - 2026-08-03
6
+
7
+ ### Fixed
6
8
 
7
- ## [0.12.9] - 2026-08-03
9
+ - Side-effecting native macOS computer input now restores the global cursor after releasing held input on success, cancellation, supervisor rejection, and action failure. Batches containing input execute in one serialized native capture-to-restore transaction, while screenshot/wait-only operations remain cursor-neutral; capture/restore failures are reported distinctly without masking the primary action error, and global focus behavior remains unchanged (#3642, #3781).
10
+ - Managed session rewrites and authority-absent Darwin appends now use native identity-verified atomic replacement instead of deterministically failing with `managed_replace_exact_unavailable` or risking a torn JSONL tail; uncertain readable outcomes are re-fsynced and carried through ctime-bound strict adoption before recovery reports them durable. This unblocks Darwin compaction and session append durability when retained native authority is absent (#3742, #3760).
11
+ - `todo_write` recovery reminders now distinguish rejected payloads from runtime aborts, preserve the available cause, and require durable state reconciliation instead of incorrectly telling the agent to change a valid payload (#3743, #3760).
12
+ - Authority-absent Darwin `appendSync` regression coverage now exercises the replace-based race window (destination mutation during successor staging) instead of the retired in-place `O_APPEND` open path, and documents that ctime-only destination transitions are tolerated by exact replacement.
13
+
14
+ ## [0.12.10] - 2026-08-03
8
15
 
9
16
  ### Added
10
17
 
@@ -30,7 +30,9 @@ export type ChatDaemonAction = "stop" | "reload";
30
30
  * semantics; discord generation 23 / slack generation 22 hardens exact Bash
31
31
  * process-tree ownership shared by chat daemon cleanup.
32
32
  * Discord generation 24 / slack generation 23 apply provider-completeness and
33
- * effective-enable admission to chat daemon lifecycle controls.
33
+ * effective-enable admission to chat daemon lifecycle controls. Discord
34
+ * generation 25 / slack generation 24 apply identity-bound exact replacement
35
+ * cleanup shared by managed-session and daemon filesystem authority.
34
36
  */
35
37
  export declare const CHAT_DAEMON_GENERATIONS: Readonly<Record<ChatDaemonKind, number>>;
36
38
  export declare function chatDaemonGeneration(kind: ChatDaemonKind): number;
@@ -54,9 +54,10 @@ export declare const NOTIFICATION_PROTOCOL_VERSION = 3;
54
54
  * adds durable provider-intent admission without changing owner, reclaim,
55
55
  * signal, or spawn authority.
56
56
  * Generation 42 applies first-class provider-settings admission to Telegram
57
- * lifecycle controls.
57
+ * lifecycle controls. Generation 43 applies identity-bound exact replacement
58
+ * cleanup shared by managed-session and daemon filesystem authority.
58
59
  */
59
- export declare const DAEMON_GENERATION = 42;
60
+ export declare const DAEMON_GENERATION = 43;
60
61
  /**
61
62
  * Serving-compatibility boundary for daemon lifecycle requests. Epoch 1 covers
62
63
  * all builds published before this field existed; epoch 2 covered generation 29;
@@ -1,4 +1,4 @@
1
- import { type NativeDirectoryTreeSnapshot, type NativeOwnerOnlySecurityResult, type RecoveryFsRoot } from "@gajae-code/natives";
1
+ import { type NativeDirectoryTreeSnapshot, type NativeExactUnlinkResult, type NativeOwnerOnlySecurityResult, type RecoveryFsRoot } from "@gajae-code/natives";
2
2
  import { type NativePublishOutcome } from "./native-publish-outcome";
3
3
  export declare const MANAGED_ARTIFACT_MAX_DEPTH = 32;
4
4
  export declare const MANAGED_ARTIFACT_MAX_FILES = 50000;
@@ -10,6 +10,16 @@ export declare class ManagedPublishError extends Error {
10
10
  readonly diagnostic: string;
11
11
  constructor(classification: ManagedPublishError["classification"], outcome: NativePublishOutcome);
12
12
  }
13
+ export declare class ManagedReplaceError extends Error {
14
+ readonly code: string;
15
+ readonly cleanupReceiptPath: string;
16
+ readonly detachedPath: string | undefined;
17
+ readonly retainedSuccessorPath: string | undefined;
18
+ readonly retainedPlaceholderPath: string | undefined;
19
+ readonly retainedUnknownPath: string | undefined;
20
+ readonly replacementCause: unknown;
21
+ constructor(result: NativeExactUnlinkResult, cleanupReceiptPath: string, replacementCause?: unknown);
22
+ }
13
23
  /** Cleanup is safe only when the native move reports that it did not commit. */
14
24
  export declare function mayCleanManagedTreeStaging(error: unknown): boolean;
15
25
  /**
@@ -122,7 +132,7 @@ export declare function captureManagedFilePrefixNoFollow(pathname: string, maxBy
122
132
  export declare function captureManagedFileNoFollow(pathname: string): ManagedFileSnapshot;
123
133
  /** Atomically publishes bytes without replacing an existing destination. */
124
134
  export declare function publishManagedFileNoReplace(destination: string, bytes: Uint8Array, assertOwned?: () => void, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
125
- export declare function publishManagedFileNoReplaceSync(destination: string, bytes: Uint8Array, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): void;
135
+ export declare function publishManagedFileNoReplaceSync(destination: string, bytes: Uint8Array, root?: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): ManagedFileSnapshot["identity"];
126
136
  /** Replace one managed regular file while retaining the secured staging fd through publication. */
127
137
  export declare function replaceManagedFileSync(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy, assertFence?: () => void, expectedDestination?: ManagedFileSnapshot["identity"]): void;
128
138
  export declare function replaceManagedFile(destination: string, bytes: Uint8Array, root: ManagedDirectoryRoot, policy?: ManagedSessionSecurityPolicy): Promise<void>;
@@ -333,6 +333,7 @@ export interface ResumeSessionIdentity {
333
333
  size: number;
334
334
  mtimeMs: number;
335
335
  mtimeNs: bigint;
336
+ ctimeNs?: bigint;
336
337
  sha256: string;
337
338
  }
338
339
  export interface ResumeTailResumable {
@@ -348,6 +349,13 @@ export interface ResumeTailError {
348
349
  reason: "missing" | "malformed" | "unstable" | "read-failed" | "legacy_migration_disabled";
349
350
  }
350
351
  export type SessionDirectoryMigrationPolicy = ManagedMigrationPolicy;
352
+ export type SessionAppendPersistenceFailurePhase = "current_append" | "prior_failure";
353
+ export declare class SessionAppendPersistenceError extends Error {
354
+ readonly phase: SessionAppendPersistenceFailurePhase;
355
+ readonly entryId: string;
356
+ readonly persistenceError: Error;
357
+ constructor(phase: SessionAppendPersistenceFailurePhase, entryId: string, persistenceError: Error);
358
+ }
351
359
  export declare class SessionManagedStorageError extends Error {
352
360
  readonly code = "managed_storage_unsupported";
353
361
  constructor();
@@ -838,6 +846,15 @@ export declare class SessionManager {
838
846
  applyEntryMessageUpdates(entries: readonly SessionMessageEntry[]): void;
839
847
  /** Write mutated custom-message entries back into the canonical entry store by id. */
840
848
  applyCustomMessageEntryUpdates(entries: readonly CustomMessageEntry[]): void;
849
+ /**
850
+ * Rehydrate the canonical transcript after a synchronous persistence failure.
851
+ *
852
+ * The failed append may have committed before reporting an uncertain outcome,
853
+ * so callers must not clear the sticky error or retry against the resident
854
+ * branch. Reloading the exact session file is the only supported recovery
855
+ * boundary for both managed and explicit persistent destinations.
856
+ */
857
+ recoverPersistenceFailure(): Promise<void>;
841
858
  /**
842
859
  * Rewrite the session file after in-place entry updates.
843
860
  * Use sparingly (e.g., pruning old tool outputs).
@@ -7,6 +7,7 @@ export interface SessionStorageStat {
7
7
  size: number;
8
8
  mtimeMs: number;
9
9
  mtimeNs: bigint;
10
+ ctimeNs: bigint;
10
11
  mtime: Date;
11
12
  isFile: boolean;
12
13
  }
@@ -239,7 +239,7 @@ export interface ComputerScreenshotDetails {
239
239
  originX?: number;
240
240
  originY?: number;
241
241
  displayEpoch?: number;
242
- captureId?: string;
242
+ captureId?: number;
243
243
  pngBytes?: number;
244
244
  path?: string;
245
245
  }
@@ -258,11 +258,44 @@ export interface ComputerToolDetails {
258
258
  keys?: string[];
259
259
  ms?: number;
260
260
  screenshot?: ComputerScreenshotDetails;
261
+ primaryError?: {
262
+ code: string;
263
+ message: string;
264
+ };
261
265
  supervisor?: string;
262
266
  steps?: ComputerToolDetails[];
263
267
  meta?: OutputMeta;
264
268
  }
269
+ type NativeBatchAction = {
270
+ action: "screenshot" | "click" | "double_click" | "move" | "drag" | "scroll" | "type" | "keypress" | "wait";
271
+ x?: number;
272
+ y?: number;
273
+ toX?: number;
274
+ toY?: number;
275
+ scrollX?: number;
276
+ scrollY?: number;
277
+ button?: string;
278
+ text?: string;
279
+ keys?: string[];
280
+ ms?: number;
281
+ timeoutMs?: number;
282
+ timeoutGroup?: number;
283
+ };
284
+ type NativeBatchStepResult = {
285
+ index: number;
286
+ action: string;
287
+ screenshot?: NativeScreenshot;
288
+ };
289
+ type NativeBatchResult = {
290
+ results: NativeBatchStepResult[];
291
+ failureCode?: string;
292
+ failureIndex?: number;
293
+ failureMessage?: string;
294
+ primaryFailureCode?: string;
295
+ primaryFailureMessage?: string;
296
+ };
265
297
  type NativeController = {
298
+ executeBatch?: (expectedEpoch: number | undefined, actions: NativeBatchAction[], timeoutMs?: number, signal?: AbortSignal) => Promise<NativeBatchResult> | NativeBatchResult;
266
299
  screenshot?: () => Promise<NativeScreenshot> | NativeScreenshot;
267
300
  click?: (expectedEpoch: number | undefined, x: number, y: number, button?: string) => void;
268
301
  doubleClick?: (expectedEpoch: number | undefined, x: number, y: number, button?: string) => void;
@@ -282,7 +315,7 @@ type NativeScreenshot = {
282
315
  originX?: number;
283
316
  originY?: number;
284
317
  displayEpoch?: number;
285
- captureId?: string;
318
+ captureId?: number;
286
319
  };
287
320
  export type ComputerControllerFactory = () => NativeController;
288
321
  export declare const COMPUTER_DISABLED_CODE = "COMPUTER_DISABLED";
@@ -25,6 +25,7 @@ export interface TodoPhase {
25
25
  export interface TodoWriteToolDetails {
26
26
  phases: TodoPhase[];
27
27
  storage: "session" | "memory";
28
+ failureKind?: "payload_rejected" | "persistence";
28
29
  }
29
30
  declare function validateRawTodoArguments(arguments_: Record<string, unknown>): RawArgumentValidationResult;
30
31
  declare const todoWriteSchema: z.ZodObject<{
@@ -117,6 +118,7 @@ export declare const todoWriteToolRenderer: {
117
118
  text?: string;
118
119
  }>;
119
120
  details?: TodoWriteToolDetails;
121
+ isError?: boolean;
120
122
  }, options: RenderResultOptions, uiTheme: Theme, _args?: TodoWriteRenderArgs): Component;
121
123
  mergeCallAndResult: boolean;
122
124
  };
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.10",
4
+ "version": "0.12.11",
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.10",
57
- "@gajae-code/agent-core": "0.12.10",
58
- "@gajae-code/ai": "0.12.10",
59
- "@gajae-code/bridge-client": "0.12.10",
60
- "@gajae-code/natives": "0.12.10",
61
- "@gajae-code/tui": "0.12.10",
62
- "@gajae-code/utils": "0.12.10",
56
+ "@gajae-code/stats": "0.12.11",
57
+ "@gajae-code/agent-core": "0.12.11",
58
+ "@gajae-code/ai": "0.12.11",
59
+ "@gajae-code/bridge-client": "0.12.11",
60
+ "@gajae-code/natives": "0.12.11",
61
+ "@gajae-code/tui": "0.12.11",
62
+ "@gajae-code/utils": "0.12.11",
63
63
  "@puppeteer/browsers": "^2.13.0",
64
64
  "@types/turndown": "5.0.6",
65
65
  "@xterm/headless": "^6.0.0",