@love-moon/ai-sdk 0.13.3 → 0.14.0

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 (33) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/client.d.ts +5 -0
  3. package/dist/client.js +22 -0
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +1 -0
  6. package/dist/providers/chat-web-session.d.ts +18 -0
  7. package/dist/providers/chat-web-session.js +44 -1
  8. package/dist/providers/claude-agent-sdk-session.d.ts +34 -0
  9. package/dist/providers/claude-agent-sdk-session.js +33 -0
  10. package/dist/providers/codex-app-server-session.d.ts +76 -6
  11. package/dist/providers/codex-app-server-session.js +113 -14
  12. package/dist/providers/codex-exec-session.d.ts +14 -0
  13. package/dist/providers/codex-exec-session.js +20 -1
  14. package/dist/providers/copilot-sdk-session.d.ts +21 -0
  15. package/dist/providers/copilot-sdk-session.js +55 -12
  16. package/dist/providers/dsh-sdk-session.d.ts +53 -3
  17. package/dist/providers/dsh-sdk-session.js +24 -1
  18. package/dist/providers/kimi-cli-session.d.ts +22 -0
  19. package/dist/providers/kimi-cli-session.js +23 -1
  20. package/dist/providers/kimi-print-session.d.ts +13 -0
  21. package/dist/providers/kimi-print-session.js +29 -0
  22. package/dist/providers/kimi-slash-commands.d.ts +1 -0
  23. package/dist/providers/kimi-slash-commands.js +23 -0
  24. package/dist/providers/opencode-sdk-session.d.ts +52 -3
  25. package/dist/providers/opencode-sdk-session.js +33 -1
  26. package/dist/shared.d.ts +46 -0
  27. package/dist/shared.js +18 -1
  28. package/dist/transports/kimi-wire-transport.d.ts +12 -0
  29. package/dist/transports/kimi-wire-transport.js +40 -1
  30. package/dist/turn-usage.d.ts +31 -0
  31. package/dist/turn-usage.js +44 -0
  32. package/dist/worker.js +1 -1
  33. package/package.json +3 -3
@@ -6,6 +6,7 @@ import { EventEmitter } from "node:events";
6
6
  import readline from "node:readline";
7
7
  import { KIMI_CLI_PRINT_VARIANT as KIMI_PRINT_PROVIDER_VARIANT } from "../built-in-backends.js";
8
8
  import { appendContextFilesToPrompt } from "../context-files.js";
9
+ import { assertKimiClearReply } from "./kimi-slash-commands.js";
9
10
  import { PROVIDER_MEDIA_CAPABILITIES, UNSUPPORTED_MEDIA_CAPABILITIES, buildKimiContent, } from "../media-adapters.js";
10
11
  import { assertMediaCapabilities, defaultPromptForMedia, resolveTurnMedia, } from "../media-input.js";
11
12
  import { emitLog, getBoundedEnvInt, loadEnvConfig, normalizeLogger, noteToolFinished, noteToolStarted, parseCommandParts, proxyToEnv, sanitizeForLog, withActiveTool, } from "../shared.js";
