halfcycle 0.12.0-rc.2 → 0.12.0-rc.4

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.2",
3
+ "version": "0.12.0-rc.4",
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 {
@@ -13537,6 +13541,8 @@ var SCRIPTS = ["test", "build", "lint", "typecheck"];
13537
13541
  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}:*)`;
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";
13540
13546
  var INSTALLED_HOOK_SCRIPTS = Object.keys(OWNED_GENERATED_HEADERS).filter((path) => path.startsWith(".claude/hooks/"));
13541
13547
  var LOCAL_ALLOW_RULES = [
13542
13548
  ...SCRIPT_RUNNERS.flatMap((runner) => SCRIPTS.map((script) => bash(`${runner} ${script}`))),
@@ -13561,6 +13567,7 @@ var LOCAL_ALLOW_RULES = [
13561
13567
  bash("git diff"),
13562
13568
  bash("git log"),
13563
13569
  bash("git show"),
13570
+ bash(COMMIT_FILE_LISTING),
13564
13571
  bash("git add"),
13565
13572
  bash("git commit"),
13566
13573
  bash("git switch"),
@@ -13570,6 +13577,7 @@ var LOCAL_ALLOW_RULES = [
13570
13577
  bash("git merge"),
13571
13578
  bash("git worktree add"),
13572
13579
  bash("git worktree list"),
13580
+ `Bash(${CONTEXT_BUDGET_IGNORE_CHECK})`,
13573
13581
  bash("git pull --ff-only"),
13574
13582
  bash("git pull --rebase"),
13575
13583
  bash("npm install"),
@@ -19070,6 +19078,65 @@ function runCheckReport(source, head, deps = {}) {
19070
19078
  `).join(""), stderr: "", exitCode: 1 };
19071
19079
  }
19072
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
+
19073
19140
  // dist/ready.js
19074
19141
  var READY_USAGE = `${ownCommand()} ready <phase> [--cap <n>] [--repo <root>]`;
19075
19142
  var STATES_TEXT = buildTaskStateSchema.options.join(", ");
