halfcycle 0.12.0-rc.3 → 0.12.0-rc.5

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,6 +1,6 @@
1
1
  {
2
2
  "name": "halfcycle",
3
- "version": "0.12.0-rc.3",
3
+ "version": "0.12.0-rc.5",
4
4
  "description": "Halfcycle Method bundle — resolution-stub slash commands, remote method-delivery registration, and governance-hook wiring for a Halfcycle engagement repo. It ships NO worker role files: a project's roles are authored from that project's own recorded decisions at orchestration kickoff (FX-2, W3-F-27).",
5
5
  "commands": [
6
6
  {
package/dist/cli.js CHANGED
@@ -2552,7 +2552,7 @@ if (switchedOn) {
2552
2552
  }
2553
2553
 
2554
2554
  // dist/bin.js
2555
- import { existsSync as existsSync17, statSync as statSync3, writeSync as writeSync4 } from "node:fs";
2555
+ import { existsSync as existsSync18, statSync as statSync3, writeSync as writeSync4 } from "node:fs";
2556
2556
 
2557
2557
  // dist/install.js
2558
2558
  import { execFileSync as execFileSync2 } from "node:child_process";
@@ -9879,6 +9879,21 @@ function assertManifestInWriteSet(manifest, writeSet) {
9879
9879
  }
9880
9880
  }
9881
9881
  function findNotShared(targetRepo, manifest, collidedPaths) {
9882
+ const paths = setupFilesToShare(targetRepo, manifest, collidedPaths);
9883
+ const ignored = readIgnoredPaths(targetRepo, paths);
9884
+ if (ignored === null)
9885
+ return null;
9886
+ const sorted = [...ignored].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
9887
+ const named2 = sorted.find((entry) => entry.path === SETTINGS_REL) ?? sorted[0];
9888
+ return {
9889
+ path: named2.path,
9890
+ pattern: named2.pattern,
9891
+ source: named2.source,
9892
+ line: named2.line,
9893
+ others: sorted.length - 1
9894
+ };
9895
+ }
9896
+ function setupFilesToShare(targetRepo, manifest, collidedPaths) {
9882
9897
  const merged = [
9883
9898
  SETTINGS_REL,
9884
9899
  ...manifest.mcp !== void 0 ? [MCP_REGISTRATION_REL] : [],
@@ -9909,18 +9924,7 @@ function findNotShared(targetRepo, manifest, collidedPaths) {
9909
9924
  INSTALL_MANIFEST_REL
9910
9925
  ])
9911
9926
  ].filter((rel) => !collided.has(rel)).filter((rel) => lstatOrNull(join8(targetRepo, rel)) !== null).filter(travelsThroughPlainDirs).sort();
9912
- const ignored = readIgnoredPaths(targetRepo, paths);
9913
- if (ignored === null)
9914
- return null;
9915
- const sorted = [...ignored].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
9916
- const named2 = sorted.find((entry) => entry.path === SETTINGS_REL) ?? sorted[0];
9917
- return {
9918
- path: named2.path,
9919
- pattern: named2.pattern,
9920
- source: named2.source,
9921
- line: named2.line,
9922
- others: sorted.length - 1
9923
- };
9927
+ return paths;
9924
9928
  }
9925
9929
  function lstatOrNull(path) {
9926
9930
  try {
@@ -10389,7 +10393,7 @@ if [ -n "$SESSION_ID" ]; then
10389
10393
  else
10390
10394
  MARKER_FILE="\${MARKER_DIR}/halfcycle-session-\${HASH}.ref"
10391
10395
  fi
10392
- git -C "$REPO_ROOT" rev-parse HEAD > "$MARKER_FILE" 2>/dev/null || true
10396
+ ( cd "$REPO_ROOT" && git rev-parse HEAD ) > "$MARKER_FILE" 2>/dev/null || true
10393
10397
  exit 0
10394
10398
  `;
10395
10399
  }
@@ -13538,6 +13542,7 @@ var SCRIPT_RUNNERS = ["npm run", "pnpm", "pnpm run", "yarn", "bun run"];
13538
13542
  var HALFCYCLE_TOOLS_RULE = `mcp__${MCP_SERVER_KEY}`;
13539
13543
  var bash = (command) => `Bash(${command}:*)`;
13540
13544
  var CONTEXT_BUDGET_IGNORE_CHECK = "git check-ignore -q .halfcycle/context-budget.json";
13545
+ var COMMIT_FILE_LISTING = "git ls-tree -r --name-only";
13541
13546
  var INSTALLED_HOOK_SCRIPTS = Object.keys(OWNED_GENERATED_HEADERS).filter((path) => path.startsWith(".claude/hooks/"));
13542
13547
  var LOCAL_ALLOW_RULES = [
13543
13548
  ...SCRIPT_RUNNERS.flatMap((runner) => SCRIPTS.map((script) => bash(`${runner} ${script}`))),
@@ -13562,6 +13567,7 @@ var LOCAL_ALLOW_RULES = [
13562
13567
  bash("git diff"),
13563
13568
  bash("git log"),
13564
13569
  bash("git show"),
13570
+ bash(COMMIT_FILE_LISTING),
13565
13571
  bash("git add"),
13566
13572
  bash("git commit"),
13567
13573
  bash("git switch"),
@@ -19072,6 +19078,65 @@ function runCheckReport(source, head, deps = {}) {
19072
19078
  `).join(""), stderr: "", exitCode: 1 };
19073
19079
  }
