overlord-cli 0.2607141512.0 → 0.2607151850.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.
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://antigravity.google/schemas/v1/plugin.json",
3
3
  "name": "overlord",
4
- "version": "0.3.1",
4
+ "version": "0.3.2",
5
5
  "description": "Chat-driven access to Overlord mission protocol workflows with hook-driven activity capture.",
6
6
  "author": {
7
7
  "name": "Cooperativ",
@@ -328,7 +328,7 @@ process.stdin.on('data', async chunk => {
328
328
  result: {
329
329
  protocolVersion: PROTOCOL_VERSION,
330
330
  capabilities: { tools: { listChanged: false } },
331
- serverInfo: { name: 'overlord-antigravity', version: '0.3.1' }
331
+ serverInfo: { name: 'overlord-antigravity', version: '0.3.2' }
332
332
  }
333
333
  });
334
334
  continue;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Overlord mission protocol workflow for Claude Code — attach/update/ask/deliver, slash commands, and hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -5,13 +5,13 @@ Claude launch prompts should keep the mission objective compact and place large
5
5
  Recommended launch shape:
6
6
 
7
7
  ```bash
8
- claude --append-system-prompt-file <context-file> --model <model> --effort <level> "Begin working on this mission."
8
+ claude --append-system-prompt-file <context-file> --model <model> --effort <level> "Attach, then immediately execute this mission's current objective."
9
9
  ```
10
10
 
11
11
  Rules:
12
12
 
13
13
  - The context file should contain the Overlord mission prompt, objective metadata, history, artifacts, attachments, and shared context assembled by the protocol layer.
14
- - The visible user prompt should point Claude at the context file and name the active mission ID; for normal execution this is a short instruction such as `Begin working on this mission.`
14
+ - The visible user prompt should point Claude at the context file, name the active mission ID, and explicitly direct execution without waiting for confirmation.
15
15
  - `--model` is passed only when the execution target has a model configured.
16
16
  - `--effort` is passed only when the installed Claude binary supports it and the execution target has an effort level configured.
17
17
  - Do not embed secrets in the prompt wrapper. Authentication comes from shared `ovld auth` credentials, Overlord-launched environment variables, `Overlord_USER_TOKEN` / `OVLD_USER_TOKEN`, or the Claude plugin `user_token` config passed to `ovld protocol` as `Overlord_USER_TOKEN`.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Chat-driven access to Overlord mission protocol workflows with hook-driven activity capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -5,13 +5,13 @@ Codex launch prompts should keep the mission objective compact and pass model an
5
5
  Recommended launch shape:
6
6
 
7
7
  ```bash
8
- codex [--model <model>] [-c model_reasoning_effort="<level>"] "Begin working on this mission."
8
+ codex [--model <model>] [-c model_reasoning_effort="<level>"] "Attach, then immediately execute this mission's current objective."
9
9
  ```
10
10
 
11
11
  Rules:
12
12
 
13
13
  - The assembled Overlord mission prompt, objective metadata, history, artifacts, attachments, and shared context should be injected as the initial session prompt by the protocol layer.
14
- - The visible user prompt should name the active mission ID; for normal execution this is a short instruction such as `Begin working on this mission.`
14
+ - The visible user prompt should name the active mission ID and explicitly direct execution without waiting for confirmation.
15
15
  - `--model` is passed only when the execution target has a model configured.
16
16
  - `-c model_reasoning_effort="<level>"` is passed only when the execution target has an effort level configured.
17
17
  - For large context, write a context file and pass a short prompt that points Codex at it.
@@ -328,7 +328,7 @@ process.stdin.on('data', async chunk => {
328
328
  result: {
329
329
  protocolVersion: PROTOCOL_VERSION,
330
330
  capabilities: { tools: { listChanged: false } },
331
- serverInfo: { name: 'overlord-codex', version: '0.3.1' }
331
+ serverInfo: { name: 'overlord-codex', version: '0.3.2' }
332
332
  }
333
333
  });
334
334
  continue;
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "Overlord mission protocol workflow for Cursor — attach/update/ask/deliver, slash commands, MCP bridge, and follow-up capture.",
5
5
  "author": {
6
6
  "name": "Cooperativ",
@@ -328,7 +328,7 @@ process.stdin.on('data', async chunk => {
328
328
  result: {
329
329
  protocolVersion: PROTOCOL_VERSION,
330
330
  capabilities: { tools: { listChanged: false } },
331
- serverInfo: { name: 'overlord-cursor', version: '0.3.1' }
331
+ serverInfo: { name: 'overlord-cursor', version: '0.3.2' }
332
332
  }
333
333
  });
334
334
  continue;
@@ -3,7 +3,7 @@
3
3
  PI receives Overlord's generated mission context as a native file input and a short visible launch message:
4
4
 
5
5
  ```bash
6
- pi --model <provider/id> --thinking <level> @<context-file> "Start work on <mission>."
6
+ pi --model <provider/id> --thinking <level> @<context-file> "Attach, then immediately execute <mission>'s current objective."
7
7
  ```
8
8
 
9
9
  Rules:
@@ -12,3 +12,4 @@ Rules:
12
12
  - Pass thinking separately with `--thinking` only when the selected launch configuration specifies it.
13
13
  - Place user-configured launch flags before the `@<context-file>` and visible message arguments.
14
14
  - The context file contains the mission, objectives, history, artifacts, attachments, and lifecycle instructions. Do not put credentials in it.
15
+ - The visible message must explicitly direct execution without waiting for confirmation.
@@ -15,7 +15,7 @@ Use this mode when the prompt already contains a mission ID or explicitly says t
15
15
 
16
16
  1. Attach first with `ovld protocol attach --mission-id <mission_id>`.
17
17
  2. The attach response prints JSON to stdout containing `session.sessionKey`. The CLI also persists this key automatically so subsequent `ovld protocol` commands in the same working directory resolve it without `--session-key`. If auto-resolution fails, pass `--session-key <sessionKey>` explicitly on every subsequent call.
18
- 3. Treat the Overlord mission prompt as authoritative for the objective, constraints, and delivery target. Begin implementing the objective immediately after attach. This differs from `connect` or `load-context`, which only retrieve mission context and never imply the agent should act.
18
+ 3. Treat the Overlord mission prompt as authoritative for the objective, constraints, and delivery target. Begin executing the current objective immediately after attach; do not wait for more instructions or ask for confirmation. This differs from `connect` or `load-context`, which only retrieve mission context and never imply the agent should act.
19
19
  4. Post updates while working: `ovld protocol update --session-key <sessionKey> --mission-id <mission_id> --summary "..." --phase execute`.
20
20
  During long mechanical stretches with nothing meaningful to post, send `ovld protocol heartbeat --session-key <sessionKey> --mission-id <mission_id> [--phase execute] [--percent <0-100>] [--note "..."]` instead of an empty update.
21
21
  5. Follow-up messages after the initial mission are captured automatically by the installed `UserPromptSubmit` hook and stay in discussion intent while the mission is in review. Do not post `user_follow_up` manually unless the hook is unavailable.
@@ -29,6 +29,7 @@ For full command syntax, flags, phase values, and event types see **CLI Command
29
29
  **Missions** represent whole features or goals. **Objectives** are the individual steps to implement that goal — one objective equals one agent prompt.
30
30
 
31
31
  Example:
32
+
32
33
  ```
33
34
  Mission: add CLI command for editing user profile
34
35
  - Objective 1: draft plan for this command
@@ -38,10 +39,12 @@ Mission: add CLI command for editing user profile
38
39
  ```
39
40
 
40
41
  When to create a mission vs an objective:
42
+
41
43
  - **Create a new mission** when the user describes a distinct feature, bug, or goal that stands on its own.
42
44
  - **Add objectives to an existing mission** when the work is a sequential step toward the same feature or goal already tracked in a mission.
43
45
 
44
46
  To add further objectives to an existing mission (Mode 2):
47
+
45
48
  ```
46
49
  ovld protocol add-objectives --mission-id <mission_id> --objectives-json '[{"objective":"..."},{"objective":"..."}]'
47
50
  ```
@@ -343,7 +346,7 @@ If `.overlord/project.json` contains more than one project, show the user the pr
343
346
 
344
347
  ## Change Rationales
345
348
 
346
- Always include `changeRationales` when delivering; optionally on updates during long-running work. Your job is rationale for *what* changed and why — the CLI captures *which* files changed (see **Deliver** above).
349
+ Always include `changeRationales` when delivering; optionally on updates during long-running work. Your job is rationale for _what_ changed and why — the CLI captures _which_ files changed (see **Deliver** above).
347
350
 
348
351
  - Rationales only for meaningful behavioral changes you made for this mission; skip formatting-only noise. Do not send `file_changes` as an artifact.
349
352
  - Do not include unrelated worktree changes in the delivery report, payload, artifacts, or rationales — even to label them pre-existing.
package/dist/index.js CHANGED
@@ -2986,7 +2986,7 @@ ${structured}`);
2986
2986
  }
2987
2987
  return parts.join(" \u2014 ");
2988
2988
  }
2989
- function createBackendClient() {
2989
+ function createBackendClient({ workspaceId } = {}) {
2990
2990
  const baseUrl = normalizeBaseUrl4(resolveBackendUrl(loadConfig()));
2991
2991
  const clientDevice = clientDeviceIdentity();
2992
2992
  async function request({
@@ -3009,6 +3009,7 @@ function createBackendClient() {
3009
3009
  "x-overlord-device-label": clientDevice.deviceLabel,
3010
3010
  "x-overlord-device-platform": clientDevice.devicePlatform,
3011
3011
  ...auth.headers,
3012
+ ...workspaceId ? { "X-Overlord-Active-Workspace": workspaceId } : {},
3012
3013
  ...extraHeaders
3013
3014
  },
3014
3015
  body: rawBody !== void 0 ? rawBody : body === void 0 ? void 0 : JSON.stringify(body)
@@ -3037,6 +3038,7 @@ Start the Desktop/local backend or run \`ovld config set cloud <url>\`.
3037
3038
  }
3038
3039
  return {
3039
3040
  baseUrl,
3041
+ forWorkspace: (nextWorkspaceId) => createBackendClient({ workspaceId: nextWorkspaceId }),
3040
3042
  health: () => request({ method: "GET", path: "/api/health" }),
3041
3043
  get: (path27) => request({ method: "GET", path: path27 }),
3042
3044
  post: ({ path: path27, body }) => request({ method: "POST", path: path27, body }),
@@ -4000,7 +4002,7 @@ function buildExecutionTargetMigrationDoctorCheck({
4000
4002
  name: "execution-target-migration",
4001
4003
  ok: false,
4002
4004
  required: false,
4003
- detail: `${targetSummary} use the hosted backend/container hostname fingerprint and cannot run checkout-local work.` + queueSummary + " In the web app, open Project Settings \u2192 Resources, re-select your client device as the execution target, re-link the primary resource to that target, and clear or re-queue stale execution requests. See docs/upgrading-client-checkout-bridge.md."
4005
+ detail: `${targetSummary} use the hosted backend/container hostname fingerprint and cannot run checkout-local work.` + queueSummary + " In the web app, open Project Settings \u2192 Resources, re-select your client device as the execution target, re-link the primary resource to that target, and clear or re-queue stale execution requests. See developer-instructions/upgrading-client-checkout-bridge.md."
4004
4006
  };
4005
4007
  }
4006
4008
  var init_execution_target_migration_doctor = __esm({
@@ -13195,8 +13197,9 @@ async function resolveMissionProjectSlug({
13195
13197
  const projectId = typeof mission.projectId === "string" ? mission.projectId.trim() : "";
13196
13198
  if (projectId) {
13197
13199
  try {
13198
- const projects = await runtime.backend.get("/api/projects");
13199
- const project = Array.isArray(projects) ? projects.find((candidate) => candidate.id === projectId) : null;
13200
+ const project = await runtime.backend.get(
13201
+ `/api/projects/${encodeURIComponent(projectId)}`
13202
+ );
13200
13203
  if (typeof project?.slug === "string" && project.slug.trim()) return project.slug.trim();
13201
13204
  } catch {
13202
13205
  }
@@ -13419,13 +13422,31 @@ async function resolveProjectByIdOrName({
13419
13422
  projectRef
13420
13423
  }) {
13421
13424
  const trimmed = projectRef.trim();
13422
- const projects = await backend.get("/api/projects");
13423
- const match = projects.find((project) => project.id === trimmed) ?? projects.find((project) => project.name === trimmed) ?? projects.find((project) => project.slug === trimmed);
13425
+ try {
13426
+ return await backend.get(`/api/projects/${encodeURIComponent(trimmed)}`);
13427
+ } catch (error) {
13428
+ if (!(error instanceof CliError) || !/project not found/i.test(error.message)) throw error;
13429
+ }
13430
+ const projects = await listAccessibleProjects({ backend });
13431
+ const match = projects.find((project) => project.name === trimmed) ?? projects.find((project) => project.slug === trimmed);
13424
13432
  if (!match) {
13425
13433
  throw new CliError({ message: `Project not found: ${trimmed}` });
13426
13434
  }
13427
13435
  return match;
13428
13436
  }
13437
+ async function listAccessibleProjects({
13438
+ backend
13439
+ }) {
13440
+ const workspaces = await backend.get("/api/workspaces");
13441
+ const projectLists = await Promise.all(
13442
+ workspaces.map(
13443
+ (workspace) => backend.get(`/api/workspaces/${encodeURIComponent(workspace.id)}/projects`)
13444
+ )
13445
+ );
13446
+ const projects = /* @__PURE__ */ new Map();
13447
+ for (const project of projectLists.flat()) projects.set(project.id, project);
13448
+ return [...projects.values()];
13449
+ }
13429
13450
  async function discoverProjectOnClient({
13430
13451
  backend,
13431
13452
  workingDirectory,
@@ -13799,6 +13820,7 @@ async function loadMissionContext({
13799
13820
  "",
13800
13821
  "## Instructions",
13801
13822
  "Use the Overlord skill. Follow the required protocol workflow.",
13823
+ EXECUTION_DIRECTIVE,
13802
13824
  "",
13803
13825
  "## Objectives",
13804
13826
  ...objectives.map((objective, index) => {
@@ -13917,7 +13939,7 @@ Execution request: ${options.executionRequestId}` : context.launchContext;
13917
13939
  executionRequestId: options.executionRequestId,
13918
13940
  projectResources
13919
13941
  });
