@linzumi/cli 0.0.60-beta → 0.0.61-beta

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 (3) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +348 -8
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -62,7 +62,7 @@ Install the CLI or run it with `npx`:
62
62
  ```bash
63
63
  npm install -g @linzumi/cli@latest
64
64
  npx -y @linzumi/cli@latest signup
65
- npx -y @linzumi/cli@0.0.60-beta --version
65
+ npx -y @linzumi/cli@0.0.61-beta --version
66
66
  linzumi --version
67
67
  ```
68
68
 
package/dist/index.js CHANGED
@@ -28294,7 +28294,7 @@ function realpathOrResolved(pathValue) {
28294
28294
  }
28295
28295
 
28296
28296
  // src/version.ts
28297
- var linzumiCliVersion = "0.0.60-beta";
28297
+ var linzumiCliVersion = "0.0.61-beta";
28298
28298
  var linzumiCliVersionText = `linzumi ${linzumiCliVersion}`;
28299
28299
 
28300
28300
  // src/runnerLock.ts
@@ -28779,6 +28779,333 @@ function normalizeLocalRunnerCache(value) {
28779
28779
  );
28780
28780
  }
28781
28781
 
28782
+ // src/threadCodexWorkerIpc.ts
28783
+ function bindThreadCodexWorkerIpc(codex) {
28784
+ const pendingServerRequests = /* @__PURE__ */ new Map();
28785
+ const state = { nextServerRequestId: 1 };
28786
+ const send = (message) => {
28787
+ if (process.send === void 0) {
28788
+ throw new Error("thread Codex worker IPC channel closed");
28789
+ }
28790
+ process.send(message);
28791
+ };
28792
+ process.on("message", (message) => {
28793
+ const parsed = threadCodexWorkerParentMessage(message);
28794
+ if (parsed === void 0) {
28795
+ return;
28796
+ }
28797
+ switch (parsed.type) {
28798
+ case "linzumi_thread_codex_worker_request":
28799
+ void codex.request(parsed.method, parsed.params).then(
28800
+ (response) => send({
28801
+ type: "linzumi_thread_codex_worker_response",
28802
+ id: parsed.id,
28803
+ response
28804
+ })
28805
+ ).catch(
28806
+ (error51) => send({
28807
+ type: "linzumi_thread_codex_worker_response",
28808
+ id: parsed.id,
28809
+ error: error51 instanceof Error ? error51.message : String(error51)
28810
+ })
28811
+ );
28812
+ return;
28813
+ case "linzumi_thread_codex_worker_notify":
28814
+ codex.notify(parsed.method, parsed.params);
28815
+ return;
28816
+ case "linzumi_thread_codex_worker_server_request_response": {
28817
+ const pending = pendingServerRequests.get(parsed.id);
28818
+ if (pending === void 0) {
28819
+ return;
28820
+ }
28821
+ pendingServerRequests.delete(parsed.id);
28822
+ if (parsed.error !== void 0) {
28823
+ pending.reject(new Error(parsed.error));
28824
+ return;
28825
+ }
28826
+ pending.resolve(parsed.result);
28827
+ return;
28828
+ }
28829
+ }
28830
+ });
28831
+ codex.onNotification((notification) => {
28832
+ send({
28833
+ type: "linzumi_thread_codex_worker_notification",
28834
+ notification
28835
+ });
28836
+ });
28837
+ codex.onRequest(
28838
+ (request) => new Promise((resolve11, reject) => {
28839
+ const id = state.nextServerRequestId;
28840
+ state.nextServerRequestId += 1;
28841
+ pendingServerRequests.set(id, { resolve: resolve11, reject });
28842
+ send({
28843
+ type: "linzumi_thread_codex_worker_server_request",
28844
+ id,
28845
+ request
28846
+ });
28847
+ })
28848
+ );
28849
+ process.once("disconnect", () => {
28850
+ for (const pending of pendingServerRequests.values()) {
28851
+ pending.reject(new Error("thread Codex worker IPC channel closed"));
28852
+ }
28853
+ pendingServerRequests.clear();
28854
+ });
28855
+ }
28856
+ function connectThreadCodexWorkerIpc(child) {
28857
+ const pendingRequests = /* @__PURE__ */ new Map();
28858
+ const notificationCallbacks = /* @__PURE__ */ new Set();
28859
+ const requestCallbacks = /* @__PURE__ */ new Set();
28860
+ const pendingNotifications = [];
28861
+ const state = { nextRequestId: 1, closed: false };
28862
+ const rejectPendingRequests = (message) => {
28863
+ const error51 = new Error(message);
28864
+ for (const pending of pendingRequests.values()) {
28865
+ pending.reject(error51);
28866
+ }
28867
+ pendingRequests.clear();
28868
+ };
28869
+ const send = (message) => {
28870
+ if (state.closed) {
28871
+ throw new Error("thread Codex worker IPC client is closed");
28872
+ }
28873
+ if (child.send === void 0 || child.connected === false) {
28874
+ throw new Error("thread Codex worker IPC channel closed");
28875
+ }
28876
+ child.send(message);
28877
+ };
28878
+ const onMessage = (message) => {
28879
+ const parsed = threadCodexWorkerChildMessage(message);
28880
+ if (parsed === void 0) {
28881
+ return;
28882
+ }
28883
+ switch (parsed.type) {
28884
+ case "linzumi_thread_codex_worker_response": {
28885
+ const pending = pendingRequests.get(parsed.id);
28886
+ if (pending === void 0) {
28887
+ return;
28888
+ }
28889
+ pendingRequests.delete(parsed.id);
28890
+ if (parsed.error !== void 0) {
28891
+ pending.reject(new Error(parsed.error));
28892
+ return;
28893
+ }
28894
+ if (parsed.response === void 0) {
28895
+ pending.reject(
28896
+ new Error("thread Codex worker response missing body")
28897
+ );
28898
+ return;
28899
+ }
28900
+ pending.resolve(parsed.response);
28901
+ return;
28902
+ }
28903
+ case "linzumi_thread_codex_worker_notification":
28904
+ if (notificationCallbacks.size === 0) {
28905
+ pendingNotifications.push(parsed.notification);
28906
+ } else {
28907
+ for (const callback of notificationCallbacks) {
28908
+ callback(parsed.notification);
28909
+ }
28910
+ }
28911
+ return;
28912
+ case "linzumi_thread_codex_worker_server_request":
28913
+ void respondToThreadCodexWorkerServerRequest(
28914
+ send,
28915
+ parsed.id,
28916
+ parsed.request,
28917
+ requestCallbacks
28918
+ );
28919
+ return;
28920
+ }
28921
+ };
28922
+ const onClosed = () => {
28923
+ state.closed = true;
28924
+ rejectPendingRequests("thread Codex worker IPC channel closed");
28925
+ };
28926
+ child.on("message", onMessage);
28927
+ child.once("exit", onClosed);
28928
+ child.once("disconnect", onClosed);
28929
+ return {
28930
+ request: (method, params) => new Promise((resolve11, reject) => {
28931
+ const id = state.nextRequestId;
28932
+ state.nextRequestId += 1;
28933
+ pendingRequests.set(id, { resolve: resolve11, reject });
28934
+ try {
28935
+ send({
28936
+ type: "linzumi_thread_codex_worker_request",
28937
+ id,
28938
+ method,
28939
+ params
28940
+ });
28941
+ } catch (error51) {
28942
+ pendingRequests.delete(id);
28943
+ reject(error51 instanceof Error ? error51 : new Error(String(error51)));
28944
+ }
28945
+ }),
28946
+ notify: (method, params) => {
28947
+ send({
28948
+ type: "linzumi_thread_codex_worker_notify",
28949
+ method,
28950
+ params
28951
+ });
28952
+ },
28953
+ onNotification: (callback) => {
28954
+ notificationCallbacks.add(callback);
28955
+ pendingNotifications.splice(0).forEach((notification) => {
28956
+ callback(notification);
28957
+ });
28958
+ },
28959
+ onRequest: (callback) => {
28960
+ requestCallbacks.add(callback);
28961
+ },
28962
+ close: () => {
28963
+ state.closed = true;
28964
+ child.off("message", onMessage);
28965
+ child.off("exit", onClosed);
28966
+ child.off("disconnect", onClosed);
28967
+ rejectPendingRequests("thread Codex worker IPC client closed");
28968
+ }
28969
+ };
28970
+ }
28971
+ async function respondToThreadCodexWorkerServerRequest(send, id, request, callbacks) {
28972
+ try {
28973
+ for (const callback of callbacks) {
28974
+ const result = await callback(request);
28975
+ if (result !== void 0) {
28976
+ send({
28977
+ type: "linzumi_thread_codex_worker_server_request_response",
28978
+ id,
28979
+ result
28980
+ });
28981
+ return;
28982
+ }
28983
+ }
28984
+ send({
28985
+ type: "linzumi_thread_codex_worker_server_request_response",
28986
+ id,
28987
+ error: `unhandled Codex app-server request: ${request.method}`
28988
+ });
28989
+ } catch (error51) {
28990
+ send({
28991
+ type: "linzumi_thread_codex_worker_server_request_response",
28992
+ id,
28993
+ error: error51 instanceof Error ? error51.message : String(error51)
28994
+ });
28995
+ }
28996
+ }
28997
+ function threadCodexWorkerParentMessage(message) {
28998
+ if (!isJsonObject(message)) {
28999
+ return void 0;
29000
+ }
29001
+ switch (message.type) {
29002
+ case "linzumi_thread_codex_worker_request": {
29003
+ const id = integerValue(message.id);
29004
+ const method = stringValue(message.method);
29005
+ if (id === void 0 || method === void 0) {
29006
+ return void 0;
29007
+ }
29008
+ return {
29009
+ type: "linzumi_thread_codex_worker_request",
29010
+ id,
29011
+ method,
29012
+ params: objectValue(message.params)
29013
+ };
29014
+ }
29015
+ case "linzumi_thread_codex_worker_notify": {
29016
+ const method = stringValue(message.method);
29017
+ if (method === void 0) {
29018
+ return void 0;
29019
+ }
29020
+ return {
29021
+ type: "linzumi_thread_codex_worker_notify",
29022
+ method,
29023
+ params: objectValue(message.params)
29024
+ };
29025
+ }
29026
+ case "linzumi_thread_codex_worker_server_request_response": {
29027
+ const id = integerValue(message.id);
29028
+ if (id === void 0) {
29029
+ return void 0;
29030
+ }
29031
+ return {
29032
+ type: "linzumi_thread_codex_worker_server_request_response",
29033
+ id,
29034
+ result: message.result,
29035
+ error: stringValue(message.error)
29036
+ };
29037
+ }
29038
+ default:
29039
+ return void 0;
29040
+ }
29041
+ }
29042
+ function threadCodexWorkerChildMessage(message) {
29043
+ if (!isJsonObject(message)) {
29044
+ return void 0;
29045
+ }
29046
+ switch (message.type) {
29047
+ case "linzumi_thread_codex_worker_response": {
29048
+ const id = integerValue(message.id);
29049
+ if (id === void 0) {
29050
+ return void 0;
29051
+ }
29052
+ return {
29053
+ type: "linzumi_thread_codex_worker_response",
29054
+ id,
29055
+ response: jsonRpcResponseValue(message.response),
29056
+ error: stringValue(message.error)
29057
+ };
29058
+ }
29059
+ case "linzumi_thread_codex_worker_notification": {
29060
+ const notification = jsonRpcNotificationValue(message.notification);
29061
+ if (notification === void 0) {
29062
+ return void 0;
29063
+ }
29064
+ return {
29065
+ type: "linzumi_thread_codex_worker_notification",
29066
+ notification
29067
+ };
29068
+ }
29069
+ case "linzumi_thread_codex_worker_server_request": {
29070
+ const id = integerValue(message.id);
29071
+ const request = jsonRpcRequestValue(message.request);
29072
+ if (id === void 0 || request === void 0) {
29073
+ return void 0;
29074
+ }
29075
+ return {
29076
+ type: "linzumi_thread_codex_worker_server_request",
29077
+ id,
29078
+ request
29079
+ };
29080
+ }
29081
+ case "linzumi_thread_codex_worker_ready":
29082
+ return void 0;
29083
+ default:
29084
+ return void 0;
29085
+ }
29086
+ }
29087
+ function jsonRpcResponseValue(value) {
29088
+ if (!isJsonObject(value) || !("id" in value)) {
29089
+ return void 0;
29090
+ }
29091
+ if ("result" in value || "error" in value) {
29092
+ return value;
29093
+ }
29094
+ return void 0;
29095
+ }
29096
+ function jsonRpcNotificationValue(value) {
29097
+ if (!isJsonObject(value) || "id" in value || typeof value.method !== "string") {
29098
+ return void 0;
29099
+ }
29100
+ return value;
29101
+ }
29102
+ function jsonRpcRequestValue(value) {
29103
+ if (!isJsonObject(value) || !("id" in value) || typeof value.method !== "string") {
29104
+ return void 0;
29105
+ }
29106
+ return value;
29107
+ }
29108
+
28782
29109
  // src/runner.ts