19074
19080
 
19081
+ // dist/setup-committed.js
19082
+ import { execFileSync as execFileSync7 } from "node:child_process";
19083
+ import { existsSync as existsSync15 } from "node:fs";
19084
+ import { join as join26 } from "node:path";
19085
+ var SETUP_COMMIT_MESSAGE = "Add Halfcycle setup files";
19086
+ var SETUP_UNCOMMITTED_LINES = {
19087
+ intro: () => "Halfcycle's setup files are not committed, so the copies your agents build in would not have Halfcycle. Nothing was started. Commit them, then run this again:",
19088
+ add: (paths) => `git add -- ${paths.map(shellWord).join(" ")}`,
19089
+ commit: (paths) => `git commit -m "${SETUP_COMMIT_MESSAGE}" -- ${paths.map(shellWord).join(" ")}`
19090
+ };
19091
+ function shellWord(path) {
19092
+ return /^[A-Za-z0-9._/@+=-]+$/.test(path) ? path : `'${path.replace(/'/g, `'\\''`)}'`;
19093
+ }
19094
+ function uncommittedSetupFiles(repoRoot) {
19095
+ if (!existsSync15(join26(repoRoot, INSTALL_MANIFEST_REL)))
19096
+ return [];
19097
+ const manifest = readPreviousManifest(repoRoot);
19098
+ if (manifest === null)
19099
+ return [];
19100
+ const paths = setupFilesToShare(repoRoot, manifest, manifest.leftAlone);
19101
+ if (paths.length === 0)
19102
+ return [];
19103
+ let out;
19104
+ let prefix;
19105
+ try {
19106
+ const run = (args2) => execFileSync7("git", ["-C", repoRoot, ...args2], {
19107
+ encoding: "utf-8",
19108
+ env: gitEnvForNamedRepo(),
19109
+ stdio: ["ignore", "pipe", "ignore"],
19110
+ maxBuffer: 64 * 1024 * 1024
19111
+ });
19112
+ prefix = run(["rev-parse", "--show-prefix"]).replace(/\r?\n$/, "");
19113
+ out = run(["--literal-pathspecs", "status", "--porcelain=v1", "-z", "--untracked-files=all", "--", ...paths]);
19114
+ } catch {
19115
+ return [];
19116
+ }
19117
+ const wanted = new Set(paths);
19118
+ const found = /* @__PURE__ */ new Set();
19119
+ const fields = out.split("\0");
19120
+ for (let i = 0; i < fields.length; i++) {
19121
+ const entry = fields[i];
19122
+ if (entry.length < 4)
19123
+ continue;
19124
+ const xy = entry.slice(0, 2);
19125
+ const fromTop = entry.slice(3);
19126
+ if (xy.includes("R") || xy.includes("C"))
19127
+ i++;
19128
+ const rel = prefix !== "" && fromTop.startsWith(prefix) ? fromTop.slice(prefix.length) : fromTop;
19129
+ if (wanted.has(rel))
19130
+ found.add(rel);
19131
+ }
19132
+ return [...found].sort();
19133
+ }
19134
+ function setupUncommittedLines(paths) {
19135
+ if (paths.length === 0)
19136
+ return [];
19137
+ return [SETUP_UNCOMMITTED_LINES.intro(), SETUP_UNCOMMITTED_LINES.add(paths), SETUP_UNCOMMITTED_LINES.commit(paths)];
19138
+ }
19139
+
19075
19140
  // dist/ready.js
19076
19141
  var READY_USAGE = `${ownCommand()} ready <phase> [--cap <n>] [--repo <root>]`;
19077
19142
  var STATES_TEXT = buildTaskStateSchema.options.join(", ");
@@ -19204,6 +19269,11 @@ function runReady(repoRoot, phase, cap) {
19204
19269
  if (!read.ok)
19205
19270
  return failed2(read.lines.map((line) => `${line}
19206
19271
  `).join(""));
19272
+ const uncommitted = setupUncommittedLines(uncommittedSetupFiles(repoRoot));
19273
+ if (uncommitted.length > 0) {
19274
+ return { stdout: uncommitted.map((line) => `${line}
19275
+ `).join(""), stderr: "", exitCode: 1 };
19276
+ }
19207
19277
  const titles = new Map(read.rows.map((row) => [row.id, row.title]));
19208
19278
  const set = readyTasks(read.rows);
19209
19279
  const out = [];
@@ -19298,9 +19368,9 @@ function runProveChild(binary, credential, repoRoot, words, deps = {}) {
19298
19368
  }
19299
19369
 
19300
19370
  // dist/uninstall.js
19301
- import { existsSync as existsSync15, lstatSync as lstatSync4, readFileSync as readFileSync23, readdirSync, rmSync as rmSync8, rmdirSync, writeFileSync as writeFileSync9 } from "node:fs";
19371
+ import { existsSync as existsSync16, lstatSync as lstatSync4, readFileSync as readFileSync23, readdirSync, rmSync as rmSync8, rmdirSync, writeFileSync as writeFileSync9 } from "node:fs";
19302
19372
  import { homedir as homedir7 } from "node:os";
19303
- import { dirname as dirname8, join as join26, relative as relative6, sep as sep2 } from "node:path";
19373
+ import { dirname as dirname8, join as join27, relative as relative6, sep as sep2 } from "node:path";
19304
19374
  var REMOVE_CREDENTIAL_FLAG = "--remove-credential";
19305
19375
  function parseUninstallArgs(args2) {
19306
19376
  let removeCredential = false;
@@ -19335,7 +19405,7 @@ function readMergedJson(targetRepo, rule) {
19335
19405
  const { rel } = rule;
19336
19406
  if (symlinkOnPath(targetRepo, rel))
19337
19407
  return { state: "symlink" };
19338
- const path = join26(targetRepo, rel);
19408
+ const path = join27(targetRepo, rel);
19339
19409
  if (!lexists(path))
19340
19410
  return { state: "absent" };
19341
19411
  let text;
@@ -19358,8 +19428,8 @@ function readMergedJson(targetRepo, rule) {
19358
19428
  }
19359
19429
  function validate(options, rules) {
19360
19430
  const { targetRepo, removeCredential, home } = options;
19361
- const manifestPath = join26(targetRepo, INSTALL_MANIFEST_REL);
19362
- const pinPath = join26(targetRepo, BUNDLE_PIN_REL);
19431
+ const manifestPath = join27(targetRepo, INSTALL_MANIFEST_REL);
19432
+ const pinPath = join27(targetRepo, BUNDLE_PIN_REL);
19363
19433
  if (symlinkOnPath(targetRepo, INSTALL_MANIFEST_REL) || symlinkOnPath(targetRepo, BUNDLE_PIN_REL)) {
19364
19434
  throw new Refusal(`.halfcycle, or a file Halfcycle keeps in it, is a symbolic link here, so nothing was followed and nothing was removed.`);
19365
19435
  }
@@ -19400,7 +19470,7 @@ function validate(options, rules) {
19400
19470
  throw new Refusal(`the project id in ${BUNDLE_PIN_REL} is not a valid Halfcycle project id, so it cannot name a folder on this machine. Nothing was removed, here or under ~/.halfcycle.`);
19401
19471
  }
19402
19472
  if (engagementId !== void 0) {
19403
- const expectedParent = join26(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
19473
+ const expectedParent = join27(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
19404
19474
  if (dirname8(engagementStateDir(engagementId, home)) !== expectedParent) {
19405
19475
  throw new Refusal(`the project id in ${BUNDLE_PIN_REL} does not name a folder under ~/.halfcycle/engagements. Nothing was removed.`);
19406
19476
  }
@@ -19426,7 +19496,7 @@ function mergedFileRules(writeSet) {
19426
19496
  function writeBack(targetRepo, rel, current, next, lists, name) {
19427
19497
  if (next === current)
19428
19498
  return;
19429
- const path = join26(targetRepo, rel);
19499
+ const path = join27(targetRepo, rel);
19430
19500
  try {
19431
19501
  if (next === null) {
19432
19502
  rmSync8(path);
@@ -19443,7 +19513,7 @@ function statusLineClaimedFromTree(targetRepo, writeSet) {
19443
19513
  try {
19444
19514
  if (symlinkOnPath(targetRepo, SETTINGS_REL))
19445
19515
  return {};
19446
- const value = JSON.parse(readFileSync23(join26(targetRepo, SETTINGS_REL), "utf-8"));
19516
+ const value = JSON.parse(readFileSync23(join27(targetRepo, SETTINGS_REL), "utf-8"));
19447
19517
  if (!isPlainObject4(value) || !("statusLine" in value))
19448
19518
  return {};
19449
19519
  const hash = canonicalSha256(value["statusLine"]);
@@ -19456,7 +19526,7 @@ function attributionClaimedFromTree(targetRepo, writeSet) {
19456
19526
  try {
19457
19527
  if (symlinkOnPath(targetRepo, SETTINGS_REL))
19458
19528
  return {};
19459
- const value = JSON.parse(readFileSync23(join26(targetRepo, SETTINGS_REL), "utf-8"));
19529
+ const value = JSON.parse(readFileSync23(join27(targetRepo, SETTINGS_REL), "utf-8"));
19460
19530
  if (!isPlainObject4(value) || !("attribution" in value))
19461
19531
  return {};
19462
19532
  const hash = canonicalSha256(value["attribution"]);
@@ -19470,7 +19540,7 @@ function noRecord(targetRepo, writeSet) {
19470
19540
  const claim = (rel, header, lines) => {
19471
19541
  let text;
19472
19542
  try {
19473
- text = symlinkOnPath(targetRepo, rel) ? "" : readFileSync23(join26(targetRepo, rel), "utf-8");
19543
+ text = symlinkOnPath(targetRepo, rel) ? "" : readFileSync23(join27(targetRepo, rel), "utf-8");
19474
19544
  } catch {
19475
19545
  text = "";
19476
19546
  }
@@ -19716,7 +19786,7 @@ function lastOccurrence(text, block) {
19716
19786
  }
19717
19787
  function coveredPathExists(targetRepo, line) {
19718
19788
  const path = line.trim().replace(/^\//, "").replace(/\/$/, "");
19719
- return path !== "" && lexists(join26(targetRepo, path));
19789
+ return path !== "" && lexists(join27(targetRepo, path));
19720
19790
  }
19721
19791
  function selfBuildMergedFileRules() {
19722
19792
  return {
@@ -19730,7 +19800,7 @@ function removeSelfBuildOwnedFile(targetRepo, rel, lists, name) {
19730
19800
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19731
19801
  return;
19732
19802
  }
19733
- const abs = join26(targetRepo, rel);
19803
+ const abs = join27(targetRepo, rel);
19734
19804
  let isFile;
19735
19805
  try {
19736
19806
  isFile = lstatSync4(abs).isFile();
@@ -19754,7 +19824,7 @@ function removeSelfBuildCrewRoster(targetRepo, lists, name) {
19754
19824
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19755
19825
  return;
19756
19826
  }
19757
- const abs = join26(targetRepo, rel);
19827
+ const abs = join27(targetRepo, rel);
19758
19828
  let bytes;
19759
19829
  try {
19760
19830
  bytes = readFileSync23(abs);
@@ -19781,7 +19851,7 @@ function removeSelfBuildCrewProfile(targetRepo, rel, text, lists, name) {
19781
19851
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19782
19852
  return;
19783
19853
  }
19784
- const abs = join26(targetRepo, rel);
19854
+ const abs = join27(targetRepo, rel);
19785
19855
  let bytes;
19786
19856
  try {
19787
19857
  bytes = readFileSync23(abs);
@@ -19806,7 +19876,7 @@ function removeSelfBuildCrewProfile(targetRepo, rel, text, lists, name) {
19806
19876
  function removeSelfBuildEmptyDir(targetRepo, dir, lists, name) {
19807
19877
  if (symlinkOnPath(targetRepo, dir))
19808
19878
  return;
19809
- const abs = join26(targetRepo, dir);
19879
+ const abs = join27(targetRepo, dir);
19810
19880
  try {
19811
19881
  if (!lstatSync4(abs).isDirectory() || readdirSync(abs).length > 0)
19812
19882
  return;
@@ -19840,7 +19910,7 @@ function uninstallSelfBuild(options) {
19840
19910
  throw err;
19841
19911
  }
19842
19912
  const { targetRepo } = options;
19843
- const pinExisted = lexists(join26(targetRepo, BUNDLE_PIN_REL));
19913
+ const pinExisted = lexists(join27(targetRepo, BUNDLE_PIN_REL));
19844
19914
  const name = (list2, text, _path) => {
19845
19915
  list2.push(text);
19846
19916
  };
@@ -19927,7 +19997,7 @@ function uninstall(options) {
19927
19997
  }
19928
19998
  const serverRemoved = removeOwnServerApproval(targetRepo);
19929
19999
  if (listRemoved || serverRemoved) {
19930
- if (existsSync15(join26(targetRepo, LOCAL_SETTINGS_REL2))) {
20000
+ if (existsSync16(join27(targetRepo, LOCAL_SETTINGS_REL2))) {
19931
20001
  name(result.restored, LOCAL_SETTINGS_REL2, LOCAL_SETTINGS_REL2);
19932
20002
  } else {
19933
20003
  name(result.removed, LOCAL_SETTINGS_REL2, LOCAL_SETTINGS_REL2);
@@ -19969,7 +20039,7 @@ function uninstall(options) {
19969
20039
  const gitattributes = manifest.gitattributes ?? { created: false, appended: [] };
19970
20040
  trimAppendedFile(targetRepo, gitattributes, deleteWhenEmpty(gitattributes.created), gitattributesRules(writeSet), result, name);
19971
20041
  const foundNothing = result.removed.length + result.restored.length + result.kept.length + result.failed.length === 0 && result.keptIgnoreLines.length === 0;
19972
- if (checked.manifest === null && !lexists(join26(targetRepo, BUNDLE_PIN_REL)) && foundNothing) {
20042
+ if (checked.manifest === null && !lexists(join27(targetRepo, BUNDLE_PIN_REL)) && foundNothing) {
19973
20043
  return { outcome: "not-installed", exitCode: 0, ...result, credential: nothingToSay };
19974
20044
  }
19975
20045
  const credential = handleCredential(options, checked);
@@ -19977,7 +20047,7 @@ function uninstall(options) {
19977
20047
  if (result.failed.length === 0 && !credentialFailed) {
19978
20048
  removeInstalledFile(targetRepo, BUNDLE_PIN_REL, recorded.get(BUNDLE_PIN_REL), writeSet, result, name);
19979
20049
  try {
19980
- rmSync8(join26(targetRepo, INSTALL_MANIFEST_REL), { force: true });
20050
+ rmSync8(join27(targetRepo, INSTALL_MANIFEST_REL), { force: true });
19981
20051
  named2.add(INSTALL_MANIFEST_REL);
19982
20052
  } catch {
19983
20053
  name(result.failed, INSTALL_MANIFEST_REL, INSTALL_MANIFEST_REL);
@@ -20012,13 +20082,13 @@ function applyMergedJson(targetRepo, rule, file, deleteWhenEmpty, lists, name, e
20012
20082
  return;
20013
20083
  const empty = Object.keys(value).length === 0 && deleteWhenEmpty;
20014
20084
  writeBack(targetRepo, rel, file.text, empty ? null : inLineEndingOf(file.text, serializeJson(value)), lists, name);
20015
- if (adopted && lexists(join26(targetRepo, rel))) {
20085
+ if (adopted && lexists(join27(targetRepo, rel))) {
20016
20086
  name(lists.leftAlone, `${rel} (Halfcycle's hooks were taken out. There is no record of this file from before the install, so a permission rule or "$schema" Halfcycle added may still be there \u2014 it cannot be told apart from your own)`, rel);
20017
20087
  }
20018
20088
  }
