@gajae-code/coding-agent 0.7.0 → 0.7.1

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,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.7.1] - 2026-06-23
6
+ ### Fixed
7
+
8
+ - Fixed packaged source installs (`gajae-code` wrapper) failing `gjc --smoke-test` because native smoke/fallback imports used monorepo-relative paths instead of the `@gajae-code/natives` package export.
9
+ - Fixed Telegram/notification turn ordering around pending asks: the assistant's lead-in text is now emitted before the ask prompt, and only the assistant `message_end` is captured as the pre-ask turn text, so remote prompts show the correct context instead of stale or duplicated output (#1006, #1007).
10
+
5
11
  ## [0.7.0] - 2026-06-22
6
12
 
7
13
  ### Added
@@ -23,6 +29,9 @@
23
29
  - Free-text answers resolve pending asks and ask choices remain unredacted (#998, #1001).
24
30
  - Recover in-flight sessions after a connection drop and connect new sessions during the `getUpdates` long-poll (#988, #990).
25
31
  - Daemon hardening: deliver ask buttons at invocation, fix the topic-reuse race, write daemon logs to file with resilient frame handling, and de-duplicate idle output (#985, #991, and related).
32
+ ### Fixed
33
+
34
+ - Avoided automatically reusing stale GJC-managed tmux sessions from older GJC versions after an upgrade; scoped `gjc --tmux` reuse now only auto-attaches sessions tagged with the current version.
26
35
 
27
36
  ## [0.6.5] - 2026-06-21
28
37
 
@@ -69,6 +69,7 @@ export interface GjcTmuxProfileContext {
69
69
  project?: string | null;
70
70
  sessionId?: string | null;
71
71
  sessionStateFile?: string | null;
72
+ version?: string | null;
72
73
  }
73
74
  export declare function applyGjcTmuxProfile(context: GjcTmuxProfileContext): GjcTmuxProfileResult;
74
75
  export declare function buildGjcTmuxWindowTitle(cwd: string, branch: string | null | undefined): string;
@@ -10,6 +10,7 @@ export declare const GJC_TMUX_BRANCH_SLUG_OPTION = "@gjc-branch-slug";
10
10
  export declare const GJC_TMUX_PROJECT_OPTION = "@gjc-project";
11
11
  export declare const GJC_TMUX_SESSION_ID_OPTION = "@gjc-session-id";
12
12
  export declare const GJC_TMUX_SESSION_STATE_FILE_OPTION = "@gjc-session-state-file";
13
+ export declare const GJC_TMUX_VERSION_OPTION = "@gjc-version";
13
14
  export interface GjcTmuxProfileCommand {
14
15
  description: string;
15
16
  args: string[];
@@ -50,6 +51,7 @@ export declare function buildGjcTmuxRequiredProfileCommands(target: string, meta
50
51
  project?: string | null;
51
52
  sessionId?: string | null;
52
53
  sessionStateFile?: string | null;
54
+ version?: string | null;
53
55
  }): GjcTmuxProfileCommand[];
54
56
  export declare function buildGjcTmuxProfileCommands(target: string, env?: NodeJS.ProcessEnv, metadata?: {
55
57
  branch?: string | null;
@@ -57,5 +59,6 @@ export declare function buildGjcTmuxProfileCommands(target: string, env?: NodeJS
57
59
  project?: string | null;
58
60
  sessionId?: string | null;
59
61
  sessionStateFile?: string | null;
62
+ version?: string | null;
60
63
  }): GjcTmuxProfileCommand[];
61
64
  export declare function normalizeTmuxCreatedAt(raw: string): string;
@@ -10,6 +10,7 @@ export interface GjcTmuxSessionStatus {
10
10
  project?: string;
11
11
  sessionId?: string;
12
12
  sessionStateFile?: string;
13
+ version?: string;
13
14
  panePids: number[];
14
15
  profile?: string;
15
16
  }
@@ -20,6 +21,7 @@ export interface GjcTmuxSessionTagsForGc {
20
21
  branchSlug?: string;
21
22
  sessionId?: string;
22
23
  sessionStateFile?: string;
24
+ version?: string;
23
25
  createdAt?: string;
24
26
  attached?: boolean;
25
27
  panePids?: number[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.7.0",
4
+ "version": "0.7.1",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -51,12 +51,12 @@
51
51
  "@agentclientprotocol/sdk": "0.21.0",
52
52
  "@babel/parser": "^7.29.3",
53
53
  "@mozilla/readability": "^0.6.0",
54
- "@gajae-code/stats": "0.7.0",
55
- "@gajae-code/agent-core": "0.7.0",
56
- "@gajae-code/ai": "0.7.0",
57
- "@gajae-code/natives": "0.7.0",
58
- "@gajae-code/tui": "0.7.0",
59
- "@gajae-code/utils": "0.7.0",
54
+ "@gajae-code/stats": "0.7.1",
55
+ "@gajae-code/agent-core": "0.7.1",
56
+ "@gajae-code/ai": "0.7.1",
57
+ "@gajae-code/natives": "0.7.1",
58
+ "@gajae-code/tui": "0.7.1",
59
+ "@gajae-code/utils": "0.7.1",
60
60
  "@puppeteer/browsers": "^2.13.0",
61
61
  "@types/turndown": "5.0.6",
62
62
  "@xterm/headless": "^6.0.0",
package/src/cli.ts CHANGED
@@ -176,9 +176,7 @@ async function runSmokeTest(): Promise<void> {
176
176
  // the COMPILED single binary (dev runs only load the on-disk .node). Loading the
177
177
  // natives module triggers loadNative()/embedded extraction; calling each new
178
178
  // export confirms the symbols are present in the shipped binary.
179
- const { h06FormatHashLines, h02ScoreSequenceFuzzy, h01FindBestFuzzyMatch } = await import(
180
- "../../natives/native/index.js"
181
- );
179
+ const { h06FormatHashLines, h02ScoreSequenceFuzzy, h01FindBestFuzzyMatch } = await import("@gajae-code/natives");
182
180
  const hashed = h06FormatHashLines("a\nb", 1);
183
181
  if (hashed.split("\n").length !== 2) {
184
182
  throw new Error(`smoke-test: h06FormatHashLines returned unexpected output: ${JSON.stringify(hashed)}`);
@@ -42,7 +42,7 @@ let scoreSequenceFuzzyNative:
42
42
  let findBestFuzzyMatchNative:
43
43
  | ((content: string, target: string, threshold: number) => NativeBestFuzzyMatchResult)
44
44
  | undefined;
45
- void import("../../../../natives/native/index.js")
45
+ void import("@gajae-code/natives")
46
46
  .then(mod => {
47
47
  if (typeof mod.h02ScoreSequenceFuzzy === "function") {
48
48
  scoreSequenceFuzzyNative = mod.h02ScoreSequenceFuzzy;
@@ -1,6 +1,7 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import * as path from "node:path";
3
3
  import { safeStderrWrite } from "@gajae-code/utils";
4
+ import { VERSION } from "@gajae-code/utils/dirs";
4
5
  import type { Args } from "../cli/args";
5
6
  import { tmuxRuntimeSessionPath } from "./session-layout";
6
7
  import { GJC_COORDINATOR_SESSION_ID_ENV, GJC_COORDINATOR_SESSION_STATE_FILE_ENV } from "./session-state-sidecar";
@@ -16,7 +17,7 @@ import {
16
17
  type GjcTmuxProfileCommand,
17
18
  resolveGjcTmuxCommand,
18
19
  } from "./tmux-common";
19
- import { findGjcTmuxSessionByName, findGjcTmuxSessionByScope } from "./tmux-sessions";
20
+ import { findGjcTmuxSessionByName, findGjcTmuxSessionByScope, type GjcTmuxSessionStatus } from "./tmux-sessions";
20
21
 
21
22
  export {
22
23
  buildGjcTmuxProfileCommands,
@@ -88,6 +89,9 @@ export interface TmuxLaunchPlan {
88
89
  function explicitTmuxSessionName(env: NodeJS.ProcessEnv): string | undefined {
89
90
  return env.GJC_TMUX_SESSION?.trim() || undefined;
90
91
  }
92
+ function hasCurrentGjcVersion(session: GjcTmuxSessionStatus | undefined): boolean {
93
+ return session?.version === VERSION;
94
+ }
91
95
 
92
96
  function findExistingSessionForLaunch(context: {
93
97
  env: NodeJS.ProcessEnv;
@@ -96,7 +100,8 @@ function findExistingSessionForLaunch(context: {
96
100
  }): string | undefined {
97
101
  const explicit = explicitTmuxSessionName(context.env);
98
102
  if (explicit) return findGjcTmuxSessionByName(explicit, context.env)?.name;
99
- return findGjcTmuxSessionByScope(context.project, context.branch, context.env)?.name;
103
+ const scoped = findGjcTmuxSessionByScope(context.project, context.branch, context.env);
104
+ return hasCurrentGjcVersion(scoped) ? scoped?.name : undefined;
100
105
  }
101
106
 
102
107
  export interface GjcTmuxProfileResult {
@@ -116,6 +121,7 @@ export interface GjcTmuxProfileContext {
116
121
  project?: string | null;
117
122
  sessionId?: string | null;
118
123
  sessionStateFile?: string | null;
124
+ version?: string | null;
119
125
  }
120
126
 
121
127
  interface CommandResolutionContext {
@@ -195,6 +201,7 @@ export function applyGjcTmuxProfile(context: GjcTmuxProfileContext): GjcTmuxProf
195
201
  project: context.project ?? null,
196
202
  sessionId: context.sessionId ?? env[GJC_COORDINATOR_SESSION_ID_ENV] ?? null,
197
203
  sessionStateFile: context.sessionStateFile ?? env[GJC_COORDINATOR_SESSION_STATE_FILE_ENV] ?? null,
204
+ version: context.version ?? null,
198
205
  });
199
206
  if (commands.length === 0) return { skipped: true, commands: [], failures: [] };
200
207
  const spawnSync = context.spawnSync ?? defaultSpawnSync;
@@ -457,6 +464,7 @@ export function launchDefaultTmuxIfNeeded(context: TmuxLaunchContext): boolean {
457
464
  project: plan.project,
458
465
  sessionId: plan.sessionId ?? null,
459
466
  sessionStateFile: plan.sessionStateFile ?? null,
467
+ version: VERSION,
460
468
  });
461
469
  const ownershipFailure = profile.failures.find(item => item.command.args.includes("@gjc-profile"));
462
470
  if (ownershipFailure) {
@@ -10,6 +10,7 @@ export const GJC_TMUX_BRANCH_SLUG_OPTION = "@gjc-branch-slug";
10
10
  export const GJC_TMUX_PROJECT_OPTION = "@gjc-project";
11
11
  export const GJC_TMUX_SESSION_ID_OPTION = "@gjc-session-id";
12
12
  export const GJC_TMUX_SESSION_STATE_FILE_OPTION = "@gjc-session-state-file";
13
+ export const GJC_TMUX_VERSION_OPTION = "@gjc-version";
13
14
 
14
15
  export interface GjcTmuxProfileCommand {
15
16
  description: string;
@@ -101,6 +102,7 @@ export function buildGjcTmuxRequiredProfileCommands(
101
102
  project?: string | null;
102
103
  sessionId?: string | null;
103
104
  sessionStateFile?: string | null;
105
+ version?: string | null;
104
106
  } = {},
105
107
  ): GjcTmuxProfileCommand[] {
106
108
  const commands: GjcTmuxProfileCommand[] = [
@@ -134,6 +136,11 @@ export function buildGjcTmuxRequiredProfileCommands(
134
136
  description: "record GJC session state marker",
135
137
  args: ["set-option", "-t", target, GJC_TMUX_SESSION_STATE_FILE_OPTION, metadata.sessionStateFile],
136
138
  });
139
+ if (metadata.version)
140
+ commands.push({
141
+ description: "record GJC version identity",
142
+ args: ["set-option", "-t", target, GJC_TMUX_VERSION_OPTION, metadata.version],
143
+ });
137
144
  return commands;
138
145
  }
139
146
 
@@ -146,6 +153,7 @@ export function buildGjcTmuxProfileCommands(
146
153
  project?: string | null;
147
154
  sessionId?: string | null;
148
155
  sessionStateFile?: string | null;
156
+ version?: string | null;
149
157
  } = {},
150
158
  ): GjcTmuxProfileCommand[] {
151
159
  const commands = buildGjcTmuxRequiredProfileCommands(target, metadata);
@@ -10,6 +10,7 @@ import {
10
10
  GJC_TMUX_PROJECT_OPTION,
11
11
  GJC_TMUX_SESSION_ID_OPTION,
12
12
  GJC_TMUX_SESSION_STATE_FILE_OPTION,
13
+ GJC_TMUX_VERSION_OPTION,
13
14
  normalizeTmuxCreatedAt,
14
15
  resolveGjcTmuxCommand,
15
16
  } from "./tmux-common";
@@ -26,6 +27,7 @@ export interface GjcTmuxSessionStatus {
26
27
  project?: string;
27
28
  sessionId?: string;
28
29
  sessionStateFile?: string;
30
+ version?: string;
29
31
  panePids: number[];
30
32
  profile?: string;
31
33
  }
@@ -37,6 +39,7 @@ export interface GjcTmuxSessionTagsForGc {
37
39
  branchSlug?: string;
38
40
  sessionId?: string;
39
41
  sessionStateFile?: string;
42
+ version?: string;
40
43
  createdAt?: string;
41
44
  attached?: boolean;
42
45
  panePids?: number[];
@@ -86,6 +89,7 @@ function parseSessionLine(line: string): GjcTmuxSessionStatus | null {
86
89
  project = "",
87
90
  sessionId = "",
88
91
  sessionStateFile = "",
92
+ version = "",
89
93
  ] = line.split("\t");
90
94
  if (!name) return null;
91
95
  return {
@@ -105,6 +109,7 @@ function parseSessionLine(line: string): GjcTmuxSessionStatus | null {
105
109
  profile: profile || undefined,
106
110
  sessionId: sessionId || undefined,
107
111
  sessionStateFile: sessionStateFile || undefined,
112
+ version: version || undefined,
108
113
  };
109
114
  }
110
115
 
@@ -131,7 +136,7 @@ function runListSessions(format: string, env: NodeJS.ProcessEnv = process.env):
131
136
 
132
137
  function listSessionLines(env: NodeJS.ProcessEnv = process.env): string[] {
133
138
  return runListSessions(
134
- `#{session_name}\t#{session_windows}\t#{session_attached}\t#{session_created}\t#{${GJC_TMUX_PROFILE_OPTION}}\t#{session_key_table}\t#{session_panes}\t#{pane_pid}\t#{${GJC_TMUX_BRANCH_OPTION}}\t#{${GJC_TMUX_BRANCH_SLUG_OPTION}}\t#{${GJC_TMUX_PROJECT_OPTION}}\t#{${GJC_TMUX_SESSION_ID_OPTION}}\t#{${GJC_TMUX_SESSION_STATE_FILE_OPTION}}`,
139
+ `#{session_name}\t#{session_windows}\t#{session_attached}\t#{session_created}\t#{${GJC_TMUX_PROFILE_OPTION}}\t#{session_key_table}\t#{session_panes}\t#{pane_pid}\t#{${GJC_TMUX_BRANCH_OPTION}}\t#{${GJC_TMUX_BRANCH_SLUG_OPTION}}\t#{${GJC_TMUX_PROJECT_OPTION}}\t#{${GJC_TMUX_SESSION_ID_OPTION}}\t#{${GJC_TMUX_SESSION_STATE_FILE_OPTION}}\t#{${GJC_TMUX_VERSION_OPTION}}`,
135
140
  env,
136
141
  );
137
142
  }
@@ -265,6 +270,7 @@ function hydrateSessionFromExactOptions(session: GjcTmuxSessionStatus, env: Node
265
270
  sessionId: session.sessionId ?? readExactOptionForGc(session.name, GJC_TMUX_SESSION_ID_OPTION, env),
266
271
  sessionStateFile:
267
272
  session.sessionStateFile ?? readExactOptionForGc(session.name, GJC_TMUX_SESSION_STATE_FILE_OPTION, env),
273
+ version: session.version ?? readExactOptionForGc(session.name, GJC_TMUX_VERSION_OPTION, env),
268
274
  };
269
275
  }
270
276
 
@@ -281,6 +287,7 @@ export function readTmuxSessionTagsForGc(
281
287
  branchSlug: readExactOptionForGc(sessionName, GJC_TMUX_BRANCH_SLUG_OPTION, env),
282
288
  sessionId: readExactOptionForGc(sessionName, GJC_TMUX_SESSION_ID_OPTION, env),
283
289
  sessionStateFile: readExactOptionForGc(sessionName, GJC_TMUX_SESSION_STATE_FILE_OPTION, env),
290
+ version: readExactOptionForGc(sessionName, GJC_TMUX_VERSION_OPTION, env),
284
291
  createdAt: session?.createdAt,
285
292
  attached: session?.attached,
286
293
  panePids: session?.panePids,
@@ -9,7 +9,7 @@ import bigrams from "./bigrams.json" with { type: "json" };
9
9
  // module evaluation so this core module (and its re-exported helpers) stays
10
10
  // usable and falls back to the TS loop if the native addon is unavailable.
11
11
  let formatHashLinesNative: ((text: string, startLine?: number) => string) | undefined;
12
- void import("../../../natives/native/index.js")
12
+ void import("@gajae-code/natives")
13
13
  .then(mod => {
14
14
  if (typeof mod.h06FormatHashLines === "function") {
15
15
  formatHashLinesNative = mod.h06FormatHashLines;