13920
- const prompt = launchContext.length > 4e3 ? `Use the Overlord context file at ${contextFile} and attach to mission ${context.displayId}.` : launchContext;
13942
+ const prompt = launchContext.length > 4e3 ? `Read the Overlord context file at ${contextFile}, attach to mission ${context.displayId}, then immediately execute its current objective. Do not wait for more instructions.` : launchContext;
13921
13943
  const command = buildAgentCommand({
13922
13944
  agent: options.agent,
13923
13945
  model: options.model,
@@ -13925,7 +13947,7 @@ Execution request: ${options.executionRequestId}` : context.launchContext;
13925
13947
  flags: options.flags,
13926
13948
  prompt,
13927
13949
  contextFile,
13928
- launchMessage: `Start work on ${context.title} (ovld mission ${context.displayId})`
13950
+ launchMessage: `Attach to ovld mission ${context.displayId}, then immediately execute ${context.title}. Do not wait for more instructions.`
13929
13951
  });
13930
13952
  const terminalScriptPath = options.terminalLauncher?.trim() ? launchScriptPath({
13931
13953
  tmpDir,
@@ -13991,7 +14013,7 @@ async function launchAgent({
13991
14013
  });
13992
14014
  return { plan, status: result.status, signal: result.signal };
13993
14015
  }
13994
- var AGENT_HISTORY_EXCLUDED_EVENT_TYPES;
14016
+ var AGENT_HISTORY_EXCLUDED_EVENT_TYPES, EXECUTION_DIRECTIVE;
13995
14017
  var init_launch = __esm({
13996
14018
  "src/launch.ts"() {
13997
14019
  "use strict";
@@ -14003,6 +14025,7 @@ var init_launch = __esm({
14003
14025
  "execution_requested",
14004
14026
  "awaiting_approval"
14005
14027
  ]);
14028
+ EXECUTION_DIRECTIVE = "This is an execution session. After attaching, immediately execute the current objective. Do not wait for more instructions or ask for confirmation; only stop to ask a question when blocked.";
14006
14029
  }
14007
14030
  });
14008
14031
 
@@ -16427,7 +16450,7 @@ async function resolveProtocolFileInputs({
16427
16450
  }
16428
16451
  async function discoverProjectId(runtime, explicit) {
16429
16452
  if (explicit) return explicit;
16430
- const projects = await runtime.backend.get("/api/projects");
16453
+ const projects = await listAccessibleProjects({ backend: runtime.backend });
16431
16454
  const first = projects[0];
16432
16455
  const id = asRecord2(first).id;
16433
16456
  if (typeof id !== "string") {
@@ -16533,22 +16556,42 @@ async function runProtocolCommand({
16533
16556
  flags["--execution-target-id"] = preferredTargetId;
16534
16557
  }
16535
16558
  }
16536
- const result = await runtime.backend.post({
16537
- path: `/api/protocol/${encodeURIComponent(subcommand)}`,
16538
- body: {
16539
- args,
16540
- positional: parsed.positional,
16541
- flags,
16542
- stdin: protocolStdin,
16543
- fileInputs,
16544
- externalSessionId: flagValue(parsed.flags, "--external-session-id") ?? resolveNativeSessionId({
16545
- explicit: void 0,
16546
- agent: flagValue(parsed.flags, "--agent") ?? "unknown",
16547
- missionId: flagValue(parsed.flags, "--mission-id") ?? "unknown",
16548
- workingDirectory
16549
- })
16550
- }
16551
- });
16559
+ const protocolBody = {
16560
+ args,
16561
+ positional: parsed.positional,
16562
+ flags,
16563
+ stdin: protocolStdin,
16564
+ fileInputs,
16565
+ externalSessionId: flagValue(parsed.flags, "--external-session-id") ?? resolveNativeSessionId({
16566
+ explicit: void 0,
16567
+ agent: flagValue(parsed.flags, "--agent") ?? "unknown",
16568
+ missionId: flagValue(parsed.flags, "--mission-id") ?? "unknown",
16569
+ workingDirectory
16570
+ })
16571
+ };
16572
+ let result;
16573
+ if (subcommand === "search-missions" && !flagValue(parsed.flags, "--project-id")) {
16574
+ const workspaces = await runtime.backend.get("/api/workspaces");
16575
+ const perWorkspace = await Promise.all(
16576
+ workspaces.map(
16577
+ (workspace) => runtime.backend.forWorkspace(workspace.id).post({
16578
+ path: "/api/protocol/search-missions",
16579
+ body: protocolBody
16580
+ })
16581
+ )
16582
+ );
16583
+ const limit = Number.parseInt(flagValue(parsed.flags, "--limit") ?? "25", 10);
16584
+ result = perWorkspace.flat().sort((left, right) => {
16585
+ const leftUpdated = String(asRecord2(left).updatedAt ?? "");
16586
+ const rightUpdated = String(asRecord2(right).updatedAt ?? "");
16587
+ return rightUpdated.localeCompare(leftUpdated);
16588
+ }).slice(0, Number.isFinite(limit) ? limit : 25);
16589
+ } else {
16590
+ result = await runtime.backend.post({
16591
+ path: `/api/protocol/${encodeURIComponent(subcommand)}`,
16592
+ body: protocolBody
16593
+ });
16594
+ }
16552
16595
  if ((subcommand === "attach" || subcommand === "resume-follow-up") && missionId) {
16553
16596
  writeBaseline({
16554
16597
  workingDirectory,
@@ -16671,7 +16714,7 @@ async function runManagementCommand({
16671
16714
  const resourceKey = flagValue(parsed.flags, "--key") ?? existingProjectJson?.resourceKey;
16672
16715
  let projectId = flagValue(parsed.flags, "--project-id");
16673
16716
  if (!projectId) {
16674
- const allProjects = await runtime.backend.get("/api/projects");
16717
+ const allProjects = await listAccessibleProjects({ backend: runtime.backend });
16675
16718
  const projects = allProjects.filter((project) => project.status !== "archived");
16676
16719
  if (projects.length === 0) {
16677
16720
  throw new CliError({
@@ -16803,34 +16846,39 @@ async function runManagementCommand({
16803
16846
  throw new CliError({ message: `Usage: ovld ${command} <agent> --mission-id <missionId>` });
16804
16847
  }
16805
16848
  const workingDirectory = flagValue(parsed.flags, "--working-directory") ?? process.cwd();
16806
- const terminal = await resolveTerminalLaunchSettings({ runtime, flags: parsed.flags });
16807
16849
  const dryRun = flagBoolean(parsed.flags, "--dry-run");
16808
16850
  const mission = await runtime.backend.get(
16809
16851
  `/api/missions/${encodeURIComponent(missionId)}`
16810
16852
  );
16853
+ const missionWorkspaceId = asRecord2(mission).workspaceId;
16854
+ const scopedRuntime = typeof missionWorkspaceId === "string" ? { ...runtime, backend: runtime.backend.forWorkspace(missionWorkspaceId) } : runtime;
16855
+ const terminal = await resolveTerminalLaunchSettings({
16856
+ runtime: scopedRuntime,
16857
+ flags: parsed.flags
16858
+ });
16811
16859
  const objectiveId = flagValue(parsed.flags, "--objective-id") ?? launchableObjectiveId(mission);
16812
16860
  const executionTargetId = await resolvePreferredExecutionTargetId({
16813
- backend: runtime.backend
16861
+ backend: scopedRuntime.backend
16814
16862
  });
16815
16863
  const prepared = await prepareMissionBranch({
16816
- runtime,
16864
+ runtime: scopedRuntime,
16817
16865
  options: {
16818
16866
  missionId,
16819
16867
  workingDirectory,
16820
16868
  objectiveId: objectiveId ?? void 0,
16821
- workspaceAutomationEnabled: await readWorktreeBranchAutomationEnabled(runtime),
16869
+ workspaceAutomationEnabled: await readWorktreeBranchAutomationEnabled(scopedRuntime),
16822
16870
  dryRun,
16823
16871
  overrideBranch: flagValue(parsed.flags, "--branch"),
16824
16872
  noWorktree: flagBoolean(parsed.flags, "--no-worktree")
16825
16873
  }
16826
16874
  });
16827
16875
  await recordBranchPrepared({
16828
- runtime,
16876
+ runtime: scopedRuntime,
16829
16877
  missionId,
16830
16878
  branchAutomation: prepared.branchAutomation
16831
16879
  });
16832
16880
  const result = await launchAgent({
16833
- runtime,
16881
+ runtime: scopedRuntime,
16834
16882
  options: {
16835
16883
  agent,
16836
16884
  missionId,
@@ -16870,10 +16918,27 @@ async function runManagementCommand({
16870
16918
  if (query) params.set("q", query);
16871
16919
  if (projectId) params.set("projectId", projectId);
16872
16920
  if (limit) params.set("limit", limit);
16873
- const result = await runtime.backend.get(
16874
- `/api/missions/search?${params}`
16875
- );
16876
- const missions = result.missions;
16921
+ let missions;
16922
+ if (projectId) {
16923
+ const project = await runtime.backend.get(
16924
+ `/api/projects/${encodeURIComponent(projectId)}`
16925
+ );
16926
+ const result = await runtime.backend.forWorkspace(project.workspaceId).get(`/api/missions/search?${params}`);
16927
+ missions = result.missions;
16928
+ } else {
16929
+ const workspaces = await runtime.backend.get("/api/workspaces");
16930
+ const results = await Promise.all(
16931
+ workspaces.map(
16932
+ (workspace) => runtime.backend.forWorkspace(workspace.id).get(`/api/missions/search?${params}`)
16933
+ )
16934
+ );
16935
+ const parsedLimit = Number.parseInt(limit ?? "25", 10);
16936
+ missions = results.flatMap((result) => result.missions).sort(
16937
+ (left, right) => String(asRecord2(right).updatedAt ?? "").localeCompare(
16938
+ String(asRecord2(left).updatedAt ?? "")
16939
+ )
16940
+ ).slice(0, Number.isFinite(parsedLimit) ? parsedLimit : 25);
16941
+ }
16877
16942
  if (json) printJson({ missions });
16878
16943
  else {
16879
16944
  for (const mission of missions) {