20019
20089
  function removeCodexConfigBlock(targetRepo, record2, deleteWhenEmpty, lists, name) {
20020
20090
  const rel = CODEX_CONFIG_REL2;
20021
- const path = join26(targetRepo, rel);
20091
+ const path = join27(targetRepo, rel);
20022
20092
  if (symlinkOnPath(targetRepo, rel)) {
20023
20093
  if (lexists(path))
20024
20094
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
@@ -20063,7 +20133,7 @@ function removeInstalledFile(targetRepo, path, entry, writeSet, lists, name) {
20063
20133
  name(lists.leftAlone, `${path} (a symbolic link, or inside one \u2014 not followed)`, path);
20064
20134
  return;
20065
20135
  }
20066
- const abs = join26(targetRepo, path);
20136
+ const abs = join27(targetRepo, path);
20067
20137
  let isFile;
20068
20138
  try {
20069
20139
  isFile = lstatSync4(abs).isFile();
@@ -20097,7 +20167,7 @@ function removeInstalledFile(targetRepo, path, entry, writeSet, lists, name) {
20097
20167
  function removeEmptyDir(targetRepo, dir, writeSet, lists, name) {
20098
20168
  if (!writeSet.dirs.has(dir) || symlinkOnPath(targetRepo, dir))
20099
20169
  return;
20100
- const abs = join26(targetRepo, dir);
20170
+ const abs = join27(targetRepo, dir);
20101
20171
  try {
20102
20172
  if (!lstatSync4(abs).isDirectory() || readdirSync(abs).length > 0)
20103
20173
  return;
@@ -20116,7 +20186,7 @@ function trimAppendedFile(targetRepo, rec, deleteWhenEmpty, rules, lists, name)
20116
20186
  name(lists.leftAlone, `${rel} (a symbolic link \u2014 not followed)`, rel);
20117
20187
  return [];
20118
20188
  }
20119
- const path = join26(targetRepo, rel);
20189
+ const path = join27(targetRepo, rel);
20120
20190
  let before;
20121
20191
  try {
20122
20192
  before = readFileSync23(path, "utf-8");
@@ -20163,16 +20233,16 @@ function filesUnder(root, rel) {
20163
20233
  const walk = (dirRel) => {
20164
20234
  let names;
20165
20235
  try {
20166
- if (!lstatSync4(join26(root, dirRel)).isDirectory())
20236
+ if (!lstatSync4(join27(root, dirRel)).isDirectory())
20167
20237
  return;
20168
- names = readdirSync(join26(root, dirRel));
20238
+ names = readdirSync(join27(root, dirRel));
20169
20239
  } catch {
20170
20240
  return;
20171
20241
  }
20172
20242
  for (const entry of names.sort()) {
20173
20243
  const childRel = `${dirRel}/${entry}`;
20174
20244
  try {
20175
- if (lstatSync4(join26(root, childRel)).isDirectory())
20245
+ if (lstatSync4(join27(root, childRel)).isDirectory())
20176
20246
  walk(childRel);
20177
20247
  else
20178
20248
  out.push(childRel);
@@ -20677,7 +20747,7 @@ async function runCrew(repoRoot, deps) {
20677
20747
  // dist/pace.js
20678
20748
  import { spawn as spawn3 } from "node:child_process";
20679
20749
  import { readFileSync as readFileSync24 } from "node:fs";
20680
- import { join as join27 } from "node:path";
20750
+ import { join as join28 } from "node:path";
20681
20751
  var PACE_USAGE = `${ownCommand()} pace [--agent claude-code|codex] [--start <phase> [--agents <n>]] [--repo <root>]`;
20682
20752
  function parsePaceArgs(argv) {
20683
20753
  let repoRoot;
@@ -20791,7 +20861,7 @@ function notPacedLine(reason) {
20791
20861
  }
20792
20862
  function readPromptScript(repoRoot) {
20793
20863
  try {
20794
- return readFileSync24(join27(repoRoot, ".claude", "hooks", "user-prompt-scope.sh"), "utf-8");
20864
+ return readFileSync24(join28(repoRoot, ".claude", "hooks", "user-prompt-scope.sh"), "utf-8");
20795
20865
  } catch {
20796
20866
  return null;
20797
20867
  }
@@ -20851,7 +20921,7 @@ async function runPace(repoRoot, start, deps, agent = null) {
20851
20921
 
20852
20922
  // dist/route.js
20853
20923
  import { readFileSync as readFileSync25 } from "node:fs";
20854
- import { join as join28 } from "node:path";
20924
+ import { join as join29 } from "node:path";
20855
20925
  var ROUTE_USAGE = `${ownCommand()} route <phase> <task> [--agent claude-code|codex] [--repo <root>]`;
20856
20926
  var ROUTE_WORK_READ_DEADLINE_MS = 5e3;
20857
20927
  function parseRouteArgs(argv) {
@@ -20894,7 +20964,7 @@ function parseRouteArgs(argv) {
20894
20964
  return { ok: true, phase: positionals[0], task: positionals[1], agent: agent ?? "claude-code", repoRoot };
20895
20965
  }
20896
20966
  function routingPath(engagementId, home) {
20897
- return join28(engagementStateDir(engagementId, home), ROUTING_FILENAME);
20967
+ return join29(engagementStateDir(engagementId, home), ROUTING_FILENAME);
20898
20968
  }
20899
20969
  function readCheapStarted(path, phase) {
20900
20970
  try {
@@ -20987,7 +21057,7 @@ async function runRoute(repoRoot, phase, taskId, agent, deps) {
20987
21057
  import { spawnSync as spawnSync3 } from "node:child_process";
20988
21058
  import { closeSync as closeSync3, fchmodSync, lstatSync as lstatSync5, mkdirSync as mkdirSync12, openSync as openSync3, readdirSync as readdirSync2, readFileSync as readFileSync26, readlinkSync, realpathSync as realpathSync7, rmSync as rmSync9, symlinkSync, writeSync as writeSync3 } from "node:fs";
20989
21059
  import { homedir as homedir8 } from "node:os";
20990
- import { join as join29, resolve as resolve8 } from "node:path";
21060
+ import { join as join30, resolve as resolve8 } from "node:path";
20991
21061
  var RESTORE_USAGE = `${ownCommand()} restore [<id>]`;
20992
21062
  function parseRestoreArgs(rest) {
20993
21063
  if (rest.length > 1)
@@ -21009,7 +21079,7 @@ function runRestore(cwd, id, options = {}) {
21009
21079
  if (engagementId === null) {
21010
21080
  return refused2(`Halfcycle is not set up in this project, so it has saved nothing here. To set it up, run: ${ownCommand()}`);
21011
21081
  }
21012
- const folder2 = join29(options.home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SAVED_DIR_NAME);
21082
+ const folder2 = join30(options.home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SAVED_DIR_NAME);
21013
21083
  const refs = savedRefs(root);
21014
21084
  if (refs === null)
21015
21085
  return refused2("Halfcycle could not read the saved copies in this project, so nothing was put back.");
@@ -21085,7 +21155,7 @@ function restoreOne(root, folder2, refs, rawId) {
21085
21155
  if (p.keptIn === "commit")
21086
21156
  fromCommit.push(p.path);
21087
21157
  else
21088
- restoreCopy(root, join29(folder2, id), p.path, out);
21158
+ restoreCopy(root, join30(folder2, id), p.path, out);
21089
21159
  }
21090
21160
  if (fromCommit.length > 0)
21091
21161
  restoreFromCommit(root, ref, fromCommit, out);
@@ -21113,7 +21183,7 @@ function makeFolders(root, rel) {
21113
21183
  const segments = rel.split("/");
21114
21184
  let at = root;
21115
21185
  for (let i = 0; i < segments.length - 1; i++) {
21116
- at = join29(at, segments[i]);
21186
+ at = join30(at, segments[i]);
21117
21187
  const shown2 = segments.slice(0, i + 1).join("/");
21118
21188
  let st = lstatOrNull3(at);
21119
21189
  if (st === null) {
@@ -21133,7 +21203,7 @@ function makeFolders(root, rel) {
21133
21203
  return null;
21134
21204
  }
21135
21205
  function place(root, rel, content, out) {
21136
- const abs = join29(root, rel);
21206
+ const abs = join30(root, rel);
21137
21207
  const there = lstatOrNull3(abs);
21138
21208
  if (there !== null) {
21139
21209
  if (sameAs(abs, there, content))
@@ -21181,14 +21251,14 @@ function restoreCopy(root, saveDir, rel, out) {
21181
21251
  let at = saveDir;
21182
21252
  const chain = [SAVED_COPIES_DIR_NAME, ...segments];
21183
21253
  for (let i = 0; i < chain.length - 1; i++) {
21184
- at = join29(at, chain[i]);
21254
+ at = join30(at, chain[i]);
21185
21255
  const st2 = lstatOrNull3(at);
21186
21256
  if (st2 === null || st2.isSymbolicLink() || !st2.isDirectory()) {
21187
21257
  out.left.push(`${rel}: the saved copy does not hold it`);
21188
21258
  return;
21189
21259
  }
21190
21260
  }
21191
- const src = join29(at, chain[chain.length - 1]);
21261
+ const src = join30(at, chain[chain.length - 1]);
21192
21262
  const st = lstatOrNull3(src);
21193
21263
  try {
21194
21264
  if (st !== null && st.isSymbolicLink())
@@ -21292,7 +21362,7 @@ function restoreLines(root, ref, saved, out) {
21292
21362
  }
21293
21363
  function pinnedEngagement(root) {
21294
21364
  try {
21295
- const pin = JSON.parse(readFileSync26(join29(root, BUNDLE_PIN_REL), "utf-8"));
21365
+ const pin = JSON.parse(readFileSync26(join30(root, BUNDLE_PIN_REL), "utf-8"));
21296
21366
  return isEngagementId(pin.engagementId) ? pin.engagementId : null;
21297
21367
  } catch {
21298
21368
  return null;
@@ -21314,11 +21384,11 @@ function savedRefs(root) {
21314
21384
  return refs;
21315
21385
  }
21316
21386
  function readSaved(folder2, id) {
21317
- const dir = join29(folder2, id);
21387
+ const dir = join30(folder2, id);
21318
21388
  const st = lstatOrNull3(dir);
21319
21389
  if (st === null || !st.isDirectory())
21320
21390
  return null;
21321
- const file = join29(dir, SAVED_FILE_NAME);
21391
+ const file = join30(dir, SAVED_FILE_NAME);
21322
21392
  const fst = lstatOrNull3(file);
21323
21393
  if (fst === null || !fst.isFile())
21324
21394
  return null;
@@ -21344,7 +21414,7 @@ function pruneAtRestore(root, folder2, refs, now) {
21344
21414
  if (!savedIdSchema.safeParse(id).success)
21345
21415
  continue;
21346
21416
  here.add(id);
21347
- const dir = join29(folder2, id);
21417
+ const dir = join30(folder2, id);
21348
21418
  const st = lstatOrNull3(dir);
21349
21419
  const answer = savedPruneAnswer({
21350
21420
  refMadeAt: refs.get(id) ?? null,
@@ -21372,7 +21442,7 @@ function pruneAtRestore(root, folder2, refs, now) {
21372
21442
  }
21373
21443
  function markedRepository(dir) {
21374
21444
  try {
21375
- const text = readFileSync26(join29(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
21445
+ const text = readFileSync26(join30(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
21376
21446
  return text === "" ? null : text;
21377
21447
  } catch {
21378
21448
  return null;
@@ -21402,9 +21472,9 @@ function realOrSelf(p) {
21402
21472
  }
21403
21473
 
21404
21474
  // dist/request-shapes-verb.js
21405
- import { chmodSync as chmodSync4, existsSync as existsSync16, mkdirSync as mkdirSync13, readFileSync as readFileSync27, rmSync as rmSync10, writeFileSync as writeFileSync10 } from "node:fs";
21475
+ import { chmodSync as chmodSync4, existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync27, rmSync as rmSync10, writeFileSync as writeFileSync10 } from "node:fs";
21406
21476
  import { homedir as homedir9, platform as platform5 } from "node:os";
21407
- import { join as join30 } from "node:path";
21477
+ import { join as join31 } from "node:path";
21408
21478
  var REQUEST_SHAPES_USAGE = `${ownCommand()} request-shapes on|off|show|clear`;
21409
21479
  var REQUEST_SHAPES_FORMS = ["on", "off", "show", "clear"];
21410
21480
  var REQUEST_SHAPES_ON_LINE = "Halfcycle will write down the shape of every request this computer sends to it, never what is in them, until you run request-shapes off.";
@@ -21449,7 +21519,7 @@ function formatLine(line) {
21449
21519
  function showLog(logPath2) {
21450
21520
  let text = "";
21451
21521
  try {
21452
- text = existsSync16(logPath2) ? readFileSync27(logPath2, "utf-8") : "";
21522
+ text = existsSync17(logPath2) ? readFileSync27(logPath2, "utf-8") : "";
21453
21523
  } catch {
21454
21524
  text = "";
21455
21525
  }
@@ -21467,9 +21537,9 @@ function ownerOnly(path, mode) {
21467
21537
  chmodSync4(path, mode);
21468
21538
  }
21469
21539
  function runRequestShapes(form, home = homedir9()) {
21470
- const folder2 = join30(home, HALFCYCLE_DIR_NAME, REQUEST_SHAPES_DIR_NAME);
21471
- const switchPath = join30(folder2, REQUEST_SHAPES_SWITCH_FILENAME);
21472
- const logPath2 = join30(folder2, REQUEST_SHAPES_LOG_FILENAME);
21540
+ const folder2 = join31(home, HALFCYCLE_DIR_NAME, REQUEST_SHAPES_DIR_NAME);
21541
+ const switchPath = join31(folder2, REQUEST_SHAPES_SWITCH_FILENAME);
21542
+ const logPath2 = join31(folder2, REQUEST_SHAPES_LOG_FILENAME);
21473
21543
  try {
21474
21544
  switch (form) {
21475
21545
  case "on":
@@ -21486,7 +21556,7 @@ function runRequestShapes(form, home = homedir9()) {
21486
21556
  case "show":
21487
21557
  return { stdout: showLog(logPath2), stderr: "", exitCode: 0 };
21488
21558
  case "clear":
21489
- if (existsSync16(logPath2)) {
21559
+ if (existsSync17(logPath2)) {
21490
21560
  writeFileSync10(logPath2, "", { mode: 384 });
21491
21561
  ownerOnly(logPath2, 384);
21492
21562
  }
@@ -21795,7 +21865,7 @@ ${USAGE}`);
21795
21865
  if (installArm) {
21796
21866
  const engagementIdArg = positionals[1];
21797
21867
  const engagementTypeRaw = positionals[2] ?? "client";
21798
- if (!existsSync17(targetRepo)) {
21868
+ if (!existsSync18(targetRepo)) {
21799
21869
  process.stderr.write(`${folderMissingRefusal(targetRepo)}
21800
21870
  `);
21801
21871
  process.exit(1);