28783
29110
  var THREAD_RUNNER_READY_TIMEOUT_MS = 3e4;
28784
29111
  async function runLocalCodexRunner(options) {
@@ -28829,14 +29156,16 @@ async function runThreadCodexWorker(options) {
28829
29156
  const started = await startOwnedCodexAppServer(options, {
28830
29157
  linzumiMcp: false
28831
29158
  });
29159
+ const codex = await connectCodexAppServer(started.url);
28832
29160
  const stop = once(() => {
29161
+ codex.close();
28833
29162
  started.stop();
28834
29163
  log.close();
28835
29164
  });
29165
+ bindThreadCodexWorkerIpc(codex);
28836
29166
  process.send({
28837
29167
  type: "linzumi_thread_codex_worker_ready",
28838
- kandanThreadId: options.threadProcess.kandanThreadId,
28839
- codexUrl: started.url
29168
+ kandanThreadId: options.threadProcess.kandanThreadId
28840
29169
  });
28841
29170
  await waitForThreadCodexWorkerStop(started.process);
28842
29171
  stop();
@@ -29870,6 +30199,18 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
29870
30199
  log
29871
30200
  });
29872
30201
  dynamicChannelSessions.set(kandanThreadId, session);
30202
+ if (sessionCodex !== codex) {
30203
+ sessionCodex.onNotification((notification) => {
30204
+ seq.value += 1;
30205
+ const params = notification.params ?? {};
30206
+ const metadata = extractCodexIds(params);
30207
+ log("codex.notification", {
30208
+ method: notification.method,
30209
+ metadata
30210
+ });
30211
+ session.handleCodexNotification(notification.method, params);
30212
+ });
30213
+ }
29873
30214
  return session;
