@coresource/hz 0.1.6 → 0.1.8

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 (2) hide show
  1. package/dist/hz.mjs +138 -69
  2. package/package.json +1 -1
package/dist/hz.mjs CHANGED
@@ -505,6 +505,9 @@ function registerAuthCommands(program, context) {
505
505
  });
506
506
  }
507
507
 
508
+ // src/commands/mission-info.ts
509
+ import pc2 from "picocolors";
510
+
508
511
  // src/commands/mission-support.ts
509
512
  import pc from "picocolors";
510
513
  function isRecord(value) {
@@ -720,6 +723,69 @@ function renderTable(stdout, headers, rows) {
720
723
  }
721
724
  }
722
725
 
726
+ // src/commands/mission-info.ts
727
+ function statusColor(status) {
728
+ switch (status) {
729
+ case "passed":
730
+ case "completed":
731
+ return pc2.green(status);
732
+ case "failed":
733
+ case "needs_triage":
734
+ return pc2.red(status);
735
+ case "running":
736
+ case "dispatched":
737
+ return pc2.cyan(status);
738
+ case "pending":
739
+ return pc2.dim(status);
740
+ default:
741
+ return status;
742
+ }
743
+ }
744
+ function renderFeatures(stdout, features) {
745
+ if (features.length === 0) {
746
+ writeLine(stdout, "No features.");
747
+ return;
748
+ }
749
+ renderTable(
750
+ stdout,
751
+ ["Feature", "Milestone", "Status"],
752
+ features.map((f) => [
753
+ plainCell(f.id),
754
+ plainCell(f.milestone ?? "\u2014"),
755
+ coloredCell(statusColor(f.status), f.status)
756
+ ])
757
+ );
758
+ }
759
+ function renderAssertions(stdout, assertions) {
760
+ if (assertions.length === 0) {
761
+ writeLine(stdout, "No assertions.");
762
+ return;
763
+ }
764
+ renderTable(
765
+ stdout,
766
+ ["Assertion", "Milestone", "Status"],
767
+ assertions.map((a) => [
768
+ plainCell(a.id),
769
+ plainCell(a.milestone ?? "\u2014"),
770
+ coloredCell(statusColor(a.status), a.status)
771
+ ])
772
+ );
773
+ }
774
+ function registerMissionInfoCommand(mission, context, dependencies = {}) {
775
+ mission.command("info").description("Show features and assertions for a mission").argument("<missionId>").action(async (missionId, command) => {
776
+ const apiClient = await createMissionApiClient(context, command, dependencies);
777
+ const [features, assertions] = await Promise.all([
778
+ apiClient.request({ path: `/missions/${missionId}/features` }).then((value) => normalizeMissionFeatures(value)),
779
+ apiClient.request({ path: `/missions/${missionId}/assertions` }).then((value) => normalizeMissionAssertions(value))
780
+ ]);
781
+ writeLine(context.stdout, pc2.bold("Features"));
782
+ renderFeatures(context.stdout, features);
783
+ writeLine(context.stdout);
784
+ writeLine(context.stdout, pc2.bold("Assertions"));
785
+ renderAssertions(context.stdout, assertions);
786
+ });
787
+ }
788
+
723
789
  // src/commands/mission-list.ts
