@workflow-code/cli 0.2.4-20261010004.codex-cli-web → 0.2.4-20261011002.codex-cli-web

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/dist/index.js CHANGED
@@ -24,7 +24,7 @@ async function main(argv = process.argv.slice(2)) {
24
24
  const prepared = prepareCliInvocation(argv);
25
25
  argv = prepared.argv;
26
26
  if (argv[0] === "web") {
27
- const webCli = await import("./web-KUC6BL6E.js");
27
+ const webCli = await import("./web-6FYGFQH2.js");
28
28
  return webCli.main(argv.slice(1));
29
29
  }
30
30
  if (argv[0] === "workspace") {
@@ -4183,10 +4183,13 @@ ${state.user?.avatarUrl ?? ""}`;
4183
4183
  try {
4184
4184
  if (this.token) {
4185
4185
  const session2 = await fetch("/api/session", { method: "POST", headers: { Authorization: `Bearer ${this.token}` }, signal: AbortSignal.timeout(1e4) });
4186
- if (!session2.ok) {
4186
+ if (session2.status === 401) {
4187
4187
  this.update("expired");
4188
4188
  return;
4189
4189
  }
4190
+ if (!session2.ok) {
4191
+ throw new Error("Cannot connect to the project.");
4192
+ }
4190
4193
  }
4191
4194
  const session = await fetch("/api/session", { headers: this.headers(), signal: AbortSignal.timeout(1e4) });
4192
4195
  if (session.status === 401) {
@@ -699,8 +699,29 @@ function createWebRuntime(projectDir, storageDir, connection) {
699
699
  return;
700
700
  }
701
701
  const auth = connection();
702
- const env = { ...process.env, WORKFLOW_RUNTIME_PLATFORM: "cli", WORKFLOW_SERVER_URL: auth?.serverUrl ?? "", WORKFLOW_SERVER_ADMIN_KEY: auth?.accessToken ?? "" };
703
- for (const key of ["TSX_TSCONFIG_PATH", "WORKFLOW_LOCAL_CORE_ROOT", "WORKFLOW_LOCAL_SHARED_ROOT", "WORKFLOW_LOCAL_SOURCE_MODE"]) {
702
+ if ((request.method === "run" || request.method === "resolve") && request.project?.requiresLogin && !auth) {
703
+ reject(new Error("Workflow Server login is not configured."));
704
+ return;
705
+ }
706
+ const env = {
707
+ ...process.env,
708
+ WORKFLOW_RUNTIME_PLATFORM: "cli",
709
+ WORKFLOW_SERVER_URL: auth?.serverUrl ?? "",
710
+ WORKFLOW_SERVER_ADMIN_KEY: auth?.accessToken ?? "",
711
+ WORKFLOW_SERVER_TOKEN: "",
712
+ WORKFLOW_LLM_SERVER_URL: auth?.serverUrl ?? "",
713
+ WORKFLOW_LLM_SERVER_TOKEN: auth?.accessToken ?? "",
714
+ WORKFLOW_CLI_AUTH_DIR: path.join(storageDir, "runtime-auth")
715
+ };
716
+ for (const key of [
717
+ "TSX_TSCONFIG_PATH",
718
+ "WORKFLOW_LOCAL_CORE_ROOT",
719
+ "WORKFLOW_LOCAL_SHARED_ROOT",
720
+ "WORKFLOW_LOCAL_SOURCE_MODE",
721
+ "WORKFLOW_DEVELOPER_ASSISTANT_HOST",
722
+ "WORKFLOW_DEVELOPER_ASSISTANT_WORKDIR",
723
+ "WORKFLOW_DEVELOPER_ASSISTANT_WORKSPACE_MANIFEST"
724
+ ]) {
704
725
  delete env[key];
705
726
  }
706
727
  if (env.NODE_OPTIONS) {
@@ -978,6 +999,7 @@ async function startWebServer(options) {
978
999
  let hostConnection = options.host?.connection;
979
1000
  let hostManaged = !!hostConnection;
980
1001
  let authEpoch = 0;
1002
+ let authCheck;
981
1003
  const sensitiveTokens = /* @__PURE__ */ new Set();
982
1004
  const runtime = options.runtime ?? createWebRuntime(projectDir, storageDir, () => connection);
983
1005
  let inspected;
@@ -1067,12 +1089,12 @@ async function startWebServer(options) {
1067
1089
  }
1068
1090
  });
1069
1091
  const refreshAuth = async (force = false) => {
1070
- if (passwordLogin || login) {
1092
+ if ((passwordLogin || login) && !force) {
1071
1093
  return;
1072
1094
  }
1073
- const epoch = ++authEpoch;
1095
+ const readingEpoch = authEpoch;
1074
1096
  const config = await readCliAuthConfig();
1075
- if (epoch !== authEpoch) {
1097
+ if (readingEpoch !== authEpoch) {
1076
1098
  return;
1077
1099
  }
1078
1100
  const serverUrl = hostManaged ? hostConnection?.serverUrl : process.env.WORKFLOW_SERVER_URL ?? config.serverUrl;
@@ -1082,31 +1104,45 @@ async function startWebServer(options) {
1082
1104
  }
1083
1105
  const identity = signedOut ? "" : `${serverUrl}
1084
1106
  ${token}`;
1085
- if (!force && identity === authIdentity && account.status !== "checking") {
1107
+ const expired = account.expiresAt && Date.parse(account.expiresAt) <= Date.now();
1108
+ if (!force && identity === authIdentity && account.status !== "error" && !expired) {
1086
1109
  return;
1087
1110
  }
1111
+ const epoch = ++authEpoch;
1112
+ authCheck?.abort();
1113
+ const check = authCheck = new AbortController();
1088
1114
  const changed = identity !== authIdentity;
1089
1115
  authIdentity = identity;
1090
- connection = !signedOut && serverUrl && token ? { serverUrl: serverUrl.replace(/\/+$/, ""), accessToken: token } : void 0;
1116
+ const candidate = !signedOut && serverUrl && token ? { serverUrl: serverUrl.replace(/\/+$/, ""), accessToken: token } : void 0;
1091
1117
  if (changed) {
1118
+ connection = void 0;
1092
1119
  authRevision++;
1093
1120
  parameterStates.clear();
1094
1121
  for (const session of controller.sessions) {
1095
1122
  controller.stop(session);
1096
1123
  }
1097
1124
  }
1098
- account = { status: connection ? "checking" : "signed-out", serverUrl: serverUrl || "http://localhost:7126", user: connection ? config.user ?? account.user : void 0, revision: account.revision + 1 };
1099
- if (connection) {
1125
+ account = { status: candidate ? "checking" : "signed-out", serverUrl: serverUrl || "http://localhost:7126", user: candidate ? changed ? hostManaged ? void 0 : config.user : account.user : void 0, revision: account.revision + 1 };
1126
+ if (candidate) {
1127
+ let unauthorized = false;
1100
1128
  try {
1101
- const response = await fetch(`${connection.serverUrl}/api/auth/me`, { headers: { Authorization: `Bearer ${connection.accessToken}` }, signal: AbortSignal.timeout(1e4), redirect: "error" });
1129
+ const response = await fetch(`${candidate.serverUrl}/api/auth/me`, { headers: { Authorization: `Bearer ${candidate.accessToken}` }, signal: AbortSignal.any([check.signal, AbortSignal.timeout(1e4)]), redirect: "error" });
1130
+ unauthorized = response.status === 401;
1102
1131
  const result = await response.json();
1103
1132
  if (epoch !== authEpoch) {
1104
1133
  return;
1105
1134
  }
1106
- if (!response.ok || result.errCode !== 0 || !result.data?.profile) {
1135
+ const profile = result.data?.profile;
1136
+ if (!response.ok || result.errCode !== 0 || typeof profile?.userId !== "string" || !profile.userId || typeof profile.email !== "string" || typeof profile.displayName !== "string") {
1107
1137
  throw new Error("Workflow login is invalid or expired.");
1108
1138
  }
1109
- account = { ...account, status: "authenticated", user: result.data.profile, expiresAt: result.data.principal?.expiresAt ?? config.expiresAt };
1139
+ if (!connection) {
1140
+ authRevision++;
1141
+ parameterStates.clear();
1142
+ }
1143
+ connection = candidate;
1144
+ const savedConnection = !hostManaged && candidate.serverUrl === config.serverUrl.replace(/\/+$/, "") && candidate.accessToken === config.apiKey;
1145
+ account = { ...account, status: "authenticated", user: profile, expiresAt: result.data.principal?.expiresAt ?? (savedConnection ? config.expiresAt : void 0) };
1110
1146
  } catch (error) {
1111
1147
  if (epoch !== authEpoch) {
1112
1148
  return;
@@ -1119,8 +1155,10 @@ ${token}`;
1119
1155
  controller.stop(session);
1120
1156
  }
1121
1157
  }
