@amistio/cli 0.1.44 → 0.1.45
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/README.md +1 -1
- package/dist/index.js +58 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,7 +88,7 @@ Approved implementation work uses Git as the handoff boundary. During worktree p
|
|
|
88
88
|
|
|
89
89
|
Failed or stale work can be requeued from the web Tasks panel. Requeue creates a new linked work attempt and preserves the original terminal attempt for audit history; Requeue all sends one backend batch that recomputes safe candidates, reports already-active and skipped rows, and still uses linked attempts. Requeue is blocked while equivalent work is already active or when the paired runner does not advertise the needed work kind. Completed implementation status is separate from proof: queue `implementationVerification` from Tasks when a plan needs source-aware evidence before cleanup or implementation status decisions.
|
|
90
90
|
|
|
91
|
-
Runner setup and local-tool execution use bounded failure controls. `amistio run --watch`
|
|
91
|
+
Runner setup and local-tool execution use bounded failure controls. During Git worktree preflight, `amistio run --watch` repairs safe stale Git registrations when the target worktree directory is missing and Git marks the registration prunable; dirty, present, or ambiguous worktrees are preserved. Other Git worktree preflight failures are retried by releasing the claim for another attempt, then fail the work item after `--max-preflight-attempts` attempts, defaulting to 3. Active local-tool runs renew the work lease, and `--tool-timeout-seconds` caps tool execution, defaulting to 1800 seconds.
|
|
92
92
|
|
|
93
93
|
The environment doctor blocks work before local AI/tool execution when `git`, `node`, Corepack, the package manager, required package scripts, dependencies, setup allowlist, Docker, or the requested execution profile is not ready. Foreground, background, and startup-service runners accept `--execution-profile`; use `--setup-package-manager-install` with `hostWorktreeWithSetup` when the runner may run the fixed package-manager install step in the execution worktree. Work and Runner surfaces receive sanitized profile/readiness metadata only; raw host paths, command lines, environment values, and secrets are not uploaded. Watch mode also performs a Git PATH preflight before auto-sync or work claiming. If the runner reports that Git is not available to the runner PATH, install Git or restart the foreground, background, or startup-service runner from an environment where `git --version` works. On macOS, service and GUI-launched runner environments may not inherit the same PATH as an interactive shell, so restart or reinstall the service after changing PATH.
|
|
94
94
|
|
package/dist/index.js
CHANGED
|
@@ -9505,6 +9505,7 @@ async function prepareGitWorktreeIsolation(rootDir, workItem) {
|
|
|
9505
9505
|
const preparedLocalEnvironmentFileCount2 = await prepareLocalWorktreeEnvironment(repoRoot, worktreePath);
|
|
9506
9506
|
return { ...identity, baseRevision, worktreePath, ...preparedLocalEnvironmentFileCount2 ? { preparedLocalEnvironmentFileCount: preparedLocalEnvironmentFileCount2 } : {} };
|
|
9507
9507
|
}
|
|
9508
|
+
await repairMissingRegisteredWorktree(repoRoot, worktreePath, identity.branch, identity.worktreeKey);
|
|
9508
9509
|
await mkdir12(path17.dirname(worktreePath), { recursive: true });
|
|
9509
9510
|
const branchExists = await gitCommandSucceeds(repoRoot, ["show-ref", "--verify", "--quiet", `refs/heads/${identity.branch}`]);
|
|
9510
9511
|
const worktreeArgs = branchExists ? ["worktree", "add", worktreePath, identity.branch] : ["worktree", "add", "-b", identity.branch, worktreePath, baseRevision];
|
|
@@ -9534,6 +9535,63 @@ async function assertExistingWorktree(worktreePath, branch) {
|
|
|
9534
9535
|
throw new Error(`Existing worktree is on ${currentBranch}; expected ${branch}.`);
|
|
9535
9536
|
}
|
|
9536
9537
|
}
|
|
9538
|
+
async function repairMissingRegisteredWorktree(repoRoot, worktreePath, branch, worktreeKey) {
|
|
9539
|
+
const registeredWorktree = await findRegisteredWorktree(repoRoot, worktreePath);
|
|
9540
|
+
if (!registeredWorktree) {
|
|
9541
|
+
return;
|
|
9542
|
+
}
|
|
9543
|
+
const expectedBranchRef = `refs/heads/${branch}`;
|
|
9544
|
+
if (registeredWorktree.branch !== expectedBranchRef) {
|
|
9545
|
+
throw new Error(`Registered Git worktree ${worktreeKey} is missing on disk but belongs to ${registeredWorktree.branch ?? "detached HEAD"}; expected ${expectedBranchRef}. Repair local Git worktrees before retrying.`);
|
|
9546
|
+
}
|
|
9547
|
+
if (registeredWorktree.locked || !registeredWorktree.prunable) {
|
|
9548
|
+
throw new Error(`Registered Git worktree ${worktreeKey} is missing on disk but is not safely prunable. Repair local Git worktrees before retrying.`);
|
|
9549
|
+
}
|
|
9550
|
+
await gitOutput(repoRoot, ["worktree", "prune", "--expire", "now"]);
|
|
9551
|
+
const remainingWorktree = await findRegisteredWorktree(repoRoot, worktreePath);
|
|
9552
|
+
if (remainingWorktree) {
|
|
9553
|
+
throw new Error(`Registered Git worktree ${worktreeKey} remained after pruning. Repair local Git worktrees before retrying.`);
|
|
9554
|
+
}
|
|
9555
|
+
}
|
|
9556
|
+
async function findRegisteredWorktree(repoRoot, worktreePath) {
|
|
9557
|
+
const worktrees = parseRegisteredGitWorktrees(await gitOutput(repoRoot, ["worktree", "list", "--porcelain"]));
|
|
9558
|
+
const targetPath = normalizeGitWorktreePath(worktreePath);
|
|
9559
|
+
return worktrees.find((worktree) => normalizeGitWorktreePath(worktree.path) === targetPath);
|
|
9560
|
+
}
|
|
9561
|
+
function parseRegisteredGitWorktrees(output) {
|
|
9562
|
+
const worktrees = [];
|
|
9563
|
+
let current;
|
|
9564
|
+
for (const line of output.split(/\r?\n/)) {
|
|
9565
|
+
if (!line) {
|
|
9566
|
+
current = void 0;
|
|
9567
|
+
continue;
|
|
9568
|
+
}
|
|
9569
|
+
if (line.startsWith("worktree ")) {
|
|
9570
|
+
current = { locked: false, path: line.slice("worktree ".length), prunable: false };
|
|
9571
|
+
worktrees.push(current);
|
|
9572
|
+
continue;
|
|
9573
|
+
}
|
|
9574
|
+
if (!current) {
|
|
9575
|
+
continue;
|
|
9576
|
+
}
|
|
9577
|
+
if (line.startsWith("branch ")) {
|
|
9578
|
+
current.branch = line.slice("branch ".length);
|
|
9579
|
+
continue;
|
|
9580
|
+
}
|
|
9581
|
+
if (line.startsWith("locked")) {
|
|
9582
|
+
current.locked = true;
|
|
9583
|
+
continue;
|
|
9584
|
+
}
|
|
9585
|
+
if (line.startsWith("prunable")) {
|
|
9586
|
+
current.prunable = true;
|
|
9587
|
+
}
|
|
9588
|
+
}
|
|
9589
|
+
return worktrees;
|
|
9590
|
+
}
|
|
9591
|
+
function normalizeGitWorktreePath(value) {
|
|
9592
|
+
const resolved = path17.resolve(value);
|
|
9593
|
+
return resolved.startsWith("/private/var/") ? resolved.replace("/private/var/", "/var/") : resolved;
|
|
9594
|
+
}
|
|
9537
9595
|
async function assertBaseRevision(repoRoot, baseRevision, currentHead) {
|
|
9538
9596
|
if (!baseRevision || baseRevision === currentHead) {
|
|
9539
9597
|
return;
|