halfcycle 0.12.0-rc.3 → 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.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/cli.js +134 -64
- package/dist/cli.js.map +3 -3
- package/dist/index.js +16 -12
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +9 -0
- package/dist/install.d.ts.map +1 -1
- package/dist/local-allow.d.ts +8 -0
- package/dist/local-allow.d.ts.map +1 -1
- package/dist/ready.d.ts +9 -2
- package/dist/ready.d.ts.map +1 -1
- package/dist/setup-committed.d.ts +38 -0
- package/dist/setup-committed.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "halfcycle",
|
|
3
|
-
"version": "0.12.0-rc.
|
|
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
|
|
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
|
-
|
|
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 {
|
|
@@ -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
|
|
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
|
|
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 =
|
|
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 =
|
|
19362
|
-
const pinPath =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 (
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
20236
|
+
if (!lstatSync4(join27(root, dirRel)).isDirectory())
|
|
20167
20237
|
return;
|
|
20168
|
-
names = readdirSync(
|
|
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(
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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,
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
21471
|
-
const switchPath =
|
|
21472
|
-
const logPath2 =
|
|
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 (
|
|
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 (!
|
|
21868
|
+
if (!existsSync18(targetRepo)) {
|
|
21799
21869
|
process.stderr.write(`${folderMissingRefusal(targetRepo)}
|
|
21800
21870
|
`);
|
|
21801
21871
|
process.exit(1);
|