fly-to-moon 0.1.16 → 0.1.18

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 -0
  2. package/dist/cli.mjs +277 -59
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -174,6 +174,7 @@ npm link
174
174
  | `--max-tokens <n>` | Abort after `n` total input+output tokens | unlimited |
175
175
  | `--detach` | Run in daemon mode (background execution with `--max-iterations`) | `false` (foreground) |
176
176
  | `--prevent-sleep <mode>` | Prevent system sleep during the run (`on`/`off` or `true`/`false`) | config file (`on`) |
177
+ | `--commit` | Commit both successful and failed iterations (default: only on success) | `false` |
177
178
  | `--version` | Show version | |
178
179
 
179
180
  ## Configuration
package/dist/cli.mjs CHANGED
@@ -135,18 +135,108 @@ function loadConfig(overrides) {
135
135
  }
136
136
  //#endregion
137
137
  //#region src/core/debug-log.ts
138
- function appendDebugLog(event, details = {}) {
139
- const logPath = process.env.GNHF_DEBUG_LOG_PATH;
140
- if (!logPath) return;
138
+ const PRE_INIT_BUFFER_CAPACITY = 1e3;
139
+ const STACK_LINE_LIMIT = 12;
140
+ const CAUSE_DEPTH_LIMIT = 6;
141
+ let logPath = null;
142
+ let preInitBuffer = [];
143
+ let preInitDroppedCount = 0;
144
+ function formatLine(event, details) {
145
+ const base = {
146
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
147
+ pid: process.pid,
148
+ event
149
+ };
141
150
  try {
142
- appendFileSync(logPath, `${JSON.stringify({
143
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
144
- pid: process.pid,
145
- event,
151
+ return `${JSON.stringify({
152
+ ...base,
146
153
  ...details
147
- })}\n`, "utf-8");
154
+ })}\n`;
155
+ } catch (error) {
156
+ return `${JSON.stringify({
157
+ ...base,
158
+ logError: error instanceof Error ? `${error.name}: ${error.message}` : String(error),
159
+ detailsKeys: Object.keys(details)
160
+ })}\n`;
161
+ }
162
+ }
163
+ function initDebugLog(path) {
164
+ const resolvedPath = process.env.GNHF_DEBUG_LOG_PATH ?? path;
165
+ logPath = resolvedPath;
166
+ try {
167
+ mkdirSync(dirname(resolvedPath), { recursive: true });
168
+ } catch {}
169
+ if (preInitBuffer.length === 0 && preInitDroppedCount === 0) return;
170
+ const droppedSentinel = preInitDroppedCount > 0 ? formatLine("debug-log:pre-init-overflow", {
171
+ droppedCount: preInitDroppedCount,
172
+ bufferCapacity: PRE_INIT_BUFFER_CAPACITY
173
+ }) : "";
174
+ try {
175
+ appendFileSync(resolvedPath, droppedSentinel + preInitBuffer.join(""), "utf-8");
176
+ } catch {} finally {
177
+ preInitBuffer = [];
178
+ preInitDroppedCount = 0;
179
+ }
180
+ }
181
+ function appendDebugLog(event, details = {}) {
182
+ const line = formatLine(event, details);
183
+ if (logPath === null) {
184
+ const envLogPath = process.env.GNHF_DEBUG_LOG_PATH;
185
+ if (envLogPath) logPath = envLogPath;
186
+ else {
187
+ preInitBuffer.push(line);
188
+ if (preInitBuffer.length > PRE_INIT_BUFFER_CAPACITY) {
189
+ preInitBuffer.shift();
190
+ preInitDroppedCount += 1;
191
+ }
192
+ return;
193
+ }
194
+ }
195
+ try {
196
+ appendFileSync(logPath, line, "utf-8");
148
197
  } catch {}
149
198
  }
199
+ function serializeError(error, depth = 0) {
200
+ try {
201
+ return serializeErrorUnsafe(error, depth);
202
+ } catch (serializationError) {
203
+ return {
204
+ value: "[serialization failed]",
205
+ serializationError: serializationError instanceof Error ? `${serializationError.name}: ${serializationError.message}` : String(serializationError)
206
+ };
207
+ }
208
+ }
209
+ function tryRead(read) {
210
+ try {
211
+ return read();
212
+ } catch {
213
+ return;
214
+ }
215
+ }
216
+ function serializeErrorUnsafe(error, depth) {
217
+ if (depth > CAUSE_DEPTH_LIMIT) return { value: "[cause chain truncated]" };
218
+ if (error instanceof Error) {
219
+ const result = {
220
+ name: tryRead(() => error.name) ?? "Error",
221
+ message: tryRead(() => error.message) ?? ""
222
+ };
223
+ const code = tryRead(() => error.code);
224
+ if (typeof code === "string" || typeof code === "number") result.code = code;
225
+ const stack = tryRead(() => error.stack);
226
+ if (typeof stack === "string") result.stack = stack.split("\n").slice(0, STACK_LINE_LIMIT).join("\n");
227
+ const cause = tryRead(() => "cause" in error ? error.cause : void 0);
228
+ if (cause !== void 0) result.cause = serializeError(cause, depth + 1);
229
+ return result;
230
+ }
231
+ if (error === null || error === void 0) return { value: String(error) };
232
+ if (typeof error === "bigint") return { value: error.toString() };
233
+ if (typeof error === "object") try {
234
+ return { value: JSON.parse(JSON.stringify(error)) };
235
+ } catch {
236
+ return { value: String(error) };
237
+ }
238
+ return { value: String(error) };
239
+ }
150
240
  //#endregion
151
241
  //#region src/core/git.ts
152
242
  const NOT_GIT_REPOSITORY_MESSAGE = "This command must be run inside a Git repository. Change into a repo or run \"git init\" first.";
@@ -274,6 +364,7 @@ function setupRun(runId, prompt, baseCommit, cwd) {
274
364
  writeFileSync(notesPath, `# fttm run: ${runId}\n\nObjective: ${prompt}\n\n## Iteration Log\n`, "utf-8");
275
365
  const schemaPath = join(runDir, "output-schema.json");
276
366
  writeSchemaFile(schemaPath);
367
+ const logPath = join(runDir, "debug.jsonl");
277
368
  const baseCommitPath = join(runDir, "base-commit");
278
369
  const hasStoredBaseCommit = existsSync(baseCommitPath);
279
370
  const resolvedBaseCommit = hasStoredBaseCommit ? readFileSync(baseCommitPath, "utf-8").trim() : baseCommit;
@@ -284,6 +375,7 @@ function setupRun(runId, prompt, baseCommit, cwd) {
284
375
  promptPath,
285
376
  notesPath,
286
377
  schemaPath,
378
+ logPath,
287
379
  baseCommit: resolvedBaseCommit,
288
380
  baseCommitPath
289
381
  };
@@ -294,6 +386,7 @@ function resumeRun(runId, cwd) {
294
386
  const promptPath = join(runDir, "prompt.md");
295
387
  const notesPath = join(runDir, "notes.md");
296
388
  const schemaPath = join(runDir, "output-schema.json");
389
+ const logPath = join(runDir, "debug.jsonl");
297
390
  writeSchemaFile(schemaPath);
298
391
  const baseCommitPath = join(runDir, "base-commit");
299
392
  return {
@@ -302,6 +395,7 @@ function resumeRun(runId, cwd) {
302
395
  promptPath,
303
396
  notesPath,
304
397
  schemaPath,
398
+ logPath,
305
399
  baseCommit: existsSync(baseCommitPath) ? readFileSync(baseCommitPath, "utf-8").trim() : backfillLegacyBaseCommit(runId, baseCommitPath, cwd),
306
400
  baseCommitPath
307
401
  };
@@ -1199,6 +1293,14 @@ var OpenCodeAgent = class {
1199
1293
  return await this.streamMessage(server, sessionId, buildPrompt(prompt), runController.signal, logStream, onUsage, onMessage);
1200
1294
  } catch (error) {
1201
1295
  if (runController.signal.aborted || isAbortError$1(error)) throw createAbortError$1();
1296
+ appendDebugLog("opencode:run:error", {
1297
+ sessionId,
1298
+ cwd,
1299
+ error: serializeError(error),
1300
+ serverClosed: this.server?.closed ?? true,
1301
+ serverStderr: this.server?.stderr.slice(-2048),
1302
+ serverStdout: this.server?.stdout.slice(-2048)
1303
+ });
1202
1304
  throw error;
1203
1305
  } finally {
1204
1306
  signal?.removeEventListener("abort", onAbort);
@@ -1328,31 +1430,32 @@ var OpenCodeAgent = class {
1328
1430
  let messageRequestError = null;
1329
1431
  const messageRequest = (async () => {
1330
1432
  try {
1433
+ await this.request(server, `/session/${sessionId}/prompt_async`, {
1434
+ method: "POST",
1435
+ body: {
1436
+ role: "user",
1437
+ parts: [{
1438
+ type: "text",
1439
+ text: prompt
1440
+ }],
1441
+ ...this.model ? { model: (() => {
1442
+ const parts = this.model.split("/");
1443
+ if (parts.length === 2) return {
1444
+ providerID: parts[0],
1445
+ modelID: parts[1]
1446
+ };
1447
+ return {
1448
+ providerID: "opencode",
1449
+ modelID: this.model
1450
+ };
1451
+ })() } : {},
1452
+ format: STRUCTURED_OUTPUT_FORMAT
1453
+ },
1454
+ signal
1455
+ });
1331
1456
  return {
1332
1457
  ok: true,
1333
- body: await this.requestText(server, `/session/${sessionId}/message`, {
1334
- method: "POST",
1335
- body: {
1336
- role: "user",
1337
- parts: [{
1338
- type: "text",
1339
- text: prompt
1340
- }],
1341
- ...this.model ? { model: (() => {
1342
- const parts = this.model.split("/");
1343
- if (parts.length === 2) return {
1344
- providerID: parts[0],
1345
- modelID: parts[1]
1346
- };
1347
- return {
1348
- providerID: "opencode",
1349
- modelID: this.model
1350
- };
1351
- })() } : {},
1352
- format: STRUCTURED_OUTPUT_FORMAT
1353
- },
1354
- signal
1355
- })
1458
+ body: ""
1356
1459
  };
1357
1460
  } catch (error) {
1358
1461
  messageRequestError = error;
@@ -1374,6 +1477,7 @@ var OpenCodeAgent = class {
1374
1477
  let lastText = null;
1375
1478
  let lastFinalAnswerText = null;
1376
1479
  let lastUsageSignature = "0:0:0:0";
1480
+ let structuredOutputFromSSE = null;
1377
1481
  const updateUsage = (messageId, tokens) => {
1378
1482
  if (!messageId || !tokens) return;
1379
1483
  usageByMessageId.set(messageId, toUsage(tokens));
@@ -1437,6 +1541,7 @@ var OpenCodeAgent = class {
1437
1541
  }
1438
1542
  if (payload?.type === "message.updated") {
1439
1543
  if (properties.info?.role === "assistant") updateUsage(properties.info.id, properties.info.tokens);
1544
+ if (properties.info?.structured) structuredOutputFromSSE = properties.info.structured;
1440
1545
  return false;
1441
1546
  }
1442
1547
  return payload?.type === "session.idle";
@@ -1513,21 +1618,13 @@ var OpenCodeAgent = class {
1513
1618
  throw messageResult.error;
1514
1619
  }
1515
1620
  const body = messageResult.body;
1516
- let response;
1517
- try {
1518
- response = JSON.parse(body);
1621
+ if (body) try {
1622
+ JSON.parse(body);
1519
1623
  } catch (error) {
1520
1624
  throw new Error(`Failed to parse opencode response: ${error instanceof Error ? error.message : String(error)}`);
1521
1625
  }
1522
- if (response.info?.role === "assistant") updateUsage(response.info.id, response.info.tokens);
1523
- for (const part of response.parts ?? []) {
1524
- if (part.type !== "text" || typeof part.text !== "string") continue;
1525
- if (!part.text.trim()) continue;
1526
- lastText = part.text;
1527
- if (part.metadata?.openai?.phase === "final_answer") lastFinalAnswerText = part.text;
1528
- }
1529
- if (response.info?.structured) return {
1530
- output: response.info.structured,
1626
+ if (structuredOutputFromSSE) return {
1627
+ output: structuredOutputFromSSE,
1531
1628
  usage
1532
1629
  };
1533
1630
  const outputText = lastFinalAnswerText ?? lastText;
@@ -1592,12 +1689,24 @@ var OpenCodeAgent = class {
1592
1689
  const headers = new Headers(options.headers);
1593
1690
  if (options.body !== void 0) headers.set("content-type", "application/json");
1594
1691
  const signal = withTimeoutSignal$1(options.signal, options.timeoutMs);
1595
- const response = await this.fetchFn(`${server.baseUrl}${path}`, {
1596
- method: options.method,
1597
- headers,
1598
- body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
1599
- signal
1600
- });
1692
+ let response;
1693
+ try {
1694
+ response = await this.fetchFn(`${server.baseUrl}${path}`, {
1695
+ method: options.method,
1696
+ headers,
1697
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
1698
+ signal
1699
+ });
1700
+ } catch (error) {
1701
+ appendDebugLog("opencode:request:error", {
1702
+ method: options.method,
1703
+ path,
1704
+ timeoutMs: options.timeoutMs,
1705
+ error: serializeError(error),
1706
+ serverClosed: server.closed
1707
+ });
1708
+ throw error;
1709
+ }
1601
1710
  if (!response.ok) {
1602
1711
  const body = await response.text();
1603
1712
  throw new Error(`opencode ${options.method} ${path} failed with ${response.status}: ${body}`);
@@ -1740,6 +1849,14 @@ var RovoDevAgent = class {
1740
1849
  return await this.streamChat(server, sessionId, runController.signal, logStream, onUsage, onMessage);
1741
1850
  } catch (error) {
1742
1851
  if (runController.signal.aborted || isAbortError(error)) throw createAbortError();
1852
+ appendDebugLog("rovodev:run:error", {
1853
+ sessionId,
1854
+ cwd,
1855
+ error: serializeError(error),
1856
+ serverClosed: this.server?.closed ?? true,
1857
+ serverStderr: this.server?.stderr.slice(-2048),
1858
+ serverStdout: this.server?.stdout.slice(-2048)
1859
+ });
1743
1860
  throw error;
1744
1861
  } finally {
1745
1862
  signal?.removeEventListener("abort", onAbort);
@@ -2070,12 +2187,24 @@ var RovoDevAgent = class {
2070
2187
  if (options.sessionId) headers.set("x-session-id", options.sessionId);
2071
2188
  if (options.body !== void 0 && !headers.has("content-type")) headers.set("content-type", "application/json");
2072
2189
  const signal = withTimeoutSignal(options.signal, options.timeoutMs);
2073
- const response = await this.fetchFn(`${server.baseUrl}${path}`, {
2074
- method: options.method,
2075
- headers,
2076
- body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
2077
- signal
2078
- });
2190
+ let response;
2191
+ try {
2192
+ response = await this.fetchFn(`${server.baseUrl}${path}`, {
2193
+ method: options.method,
2194
+ headers,
2195
+ body: options.body === void 0 ? void 0 : JSON.stringify(options.body),
2196
+ signal
2197
+ });
2198
+ } catch (error) {
2199
+ appendDebugLog("rovodev:request:error", {
2200
+ method: options.method,
2201
+ path,
2202
+ timeoutMs: options.timeoutMs,
2203
+ error: serializeError(error),
2204
+ serverClosed: server.closed
2205
+ });
2206
+ throw error;
2207
+ }
2079
2208
  if (!response.ok) {
2080
2209
  const body = await response.text();
2081
2210
  throw new Error(`rovodev ${options.method} ${path} failed with ${response.status}: ${body}`);
@@ -2177,6 +2306,11 @@ var Orchestrator = class extends EventEmitter {
2177
2306
  }
2178
2307
  stop() {
2179
2308
  this.stopRequested = true;
2309
+ appendDebugLog("orchestrator:stop-requested", {
2310
+ iteration: this.state.currentIteration,
2311
+ hasActiveIteration: this.activeIterationPromise !== null,
2312
+ loopDone: this.loopDone
2313
+ });
2180
2314
  this.activeAbortController?.abort();
2181
2315
  if (this.loopDone) {
2182
2316
  this.emit("stopped");
@@ -2211,6 +2345,15 @@ var Orchestrator = class extends EventEmitter {
2211
2345
  this.state.startTime = /* @__PURE__ */ new Date();
2212
2346
  this.state.status = "running";
2213
2347
  this.emit("state", this.getState());
2348
+ appendDebugLog("orchestrator:start", {
2349
+ agent: this.agent.name,
2350
+ runId: this.runInfo.runId,
2351
+ startIteration: this.state.currentIteration,
2352
+ maxIterations: this.limits.maxIterations,
2353
+ maxTokens: this.limits.maxTokens,
2354
+ maxConsecutiveFailures: this.config.maxConsecutiveFailures,
2355
+ initialCommitCount: this.state.commitCount
2356
+ });
2214
2357
  try {
2215
2358
  while (!this.stopRequested) {
2216
2359
  const preIterationAbortReason = this.getPreIterationAbortReason();
@@ -2266,6 +2409,15 @@ var Orchestrator = class extends EventEmitter {
2266
2409
  if (this.stopPromise) await this.stopPromise;
2267
2410
  else await this.closeAgent();
2268
2411
  this.loopDone = true;
2412
+ appendDebugLog("orchestrator:end", {
2413
+ status: this.state.status,
2414
+ iterations: this.state.currentIteration,
2415
+ successCount: this.state.successCount,
2416
+ failCount: this.state.failCount,
2417
+ totalInputTokens: this.state.totalInputTokens,
2418
+ totalOutputTokens: this.state.totalOutputTokens,
2419
+ commitCount: this.state.commitCount
2420
+ });
2269
2421
  }
2270
2422
  }
2271
2423
  async runIteration(prompt) {
@@ -2288,6 +2440,12 @@ var Orchestrator = class extends EventEmitter {
2288
2440
  this.emit("state", this.getState());
2289
2441
  };
2290
2442
  const logPath = join(this.runInfo.runDir, `iteration-${this.state.currentIteration}.jsonl`);
2443
+ const agentStartedAt = Date.now();
2444
+ appendDebugLog("agent:run:start", {
2445
+ iteration: this.state.currentIteration,
2446
+ agent: this.agent.name,
2447
+ logPath
2448
+ });
2291
2449
  try {
2292
2450
  const result = await this.agent.run(prompt, this.cwd, {
2293
2451
  onUsage,
@@ -2295,6 +2453,15 @@ var Orchestrator = class extends EventEmitter {
2295
2453
  signal: this.activeAbortController.signal,
2296
2454
  logPath
2297
2455
  });
2456
+ appendDebugLog("agent:run:end", {
2457
+ iteration: this.state.currentIteration,
2458
+ elapsedMs: Date.now() - agentStartedAt,
2459
+ success: result.output.success,
2460
+ inputTokens: result.usage.inputTokens,
2461
+ outputTokens: result.usage.outputTokens,
2462
+ cacheReadTokens: result.usage.cacheReadTokens,
2463
+ cacheCreationTokens: result.usage.cacheCreationTokens
2464
+ });
2298
2465
  if (this.stopRequested) return { type: "stopped" };
2299
2466
  if (result.output.success) return {
2300
2467
  type: "completed",
@@ -2306,13 +2473,29 @@ var Orchestrator = class extends EventEmitter {
2306
2473
  };
2307
2474
  } catch (err) {
2308
2475
  if (this.pendingAbortReason && err instanceof Error && err.message === "Agent was aborted") {
2476
+ appendDebugLog("agent:run:aborted", {
2477
+ iteration: this.state.currentIteration,
2478
+ elapsedMs: Date.now() - agentStartedAt,
2479
+ reason: this.pendingAbortReason
2480
+ });
2309
2481
  resetHard(this.cwd);
2310
2482
  return {
2311
2483
  type: "aborted",
2312
2484
  reason: this.pendingAbortReason
2313
2485
  };
2314
2486
  }
2315
- if (this.stopRequested) return { type: "stopped" };
2487
+ if (this.stopRequested) {
2488
+ appendDebugLog("agent:run:stopped", {
2489
+ iteration: this.state.currentIteration,
2490
+ elapsedMs: Date.now() - agentStartedAt
2491
+ });
2492
+ return { type: "stopped" };
2493
+ }
2494
+ appendDebugLog("agent:run:error", {
2495
+ iteration: this.state.currentIteration,
2496
+ elapsedMs: Date.now() - agentStartedAt,
2497
+ error: serializeError(err)
2498
+ });
2316
2499
  const summary = err instanceof Error ? err.message : String(err);
2317
2500
  return {
2318
2501
  type: "completed",
@@ -2387,13 +2570,20 @@ var Orchestrator = class extends EventEmitter {
2387
2570
  this.state.status = "aborted";
2388
2571
  this.state.lastMessage = reason;
2389
2572
  this.state.waitingUntil = null;
2573
+ appendDebugLog("orchestrator:abort", {
2574
+ reason,
2575
+ iteration: this.state.currentIteration,
2576
+ consecutiveFailures: this.state.consecutiveFailures
2577
+ });
2390
2578
  this.emit("abort", reason);
2391
2579
  this.emit("state", this.getState());
2392
2580
  }
2393
2581
  async closeAgent() {
2394
2582
  try {
2395
2583
  await this.agent.close?.();
2396
- } catch {}
2584
+ } catch (err) {
2585
+ appendDebugLog("agent:close:error", { error: serializeError(err) });
2586
+ }
2397
2587
  }
2398
2588
  };
2399
2589
  //#endregion
@@ -3310,7 +3500,22 @@ program.name("fttm").description("Fly to the moon, fly to the mars - AI agents f
3310
3500
  if (!reexeced) persistedPrompt?.cleanup();
3311
3501
  }
3312
3502
  }
3313
- appendDebugLog("run:start", { args: process$1.argv.slice(2) });
3503
+ initDebugLog(runInfo.logPath);
3504
+ appendDebugLog("run:start", {
3505
+ args: process$1.argv.slice(2),
3506
+ runId: runInfo.runId,
3507
+ runDir: runInfo.runDir,
3508
+ agent: config.agent,
3509
+ promptLength: prompt.length,
3510
+ promptFromStdin,
3511
+ startIteration,
3512
+ maxIterations: options.maxIterations,
3513
+ maxTokens: options.maxTokens,
3514
+ preventSleep: config.preventSleep,
3515
+ platform: process$1.platform,
3516
+ nodeVersion: process$1.version,
3517
+ fttmVersion: packageVersion
3518
+ });
3314
3519
  const orchestrator = new Orchestrator(config, createAgent(config.agent, runInfo, config.agentPathOverride[config.agent], options.model), runInfo, prompt, cwd, startIteration, {
3315
3520
  maxIterations: options.maxIterations,
3316
3521
  maxTokens: options.maxTokens,
@@ -3334,6 +3539,7 @@ program.name("fttm").description("Fly to the moon, fly to the mars - AI agents f
3334
3539
  const orchestratorPromise = orchestrator.start().finally(() => {
3335
3540
  if (!(orchestrator.getState().status === "aborted" && process$1.stdin.isTTY)) renderer.stop();
3336
3541
  }).catch((err) => {
3542
+ appendDebugLog("orchestrator:fatal", { error: serializeError(err) });
3337
3543
  exitAltScreen();
3338
3544
  die(err instanceof Error ? err.message : String(err));
3339
3545
  });
@@ -3355,7 +3561,19 @@ program.name("fttm").description("Fly to the moon, fly to the mars - AI agents f
3355
3561
  process$1.off("SIGTERM", handleSigTerm);
3356
3562
  await sleepPreventionCleanup?.();
3357
3563
  }
3358
- appendDebugLog("run:complete", { signal: shutdownSignal });
3564
+ {
3565
+ const finalState = orchestrator.getState();
3566
+ appendDebugLog("run:complete", {
3567
+ signal: shutdownSignal,
3568
+ status: finalState.status,
3569
+ iterations: finalState.currentIteration,
3570
+ successCount: finalState.successCount,
3571
+ failCount: finalState.failCount,
3572
+ totalInputTokens: finalState.totalInputTokens,
3573
+ totalOutputTokens: finalState.totalOutputTokens,
3574
+ commitCount: finalState.commitCount
3575
+ });
3576
+ }
3359
3577
  if (shutdownSignal) process$1.exit(getSignalExitCode(shutdownSignal));
3360
3578
  });
3361
3579
  function enterAltScreen() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fly-to-moon",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Humans fly to space. AI does the work. — Fly to the moon, fly to Mars",
5
5
  "type": "module",
6
6
  "bin": {