1122
- account = { ...account, status: "error", error: String(error.message) };
1158
+ account = { ...account, status: unauthorized ? "expired" : "error", error: String(error.message) };
1123
1159
  }
1160
+ } else {
1161
+ connection = void 0;
1124
1162
  }
1125
1163
  broadcast();
1126
1164
  };
@@ -1380,17 +1418,23 @@ ${token}`;
1380
1418
  account = { ...account, status: "checking" };
1381
1419
  broadcast();
1382
1420
  if (message.email !== void 0 || message.password !== void 0) {
1421
+ const epoch = ++authEpoch;
1383
1422
  passwordLogin = true;
1384
1423
  try {
1385
1424
  if (typeof message.email !== "string" || typeof message.password !== "string") {
1386
1425
  throw new Error("Invalid login credentials.");
1387
1426
  }
1388
1427
  await loginWebAccount(url.toString().replace(/\/+$/, ""), message.email, message.password);
1428
+ if (epoch !== authEpoch) {
1429
+ break;
1430
+ }
1389
1431
  hostManaged = false;
1390
1432
  hostConnection = void 0;
1391
1433
  } catch (error) {
1392
- account = { ...account, status: "error", error: String(error.message) };
1393
- broadcast();
1434
+ if (epoch === authEpoch) {
1435
+ account = { ...account, status: "error", error: String(error.message) };
1436
+ broadcast();
1437
+ }
1394
1438
  throw error;
1395
1439
  } finally {
1396
1440
  passwordLogin = false;
@@ -1434,7 +1478,9 @@ ${token}`;
1434
1478
  void (async () => {
1435
1479
  response.setHeader("X-Content-Type-Options", "nosniff");
1436
1480
  response.setHeader("Referrer-Policy", "no-referrer");
1437
- if (request.headers.host !== new URL(origin).host || request.headers.origin && request.headers.origin !== origin) {
1481
+ const host = new URL(`http://${request.headers.host ?? ""}`);
1482
+ const forwarded = !!options.host && ["127.0.0.1", "localhost", "[::1]"].includes(host.hostname) && !host.username && !host.password && host.pathname === "/" && !host.search && !host.hash;
1483
+ if (request.headers.host !== new URL(origin).host && !forwarded || request.headers.origin && request.headers.origin !== (forwarded ? host.origin : origin)) {
1438
1484
  json(response, 403, { message: "Invalid request origin." });
1439
1485
  return;
1440
1486
  }
@@ -1555,12 +1601,16 @@ ${token}`;
1555
1601
  project,
1556
1602
  controller,
1557
1603
  setHostConnection: async (value) => {
1604
+ authEpoch++;
1605
+ authCheck?.abort();
1558
1606
  hostConnection = value;
1559
1607
  hostManaged = true;
1560
1608
  signedOut = !value;
1561
1609
  await refreshAuth(true);
1562
1610
  },
1563
1611
  close: () => closing ??= (async () => {
1612
+ authEpoch++;
1613
+ authCheck?.abort();
1564
1614
  clearInterval(authPoll);
1565
1615
  if (broadcastTimer) {
1566
1616
  clearTimeout(broadcastTimer);
@@ -1712,7 +1762,11 @@ async function main(argv) {
1712
1762
  }
1713
1763
  const message = JSON.parse(line);
1714
1764
  if (message.type === "auth") {
1715
- await app.setHostConnection(parseHostConnection(message.connection));
1765
+ void app.setHostConnection(parseHostConnection(message.connection)).catch(() => {
1766
+ console.error("Workflow web host connection failed.");
1767
+ process.exitCode = 1;
1768
+ close();
1769
+ });
1716
1770
  } else if (message.type === "close") {
1717
1771
  break;
1718
1772
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@workflow-code/cli",
3
- "version": "0.2.4-20261010004.codex-cli-web",
3
+ "version": "0.2.4-20261011002.codex-cli-web",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "workflow-code": "./dist/index.js"
@@ -37,8 +37,8 @@
37
37
  "workflow-code": "0.2.4-20260929001",
38
38
  "@workflow-code/auth-config": "0.1.0",
39
39
  "@workflow-code/execution-targets": "0.1.0",
40
- "@workflow-code/openai-responses": "0.1.0",
41
40
  "@workflow-code/i18n": "0.1.0",
41
+ "@workflow-code/openai-responses": "0.1.0",
42
42
  "@workflow-code/project-dependencies": "0.1.0",
43
43
  "@workflow-code/project-info": "0.1.0",
44
44
  "@workflow-code/project-upload": "0.1.0",