@codions/portta 0.0.0-develop.159.sha-0da77d5 → 0.0.0-develop.166.sha-d31f10f

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/dist/host.js CHANGED
@@ -33142,7 +33142,7 @@ var require_compile = __commonJS({
33142
33142
  const schOrFunc = root.refs[ref];
33143
33143
  if (schOrFunc)
33144
33144
  return schOrFunc;
33145
- let _sch = resolve21.call(this, root, ref);
33145
+ let _sch = resolve22.call(this, root, ref);
33146
33146
  if (_sch === void 0) {
33147
33147
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
33148
33148
  const { schemaId } = this.opts;
@@ -33169,7 +33169,7 @@ var require_compile = __commonJS({
33169
33169
  function sameSchemaEnv(s1, s2) {
33170
33170
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
33171
33171
  }
33172
- function resolve21(root, ref) {
33172
+ function resolve22(root, ref) {
33173
33173
  let sch;
33174
33174
  while (typeof (sch = this.refs[ref]) == "string")
33175
33175
  ref = sch;
@@ -33994,7 +33994,7 @@ var require_fast_uri = __commonJS({
33994
33994
  }
33995
33995
  return uri;
33996
33996
  }
33997
- function resolve21(baseURI, relativeURI, options) {
33997
+ function resolve22(baseURI, relativeURI, options) {
33998
33998
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
33999
33999
  const {
34000
34000
  parsed: baseParsed,
@@ -34027,49 +34027,49 @@ var require_fast_uri = __commonJS({
34027
34027
  schemelessOptions.skipEscape = true;
34028
34028
  return serialize2(resolved2, schemelessOptions);
34029
34029
  }
34030
- function resolveComponent(base, relative5, options, skipNormalization) {
34030
+ function resolveComponent(base, relative6, options, skipNormalization) {
34031
34031
  const target = {};
34032
34032
  if (!skipNormalization) {
34033
34033
  base = parse4(serialize2(base, options), options);
34034
- relative5 = parse4(serialize2(relative5, options), options);
34034
+ relative6 = parse4(serialize2(relative6, options), options);
34035
34035
  }
34036
34036
  options = options || {};
34037
- if (!options.tolerant && relative5.scheme) {
34038
- target.scheme = relative5.scheme;
34039
- target.userinfo = relative5.userinfo;
34040
- target.host = relative5.host;
34041
- target.port = relative5.port;
34042
- target.path = removeDotSegments(relative5.path || "");
34043
- target.query = relative5.query;
34037
+ if (!options.tolerant && relative6.scheme) {
34038
+ target.scheme = relative6.scheme;
34039
+ target.userinfo = relative6.userinfo;
34040
+ target.host = relative6.host;
34041
+ target.port = relative6.port;
34042
+ target.path = removeDotSegments(relative6.path || "");
34043
+ target.query = relative6.query;
34044
34044
  } else {
34045
- if (relative5.userinfo !== void 0 || relative5.host !== void 0 || relative5.port !== void 0) {
34046
- target.userinfo = relative5.userinfo;
34047
- target.host = relative5.host;
34048
- target.port = relative5.port;
34049
- target.path = removeDotSegments(relative5.path || "");
34050
- target.query = relative5.query;
34045
+ if (relative6.userinfo !== void 0 || relative6.host !== void 0 || relative6.port !== void 0) {
34046
+ target.userinfo = relative6.userinfo;
34047
+ target.host = relative6.host;
34048
+ target.port = relative6.port;
34049
+ target.path = removeDotSegments(relative6.path || "");
34050
+ target.query = relative6.query;
34051
34051
  } else {
34052
- if (!relative5.path) {
34052
+ if (!relative6.path) {
34053
34053
  target.path = base.path;
34054
- if (relative5.query !== void 0) {
34055
- target.query = relative5.query;
34054
+ if (relative6.query !== void 0) {
34055
+ target.query = relative6.query;
34056
34056
  } else {
34057
34057
  target.query = base.query;
34058
34058
  }
34059
34059
  } else {
34060
- if (relative5.path[0] === "/") {
34061
- target.path = removeDotSegments(relative5.path);
34060
+ if (relative6.path[0] === "/") {
34061
+ target.path = removeDotSegments(relative6.path);
34062
34062
  } else {
34063
34063
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
34064
- target.path = "/" + relative5.path;
34064
+ target.path = "/" + relative6.path;
34065
34065
  } else if (!base.path) {
34066
- target.path = relative5.path;
34066
+ target.path = relative6.path;
34067
34067
  } else {
34068
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative5.path;
34068
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative6.path;
34069
34069
  }
34070
34070
  target.path = removeDotSegments(target.path);
34071
34071
  }
34072
- target.query = relative5.query;
34072
+ target.query = relative6.query;
34073
34073
  }
34074
34074
  target.userinfo = base.userinfo;
34075
34075
  target.host = base.host;
@@ -34077,7 +34077,7 @@ var require_fast_uri = __commonJS({
34077
34077
  }
34078
34078
  target.scheme = base.scheme;
34079
34079
  }
34080
- target.fragment = relative5.fragment;
34080
+ target.fragment = relative6.fragment;
34081
34081
  return target;
34082
34082
  }
34083
34083
  function equal(uriA, uriB, options) {
@@ -34356,7 +34356,7 @@ var require_fast_uri = __commonJS({
34356
34356
  var fastUri = {
34357
34357
  SCHEMES,
34358
34358
  normalize: normalize2,
34359
- resolve: resolve21,
34359
+ resolve: resolve22,
34360
34360
  resolveComponent,
34361
34361
  equal,
34362
34362
  serialize: serialize2,
@@ -41506,10 +41506,9 @@ function expandTemplate(template, env2) {
41506
41506
 
41507
41507
  // ../host/src/modules/taskflow/adapters/devcontainer-environment.ts
41508
41508
  import { createHash as createHash3 } from "node:crypto";
41509
- import { readFileSync as readFileSync3 } from "node:fs";
41510
- import { access, readdir, readFile } from "node:fs/promises";
41509
+ import { access as access2, readdir, readFile as readFile2 } from "node:fs/promises";
41511
41510
  import { createRequire } from "node:module";
41512
- import { dirname as dirname4, isAbsolute as isAbsolute2, join as join4, posix, relative, resolve as resolve2, sep } from "node:path";
41511
+ import { dirname as dirname4, join as join5, relative as relative2, resolve as resolve3 } from "node:path";
41513
41512
 
41514
41513
  // ../../node_modules/zod/v4/classic/external.js
41515
41514
  var external_exports = {};
@@ -44775,16 +44774,16 @@ function hostToolInvocation(tool, options) {
44775
44774
  return /[\s'"\\]/.test(resolved2) ? `'${resolved2.replaceAll("'", "'\\''")}'` : resolved2;
44776
44775
  }
44777
44776
  function resolveWorkerBins(env2 = process.env) {
44778
- const resolve21 = (name, override) => {
44777
+ const resolve22 = (name, override) => {
44779
44778
  const explicit = override?.trim();
44780
44779
  if (explicit) return resolveHostTool(explicit, { env: env2 }) ?? explicit;
44781
44780
  return resolveHostTool(name, { env: env2 }) ?? void 0;
44782
44781
  };
44783
44782
  return {
44784
- codexBin: resolve21("codex", env2.CODEX_BIN),
44785
- opencodeBin: resolve21("opencode", env2.OPENCODE_BIN),
44786
- pathToClaudeCodeExecutable: resolve21("claude"),
44787
- piBin: resolve21("pi", env2.PI_BIN)
44783
+ codexBin: resolve22("codex", env2.CODEX_BIN),
44784
+ opencodeBin: resolve22("opencode", env2.OPENCODE_BIN),
44785
+ pathToClaudeCodeExecutable: resolve22("claude"),
44786
+ piBin: resolve22("pi", env2.PI_BIN)
44788
44787
  };
44789
44788
  }
44790
44789
 
@@ -44822,10 +44821,10 @@ function webStream(stream) {
44822
44821
  };
44823
44822
  }
44824
44823
  function writeToStdin(stream, input2) {
44825
- return new Promise((resolve21, reject2) => {
44824
+ return new Promise((resolve22, reject2) => {
44826
44825
  stream.write(input2, (error61) => {
44827
44826
  if (error61) reject2(error61);
44828
- else resolve21();
44827
+ else resolve22();
44829
44828
  });
44830
44829
  });
44831
44830
  }
@@ -44847,8 +44846,8 @@ var NodeProcessRunner = class {
44847
44846
  let settled = false;
44848
44847
  let resolveExit = () => {
44849
44848
  };
44850
- const exited = new Promise((resolve21) => {
44851
- resolveExit = resolve21;
44849
+ const exited = new Promise((resolve22) => {
44850
+ resolveExit = resolve22;
44852
44851
  });
44853
44852
  const finish = (code, signal, closeOutputs = false) => {
44854
44853
  if (settled) return;
@@ -44926,6 +44925,177 @@ async function runCaptured(runner, spec) {
44926
44925
  return { stdout, stderr, exit };
44927
44926
  }
44928
44927
 
44928
+ // ../host/src/modules/taskflow/adapters/worktree-git-mount.ts
44929
+ import { access, readFile, realpath, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
44930
+ import { basename as basename2, isAbsolute as isAbsolute2, join as join4, posix, relative, resolve as resolve2, sep } from "node:path";
44931
+ var PREFLIGHT = "Dev Container preflight";
44932
+ var BACK_LINK = "gitdir";
44933
+ function repairCommand(workspacePath) {
44934
+ return `git -C ${workspacePath} worktree repair --relative-paths`;
44935
+ }
44936
+ function toPosix(value) {
44937
+ return sep === "/" ? value : value.replaceAll(sep, "/");
44938
+ }
44939
+ async function exists(path) {
44940
+ try {
44941
+ await access(path);
44942
+ return true;
44943
+ } catch {
44944
+ return false;
44945
+ }
44946
+ }
44947
+ async function readRaw(path) {
44948
+ try {
44949
+ return await readFile(path, "utf8");
44950
+ } catch {
44951
+ return null;
44952
+ }
44953
+ }
44954
+ async function writeAtomic(path, content) {
44955
+ const temporary = `${path}.${process.pid}.${Date.now()}.tmp`;
44956
+ try {
44957
+ await writeFile2(temporary, content, "utf8");
44958
+ await rename(temporary, path);
44959
+ } catch (error61) {
44960
+ await unlink(temporary).catch(() => {
44961
+ });
44962
+ throw error61;
44963
+ }
44964
+ }
44965
+ async function gitDirs(runner, cwd) {
44966
+ const result = await runCaptured(runner, {
44967
+ command: "git",
44968
+ args: ["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"],
44969
+ cwd
44970
+ });
44971
+ if (result.exit.code !== 0) return null;
44972
+ const [gitDir, commonDir] = result.stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
44973
+ return gitDir && commonDir ? { gitDir, commonDir } : null;
44974
+ }
44975
+ function linkTarget(content) {
44976
+ const value = content.trim();
44977
+ if (!value.startsWith("gitdir:")) return null;
44978
+ const target = value.slice("gitdir:".length).trim();
44979
+ return target.length > 0 ? target : null;
44980
+ }
44981
+ async function worktreeLink(workspacePath) {
44982
+ const content = await readRaw(join4(workspacePath, ".git"));
44983
+ return content === null ? null : linkTarget(content);
44984
+ }
44985
+ async function porttaOwned(runner, workspacePath, gitDir) {
44986
+ if (await exists(gitRuntimePaths(gitDir).meta)) return true;
44987
+ const result = await runCaptured(runner, {
44988
+ command: "git",
44989
+ args: ["config", "--get", RUNTIME_IDENTITY.gitBaseConfigKey],
44990
+ cwd: workspacePath
44991
+ });
44992
+ return result.exit.code === 0 && result.stdout.trim().length > 0;
44993
+ }
44994
+ async function planRelativeRelink(workspacePath, dirs) {
44995
+ const forwardPath = join4(workspacePath, ".git");
44996
+ const backPath = join4(dirs.gitDir, BACK_LINK);
44997
+ if (join4(dirs.commonDir, "worktrees", basename2(dirs.gitDir)) !== dirs.gitDir)
44998
+ return {
44999
+ ok: false,
45000
+ reason: `its Git dir ${dirs.gitDir} is not <common dir>/worktrees/<id> under ${dirs.commonDir}`
45001
+ };
45002
+ const forward = await readRaw(forwardPath);
45003
+ if (forward === null) return { ok: false, reason: `${forwardPath} could not be read` };
45004
+ const target = linkTarget(forward);
45005
+ if (target === null) return { ok: false, reason: `${forwardPath} does not record a gitdir link` };
45006
+ if (resolve2(workspacePath, target) !== dirs.gitDir)
45007
+ return { ok: false, reason: `${forwardPath} points at ${resolve2(workspacePath, target)}, not at ${dirs.gitDir}` };
45008
+ const back = await readRaw(backPath);
45009
+ if (back === null) return { ok: false, reason: `${backPath} could not be read` };
45010
+ if (resolve2(dirs.gitDir, back.trim()) !== forwardPath)
45011
+ return { ok: false, reason: `${backPath} points at ${resolve2(dirs.gitDir, back.trim())}, not at ${forwardPath}` };
45012
+ return {
45013
+ ok: true,
45014
+ writes: [
45015
+ { path: forwardPath, previous: forward, next: `gitdir: ${toPosix(relative(workspacePath, dirs.gitDir))}
45016
+ ` },
45017
+ { path: backPath, previous: back, next: `${toPosix(relative(dirs.gitDir, forwardPath))}
45018
+ ` }
45019
+ ]
45020
+ };
45021
+ }
45022
+ async function relinkRelative(runner, workspacePath, dirs) {
45023
+ const plan = await planRelativeRelink(workspacePath, dirs);
45024
+ if (!plan.ok) return plan.reason;
45025
+ const written = [];
45026
+ const restore = async () => {
45027
+ for (const write2 of written) await writeAtomic(write2.path, write2.previous).catch(() => {
45028
+ });
45029
+ };
45030
+ for (const write2 of plan.writes) {
45031
+ try {
45032
+ await writeAtomic(write2.path, write2.next);
45033
+ written.push(write2);
45034
+ } catch (error61) {
45035
+ await restore();
45036
+ return `${write2.path} could not be rewritten: ${error61 instanceof Error ? error61.message : String(error61)}`;
45037
+ }
45038
+ }
45039
+ const after = await gitDirs(runner, workspacePath);
45040
+ if (!after || after.gitDir !== dirs.gitDir || after.commonDir !== dirs.commonDir) {
45041
+ await restore();
45042
+ return "the rewritten links did not resolve back to the same repository, so they were reverted";
45043
+ }
45044
+ return null;
45045
+ }
45046
+ async function worktreeGitMountArgs(input2) {
45047
+ const { runner } = input2;
45048
+ const workspacePath = await realpath(input2.workspacePath).catch(() => input2.workspacePath);
45049
+ const dirs = await gitDirs(runner, workspacePath);
45050
+ if (!dirs || dirs.gitDir === dirs.commonDir) return [];
45051
+ const where = input2.configRef ? `${workspacePath} (${input2.configRef})` : workspacePath;
45052
+ if (input2.workspaceMount) {
45053
+ throw new Error(
45054
+ `${PREFLIGHT}: ${where} is a linked Git worktree and the configuration sets a custom workspaceMount. The Dev Containers CLI then ignores --mount-git-worktree-common-dir (devcontainers/cli#1243), so the Git common dir cannot be mounted and Git would not work inside the container. Remove workspaceMount from the Dev Container configuration, or open this configuration from the main checkout.`
45055
+ );
45056
+ }
45057
+ let link = await worktreeLink(workspacePath);
45058
+ const backLink = await readRaw(join4(dirs.gitDir, BACK_LINK));
45059
+ if (link !== null && isAbsolute2(link) || backLink !== null && isAbsolute2(backLink.trim())) {
45060
+ if (!await porttaOwned(runner, workspacePath, dirs.gitDir)) {
45061
+ throw new Error(
45062
+ `${PREFLIGHT}: the Git worktree at ${where} is linked with an absolute gitdir, which does not exist inside a container. Portta did not create this worktree and will not rewrite its links. Migrate it explicitly with: ${repairCommand(workspacePath)}`
45063
+ );
45064
+ }
45065
+ const failure = await relinkRelative(runner, workspacePath, dirs);
45066
+ if (failure !== null) {
45067
+ throw new Error(
45068
+ `${PREFLIGHT}: the Git worktree at ${where} is linked with an absolute gitdir and could not be migrated to relative links: ${failure}. Run: ${repairCommand(workspacePath)}`
45069
+ );
45070
+ }
45071
+ link = await worktreeLink(workspacePath);
45072
+ }
45073
+ if (link === null || isAbsolute2(link)) {
45074
+ throw new Error(
45075
+ `${PREFLIGHT}: the Git worktree at ${where} has no relative gitdir link, so the Git common dir cannot be mounted into the container. Run: ${repairCommand(workspacePath)}`
45076
+ );
45077
+ }
45078
+ const containerWorkspacePath = input2.containerWorkspacePath;
45079
+ if (!containerWorkspacePath) {
45080
+ throw new Error(
45081
+ `${PREFLIGHT}: the container workspace folder for ${where} is unknown, so the Git common dir of this linked worktree cannot be mounted into the container.`
45082
+ );
45083
+ }
45084
+ const up = toPosix(relative(dirs.gitDir, dirs.commonDir));
45085
+ if (up.length === 0 || up.split("/").some((segment) => segment !== "..")) {
45086
+ throw new Error(
45087
+ `${PREFLIGHT}: the Git common dir ${dirs.commonDir} does not contain the worktree Git dir ${dirs.gitDir}, so it cannot be mapped into the container for ${where}.`
45088
+ );
45089
+ }
45090
+ const containerGitDir = posix.resolve(containerWorkspacePath, toPosix(link));
45091
+ const containerCommonDir = posix.resolve(containerGitDir, up);
45092
+ return [
45093
+ "--mount-git-worktree-common-dir",
45094
+ "--mount",
45095
+ `type=bind,source=${dirs.commonDir},target=${containerCommonDir}`
45096
+ ];
45097
+ }
45098
+
44929
45099
  // ../host/src/modules/taskflow/adapters/devcontainer-environment.ts
44930
45100
  var cliOutputSchema = external_exports.object({
44931
45101
  containerId: external_exports.string(),
@@ -44947,47 +45117,26 @@ function hash2(value) {
44947
45117
  function quoteShell(value) {
44948
45118
  return `'${value.replaceAll("'", "'\\''")}'`;
44949
45119
  }
44950
- function relativeWorktreeGitDir(workspacePath) {
45120
+ async function exists2(path) {
44951
45121
  try {
44952
- const value = readFileSync3(join4(workspacePath, ".git"), "utf8").trim();
44953
- const gitDir = value.startsWith("gitdir: ") ? value.slice("gitdir: ".length).trim() : "";
44954
- return gitDir.length > 0 && !isAbsolute2(gitDir) ? gitDir : null;
44955
- } catch {
44956
- return null;
44957
- }
44958
- }
44959
- function commonGitDir(path, separator) {
44960
- const marker = `${separator}worktrees${separator}`;
44961
- const index = path.lastIndexOf(marker);
44962
- return index > 0 ? path.slice(0, index) : null;
44963
- }
44964
- function worktreeGitMount(workspacePath, containerWorkspacePath) {
44965
- const gitDir = relativeWorktreeGitDir(workspacePath);
44966
- if (!gitDir || !containerWorkspacePath) return null;
44967
- const source = commonGitDir(resolve2(workspacePath, gitDir), sep);
44968
- const target = commonGitDir(posix.resolve(containerWorkspacePath, gitDir.replaceAll(sep, "/")), "/");
44969
- return source && target ? `type=bind,source=${source},target=${target}` : null;
44970
- }
44971
- async function exists(path) {
44972
- try {
44973
- await access(path);
45122
+ await access2(path);
44974
45123
  return true;
44975
45124
  } catch {
44976
45125
  return false;
44977
45126
  }
44978
45127
  }
44979
45128
  async function findDevcontainerConfigs(workspacePath) {
44980
- const rootConfig = join4(workspacePath, ".devcontainer.json");
44981
- const directory = join4(workspacePath, ".devcontainer");
45129
+ const rootConfig = join5(workspacePath, ".devcontainer.json");
45130
+ const directory = join5(workspacePath, ".devcontainer");
44982
45131
  const configs = [];
44983
- if (await exists(rootConfig)) configs.push(rootConfig);
44984
- if (await exists(join4(directory, "devcontainer.json"))) configs.push(join4(directory, "devcontainer.json"));
44985
- if (await exists(directory)) {
45132
+ if (await exists2(rootConfig)) configs.push(rootConfig);
45133
+ if (await exists2(join5(directory, "devcontainer.json"))) configs.push(join5(directory, "devcontainer.json"));
45134
+ if (await exists2(directory)) {
44986
45135
  const entries = await readdir(directory, { withFileTypes: true });
44987
45136
  for (const entry of entries) {
44988
45137
  if (!entry.isDirectory()) continue;
44989
- const candidate = join4(directory, entry.name, "devcontainer.json");
44990
- if (await exists(candidate)) configs.push(candidate);
45138
+ const candidate = join5(directory, entry.name, "devcontainer.json");
45139
+ if (await exists2(candidate)) configs.push(candidate);
44991
45140
  }
44992
45141
  }
44993
45142
  return [...new Set(configs)].sort();
@@ -45082,7 +45231,7 @@ async function resolveComposeConfiguration(runner, config2, merged) {
45082
45231
  if (files.length === 0) return { hashMaterial: "", risks: [] };
45083
45232
  const args = [
45084
45233
  "compose",
45085
- ...files.flatMap((file2) => ["-f", resolve2(dirname4(config2), file2)]),
45234
+ ...files.flatMap((file2) => ["-f", resolve3(dirname4(config2), file2)]),
45086
45235
  "config",
45087
45236
  "--format",
45088
45237
  "json"
@@ -45106,6 +45255,7 @@ var DevContainerProvider = class {
45106
45255
  cli;
45107
45256
  cliPrefix;
45108
45257
  workspaceFolders = /* @__PURE__ */ new Map();
45258
+ workspaceMounts = /* @__PURE__ */ new Map();
45109
45259
  runner;
45110
45260
  constructor(runner = new NodeProcessRunner(), cli) {
45111
45261
  this.runner = runner;
@@ -45116,7 +45266,7 @@ var DevContainerProvider = class {
45116
45266
  }
45117
45267
  const packagePath = createRequire(import.meta.url).resolve("@devcontainers/cli/package.json");
45118
45268
  this.cli = process.execPath;
45119
- this.cliPrefix = [join4(dirname4(packagePath), "devcontainer.js")];
45269
+ this.cliPrefix = [join5(dirname4(packagePath), "devcontainer.js")];
45120
45270
  }
45121
45271
  args(args) {
45122
45272
  return [...this.cliPrefix, ...args];
@@ -45138,7 +45288,7 @@ var DevContainerProvider = class {
45138
45288
  return {
45139
45289
  provider: this.id,
45140
45290
  available: version2.supported,
45141
- configRefs: configs.map((config2) => relative(context.workspacePath, config2)),
45291
+ configRefs: configs.map((config2) => relative2(context.workspacePath, config2)),
45142
45292
  ...version2.version ? { version: version2.version } : {},
45143
45293
  diagnostics: version2.diagnostic ? [version2.diagnostic] : []
45144
45294
  };
@@ -45146,7 +45296,7 @@ var DevContainerProvider = class {
45146
45296
  async configFor(context) {
45147
45297
  const configs = await findDevcontainerConfigs(context.workspacePath);
45148
45298
  if (context.configRef) {
45149
- const selected2 = resolve2(context.workspacePath, context.configRef);
45299
+ const selected2 = resolve3(context.workspacePath, context.configRef);
45150
45300
  if (!configs.includes(selected2)) throw new Error(`Dev Container config was not found: ${context.configRef}`);
45151
45301
  return selected2;
45152
45302
  }
@@ -45176,16 +45326,19 @@ var DevContainerProvider = class {
45176
45326
  });
45177
45327
  if (result.exit.code !== 0) throw new Error(`devcontainer read-configuration failed: ${result.stderr.trim()}`);
45178
45328
  const raw2 = readOutputSchema.parse(JSON.parse(result.stdout));
45179
- const rawConfig = await readFile(config2, "utf8");
45329
+ const rawConfig = await readFile2(config2, "utf8");
45180
45330
  const merged = record2(raw2.mergedConfiguration ?? raw2.configuration);
45181
45331
  if (typeof merged.workspaceFolder === "string") this.workspaceFolders.set(config2, merged.workspaceFolder);
45332
+ if (typeof merged.workspaceMount === "string" && merged.workspaceMount.trim().length > 0)
45333
+ this.workspaceMounts.set(config2, merged.workspaceMount);
45334
+ else this.workspaceMounts.delete(config2);
45182
45335
  const compose2 = await resolveComposeConfiguration(this.runner, config2, merged);
45183
- const lockfile = join4(dirname4(config2), "devcontainer-lock.json");
45184
- const lockfileExists = await exists(lockfile);
45185
- const lockfileContents = lockfileExists ? await readFile(lockfile, "utf8") : "";
45336
+ const lockfile = join5(dirname4(config2), "devcontainer-lock.json");
45337
+ const lockfileExists = await exists2(lockfile);
45338
+ const lockfileContents = lockfileExists ? await readFile2(lockfile, "utf8") : "";
45186
45339
  return {
45187
45340
  provider: this.id,
45188
- configRef: relative(context.workspacePath, config2),
45341
+ configRef: relative2(context.workspacePath, config2),
45189
45342
  configHash: hash2(`${rawConfig}\0${result.stdout}\0${compose2.hashMaterial}\0${lockfileContents}`),
45190
45343
  workspace: { hostPath: context.workspacePath },
45191
45344
  capabilities: {
@@ -45203,10 +45356,16 @@ var DevContainerProvider = class {
45203
45356
  }
45204
45357
  async up(environment, scope, removeExisting) {
45205
45358
  if (!environment.configRef) throw new Error("Dev Container environment requires configRef");
45206
- const config2 = resolve2(environment.workspace.hostPath, environment.configRef);
45359
+ const config2 = resolve3(environment.workspace.hostPath, environment.configRef);
45207
45360
  const id = environmentIdFor(scope, "devcontainer", environment.configRef);
45208
45361
  const composeName = `tf_${id.slice(4)}`;
45209
- const gitMount = worktreeGitMount(environment.workspace.hostPath, this.workspaceFolders.get(config2));
45362
+ const gitArgs = await worktreeGitMountArgs({
45363
+ runner: this.runner,
45364
+ workspacePath: environment.workspace.hostPath,
45365
+ containerWorkspacePath: this.workspaceFolders.get(config2),
45366
+ workspaceMount: this.workspaceMounts.get(config2),
45367
+ configRef: environment.configRef
45368
+ });
45210
45369
  const result = await runCaptured(this.runner, {
45211
45370
  command: this.cli,
45212
45371
  args: this.args([
@@ -45219,8 +45378,7 @@ var DevContainerProvider = class {
45219
45378
  `taskflow.environment.id=${id}`,
45220
45379
  "--include-configuration",
45221
45380
  "--include-merged-configuration",
45222
- ...relativeWorktreeGitDir(environment.workspace.hostPath) ? ["--mount-git-worktree-common-dir"] : [],
45223
- ...gitMount ? ["--mount", gitMount] : [],
45381
+ ...gitArgs,
45224
45382
  ...removeExisting ? ["--remove-existing-container"] : []
45225
45383
  ]),
45226
45384
  cwd: dirname4(config2),
@@ -45414,14 +45572,14 @@ exec ${argv.join(" ")} "$cwd" ${quoteShell(executable)} "$@"
45414
45572
  const configuredFiles = configuration.dockerComposeFile;
45415
45573
  const files = Array.isArray(configuredFiles) ? configuredFiles.filter((value) => typeof value === "string") : typeof configuredFiles === "string" ? [configuredFiles] : [];
45416
45574
  if (project && typeof configRef === "string" && files.length > 0) {
45417
- const configDirectory = dirname4(resolve2(handle.workspace.hostPath, configRef));
45575
+ const configDirectory = dirname4(resolve3(handle.workspace.hostPath, configRef));
45418
45576
  return {
45419
45577
  command: "docker",
45420
45578
  args: [
45421
45579
  "compose",
45422
45580
  "--project-name",
45423
45581
  project,
45424
- ...files.flatMap((file2) => ["-f", resolve2(configDirectory, file2)]),
45582
+ ...files.flatMap((file2) => ["-f", resolve3(configDirectory, file2)]),
45425
45583
  "logs",
45426
45584
  "--follow",
45427
45585
  "--tail",
@@ -45440,10 +45598,10 @@ exec ${argv.join(" ")} "$cwd" ${quoteShell(executable)} "$@"
45440
45598
 
45441
45599
  // ../host/src/modules/taskflow/adapters/dockerfile-environment.ts
45442
45600
  import { createHash as createHash4 } from "node:crypto";
45443
- import { existsSync, readFileSync as readFileSync4 } from "node:fs";
45444
- import { resolve as resolve3 } from "node:path";
45601
+ import { existsSync, readFileSync as readFileSync3 } from "node:fs";
45602
+ import { resolve as resolve4 } from "node:path";
45445
45603
  function dockerfileFor(context) {
45446
- const dockerfile = resolve3(context.workspacePath, context.configRef ?? "Dockerfile");
45604
+ const dockerfile = resolve4(context.workspacePath, context.configRef ?? "Dockerfile");
45447
45605
  if (!existsSync(dockerfile)) throw new Error(`Dockerfile does not exist: ${context.configRef ?? "Dockerfile"}`);
45448
45606
  return dockerfile;
45449
45607
  }
@@ -45470,7 +45628,7 @@ var DockerfileEnvironmentProvider = class {
45470
45628
  command: "docker",
45471
45629
  args: ["version", "--format", "{{.Client.Version}}"]
45472
45630
  });
45473
- const dockerfile = resolve3(context.workspacePath, "Dockerfile");
45631
+ const dockerfile = resolve4(context.workspacePath, "Dockerfile");
45474
45632
  return {
45475
45633
  provider: this.id,
45476
45634
  available: version2.exit.code === 0 && existsSync(dockerfile),
@@ -45481,7 +45639,7 @@ var DockerfileEnvironmentProvider = class {
45481
45639
  }
45482
45640
  async resolve(context) {
45483
45641
  const dockerfile = dockerfileFor(context);
45484
- const source = readFileSync4(dockerfile, "utf8");
45642
+ const source = readFileSync3(dockerfile, "utf8");
45485
45643
  return {
45486
45644
  provider: this.id,
45487
45645
  configRef: dockerfile,
@@ -45765,8 +45923,8 @@ function sanitizeProjectPrefix(raw2) {
45765
45923
  return raw2.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").replace(/-{2,}/g, "-");
45766
45924
  }
45767
45925
  function deriveProjectPrefix(projectDir, takenPrefixes) {
45768
- const basename11 = projectDir.replace(/\/+$/, "").split("/").pop() ?? APP_SLUG;
45769
- const base = sanitizeProjectPrefix(basename11) || APP_SLUG;
45926
+ const basename12 = projectDir.replace(/\/+$/, "").split("/").pop() ?? APP_SLUG;
45927
+ const base = sanitizeProjectPrefix(basename12) || APP_SLUG;
45770
45928
  const taken = /* @__PURE__ */ new Set([...takenPrefixes, ...RESERVED_PROJECT_PREFIXES]);
45771
45929
  if (!taken.has(base)) return base;
45772
45930
  for (let n = 2; n < 1e3; n++) {
@@ -46312,6 +46470,9 @@ var AvailableBranchSchema = external_exports.object({
46312
46470
  var AvailableBranchesQuerySchema = external_exports.object({
46313
46471
  includeRemote: BooleanLikeSchema.optional()
46314
46472
  });
46473
+ var RemoveWorktreeQuerySchema = external_exports.object({
46474
+ force: BooleanLikeSchema.optional()
46475
+ });
46315
46476
  var NumberLikePathParamSchema = external_exports.union([
46316
46477
  external_exports.number().int().nonnegative(),
46317
46478
  external_exports.string().regex(/^\d+$/).transform((value) => Number(value))
@@ -47245,6 +47406,7 @@ var apiContract = defineRoutes({
47245
47406
  summary: "Remove a worktree",
47246
47407
  path: apiPaths.removeWorktree,
47247
47408
  pathParams: WorktreeNameParamsSchema,
47409
+ query: RemoveWorktreeQuerySchema,
47248
47410
  responses: {
47249
47411
  200: OkResponseSchema,
47250
47412
  ...commonErrorResponses
@@ -47841,7 +48003,7 @@ exec ${JSON.stringify(executable)} "$@"
47841
48003
  };
47842
48004
 
47843
48005
  // ../host/src/modules/taskflow/adapters/projects-registry.ts
47844
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
48006
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
47845
48007
  import { dirname as dirname6 } from "node:path";
47846
48008
  function defaultRegistryFile() {
47847
48009
  return globalPaths().projectsRegistry;
@@ -47850,7 +48012,7 @@ function createProjectsRegistry(file2 = defaultRegistryFile()) {
47850
48012
  function read() {
47851
48013
  let raw2;
47852
48014
  try {
47853
- raw2 = readFileSync5(file2, "utf8");
48015
+ raw2 = readFileSync4(file2, "utf8");
47854
48016
  } catch {
47855
48017
  return [];
47856
48018
  }
@@ -48271,15 +48433,15 @@ import { spawnSync as spawnSync3 } from "node:child_process";
48271
48433
 
48272
48434
  // ../host/src/modules/taskflow/adapters/session-gateway.ts
48273
48435
  import { createHash as createHash5 } from "node:crypto";
48274
- import { basename as basename2, resolve as resolve4 } from "node:path";
48436
+ import { basename as basename3, resolve as resolve5 } from "node:path";
48275
48437
  function sanitizeNameSegment(value, maxLength = 24) {
48276
48438
  const sanitized = value.toLowerCase().replace(/[^a-z0-9_.-]+/g, "-").replace(/-{2,}/g, "-").replace(/^[.-]+|[.-]+$/g, "");
48277
48439
  const trimmed = sanitized.slice(0, maxLength);
48278
48440
  return trimmed || "x";
48279
48441
  }
48280
48442
  function buildProjectSessionName(projectRoot2) {
48281
- const resolved2 = resolve4(projectRoot2);
48282
- const base = sanitizeNameSegment(basename2(resolved2), 18);
48443
+ const resolved2 = resolve5(projectRoot2);
48444
+ const base = sanitizeNameSegment(basename3(resolved2), 18);
48283
48445
  const hash4 = createHash5("sha1").update(resolved2).digest("hex").slice(0, 8);
48284
48446
  return `${RUNTIME_IDENTITY.tmuxPrefix}-${base}-${hash4}`;
48285
48447
  }
@@ -48546,19 +48708,19 @@ var TmuxGateway = class {
48546
48708
 
48547
48709
  // ../host/src/modules/taskflow/assets.ts
48548
48710
  import { existsSync as existsSync2 } from "node:fs";
48549
- import { join as join5, resolve as resolve5 } from "node:path";
48711
+ import { join as join6, resolve as resolve6 } from "node:path";
48550
48712
  function taskflowAssets(env2 = process.env, directory = import.meta.dirname) {
48551
- const bundled = join5(directory, "assets");
48552
- if (existsSync2(join5(bundled, "workflows"))) {
48713
+ const bundled = join6(directory, "assets");
48714
+ if (existsSync2(join6(bundled, "workflows"))) {
48553
48715
  return {
48554
- workflowBuiltinsDir: env2[ENV_NAMES.workflowBuiltinsDir] || join5(bundled, "workflows"),
48555
- workflowSkill: join5(bundled, "skills", "portta-workflows", "SKILL.md")
48716
+ workflowBuiltinsDir: env2[ENV_NAMES.workflowBuiltinsDir] || join6(bundled, "workflows"),
48717
+ workflowSkill: join6(bundled, "skills", "portta-workflows", "SKILL.md")
48556
48718
  };
48557
48719
  }
48558
- const repository = resolve5(directory, "../../../../..");
48720
+ const repository = resolve6(directory, "../../../../..");
48559
48721
  return {
48560
- workflowBuiltinsDir: env2[ENV_NAMES.workflowBuiltinsDir] || join5(repository, "packages", "host", "workflows"),
48561
- workflowSkill: join5(repository, "skills", "portta-workflows", "SKILL.md")
48722
+ workflowBuiltinsDir: env2[ENV_NAMES.workflowBuiltinsDir] || join6(repository, "packages", "host", "workflows"),
48723
+ workflowSkill: join6(repository, "skills", "portta-workflows", "SKILL.md")
48562
48724
  };
48563
48725
  }
48564
48726
 
@@ -48766,19 +48928,19 @@ import { homedir as homedir2 } from "node:os";
48766
48928
  // ../host/src/modules/taskflow/adapters/git.ts
48767
48929
  import { spawnSync as spawnSync4 } from "node:child_process";
48768
48930
  import { readdirSync, realpathSync, rmSync, statSync as statSync3 } from "node:fs";
48769
- import { basename as basename3, dirname as dirname7, join as join6, resolve as resolve6 } from "node:path";
48931
+ import { basename as basename4, dirname as dirname7, join as join7, resolve as resolve7 } from "node:path";
48770
48932
  function canonicalizeFsPath(input2) {
48771
- const resolved2 = resolve6(input2);
48933
+ const resolved2 = resolve7(input2);
48772
48934
  try {
48773
48935
  return realpathSync(resolved2);
48774
48936
  } catch {
48775
48937
  const missing = [];
48776
48938
  let current = resolved2;
48777
48939
  while (current !== dirname7(current)) {
48778
- missing.unshift(basename3(current));
48940
+ missing.unshift(basename4(current));
48779
48941
  current = dirname7(current);
48780
48942
  try {
48781
- return join6(realpathSync(current), ...missing);
48943
+ return join7(realpathSync(current), ...missing);
48782
48944
  } catch {
48783
48945
  }
48784
48946
  }
@@ -48862,7 +49024,7 @@ function currentCheckoutRef(cwd) {
48862
49024
  }
48863
49025
  function resolveRepoRoot(dir) {
48864
49026
  const direct = tryRunGit(["rev-parse", "--show-toplevel"], dir);
48865
- if (direct.ok) return resolve6(dir, direct.stdout);
49027
+ if (direct.ok) return resolve7(dir, direct.stdout);
48866
49028
  let entries;
48867
49029
  try {
48868
49030
  entries = readdirSync(dir);
@@ -48870,24 +49032,24 @@ function resolveRepoRoot(dir) {
48870
49032
  return null;
48871
49033
  }
48872
49034
  for (const entry of entries) {
48873
- const child = join6(dir, entry);
49035
+ const child = join7(dir, entry);
48874
49036
  try {
48875
49037
  if (!statSync3(child).isDirectory()) continue;
48876
49038
  } catch {
48877
49039
  continue;
48878
49040
  }
48879
49041
  const childResult = tryRunGit(["rev-parse", "--show-toplevel"], child);
48880
- if (childResult.ok) return resolve6(child, childResult.stdout);
49042
+ if (childResult.ok) return resolve7(child, childResult.stdout);
48881
49043
  }
48882
49044
  return null;
48883
49045
  }
48884
49046
  function resolveWorktreeRoot(cwd) {
48885
49047
  const output2 = runGit(["rev-parse", "--show-toplevel"], cwd);
48886
- return resolve6(cwd, output2);
49048
+ return resolve7(cwd, output2);
48887
49049
  }
48888
49050
  function resolveWorktreeGitDir(cwd) {
48889
49051
  const output2 = runGit(["rev-parse", "--git-dir"], cwd);
48890
- return resolve6(cwd, output2);
49052
+ return resolve7(cwd, output2);
48891
49053
  }
48892
49054
  function parseGitWorktreePorcelain(output2) {
48893
49055
  const entries = [];
@@ -49084,6 +49246,21 @@ var NodeGitGateway = class {
49084
49246
  const result = tryRunGit(["diff", "HEAD", "--no-color"], cwd);
49085
49247
  return result.ok ? result.stdout : "";
49086
49248
  }
49249
+ /**
49250
+ * Commits reachable from HEAD and from nothing else that would survive this
49251
+ * worktree: not on an origin branch, not on the project's main branch. It
49252
+ * answers "would deleting this branch lose work", which `aheadCount` cannot:
49253
+ * with no upstream and no remote at all, every commit counts as ahead.
49254
+ */
49255
+ countUnsavedCommits(cwd, baseBranch) {
49256
+ const count = (args) => {
49257
+ const result = tryRunGit(args, cwd);
49258
+ return result.ok ? parseInt(result.stdout, 10) || 0 : null;
49259
+ };
49260
+ const excludingBase = baseBranch ? count(["rev-list", "--count", "HEAD", "--not", "--remotes=origin", baseBranch]) : null;
49261
+ if (excludingBase !== null) return excludingBase;
49262
+ return count(["rev-list", "--count", "HEAD", "--not", "--remotes=origin"]) ?? 0;
49263
+ }
49087
49264
  listUnpushedCommits(cwd) {
49088
49265
  let result = tryRunGit(["log", "--oneline", "@{upstream}..HEAD"], cwd);
49089
49266
  if (!result.ok) {
@@ -49434,7 +49611,7 @@ function resolveSocketPath(env2) {
49434
49611
  return session ? `${home2}/.config/herdr/sessions/${session}/herdr.sock` : `${home2}/.config/herdr/herdr.sock`;
49435
49612
  }
49436
49613
  async function request(socketPath, method, params) {
49437
- return await new Promise((resolve21, reject2) => {
49614
+ return await new Promise((resolve22, reject2) => {
49438
49615
  let buffer = "";
49439
49616
  let settled = false;
49440
49617
  const settle = (fn) => {
@@ -49458,7 +49635,7 @@ async function request(socketPath, method, params) {
49458
49635
  const line = buffer.slice(0, newline);
49459
49636
  clearTimeout(timer);
49460
49637
  try {
49461
- settle(() => resolve21(parseHerdrResponse(JSON.parse(line))));
49638
+ settle(() => resolve22(parseHerdrResponse(JSON.parse(line))));
49462
49639
  } catch {
49463
49640
  settle(() => reject2(new HerdrRequestError(method, "invalid_response", line.slice(0, 200))));
49464
49641
  }
@@ -49758,8 +49935,8 @@ var HerdrGateway = class {
49758
49935
  };
49759
49936
 
49760
49937
  // ../host/src/modules/taskflow/adapters/hooks.ts
49761
- import { access as access2 } from "node:fs/promises";
49762
- import { join as join7 } from "node:path";
49938
+ import { access as access3 } from "node:fs/promises";
49939
+ import { join as join8 } from "node:path";
49763
49940
  function buildErrorMessage(name, exitCode, stdout, stderr) {
49764
49941
  const output2 = stderr.trim() || stdout.trim();
49765
49942
  if (output2) {
@@ -49804,7 +49981,7 @@ var NodeLifecycleHookRunner = class {
49804
49981
  }
49805
49982
  async hasEnvrc(cwd) {
49806
49983
  try {
49807
- await access2(join7(cwd, ".envrc"));
49984
+ await access3(join8(cwd, ".envrc"));
49808
49985
  return true;
49809
49986
  } catch {
49810
49987
  return false;
@@ -49839,7 +50016,7 @@ var NodePortProbe = class {
49839
50016
  this.hostnames = hostnames;
49840
50017
  }
49841
50018
  isListening(port) {
49842
- return new Promise((resolve21) => {
50019
+ return new Promise((resolve22) => {
49843
50020
  let settled = false;
49844
50021
  let pending = this.hostnames.length;
49845
50022
  const settle = (result) => {
@@ -49847,20 +50024,20 @@ var NodePortProbe = class {
49847
50024
  if (result) {
49848
50025
  settled = true;
49849
50026
  clearTimeout(timer);
49850
- resolve21(true);
50027
+ resolve22(true);
49851
50028
  return;
49852
50029
  }
49853
50030
  pending--;
49854
50031
  if (pending === 0) {
49855
50032
  settled = true;
49856
50033
  clearTimeout(timer);
49857
- resolve21(false);
50034
+ resolve22(false);
49858
50035
  }
49859
50036
  };
49860
50037
  const timer = setTimeout(() => {
49861
50038
  if (!settled) {
49862
50039
  settled = true;
49863
- resolve21(false);
50040
+ resolve22(false);
49864
50041
  }
49865
50042
  }, this.timeoutMs);
49866
50043
  for (const hostname3 of this.hostnames) {
@@ -49882,7 +50059,7 @@ var NodePortProbe = class {
49882
50059
 
49883
50060
  // ../host/src/modules/taskflow/adapters/session-discovery.ts
49884
50061
  import { open as open2, readdir as readdir3, stat as stat3 } from "node:fs/promises";
49885
- import { basename as basename5, join as join9 } from "node:path";
50062
+ import { basename as basename6, join as join10 } from "node:path";
49886
50063
  import { setTimeout as sleep3 } from "node:timers/promises";
49887
50064
 
49888
50065
  // ../host/src/modules/taskflow/lib/type-guards.ts
@@ -49894,8 +50071,8 @@ function isStringArray2(raw2) {
49894
50071
  }
49895
50072
 
49896
50073
  // ../host/src/modules/taskflow/adapters/claude-cli.ts
49897
- import { readdir as readdir2, readFile as readFile2, stat as stat2 } from "node:fs/promises";
49898
- import { basename as basename4, join as join8 } from "node:path";
50074
+ import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
50075
+ import { basename as basename5, join as join9 } from "node:path";
49899
50076
  function isRecord4(raw2) {
49900
50077
  return typeof raw2 === "object" && raw2 !== null && !Array.isArray(raw2);
49901
50078
  }
@@ -50079,19 +50256,19 @@ function readClaudeProjectsRoot() {
50079
50256
  if (!home2) {
50080
50257
  throw new Error("HOME is required to resolve Claude sessions");
50081
50258
  }
50082
- return join8(home2, ".claude", "projects");
50259
+ return join9(home2, ".claude", "projects");
50083
50260
  }
50084
50261
  async function listJsonlFiles(dir) {
50085
50262
  try {
50086
50263
  const entries = await readdir2(dir, { withFileTypes: true });
50087
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => join8(dir, entry.name));
50264
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => join9(dir, entry.name));
50088
50265
  } catch {
50089
50266
  return [];
50090
50267
  }
50091
50268
  }
50092
50269
  async function findClaudeSessionPath(sessionId, cwd) {
50093
50270
  const projectsRoot = readClaudeProjectsRoot();
50094
- const primaryPath = join8(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
50271
+ const primaryPath = join9(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
50095
50272
  try {
50096
50273
  await stat2(primaryPath);
50097
50274
  return primaryPath;
@@ -50100,7 +50277,7 @@ async function findClaudeSessionPath(sessionId, cwd) {
50100
50277
  const projectDirs = await readdir2(projectsRoot, { withFileTypes: true }).catch(() => []);
50101
50278
  for (const entry of projectDirs) {
50102
50279
  if (!entry.isDirectory()) continue;
50103
- const candidate = join8(projectsRoot, entry.name, `${sessionId}.jsonl`);
50280
+ const candidate = join9(projectsRoot, entry.name, `${sessionId}.jsonl`);
50104
50281
  try {
50105
50282
  await stat2(candidate);
50106
50283
  return candidate;
@@ -50224,7 +50401,7 @@ var ClaudeCliClient = class {
50224
50401
  }
50225
50402
  async listSessions(cwd) {
50226
50403
  const projectsRoot = readClaudeProjectsRoot();
50227
- const primaryDir = join8(projectsRoot, encodeClaudeProjectDir(cwd));
50404
+ const primaryDir = join9(projectsRoot, encodeClaudeProjectDir(cwd));
50228
50405
  const primaryFiles = await listJsonlFiles(primaryDir);
50229
50406
  if (primaryFiles.length > 0) {
50230
50407
  return await this.summarizeSessionFiles(primaryFiles, cwd);
@@ -50233,7 +50410,7 @@ var ClaudeCliClient = class {
50233
50410
  const matchedFiles = [];
50234
50411
  for (const entry of projectDirs) {
50235
50412
  if (!entry.isDirectory()) continue;
50236
- const files = await listJsonlFiles(join8(projectsRoot, entry.name));
50413
+ const files = await listJsonlFiles(join9(projectsRoot, entry.name));
50237
50414
  for (const filePath of files) {
50238
50415
  const session = await this.readSessionFile(filePath);
50239
50416
  if (session?.cwd === cwd) {
@@ -50281,8 +50458,8 @@ var ClaudeCliClient = class {
50281
50458
  let sessionIdResolve = null;
50282
50459
  let sessionIdReject = null;
50283
50460
  let interrupted = false;
50284
- const sessionId = new Promise((resolve21, reject2) => {
50285
- sessionIdResolve = resolve21;
50461
+ const sessionId = new Promise((resolve22, reject2) => {
50462
+ sessionIdResolve = resolve22;
50286
50463
  sessionIdReject = reject2;
50287
50464
  });
50288
50465
  const resolveSessionId = (value) => {
@@ -50353,7 +50530,7 @@ var ClaudeCliClient = class {
50353
50530
  const info = await stat2(filePath).catch(() => null);
50354
50531
  if (!info) return null;
50355
50532
  return {
50356
- sessionId: basename4(filePath, ".jsonl"),
50533
+ sessionId: basename5(filePath, ".jsonl"),
50357
50534
  cwd,
50358
50535
  path: filePath,
50359
50536
  lastSeenAt: info.mtime.toISOString()
@@ -50364,10 +50541,10 @@ var ClaudeCliClient = class {
50364
50541
  }
50365
50542
  async readSessionFile(filePath) {
50366
50543
  try {
50367
- const text = await readFile2(filePath, "utf8");
50544
+ const text = await readFile3(filePath, "utf8");
50368
50545
  return buildClaudeSessionFromText({
50369
50546
  path: filePath,
50370
- sessionId: basename4(filePath, ".jsonl"),
50547
+ sessionId: basename5(filePath, ".jsonl"),
50371
50548
  text
50372
50549
  });
50373
50550
  } catch {
@@ -50430,12 +50607,12 @@ function newestFirst(sessions2) {
50430
50607
  return sessions2.sort((left, right) => right.mtimeMs - left.mtimeMs).map((entry) => entry.sessionId);
50431
50608
  }
50432
50609
  async function listClaudeSessionIds(cwd) {
50433
- const dir = join9(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
50610
+ const dir = join10(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
50434
50611
  const names = await readdir3(dir).catch(() => []);
50435
50612
  const stamped = await Promise.all(
50436
50613
  names.filter((name) => name.endsWith(".jsonl")).map(async (name) => {
50437
- const info = await stat3(join9(dir, name)).catch(() => null);
50438
- return info ? { sessionId: basename5(name, ".jsonl"), mtimeMs: info.mtimeMs } : null;
50614
+ const info = await stat3(join10(dir, name)).catch(() => null);
50615
+ return info ? { sessionId: basename6(name, ".jsonl"), mtimeMs: info.mtimeMs } : null;
50439
50616
  })
50440
50617
  );
50441
50618
  return newestFirst(stamped.filter((entry) => entry !== null));
@@ -50470,15 +50647,15 @@ async function readCodexSessionCwdId(path) {
50470
50647
  }
50471
50648
  }
50472
50649
  async function listCodexSessionIds(cwd) {
50473
- const root = join9(home(), ".codex", "sessions");
50650
+ const root = join10(home(), ".codex", "sessions");
50474
50651
  const relPaths = await readdir3(root, { recursive: true }).catch(() => []);
50475
50652
  const rollouts = relPaths.filter((rel) => {
50476
- const name = basename5(rel);
50653
+ const name = basename6(rel);
50477
50654
  return name.startsWith("rollout-") && name.endsWith(".jsonl");
50478
50655
  });
50479
50656
  const stamped = await Promise.all(
50480
50657
  rollouts.map(async (rel) => {
50481
- const path = join9(root, rel);
50658
+ const path = join10(root, rel);
50482
50659
  const meta3 = await readCodexSessionCwdId(path);
50483
50660
  if (!meta3 || meta3.cwd !== cwd) return null;
50484
50661
  const info = await stat3(path).catch(() => null);
@@ -50488,11 +50665,11 @@ async function listCodexSessionIds(cwd) {
50488
50665
  return newestFirst(stamped.filter((entry) => entry !== null));
50489
50666
  }
50490
50667
  async function findCodexSessionPath(sessionId, cwd) {
50491
- const root = join9(home(), ".codex", "sessions");
50668
+ const root = join10(home(), ".codex", "sessions");
50492
50669
  const relPaths = await readdir3(root, { recursive: true }).catch(() => []);
50493
50670
  for (const rel of relPaths) {
50494
- if (!basename5(rel).endsWith(`${sessionId}.jsonl`)) continue;
50495
- const path = join9(root, rel);
50671
+ if (!basename6(rel).endsWith(`${sessionId}.jsonl`)) continue;
50672
+ const path = join10(root, rel);
50496
50673
  const meta3 = await readCodexSessionCwdId(path);
50497
50674
  if (meta3?.id === sessionId && meta3.cwd === cwd) return path;
50498
50675
  }
@@ -50573,8 +50750,8 @@ async function captureNewSessionId(discovery, agent, cwd, before, options = {})
50573
50750
  }
50574
50751
 
50575
50752
  // ../host/src/modules/taskflow/adapters/fs.ts
50576
- import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
50577
- import { join as join10 } from "node:path";
50753
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
50754
+ import { join as join11 } from "node:path";
50578
50755
  var SAFE_ENV_VALUE_RE = /^[A-Za-z0-9_./:@%+=,-]+$/;
50579
50756
  var DOTENV_LINE_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=\s*(.*)/;
50580
50757
  function stringifyAllocatedPorts(ports) {
@@ -50605,7 +50782,7 @@ function parseDotenv(content) {
50605
50782
  }
50606
50783
  async function loadDotenvLocal(worktreePath) {
50607
50784
  try {
50608
- const content = await readFile3(join10(worktreePath, ".env.local"), "utf8");
50785
+ const content = await readFile4(join11(worktreePath, ".env.local"), "utf8");
50609
50786
  return parseDotenv(content);
50610
50787
  } catch {
50611
50788
  return {};
@@ -50636,7 +50813,7 @@ async function ensureWorktreeStorageDirs(gitDir) {
50636
50813
  async function readWorktreeMeta(gitDir) {
50637
50814
  const { metaPath } = getWorktreeStoragePaths(gitDir);
50638
50815
  try {
50639
- const raw2 = JSON.parse(await readFile3(metaPath, "utf8"));
50816
+ const raw2 = JSON.parse(await readFile4(metaPath, "utf8"));
50640
50817
  return normalizeWorktreeMeta(raw2);
50641
50818
  } catch {
50642
50819
  return null;
@@ -50644,7 +50821,7 @@ async function readWorktreeMeta(gitDir) {
50644
50821
  }
50645
50822
  async function writeWorktreeMeta(gitDir, meta3) {
50646
50823
  const { metaPath } = await ensureWorktreeStorageDirs(gitDir);
50647
- await writeFile2(metaPath, `${JSON.stringify(meta3, null, 2)}
50824
+ await writeFile3(metaPath, `${JSON.stringify(meta3, null, 2)}
50648
50825
  `);
50649
50826
  }
50650
50827
  function isArchivedWorktreeEntry(raw2) {
@@ -50662,7 +50839,7 @@ function isWorktreeArchiveState(raw2) {
50662
50839
  async function readWorktreeArchiveState(gitDir) {
50663
50840
  const archivePath = getProjectArchiveStatePath(gitDir);
50664
50841
  try {
50665
- const raw2 = JSON.parse(await readFile3(archivePath, "utf8"));
50842
+ const raw2 = JSON.parse(await readFile4(archivePath, "utf8"));
50666
50843
  return isWorktreeArchiveState(raw2) ? {
50667
50844
  schemaVersion: raw2.schemaVersion,
50668
50845
  entries: raw2.entries.map((entry) => ({ ...entry }))
@@ -50674,13 +50851,13 @@ async function readWorktreeArchiveState(gitDir) {
50674
50851
  async function writeWorktreeArchiveState(gitDir, state) {
50675
50852
  const archivePath = getProjectArchiveStatePath(gitDir);
50676
50853
  await ensureWorktreeStorageDirs(gitDir);
50677
- await writeFile2(archivePath, `${JSON.stringify(state, null, 2)}
50854
+ await writeFile3(archivePath, `${JSON.stringify(state, null, 2)}
50678
50855
  `);
50679
50856
  }
50680
50857
  async function writeOpenSessionsState(gitDir, state) {
50681
50858
  const statePath = getProjectOpenSessionsStatePath(gitDir);
50682
50859
  await ensureWorktreeStorageDirs(gitDir);
50683
- await writeFile2(statePath, `${JSON.stringify(state, null, 2)}
50860
+ await writeFile3(statePath, `${JSON.stringify(state, null, 2)}
50684
50861
  `);
50685
50862
  }
50686
50863
  function buildRuntimeEnvMap(meta3, extraEnv = {}, dotenvValues = {}) {
@@ -50711,11 +50888,11 @@ function renderEnvFile(env2) {
50711
50888
  }
50712
50889
  async function writeRuntimeEnv(gitDir, env2) {
50713
50890
  const { runtimeEnvPath } = await ensureWorktreeStorageDirs(gitDir);
50714
- await writeFile2(runtimeEnvPath, renderEnvFile(env2));
50891
+ await writeFile3(runtimeEnvPath, renderEnvFile(env2));
50715
50892
  }
50716
50893
  async function writeControlEnv(gitDir, env2) {
50717
50894
  const { controlEnvPath } = await ensureWorktreeStorageDirs(gitDir);
50718
- await writeFile2(controlEnvPath, renderEnvFile(env2));
50895
+ await writeFile3(controlEnvPath, renderEnvFile(env2));
50719
50896
  }
50720
50897
  function isRecord5(raw2) {
50721
50898
  return typeof raw2 === "object" && raw2 !== null && !Array.isArray(raw2);
@@ -50800,7 +50977,7 @@ function isPrEntry(raw2) {
50800
50977
  async function readWorktreePrs(gitDir) {
50801
50978
  const { prsPath } = getWorktreeStoragePaths(gitDir);
50802
50979
  try {
50803
- const raw2 = JSON.parse(await readFile3(prsPath, "utf8"));
50980
+ const raw2 = JSON.parse(await readFile4(prsPath, "utf8"));
50804
50981
  if (!Array.isArray(raw2) || !raw2.every((entry) => isPrEntry(entry))) return [];
50805
50982
  return raw2.map((entry) => ({ ...entry, isDraft: entry.isDraft ?? false }));
50806
50983
  } catch {
@@ -50809,12 +50986,12 @@ async function readWorktreePrs(gitDir) {
50809
50986
  }
50810
50987
  async function writeWorktreePrs(gitDir, prs) {
50811
50988
  const { prsPath } = await ensureWorktreeStorageDirs(gitDir);
50812
- await writeFile2(prsPath, `${JSON.stringify(prs, null, 2)}
50989
+ await writeFile3(prsPath, `${JSON.stringify(prs, null, 2)}
50813
50990
  `);
50814
50991
  }
50815
50992
 
50816
50993
  // ../host/src/modules/taskflow/services/archive-service.ts
50817
- import { resolve as resolve7 } from "node:path";
50994
+ import { resolve as resolve8 } from "node:path";
50818
50995
  function createArchiveState(entries) {
50819
50996
  return {
50820
50997
  schemaVersion: WORKTREE_ARCHIVE_STATE_VERSION,
@@ -50822,7 +50999,7 @@ function createArchiveState(entries) {
50822
50999
  };
50823
51000
  }
50824
51001
  function normalizeArchivePath(path) {
50825
- return resolve7(path);
51002
+ return resolve8(path);
50826
51003
  }
50827
51004
  function buildArchivedWorktreePathSet(state) {
50828
51005
  return new Set(state.entries.map((entry) => normalizeArchivePath(entry.path)));
@@ -50896,8 +51073,8 @@ var ArchiveStateService = class {
50896
51073
  const previous = this.mutationQueue;
50897
51074
  let release = () => {
50898
51075
  };
50899
- this.mutationQueue = new Promise((resolve21) => {
50900
- release = resolve21;
51076
+ this.mutationQueue = new Promise((resolve22) => {
51077
+ release = resolve22;
50901
51078
  });
50902
51079
  await previous.catch(() => {
50903
51080
  });
@@ -51075,8 +51252,8 @@ var AutoNameService = class {
51075
51252
 
51076
51253
  // ../host/src/modules/taskflow/services/lifecycle-service.ts
51077
51254
  import { randomUUID as randomUUID3 } from "node:crypto";
51078
- import { mkdir as mkdir4, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
51079
- import { dirname as dirname10, relative as relative2, resolve as resolve10 } from "node:path";
51255
+ import { mkdir as mkdir4, readFile as readFile6, writeFile as writeFile5 } from "node:fs/promises";
51256
+ import { dirname as dirname10, relative as relative3, resolve as resolve11 } from "node:path";
51080
51257
 
51081
51258
  // ../host/src/modules/taskflow/adapters/agent-capabilities.ts
51082
51259
  var CAPABILITY_TIMEOUT_MS = 15e3;
@@ -51121,8 +51298,8 @@ ${stderr}`;
51121
51298
  };
51122
51299
 
51123
51300
  // ../host/src/modules/taskflow/adapters/agent-runtime.ts
51124
- import { chmod, mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
51125
- import { dirname as dirname8, join as join11, resolve as resolve8 } from "node:path";
51301
+ import { chmod, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
51302
+ import { dirname as dirname8, join as join12, resolve as resolve9 } from "node:path";
51126
51303
  var GENERATED_AGENT_FILES_EXCLUDES = [".claude/settings.local.json", ".codex/hooks.json"];
51127
51304
  function shellQuote(value) {
51128
51305
  return `'${value.replaceAll("'", "'\\''")}'`;
@@ -51132,7 +51309,7 @@ function isRecord6(value) {
51132
51309
  }
51133
51310
  async function readJsonRecord(path) {
51134
51311
  try {
51135
- const parsed = JSON.parse(await readFile4(path, "utf8"));
51312
+ const parsed = JSON.parse(await readFile5(path, "utf8"));
51136
51313
  return isRecord6(parsed) ? parsed : {};
51137
51314
  } catch {
51138
51315
  return {};
@@ -51548,7 +51725,7 @@ async function mergeClaudeSettings(settingsPath, hookSettings) {
51548
51725
  const existingHooks = existing.hooks;
51549
51726
  const mergedHooks = existingHooks && typeof existingHooks === "object" && !Array.isArray(existingHooks) ? { ...existingHooks, ...hookSettings } : hookSettings;
51550
51727
  const merged = { ...existing, hooks: mergedHooks };
51551
- await writeFile3(settingsPath, `${JSON.stringify(merged, null, 2)}
51728
+ await writeFile4(settingsPath, `${JSON.stringify(merged, null, 2)}
51552
51729
  `);
51553
51730
  }
51554
51731
  function commandStartsWithAgentCtl(command, agentCtlPath) {
@@ -51571,24 +51748,24 @@ async function mergeCodexHooksFile(hooksPath, hookSettings, agentCtlPath) {
51571
51748
  const preservedGroups = Array.isArray(eventGroups) ? eventGroups.filter((group) => !isTaskflowHookGroup(group, agentCtlPath)) : [];
51572
51749
  mergedHooks[eventName] = [...preservedGroups, ...groups];
51573
51750
  }
51574
- await writeFile3(hooksPath, `${JSON.stringify({ ...existing, hooks: mergedHooks }, null, 2)}
51751
+ await writeFile4(hooksPath, `${JSON.stringify({ ...existing, hooks: mergedHooks }, null, 2)}
51575
51752
  `);
51576
51753
  }
51577
51754
  async function resolveGitCommonDir(gitDir) {
51578
51755
  try {
51579
- const commonDir = (await readFile4(join11(gitDir, "commondir"), "utf8")).trim();
51756
+ const commonDir = (await readFile5(join12(gitDir, "commondir"), "utf8")).trim();
51580
51757
  if (!commonDir) return gitDir;
51581
- return commonDir.startsWith("/") ? commonDir : resolve8(gitDir, commonDir);
51758
+ return commonDir.startsWith("/") ? commonDir : resolve9(gitDir, commonDir);
51582
51759
  } catch {
51583
51760
  return gitDir;
51584
51761
  }
51585
51762
  }
51586
51763
  async function ensureGeneratedAgentFilesIgnored(gitDir) {
51587
51764
  const commonDir = await resolveGitCommonDir(gitDir);
51588
- const excludePath = join11(commonDir, "info", "exclude");
51765
+ const excludePath = join12(commonDir, "info", "exclude");
51589
51766
  let existing = "";
51590
51767
  try {
51591
- existing = await readFile4(excludePath, "utf8");
51768
+ existing = await readFile5(excludePath, "utf8");
51592
51769
  } catch {
51593
51770
  existing = "";
51594
51771
  }
@@ -51597,19 +51774,19 @@ async function ensureGeneratedAgentFilesIgnored(gitDir) {
51597
51774
  if (missing.length === 0) return;
51598
51775
  await mkdir3(dirname8(excludePath), { recursive: true });
51599
51776
  const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
51600
- await writeFile3(excludePath, `${existing}${separator}${missing.join("\n")}
51777
+ await writeFile4(excludePath, `${existing}${separator}${missing.join("\n")}
51601
51778
  `);
51602
51779
  }
51603
51780
  async function ensureAgentRuntimeArtifacts(input2) {
51604
51781
  const storagePaths = getWorktreeStoragePaths(input2.gitDir);
51605
51782
  const artifacts = {
51606
- agentCtlPath: join11(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
51607
- claudeSettingsPath: join11(input2.worktreePath, ".claude", "settings.local.json"),
51608
- codexHooksPath: join11(input2.worktreePath, ".codex", "hooks.json")
51783
+ agentCtlPath: join12(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
51784
+ claudeSettingsPath: join12(input2.worktreePath, ".claude", "settings.local.json"),
51785
+ codexHooksPath: join12(input2.worktreePath, ".codex", "hooks.json")
51609
51786
  };
51610
51787
  await mkdir3(dirname8(artifacts.claudeSettingsPath), { recursive: true });
51611
51788
  await mkdir3(dirname8(artifacts.codexHooksPath), { recursive: true });
51612
- await writeFile3(artifacts.agentCtlPath, buildAgentCtlScript());
51789
+ await writeFile4(artifacts.agentCtlPath, buildAgentCtlScript());
51613
51790
  await chmod(artifacts.agentCtlPath, 493);
51614
51791
  const hookSettings = buildClaudeHookSettings(artifacts);
51615
51792
  const hooks = hookSettings.hooks;
@@ -51734,7 +51911,7 @@ function listAgentDetails(config2) {
51734
51911
  }
51735
51912
 
51736
51913
  // ../host/src/modules/taskflow/services/agent-service.ts
51737
- import { dirname as dirname9, join as join12 } from "node:path";
51914
+ import { dirname as dirname9, join as join13 } from "node:path";
51738
51915
  var DOCKER_PATH_FALLBACK = "/root/.local/bin:/usr/local/bin:/root/.bun/bin:/root/.cargo/bin";
51739
51916
  var CUSTOM_AGENT_TEMPLATE_VARS = {
51740
51917
  PROMPT: ENV_NAMES.agentPrompt,
@@ -51755,7 +51932,7 @@ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
51755
51932
  }
51756
51933
  function buildCodexNotifyFlag(runtimeEnvPath) {
51757
51934
  if (!runtimeEnvPath) return "";
51758
- const agentCtlPath = join12(dirname9(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
51935
+ const agentCtlPath = join13(dirname9(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
51759
51936
  return ` -c ${quoteShell3(`notify=${JSON.stringify([agentCtlPath, "codex-notify"])}`)}`;
51760
51937
  }
51761
51938
  function buildBuiltInAgentInvocation(input2) {
@@ -51881,7 +52058,7 @@ function buildDockerAgentPaneCommand(input2) {
51881
52058
  }
51882
52059
 
51883
52060
  // ../host/src/modules/taskflow/services/session-service.ts
51884
- import { resolve as resolve9 } from "node:path";
52061
+ import { resolve as resolve10 } from "node:path";
51885
52062
  function quoteShell4(value) {
51886
52063
  return `'${value.replaceAll("'", "'\\''")}'`;
51887
52064
  }
@@ -51895,7 +52072,7 @@ function buildCommandPaneStartupCommand(template, ctx) {
51895
52072
  if (!template.workingDir) {
51896
52073
  return template.command;
51897
52074
  }
51898
- const workingDir = resolve9(resolvePaneCwd(template, ctx), template.workingDir);
52075
+ const workingDir = resolve10(resolvePaneCwd(template, ctx), template.workingDir);
51899
52076
  return `cd -- ${quoteShell4(workingDir)} && ${template.command}`;
51900
52077
  }
51901
52078
  function resolvePaneStartupCommand(template, ctx) {
@@ -52196,7 +52373,7 @@ function trimTrailingSlashes(value) {
52196
52373
  return value.replace(/\/+$/, "");
52197
52374
  }
52198
52375
  function isPathWithin(parent, child) {
52199
- const path = relative2(parent, child);
52376
+ const path = relative3(parent, child);
52200
52377
  return path !== "" && !path.startsWith("..") && !path.includes(`..${process.platform === "win32" ? "\\" : "/"}`);
52201
52378
  }
52202
52379
  function normalizeWorktreeLabel(label) {
@@ -52664,9 +52841,23 @@ var LifecycleService = class {
52664
52841
  throw this.wrapOperationError(error61);
52665
52842
  }
52666
52843
  }
52667
- async removeWorktree(branch) {
52844
+ /**
52845
+ * Removing a worktree deletes its branch with `--force`, so anything living
52846
+ * only there is gone. Uncommitted changes and unpushed commits therefore
52847
+ * refuse the removal unless the caller says to discard them.
52848
+ */
52849
+ async removeWorktree(branch, options = {}) {
52668
52850
  try {
52669
52851
  const resolved2 = await this.resolveExistingWorktree(branch);
52852
+ if (!options.force) {
52853
+ const unsaved = this.describeUnsavedWork(resolved2.entry);
52854
+ if (unsaved) {
52855
+ throw new LifecycleError(
52856
+ `Worktree has ${unsaved}: ${branch}. Commit or push them, or remove with --force to discard them.`,
52857
+ 409
52858
+ );
52859
+ }
52860
+ }
52670
52861
  await this.removeResolvedWorktree(resolved2);
52671
52862
  } catch (error61) {
52672
52863
  throw this.wrapOperationError(error61);
@@ -52677,15 +52868,21 @@ var LifecycleService = class {
52677
52868
  const resolvedWorktrees = await this.resolveAllWorktrees();
52678
52869
  const sessionName = buildProjectSessionName(this.deps.projectRoot);
52679
52870
  const removedBranches = [];
52871
+ const keptBranches = [];
52680
52872
  for (const resolved2 of resolvedWorktrees) {
52681
52873
  const branch = resolved2.entry.branch ?? resolved2.entry.path;
52682
52874
  if (await this.deps.sessions.hasWindow(sessionName, buildWorktreeWindowName(branch))) {
52683
52875
  continue;
52684
52876
  }
52877
+ const unsaved = this.describeUnsavedWork(resolved2.entry);
52878
+ if (unsaved) {
52879
+ keptBranches.push({ branch, reason: unsaved });
52880
+ continue;
52881
+ }
52685
52882
  await this.removeResolvedWorktree(resolved2);
52686
52883
  removedBranches.push(branch);
52687
52884
  }
52688
- return { removedBranches };
52885
+ return { removedBranches, keptBranches };
52689
52886
  } catch (error61) {
52690
52887
  throw this.wrapOperationError(error61);
52691
52888
  }
@@ -52871,7 +53068,7 @@ var LifecycleService = class {
52871
53068
  return allocateServicePorts(metas, this.deps.config.services);
52872
53069
  }
52873
53070
  resolveWorktreePath(branch) {
52874
- return resolve10(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
53071
+ return resolve11(this.deps.projectRoot, this.deps.config.workspace.worktreeRoot, branch);
52875
53072
  }
52876
53073
  /**
52877
53074
  * A worktree root below the repository is intentionally kept out of the
@@ -52880,36 +53077,36 @@ var LifecycleService = class {
52880
53077
  * tracked project files or leaking the choice to other contributors.
52881
53078
  */
52882
53079
  async excludeInternalWorktreeRoot(worktreePath) {
52883
- const projectRoot2 = resolve10(this.deps.projectRoot);
52884
- const worktreeRoot = resolve10(projectRoot2, this.deps.config.workspace.worktreeRoot);
53080
+ const projectRoot2 = resolve11(this.deps.projectRoot);
53081
+ const worktreeRoot = resolve11(projectRoot2, this.deps.config.workspace.worktreeRoot);
52885
53082
  if (!isPathWithin(projectRoot2, worktreeRoot) || !isPathWithin(worktreeRoot, worktreePath)) return;
52886
- const relativeRoot = relative2(projectRoot2, worktreeRoot).split("\\").join("/");
53083
+ const relativeRoot = relative3(projectRoot2, worktreeRoot).split("\\").join("/");
52887
53084
  const rule = `/${relativeRoot}/`;
52888
53085
  const gitDir = this.deps.git.resolveWorktreeGitDir(projectRoot2);
52889
- const excludePath = resolve10(gitDir, "info", "exclude");
53086
+ const excludePath = resolve11(gitDir, "info", "exclude");
52890
53087
  await mkdir4(dirname10(excludePath), { recursive: true });
52891
53088
  let existing = "";
52892
53089
  try {
52893
- existing = await readFile5(excludePath, "utf8");
53090
+ existing = await readFile6(excludePath, "utf8");
52894
53091
  } catch {
52895
53092
  }
52896
53093
  if (existing.split(/\r?\n/).some((line) => line.trim() === rule)) return;
52897
- await writeFile4(excludePath, `${existing}${existing && !existing.endsWith("\n") ? "\n" : ""}${rule}
53094
+ await writeFile5(excludePath, `${existing}${existing && !existing.endsWith("\n") ? "\n" : ""}${rule}
52898
53095
  `);
52899
53096
  }
52900
53097
  listLocalBranches() {
52901
- return this.deps.git.listLocalBranches(resolve10(this.deps.projectRoot));
53098
+ return this.deps.git.listLocalBranches(resolve11(this.deps.projectRoot));
52902
53099
  }
52903
53100
  listRemoteBranches() {
52904
- return this.deps.git.listRemoteBranches(resolve10(this.deps.projectRoot));
53101
+ return this.deps.git.listRemoteBranches(resolve11(this.deps.projectRoot));
52905
53102
  }
52906
53103
  listCheckedOutBranches() {
52907
53104
  return new Set(
52908
- this.deps.git.listWorktrees(resolve10(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch)
53105
+ this.deps.git.listWorktrees(resolve11(this.deps.projectRoot)).filter((entry) => !entry.bare && entry.branch !== null).map((entry) => entry.branch)
52909
53106
  );
52910
53107
  }
52911
53108
  listProjectWorktrees() {
52912
- const projectRoot2 = resolve10(this.deps.projectRoot);
53109
+ const projectRoot2 = resolve11(this.deps.projectRoot);
52913
53110
  return this.deps.git.listLiveWorktrees(projectRoot2).filter((entry) => !entry.bare && !sameFsPath(entry.path, projectRoot2));
52914
53111
  }
52915
53112
  async readManagedMetas() {
@@ -53182,6 +53379,14 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
53182
53379
  }
53183
53380
  return cleanupErrors.length > 0 ? cleanupErrors.join("; ") : null;
53184
53381
  }
53382
+ /** What this worktree holds that exists nowhere else, or null when it is safe to delete. */
53383
+ describeUnsavedWork(entry) {
53384
+ const status = this.deps.git.readWorktreeStatus(entry.path);
53385
+ if (status.dirty) return "uncommitted changes";
53386
+ const commits = this.deps.git.countUnsavedCommits(entry.path, this.deps.config.workspace.mainBranch);
53387
+ if (commits > 0) return `${commits} commit${commits === 1 ? "" : "s"} that are only here`;
53388
+ return null;
53389
+ }
53185
53390
  ensureNoUncommittedChanges(entry) {
53186
53391
  const status = this.deps.git.readWorktreeStatus(entry.path);
53187
53392
  if (status.dirty) {
@@ -53278,7 +53483,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
53278
53483
  const cleanupErrors = [];
53279
53484
  for (const branch of [...branches].reverse()) {
53280
53485
  try {
53281
- await this.removeWorktree(branch);
53486
+ await this.removeWorktree(branch, { force: true });
53282
53487
  } catch (error61) {
53283
53488
  cleanupErrors.push(`rollback failed for ${branch}: ${toErrorMessage2(error61)}`);
53284
53489
  }
@@ -53705,7 +53910,7 @@ var ProjectRuntime = class {
53705
53910
  };
53706
53911
 
53707
53912
  // ../host/src/modules/taskflow/services/reconciliation-service.ts
53708
- import { basename as basename6, resolve as resolve11 } from "node:path";
53913
+ import { basename as basename7, resolve as resolve12 } from "node:path";
53709
53914
 
53710
53915
  // ../host/src/modules/taskflow/lib/async.ts
53711
53916
  async function mapWithConcurrency(items, limit, fn) {
@@ -53751,7 +53956,7 @@ function startSerializedInterval(run, intervalMs, deps = {}) {
53751
53956
 
53752
53957
  // ../host/src/modules/taskflow/services/reconciliation-service.ts
53753
53958
  function makeUnmanagedWorktreeId(path) {
53754
- return `unmanaged:${resolve11(path)}`;
53959
+ return `unmanaged:${resolve12(path)}`;
53755
53960
  }
53756
53961
  function isValidPort2(port) {
53757
53962
  return port !== null && Number.isInteger(port) && port >= 1 && port <= 65535;
@@ -53786,7 +53991,7 @@ function findWindow(windows, sessionName, branch) {
53786
53991
  return windows.find((window) => window.sessionName === sessionName && window.windowName === windowName) ?? null;
53787
53992
  }
53788
53993
  function resolveBranch(entry, metaBranch) {
53789
- const fallback = basename6(entry.path);
53994
+ const fallback = basename7(entry.path);
53790
53995
  return entry.branch ?? metaBranch ?? (fallback.length > 0 ? fallback : "unknown");
53791
53996
  }
53792
53997
  var ReconciliationService = class {
@@ -53809,7 +54014,7 @@ var ReconciliationService = class {
53809
54014
  if (!options.force && this.now() - this.lastReconciledAt < this.freshnessMs) {
53810
54015
  return;
53811
54016
  }
53812
- const normalizedRepoRoot = resolve11(repoRoot);
54017
+ const normalizedRepoRoot = resolve12(repoRoot);
53813
54018
  const reconcilePromise = this.runReconcile(normalizedRepoRoot).then(() => {
53814
54019
  this.lastReconciledAt = this.now();
53815
54020
  });
@@ -56862,7 +57067,7 @@ function environmentRoutes(deps) {
56862
57067
  }
56863
57068
 
56864
57069
  // ../host/src/modules/taskflow/server/routes/github.ts
56865
- import { resolve as resolve12 } from "node:path";
57070
+ import { resolve as resolve13 } from "node:path";
56866
57071
 
56867
57072
  // ../host/src/modules/taskflow/services/auto-pull-service.ts
56868
57073
  function pullMainBranch(deps) {
@@ -57323,7 +57528,7 @@ function githubRoutes(deps) {
57323
57528
  const linkedRepo = config2.integrations.github.linkedRepos.find((lr) => lr.alias === repo);
57324
57529
  if (!linkedRepo) return errorResponse(`Unknown linked repo: ${repo}`, 404);
57325
57530
  if (!linkedRepo.dir) return errorResponse(`Linked repo "${repo}" has no dir configured`, 400);
57326
- const resolvedDir = resolve12(projectDir, linkedRepo.dir);
57531
+ const resolvedDir = resolve13(projectDir, linkedRepo.dir);
57327
57532
  const repoRoot = git2.resolveRepoRoot(resolvedDir);
57328
57533
  if (!repoRoot) return errorResponse(`Linked repo "${repo}" dir is not a git repository: ${resolvedDir}`, 400);
57329
57534
  projectRoot2 = repoRoot;
@@ -57369,7 +57574,7 @@ function hasHeader(headers, name) {
57369
57574
  return getHeader(headers, name) !== void 0;
57370
57575
  }
57371
57576
  function putViaNodeHttps(url2, headers, body) {
57372
- return new Promise((resolve21, reject2) => {
57577
+ return new Promise((resolve22, reject2) => {
57373
57578
  const parsed = new URL(url2);
57374
57579
  const req = httpsRequest(
57375
57580
  {
@@ -57386,7 +57591,7 @@ function putViaNodeHttps(url2, headers, body) {
57386
57591
  const chunks = [];
57387
57592
  res.on("data", (chunk) => chunks.push(chunk));
57388
57593
  res.on("end", () => {
57389
- resolve21({
57594
+ resolve22({
57390
57595
  status: res.statusCode ?? 0,
57391
57596
  body: Buffer.concat(chunks).toString("utf8")
57392
57597
  });
@@ -58126,7 +58331,7 @@ function projectsRoutes(deps) {
58126
58331
 
58127
58332
  // ../host/src/modules/taskflow/server/routes/runs.ts
58128
58333
  import { randomUUID as randomUUID4 } from "node:crypto";
58129
- import { resolve as resolve13 } from "node:path";
58334
+ import { resolve as resolve14 } from "node:path";
58130
58335
  import { setTimeout as delay } from "node:timers/promises";
58131
58336
  var CONFLICT_REASONS = [
58132
58337
  "branch_conflict",
@@ -58263,7 +58468,7 @@ async function apiCreateProjectRun(project, body) {
58263
58468
  permissionMode: body.permissionMode ?? "interactive",
58264
58469
  mcpServers: body.mcpServers ?? [],
58265
58470
  projectRoot: projectDir,
58266
- workspaceRoot: resolve13(projectDir, config2.workspace.worktreeRoot),
58471
+ workspaceRoot: resolve14(projectDir, config2.workspace.worktreeRoot),
58267
58472
  baseBranch: config2.workspace.mainBranch,
58268
58473
  baseCommit: git2.currentBranch(projectDir),
58269
58474
  agent: config2.workspace.defaultAgent,
@@ -58299,7 +58504,7 @@ async function apiCreateProjectRun(project, body) {
58299
58504
  snapshot: snapshot.snapshot,
58300
58505
  dataRoot: project.runs.dataRoot,
58301
58506
  projectRoot: projectDir,
58302
- workspaceRoot: resolve13(projectDir, config2.workspace.worktreeRoot),
58507
+ workspaceRoot: resolve14(projectDir, config2.workspace.worktreeRoot),
58303
58508
  baseBranch: config2.workspace.mainBranch,
58304
58509
  baseCommit: git2.currentBranch(projectDir),
58305
58510
  profile,
@@ -58423,9 +58628,9 @@ function runRoutes(deps) {
58423
58628
 
58424
58629
  // ../host/src/modules/taskflow/server/routes/worktrees.ts
58425
58630
  import { mkdirSync as mkdirSync4 } from "node:fs";
58426
- import { writeFile as writeFile5 } from "node:fs/promises";
58631
+ import { writeFile as writeFile6 } from "node:fs/promises";
58427
58632
  import { tmpdir } from "node:os";
58428
- import { join as join13, resolve as resolve14 } from "node:path";
58633
+ import { join as join14, resolve as resolve15 } from "node:path";
58429
58634
 
58430
58635
  // ../host/src/modules/taskflow/services/conversation-export-service.ts
58431
58636
  var TaskflowConversationAttachmentMessageSchema = AgentsUiConversationMessageSchema.extend({
@@ -58969,14 +59174,14 @@ ${resolvedPrompt}` : conversationContext;
58969
59174
  201
58970
59175
  );
58971
59176
  }
58972
- async function apiDeleteWorktree(project, name) {
59177
+ async function apiDeleteWorktree(project, name, force) {
58973
59178
  return project.withRemovingBranch(name, async () => {
58974
59179
  log.info(`[worktree:rm] name=${name}`);
58975
59180
  const worktree = project.runtime.projectRuntime.getWorktreeByBranch(name);
58976
59181
  const environmentId = worktree ? environmentIdForWorkspace(project.environments.projectEnvironments(), worktree.worktreeId) : null;
58977
59182
  const environment = environmentId ? project.environments.environmentForProject(environmentId) : null;
58978
59183
  if (environment) await project.environments.destroyEnvironmentRecord(environment);
58979
- await project.runtime.lifecycleService.removeWorktree(name);
59184
+ await project.runtime.lifecycleService.removeWorktree(name, { force });
58980
59185
  log.debug(`[worktree:rm] done name=${name}`);
58981
59186
  return jsonResponse({ ok: true });
58982
59187
  });
@@ -59130,7 +59335,7 @@ async function apiUploadFiles(project, name, req) {
59130
59335
  }
59131
59336
  const entries = formData.getAll("files");
59132
59337
  if (entries.length === 0) return errorResponse("No files provided", 400);
59133
- const uploadDir = join13(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
59338
+ const uploadDir = join14(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
59134
59339
  mkdirSync4(uploadDir, { recursive: true });
59135
59340
  const results = [];
59136
59341
  for (const entry of entries) {
@@ -59142,11 +59347,11 @@ async function apiUploadFiles(project, name, req) {
59142
59347
  return errorResponse(`File too large: ${entry.name} (max 10MB)`, 400);
59143
59348
  }
59144
59349
  const safeName = `${Date.now()}_${sanitizeFilename(entry.name)}`;
59145
- const destPath = join13(uploadDir, safeName);
59146
- if (!resolve14(destPath).startsWith(`${uploadDir}/`)) {
59350
+ const destPath = join14(uploadDir, safeName);
59351
+ if (!resolve15(destPath).startsWith(`${uploadDir}/`)) {
59147
59352
  return errorResponse("Invalid filename", 400);
59148
59353
  }
59149
- await writeFile5(destPath, new Uint8Array(await entry.arrayBuffer()));
59354
+ await writeFile6(destPath, new Uint8Array(await entry.arrayBuffer()));
59150
59355
  results.push({ path: destPath });
59151
59356
  }
59152
59357
  log.info(`[upload] branch=${name} files=${results.length}`);
@@ -59163,9 +59368,9 @@ function worktreeRoutes(deps) {
59163
59368
  const app = projectRouter();
59164
59369
  projectRoute(app, deps, "fetchWorktrees", "Worktrees", (project) => apiGetWorktrees(project));
59165
59370
  projectRoute(app, deps, "createWorktree", "Worktrees", (project, { body }) => apiCreateWorktree(project, body));
59166
- projectRoute(app, deps, "removeWorktree", "Worktrees", (project, { params }) => {
59371
+ projectRoute(app, deps, "removeWorktree", "Worktrees", (project, { params, query: query2 }) => {
59167
59372
  const name = worktreeName(params.name);
59168
- return name instanceof Response ? name : apiDeleteWorktree(project, name);
59373
+ return name instanceof Response ? name : apiDeleteWorktree(project, name, query2.force === true);
59169
59374
  });
59170
59375
  projectRoute(app, deps, "openWorktree", "Worktrees", (project, { params, body }) => {
59171
59376
  const name = worktreeName(params.name);
@@ -59320,7 +59525,7 @@ function createHostProjects(deps) {
59320
59525
  import { spawn as spawn6 } from "node:child_process";
59321
59526
  import { randomUUID as randomUUID6 } from "node:crypto";
59322
59527
  import { existsSync as existsSync6 } from "node:fs";
59323
- import { dirname as dirname15, join as join28, resolve as resolve20 } from "node:path";
59528
+ import { dirname as dirname15, join as join29, resolve as resolve21 } from "node:path";
59324
59529
  import { fileURLToPath } from "node:url";
59325
59530
 
59326
59531
  // ../host/src/modules/taskflow/adapters/codex-app-server.ts
@@ -59767,8 +59972,8 @@ var CodexAppServerClient = class {
59767
59972
  }
59768
59973
  const id = this.nextId;
59769
59974
  this.nextId += 1;
59770
- const result = await new Promise((resolve21, reject2) => {
59771
- this.pending.set(id, { resolve: resolve21, reject: reject2 });
59975
+ const result = await new Promise((resolve22, reject2) => {
59976
+ this.pending.set(id, { resolve: resolve22, reject: reject2 });
59772
59977
  try {
59773
59978
  this.send({
59774
59979
  id,
@@ -60431,7 +60636,7 @@ function createRunStore(path = defaultRunStorePath()) {
60431
60636
  },
60432
60637
  reserveWorkspace(input2) {
60433
60638
  const strategy = input2.strategy ?? "isolated_worktree";
60434
- const access3 = input2.access ?? "exclusive_write";
60639
+ const access4 = input2.access ?? "exclusive_write";
60435
60640
  const current = selectRun.get(input2.runId);
60436
60641
  if (!current) return { ok: false, reason: "not_found" };
60437
60642
  const run = toRunRecord(current);
@@ -60446,7 +60651,7 @@ function createRunStore(path = defaultRunStorePath()) {
60446
60651
  reserveWorkspace.run({
60447
60652
  ...input2,
60448
60653
  strategy,
60449
- access: access3,
60654
+ access: access4,
60450
60655
  canonicalWorkspacePath: strategy === "isolated_worktree" ? input2.canonicalWorkspacePath : null,
60451
60656
  branch: strategy === "isolated_worktree" ? input2.branch : null,
60452
60657
  checkoutCanonicalPath: strategy === "isolated_worktree" ? null : input2.canonicalWorkspacePath,
@@ -60747,16 +60952,16 @@ var DEFAULTS = {
60747
60952
  };
60748
60953
 
60749
60954
  // ../host/src/modules/taskflow/workflows/runtime/journal.ts
60750
- import { appendFileSync, existsSync as existsSync3, mkdirSync as mkdirSync6, readdirSync as readdirSync2, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "node:fs";
60751
- import { dirname as dirname12, join as join14 } from "node:path";
60955
+ import { appendFileSync, existsSync as existsSync3, mkdirSync as mkdirSync6, readdirSync as readdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
60956
+ import { dirname as dirname12, join as join15 } from "node:path";
60752
60957
  function dataRoot(roots = {}) {
60753
60958
  return roots.dataRoot ?? globalPaths().root;
60754
60959
  }
60755
60960
  function runDir(runId, roots = {}) {
60756
- return join14(dataRoot(roots), "runs", runId);
60961
+ return join15(dataRoot(roots), "runs", runId);
60757
60962
  }
60758
60963
  function journalPath(runId, roots = {}) {
60759
- return join14(runDir(runId, roots), "journal.jsonl");
60964
+ return join15(runDir(runId, roots), "journal.jsonl");
60760
60965
  }
60761
60966
  function ensureRunDir(runId, roots = {}) {
60762
60967
  const dir = runDir(runId, roots);
@@ -60764,9 +60969,9 @@ function ensureRunDir(runId, roots = {}) {
60764
60969
  return dir;
60765
60970
  }
60766
60971
  function listRunIds(roots = {}) {
60767
- const dir = join14(dataRoot(roots), "runs");
60972
+ const dir = join15(dataRoot(roots), "runs");
60768
60973
  if (!existsSync3(dir)) return [];
60769
- return readdirSync2(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync3(join14(dir, e.name, "journal.jsonl"))).map((e) => e.name).sort().reverse();
60974
+ return readdirSync2(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync3(join15(dir, e.name, "journal.jsonl"))).map((e) => e.name).sort().reverse();
60770
60975
  }
60771
60976
  var JournalNotFoundError = class extends Error {
60772
60977
  runId;
@@ -60803,7 +61008,7 @@ var Journal = class {
60803
61008
  const path = journalPath(runId, roots);
60804
61009
  const out = { results: /* @__PURE__ */ new Map(), indexByKey: /* @__PURE__ */ new Map() };
60805
61010
  if (!existsSync3(path)) return out;
60806
- const text = readFileSync6(path, "utf8");
61011
+ const text = readFileSync5(path, "utf8");
60807
61012
  for (const line of text.split("\n")) {
60808
61013
  const trimmed = line.trim();
60809
61014
  if (!trimmed) continue;
@@ -60846,7 +61051,7 @@ function canonicalArgs(value) {
60846
61051
  }
60847
61052
  function writeResult(runId, value, roots = {}) {
60848
61053
  const dir = ensureRunDir(runId, roots);
60849
- writeFileSync3(join14(dir, "result.json"), JSON.stringify(value, null, 2), "utf8");
61054
+ writeFileSync3(join15(dir, "result.json"), JSON.stringify(value, null, 2), "utf8");
60850
61055
  }
60851
61056
 
60852
61057
  // ../host/src/modules/taskflow/workflows/runtime/keys.ts
@@ -61179,7 +61384,7 @@ async function runInSandbox(opts) {
61179
61384
  }
61180
61385
  function raceLifecycle(work, signal, execTimeoutMs) {
61181
61386
  if (!signal && !execTimeoutMs) return work;
61182
- return new Promise((resolve21, reject2) => {
61387
+ return new Promise((resolve22, reject2) => {
61183
61388
  let settled = false;
61184
61389
  let timer;
61185
61390
  const cleanup = () => {
@@ -61210,7 +61415,7 @@ function raceLifecycle(work, signal, execTimeoutMs) {
61210
61415
  timer.unref?.();
61211
61416
  }
61212
61417
  work.then(
61213
- (v) => finish(() => resolve21(v)),
61418
+ (v) => finish(() => resolve22(v)),
61214
61419
  (e) => finish(() => reject2(e))
61215
61420
  );
61216
61421
  });
@@ -61218,13 +61423,13 @@ function raceLifecycle(work, signal, execTimeoutMs) {
61218
61423
 
61219
61424
  // ../host/src/modules/taskflow/workflows/runtime/run.ts
61220
61425
  import { createHash as createHash8, randomBytes as randomBytes2 } from "node:crypto";
61221
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
61222
- import { join as join21, resolve as resolve16 } from "node:path";
61426
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
61427
+ import { join as join22, resolve as resolve17 } from "node:path";
61223
61428
 
61224
61429
  // ../host/src/modules/taskflow/workflows/worker/claude.ts
61225
61430
  import { readlinkSync, realpathSync as realpathSync2 } from "node:fs";
61226
61431
  import { homedir as homedir3 } from "node:os";
61227
- import { basename as basename7, dirname as dirname13, isAbsolute as isAbsolute3, join as join15, relative as relative3, resolve as resolve15 } from "node:path";
61432
+ import { basename as basename8, dirname as dirname13, isAbsolute as isAbsolute3, join as join16, relative as relative4, resolve as resolve16 } from "node:path";
61228
61433
 
61229
61434
  // ../host/src/modules/taskflow/workflows/worker/index.ts
61230
61435
  var AgentError = class extends Error {
@@ -61616,10 +61821,10 @@ function checkTool(sandbox, cwd, toolName2, input2) {
61616
61821
  return void 0;
61617
61822
  }
61618
61823
  function withinCwd(cwd, candidate) {
61619
- const base = realpathUpward(resolve15(cwd));
61620
- const target = realpathUpward(isAbsolute3(candidate) ? resolve15(candidate) : resolve15(resolve15(cwd), candidate));
61824
+ const base = realpathUpward(resolve16(cwd));
61825
+ const target = realpathUpward(isAbsolute3(candidate) ? resolve16(candidate) : resolve16(resolve16(cwd), candidate));
61621
61826
  if (target === base) return true;
61622
- const rel = relative3(base, target);
61827
+ const rel = relative4(base, target);
61623
61828
  return rel !== "" && !rel.startsWith("..") && !isAbsolute3(rel);
61624
61829
  }
61625
61830
  function realpathUpward(p) {
@@ -61628,18 +61833,18 @@ function realpathUpward(p) {
61628
61833
  for (let hops = 0; hops < 40; hops++) {
61629
61834
  try {
61630
61835
  const real = realpathSync2(existing);
61631
- return suffix ? join15(real, suffix) : real;
61836
+ return suffix ? join16(real, suffix) : real;
61632
61837
  } catch {
61633
61838
  }
61634
61839
  try {
61635
61840
  const link = readlinkSync(existing);
61636
- existing = isAbsolute3(link) ? resolve15(link) : resolve15(dirname13(existing), link);
61841
+ existing = isAbsolute3(link) ? resolve16(link) : resolve16(dirname13(existing), link);
61637
61842
  continue;
61638
61843
  } catch {
61639
61844
  }
61640
61845
  const parent = dirname13(existing);
61641
61846
  if (parent === existing) return p;
61642
- suffix = suffix ? join15(basename7(existing), suffix) : basename7(existing);
61847
+ suffix = suffix ? join16(basename8(existing), suffix) : basename8(existing);
61643
61848
  existing = parent;
61644
61849
  }
61645
61850
  return p;
@@ -61749,7 +61954,7 @@ function unquote(s) {
61749
61954
  }
61750
61955
  function expandHome(p) {
61751
61956
  if (p === "~") return homedir3();
61752
- if (p.startsWith("~/")) return join15(homedir3(), p.slice(2));
61957
+ if (p.startsWith("~/")) return join16(homedir3(), p.slice(2));
61753
61958
  return p;
61754
61959
  }
61755
61960
  function usageFromResult(last) {
@@ -61770,8 +61975,8 @@ function numOr(v) {
61770
61975
  }
61771
61976
 
61772
61977
  // ../host/src/modules/taskflow/workflows/worker/codex.ts
61773
- import { copyFile, writeFile as writeFile6 } from "node:fs/promises";
61774
- import { basename as basename8, join as join16 } from "node:path";
61978
+ import { copyFile, writeFile as writeFile7 } from "node:fs/promises";
61979
+ import { basename as basename9, join as join17 } from "node:path";
61775
61980
 
61776
61981
  // ../host/src/modules/taskflow/workflows/worker/codex-protocol.ts
61777
61982
  function isObject2(value) {
@@ -62024,13 +62229,13 @@ var JsonRpcStdioClient = class {
62024
62229
  * error member, and rejects with a timeout if no response arrives in time.
62025
62230
  */
62026
62231
  request(method, params) {
62027
- return new Promise((resolve21, reject2) => {
62232
+ return new Promise((resolve22, reject2) => {
62028
62233
  if (this.dead || !this.child) {
62029
62234
  reject2(new StdioTransportError("not_writable", "child is not running"));
62030
62235
  return;
62031
62236
  }
62032
62237
  const id = this.allocId();
62033
- const entry = { resolve: resolve21, reject: reject2 };
62238
+ const entry = { resolve: resolve22, reject: reject2 };
62034
62239
  this.pending.set(id, entry);
62035
62240
  if (this.requestTimeoutMs > 0) {
62036
62241
  entry.timer = setTimeout(() => {
@@ -62243,12 +62448,12 @@ var CodexWorker = class {
62243
62448
  runTurn(ctx, sandbox, cwd, turnParams, forwardProgress, seedUsage) {
62244
62449
  const { threadId } = turnParams;
62245
62450
  let onAbort;
62246
- const p = new Promise((resolve21, reject2) => {
62451
+ const p = new Promise((resolve22, reject2) => {
62247
62452
  const state = {
62248
62453
  threadId,
62249
62454
  deltaText: "",
62250
62455
  usage: seedUsage ?? emptyUsage(),
62251
- resolve: resolve21,
62456
+ resolve: resolve22,
62252
62457
  reject: reject2,
62253
62458
  settled: false,
62254
62459
  ctx,
@@ -62519,14 +62724,14 @@ var CodexWorker = class {
62519
62724
  handleImageGeneration(state, item) {
62520
62725
  if (state.sandbox === "read-only") return;
62521
62726
  const rawId = typeof item.id === "string" && item.id.length > 0 ? item.id : "image";
62522
- const id = basename8(rawId) || "image";
62727
+ const id = basename9(rawId) || "image";
62523
62728
  const savedPath = typeof item.savedPath === "string" ? item.savedPath : void 0;
62524
62729
  const b64 = typeof item.result === "string" ? item.result : void 0;
62525
- const dest = join16(state.cwd, `${id}.png`);
62730
+ const dest = join17(state.cwd, `${id}.png`);
62526
62731
  const write2 = (async () => {
62527
62732
  try {
62528
62733
  if (savedPath) await copyFile(savedPath, dest);
62529
- else if (b64) await writeFile6(dest, Buffer.from(b64, "base64"));
62734
+ else if (b64) await writeFile7(dest, Buffer.from(b64, "base64"));
62530
62735
  else return;
62531
62736
  if (state.forwardProgress)
62532
62737
  state.ctx.onProgress({ kind: "tool-result", id, name: "image_generation", output: `saved image \u2192 ${dest}` });
@@ -62832,7 +63037,7 @@ var DEFAULT_STALL_TIMEOUT_MS = 30 * 6e4;
62832
63037
  var DEFAULT_KILL_GRACE_MS = 5e3;
62833
63038
  var DEFAULT_STDERR_LIMIT2 = 16 * 1024;
62834
63039
  function runJsonlSubprocess(o) {
62835
- return new Promise((resolve21, reject2) => {
63040
+ return new Promise((resolve22, reject2) => {
62836
63041
  if (o.signal.aborted) {
62837
63042
  reject2(new AgentInterrupted());
62838
63043
  return;
@@ -62944,7 +63149,7 @@ function runJsonlSubprocess(o) {
62944
63149
  stdoutBuf = "";
62945
63150
  deliver(rest);
62946
63151
  }
62947
- settle(() => resolve21({ code, signal: signal ?? null, stderrTail: stderrBuf.trim() }));
63152
+ settle(() => resolve22({ code, signal: signal ?? null, stderrTail: stderrBuf.trim() }));
62948
63153
  });
62949
63154
  o.signal.addEventListener("abort", onAbort, { once: true });
62950
63155
  touch();
@@ -63290,7 +63495,7 @@ function numOf(v) {
63290
63495
  // ../host/src/modules/taskflow/workflows/worker/pi.ts
63291
63496
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
63292
63497
  import { tmpdir as tmpdir2 } from "node:os";
63293
- import { join as join17 } from "node:path";
63498
+ import { join as join18 } from "node:path";
63294
63499
  var PROVIDER3 = "pi";
63295
63500
  var PI_MIN_VERSION = "0.79.1";
63296
63501
  var EFFORT_TO_THINKING = {
@@ -63405,7 +63610,7 @@ var PiWorker = class {
63405
63610
  return this.versionCheck;
63406
63611
  }
63407
63612
  async checkVersion() {
63408
- const scratch = mkdtempSync(join17(tmpdir2(), `${APP_SLUG}-pi-version-`));
63613
+ const scratch = mkdtempSync(join18(tmpdir2(), `${APP_SLUG}-pi-version-`));
63409
63614
  let out;
63410
63615
  try {
63411
63616
  out = await captureStdout({
@@ -63638,7 +63843,7 @@ var DefaultWorkerFactory = class {
63638
63843
  };
63639
63844
 
63640
63845
  // ../host/src/modules/taskflow/workflows/runtime/event-sink.ts
63641
- import { join as join18 } from "node:path";
63846
+ import { join as join19 } from "node:path";
63642
63847
 
63643
63848
  // ../host/src/modules/taskflow/workflows/runtime/jsonl-writer.ts
63644
63849
  import { createWriteStream, mkdirSync as mkdirSync7 } from "node:fs";
@@ -63674,12 +63879,12 @@ var JsonlWriter = class {
63674
63879
  }
63675
63880
  }
63676
63881
  close() {
63677
- return new Promise((resolve21) => {
63882
+ return new Promise((resolve22) => {
63678
63883
  if (this.dead) {
63679
- resolve21();
63884
+ resolve22();
63680
63885
  return;
63681
63886
  }
63682
- this.stream.end(() => resolve21());
63887
+ this.stream.end(() => resolve22());
63683
63888
  });
63684
63889
  }
63685
63890
  };
@@ -63694,7 +63899,7 @@ var FileEventSink = class {
63694
63899
  listeners;
63695
63900
  clock;
63696
63901
  constructor(runId, opts = {}) {
63697
- this.writer = new JsonlWriter(join18(runDir(runId, opts.roots), "events.jsonl"), { flags: "a" });
63902
+ this.writer = new JsonlWriter(join19(runDir(runId, opts.roots), "events.jsonl"), { flags: "a" });
63698
63903
  this.listeners = opts.listeners ?? [];
63699
63904
  this.clock = opts.clock ?? (() => globalThis.Date.now());
63700
63905
  }
@@ -63758,7 +63963,7 @@ var Semaphore = class {
63758
63963
  this.active++;
63759
63964
  return this.makeRelease();
63760
63965
  }
63761
- await new Promise((resolve21) => this.queue.push(resolve21));
63966
+ await new Promise((resolve22) => this.queue.push(resolve22));
63762
63967
  return this.makeRelease();
63763
63968
  }
63764
63969
  makeRelease() {
@@ -63785,15 +63990,15 @@ var Semaphore = class {
63785
63990
  };
63786
63991
 
63787
63992
  // ../host/src/modules/taskflow/workflows/runtime/transcript.ts
63788
- import { join as join19 } from "node:path";
63993
+ import { join as join20 } from "node:path";
63789
63994
  function agentsDir(runId, roots = {}) {
63790
- return join19(runDir(runId, roots), "agents");
63995
+ return join20(runDir(runId, roots), "agents");
63791
63996
  }
63792
63997
  function agentTranscriptPath(runId, index, roots = {}) {
63793
- return join19(agentsDir(runId, roots), `${index}.jsonl`);
63998
+ return join20(agentsDir(runId, roots), `${index}.jsonl`);
63794
63999
  }
63795
64000
  function agentTranscriptPathByName(runId, name, roots = {}) {
63796
- return join19(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
64001
+ return join20(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
63797
64002
  }
63798
64003
  var TEXT_FLUSH_MS = 120;
63799
64004
  var TEXT_FLUSH_BYTES = 2048;
@@ -63875,7 +64080,7 @@ function sanitizeName(name) {
63875
64080
  // ../host/src/modules/taskflow/workflows/runtime/worktree.ts
63876
64081
  import { execFile } from "node:child_process";
63877
64082
  import { existsSync as existsSync4, rmSync as rmSync3 } from "node:fs";
63878
- import { join as join20 } from "node:path";
64083
+ import { join as join21 } from "node:path";
63879
64084
  import { promisify } from "node:util";
63880
64085
  var exec = promisify(execFile);
63881
64086
  var BASE_CONFIG_KEY = RUNTIME_IDENTITY.gitBaseConfigKey;
@@ -63893,10 +64098,10 @@ async function findGitRoot(cwd) {
63893
64098
  async function createWorktree(args) {
63894
64099
  const name = `${args.runId}-${args.index}`;
63895
64100
  const branch = args.branch ?? `aw/${name}`;
63896
- const path = join20(projectPaths(args.gitRoot).worktrees, name);
64101
+ const path = join21(projectPaths(args.gitRoot).worktrees, name);
63897
64102
  const base = await git(args.gitRoot, ["rev-parse", "HEAD"]);
63898
64103
  await pruneStaleWorktree(args.gitRoot, path);
63899
- await git(args.gitRoot, ["worktree", "add", "--detach", path, base]);
64104
+ await git(args.gitRoot, ["worktree", "add", "--relative-paths", "--detach", path, base]);
63900
64105
  await git(path, ["checkout", "-B", branch]);
63901
64106
  try {
63902
64107
  await git(path, ["config", BASE_CONFIG_KEY, base]);
@@ -64616,8 +64821,8 @@ function fmtDur(ms) {
64616
64821
  // ../host/src/modules/taskflow/workflows/runtime/run.ts
64617
64822
  var HEARTBEAT_MS = 5e3;
64618
64823
  async function runWorkflow(opts) {
64619
- const filePath = resolve16(opts.file);
64620
- const source = readFileSync7(filePath, "utf8");
64824
+ const filePath = resolve17(opts.file);
64825
+ const source = readFileSync6(filePath, "utf8");
64621
64826
  const fileHash = sha2562(source);
64622
64827
  const findings = determinismLint(source);
64623
64828
  if (findings.length > 0) {
@@ -64674,7 +64879,7 @@ async function runWorkflow(opts) {
64674
64879
  if (opts.signal?.aborted) ac.abort();
64675
64880
  else opts.signal?.addEventListener("abort", onSig, { once: true });
64676
64881
  events.emit({ type: "run", status: "started", runId, workflowFile: filePath });
64677
- const heartbeatFile = join21(runDir(runId, opts.roots), ".heartbeat");
64882
+ const heartbeatFile = join22(runDir(runId, opts.roots), ".heartbeat");
64678
64883
  const beat = () => {
64679
64884
  try {
64680
64885
  writeFileSync4(heartbeatFile, String(Date.now()));
@@ -64753,7 +64958,7 @@ function resolveDefaults(meta3, opts) {
64753
64958
  effort: o.effort,
64754
64959
  sandbox,
64755
64960
  approval: DEFAULTS.approval,
64756
- cwd: resolve16(configuredCwd ?? process.cwd()),
64961
+ cwd: resolve17(configuredCwd ?? process.cwd()),
64757
64962
  concurrency,
64758
64963
  maxAgents: DEFAULTS.maxAgents,
64759
64964
  maxFanout: DEFAULTS.maxFanout,
@@ -65020,7 +65225,7 @@ var AgentSupervisorClient = class {
65020
65225
  throw new Error("Taskflow runtime supervisor did not become available");
65021
65226
  }
65022
65227
  send(request2) {
65023
- return new Promise((resolve21, reject2) => {
65228
+ return new Promise((resolve22, reject2) => {
65024
65229
  const socket = createConnection2(this.deps.socketPath);
65025
65230
  let data = "";
65026
65231
  socket.setEncoding("utf8");
@@ -65041,7 +65246,7 @@ var AgentSupervisorClient = class {
65041
65246
  }
65042
65247
  try {
65043
65248
  const response = responseResult(JSON.parse(line));
65044
- resolve21(response.result);
65249
+ resolve22(response.result);
65045
65250
  } catch (error61) {
65046
65251
  reject2(error61);
65047
65252
  }
@@ -65664,8 +65869,8 @@ var EnvironmentDiagnosticsService = class {
65664
65869
  return check2("github", "GitHub", "error", true, "GitHub CLI is not authenticated", "Run gh auth login");
65665
65870
  }
65666
65871
  for (const linked of this.deps.config.integrations.github.linkedRepos) {
65667
- const access3 = await this.runCommand(gh, ["repo", "view", linked.repo, "--json", "nameWithOwner"]);
65668
- if (!access3.ok) {
65872
+ const access4 = await this.runCommand(gh, ["repo", "view", linked.repo, "--json", "nameWithOwner"]);
65873
+ if (!access4.ok) {
65669
65874
  return check2(
65670
65875
  "github",
65671
65876
  "GitHub",
@@ -65762,7 +65967,7 @@ var EnvironmentDiagnosticsService = class {
65762
65967
  // ../host/src/modules/taskflow/services/environment-worker-factory.ts
65763
65968
  import { chmodSync as chmodSync2, mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync5 } from "node:fs";
65764
65969
  import { tmpdir as tmpdir3 } from "node:os";
65765
- import { join as join22, posix as posix2, relative as relative4 } from "node:path";
65970
+ import { join as join23, posix as posix2, relative as relative5 } from "node:path";
65766
65971
  var executableByProvider = {
65767
65972
  codex: "codex",
65768
65973
  "claude-code": "claude",
@@ -65789,7 +65994,7 @@ var MappedWorkspaceWorker = class {
65789
65994
  }
65790
65995
  };
65791
65996
  function mapAgentSpecToEnvironment(spec, hostWorkspace, containerWorkspace) {
65792
- const suffix = relative4(hostWorkspace, spec.cwd);
65997
+ const suffix = relative5(hostWorkspace, spec.cwd);
65793
65998
  if (suffix.startsWith("..")) {
65794
65999
  throw new Error(`Execution workspace is outside the environment mount: ${spec.cwd}`);
65795
66000
  }
@@ -65810,10 +66015,10 @@ var EnvironmentWorkerFactory = class {
65810
66015
  this.handle = handle;
65811
66016
  const containerWorkspace = handle.workspace.containerPath;
65812
66017
  if (!containerWorkspace) throw new Error(`Environment has no container workspace: ${handle.id}`);
65813
- this.directory = mkdtempSync2(join22(tmpdir3(), "taskflow-environment-workers-"));
66018
+ this.directory = mkdtempSync2(join23(tmpdir3(), "taskflow-environment-workers-"));
65814
66019
  const paths = Object.fromEntries(
65815
66020
  Object.entries(executableByProvider).map(([provider, executable]) => {
65816
- const path = join22(this.directory, provider);
66021
+ const path = join23(this.directory, provider);
65817
66022
  writeFileSync5(path, transport.executableShim(handle, executable), { encoding: "utf8", mode: 448 });
65818
66023
  chmodSync2(path, 448);
65819
66024
  return [provider, path];
@@ -65845,8 +66050,8 @@ var RoutingEnvironmentWorker = class {
65845
66050
  id;
65846
66051
  resolve;
65847
66052
  factoryFor;
65848
- constructor(id, resolve21, factoryFor) {
65849
- this.resolve = resolve21;
66053
+ constructor(id, resolve22, factoryFor) {
66054
+ this.resolve = resolve22;
65850
66055
  this.factoryFor = factoryFor;
65851
66056
  this.id = id;
65852
66057
  }
@@ -65863,8 +66068,8 @@ var RoutingEnvironmentWorkerFactory = class {
65863
66068
  workers = /* @__PURE__ */ new Map();
65864
66069
  resolve;
65865
66070
  onShutdown;
65866
- constructor(resolve21, onShutdown) {
65867
- this.resolve = resolve21;
66071
+ constructor(resolve22, onShutdown) {
66072
+ this.resolve = resolve22;
65868
66073
  this.onShutdown = onShutdown;
65869
66074
  }
65870
66075
  get(id) {
@@ -65890,11 +66095,11 @@ var RoutingEnvironmentWorkerFactory = class {
65890
66095
  };
65891
66096
 
65892
66097
  // ../host/src/modules/taskflow/services/execution-transcript-service.ts
65893
- import { readFile as readFile7 } from "node:fs/promises";
65894
- import { basename as basename9, dirname as dirname14, isAbsolute as isAbsolute4, normalize } from "node:path";
66098
+ import { readFile as readFile8 } from "node:fs/promises";
66099
+ import { basename as basename10, dirname as dirname14, isAbsolute as isAbsolute4, normalize } from "node:path";
65895
66100
 
65896
66101
  // ../host/src/modules/taskflow/services/codex-session-log-service.ts
65897
- import { readFile as readFile6 } from "node:fs/promises";
66102
+ import { readFile as readFile7 } from "node:fs/promises";
65898
66103
  var TOOL_OUTPUT_TRUNCATE_LIMIT = 12e3;
65899
66104
  function readString3(raw2) {
65900
66105
  return typeof raw2 === "string" && raw2.length > 0 ? raw2 : null;
@@ -66155,7 +66360,7 @@ function parseCodexSessionMessages(text) {
66155
66360
  async function readCodexSessionMessages(thread) {
66156
66361
  if (!thread.path) return [];
66157
66362
  try {
66158
- return parseCodexSessionMessages(await readFile6(thread.path, "utf8"));
66363
+ return parseCodexSessionMessages(await readFile7(thread.path, "utf8"));
66159
66364
  } catch {
66160
66365
  return [];
66161
66366
  }
@@ -66171,7 +66376,7 @@ function transcriptPath(value, engineRunId) {
66171
66376
  const path = normalize(candidate);
66172
66377
  const agents = dirname14(path);
66173
66378
  const run = dirname14(agents);
66174
- if (basename9(agents) !== "agents" || basename9(run) !== engineRunId || basename9(dirname14(run)) !== "runs" || !basename9(path).endsWith(".jsonl"))
66379
+ if (basename10(agents) !== "agents" || basename10(run) !== engineRunId || basename10(dirname14(run)) !== "runs" || !basename10(path).endsWith(".jsonl"))
66175
66380
  return null;
66176
66381
  return path;
66177
66382
  }
@@ -66225,7 +66430,7 @@ var ExecutionTranscriptService = class {
66225
66430
  if (path === null) return { ok: false, reason: "unavailable" };
66226
66431
  let bytes;
66227
66432
  try {
66228
- bytes = await readFile7(path);
66433
+ bytes = await readFile8(path);
66229
66434
  } catch (error61) {
66230
66435
  if (error61.code !== "ENOENT") return { ok: false, reason: "unavailable" };
66231
66436
  return { ok: true, response: { executionId, entries: [], nextCursor: 0 } };
@@ -66259,7 +66464,7 @@ var ExecutionTranscriptService = class {
66259
66464
  if (!path) return { ok: false, reason: "unavailable" };
66260
66465
  let text;
66261
66466
  try {
66262
- text = await readFile7(path, "utf8");
66467
+ text = await readFile8(path, "utf8");
66263
66468
  } catch {
66264
66469
  return { ok: false, reason: "unavailable" };
66265
66470
  }
@@ -66845,12 +67050,12 @@ var RunPresentationService = class {
66845
67050
  };
66846
67051
 
66847
67052
  // ../host/src/modules/taskflow/services/run-service.ts
66848
- import { readFile as readFile8 } from "node:fs/promises";
66849
- import { join as join24 } from "node:path";
67053
+ import { readFile as readFile9 } from "node:fs/promises";
67054
+ import { join as join25 } from "node:path";
66850
67055
 
66851
67056
  // ../host/src/modules/taskflow/services/workspace-facade.ts
66852
- import { join as join23 } from "node:path";
66853
- function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, baseCommit, workspace, access3) {
67057
+ import { join as join24 } from "node:path";
67058
+ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, baseCommit, workspace, access4) {
66854
67059
  const segment = runId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "run";
66855
67060
  if (workspace.strategy !== "isolated_worktree") {
66856
67061
  const branch = workspace.strategy === "current_branch" ? "" : workspace.branch?.trim() || `${APP_SLUG}/run-${segment}`;
@@ -66862,11 +67067,11 @@ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, bas
66862
67067
  baseBranch: workspace.strategy === "new_branch" ? workspace.baseBranch?.trim() || baseBranch : baseBranch,
66863
67068
  baseCommit,
66864
67069
  strategy: workspace.strategy,
66865
- access: access3
67070
+ access: access4
66866
67071
  };
66867
67072
  }
66868
67073
  const name = `${APP_SLUG}-run-${segment}`;
66869
- const path = join23(workspaceRoot, name);
67074
+ const path = join24(workspaceRoot, name);
66870
67075
  return {
66871
67076
  workspaceId: `workspace_${runId}`,
66872
67077
  path,
@@ -66875,7 +67080,7 @@ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, bas
66875
67080
  baseBranch: workspace.baseBranch?.trim() || baseBranch,
66876
67081
  baseCommit,
66877
67082
  strategy: workspace.strategy,
66878
- access: access3
67083
+ access: access4
66879
67084
  };
66880
67085
  }
66881
67086
  function slugSegment(value, fallback) {
@@ -66884,7 +67089,7 @@ function slugSegment(value, fallback) {
66884
67089
  function forkBindingFor(run, workspaceRoot, slug2) {
66885
67090
  const runSegment = slugSegment(run.id, "run");
66886
67091
  const forkSegment = slugSegment(slug2, "fork");
66887
- const path = join23(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
67092
+ const path = join24(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
66888
67093
  return {
66889
67094
  workspaceId: `workspace_lease_${run.id}_${forkSegment}`,
66890
67095
  path,
@@ -66936,7 +67141,7 @@ var WorkspaceFacade = class {
66936
67141
  if (run === null) return { ok: false, reason: "not_found" };
66937
67142
  if (run.workspacePolicy === "none") return { ok: true, run, workspace: null, replayed: true };
66938
67143
  const workspace = input2.workspace ?? { strategy: "isolated_worktree" };
66939
- const access3 = input2.access ?? "exclusive_write";
67144
+ const access4 = input2.access ?? "exclusive_write";
66940
67145
  const currentBranch = this.deps.git.currentBranch(input2.projectRoot);
66941
67146
  if (workspace.strategy === "current_branch" && currentBranch.length === 0)
66942
67147
  return { ok: false, reason: "detached_head" };
@@ -66952,7 +67157,7 @@ var WorkspaceFacade = class {
66952
67157
  effectiveBase,
66953
67158
  baseCommit,
66954
67159
  workspace,
66955
- access3
67160
+ access4
66956
67161
  );
66957
67162
  if (workspace.strategy === "current_branch") binding.branch = currentBranch;
66958
67163
  if (workspace.strategy !== "isolated_worktree") {
@@ -66960,7 +67165,7 @@ var WorkspaceFacade = class {
66960
67165
  runId: input2.runId,
66961
67166
  projectId: run.projectId,
66962
67167
  canonicalPath: binding.canonicalPath,
66963
- access: access3,
67168
+ access: access4,
66964
67169
  createdAt: this.now().toISOString()
66965
67170
  });
66966
67171
  if (!claim2.ok) return { ok: false, reason: "checkout_busy" };
@@ -67827,7 +68032,7 @@ var RunService = class {
67827
68032
  root,
67828
68033
  terminal.cursor,
67829
68034
  terminal.type === "completed" ? "completed" : active.cancelling ? "cancelled" : "failed",
67830
- terminal.type === "completed" ? { resultPath: join24(root.dataRoot, "runs", engineRunId, "result.json") } : null
68035
+ terminal.type === "completed" ? { resultPath: join25(root.dataRoot, "runs", engineRunId, "result.json") } : null
67831
68036
  );
67832
68037
  const completedAt = this.now().toISOString();
67833
68038
  if (terminal.type === "completed") {
@@ -67939,7 +68144,7 @@ var RunService = class {
67939
68144
  async completedResult(engineRunId, dataRoot2) {
67940
68145
  try {
67941
68146
  const result = JsonValueSchema.safeParse(
67942
- JSON.parse(await readFile8(join24(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
68147
+ JSON.parse(await readFile9(join25(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
67943
68148
  );
67944
68149
  return result.success ? result.data : null;
67945
68150
  } catch {
@@ -67986,12 +68191,12 @@ var RunService = class {
67986
68191
  };
67987
68192
 
67988
68193
  // ../host/src/modules/taskflow/services/session-restore-service.ts
67989
- import { basename as basename10, resolve as resolve17 } from "node:path";
68194
+ import { basename as basename11, resolve as resolve18 } from "node:path";
67990
68195
  function entryBranch(entry) {
67991
- return entry.branch ?? basename10(entry.path);
68196
+ return entry.branch ?? basename11(entry.path);
67992
68197
  }
67993
68198
  function computeOpenBranches(input2) {
67994
- const resolvedProjectDir = resolve17(input2.projectDir);
68199
+ const resolvedProjectDir = resolve18(input2.projectDir);
67995
68200
  const openWindowNames = new Set(
67996
68201
  input2.windows.filter((window) => window.sessionName === input2.sessionName).map((window) => window.windowName)
67997
68202
  );
@@ -68006,7 +68211,7 @@ function buildOpenSessionsState(branches, savedAt) {
68006
68211
  }
68007
68212
  var DEFAULT_SESSION_SNAPSHOT_INTERVAL_MS = 3e4;
68008
68213
  async function saveOpenSessionsSnapshot(deps) {
68009
- const projectRoot2 = resolve17(deps.projectRoot);
68214
+ const projectRoot2 = resolve18(deps.projectRoot);
68010
68215
  const sessionName = buildProjectSessionName(projectRoot2);
68011
68216
  let windows = [];
68012
68217
  try {
@@ -68313,8 +68518,8 @@ var TaskflowDirectSessionService = class {
68313
68518
 
68314
68519
  // ../host/src/modules/taskflow/services/workflow-catalog-service.ts
68315
68520
  import { createHash as createHash9 } from "node:crypto";
68316
- import { readdir as readdir4, readFile as readFile9, stat as stat4 } from "node:fs/promises";
68317
- import { join as join25, resolve as resolve18 } from "node:path";
68521
+ import { readdir as readdir4, readFile as readFile10, stat as stat4 } from "node:fs/promises";
68522
+ import { join as join26, resolve as resolve19 } from "node:path";
68318
68523
  var MAX_WORKFLOW_BYTES = 524288;
68319
68524
  function hash3(value) {
68320
68525
  return `sha256:${createHash9("sha256").update(value).digest("hex")}`;
@@ -68358,9 +68563,9 @@ function duplicateDiagnostic(name, origin) {
68358
68563
  }
68359
68564
  function rootsFor(config2) {
68360
68565
  return [
68361
- { origin: "project", directory: projectPaths(resolve18(config2.projectRoot)).workflows, priority: 0 },
68362
- { origin: "global", directory: join25(resolve18(config2.taskflowHome), PATH_NAMES.workflows), priority: 1 },
68363
- { origin: "builtin", directory: resolve18(config2.builtinRoot), priority: 2 }
68566
+ { origin: "project", directory: projectPaths(resolve19(config2.projectRoot)).workflows, priority: 0 },
68567
+ { origin: "global", directory: join26(resolve19(config2.taskflowHome), PATH_NAMES.workflows), priority: 1 },
68568
+ { origin: "builtin", directory: resolve19(config2.builtinRoot), priority: 2 }
68364
68569
  ];
68365
68570
  }
68366
68571
  var WorkflowCatalogService = class {
@@ -68465,7 +68670,7 @@ var WorkflowCatalogService = class {
68465
68670
  return { candidates, diagnostics, invalidEntries };
68466
68671
  }
68467
68672
  for (const name of names) {
68468
- const path = join25(root.directory, name);
68673
+ const path = join26(root.directory, name);
68469
68674
  try {
68470
68675
  if ((await stat4(path)).size > MAX_WORKFLOW_BYTES) {
68471
68676
  const diagnostic = {
@@ -68478,14 +68683,14 @@ var WorkflowCatalogService = class {
68478
68683
  invalidEntries.push({ status: "invalid", origin: root.origin, path, diagnostic });
68479
68684
  continue;
68480
68685
  }
68481
- const source = await readFile9(path, "utf8");
68686
+ const source = await readFile10(path, "utf8");
68482
68687
  const parsed = parseWorkflow(source);
68483
68688
  const definition = {
68484
- id: `${root.origin}:${hash3(resolve18(path))}`,
68689
+ id: `${root.origin}:${hash3(resolve19(path))}`,
68485
68690
  name: parsed.meta.name,
68486
68691
  description: parsed.meta.description,
68487
68692
  origin: root.origin,
68488
- path: resolve18(path),
68693
+ path: resolve19(path),
68489
68694
  contentHash: hash3(source),
68490
68695
  source,
68491
68696
  metadata: metadataFor(parsed.meta, this.keyVersion),
@@ -68508,7 +68713,7 @@ var WorkflowCatalogService = class {
68508
68713
  };
68509
68714
 
68510
68715
  // ../host/src/modules/taskflow/services/workflow-event-bridge.ts
68511
- import { join as join26 } from "node:path";
68716
+ import { join as join27 } from "node:path";
68512
68717
  function record4(value) {
68513
68718
  if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
68514
68719
  const output2 = {};
@@ -68598,7 +68803,7 @@ function executionFor(run, existing, details, context) {
68598
68803
  key: details.key,
68599
68804
  index: details.index,
68600
68805
  phaseIndex: details.phaseIndex,
68601
- transcriptPath: context ? join26(context.dataRoot, "runs", context.engineRunId, "agents", `${details.index}.jsonl`) : null
68806
+ transcriptPath: context ? join27(context.dataRoot, "runs", context.engineRunId, "agents", `${details.index}.jsonl`) : null
68602
68807
  },
68603
68808
  workspaceId: run.workspaceId,
68604
68809
  input: existing?.input ?? null,
@@ -68658,8 +68863,8 @@ var WorkflowEventBridge = class {
68658
68863
  };
68659
68864
 
68660
68865
  // ../host/src/modules/taskflow/services/workflow-runner.ts
68661
- import { mkdir as mkdir5, writeFile as writeFile7 } from "node:fs/promises";
68662
- import { join as join27 } from "node:path";
68866
+ import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
68867
+ import { join as join28 } from "node:path";
68663
68868
  function envelope(spec, message) {
68664
68869
  return {
68665
68870
  ...message,
@@ -68693,10 +68898,10 @@ var NodeWorkflowRunner = class {
68693
68898
  const pid = process.pid;
68694
68899
  let heartbeat;
68695
68900
  const done = (async () => {
68696
- const runDirectory = join27(spec.spec.dataRoot, "runs", spec.engineRunId);
68901
+ const runDirectory = join28(spec.spec.dataRoot, "runs", spec.engineRunId);
68697
68902
  await mkdir5(runDirectory, { recursive: true });
68698
- const snapshotPath = join27(runDirectory, "workflow.js");
68699
- await writeFile7(snapshotPath, spec.spec.source, "utf8");
68903
+ const snapshotPath = join28(runDirectory, "workflow.js");
68904
+ await writeFile8(snapshotPath, spec.spec.source, "utf8");
68700
68905
  emit(envelope(spec, { type: "started", pid }));
68701
68906
  heartbeat = setInterval(() => {
68702
68907
  emit(envelope(spec, { type: "heartbeat", cursor }));
@@ -69368,16 +69573,16 @@ var WorktreeConversationService = class {
69368
69573
 
69369
69574
  // ../host/src/modules/taskflow/adapters/docker-compose-environment.ts
69370
69575
  import { createHash as createHash10 } from "node:crypto";
69371
- import { existsSync as existsSync5, readFileSync as readFileSync8 } from "node:fs";
69372
- import { resolve as resolve19 } from "node:path";
69576
+ import { existsSync as existsSync5, readFileSync as readFileSync7 } from "node:fs";
69577
+ import { resolve as resolve20 } from "node:path";
69373
69578
  var COMPOSE_FILENAMES = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"];
69374
69579
  function composeFile(workspacePath, configured) {
69375
69580
  if (configured) {
69376
- const candidate = resolve19(workspacePath, configured);
69581
+ const candidate = resolve20(workspacePath, configured);
69377
69582
  if (existsSync5(candidate)) return candidate;
69378
69583
  throw new Error(`Docker Compose file does not exist: ${configured}`);
69379
69584
  }
69380
- const found = COMPOSE_FILENAMES.map((file2) => resolve19(workspacePath, file2)).find(existsSync5);
69585
+ const found = COMPOSE_FILENAMES.map((file2) => resolve20(workspacePath, file2)).find(existsSync5);
69381
69586
  if (!found) throw new Error("No Docker Compose file was found");
69382
69587
  return found;
69383
69588
  }
@@ -69398,7 +69603,7 @@ var DockerComposeEnvironmentProvider = class {
69398
69603
  }
69399
69604
  async probe(context) {
69400
69605
  const version2 = await runCaptured(this.runner, { command: "docker", args: ["compose", "version", "--short"] });
69401
- const configs = COMPOSE_FILENAMES.map((file2) => resolve19(context.workspacePath, file2)).filter(existsSync5);
69606
+ const configs = COMPOSE_FILENAMES.map((file2) => resolve20(context.workspacePath, file2)).filter(existsSync5);
69402
69607
  return {
69403
69608
  provider: this.id,
69404
69609
  available: version2.exit.code === 0 && configs.length > 0,
@@ -69409,7 +69614,7 @@ var DockerComposeEnvironmentProvider = class {
69409
69614
  }
69410
69615
  async resolve(context) {
69411
69616
  const file2 = composeFile(context.workspacePath, context.configRef);
69412
- const source = readFileSync8(file2, "utf8");
69617
+ const source = readFileSync7(file2, "utf8");
69413
69618
  return {
69414
69619
  provider: this.id,
69415
69620
  configRef: file2,
@@ -70021,11 +70226,11 @@ var LocalDatagramForwardProvider = class {
70021
70226
  void this.pipeResponse(command.stdout, socket, remote);
70022
70227
  void command.exited.finally(() => commands.delete(command));
70023
70228
  });
70024
- await new Promise((resolve21, reject2) => {
70229
+ await new Promise((resolve22, reject2) => {
70025
70230
  socket.once("error", reject2);
70026
70231
  socket.bind(0, "127.0.0.1", () => {
70027
70232
  socket.off("error", reject2);
70028
- resolve21();
70233
+ resolve22();
70029
70234
  });
70030
70235
  });
70031
70236
  const address = socket.address();
@@ -70049,8 +70254,8 @@ var LocalDatagramForwardProvider = class {
70049
70254
  if (!active) return;
70050
70255
  this.active.delete(endpointId);
70051
70256
  await Promise.all(Array.from(active.commands, (command) => command.kill()));
70052
- await new Promise((resolve21) => {
70053
- active.socket.close(() => resolve21());
70257
+ await new Promise((resolve22) => {
70258
+ active.socket.close(() => resolve22());
70054
70259
  });
70055
70260
  }
70056
70261
  async close() {
@@ -70127,11 +70332,11 @@ var LocalForwardProvider = class {
70127
70332
  }
70128
70333
  });
70129
70334
  });
70130
- await new Promise((resolve21, reject2) => {
70335
+ await new Promise((resolve22, reject2) => {
70131
70336
  server.once("error", reject2);
70132
70337
  server.listen(0, "127.0.0.1", () => {
70133
70338
  server.off("error", reject2);
70134
- resolve21();
70339
+ resolve22();
70135
70340
  });
70136
70341
  });
70137
70342
  const address = server.address();
@@ -70157,8 +70362,8 @@ var LocalForwardProvider = class {
70157
70362
  if (!active) return;
70158
70363
  this.active.delete(endpointId);
70159
70364
  for (const socket of active.sockets) socket.destroy();
70160
- await new Promise((resolve21) => {
70161
- active.server.close(() => resolve21());
70365
+ await new Promise((resolve22) => {
70366
+ active.server.close(() => resolve22());
70162
70367
  });
70163
70368
  }
70164
70369
  async close() {
@@ -70775,13 +70980,13 @@ function createProjectApp(runtime, instancePrefix, host) {
70775
70980
  const workflowEvents = new WorkflowEventBridge({ store: runStore, publisher: runEventPublisher });
70776
70981
  const workspaces = new WorkspaceFacade({ store: runStore, git: git2 });
70777
70982
  const workflowDataRoot = globalPaths().root;
70778
- const supervisorSocket = join28(workflowDataRoot, "runtime", "supervisor.sock");
70983
+ const supervisorSocket = join29(workflowDataRoot, "runtime", "supervisor.sock");
70779
70984
  const supervisor = new AgentSupervisorClient({
70780
70985
  socketPath: supervisorSocket,
70781
70986
  startDaemon: () => {
70782
70987
  const directory = dirname15(fileURLToPath(import.meta.url));
70783
- const builtEntry = join28(directory, "supervisor.js");
70784
- const sourceEntry = join28(directory, "supervisor.ts");
70988
+ const builtEntry = join29(directory, "supervisor.js");
70989
+ const sourceEntry = join29(directory, "supervisor.ts");
70785
70990
  const child = existsSync6(builtEntry) ? spawn6(process.execPath, [builtEntry], { detached: true, stdio: "ignore" }) : spawn6(process.execPath, ["--import", "tsx", sourceEntry], { detached: true, stdio: "ignore" });
70786
70991
  child.unref();
70787
70992
  }
@@ -71067,7 +71272,7 @@ function createProjectApp(runtime, instancePrefix, host) {
71067
71272
  startupEnvs: config2.startupEnvs,
71068
71273
  linkedRepos: config2.integrations.github.linkedRepos.map((lr) => ({
71069
71274
  alias: lr.alias,
71070
- ...lr.dir ? { dir: resolve20(PROJECT_DIR, lr.dir) } : {}
71275
+ ...lr.dir ? { dir: resolve21(PROJECT_DIR, lr.dir) } : {}
71071
71276
  })),
71072
71277
  linearAutoCreateWorktrees: linearAutoCreateEnabled,
71073
71278
  autoRemoveOnMerge: autoRemoveOnMergeEnabled,
@@ -71153,13 +71358,13 @@ function createProjectApp(runtime, instancePrefix, host) {
71153
71358
  }
71154
71359
  }
71155
71360
  async function getWorktreeGitDirs() {
71156
- const gitDirs = /* @__PURE__ */ new Map();
71157
- const projectRoot2 = resolve20(PROJECT_DIR);
71361
+ const gitDirs2 = /* @__PURE__ */ new Map();
71362
+ const projectRoot2 = resolve21(PROJECT_DIR);
71158
71363
  for (const entry of git2.listLiveWorktrees(projectRoot2)) {
71159
71364
  if (entry.bare || sameFsPath(entry.path, projectRoot2) || !entry.branch) continue;
71160
- gitDirs.set(entry.branch, git2.resolveWorktreeGitDir(entry.path));
71365
+ gitDirs2.set(entry.branch, git2.resolveWorktreeGitDir(entry.path));
71161
71366
  }
71162
- return gitDirs;
71367
+ return gitDirs2;
71163
71368
  }
71164
71369
  async function readProjectSnapshot() {
71165
71370
  const linearApiKey = process.env.LINEAR_API_KEY;
@@ -72223,7 +72428,7 @@ function createDaemonTaskflowHost(context) {
72223
72428
  port: hostListen(env2).port,
72224
72429
  workflowBuiltinsDir: taskflowAssets(env2).workflowBuiltinsDir,
72225
72430
  version: env2.PORTTA_VERSION || "0.0.0-local",
72226
- buildDate: true ? "2026-09-17T17:01:02Z" : (/* @__PURE__ */ new Date()).toISOString(),
72431
+ buildDate: true ? "2026-09-18T00:00:48Z" : (/* @__PURE__ */ new Date()).toISOString(),
72227
72432
  environmentStore: createEnvironmentStore(paths.database),
72228
72433
  hostEnvironmentProvider: new HostEnvironmentProvider(),
72229
72434
  devContainerProvider: new DevContainerProvider(),
@@ -72702,7 +72907,7 @@ var readBodyDirect = (request2) => {
72702
72907
  request2[bodyBufferKey] = buffered;
72703
72908
  return Promise.resolve(buffered);
72704
72909
  }
72705
- const promise2 = new Promise((resolve21, reject2) => {
72910
+ const promise2 = new Promise((resolve22, reject2) => {
72706
72911
  const chunks = [];
72707
72912
  let settled = false;
72708
72913
  const finish = (callback) => {
@@ -72720,7 +72925,7 @@ var readBodyDirect = (request2) => {
72720
72925
  else if (recovered === void 0) reject2(error61 ?? normalizeAbortError(request2, incoming));
72721
72926
  else {
72722
72927
  request2[bodyBufferKey] = recovered;
72723
- resolve21(recovered);
72928
+ resolve22(recovered);
72724
72929
  }
72725
72930
  });
72726
72931
  return true;
@@ -72732,7 +72937,7 @@ var readBodyDirect = (request2) => {
72732
72937
  finish(() => {
72733
72938
  const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);
72734
72939
  request2[bodyBufferKey] = buffer;
72735
- resolve21(buffer);
72940
+ resolve22(buffer);
72736
72941
  });
72737
72942
  };
72738
72943
  const onError = (error61) => {
@@ -73257,7 +73462,7 @@ var responseViaResponseObject = async (res, outgoing, options = {}) => {
73257
73462
  });
73258
73463
  if (!chunk) {
73259
73464
  if (i === 1) {
73260
- await new Promise((resolve21) => setTimeout(resolve21));
73465
+ await new Promise((resolve22) => setTimeout(resolve22));
73261
73466
  maxReadCount = 3;
73262
73467
  continue;
73263
73468
  }
@@ -73554,8 +73759,8 @@ var SESSION_ABANDON_AFTER_SECONDS = 6 * 60 * 60;
73554
73759
  var INSTRUCTION_MAX_BYTES = 64 * 1024;
73555
73760
 
73556
73761
  // ../core/src/database-config.ts
73557
- import { join as join29 } from "node:path";
73558
- var DATABASE_RELATIVE_PATH = join29("state", "panel", "portta.db");
73762
+ import { join as join30 } from "node:path";
73763
+ var DATABASE_RELATIVE_PATH = join30("state", "panel", "portta.db");
73559
73764
 
73560
73765
  // ../../node_modules/ws/wrapper.mjs
73561
73766
  var import_stream = __toESM(require_stream(), 1);
@@ -73611,7 +73816,7 @@ function ghPath() {
73611
73816
  }
73612
73817
  function runGh2(args, options = {}) {
73613
73818
  const binary = ghPath();
73614
- return new Promise((resolve21, reject2) => {
73819
+ return new Promise((resolve22, reject2) => {
73615
73820
  const child = execFile2(
73616
73821
  binary,
73617
73822
  args,
@@ -73624,7 +73829,7 @@ function runGh2(args, options = {}) {
73624
73829
  env: { ...process.env, GH_PAGER: "cat", NO_COLOR: "1", GH_PROMPT_DISABLED: "1" }
73625
73830
  },
73626
73831
  (error61, stdout, stderr) => {
73627
- if (!error61) return resolve21(stdout);
73832
+ if (!error61) return resolve22(stdout);
73628
73833
  if (error61.killed) {
73629
73834
  return reject2(new ForgeError("timeout", `gh ${args[0]} ${args[1] ?? ""} took longer than ${TIMEOUT_MS / 1e3}s`));
73630
73835
  }
@@ -74087,11 +74292,11 @@ async function startHost(options) {
74087
74292
  const sockets = new import_websocket_server.default({ noServer: true });
74088
74293
  const server = createServer2(getRequestListener(app.fetch));
74089
74294
  server.on("upgrade", createHostUpgrade(options, sockets));
74090
- await new Promise((resolve21, reject2) => {
74295
+ await new Promise((resolve22, reject2) => {
74091
74296
  server.once("error", reject2);
74092
74297
  server.listen(options.port, options.host, () => {
74093
74298
  server.off("error", reject2);
74094
- resolve21();
74299
+ resolve22();
74095
74300
  });
74096
74301
  });
74097
74302
  const address = server.address();
@@ -74102,8 +74307,8 @@ async function startHost(options) {
74102
74307
  close: async () => {
74103
74308
  for (const socket of sockets.clients) socket.close(1001, "the host daemon is shutting down");
74104
74309
  sockets.close();
74105
- await new Promise((resolve21) => {
74106
- server.close(() => resolve21());
74310
+ await new Promise((resolve22) => {
74311
+ server.close(() => resolve22());
74107
74312
  server.closeAllConnections();
74108
74313
  });
74109
74314
  for (const module of options.modules) await module.close?.();