@@ -19202,6 +19269,11 @@ function runReady(repoRoot, phase, cap) {
19202
19269
  if (!read.ok)
19203
19270
  return failed2(read.lines.map((line) => `${line}
19204
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
+ }
19205
19277
  const titles = new Map(read.rows.map((row) => [row.id, row.title]));
19206
19278
  const set = readyTasks(read.rows);
19207
19279
  const out = [];
@@ -19296,9 +19368,9 @@ function runProveChild(binary, credential, repoRoot, words, deps = {}) {
19296
19368
  }
19297
19369
 
19298
19370
  // dist/uninstall.js
19299
- 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";
19300
19372
  import { homedir as homedir7 } from "node:os";
19301
- 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";
19302
19374
  var REMOVE_CREDENTIAL_FLAG = "--remove-credential";
19303
19375
  function parseUninstallArgs(args2) {
19304
19376
  let removeCredential = false;
@@ -19333,7 +19405,7 @@ function readMergedJson(targetRepo, rule) {
19333
19405
  const { rel } = rule;
19334
19406
  if (symlinkOnPath(targetRepo, rel))
19335
19407
  return { state: "symlink" };
19336
- const path = join26(targetRepo, rel);
19408
+ const path = join27(targetRepo, rel);
19337
19409
  if (!lexists(path))
19338
19410
  return { state: "absent" };
19339
19411
  let text;
@@ -19356,8 +19428,8 @@ function readMergedJson(targetRepo, rule) {
19356
19428
  }
19357
19429
  function validate(options, rules) {
19358
19430
  const { targetRepo, removeCredential, home } = options;
19359
- const manifestPath = join26(targetRepo, INSTALL_MANIFEST_REL);
19360
- const pinPath = join26(targetRepo, BUNDLE_PIN_REL);
19431
+ const manifestPath = join27(targetRepo, INSTALL_MANIFEST_REL);
19432
+ const pinPath = join27(targetRepo, BUNDLE_PIN_REL);
19361
19433
  if (symlinkOnPath(targetRepo, INSTALL_MANIFEST_REL) || symlinkOnPath(targetRepo, BUNDLE_PIN_REL)) {
19362
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.`);
19363
19435
  }
@@ -19398,7 +19470,7 @@ function validate(options, rules) {
19398
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.`);
19399
19471
  }
19400
19472
  if (engagementId !== void 0) {
19401
- const expectedParent = join26(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
19473
+ const expectedParent = join27(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
19402
19474
  if (dirname8(engagementStateDir(engagementId, home)) !== expectedParent) {
19403
19475
  throw new Refusal(`the project id in ${BUNDLE_PIN_REL} does not name a folder under ~/.halfcycle/engagements. Nothing was removed.`);
19404
19476
  }
@@ -19424,7 +19496,7 @@ function mergedFileRules(writeSet) {
19424
19496
  function writeBack(targetRepo, rel, current, next, lists, name) {
19425
19497
  if (next === current)
19426
19498
  return;
19427
- const path = join26(targetRepo, rel);
19499
+ const path = join27(targetRepo, rel);
19428
19500
  try {
19429
19501
  if (next === null) {
19430
19502
  rmSync8(path);
@@ -19441,7 +19513,7 @@ function statusLineClaimedFromTree(targetRepo, writeSet) {
19441
19513
  try {
19442
19514
  if (symlinkOnPath(targetRepo, SETTINGS_REL))
19443
19515
  return {};
19444
- const value = JSON.parse(readFileSync23(join26(targetRepo, SETTINGS_REL), "utf-8"));
19516
+ const value = JSON.parse(readFileSync23(join27(targetRepo, SETTINGS_REL), "utf-8"));
19445
19517
  if (!isPlainObject4(value) || !("statusLine" in value))
19446
19518
  return {};
19447
19519
  const hash = canonicalSha256(value["statusLine"]);
@@ -19454,7 +19526,7 @@ function attributionClaimedFromTree(targetRepo, writeSet) {
19454
19526
  try {
19455
19527
  if (symlinkOnPath(targetRepo, SETTINGS_REL))
19456
19528
  return {};
19457
- const value = JSON.parse(readFileSync23(join26(targetRepo, SETTINGS_REL), "utf-8"));
19529
+ const value = JSON.parse(readFileSync23(join27(targetRepo, SETTINGS_REL), "utf-8"));
19458
19530
  if (!isPlainObject4(value) || !("attribution" in value))
19459
19531
  return {};
19460
19532
  const hash = canonicalSha256(value["attribution"]);
@@ -19468,7 +19540,7 @@ function noRecord(targetRepo, writeSet) {
19468
19540
  const claim = (rel, header, lines) => {
19469
19541
  let text;
19470
19542
  try {
19471
- text = symlinkOnPath(targetRepo, rel) ? "" : readFileSync23(join26(targetRepo, rel), "utf-8");
19543
+ text = symlinkOnPath(targetRepo, rel) ? "" : readFileSync23(join27(targetRepo, rel), "utf-8");
19472
19544
  } catch {
19473
19545
  text = "";
19474
19546
  }
@@ -19714,7 +19786,7 @@ function lastOccurrence(text, block) {
19714
19786
  }
19715
19787
  function coveredPathExists(targetRepo, line) {
19716
19788
  const path = line.trim().replace(/^\//, "").replace(/\/$/, "");
19717
- return path !== "" && lexists(join26(targetRepo, path));
19789
+ return path !== "" && lexists(join27(targetRepo, path));
19718
19790
  }
19719
19791
  function selfBuildMergedFileRules() {
19720
19792
  return {
@@ -19728,7 +19800,7 @@ function removeSelfBuildOwnedFile(targetRepo, rel, lists, name) {
19728
19800
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19729
19801
  return;
19730
19802
  }
19731
- const abs = join26(targetRepo, rel);
19803
+ const abs = join27(targetRepo, rel);
19732
19804
  let isFile;
19733
19805
  try {
19734
19806
  isFile = lstatSync4(abs).isFile();
@@ -19752,7 +19824,7 @@ function removeSelfBuildCrewRoster(targetRepo, lists, name) {
19752
19824
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19753
19825
  return;
19754
19826
  }
19755
- const abs = join26(targetRepo, rel);
19827
+ const abs = join27(targetRepo, rel);
19756
19828
  let bytes;
19757
19829
  try {
19758
19830
  bytes = readFileSync23(abs);
@@ -19779,7 +19851,7 @@ function removeSelfBuildCrewProfile(targetRepo, rel, text, lists, name) {
19779
19851
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
19780
19852
  return;
19781
19853
  }
19782
- const abs = join26(targetRepo, rel);
19854
+ const abs = join27(targetRepo, rel);
19783
19855
  let bytes;
19784
19856
  try {
19785
19857
  bytes = readFileSync23(abs);
@@ -19804,7 +19876,7 @@ function removeSelfBuildCrewProfile(targetRepo, rel, text, lists, name) {
19804
19876
  function removeSelfBuildEmptyDir(targetRepo, dir, lists, name) {
19805
19877
  if (symlinkOnPath(targetRepo, dir))
19806
19878
  return;
19807
- const abs = join26(targetRepo, dir);
19879
+ const abs = join27(targetRepo, dir);
19808
19880
  try {
19809
19881
  if (!lstatSync4(abs).isDirectory() || readdirSync(abs).length > 0)
19810
19882
  return;
@@ -19838,7 +19910,7 @@ function uninstallSelfBuild(options) {
19838
19910
  throw err;
19839
19911
  }
19840
19912
  const { targetRepo } = options;
19841
- const pinExisted = lexists(join26(targetRepo, BUNDLE_PIN_REL));
19913
+ const pinExisted = lexists(join27(targetRepo, BUNDLE_PIN_REL));
19842
19914
  const name = (list2, text, _path) => {
19843
19915
  list2.push(text);
19844
19916
  };
@@ -19925,7 +19997,7 @@ function uninstall(options) {
19925
19997
  }
19926
19998
  const serverRemoved = removeOwnServerApproval(targetRepo);
19927
19999
  if (listRemoved || serverRemoved) {
19928
- if (existsSync15(join26(targetRepo, LOCAL_SETTINGS_REL2))) {
20000
+ if (existsSync16(join27(targetRepo, LOCAL_SETTINGS_REL2))) {
19929
20001
  name(result.restored, LOCAL_SETTINGS_REL2, LOCAL_SETTINGS_REL2);
19930
20002
  } else {
19931
20003
  name(result.removed, LOCAL_SETTINGS_REL2, LOCAL_SETTINGS_REL2);
@@ -19967,7 +20039,7 @@ function uninstall(options) {
19967
20039
  const gitattributes = manifest.gitattributes ?? { created: false, appended: [] };
19968
20040
  trimAppendedFile(targetRepo, gitattributes, deleteWhenEmpty(gitattributes.created), gitattributesRules(writeSet), result, name);
19969
20041
  const foundNothing = result.removed.length + result.restored.length + result.kept.length + result.failed.length === 0 && result.keptIgnoreLines.length === 0;
19970
- if (checked.manifest === null && !lexists(join26(targetRepo, BUNDLE_PIN_REL)) && foundNothing) {
20042
+ if (checked.manifest === null && !lexists(join27(targetRepo, BUNDLE_PIN_REL)) && foundNothing) {
19971
20043
  return { outcome: "not-installed", exitCode: 0, ...result, credential: nothingToSay };
19972
20044
  }
19973
20045
  const credential = handleCredential(options, checked);
@@ -19975,7 +20047,7 @@ function uninstall(options) {
19975
20047
  if (result.failed.length === 0 && !credentialFailed) {
19976
20048
  removeInstalledFile(targetRepo, BUNDLE_PIN_REL, recorded.get(BUNDLE_PIN_REL), writeSet, result, name);
19977
20049
  try {
19978
- rmSync8(join26(targetRepo, INSTALL_MANIFEST_REL), { force: true });
20050
+ rmSync8(join27(targetRepo, INSTALL_MANIFEST_REL), { force: true });
19979
20051
  named2.add(INSTALL_MANIFEST_REL);
19980
20052
  } catch {
19981
20053
  name(result.failed, INSTALL_MANIFEST_REL, INSTALL_MANIFEST_REL);
@@ -20010,13 +20082,13 @@ function applyMergedJson(targetRepo, rule, file, deleteWhenEmpty, lists, name, e
20010
20082
  return;
20011
20083
  const empty = Object.keys(value).length === 0 && deleteWhenEmpty;
20012
20084
  writeBack(targetRepo, rel, file.text, empty ? null : inLineEndingOf(file.text, serializeJson(value)), lists, name);
20013
- if (adopted && lexists(join26(targetRepo, rel))) {
20085
+ if (adopted && lexists(join27(targetRepo, rel))) {
20014
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);
20015
20087
  }
20016
20088
  }
20017
20089
  function removeCodexConfigBlock(targetRepo, record2, deleteWhenEmpty, lists, name) {
20018
20090
  const rel = CODEX_CONFIG_REL2;
20019
- const path = join26(targetRepo, rel);
20091
+ const path = join27(targetRepo, rel);
20020
20092
  if (symlinkOnPath(targetRepo, rel)) {
20021
20093
  if (lexists(path))
20022
20094
  name(lists.leftAlone, `${rel} (a symbolic link, or inside one \u2014 not followed)`, rel);
@@ -20061,7 +20133,7 @@ function removeInstalledFile(targetRepo, path, entry, writeSet, lists, name) {
20061
20133
  name(lists.leftAlone, `${path} (a symbolic link, or inside one \u2014 not followed)`, path);
20062
20134
  return;
20063
20135
  }
20064
- const abs = join26(targetRepo, path);
20136
+ const abs = join27(targetRepo, path);
20065
20137
  let isFile;
20066
20138
  try {
20067
20139
  isFile = lstatSync4(abs).isFile();
@@ -20095,7 +20167,7 @@ function removeInstalledFile(targetRepo, path, entry, writeSet, lists, name) {
20095
20167
  function removeEmptyDir(targetRepo, dir, writeSet, lists, name) {
20096
20168
  if (!writeSet.dirs.has(dir) || symlinkOnPath(targetRepo, dir))
20097
20169
  return;
20098
- const abs = join26(targetRepo, dir);
20170
+ const abs = join27(targetRepo, dir);
20099
20171
  try {
20100
20172
  if (!lstatSync4(abs).isDirectory() || readdirSync(abs).length > 0)
20101
20173
  return;
@@ -20114,7 +20186,7 @@ function trimAppendedFile(targetRepo, rec, deleteWhenEmpty, rules, lists, name)
20114
20186
  name(lists.leftAlone, `${rel} (a symbolic link \u2014 not followed)`, rel);
20115
20187
  return [];
20116
20188
  }
20117
- const path = join26(targetRepo, rel);
20189
+ const path = join27(targetRepo, rel);
20118
20190
  let before;
20119
20191
  try {
20120
20192
  before = readFileSync23(path, "utf-8");
@@ -20161,16 +20233,16 @@ function filesUnder(root, rel) {
20161
20233
  const walk = (dirRel) => {
20162
20234
  let names;
20163
20235
  try {
20164
- if (!lstatSync4(join26(root, dirRel)).isDirectory())
20236
+ if (!lstatSync4(join27(root, dirRel)).isDirectory())
20165
20237
  return;
20166
- names = readdirSync(join26(root, dirRel));
20238
+ names = readdirSync(join27(root, dirRel));
20167
20239
  } catch {
20168
20240
  return;
20169
20241
  }
20170
20242
  for (const entry of names.sort()) {
20171
20243
  const childRel = `${dirRel}/${entry}`;
20172
20244
  try {
20173
- if (lstatSync4(join26(root, childRel)).isDirectory())
20245
+ if (lstatSync4(join27(root, childRel)).isDirectory())
20174
20246
  walk(childRel);
20175
20247
  else
20176
20248
  out.push(childRel);
@@ -20675,7 +20747,7 @@ async function runCrew(repoRoot, deps) {
20675
20747
  // dist/pace.js
20676
20748
  import { spawn as spawn3 } from "node:child_process";
20677
20749
  import { readFileSync as readFileSync24 } from "node:fs";
20678
- import { join as join27 } from "node:path";
20750
+ import { join as join28 } from "node:path";
20679
20751
  var PACE_USAGE = `${ownCommand()} pace [--agent claude-code|codex] [--start <phase> [--agents <n>]] [--repo <root>]`;
20680
20752
  function parsePaceArgs(argv) {
20681
20753
  let repoRoot;
@@ -20789,7 +20861,7 @@ function notPacedLine(reason) {
20789
20861
  }
20790
20862
  function readPromptScript(repoRoot) {
20791
20863
  try {
20792
- 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");
20793
20865
  } catch {
20794
20866
  return null;
20795
20867
  }
@@ -20849,7 +20921,7 @@ async function runPace(repoRoot, start, deps, agent = null) {
20849
20921
 
20850
20922
  // dist/route.js
20851
20923
  import { readFileSync as readFileSync25 } from "node:fs";
20852
- import { join as join28 } from "node:path";
20924
+ import { join as join29 } from "node:path";
20853
20925
  var ROUTE_USAGE = `${ownCommand()} route <phase> <task> [--agent claude-code|codex] [--repo <root>]`;
20854
20926
  var ROUTE_WORK_READ_DEADLINE_MS = 5e3;
20855
20927
  function parseRouteArgs(argv) {
@@ -20892,7 +20964,7 @@ function parseRouteArgs(argv) {
20892
20964
  return { ok: true, phase: positionals[0], task: positionals[1], agent: agent ?? "claude-code", repoRoot };
20893
20965
  }
20894
20966
  function routingPath(engagementId, home) {
20895
- return join28(engagementStateDir(engagementId, home), ROUTING_FILENAME);
20967
+ return join29(engagementStateDir(engagementId, home), ROUTING_FILENAME);
20896
20968
  }
20897
20969
  function readCheapStarted(path, phase) {
20898
20970
  try {
@@ -20985,7 +21057,7 @@ async function runRoute(repoRoot, phase, taskId, agent, deps) {
20985
21057
  import { spawnSync as spawnSync3 } from "node:child_process";
20986
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";
20987
21059
  import { homedir as homedir8 } from "node:os";
20988
- import { join as join29, resolve as resolve8 } from "node:path";
21060
+ import { join as join30, resolve as resolve8 } from "node:path";
20989
21061
  var RESTORE_USAGE = `${ownCommand()} restore [<id>]`;
20990
21062
  function parseRestoreArgs(rest) {
20991
21063
  if (rest.length > 1)
@@ -21007,7 +21079,7 @@ function runRestore(cwd, id, options = {}) {
21007
21079
  if (engagementId === null) {
21008
21080
  return refused2(`Halfcycle is not set up in this project, so it has saved nothing here. To set it up, run: ${ownCommand()}`);
21009
21081
  }
21010
- 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);
21011
21083
  const refs = savedRefs(root);
21012
21084
  if (refs === null)
21013
21085
  return refused2("Halfcycle could not read the saved copies in this project, so nothing was put back.");
@@ -21083,7 +21155,7 @@ function restoreOne(root, folder2, refs, rawId) {
21083
21155
  if (p.keptIn === "commit")
21084
21156
  fromCommit.push(p.path);
21085
21157
  else
21086
- restoreCopy(root, join29(folder2, id), p.path, out);
21158
+ restoreCopy(root, join30(folder2, id), p.path, out);
21087
21159
  }
21088
21160
  if (fromCommit.length > 0)
21089
21161
  restoreFromCommit(root, ref, fromCommit, out);
@@ -21111,7 +21183,7 @@ function makeFolders(root, rel) {
21111
21183
  const segments = rel.split("/");
21112
21184
  let at = root;
21113
21185
  for (let i = 0; i < segments.length - 1; i++) {
21114
- at = join29(at, segments[i]);
21186
+ at = join30(at, segments[i]);
21115
21187
  const shown2 = segments.slice(0, i + 1).join("/");
21116
21188
  let st = lstatOrNull3(at);
21117
21189
  if (st === null) {
@@ -21131,7 +21203,7 @@ function makeFolders(root, rel) {
21131
21203
  return null;
21132
21204
  }
21133
21205
  function place(root, rel, content, out) {
21134
- const abs = join29(root, rel);
21206
+ const abs = join30(root, rel);
21135
21207
  const there = lstatOrNull3(abs);
21136
21208
  if (there !== null) {
21137
21209
  if (sameAs(abs, there, content))
@@ -21179,14 +21251,14 @@ function restoreCopy(root, saveDir, rel, out) {
21179
21251
  let at = saveDir;
21180
21252
  const chain = [SAVED_COPIES_DIR_NAME, ...segments];
21181
21253
  for (let i = 0; i < chain.length - 1; i++) {
21182
- at = join29(at, chain[i]);
21254
+ at = join30(at, chain[i]);
21183
21255
  const st2 = lstatOrNull3(at);
21184
21256
  if (st2 === null || st2.isSymbolicLink() || !st2.isDirectory()) {
21185
21257
  out.left.push(`${rel}: the saved copy does not hold it`);
21186
21258
  return;
21187
21259
  }
21188
21260
  }
21189
- const src = join29(at, chain[chain.length - 1]);
21261
+ const src = join30(at, chain[chain.length - 1]);
21190
21262
  const st = lstatOrNull3(src);
21191
21263
  try {
21192
21264
  if (st !== null && st.isSymbolicLink())
@@ -21290,7 +21362,7 @@ function restoreLines(root, ref, saved, out) {
21290
21362
  }
21291
21363
  function pinnedEngagement(root) {
21292
21364
  try {
21293
- 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"));
21294
21366
  return isEngagementId(pin.engagementId) ? pin.engagementId : null;
21295
21367
  } catch {
21296
21368
  return null;
@@ -21312,11 +21384,11 @@ function savedRefs(root) {
21312
21384
  return refs;
21313
21385
  }
21314
21386
  function readSaved(folder2, id) {
21315
- const dir = join29(folder2, id);
21387
+ const dir = join30(folder2, id);
21316
21388
  const st = lstatOrNull3(dir);
21317
21389
  if (st === null || !st.isDirectory())
21318
21390
  return null;
21319
- const file = join29(dir, SAVED_FILE_NAME);
21391
+ const file = join30(dir, SAVED_FILE_NAME);
21320
21392
  const fst = lstatOrNull3(file);
21321
21393
  if (fst === null || !fst.isFile())
21322
21394
  return null;
@@ -21342,7 +21414,7 @@ function pruneAtRestore(root, folder2, refs, now) {
21342
21414
  if (!savedIdSchema.safeParse(id).success)
21343
21415
  continue;
21344
21416
  here.add(id);
21345
- const dir = join29(folder2, id);
21417
+ const dir = join30(folder2, id);
21346
21418
  const st = lstatOrNull3(dir);
21347
21419
  const answer = savedPruneAnswer({
21348
21420
  refMadeAt: refs.get(id) ?? null,
@@ -21370,7 +21442,7 @@ function pruneAtRestore(root, folder2, refs, now) {
21370
21442
  }
21371
21443
  function markedRepository(dir) {
21372
21444
  try {
21373
- 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();
21374
21446
  return text === "" ? null : text;
21375
21447
  } catch {
21376
21448
  return null;
@@ -21400,9 +21472,9 @@ function realOrSelf(p) {
21400
21472
  }
21401
21473
 
21402
21474
  // dist/request-shapes-verb.js
21403
- 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";
21404
21476
  import { homedir as homedir9, platform as platform5 } from "node:os";
21405
- import { join as join30 } from "node:path";
21477
+ import { join as join31 } from "node:path";
21406
21478
  var REQUEST_SHAPES_USAGE = `${ownCommand()} request-shapes on|off|show|clear`;
21407
21479
  var REQUEST_SHAPES_FORMS = ["on", "off", "show", "clear"];
21408
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.";
@@ -21447,7 +21519,7 @@ function formatLine(line) {
21447
21519
  function showLog(logPath2) {
21448
21520
  let text = "";
21449
21521
  try {
21450
- text = existsSync16(logPath2) ? readFileSync27(logPath2, "utf-8") : "";
21522
+ text = existsSync17(logPath2) ? readFileSync27(logPath2, "utf-8") : "";
21451
21523
  } catch {
21452
21524
  text = "";
21453
21525
  }
@@ -21465,9 +21537,9 @@ function ownerOnly(path, mode) {
21465
21537
  chmodSync4(path, mode);
21466
21538
  }
21467
21539
  function runRequestShapes(form, home = homedir9()) {
21468
- const folder2 = join30(home, HALFCYCLE_DIR_NAME, REQUEST_SHAPES_DIR_NAME);
21469
- const switchPath = join30(folder2, REQUEST_SHAPES_SWITCH_FILENAME);
21470
- 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);
21471
21543
  try {
21472
21544
  switch (form) {
21473
21545
  case "on":
@@ -21484,7 +21556,7 @@ function runRequestShapes(form, home = homedir9()) {
21484
21556
  case "show":
21485
21557
  return { stdout: showLog(logPath2), stderr: "", exitCode: 0 };
21486
21558
  case "clear":
21487
- if (existsSync16(logPath2)) {
21559
+ if (existsSync17(logPath2)) {
21488
21560
  writeFileSync10(logPath2, "", { mode: 384 });
21489
21561
  ownerOnly(logPath2, 384);
21490
21562
  }
@@ -21793,7 +21865,7 @@ ${USAGE}`);
21793
21865
  if (installArm) {
21794
21866
  const engagementIdArg = positionals[1];
21795
21867
  const engagementTypeRaw = positionals[2] ?? "client";
21796
- if (!existsSync17(targetRepo)) {
21868
+ if (!existsSync18(targetRepo)) {
21797
21869
  process.stderr.write(`${folderMissingRefusal(targetRepo)}
21798
21870
  `);
21799
21871
  process.exit(1);