@coresource/hz 0.1.9 → 0.20.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.
Files changed (2) hide show
  1. package/dist/hz.mjs +197 -69
  2. package/package.json +1 -1
package/dist/hz.mjs CHANGED
@@ -552,9 +552,11 @@ function normalizeMissionSummary(value) {
552
552
  return {
553
553
  completedFeatures: asFiniteNumber(value.completedFeatures),
554
554
  createdAt: asNonEmptyString(value.createdAt),
555
+ description: asNonEmptyString(value.description) ?? asNonEmptyString(value.taskDescription),
555
556
  missionId,
556
557
  passedAssertions: asFiniteNumber(value.passedAssertions),
557
558
  state: asNonEmptyString(value.state) ?? "unknown",
559
+ taskDescription: asNonEmptyString(value.taskDescription) ?? asNonEmptyString(value.description),
558
560
  totalAssertions: asFiniteNumber(value.totalAssertions),
559
561
  totalFeatures: asFiniteNumber(value.totalFeatures)
560
562
  };
@@ -579,6 +581,7 @@ function normalizeMissionState(value) {
579
581
  sandboxMinutesUsed: asNullableNumber(value.sandboxMinutesUsed),
580
582
  sealedMilestones: asFiniteNumber(value.sealedMilestones),
581
583
  state: asNonEmptyString(value.state) ?? "unknown",
584
+ taskDescription: asNonEmptyString(value.taskDescription),
582
585
  totalAssertions: asFiniteNumber(value.totalAssertions),
583
586
  totalFeatures: asFiniteNumber(value.totalFeatures),
584
587
  totalMilestones: asFiniteNumber(value.totalMilestones),
@@ -685,6 +688,27 @@ function formatPercent(part, total) {
685
688
  }
686
689
  return `${(part / total * 100).toFixed(1)}%`;
687
690
  }
691
+ function truncateText(value, limit) {
692
+ if (value.length <= limit) {
693
+ return value;
694
+ }
695
+ return `${value.slice(0, Math.max(0, limit - 1)).trimEnd()}\u2026`;
696
+ }
697
+ function summarizeMissionDescription(value, limit = 72) {
698
+ if (!value) {
699
+ return "\u2014";
700
+ }
701
+ const taskSectionMatch = value.match(
702
+ /(?:^|\n)##\s*Task\s*\n+([\s\S]*?)(?:\n\s*\n|\n##\s|$)/i
703
+ );
704
+ const source = taskSectionMatch?.[1] ?? value;
705
+ const lines = source.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
706
+ const candidate = lines.find((line) => !line.startsWith("#") && !/^[-*]\s/.test(line)) ?? lines[0];
707
+ if (!candidate) {
708
+ return "\u2014";
709
+ }
710
+ return truncateText(candidate.replace(/\s+/g, " "), limit);
711
+ }
688
712
  function plainCell(value) {
689
713
  return {
690
714
  display: value,
@@ -787,21 +811,42 @@ function registerMissionInfoCommand(mission, context, dependencies = {}) {
787
811
  }
788
812
 
789
813
  // src/commands/mission-list.ts
814
+ async function resolveMissionDescription(apiClient, missionSummary) {
815
+ if (missionSummary.taskDescription || missionSummary.description) {
816
+ return missionSummary.taskDescription ?? missionSummary.description;
817
+ }
818
+ try {
819
+ const missionState = normalizeMissionState(
820
+ await apiClient.request({
821
+ path: `/missions/${missionSummary.missionId}/mission/state`
822
+ })
823
+ );
824
+ return missionState.taskDescription;
825
+ } catch {
826
+ return null;
827
+ }
828
+ }
790
829
  function registerMissionListCommand(mission, context, dependencies = {}) {
791
830
  mission.command("list").description("List recent missions").action(async (_options, command) => {
792
831
  const apiClient = await createMissionApiClient(context, command, dependencies);
793
- const missions = normalizeMissionSummaries(
832
+ const missionSummaries = normalizeMissionSummaries(
794
833
  await apiClient.request({
795
834
  path: "/missions"
796
835
  })
797
836
  );
798
- if (missions.length === 0) {
837
+ if (missionSummaries.length === 0) {
799
838
  writeLine(context.stdout, "No missions found");
800
839
  return;
801
840
  }
841
+ const missions = await Promise.all(
842
+ missionSummaries.map(async (missionSummary) => ({
843
+ ...missionSummary,
844
+ description: await resolveMissionDescription(apiClient, missionSummary)
845
+ }))
846
+ );
802
847
  renderTable(
803
848
  context.stdout,
804
- ["Mission ID", "State", "Created", "Features", "Assertions"],
849
+ ["Mission ID", "State", "Created", "Features", "Assertions", "Description"],
805
850
  missions.map((missionSummary) => [
806
851
  plainCell(missionSummary.missionId),
807
852
  coloredCell(
@@ -814,7 +859,8 @@ function registerMissionListCommand(mission, context, dependencies = {}) {
814
859
  ),
815
860
  plainCell(
816
861
  `${missionSummary.passedAssertions}/${missionSummary.totalAssertions}`
817
- )
862
+ ),
863
+ plainCell(summarizeMissionDescription(missionSummary.description))
818
864
  ])
819
865
  );
820
866
  });
@@ -2149,17 +2195,9 @@ function defaultCreateWebSocket(url, options) {
2149
2195
  return new WebSocket(url, { headers: options.headers });
2150
2196
  }
2151
2197
  function defaultRegisterSignalHandler(signal, handler) {
2152
- let fired = false;
2153
- const wrapper = () => {
2154
- if (fired) {
2155
- process.exit(130);
2156
- }
2157
- fired = true;
2158
- handler();
2159
- };
2160
- process.on(signal, wrapper);
2198
+ process.once(signal, handler);
2161
2199
  return () => {
2162
- process.off(signal, wrapper);
2200
+ process.off(signal, handler);
2163
2201
  };
2164
2202
  }
2165
2203
  function createMissionWebSocketUrl(endpoint, missionId) {
@@ -2898,6 +2936,17 @@ function resolveResumeExitCode(state) {
2898
2936
  return null;
2899
2937
  }
2900
2938
  }
2939
+ function resolveWatchExitCode(state) {
2940
+ switch (state) {
2941
+ case "cancelled":
2942
+ case "completed":
2943
+ return 0;
2944
+ case "failed":
2945
+ return 1;
2946
+ default:
2947
+ return null;
2948
+ }
2949
+ }
2901
2950
  async function runMissionResume(missionIdValue, command, context, dependencies) {
2902
2951
  const homeDir = resolveLifecycleHomeDir(context);
2903
2952
  const missionId = await resolveMissionId(missionIdValue, context, command, homeDir);
@@ -2969,6 +3018,48 @@ async function runMissionResume(missionIdValue, command, context, dependencies)
2969
3018
  throw new CommanderError(monitorResult.exitCode, "mission-monitor", "");
2970
3019
  }
2971
3020
  }
3021
+ async function runMissionWatch(missionIdValue, command, context, dependencies) {
3022
+ const homeDir = resolveLifecycleHomeDir(context);
3023
+ const missionId = await resolveMissionId(missionIdValue, context, command, homeDir);
3024
+ const { apiClient, authConfig } = await createMissionClientContext(
3025
+ context,
3026
+ command,
3027
+ dependencies,
3028
+ homeDir
3029
+ );
3030
+ const snapshot = await fetchMissionSnapshot(apiClient, missionId);
3031
+ writeLine(
3032
+ context.stdout,
3033
+ `Watching mission ${pc5.cyan(missionId)} from state ${pc5.bold(snapshot.state.state)}.`
3034
+ );
3035
+ renderMissionSnapshot(context.stdout, snapshot);
3036
+ const watchExitCode = resolveWatchExitCode(snapshot.state.state);
3037
+ if (watchExitCode === 0) {
3038
+ return;
3039
+ }
3040
+ if (watchExitCode === 1) {
3041
+ throw new CliError(
3042
+ `Mission ${missionId} is currently ${snapshot.state.state}.`,
3043
+ 1
3044
+ );
3045
+ }
3046
+ const monitorResult = await monitorMission({
3047
+ apiClient,
3048
+ apiKey: authConfig.apiKey,
3049
+ createSpinner: dependencies.createSpinner,
3050
+ createWebSocket: dependencies.createWebSocket,
3051
+ endpoint: authConfig.endpoint,
3052
+ missionId,
3053
+ promptInput: dependencies.promptInput,
3054
+ promptSelect: dependencies.promptSelect,
3055
+ registerSignalHandler: dependencies.registerSignalHandler,
3056
+ sleep: dependencies.sleep,
3057
+ stdout: context.stdout
3058
+ });
3059
+ if (monitorResult.exitCode !== 0) {
3060
+ throw new CommanderError(monitorResult.exitCode, "mission-monitor", "");
3061
+ }
3062
+ }
2972
3063
  function registerMissionLifecycleCommands(mission, context, dependencies = {}) {
2973
3064
  mission.command("pause").description("Pause a mission").argument("[missionId]").action(async (missionId, _options, command) => {
2974
3065
  await runLifecycleMutation(
@@ -2982,6 +3073,9 @@ function registerMissionLifecycleCommands(mission, context, dependencies = {}) {
2982
3073
  mission.command("resume").description("Resume a mission").argument("[missionId]").action(async (missionId, _options, command) => {
2983
3074
  await runMissionResume(missionId, command, context, dependencies);
2984
3075
  });
3076
+ mission.command("watch").description("Watch a mission's live progress").argument("[missionId]").action(async (missionId, _options, command) => {
3077
+ await runMissionWatch(missionId, command, context, dependencies);
3078
+ });
2985
3079
  mission.command("cancel").description("Cancel a mission").argument("[missionId]").action(async (missionId, _options, command) => {
2986
3080
  await runLifecycleMutation(
2987
3081
  "cancel",
@@ -2991,41 +3085,15 @@ function registerMissionLifecycleCommands(mission, context, dependencies = {}) {
2991
3085
  dependencies
2992
3086
  );
2993
3087
  });
2994
- mission.command("watch").description("Watch a mission's live progress").argument("[missionId]").option("--yes", "Automatically approve all triage prompts").action(async (missionId, options, command) => {
2995
- const homeDir = resolveLifecycleHomeDir(context);
2996
- const resolved = await resolveMissionId(missionId, context, command, homeDir);
2997
- const { apiClient, authConfig } = await createMissionClientContext(
2998
- context,
2999
- command,
3000
- dependencies,
3001
- homeDir
3002
- );
3003
- const monitorResult = await monitorMission({
3004
- apiClient,
3005
- apiKey: authConfig.apiKey,
3006
- autoApprove: options.yes === true,
3007
- createSpinner: dependencies.createSpinner,
3008
- createWebSocket: dependencies.createWebSocket,
3009
- endpoint: authConfig.endpoint,
3010
- missionId: resolved,
3011
- promptInput: dependencies.promptInput,
3012
- promptSelect: dependencies.promptSelect,
3013
- registerSignalHandler: dependencies.registerSignalHandler,
3014
- sleep: dependencies.sleep,
3015
- stdout: context.stdout
3016
- });
3017
- if (monitorResult.exitCode !== 0) {
3018
- throw new CommanderError(monitorResult.exitCode, "mission-monitor", "");
3019
- }
3020
- });
3021
3088
  }
3022
3089
 
3023
3090
  // src/commands/mission-run.ts
3024
3091
  import { stat as stat3 } from "fs/promises";
3025
- import path6 from "path";
3092
+ import path7 from "path";
3026
3093
  import { CommanderError as CommanderError2 } from "commander";
3027
3094
 
3028
3095
  // src/planning.ts
3096
+ import path4 from "path";
3029
3097
  import {
3030
3098
  confirm as defaultConfirmPrompt,
3031
3099
  input as defaultInputPrompt2,
@@ -3233,25 +3301,85 @@ function renderFailures(stdout, failures) {
3233
3301
  writeLine(stdout, `- ${failure}`);
3234
3302
  });
3235
3303
  }
3236
- async function promptForAnswers(options, questions, round) {
3237
- if (options.autoApprove) {
3238
- return {
3239
- answers: [],
3240
- transcript: []
3241
- };
3304
+ function tokenizeText(value) {
3305
+ return value.toLowerCase().split(/[^a-z0-9]+/i).filter((token) => token.length > 1);
3306
+ }
3307
+ function summarizeRepoNames(repoPaths) {
3308
+ return repoPaths.map((repoPath) => {
3309
+ const repoName = path4.basename(repoPath);
3310
+ return repoName.length > 0 ? repoName : repoPath;
3311
+ });
3312
+ }
3313
+ function pickAutoApprovedOption(question, taskDescription, repoPaths) {
3314
+ if (!question.options || question.options.length === 0) {
3315
+ return null;
3242
3316
  }
3317
+ const repoNames = summarizeRepoNames(repoPaths);
3318
+ const references = (question.references ?? []).map((reference) => path4.basename(reference));
3319
+ const contextTokens = /* @__PURE__ */ new Set([
3320
+ ...tokenizeText(question.text),
3321
+ ...tokenizeText(taskDescription),
3322
+ ...repoNames.flatMap((repoName) => tokenizeText(repoName)),
3323
+ ...references.flatMap((reference) => tokenizeText(reference))
3324
+ ]);
3325
+ let bestOption = question.options[0] ?? null;
3326
+ let bestScore = Number.NEGATIVE_INFINITY;
3327
+ for (const option of question.options) {
3328
+ const label = `${option.label} ${option.description ?? ""} ${option.id}`.trim();
3329
+ const optionTokens = tokenizeText(label);
3330
+ let score = 0;
3331
+ for (const token of optionTokens) {
3332
+ if (contextTokens.has(token)) {
3333
+ score += 3;
3334
+ }
3335
+ if (/continue|approve|yes|confirm|accept|keep|use|primary/.test(token)) {
3336
+ score += 1;
3337
+ }
3338
+ }
3339
+ if (score > bestScore) {
3340
+ bestScore = score;
3341
+ bestOption = option;
3342
+ }
3343
+ }
3344
+ return bestOption;
3345
+ }
3346
+ function buildAutoApprovedDetail(question, taskDescription, repoPaths) {
3347
+ if (question.inputDefault && question.inputDefault.trim().length > 0) {
3348
+ return question.inputDefault.trim();
3349
+ }
3350
+ const repoNames = summarizeRepoNames(repoPaths);
3351
+ const repoPhrase = repoNames.length === 1 ? `the \`${repoNames[0]}\` repository` : `the repositories ${repoNames.map((repoName) => `\`${repoName}\``).join(", ")}`;
3352
+ const references = question.references && question.references.length > 0 ? ` Ground the answer in ${question.references.join(", ")}.` : "";
3353
+ const questionText = question.text.toLowerCase();
3354
+ const task = taskDescription.trim().replace(/\s+/g, " ");
3355
+ if (/validation|test|package\.json/.test(questionText)) {
3356
+ return `Validate the change in ${repoPhrase} with the referenced tests and package scripts, then run the relevant tests, typecheck, and build checks.${references}`;
3357
+ }
3358
+ if (/repo surface|repo path|scope|primary repo/.test(questionText)) {
3359
+ return `Focus on ${repoPhrase} as the primary implementation surface for: ${task}.${references}`;
3360
+ }
3361
+ if (/debug info|api connection|endpoint|response status|http method|verbose/.test(questionText)) {
3362
+ return `Implement ${task} so verbose mode shows safe API-connection diagnostics such as the configured endpoint, HTTP method, and response status without exposing secrets.${references}`;
3363
+ }
3364
+ if (/req-func|flag|command/.test(questionText) || /--[a-z0-9-]+/.test(task)) {
3365
+ return `Implement ${task} in ${repoPhrase}, preserving the default output unless the requested flag or option is present.${references}`;
3366
+ }
3367
+ return `${task}. Use ${repoPhrase} as the source of truth.${references}`;
3368
+ }
3369
+ async function promptForAnswers(options, questions, round) {
3243
3370
  const promptSelect = options.promptSelect ?? defaultPromptSelect2;
3244
3371
  const promptInput = options.promptInput ?? defaultPromptInput2;
3245
3372
  const answers = [];
3246
3373
  const transcript = [];
3247
3374
  for (const question of questions) {
3248
3375
  if (question.options && question.options.length > 0) {
3376
+ const autoSelectedOption = options.autoApprove ? pickAutoApprovedOption(question, options.taskDescription, options.repoPaths) : null;
3249
3377
  const choices = question.options.map((option) => ({
3250
3378
  description: option.description,
3251
3379
  name: option.label,
3252
3380
  value: option.id
3253
3381
  }));
3254
- const optionId2 = await promptSelect({
3382
+ const optionId2 = autoSelectedOption?.id ?? await promptSelect({
3255
3383
  choices,
3256
3384
  message: question.text
3257
3385
  });
@@ -3270,7 +3398,7 @@ async function promptForAnswers(options, questions, round) {
3270
3398
  });
3271
3399
  continue;
3272
3400
  }
3273
- const detail = await promptInput({
3401
+ const detail = options.autoApprove ? buildAutoApprovedDetail(question, options.taskDescription, options.repoPaths) : await promptInput({
3274
3402
  default: question.inputDefault,
3275
3403
  message: question.detailPrompt ?? question.text
3276
3404
  });
@@ -3519,7 +3647,7 @@ async function runPlanningFlow(options) {
3519
3647
  // src/upload.ts
3520
3648
  import { confirm } from "@inquirer/prompts";
3521
3649
  import { createReadStream as createReadStream2 } from "fs";
3522
- import path5 from "path";
3650
+ import path6 from "path";
3523
3651
  import { Transform as Transform2 } from "stream";
3524
3652
  import ora3 from "ora";
3525
3653
  import pc7 from "picocolors";
@@ -3537,7 +3665,7 @@ import {
3537
3665
  rm as rm3,
3538
3666
  stat as stat2
3539
3667
  } from "fs/promises";
3540
- import path4 from "path";
3668
+ import path5 from "path";
3541
3669
  import { createInterface } from "readline";
3542
3670
  import { Transform } from "stream";
3543
3671
  import { pipeline } from "stream/promises";
@@ -3561,7 +3689,7 @@ var SECRET_PATTERNS = [
3561
3689
  {
3562
3690
  kind: "stripe_live_key",
3563
3691
  message: "Found a Stripe live secret key.",
3564
- regex: /sk_live_[A-Za-z0-9]+/g
3692
+ regex: /sk_live_[A-Za-z0-9]{16,}/g
3565
3693
  },
3566
3694
  {
3567
3695
  kind: "aws_access_key",
@@ -3571,7 +3699,7 @@ var SECRET_PATTERNS = [
3571
3699
  {
3572
3700
  kind: "github_personal_access_token",
3573
3701
  message: "Found a GitHub personal access token.",
3574
- regex: /ghp_[A-Za-z0-9]+/g
3702
+ regex: /ghp_[A-Za-z0-9]{36,}/g
3575
3703
  },
3576
3704
  {
3577
3705
  kind: "private_key",
@@ -3608,7 +3736,7 @@ function compareStrings(left, right) {
3608
3736
  return left < right ? -1 : 1;
3609
3737
  }
3610
3738
  function toPosixPath(filePath) {
3611
- return filePath.split(path4.sep).join(path4.posix.sep);
3739
+ return filePath.split(path5.sep).join(path5.posix.sep);
3612
3740
  }
3613
3741
  function splitNullTerminatedBuffer(buffer) {
3614
3742
  return buffer.toString("utf8").split("\0").filter((entry) => entry.length > 0);
@@ -3640,7 +3768,7 @@ async function ensureDirectory2(dirPath) {
3640
3768
  }
3641
3769
  async function validateDirectoryPath(repoPath, options) {
3642
3770
  const cwd = options.cwd ?? process.cwd();
3643
- const absolutePath = path4.resolve(cwd, repoPath);
3771
+ const absolutePath = path5.resolve(cwd, repoPath);
3644
3772
  let directoryStats;
3645
3773
  try {
3646
3774
  directoryStats = await stat2(absolutePath);
@@ -3671,7 +3799,7 @@ async function resolveRepositoryInputs(repoPaths, options) {
3671
3799
  );
3672
3800
  const counts = /* @__PURE__ */ new Map();
3673
3801
  const baseNames = absolutePaths.map(
3674
- (absolutePath) => sanitizeIdentifier(path4.basename(absolutePath))
3802
+ (absolutePath) => sanitizeIdentifier(path5.basename(absolutePath))
3675
3803
  );
3676
3804
  for (const baseName of baseNames) {
3677
3805
  counts.set(baseName, (counts.get(baseName) ?? 0) + 1);
@@ -3719,7 +3847,7 @@ function matchSecretPatterns(line, relativePath, lineNumber) {
3719
3847
  }
3720
3848
  async function scanRegularFileForSecrets(filePath, relativePath) {
3721
3849
  const findings = [];
3722
- const basename = path4.posix.basename(relativePath);
3850
+ const basename = path5.posix.basename(relativePath);
3723
3851
  if (basename.startsWith(".env")) {
3724
3852
  findings.push({
3725
3853
  kind: "env_file",
@@ -3741,7 +3869,7 @@ async function scanRegularFileForSecrets(filePath, relativePath) {
3741
3869
  return findings;
3742
3870
  }
3743
3871
  async function classifyRepositoryEntry(repoPath, relativePath) {
3744
- const absolutePath = path4.join(repoPath, relativePath);
3872
+ const absolutePath = path5.join(repoPath, relativePath);
3745
3873
  const entryStats = await lstat(absolutePath);
3746
3874
  if (entryStats.isDirectory()) {
3747
3875
  return null;
@@ -3770,8 +3898,8 @@ async function classifyRepositoryEntry(repoPath, relativePath) {
3770
3898
  }
3771
3899
  function shouldIgnoreNonGitEntry(relativePath, isDirectory) {
3772
3900
  const normalizedPath = toPosixPath(relativePath);
3773
- const basename = path4.posix.basename(normalizedPath);
3774
- const segments = normalizedPath.split(path4.posix.sep);
3901
+ const basename = path5.posix.basename(normalizedPath);
3902
+ const segments = normalizedPath.split(path5.posix.sep);
3775
3903
  if (segments.includes(GIT_DIR_NAME)) {
3776
3904
  return true;
3777
3905
  }
@@ -3781,13 +3909,13 @@ function shouldIgnoreNonGitEntry(relativePath, isDirectory) {
3781
3909
  return basename === ".DS_Store" || basename === ".env";
3782
3910
  }
3783
3911
  async function walkNonGitEntries(repoPath, currentRelativePath = "") {
3784
- const currentAbsolutePath = path4.join(repoPath, currentRelativePath);
3912
+ const currentAbsolutePath = path5.join(repoPath, currentRelativePath);
3785
3913
  const dirEntries = await readdir3(currentAbsolutePath, { withFileTypes: true });
3786
3914
  const results = [];
3787
3915
  for (const dirEntry of dirEntries.sort(
3788
3916
  (left, right) => compareStrings(left.name, right.name)
3789
3917
  )) {
3790
- const relativePath = currentRelativePath ? path4.posix.join(currentRelativePath, dirEntry.name) : dirEntry.name;
3918
+ const relativePath = currentRelativePath ? path5.posix.join(currentRelativePath, dirEntry.name) : dirEntry.name;
3791
3919
  if (shouldIgnoreNonGitEntry(relativePath, dirEntry.isDirectory())) {
3792
3920
  continue;
3793
3921
  }
@@ -3811,7 +3939,7 @@ async function pathExists(filePath) {
3811
3939
  }
3812
3940
  }
3813
3941
  async function isGitBackedRepository(repoPath) {
3814
- return pathExists(path4.join(repoPath, GIT_DIR_NAME));
3942
+ return pathExists(path5.join(repoPath, GIT_DIR_NAME));
3815
3943
  }
3816
3944
  async function runGitCommand(repoPath, args, options = {}) {
3817
3945
  const encoding = options.encoding ?? "utf8";
@@ -3876,7 +4004,7 @@ async function discoverGitEntries(repoPath) {
3876
4004
  const candidateEntries = [.../* @__PURE__ */ new Set([...trackedEntries, ...untrackedEntries])].map((entry) => toPosixPath(entry)).filter((entry) => !entry.startsWith(".git/") && entry !== ".git");
3877
4005
  const relativePaths = [];
3878
4006
  for (const entry of candidateEntries.sort(compareStrings)) {
3879
- if (await pathExists(path4.join(repoPath, entry))) {
4007
+ if (await pathExists(path5.join(repoPath, entry))) {
3880
4008
  relativePaths.push(entry);
3881
4009
  }
3882
4010
  }
@@ -3956,7 +4084,7 @@ async function analyzeRepository(input) {
3956
4084
  }
3957
4085
  async function writeDeterministicArchive(analysis, outputDir) {
3958
4086
  await ensureDirectory2(outputDir);
3959
- const finalArchivePath = path4.join(outputDir, `${analysis.input.repoId}.tar.zst`);
4087
+ const finalArchivePath = path5.join(outputDir, `${analysis.input.repoId}.tar.zst`);
3960
4088
  const tempArchivePath = `${finalArchivePath}.${process.pid}.${Date.now()}.tmp`;
3961
4089
  const archiveHash = createHash2("sha256");
3962
4090
  let archiveBytes = 0;
@@ -4323,7 +4451,7 @@ async function runUploadPipeline(options) {
4323
4451
  repos = await snapshotRepositories({
4324
4452
  allowSecrets: options.allowSecrets === true,
4325
4453
  cwd: options.cwd,
4326
- outputDir: path5.join(launchSnapshot.paths.launchDir, "archives"),
4454
+ outputDir: path6.join(launchSnapshot.paths.launchDir, "archives"),
4327
4455
  repoPaths: options.repoPaths
4328
4456
  });
4329
4457
  } catch (error) {
@@ -4333,7 +4461,7 @@ async function runUploadPipeline(options) {
4333
4461
  repos = await snapshotRepositories({
4334
4462
  allowSecrets: true,
4335
4463
  cwd: options.cwd,
4336
- outputDir: path5.join(launchSnapshot.paths.launchDir, "archives"),
4464
+ outputDir: path6.join(launchSnapshot.paths.launchDir, "archives"),
4337
4465
  repoPaths: options.repoPaths
4338
4466
  });
4339
4467
  repos = repos.map((repo) => ({
@@ -4465,7 +4593,7 @@ async function resolveRepoPaths(repoValues, cwd = process.cwd()) {
4465
4593
  if (repoValues.length === 0) {
4466
4594
  throw new CliError("At least one `--repo` path is required.");
4467
4595
  }
4468
- const resolved = [...new Set(repoValues.map((repoPath) => path6.resolve(cwd, repoPath)))];
4596
+ const resolved = [...new Set(repoValues.map((repoPath) => path7.resolve(cwd, repoPath)))];
4469
4597
  for (const repoPath of resolved) {
4470
4598
  let repoStats;
4471
4599
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coresource/hz",
3
- "version": "0.1.9",
3
+ "version": "0.20.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "hz": "dist/hz.mjs"