29874
30215
  };
29875
30216
  const attachThreadSession = async (control, cwd, codexThreadId) => {
@@ -29939,7 +30280,7 @@ async function openLocalCodexRunner(options, log, cleanup, close) {
29939
30280
  throw error51;
29940
30281
  }
29941
30282
  try {
29942
- const threadCodex = await connectCodexAppServer(handle.codexUrl);
30283
+ const threadCodex = handle.codex;
29943
30284
  const closeThreadCodex = once(() => threadCodex.close());
29944
30285
  handle.onExit?.(closeThreadCodex);
29945
30286
  const runtimeHandle = {
@@ -32813,7 +33154,7 @@ async function spawnLocalThreadRunnerProcess(options) {
32813
33154
  });
32814
33155
  return {
32815
33156
  kandanThreadId: ready2.kandanThreadId,
32816
- codexUrl: ready2.codexUrl,
33157
+ codex: connectThreadCodexWorkerIpc(child),
32817
33158
  processPid: child.pid,
32818
33159
  onExit: (listener) => {
32819
33160
  if (exitState.exited) {
@@ -32840,11 +33181,10 @@ function threadRunnerReadyMessage(message, expectedKandanThreadId) {
32840
33181
  return void 0;
32841
33182
  }
32842
33183
  const kandanThreadId = stringValue(message.kandanThreadId);
32843
- const codexUrl = stringValue(message.codexUrl);
32844
- if (kandanThreadId !== expectedKandanThreadId || codexUrl === void 0) {
33184
+ if (kandanThreadId !== expectedKandanThreadId) {
32845
33185
  throw new Error("thread Codex worker reported invalid ready payload");
32846
33186
  }
32847
- return { kandanThreadId, codexUrl };
33187
+ return { kandanThreadId };
32848
33188
  }
32849
33189
  function waitForThreadCodexWorkerStop(codexProcess) {
32850
33190
  return new Promise((resolve11) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "0.0.60-beta",
3
+ "version": "0.0.61-beta",
4
4
  "description": "Linzumi CLI — point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {