@moxt-ai/cli 0.3.3-moxt-run.1 → 0.3.3-moxt-run.2

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/README.md CHANGED
@@ -171,7 +171,7 @@ moxt run codex -- exec "summarize this repository"
171
171
  moxt run claude -- -p "summarize this repository"
172
172
  ```
173
173
 
174
- Uploaded files are stored by Moxt under `Local Agent Sessions/<run-id>/` in personal space. For upload mode, `-w, --workspace` takes precedence over `MOXT_WORKSPACE_ID`; when neither is set, `moxt run` only writes the local capture artifact. The command does not accept a workspace destination selector for run uploads; the server chooses the storage location. `moxt run` preserves the local agent's stdin/stdout/stderr behavior and returns the agent's exit code even when upload cleanup fails afterward.
174
+ Uploaded files are stored by Moxt under `Local Agent Sessions/<run-id>/` in personal space. For upload mode, `-w, --workspace` takes precedence over `MOXT_WORKSPACE_ID`; when neither is set, `moxt run` only writes the local capture artifact. While the local agent is running, Moxt periodically uploads changed artifact files and overwrites the same `run-id + artifact path` on the server. When the agent exits, Moxt performs one final flush. The command does not accept a workspace destination selector for run uploads; the server chooses the storage location. `moxt run` preserves the local agent's stdin/stdout/stderr behavior and returns the agent's exit code even when upload cleanup fails afterward.
175
175
 
176
176
  Local run artifacts are written under the platform user data directory by default:
177
177
  macOS `~/Library/Application Support/moxt/runs/<run-id>/`, Linux `${XDG_DATA_HOME:-~/.local/share}/moxt/runs/<run-id>/`, and Windows `%LOCALAPPDATA%\Moxt\runs\<run-id>`. For tests or local debugging, override with `MOXT_RUN_OUTPUT_ROOT` or `MOXT_RUN_OUTPUT_DIR`.
@@ -215,6 +215,8 @@ Set the following environment variables:
215
215
  | `MOXT_API_KEY` | Your Moxt API key |
216
216
  | `MOXT_WORKSPACE_ID` | Default workspace ID for `moxt run` upload mode and AI E2E verification |
217
217
  | `MOXT_HOST` | API hostname (default: `api.moxt.ai`) |
218
+ | `MOXT_RUN_UPLOAD_INTERVAL_MS` | Optional `moxt run` live-upload scan interval, default `5000`, minimum `250` |
219
+ | `MOXT_RUN_UPLOAD_TIMEOUT_MS` | Optional `moxt run` per-file upload timeout, default `30000`, minimum `100` |
218
220
  | `MOXT_CF_ACCESS_TOKEN` / `CF_ACCESS_TOKEN` | Optional Cloudflare Access token for protected development or testing hosts |
219
221
  | `MOXT_CF_ACCESS_CLIENT_ID` / `MOXT_CF_ACCESS_CLIENT_SECRET` | Optional Cloudflare Access service-token credentials |
220
222
  | `MOXT_TELEMETRY_DISABLED` | Set to `1` to disable anonymous usage telemetry |
package/dist/index.js CHANGED
@@ -149,7 +149,7 @@ function getApiKeyOrUndefined() {
149
149
 
150
150
  // src/utils/http.ts
151
151
  function getUserAgent() {
152
- return `moxt-cli/${"0.3.3-moxt-run.1"} (${platform()}/${arch()}) node/${process.versions.node}`;
152
+ return `moxt-cli/${"0.3.3-moxt-run.2"} (${platform()}/${arch()}) node/${process.versions.node}`;
153
153
  }
154
154
  async function fetchApi(method, path2, body) {
155
155
  const apiKey = getApiKey();
@@ -1862,13 +1862,71 @@ function firstValue(...values) {
1862
1862
 
1863
1863
  // src/run/moxt-uploader.ts
1864
1864
  var DEFAULT_HOST2 = "api.moxt.ai";
1865
+ var DEFAULT_UPLOAD_INTERVAL_MS = 5e3;
1865
1866
  var DEFAULT_UPLOAD_TIMEOUT_MS = 3e4;
1866
- async function uploadRunArtifacts(options) {
1867
- const outputDirs = captureOutputDirectories(options.env, options.runId);
1867
+ var MIN_UPLOAD_INTERVAL_MS = 250;
1868
+ var MIN_UPLOAD_TIMEOUT_MS = 100;
1869
+ function createRunArtifactUploader(options) {
1870
+ return new RunArtifactUploader(options);
1871
+ }
1872
+ var RunArtifactUploader = class {
1873
+ enabled;
1874
+ env;
1875
+ runId;
1876
+ config;
1877
+ outputDirs;
1878
+ timer;
1879
+ uploadInFlight = null;
1880
+ constructor(options) {
1881
+ this.env = options.env;
1882
+ this.runId = options.runId;
1883
+ this.config = uploadConfig(options.upload, options.env);
1884
+ this.outputDirs = captureOutputDirectories(options.env, options.runId);
1885
+ this.enabled = this.outputDirs.length > 0;
1886
+ }
1887
+ start() {
1888
+ if (!this.enabled) {
1889
+ return;
1890
+ }
1891
+ this.timer = setInterval(() => {
1892
+ this.queueUpload();
1893
+ }, this.config.intervalMs);
1894
+ this.queueUpload();
1895
+ }
1896
+ async stop() {
1897
+ if (this.timer !== void 0) {
1898
+ clearInterval(this.timer);
1899
+ this.timer = void 0;
1900
+ }
1901
+ if (this.uploadInFlight !== null) {
1902
+ try {
1903
+ await this.uploadInFlight;
1904
+ } catch {
1905
+ }
1906
+ }
1907
+ }
1908
+ async flush() {
1909
+ if (!this.enabled) {
1910
+ return;
1911
+ }
1912
+ await this.stop();
1913
+ await uploadOutputDirs(this.outputDirs, this.runId, this.config, this.env);
1914
+ }
1915
+ queueUpload() {
1916
+ if (this.uploadInFlight !== null) {
1917
+ return;
1918
+ }
1919
+ this.uploadInFlight = uploadOutputDirs(this.outputDirs, this.runId, this.config, this.env).catch(() => {
1920
+ }).finally(() => {
1921
+ this.uploadInFlight = null;
1922
+ });
1923
+ }
1924
+ };
1925
+ async function uploadOutputDirs(outputDirs, runId, config, env) {
1868
1926
  const failures = [];
1869
1927
  for (const outputDir of outputDirs) {
1870
1928
  try {
1871
- await uploadDirectory(outputDir, options.runId, options.upload, options.env);
1929
+ await uploadDirectory(outputDir, runId, config, env);
1872
1930
  } catch (error) {
1873
1931
  failures.push(`${outputDir}: ${errorMessage2(error)}`);
1874
1932
  }
@@ -1877,6 +1935,13 @@ async function uploadRunArtifacts(options) {
1877
1935
  throw new Error(failures.join("; "));
1878
1936
  }
1879
1937
  }
1938
+ function uploadConfig(upload, env) {
1939
+ return {
1940
+ ...upload,
1941
+ intervalMs: Math.max(MIN_UPLOAD_INTERVAL_MS, numberEnv(env.MOXT_RUN_UPLOAD_INTERVAL_MS) ?? DEFAULT_UPLOAD_INTERVAL_MS),
1942
+ timeoutMs: Math.max(MIN_UPLOAD_TIMEOUT_MS, numberEnv(env.MOXT_RUN_UPLOAD_TIMEOUT_MS) ?? DEFAULT_UPLOAD_TIMEOUT_MS)
1943
+ };
1944
+ }
1880
1945
  async function uploadDirectory(outputDir, runId, config, env) {
1881
1946
  const files = await discoverUploadFiles(outputDir);
1882
1947
  const state = await readUploadState(outputDir, runId);
@@ -1981,10 +2046,6 @@ async function collectFiles(outputDir, dir, paths) {
1981
2046
  if (!entry.isFile()) {
1982
2047
  continue;
1983
2048
  }
1984
- const fileStat = await stat(absolute);
1985
- if (fileStat.size === 0) {
1986
- continue;
1987
- }
1988
2049
  paths.push(relative(outputDir, absolute).replaceAll("\\", "/"));
1989
2050
  }
1990
2051
  }
@@ -2092,7 +2153,7 @@ function apiBaseUrl(env) {
2092
2153
  return `https://${env.MOXT_HOST ?? DEFAULT_HOST2}/openapi/v1`;
2093
2154
  }
2094
2155
  function userAgent() {
2095
- return `moxt-cli/${"0.3.3-moxt-run.1"} (${platform2()}/${arch2()}) node/${process.versions.node}`;
2156
+ return `moxt-cli/${"0.3.3-moxt-run.2"} (${platform2()}/${arch2()}) node/${process.versions.node}`;
2096
2157
  }
2097
2158
  function errorMessage2(error) {
2098
2159
  if (error instanceof Error && error.message !== "") {
@@ -2100,6 +2161,13 @@ function errorMessage2(error) {
2100
2161
  }
2101
2162
  return String(error);
2102
2163
  }
2164
+ function numberEnv(value) {
2165
+ if (value === void 0 || value.trim() === "") {
2166
+ return void 0;
2167
+ }
2168
+ const parsed = Number(value);
2169
+ return Number.isFinite(parsed) ? parsed : void 0;
2170
+ }
2103
2171
  function isObject2(value) {
2104
2172
  return typeof value === "object" && value !== null && !Array.isArray(value);
2105
2173
  }
@@ -2520,6 +2588,12 @@ async function runLocalAgent(options) {
2520
2588
  );
2521
2589
  return 1;
2522
2590
  }
2591
+ const uploader = options.upload === void 0 ? void 0 : createRunArtifactUploader({
2592
+ env: captureEnv,
2593
+ runId,
2594
+ upload: options.upload
2595
+ });
2596
+ uploader?.start();
2523
2597
  const observedSignals = /* @__PURE__ */ new Set();
2524
2598
  let child = null;
2525
2599
  let pendingForward = null;
@@ -2604,6 +2678,7 @@ async function runLocalAgent(options) {
2604
2678
  await liveCapture.stop();
2605
2679
  } catch {
2606
2680
  }
2681
+ await uploader?.stop();
2607
2682
  const payload = buildPayload({
2608
2683
  agent: options.agent,
2609
2684
  cwd,
@@ -2641,11 +2716,7 @@ async function runLocalAgent(options) {
2641
2716
  }
2642
2717
  if (finalized && options.upload !== void 0) {
2643
2718
  try {
2644
- await uploadRunArtifacts({
2645
- env: captureEnv,
2646
- runId,
2647
- upload: options.upload
2648
- });
2719
+ await uploader?.flush();
2649
2720
  } catch (error) {
2650
2721
  printError(`moxt: cannot upload run artifact: ${errorMessage3(error)}`);
2651
2722
  }
@@ -3098,7 +3169,7 @@ var FLUSH_TIMEOUT_MS = 3e3;
3098
3169
  var MAX_BATCH_SIZE = 100;
3099
3170
  function commonLabels() {
3100
3171
  return {
3101
- cli_version: "0.3.3-moxt-run.1",
3172
+ cli_version: "0.3.3-moxt-run.2",
3102
3173
  node_version: process.versions.node,
3103
3174
  os: platform3(),
3104
3175
  arch: arch3(),
@@ -3144,7 +3215,7 @@ async function flush() {
3144
3215
  }
3145
3216
  const batch = buffer.splice(0, MAX_BATCH_SIZE);
3146
3217
  const payload = {
3147
- release_id: "0.3.3-moxt-run.1",
3218
+ release_id: "0.3.3-moxt-run.2",
3148
3219
  client_type: "cli",
3149
3220
  metric_data_list: batch.map((m) => ({
3150
3221
  profile: "cli",
@@ -3285,9 +3356,9 @@ function installExitHandler() {
3285
3356
 
3286
3357
  // src/index.ts
3287
3358
  updateNotifier({
3288
- pkg: { name: "@moxt-ai/cli", version: "0.3.3-moxt-run.1" }
3359
+ pkg: { name: "@moxt-ai/cli", version: "0.3.3-moxt-run.2" }
3289
3360
  }).notify();
3290
- var program = createProgram("0.3.3-moxt-run.1");
3361
+ var program = createProgram("0.3.3-moxt-run.2");
3291
3362
  instrumentProgram(program);
3292
3363
  installExitHandler();
3293
3364
  program.parseAsync(process.argv).then(async () => {