724
790
  function registerMissionListCommand(mission, context, dependencies = {}) {
725
791
  mission.command("list").description("List recent missions").action(async (_options, command) => {
@@ -758,12 +824,12 @@ function registerMissionListCommand(mission, context, dependencies = {}) {
758
824
  import { readdir as readdir2, readFile as readFile3, stat } from "fs/promises";
759
825
  import path3 from "path";
760
826
  import { CommanderError } from "commander";
761
- import pc4 from "picocolors";
827
+ import pc5 from "picocolors";
762
828
 
763
829
  // src/monitor.ts
764
830
  import { setTimeout as delay2 } from "timers/promises";
765
831
  import ora from "ora";
766
- import pc3 from "picocolors";
832
+ import pc4 from "picocolors";
767
833
  import WebSocket from "ws";
768
834
 
769
835
  // src/state.ts
@@ -1530,7 +1596,7 @@ import {
1530
1596
  input as defaultInputPrompt,
1531
1597
  select as defaultSelectPrompt
1532
1598
  } from "@inquirer/prompts";
1533
- import pc2 from "picocolors";
1599
+ import pc3 from "picocolors";
1534
1600
  var TRIAGE_PROGRESS_PAGE_SIZE = 200;
1535
1601
  var AUTO_DISMISS_RATIONALE = "Auto-dismissed by `hz mission run --yes`.";
1536
1602
  function isRecord3(value) {
@@ -1745,7 +1811,7 @@ function buildTriageItem(feature, allAssertions, suggestedActionsByFeature) {
1745
1811
  }
1746
1812
  function writeItemBlock(stdout, item) {
1747
1813
  writeLine(stdout);
1748
- writeLine(stdout, pc2.bold(`Triage required for ${pc2.cyan(item.feature.id)}`));
1814
+ writeLine(stdout, pc3.bold(`Triage required for ${pc3.cyan(item.feature.id)}`));
1749
1815
  writeLine(stdout, `Failure: ${item.failureDescription}`);
1750
1816
  writeLine(
1751
1817
  stdout,
@@ -1897,7 +1963,7 @@ async function runTriageInteraction(options) {
1897
1963
  ]);
1898
1964
  const triageItems = features.filter((feature) => feature.status === "needs_triage").map((feature) => buildTriageItem(feature, assertions, suggestedActionsByFeature));
1899
1965
  if (triageItems.length === 0) {
1900
- writeLine(options.stdout, pc2.dim("No outstanding triage items were found."));
1966
+ writeLine(options.stdout, pc3.dim("No outstanding triage items were found."));
1901
1967
  return {
1902
1968
  createdFixes: 0,
1903
1969
  dismissed: 0,
@@ -1910,7 +1976,7 @@ async function runTriageInteraction(options) {
1910
1976
  if (options.autoApprove) {
1911
1977
  writeLine(
1912
1978
  options.stdout,
1913
- pc2.yellow(
1979
+ pc3.yellow(
1914
1980
  `Auto-dismissing triage items: ${triageItems.map((item) => item.feature.id).join(", ")}`
1915
1981
  )
1916
1982
  );
@@ -1955,7 +2021,7 @@ async function runTriageInteraction(options) {
1955
2021
  });
1956
2022
  await dismissItem(options.apiClient, options.missionId, item, rationale);
1957
2023
  result.dismissed += 1;
1958
- writeLine(options.stdout, `Dismissed triage for ${pc2.cyan(item.feature.id)}.`);
2024
+ writeLine(options.stdout, `Dismissed triage for ${pc3.cyan(item.feature.id)}.`);
1959
2025
  break;
1960
2026
  }
1961
2027
  case "create-fix": {
@@ -1982,7 +2048,7 @@ async function runTriageInteraction(options) {
1982
2048
  result.createdFixes += 1;
1983
2049
  writeLine(
1984
2050
  options.stdout,
1985
- `Created fix feature ${pc2.cyan(createdFeature.id)} for ${pc2.cyan(item.feature.id)}.`
2051
+ `Created fix feature ${pc3.cyan(createdFeature.id)} for ${pc3.cyan(item.feature.id)}.`
1986
2052
  );
1987
2053
  break;
1988
2054
  }
@@ -1998,8 +2064,8 @@ async function runTriageInteraction(options) {
1998
2064
  result.skipped += 1;
1999
2065
  writeLine(
2000
2066
  options.stdout,
2001
- pc2.yellow(
2002
- `No assertions were reassigned for ${pc2.cyan(item.feature.id)}.`
2067
+ pc3.yellow(
2068
+ `No assertions were reassigned for ${pc3.cyan(item.feature.id)}.`
2003
2069
  )
2004
2070
  );
2005
2071
  break;
@@ -2007,7 +2073,7 @@ async function runTriageInteraction(options) {
2007
2073
  result.movedAssertions += moved;
2008
2074
  writeLine(
2009
2075
  options.stdout,
2010
- `Reassigned ${moved} assertion${moved === 1 ? "" : "s"} for ${pc2.cyan(item.feature.id)}.`
2076
+ `Reassigned ${moved} assertion${moved === 1 ? "" : "s"} for ${pc3.cyan(item.feature.id)}.`
2011
2077
  );
2012
2078
  break;
2013
2079
  }
@@ -2016,7 +2082,7 @@ async function runTriageInteraction(options) {
2016
2082
  result.skipped += 1;
2017
2083
  writeLine(
2018
2084
  options.stdout,
2019
- pc2.dim(`Skipped triage for ${item.feature.id}; it will remain unresolved.`)
2085
+ pc3.dim(`Skipped triage for ${item.feature.id}; it will remain unresolved.`)
2020
2086
  );
2021
2087
  break;
2022
2088
  }
@@ -2123,7 +2189,7 @@ function formatSummaryLine(summary) {
2123
2189
  return `${summary.completedFeatures}/${summary.totalFeatures} features \xB7 ${summary.passedAssertions}/${summary.totalAssertions} assertions`;
2124
2190
  }
2125
2191
  function formatSpinnerText(missionId, summary) {
2126
- return `${pc3.cyan(missionId)} ${pc3.bold(summary.state)} \xB7 ${formatSummaryLine(summary)}`;
2192
+ return `${pc4.cyan(missionId)} ${pc4.bold(summary.state)} \xB7 ${formatSummaryLine(summary)}`;
2127
2193
  }
2128
2194
  function normalizeSummary(missionId, value) {
2129
2195
  if (!isRecord4(value)) {
@@ -2186,13 +2252,13 @@ function buildBackfillDescription(event) {
2186
2252
  const milestone = asNonEmptyString4(data.milestone);
2187
2253
  const assertionId = asNonEmptyString4(data.assertionId);
2188
2254
  if (featureId) {
2189
- return `Backfilled ${type} for ${pc3.cyan(featureId)}.`;
2255
+ return `Backfilled ${type} for ${pc4.cyan(featureId)}.`;
2190
2256
  }
2191
2257
  if (assertionId) {
2192
- return `Backfilled ${type} for ${pc3.cyan(assertionId)}.`;
2258
+ return `Backfilled ${type} for ${pc4.cyan(assertionId)}.`;
2193
2259
  }
2194
2260
  if (milestone) {
2195
- return `Backfilled ${type} for milestone ${pc3.cyan(milestone)}.`;
2261
+ return `Backfilled ${type} for milestone ${pc4.cyan(milestone)}.`;
2196
2262
  }
2197
2263
  return `Backfilled ${type}.`;
2198
2264
  }
@@ -2253,7 +2319,7 @@ async function monitorMission(options) {
2253
2319
  spinner.start();
2254
2320
  writeLine(
2255
2321
  options.stdout,
2256
- `Monitoring mission ${pc3.cyan(options.missionId)} \xB7 ${formatSummaryLine(summary)}`
2322
+ `Monitoring mission ${pc4.cyan(options.missionId)} \xB7 ${formatSummaryLine(summary)}`
2257
2323
  );
2258
2324
  const updateSpinner = () => {
2259
2325
  spinner.text = formatSpinnerText(options.missionId, summary);
@@ -2268,7 +2334,7 @@ async function monitorMission(options) {
2268
2334
  await refreshSummary();
2269
2335
  const message = `Mission completed \xB7 ${formatSummaryLine(summary)}`;
2270
2336
  spinner.succeed(message);
2271
- writeLine(options.stdout, pc3.green(message));
2337
+ writeLine(options.stdout, pc4.green(message));
2272
2338
  return {
2273
2339
  exitCode: 0,
2274
2340
  reason: "completed",
@@ -2280,7 +2346,7 @@ async function monitorMission(options) {
2280
2346
  await refreshSummary();
2281
2347
  const message = `Budget exceeded \xB7 ${formatBudgetUsage(details)}`;
2282
2348
  spinner.fail(message);
2283
- writeLine(options.stdout, pc3.red(message));
2349
+ writeLine(options.stdout, pc4.red(message));
2284
2350
  return {
2285
2351
  exitCode: 1,
2286
2352
  reason: "budget_exceeded",
@@ -2304,12 +2370,12 @@ async function monitorMission(options) {
2304
2370
  if (triageResult.totalItems === 0) {
2305
2371
  writeLine(
2306
2372
  options.stdout,
2307
- pc3.dim("No triage items required action. Resuming the orchestration loop.")
2373
+ pc4.dim("No triage items required action. Resuming the orchestration loop.")
2308
2374
  );
2309
2375
  } else {
2310
2376
  writeLine(
2311
2377
  options.stdout,
2312
- pc3.green(
2378
+ pc4.green(
2313
2379
  `Triage complete \xB7 ${triageResult.dismissed} dismissed \xB7 ${triageResult.createdFixes} fix features \xB7 ${triageResult.movedAssertions} assertions moved \xB7 ${triageResult.skipped} skipped`
2314
2380
  )
2315
2381
  );
@@ -2325,7 +2391,7 @@ async function monitorMission(options) {
2325
2391
  spinner.fail("Monitoring stopped.");
2326
2392
  writeLine(
2327
2393
  options.stdout,
2328
- pc3.yellow("Interrupted. Local state is saved. Remote mission continues.")
2394
+ pc4.yellow("Interrupted. Local state is saved. Remote mission continues.")
2329
2395
  );
2330
2396
  return {
2331
2397
  exitCode: 130,
@@ -2344,13 +2410,13 @@ async function monitorMission(options) {
2344
2410
  case "dispatched":
2345
2411
  writeLine(
2346
2412
  options.stdout,
2347
- `Dispatching ${pc3.cyan(result.featureId)} (${pc3.dim(result.workerSessionId)}).`
2413
+ `Dispatching ${pc4.cyan(result.featureId)} (${pc4.dim(result.workerSessionId)}).`
2348
2414
  );
2349
2415
  return null;
2350
2416
  case "no_work":
2351
2417
  writeLine(
2352
2418
  options.stdout,
2353
- pc3.dim("No eligible work is available yet. Waiting for updates.")
2419
+ pc4.dim("No eligible work is available yet. Waiting for updates.")
2354
2420
  );
2355
2421
  return null;
2356
2422
  case "completed":
@@ -2391,7 +2457,7 @@ async function monitorMission(options) {
2391
2457
  reconnectAttempt += 1;
2392
2458
  writeLine(
2393
2459
  options.stdout,
2394
- pc3.yellow(
2460
+ pc4.yellow(
2395
2461
  `WebSocket connection failed: ${error instanceof Error ? error.message : String(error)}. Reconnecting in ${delayMs2} ms...`
2396
2462
  )
2397
2463
  );
@@ -2426,7 +2492,7 @@ async function monitorMission(options) {
2426
2492
  switch (type) {
2427
2493
  case "state_changed": {
2428
2494
  const state = asNonEmptyString4(data.state) ?? "unknown";
2429
- writeLine(options.stdout, `Mission state \u2192 ${pc3.cyan(state)}`);
2495
+ writeLine(options.stdout, `Mission state \u2192 ${pc4.cyan(state)}`);
2430
2496
  await refreshSummary();
2431
2497
  if (state === "completed") {
2432
2498
  return completedResult();
@@ -2444,7 +2510,7 @@ async function monitorMission(options) {
2444
2510
  }
2445
2511
  writeLine(
2446
2512
  options.stdout,
2447
- `Feature ${pc3.cyan(featureId)} \u2192 ${pc3.bold(status)}`
2513
+ `Feature ${pc4.cyan(featureId)} \u2192 ${pc4.bold(status)}`
2448
2514
  );
2449
2515
  await refreshSummary();
2450
2516
  return null;
@@ -2454,7 +2520,7 @@ async function monitorMission(options) {
2454
2520
  const status = asNonEmptyString4(data.status) ?? "updated";
2455
2521
  writeLine(
2456
2522
  options.stdout,
2457
- `Milestone ${pc3.cyan(milestone)} \u2192 ${pc3.bold(status)}`
2523
+ `Milestone ${pc4.cyan(milestone)} \u2192 ${pc4.bold(status)}`
2458
2524
  );
2459
2525
  await refreshSummary();
2460
2526
  return null;
@@ -2464,7 +2530,7 @@ async function monitorMission(options) {
2464
2530
  const status = asNonEmptyString4(data.status) ?? "updated";
2465
2531
  writeLine(
2466
2532
  options.stdout,
2467
- `Assertion ${pc3.cyan(assertionId)} \u2192 ${pc3.bold(status)}`
2533
+ `Assertion ${pc4.cyan(assertionId)} \u2192 ${pc4.bold(status)}`
2468
2534
  );
2469
2535
  await refreshSummary();
2470
2536
  return null;
@@ -2474,7 +2540,7 @@ async function monitorMission(options) {
2474
2540
  const status = asNonEmptyString4(data.status) ?? "received";
2475
2541
  writeLine(
2476
2542
  options.stdout,
2477
- `Handoff received for ${pc3.cyan(featureId)} (${status}).`
2543
+ `Handoff received for ${pc4.cyan(featureId)} (${status}).`
2478
2544
  );
2479
2545
  return null;
2480
2546
  }
@@ -2483,8 +2549,8 @@ async function monitorMission(options) {
2483
2549
  const featureId = asNonEmptyString4(data.featureId) ?? "feature";
2484
2550
  writeLine(
2485
2551
  options.stdout,
2486
- pc3.yellow(
2487
- `Triage is required for ${pc3.cyan(featureId)}. Auto-start is paused.`
2552
+ pc4.yellow(
2553
+ `Triage is required for ${pc4.cyan(featureId)}. Auto-start is paused.`
2488
2554
  )
2489
2555
  );
2490
2556
  return completeTriage();
@@ -2493,7 +2559,7 @@ async function monitorMission(options) {
2493
2559
  const featureId = asNonEmptyString4(data.featureId) ?? "feature";
2494
2560
  writeLine(
2495
2561
  options.stdout,
2496
- pc3.yellow(`Worker timed out for ${pc3.cyan(featureId)}.`)
2562
+ pc4.yellow(`Worker timed out for ${pc4.cyan(featureId)}.`)
2497
2563
  );
2498
2564
  await refreshSummary();
2499
2565
  return null;
@@ -2502,7 +2568,7 @@ async function monitorMission(options) {
2502
2568
  const details = normalizeBudgetDetails(data);
2503
2569
  writeLine(
2504
2570
  options.stdout,
2505
- pc3.yellow(`Budget warning \xB7 ${formatBudgetUsage(details)}`)
2571
+ pc4.yellow(`Budget warning \xB7 ${formatBudgetUsage(details)}`)
2506
2572
  );
2507
2573
  await refreshSummary();
2508
2574
  return null;
@@ -2528,7 +2594,7 @@ async function monitorMission(options) {
2528
2594
  }).catch((error) => {
2529
2595
  writeLine(
2530
2596
  options.stdout,
2531
- pc3.yellow(
2597
+ pc4.yellow(
2532
2598
  `Monitoring update failed: ${error instanceof Error ? error.message : String(error)}. Reconnecting...`
2533
2599
  )
2534
2600
  );
@@ -2539,7 +2605,7 @@ async function monitorMission(options) {
2539
2605
  socket.on("error", (error) => {
2540
2606
  writeLine(
2541
2607
  options.stdout,
2542
- pc3.yellow(
2608
+ pc4.yellow(
2543
2609
  `WebSocket error: ${error instanceof Error ? error.message : String(error)}`
2544
2610
  )
2545
2611
  );
@@ -2567,7 +2633,7 @@ async function monitorMission(options) {
2567
2633
  continue;
2568
2634
  }
2569
2635
  lastSeen = Math.max(lastSeen, asFiniteNumber3(event.seq));
2570
- writeLine(options.stdout, pc3.dim(buildBackfillDescription(event)));
2636
+ writeLine(options.stdout, pc4.dim(buildBackfillDescription(event)));
2571
2637
  }
2572
2638
  }
2573
2639
  connectedOnce = true;
@@ -2591,7 +2657,7 @@ async function monitorMission(options) {
2591
2657
  reconnectAttempt += 1;
2592
2658
  writeLine(
2593
2659
  options.stdout,
2594
- pc3.yellow(`Reconnecting to mission updates in ${delayMs} ms...`)
2660
+ pc4.yellow(`Reconnecting to mission updates in ${delayMs} ms...`)
2595
2661
  );
2596
2662
  await sleep(delayMs);
2597
2663
  }
@@ -2607,7 +2673,7 @@ function asNonEmptyString5(value) {
2607
2673
  }
2608
2674
  function writeSection(stdout, title) {
2609
2675
  writeLine(stdout);
2610
- writeLine(stdout, pc4.bold(title));
2676
+ writeLine(stdout, pc5.bold(title));
2611
2677
  }
2612
2678
  function summarizeAssertions(assertions) {
2613
2679
  return assertions.reduce(
@@ -2752,7 +2818,7 @@ async function resolveMissionId(missionId, context, command, homeDir) {
2752
2818
  if (detectedMissionId) {
2753
2819
  writeLine(
2754
2820
  context.stdout,
2755
- `Using the most recent local mission: ${pc4.cyan(detectedMissionId)}`
2821
+ `Using the most recent local mission: ${pc5.cyan(detectedMissionId)}`
2756
2822
  );
2757
2823
  return detectedMissionId;
2758
2824
  }
@@ -2787,6 +2853,7 @@ async function runLifecycleMutation(action, missionIdValue, command, context, de
2787
2853
  );
2788
2854
  try {
2789
2855
  const response = await apiClient.request({
2856
+ body: {},
2790
2857
  method: "POST",
2791
2858
  path: `/missions/${missionId}/mission/${action}`
2792
2859
  });
@@ -2794,13 +2861,13 @@ async function runLifecycleMutation(action, missionIdValue, command, context, de
2794
2861
  if (action === "pause") {
2795
2862
  writeLine(
2796
2863
  context.stdout,
2797
- `Mission ${pc4.cyan(missionId)} paused. Current state: ${pc4.bold(nextState)}.`
2864
+ `Mission ${pc5.cyan(missionId)} paused. Current state: ${pc5.bold(nextState)}.`
2798
2865
  );
2799
2866
  return;
2800
2867
  }
2801
2868
  writeLine(
2802
2869
  context.stdout,
2803
- `Mission ${pc4.cyan(missionId)} cancelled. This action is irreversible. Current state: ${pc4.bold(nextState)}.`
2870
+ `Mission ${pc5.cyan(missionId)} cancelled. This action is irreversible. Current state: ${pc5.bold(nextState)}.`
2804
2871
  );
2805
2872
  } catch (error) {
2806
2873
  if (!(error instanceof ApiError) || error.status !== 409) {
@@ -2814,7 +2881,7 @@ async function runLifecycleMutation(action, missionIdValue, command, context, de
2814
2881
  const verb = action === "pause" ? "paused" : "cancelled";
2815
2882
  writeLine(
2816
2883
  context.stdout,
2817
- `Mission ${pc4.cyan(missionId)} cannot be ${verb} because it is currently ${pc4.bold(missionState.state)}.`
2884
+ `Mission ${pc5.cyan(missionId)} cannot be ${verb} because it is currently ${pc5.bold(missionState.state)}.`
2818
2885
  );
2819
2886
  throw new CommanderError(1, `mission-${action}`, "");
2820
2887
  }
@@ -2844,13 +2911,14 @@ async function runMissionResume(missionIdValue, command, context, dependencies)
2844
2911
  if (snapshot.state.state === "paused") {
2845
2912
  try {
2846
2913
  const response = await apiClient.request({
2914
+ body: {},
2847
2915
  method: "POST",
2848
2916
  path: `/missions/${missionId}/mission/resume`
2849
2917
  });
2850
2918
  const nextState = asNonEmptyString5(response.state) ?? "orchestrator_turn";
2851
2919
  writeLine(
2852
2920
  context.stdout,
2853
- `Mission ${pc4.cyan(missionId)} resumed. Current state: ${pc4.bold(nextState)}.`
2921
+ `Mission ${pc5.cyan(missionId)} resumed. Current state: ${pc5.bold(nextState)}.`
2854
2922
  );
2855
2923
  } catch (error) {
2856
2924
  if (!(error instanceof ApiError) || error.status !== 409) {
@@ -2863,14 +2931,14 @@ async function runMissionResume(missionIdValue, command, context, dependencies)
2863
2931
  );
2864
2932
  writeLine(
2865
2933
  context.stdout,
2866
- `Mission ${pc4.cyan(missionId)} is currently ${pc4.bold(snapshot.state.state)}. Reconnecting to live updates if available.`
2934
+ `Mission ${pc5.cyan(missionId)} is currently ${pc5.bold(snapshot.state.state)}. Reconnecting to live updates if available.`
2867
2935
  );
2868
2936
  }
2869
2937
  snapshot = await fetchMissionSnapshot(apiClient, missionId);
2870
2938
  } else if (snapshot.state.state !== "cancelled" && snapshot.state.state !== "completed") {
2871
2939
  writeLine(
2872
2940
  context.stdout,
2873
- `Reconnecting to mission ${pc4.cyan(missionId)} from state ${pc4.bold(snapshot.state.state)}.`
2941
+ `Reconnecting to mission ${pc5.cyan(missionId)} from state ${pc5.bold(snapshot.state.state)}.`
2874
2942
  );
2875
2943
  }
2876
2944
  renderMissionSnapshot(context.stdout, snapshot);
@@ -2963,7 +3031,7 @@ import {
2963
3031
  select as defaultSelectPrompt2
2964
3032
  } from "@inquirer/prompts";
2965
3033
  import ora2 from "ora";
2966
- import pc5 from "picocolors";
3034
+ import pc6 from "picocolors";
2967
3035
  var DEFAULT_ANALYSIS_TIMEOUT_MS = 5 * 60 * 1e3;
2968
3036
  var DEFAULT_POLL_INTERVAL_MS = 5e3;
2969
3037
  var FREE_TEXT_OPTION_ID = "free_text";
@@ -3130,18 +3198,18 @@ async function postDraftApproval(client, sessionId) {
3130
3198
  }
3131
3199
  function writeSection2(stdout, title) {
3132
3200
  writeLine(stdout);
3133
- writeLine(stdout, pc5.bold(title));
3201
+ writeLine(stdout, pc6.bold(title));
3134
3202
  }
3135
3203
  function renderQuestion(stdout, question, index) {
3136
3204
  writeLine(stdout, `${index + 1}. ${question.text}`);
3137
3205
  if (question.references && question.references.length > 0) {
3138
- writeLine(stdout, ` ${pc5.dim(`References: ${question.references.join(", ")}`)}`);
3206
+ writeLine(stdout, ` ${pc6.dim(`References: ${question.references.join(", ")}`)}`);
3139
3207
  }
3140
3208
  }
3141
3209
  function renderMilestones(stdout, milestones, reviewRound) {
3142
3210
  writeSection2(stdout, `Milestone review round ${reviewRound}`);
3143
3211
  milestones.forEach((milestone, index) => {
3144
- writeLine(stdout, `${index + 1}. ${pc5.cyan(milestone.name)}`);
3212
+ writeLine(stdout, `${index + 1}. ${pc6.cyan(milestone.name)}`);
3145
3213
  if (milestone.description) {
3146
3214
  writeLine(stdout, ` ${milestone.description}`);
3147
3215
  }
@@ -3291,7 +3359,7 @@ async function resolveClarification(options, sessionId, initialPayload) {
3291
3359
  }
3292
3360
  writeLine(
3293
3361
  options.stdout,
3294
- pc5.yellow("Proceeding because --force is enabled.")
3362
+ pc6.yellow("Proceeding because --force is enabled.")
3295
3363
  );
3296
3364
  payload = await postMilestoneConfirmation(options.client, sessionId, {});
3297
3365
  return {
@@ -3373,7 +3441,7 @@ async function runPlanningFlow(options) {
3373
3441
  if (options.existingMissionDraft) {
3374
3442
  writeLine(
3375
3443
  options.stdout,
3376
- pc5.cyan("Skipping planning because mission-draft.json already exists.")
3444
+ pc6.cyan("Skipping planning because mission-draft.json already exists.")
3377
3445
  );
3378
3446
  return {
3379
3447
  cancelled: false,
@@ -3429,7 +3497,7 @@ async function runPlanningFlow(options) {
3429
3497
  message: "Approve this draft and continue to upload?"
3430
3498
  });
3431
3499
  if (!approved) {
3432
- writeLine(options.stdout, pc5.yellow("Planning cancelled before upload."));
3500
+ writeLine(options.stdout, pc6.yellow("Planning cancelled before upload."));
3433
3501
  return {
3434
3502
  cancelled: true,
3435
3503
  draft,
@@ -3438,7 +3506,7 @@ async function runPlanningFlow(options) {
3438
3506
  };
3439
3507
  }
3440
3508
  await options.persistMissionDraft(draft);
3441
- writeLine(options.stdout, pc5.green("Saved approved mission draft."));
3509
+ writeLine(options.stdout, pc6.green("Saved approved mission draft."));
3442
3510
  return {
3443
3511
  cancelled: false,
3444
3512
  draft,
@@ -3453,7 +3521,7 @@ import { createReadStream as createReadStream2 } from "fs";
3453
3521
  import path5 from "path";
3454
3522
  import { Transform as Transform2 } from "stream";
3455
3523
  import ora3 from "ora";
3456
- import pc6 from "picocolors";
3524
+ import pc7 from "picocolors";
3457
3525
 
3458
3526
  // src/snapshot.ts
3459
3527
  import { execFile } from "child_process";
@@ -4050,15 +4118,15 @@ function isTerminalUploadStatus2(status) {
4050
4118
  return status === "uploaded" || status === "blob_exists";
4051
4119
  }
4052
4120
  function renderSafetyGate(stdout, repos, existingBlobs) {
4053
- writeLine(stdout, pc6.bold("Upload safety check"));
4121
+ writeLine(stdout, pc7.bold("Upload safety check"));
4054
4122
  writeLine(stdout, "Repos queued for upload:");
4055
4123
  for (const repo of repos) {
4056
- const cleanliness = repo.manifest.dirty ? pc6.yellow("dirty") : pc6.green("clean");
4057
- const secretSummary = repo.secretFindings.length > 0 ? pc6.red(`${repo.secretFindings.length} finding(s)`) : pc6.green("no findings");
4058
- const dedupSummary = existingBlobs.has(repo.manifest.archiveSha256) ? pc6.cyan("blob already exists remotely") : "new upload";
4124
+ const cleanliness = repo.manifest.dirty ? pc7.yellow("dirty") : pc7.green("clean");
4125
+ const secretSummary = repo.secretFindings.length > 0 ? pc7.red(`${repo.secretFindings.length} finding(s)`) : pc7.green("no findings");
4126
+ const dedupSummary = existingBlobs.has(repo.manifest.archiveSha256) ? pc7.cyan("blob already exists remotely") : "new upload";
4059
4127
  writeLine(
4060
4128
  stdout,
4061
- `- ${pc6.cyan(repo.manifest.repoId)} \u2014 ${repo.manifest.localPath}`
4129
+ `- ${pc7.cyan(repo.manifest.repoId)} \u2014 ${repo.manifest.localPath}`
4062
4130
  );
4063
4131
  writeLine(
4064
4132
  stdout,
@@ -4202,7 +4270,7 @@ async function processRepoUpload(options, repo, remoteLaunchId) {
4202
4270
  );
4203
4271
  writeLine(
4204
4272
  options.stdout,
4205
- pc6.cyan(`Skipping upload for ${repo.manifest.repoId}; blob already exists remotely.`)
4273
+ pc7.cyan(`Skipping upload for ${repo.manifest.repoId}; blob already exists remotely.`)
4206
4274
  );
4207
4275
  return;
4208
4276
  }
@@ -4296,7 +4364,7 @@ async function runUploadPipeline(options) {
4296
4364
  })) {
4297
4365
  writeLine(
4298
4366
  options.stdout,
4299
- pc6.yellow("Upload cancelled before creating a remote launch.")
4367
+ pc7.yellow("Upload cancelled before creating a remote launch.")
4300
4368
  );
4301
4369
  return {
4302
4370
  finalized: false,
@@ -4313,7 +4381,7 @@ async function runUploadPipeline(options) {
4313
4381
  if (existingBlobs.size > 0) {
4314
4382
  writeLine(
4315
4383
  options.stdout,
4316
- pc6.cyan(
4384
+ pc7.cyan(
4317
4385
  `Remote dedup will reuse ${existingBlobs.size} existing blob${existingBlobs.size === 1 ? "" : "s"}.`
4318
4386
  )
4319
4387
  );
@@ -4340,7 +4408,7 @@ async function runUploadPipeline(options) {
4340
4408
  if (isTerminalUploadStatus2(uploadStates.get(repo.manifest.repoId))) {
4341
4409
  writeLine(
4342
4410
  options.stdout,
4343
- pc6.cyan(`Skipping ${repo.manifest.repoId}; already completed in upload-state.json.`)
4411
+ pc7.cyan(`Skipping ${repo.manifest.repoId}; already completed in upload-state.json.`)
4344
4412
  );
4345
4413
  continue;
4346
4414
  }
@@ -4358,7 +4426,7 @@ async function runUploadPipeline(options) {
4358
4426
  failures.push(repo.manifest.repoId);
4359
4427
  writeLine(
4360
4428
  options.stdout,
4361
- pc6.red(
4429
+ pc7.red(
4362
4430
  error instanceof Error ? error.message : `Upload failed for ${repo.manifest.repoId}.`
4363
4431
  )
4364
4432
  );
@@ -4380,7 +4448,7 @@ async function runUploadPipeline(options) {
4380
4448
  }
4381
4449
  writeLine(
4382
4450
  options.stdout,
4383
- pc6.green(`Upload complete. Remote launch ${remoteLaunchId} is finalized.`)
4451
+ pc7.green(`Upload complete. Remote launch ${remoteLaunchId} is finalized.`)
4384
4452
  );
4385
4453
  return {
4386
4454
  finalized: true,
@@ -4555,10 +4623,10 @@ function registerMissionRunCommand(mission, context, dependencies = {}) {
4555
4623
  }
4556
4624
 
4557
4625
  // src/commands/mission-status.ts
4558
- import pc7 from "picocolors";
4626
+ import pc8 from "picocolors";
4559
4627
  function writeSection3(stdout, title) {
4560
4628
  writeLine(stdout);
4561
- writeLine(stdout, pc7.bold(title));
4629
+ writeLine(stdout, pc8.bold(title));
4562
4630
  }
4563
4631
  function normalizeMilestoneOrder(milestones, features, assertions) {
4564
4632
  const known = new Map(milestones.map((milestone) => [milestone.name, milestone]));
@@ -4658,7 +4726,7 @@ function renderMilestones2(stdout, milestones, features) {
4658
4726
  for (const milestone of milestones) {
4659
4727
  writeLine(
4660
4728
  stdout,
4661
- `- ${pc7.cyan(milestone.name)} (${milestone.state}) \xB7 ${milestone.completedFeatureCount}/${milestone.featureCount} features \xB7 ${milestone.passedAssertionCount}/${milestone.assertionCount} assertions`
4729
+ `- ${pc8.cyan(milestone.name)} (${milestone.state}) \xB7 ${milestone.completedFeatureCount}/${milestone.featureCount} features \xB7 ${milestone.passedAssertionCount}/${milestone.assertionCount} assertions`
4662
4730
  );
4663
4731
  const milestoneFeatures = features.filter(
4664
4732
  (feature) => feature.milestone === milestone.name
@@ -4718,6 +4786,7 @@ function registerMissionCommands(program, context, dependencies = {}) {
4718
4786
  const mission = program.command("mission").description("Manage missions");
4719
4787
  registerMissionRunCommand(mission, context, dependencies);
4720
4788
  registerMissionStatusCommand(mission, context, dependencies);
4789
+ registerMissionInfoCommand(mission, context, dependencies);
4721
4790
  registerMissionListCommand(mission, context, dependencies);
4722
4791
  registerMissionLifecycleCommands(mission, context, dependencies);
4723
4792
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coresource/hz",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "hz": "dist/hz.mjs"