@@ -272,6 +273,7 @@ export class KimiPrintSession extends EventEmitter {
272
273
  capabilities: {
273
274
  // Kimi Code's `--prompt` CLI is unverified for slash commands.
274
275
  compact: this.cliMode !== "prompt",
276
+ clear: this.cliMode !== "prompt",
275
277
  media: this.cliMode === "prompt"
276
278
  ? UNSUPPORTED_MEDIA_CAPABILITIES
277
279
  : PROVIDER_MEDIA_CAPABILITIES[KIMI_PRINT_PROVIDER_VARIANT],
@@ -505,6 +507,33 @@ export class KimiPrintSession extends EventEmitter {
505
507
  metadata: turnResult.metadata,
506
508
  };
507
509
  }
510
+ /**
511
+ * Native `/clear`: kimi-cli's built-in slash command, answered locally without
512
+ * a model call. Print mode spawns a child per turn, so nothing is torn down;
513
+ * the `--session` id stays the same and only its context file rotates.
514
+ *
515
+ * @param {Record<string, unknown>} [request]
516
+ * @param {{ onProgress?: Function }} [options]
517
+ * @returns {Promise<import("../shared.js").ClearResult>}
518
+ */
519
+ async runClear(request = {}, { onProgress = null } = {}) {
520
+ if (this.cliMode === "prompt") {
521
+ throw createTurnError("Kimi prompt mode does not support /clear", { reason: "unsupported_clear" });
522
+ }
523
+ if (this.pendingHistorySeed) {
524
+ return { clear: { status: "noop" }, usage: null, metadata: {} };
525
+ }
526
+ const turnResult = await this.runTurn("/clear", { onProgress, suppressReply: true });
527
+ // Print mode exits 0 even when the model call fails, so only kimi-cli's
528
+ // fixed reply is trusted.
529
+ assertKimiClearReply(turnResult.text);
530
+ this.history = [];
531
+ return {
532
+ clear: { status: "cleared", sessionId: this.sessionId || undefined },
533
+ usage: turnResult.usage,
534
+ metadata: turnResult.metadata,
535
+ };
536
+ }
508
537
  async runTurn(promptText, { useInitialImages = false, media: mediaInput, contextFiles, onProgress = null, jsonSchema = null, suppressReply = false } = {}) {
509
538
  if (this.closeRequested || this.closed) {
510
539
  throw this.createSessionClosedError();
@@ -0,0 +1 @@
1
+ export function assertKimiClearReply(reply: any): void;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * kimi-cli answers `/clear` itself, without calling the model, with a fixed
3
+ * line (see kimi_cli/soul/slash.py). Both kimi modes verify that line before
4
+ * reporting success: if a kimi version ever stops treating `/clear` as a
5
+ * built-in, the text reaches the model as an ordinary turn — which grows the
6
+ * context instead of clearing it — and we must fail loudly rather than tell the
7
+ * user their context is gone.
8
+ *
9
+ * Kept in one place so the two modes cannot drift apart, in either direction.
10
+ */
11
+ const KIMI_CLEAR_ACK = /context has been cleared/i;
12
+ function createClearFailedError(message) {
13
+ const error = new Error(message);
14
+ error.reason = "clear_failed";
15
+ return error;
16
+ }
17
+ export function assertKimiClearReply(reply) {
18
+ const text = String(reply || "");
19
+ if (KIMI_CLEAR_ACK.test(text)) {
20
+ return;
21
+ }
22
+ throw createClearFailedError(`Kimi clear failed${text.trim() ? `: ${text.trim()}` : ""}`);
23
+ }
@@ -80,6 +80,7 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
80
80
  currentTurnStatus: any;
81
81
  capabilities: {
82
82
  compact: boolean;
83
+ clear: boolean;
83
84
  media: Readonly<{
84
85
  image: "native";
85
86
  }>;
@@ -208,9 +209,57 @@ export class OpencodeSdkSession extends EventEmitter<[never]> {
208
209
  * @param {{ onProgress?: Function }} [options]
209
210
  * @returns {Promise<import("../shared.js").CompactResult>}
210
211
  */
211
- runCompact(request?: import("../shared.js").CompactRequest, { onProgress }?: {
212
- onProgress?: Function;
213
- }): Promise<import("../shared.js").CompactResult>;
212
+ /**
213
+ * Native clear: create a new session on the SAME opencode server (the server
214
+ * process and its event stream stay up); the old session is left untouched on
215
+ * disk, exactly like the boot path's `session.create`.
216
+ */
217
+ runClear(): Promise<{
218
+ clear: {
219
+ status: string;
220
+ sessionId?: undefined;
221
+ };
222
+ usage: null;
223
+ metadata: {};
224
+ } | {
225
+ clear: {
226
+ status: string;
227
+ sessionId: any;
228
+ };
229
+ usage: null;
230
+ metadata: {};
231
+ }>;
232
+ runCompact(request?: {}, { onProgress }?: {
233
+ onProgress?: null | undefined;
234
+ }): Promise<{
235
+ compact: {
236
+ status: string;
237
+ instructionsApplied: boolean;
238
+ };
239
+ usage: null;
240
+ metadata: {};
241
+ } | {
242
+ compact: {
243
+ status: string;
244
+ instructionsApplied: boolean;
245
+ };
246
+ usage: {
247
+ total: number | undefined;
248
+ input: number | undefined;
249
+ output: number | undefined;
250
+ reasoning: number | undefined;
251
+ cache: {
252
+ read: number | undefined;
253
+ write: number | undefined;
254
+ };
255
+ } | null;
256
+ metadata: {
257
+ providerID: any;
258
+ modelID: any;
259
+ source: string;
260
+ sessionId: any;
261
+ };
262
+ }>;
214
263
  runTurn(promptText: any, { useInitialImages, media: mediaInput, contextFiles, onProgress, jsonSchema }?: {
215
264
  useInitialImages?: boolean | undefined;
216
265
  onProgress?: null | undefined;
@@ -231,7 +231,7 @@ export class OpencodeSdkSession extends EventEmitter {
231
231
  resumeReady: Boolean(this.sessionId),
232
232
  manualResume: null,
233
233
  currentTurnStatus: this.getCurrentTurnStatus(),
234
- capabilities: { compact: true, media: PROVIDER_MEDIA_CAPABILITIES[OPENCODE_PROVIDER_VARIANT] },
234
+ capabilities: { compact: true, clear: true, media: PROVIDER_MEDIA_CAPABILITIES[OPENCODE_PROVIDER_VARIANT] },
235
235
  pid: this.transport.pid || undefined,
236
236
  };
237
237
  }
@@ -1227,6 +1227,38 @@ export class OpencodeSdkSession extends EventEmitter {
1227
1227
  * @param {{ onProgress?: Function }} [options]
1228
1228
  * @returns {Promise<import("../shared.js").CompactResult>}
1229
1229
  */
1230
+ /**
1231
+ * Native clear: create a new session on the SAME opencode server (the server
1232
+ * process and its event stream stay up); the old session is left untouched on
1233
+ * disk, exactly like the boot path's `session.create`.
1234
+ */
1235
+ async runClear() {
1236
+ if (this.closeRequested) {
1237
+ throw this.createSessionClosedError();
1238
+ }
1239
+ if (this.currentTurn) {
1240
+ throw createTurnError("Opencode turn already running", {
1241
+ reason: "turn_already_running",
1242
+ });
1243
+ }
1244
+ if (this.pendingHistorySeed || (!this.resumeSessionId && !this.sessionId && this.history.length === 0)) {
1245
+ return { clear: { status: "noop" }, usage: null, metadata: {} };
1246
+ }
1247
+ await this.boot();
1248
+ if (typeof this.client?.session?.create !== "function") {
1249
+ throw new Error("Opencode session create API is unavailable");
1250
+ }
1251
+ const session = await this.requestOrThrow(this.client.session.create({}, { throwOnError: true, responseStyle: "data" }));
1252
+ this.applySessionInfo(session);
1253
+ // A later re-boot must not reattach to the session we walked away from.
1254
+ this.resumeSessionId = "";
1255
+ this.history = [];
1256
+ return {
1257
+ clear: { status: "cleared", sessionId: this.sessionId || undefined },
1258
+ usage: null,
1259
+ metadata: {},
1260
+ };
1261
+ }
1230
1262
  async runCompact(request = {}, { onProgress = null } = {}) {
1231
1263
  if (this.closeRequested) {
1232
1264
  throw this.createSessionClosedError();
package/dist/shared.d.ts CHANGED
@@ -100,6 +100,7 @@ export const TERMINAL_GOAL_STATUSES: ReadonlyArray<GoalStatus>;
100
100
  * @typedef {Object} SessionCapabilities
101
101
  * @property {boolean} [goal]
102
102
  * @property {boolean} [compact]
103
+ * @property {boolean} [clear]
103
104
  */
104
105
  /**
105
106
  * Manual context compaction (`/compact`) contract for providers that
@@ -124,6 +125,22 @@ export const TERMINAL_GOAL_STATUSES: ReadonlyArray<GoalStatus>;
124
125
  * @property {unknown} [usage]
125
126
  * @property {Record<string, unknown>} [metadata]
126
127
  */
128
+ /**
129
+ * Native context clear (`/clear`) contract for providers that implement the
130
+ * optional `runClear` method and advertise `capabilities.clear === true`.
131
+ * Providers must NOT emit assistant messages while clearing; the caller
132
+ * renders the user-facing confirmation.
133
+ *
134
+ * @typedef {Object} ClearState
135
+ * @property {"cleared"|"noop"} status `noop` = there was nothing to clear.
136
+ * @property {string} [sessionId] New session id when the backend starts a new
137
+ * conversation; callers rebind the task to it.
138
+ *
139
+ * @typedef {Object} ClearResult
140
+ * @property {ClearState} clear
141
+ * @property {unknown} [usage]
142
+ * @property {Record<string, unknown>} [metadata]
143
+ */
127
144
  /**
128
145
  * Default capabilities assigned to providers that do not opt into any optional
129
146
  * feature. Treat the returned object as read-only; clone before mutating.
@@ -212,6 +229,7 @@ export type GoalResult = {
212
229
  export type SessionCapabilities = {
213
230
  goal?: boolean | undefined;
214
231
  compact?: boolean | undefined;
232
+ clear?: boolean | undefined;
215
233
  };
216
234
  /**
217
235
  * Manual context compaction (`/compact`) contract for providers that
@@ -254,3 +272,31 @@ export type CompactResult = {
254
272
  usage?: unknown;
255
273
  metadata?: Record<string, unknown> | undefined;
256
274
  };
275
+ /**
276
+ * Native context clear (`/clear`) contract for providers that implement the
277
+ * optional `runClear` method and advertise `capabilities.clear === true`.
278
+ * Providers must NOT emit assistant messages while clearing; the caller
279
+ * renders the user-facing confirmation.
280
+ */
281
+ export type ClearState = {
282
+ /**
283
+ * `noop` = there was nothing to clear.
284
+ */
285
+ status: "cleared" | "noop";
286
+ /**
287
+ * New session id when the backend starts a new
288
+ * conversation; callers rebind the task to it.
289
+ */
290
+ sessionId?: string | undefined;
291
+ };
292
+ /**
293
+ * Native context clear (`/clear`) contract for providers that implement the
294
+ * optional `runClear` method and advertise `capabilities.clear === true`.
295
+ * Providers must NOT emit assistant messages while clearing; the caller
296
+ * renders the user-facing confirmation.
297
+ */
298
+ export type ClearResult = {
299
+ clear: ClearState;
300
+ usage?: unknown;
301
+ metadata?: Record<string, unknown> | undefined;
302
+ };
package/dist/shared.js CHANGED
@@ -81,6 +81,7 @@ export function isTerminalGoalStatus(value) {
81
81
  * @typedef {Object} SessionCapabilities
82
82
  * @property {boolean} [goal]
83
83
  * @property {boolean} [compact]
84
+ * @property {boolean} [clear]
84
85
  */
85
86
  /**
86
87
  * Manual context compaction (`/compact`) contract for providers that
@@ -105,13 +106,29 @@ export function isTerminalGoalStatus(value) {
105
106
  * @property {unknown} [usage]
106
107
  * @property {Record<string, unknown>} [metadata]
107
108
  */
109
+ /**
110
+ * Native context clear (`/clear`) contract for providers that implement the
111
+ * optional `runClear` method and advertise `capabilities.clear === true`.
112
+ * Providers must NOT emit assistant messages while clearing; the caller
113
+ * renders the user-facing confirmation.
114
+ *
115
+ * @typedef {Object} ClearState
116
+ * @property {"cleared"|"noop"} status `noop` = there was nothing to clear.
117
+ * @property {string} [sessionId] New session id when the backend starts a new
118
+ * conversation; callers rebind the task to it.
119
+ *
120
+ * @typedef {Object} ClearResult
121
+ * @property {ClearState} clear
122
+ * @property {unknown} [usage]
123
+ * @property {Record<string, unknown>} [metadata]
124
+ */
108
125
  /**
109
126
  * Default capabilities assigned to providers that do not opt into any optional
110
127
  * feature. Treat the returned object as read-only; clone before mutating.
111
128
  *
112
129
  * @type {Readonly<SessionCapabilities>}
113
130
  */
114
- export const DEFAULT_SESSION_CAPABILITIES = Object.freeze({ goal: false, compact: false });
131
+ export const DEFAULT_SESSION_CAPABILITIES = Object.freeze({ goal: false, compact: false, clear: false });
115
132
  /**
116
133
  * Resolve a session's capability snapshot, falling back to
117
134
  * {@link DEFAULT_SESSION_CAPABILITIES}.
@@ -1,3 +1,15 @@
1
+ /**
2
+ * Drop resume flags from the configured command line. The session id is owned
3
+ * by the caller (we always append our own `--session=`), so a configured
4
+ * `--continue`/`--session`/`--resume` would silently reattach a fresh session —
5
+ * e.g. a `/clear` — to the previous conversation.
6
+ *
7
+ * Only those flags are touched. Notably `-c` is kimi's alias for
8
+ * `--prompt`/`--command` (it takes a value), not a continue switch, so it is
9
+ * passed through untouched — dropping the flag alone would leave its value
10
+ * behind as a stray positional argument.
11
+ */
12
+ export function filterKimiWireBaseArgs(args: any): string[];
1
13
  export class KimiWireTransport extends EventEmitter<[never]> {
2
14
  constructor(options?: {});
3
15
  options: {};
@@ -37,6 +37,45 @@ function quoteShellArg(value) {
37
37
  }
38
38
  return `'${normalized.replace(/'/g, `'\\''`)}'`;
39
39
  }
40
+ /**
41
+ * Drop resume flags from the configured command line. The session id is owned
42
+ * by the caller (we always append our own `--session=`), so a configured
43
+ * `--continue`/`--session`/`--resume` would silently reattach a fresh session —
44
+ * e.g. a `/clear` — to the previous conversation.
45
+ *
46
+ * Only those flags are touched. Notably `-c` is kimi's alias for
47
+ * `--prompt`/`--command` (it takes a value), not a continue switch, so it is
48
+ * passed through untouched — dropping the flag alone would leave its value
49
+ * behind as a stray positional argument.
50
+ */
51
+ export function filterKimiWireBaseArgs(args) {
52
+ const filtered = [];
53
+ let skipNext = false;
54
+ for (const rawArg of Array.isArray(args) ? args : []) {
55
+ const arg = String(rawArg || "");
56
+ if (!arg) {
57
+ continue;
58
+ }
59
+ if (skipNext) {
60
+ skipNext = false;
61
+ continue;
62
+ }
63
+ if (arg === "--continue" || arg === "-C") {
64
+ continue;
65
+ }
66
+ if (arg === "--session" || arg === "-S" || arg === "--resume" || arg === "-r") {
67
+ skipNext = true;
68
+ continue;
69
+ }
70
+ if (arg.startsWith("--session=") ||
71
+ arg.startsWith("--resume=") ||
72
+ ["-S", "-r"].some((prefix) => arg.startsWith(prefix) && arg.length > prefix.length)) {
73
+ continue;
74
+ }
75
+ filtered.push(arg);
76
+ }
77
+ return filtered;
78
+ }
40
79
  export class KimiWireTransport extends EventEmitter {
41
80
  constructor(options = {}) {
42
81
  super();
@@ -55,7 +94,7 @@ export class KimiWireTransport extends EventEmitter {
55
94
  throw new Error("Invalid kimi command");
56
95
  }
57
96
  this.command = command;
58
- this.baseArgs = args;
97
+ this.baseArgs = filterKimiWireBaseArgs(args);
59
98
  this.env = options.env && typeof options.env === "object" ? { ...options.env } : {};
60
99
  this.sessionId =
61
100
  typeof options.sessionId === "string" && options.sessionId.trim()
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @typedef {object} TurnUsageSummary
3
+ * @property {number} tokens Everything the turn read and wrote.
4
+ * @property {number} [inputTokens] All input the model read, cached or not.
5
+ * @property {number} [cachedInputTokens] The part of `inputTokens` served from the prompt cache.
6
+ */
7
+ /**
8
+ * Normalizes one turn's provider usage; the input cache hit ratio is
9
+ * `cachedInputTokens / inputTokens`. Claude's `input_tokens` excludes cache
10
+ * reads and writes, so its input is all three; the Codex provider reports
11
+ * per-turn deltas whose `turnInputTokens` already include the cached ones.
12
+ * Unknown shapes → null.
13
+ *
14
+ * @param {unknown} usage
15
+ * @returns {TurnUsageSummary | null}
16
+ */
17
+ export function summarizeTurnUsage(usage: unknown): TurnUsageSummary | null;
18
+ export type TurnUsageSummary = {
19
+ /**
20
+ * Everything the turn read and wrote.
21
+ */
22
+ tokens: number;
23
+ /**
24
+ * All input the model read, cached or not.
25
+ */
26
+ inputTokens?: number | undefined;
27
+ /**
28
+ * The part of `inputTokens` served from the prompt cache.
29
+ */
30
+ cachedInputTokens?: number | undefined;
31
+ };
@@ -0,0 +1,44 @@
1
+ /**
2
+ * @typedef {object} TurnUsageSummary
3
+ * @property {number} tokens Everything the turn read and wrote.
4
+ * @property {number} [inputTokens] All input the model read, cached or not.
5
+ * @property {number} [cachedInputTokens] The part of `inputTokens` served from the prompt cache.
6
+ */
7
+ /**
8
+ * Normalizes one turn's provider usage; the input cache hit ratio is
9
+ * `cachedInputTokens / inputTokens`. Claude's `input_tokens` excludes cache
10
+ * reads and writes, so its input is all three; the Codex provider reports
11
+ * per-turn deltas whose `turnInputTokens` already include the cached ones.
12
+ * Unknown shapes → null.
13
+ *
14
+ * @param {unknown} usage
15
+ * @returns {TurnUsageSummary | null}
16
+ */
17
+ export function summarizeTurnUsage(usage) {
18
+ if (!usage || typeof usage !== "object") {
19
+ return null;
20
+ }
21
+ const read = (key) => {
22
+ const value = Number(/** @type {Record<string, unknown>} */ (usage)[key]);
23
+ return Number.isFinite(value) ? value : null;
24
+ };
25
+ const turnTotal = read("turnTotalTokens");
26
+ if (turnTotal !== null) {
27
+ const inputTokens = read("turnInputTokens");
28
+ const cachedInputTokens = read("turnCachedInputTokens");
29
+ return inputTokens !== null && cachedInputTokens !== null
30
+ ? { tokens: turnTotal, inputTokens, cachedInputTokens }
31
+ : { tokens: turnTotal };
32
+ }
33
+ const [input, cacheWrite, cacheRead, output] = [
34
+ "input_tokens",
35
+ "cache_creation_input_tokens",
36
+ "cache_read_input_tokens",
37
+ "output_tokens",
38
+ ].map(read);
39
+ if ([input, cacheWrite, cacheRead, output].every((value) => value === null)) {
40
+ return null;
41
+ }
42
+ const inputTokens = (input ?? 0) + (cacheWrite ?? 0) + (cacheRead ?? 0);
43
+ return { tokens: inputTokens + (output ?? 0), inputTokens, cachedInputTokens: cacheRead ?? 0 };
44
+ }
package/dist/worker.js CHANGED
@@ -76,7 +76,7 @@ async function handleRequest(message) {
76
76
  throw new Error(`Unsupported worker method: ${method}`);
77
77
  }
78
78
  const args = Array.isArray(message.args) ? [...message.args] : [];
79
- if (method === "runTurn" || method === "runGoal" || method === "runCompact") {
79
+ if (method === "runTurn" || method === "runGoal" || method === "runCompact" || method === "runClear") {
80
80
  const firstArg = args[0];
81
81
  const options = args[1] && typeof args[1] === "object" ? { ...args[1] } : {};
82
82
  options.onProgress = (payload) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@love-moon/ai-sdk",
3
- "version": "0.13.3",
3
+ "version": "0.14.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/lovemoon-ai/conductor.git"
@@ -53,12 +53,12 @@
53
53
  "zod": "^4.1.5"
54
54
  },
55
55
  "optionalDependencies": {
56
- "@love-moon/chat-web": "^0.13.3"
56
+ "@love-moon/chat-web": "^0.14.0"
57
57
  },
58
58
  "devDependencies": {
59
59
  "@types/node": "^22.10.2",
60
60
  "tsx": "^4.20.6",
61
61
  "typescript": "^5.6.3"
62
62
  },
63
- "gitCommitId": "d61c070"
63
+ "gitCommitId": "6def94c"
64
64
  }