@codions/portta 0.0.0-develop.171.sha-d749180 → 0.0.0-develop.174.sha-9f22fb0

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.
Files changed (31) hide show
  1. package/dist/assets/skills/portta-workflows/SKILL.md +1 -1
  2. package/dist/assets/workflows/bake-off.workflow.js +6 -5
  3. package/dist/assets/workflows/code-review.workflow.js +4 -4
  4. package/dist/assets/workflows/deep-research.workflow.js +4 -3
  5. package/dist/assets/workflows/multi-provider-review.workflow.js +5 -4
  6. package/dist/assets/workflows/provider-debate.workflow.js +7 -6
  7. package/dist/assets/workflows/second-opinion.workflow.js +4 -3
  8. package/dist/cli.js +794 -847
  9. package/dist/documentation.json +1 -1
  10. package/dist/host.js +53 -93
  11. package/dist/runtime/.env.example +8 -17
  12. package/dist/runtime/VERSION +1 -1
  13. package/dist/runtime/docker/compose/features/panel-host.yaml +4 -5
  14. package/dist/runtime/templates/README.md +9 -6
  15. package/dist/runtime/templates/overlays/07-worktree.env +1 -1
  16. package/dist/runtime/templates/project/PORTTA.md +3 -3
  17. package/dist/supervisor.js +0 -1
  18. package/package.json +2 -5
  19. package/dist/runtime/config/traefik/dynamic/auth.example.yaml.disabled +0 -24
  20. package/dist/runtime/docker/images/README.md +0 -12
  21. package/dist/runtime/docker/images/sandbox/Dockerfile +0 -79
  22. package/dist/runtime/docker/images/sandbox/README.md +0 -109
  23. package/dist/runtime/docker/images/sandbox/VERSION +0 -1
  24. package/dist/runtime/docker/images/sandbox/agents/claude-code.sh +0 -18
  25. package/dist/runtime/docker/images/sandbox/agents/codex.sh +0 -4
  26. package/dist/runtime/docker/images/sandbox/agents/opencode.sh +0 -4
  27. package/dist/runtime/docker/images/sandbox/agents/pi.sh +0 -4
  28. package/dist/runtime/docker/images/sandbox/scripts/entrypoint.sh +0 -8
  29. package/dist/runtime/docker/images/sandbox/scripts/generate-manifest.mjs +0 -81
  30. package/dist/runtime/docker/images/sandbox/scripts/install-tools.sh +0 -46
  31. package/dist/runtime/docker/images/sandbox/scripts/verify-image.sh +0 -18
package/dist/cli.js CHANGED
@@ -19820,17 +19820,12 @@ function fitLabel(label3, limit = MAX_LABEL) {
19820
19820
  const keep = limit - digest2.length - 1;
19821
19821
  return `${label3.slice(0, keep).replace(/-+$/, "")}-${digest2}`;
19822
19822
  }
19823
- function hostLabel(parts2, style = "project-service") {
19823
+ function hostLabel(parts2) {
19824
19824
  const project2 = slug(parts2.project);
19825
19825
  const service2 = slug(parts2.service);
19826
19826
  const context = parts2.context ? slug(parts2.context) : "";
19827
- if (style === "project-service") {
19828
- const base2 = service2 ? `${project2}-${service2}` : project2;
19829
- return fitLabel(context ? `${base2}${COMPONENT_SEPARATOR}${context}` : base2);
19830
- }
19831
- const components = [service2, project2];
19832
- if (context) components.push(context);
19833
- return fitLabel(components.filter(Boolean).join(COMPONENT_SEPARATOR));
19827
+ const base2 = service2 ? `${project2}-${service2}` : project2;
19828
+ return fitLabel(context ? `${base2}${COMPONENT_SEPARATOR}${context}` : base2);
19834
19829
  }
19835
19830
  var MAX_LABEL, COMPONENT_SEPARATOR;
19836
19831
  var init_hostname = __esm({
@@ -20014,10 +20009,6 @@ function composeFiles(config3) {
20014
20009
  if (config3.tunnelEnabled) files.push("docker/compose/features/cloudflare-tunnel.yaml");
20015
20010
  return files;
20016
20011
  }
20017
- function composeFilesForRoot(config3, root2) {
20018
- void root2;
20019
- return composeFiles(config3);
20020
- }
20021
20012
  var AUTH_BUILD_FILE, AUTH_DEV_FILE, TASKFLOW_FILE, PANEL_HOST_FILE, TRUTHY, GATEWAY_PROFILES, PANEL_ACCESS_MODES, PANEL_ACCESS_WITHOUT_AUTH, PANEL_AUTH_MODES;
20022
20013
  var init_config = __esm({
20023
20014
  "../core/src/config.ts"() {
@@ -20354,7 +20345,6 @@ var BRIDGE_IMAGE, KIND_RULES;
20354
20345
  var init_discovery = __esm({
20355
20346
  "../core/src/discovery.ts"() {
20356
20347
  "use strict";
20357
- init_namespace();
20358
20348
  BRIDGE_IMAGE = "alpine/socat:1.8.1.3";
20359
20349
  KIND_RULES = [
20360
20350
  { match: /postgres|postgis|timescale/, kind: "postgres", port: 5432 },
@@ -20373,7 +20363,6 @@ var init_discovery = __esm({
20373
20363
  });
20374
20364
 
20375
20365
  // ../core/src/endpoints.ts
20376
- var PROVIDERS, PROVIDERS_BY_ID;
20377
20366
  var init_endpoints = __esm({
20378
20367
  "../core/src/endpoints.ts"() {
20379
20368
  "use strict";
@@ -20381,19 +20370,6 @@ var init_endpoints = __esm({
20381
20370
  init_discovery();
20382
20371
  init_domain();
20383
20372
  init_hostname();
20384
- PROVIDERS = [
20385
- { id: "internal", scope: "internal", requires: null, optional: false },
20386
- { id: "local", scope: "local", requires: "localhost", optional: false },
20387
- { id: "lan", scope: "lan", requires: "lan", optional: true },
20388
- { id: "tailscale", scope: "private", requires: "tailscale", optional: true },
20389
- { id: "tailscale-serve", scope: "private", requires: "tailscale-https", optional: true },
20390
- { id: "public-ip", scope: "public", requires: "public-ipv4", optional: true },
20391
- { id: "auto-domain", scope: "public", requires: "auto-domain", optional: true },
20392
- { id: "custom-domain", scope: "public", requires: "custom-domain", optional: true },
20393
- { id: "cloudflare-tunnel", scope: "public", requires: "cloudflare-tunnel", optional: true },
20394
- { id: "bridge", scope: "local", requires: null, optional: true }
20395
- ];
20396
- PROVIDERS_BY_ID = new Map(PROVIDERS.map((spec) => [spec.id, spec]));
20397
20373
  }
20398
20374
  });
20399
20375
 
@@ -20575,15 +20551,6 @@ var init_env = __esm({
20575
20551
  }
20576
20552
  });
20577
20553
 
20578
- // ../core/src/host.ts
20579
- var MIB;
20580
- var init_host = __esm({
20581
- "../core/src/host.ts"() {
20582
- "use strict";
20583
- MIB = 1024 * 1024;
20584
- }
20585
- });
20586
-
20587
20554
  // ../core/src/host-security.ts
20588
20555
  function permissionProblem(output2) {
20589
20556
  return /permission denied|operation not permitted|must be root|need to be root|requires root|not authorized/i.test(output2) ? "could not be checked: this user does not have permission" : null;
@@ -22424,7 +22391,6 @@ var init_src = __esm({
22424
22391
  init_endpoints();
22425
22392
  init_env();
22426
22393
  init_hostname();
22427
- init_host();
22428
22394
  init_host_security();
22429
22395
  init_images();
22430
22396
  init_metrics();
@@ -22501,7 +22467,7 @@ var init_package = __esm({
22501
22467
  "package.json"() {
22502
22468
  package_default = {
22503
22469
  name: "@codions/portta",
22504
- version: "0.0.0-develop.171.sha-d749180",
22470
+ version: "0.0.0-develop.174.sha-9f22fb0",
22505
22471
  description: "Machine-first CLI for a shared Docker development gateway",
22506
22472
  license: "MIT",
22507
22473
  type: "module",
@@ -22520,10 +22486,7 @@ var init_package = __esm({
22520
22486
  typecheck: "tsc -p tsconfig.json --noEmit",
22521
22487
  test: "vitest run",
22522
22488
  prepack: "npm run build",
22523
- prepublishOnly: "npm run typecheck && npm test",
22524
- preversion: "node scripts/git-version.mjs check",
22525
- version: "node scripts/git-version.mjs sync",
22526
- postversion: "node scripts/git-version.mjs verify"
22489
+ prepublishOnly: "npm run typecheck && npm test"
22527
22490
  },
22528
22491
  engines: {
22529
22492
  node: ">=24"
@@ -22575,7 +22538,7 @@ var init_version = __esm({
22575
22538
  "use strict";
22576
22539
  init_package();
22577
22540
  CLI_VERSION = package_default.version;
22578
- CLI_BUILD_DATE = true ? "2026-09-18T00:56:55Z" : void 0;
22541
+ CLI_BUILD_DATE = true ? "2026-09-18T02:50:11Z" : void 0;
22579
22542
  }
22580
22543
  });
22581
22544
 
@@ -22591,12 +22554,13 @@ function versionForRoot(root2) {
22591
22554
  if (existsSync4(generated)) return readFileSync4(generated, "utf8").trim();
22592
22555
  const manifest = join5(root2, "packages", "cli", "package.json");
22593
22556
  if (existsSync4(manifest)) return LOCAL_DEV_VERSION;
22594
- throw new PreconditionError(`missing generated VERSION in ${root2}`, "reinstall the portta npm package");
22557
+ throw new PreconditionError(`missing generated VERSION in ${root2}`, "reinstall the @codions/portta npm package");
22595
22558
  }
22596
22559
  function wellKnownRoots() {
22597
22560
  const home2 = process.env["HOME"];
22598
22561
  return [
22599
22562
  process.env["PORTTA_HOME"],
22563
+ home2 ? join5(home2, "portta") : void 0,
22600
22564
  "/opt/portta",
22601
22565
  home2 ? join5(home2, ".portta") : void 0,
22602
22566
  "/var/lib/portta"
@@ -22636,7 +22600,7 @@ function gatewayContext(options = {}) {
22636
22600
  const config3 = loadGatewayConfig(env);
22637
22601
  env["PORTTA_DOMAIN"] = config3.domain;
22638
22602
  env["PORTTA_BIND_ADDRESS"] = config3.bindAddress;
22639
- const files = composeFilesForRoot(config3, root2);
22603
+ const files = composeFiles(config3);
22640
22604
  for (const fileName of files) {
22641
22605
  if (!existsSync4(join5(root2, fileName))) throw new PreconditionError(`missing compose file: ${fileName}`);
22642
22606
  }
@@ -34341,6 +34305,138 @@ var init_execa = __esm({
34341
34305
  }
34342
34306
  });
34343
34307
 
34308
+ // src/process.ts
34309
+ import { spawn as spawn2 } from "node:child_process";
34310
+ import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
34311
+ function setProcessReporter(options) {
34312
+ reporting = options;
34313
+ }
34314
+ function effectiveStdio(requested) {
34315
+ if (requested === "inherit") return "inherit";
34316
+ if (reporting.quiet) return "pipe";
34317
+ if (reporting.verbose) return "stream";
34318
+ return requested;
34319
+ }
34320
+ function outputTargets(mode) {
34321
+ if (mode !== "stream") return { stdio: mode };
34322
+ return {
34323
+ stdin: "pipe",
34324
+ stdout: reporting.json ? "pipe" : ["pipe", "inherit"],
34325
+ stderr: ["pipe", "inherit"]
34326
+ };
34327
+ }
34328
+ function elapsed(sinceMs) {
34329
+ const seconds = Math.round((Date.now() - sinceMs) / 1e3);
34330
+ if (seconds < 60) return `${seconds}s`;
34331
+ return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, "0")}s`;
34332
+ }
34333
+ function describeCommand(file2, args, limit = 88) {
34334
+ const words = [];
34335
+ for (let index = 0; index < args.length; index += 1) {
34336
+ const argument = args[index] ?? "";
34337
+ if (argument === "-f" || argument === "--file") {
34338
+ index += 1;
34339
+ continue;
34340
+ }
34341
+ words.push(argument);
34342
+ }
34343
+ const line4 = [file2, ...words].join(" ");
34344
+ return line4.length <= limit ? line4 : `${line4.slice(0, limit - 1)}\u2026`;
34345
+ }
34346
+ function startHeartbeat(file2, args) {
34347
+ if (reporting.quiet) return () => {
34348
+ };
34349
+ const started = Date.now();
34350
+ const label3 = describeCommand(file2, args);
34351
+ let hinted = false;
34352
+ const announce = () => {
34353
+ process.stderr.write(`wait still running: ${label3} (${elapsed(started)})
34354
+ `);
34355
+ if (!hinted && Date.now() - started >= HEARTBEAT_HINT_MS) {
34356
+ hinted = true;
34357
+ process.stderr.write(" -> a first build of the panel image takes several minutes; Ctrl-C is safe, and --verbose shows its output\n");
34358
+ }
34359
+ };
34360
+ let repeat;
34361
+ const first = setTimeout(() => {
34362
+ announce();
34363
+ repeat = setInterval(announce, HEARTBEAT_EVERY_MS);
34364
+ repeat.unref?.();
34365
+ }, HEARTBEAT_FIRST_MS);
34366
+ first.unref?.();
34367
+ return () => {
34368
+ clearTimeout(first);
34369
+ if (repeat) clearInterval(repeat);
34370
+ };
34371
+ }
34372
+ async function runProcess(file2, args = [], options = {}) {
34373
+ const mode = effectiveStdio(options.stdio ?? "pipe");
34374
+ const execaOptions = {
34375
+ cwd: options.cwd,
34376
+ env: options.env,
34377
+ input: options.input,
34378
+ reject: options.reject ?? true,
34379
+ shell: false,
34380
+ timeout: options.timeout,
34381
+ ...outputTargets(mode)
34382
+ };
34383
+ const stopHeartbeat = mode === "pipe" ? startHeartbeat(file2, args) : () => {
34384
+ };
34385
+ try {
34386
+ const result = await execa(file2, [...args], execaOptions);
34387
+ const notStarted = result.failed && result.exitCode === void 0 && !result.signal && !result.timedOut;
34388
+ return {
34389
+ stdout: typeof result.stdout === "string" ? result.stdout : "",
34390
+ stderr: typeof result.stderr === "string" ? result.stderr : "",
34391
+ exitCode: result.exitCode ?? (result.failed ? 1 : 0),
34392
+ failed: result.failed,
34393
+ ...notStarted && "originalMessage" in result ? { error: String(result.originalMessage) } : {}
34394
+ };
34395
+ } finally {
34396
+ stopHeartbeat();
34397
+ }
34398
+ }
34399
+ async function runForeground(file2, args, options = {}) {
34400
+ const child = execa(file2, [...args], { cwd: options.cwd, env: options.env, stdio: "inherit", reject: false, shell: false });
34401
+ const forwarded = ["SIGINT", "SIGTERM", "SIGHUP"].map((signal) => [signal, () => {
34402
+ child.kill(signal);
34403
+ }]);
34404
+ for (const [signal, forward] of forwarded) process.on(signal, forward);
34405
+ try {
34406
+ const result = await child;
34407
+ return result.exitCode ?? (result.signal ? 1 : 0);
34408
+ } finally {
34409
+ for (const [signal, forward] of forwarded) process.off(signal, forward);
34410
+ }
34411
+ }
34412
+ function spawnDetached(file2, args, options = {}) {
34413
+ const log3 = options.logFile ? openSync2(options.logFile, "a", 384) : null;
34414
+ try {
34415
+ const child = spawn2(file2, [...args], {
34416
+ cwd: options.cwd,
34417
+ env: options.env,
34418
+ shell: false,
34419
+ detached: true,
34420
+ stdio: log3 === null ? "ignore" : ["ignore", log3, log3]
34421
+ });
34422
+ child.unref();
34423
+ return child.pid;
34424
+ } finally {
34425
+ if (log3 !== null) closeSync2(log3);
34426
+ }
34427
+ }
34428
+ var reporting, HEARTBEAT_FIRST_MS, HEARTBEAT_EVERY_MS, HEARTBEAT_HINT_MS;
34429
+ var init_process = __esm({
34430
+ "src/process.ts"() {
34431
+ "use strict";
34432
+ init_execa();
34433
+ reporting = {};
34434
+ HEARTBEAT_FIRST_MS = 1e4;
34435
+ HEARTBEAT_EVERY_MS = 3e4;
34436
+ HEARTBEAT_HINT_MS = 18e4;
34437
+ }
34438
+ });
34439
+
34344
34440
  // ../../node_modules/hono/dist/compose.js
34345
34441
  var compose;
34346
34442
  var init_compose = __esm({
@@ -36812,7 +36908,7 @@ var init_user_shell_env = __esm({
36812
36908
  // ../host/src/modules/taskflow/lib/host-tools.ts
36813
36909
  import { spawnSync as spawnSync2 } from "node:child_process";
36814
36910
  import { accessSync as accessSync2, constants as constants5, statSync as statSync3 } from "node:fs";
36815
- import { delimiter as delimiter2, dirname as dirname5, isAbsolute, join as join8 } from "node:path";
36911
+ import { delimiter as delimiter2, dirname as dirname5, isAbsolute, join as join9 } from "node:path";
36816
36912
  function defaultIsExecutableFile(candidate) {
36817
36913
  try {
36818
36914
  accessSync2(candidate, constants5.X_OK);
@@ -36826,20 +36922,20 @@ function firstExecutable(candidates, isExecutable) {
36826
36922
  }
36827
36923
  function pathCandidates(tool, pathEnv) {
36828
36924
  if (!pathEnv) return [];
36829
- return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join8(entry, tool));
36925
+ return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join9(entry, tool));
36830
36926
  }
36831
36927
  function wellKnownBinDirectories(input2) {
36832
36928
  const directories = [];
36833
36929
  const home2 = input2.env.HOME?.trim();
36834
36930
  if (home2) {
36835
36931
  directories.push(
36836
- join8(home2, ".local", "bin"),
36837
- join8(home2, ".cargo", "bin"),
36838
- join8(home2, ".bun", "bin"),
36839
- join8(home2, ".volta", "bin"),
36840
- join8(home2, ".asdf", "shims"),
36841
- join8(home2, ".local", "share", "mise", "shims"),
36842
- join8(home2, ".npm-global", "bin")
36932
+ join9(home2, ".local", "bin"),
36933
+ join9(home2, ".cargo", "bin"),
36934
+ join9(home2, ".bun", "bin"),
36935
+ join9(home2, ".volta", "bin"),
36936
+ join9(home2, ".asdf", "shims"),
36937
+ join9(home2, ".local", "share", "mise", "shims"),
36938
+ join9(home2, ".npm-global", "bin")
36843
36939
  );
36844
36940
  }
36845
36941
  directories.push(dirname5(input2.execPath));
@@ -36850,7 +36946,7 @@ function wellKnownBinDirectories(input2) {
36850
36946
  }
36851
36947
  function wellKnownToolPaths(tool, env) {
36852
36948
  const home2 = env.HOME?.trim();
36853
- if (tool === "claude" && home2) return [join8(home2, ".claude", "local", "claude")];
36949
+ if (tool === "claude" && home2) return [join9(home2, ".claude", "local", "claude")];
36854
36950
  return [];
36855
36951
  }
36856
36952
  function loginWhichCommand(tool) {
@@ -36897,7 +36993,7 @@ function resolveNpmGlobalBin(input2) {
36897
36993
  env: input2.env,
36898
36994
  execPath: input2.execPath,
36899
36995
  platform: input2.platform
36900
- }).map((directory) => join8(directory, "npm")),
36996
+ }).map((directory) => join9(directory, "npm")),
36901
36997
  input2.isExecutable
36902
36998
  );
36903
36999
  if (!npm) return null;
@@ -36909,7 +37005,7 @@ function resolveNpmGlobalBin(input2) {
36909
37005
  });
36910
37006
  if (result.error || result.status !== 0) return null;
36911
37007
  const prefix = (result.stdout ?? "").trim().split(/\r?\n/u)[0]?.trim();
36912
- return prefix ? join8(prefix, "bin") : null;
37008
+ return prefix ? join9(prefix, "bin") : null;
36913
37009
  }
36914
37010
  function createHostToolResolver(options = {}) {
36915
37011
  const env = options.env ?? process.env;
@@ -36938,7 +37034,7 @@ function createHostToolResolver(options = {}) {
36938
37034
  npmGlobalBin = resolveNpmGlobalBin({ env, execPath: execPath2, isExecutable, platform: platform4 });
36939
37035
  }
36940
37036
  const wellKnown = wellKnownBinDirectories({ env, execPath: execPath2, npmGlobalBin, platform: platform4 }).map(
36941
- (directory) => join8(directory, name)
37037
+ (directory) => join9(directory, name)
36942
37038
  );
36943
37039
  const wellKnownHit = firstExecutable(wellKnown, isExecutable);
36944
37040
  if (wellKnownHit) return wellKnownHit;
@@ -37128,7 +37224,6 @@ var init_config2 = __esm({
37128
37224
  tmuxBufferPrefix: `${APP_SLUG}-prompt`,
37129
37225
  dockerContainerPrefix: APP_SLUG,
37130
37226
  tempUploadDir: `${APP_SLUG}-uploads`,
37131
- dockerImage: "portta-sandbox",
37132
37227
  gitBaseConfigKey: `${APP_SLUG}.base`
37133
37228
  };
37134
37229
  SERVICE_IDENTITY = {
@@ -44496,48 +44591,48 @@ var init_main2 = __esm({
44496
44591
 
44497
44592
  // ../core/src/taskflow/paths.ts
44498
44593
  import { homedir as homedir2 } from "node:os";
44499
- import { join as join9 } from "node:path";
44594
+ import { join as join10 } from "node:path";
44500
44595
  function globalConfigDir(options = {}) {
44501
44596
  const env = options.env ?? process.env;
44502
44597
  const override = env[ENV_NAMES.home]?.trim();
44503
- return override || join9(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44598
+ return override || join10(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44504
44599
  }
44505
44600
  function globalPaths(options = {}) {
44506
44601
  const home2 = globalConfigDir(options);
44507
44602
  const env = options.env ?? process.env;
44508
- const root2 = env[ENV_NAMES.hostStateDir]?.trim() || join9(home2, HOST_STATE_DIR);
44603
+ const root2 = env[ENV_NAMES.hostStateDir]?.trim() || join10(home2, HOST_STATE_DIR);
44509
44604
  return {
44510
44605
  root: root2,
44511
- env: join9(home2, PATH_NAMES.env),
44512
- controlToken: join9(root2, PATH_NAMES.controlToken),
44513
- projectsRegistry: join9(root2, PATH_NAMES.projectsRegistry),
44514
- database: join9(root2, PATH_NAMES.database),
44515
- runs: join9(root2, PATH_NAMES.runs),
44516
- workflows: join9(root2, PATH_NAMES.workflows)
44606
+ env: join10(home2, PATH_NAMES.env),
44607
+ controlToken: join10(root2, PATH_NAMES.controlToken),
44608
+ projectsRegistry: join10(root2, PATH_NAMES.projectsRegistry),
44609
+ database: join10(root2, PATH_NAMES.database),
44610
+ runs: join10(root2, PATH_NAMES.runs),
44611
+ workflows: join10(root2, PATH_NAMES.workflows)
44517
44612
  };
44518
44613
  }
44519
44614
  function projectPaths(projectRoot2) {
44520
- const root2 = join9(projectRoot2, PROJECT_CONFIG_DIR);
44615
+ const root2 = join10(projectRoot2, PROJECT_CONFIG_DIR);
44521
44616
  return {
44522
44617
  root: root2,
44523
- config: join9(root2, PATH_NAMES.projectConfig),
44524
- localConfig: join9(root2, PATH_NAMES.projectLocalConfig),
44525
- configExample: join9(root2, PATH_NAMES.projectConfigExample),
44526
- workflows: join9(root2, PATH_NAMES.workflows),
44527
- worktrees: join9(root2, PATH_NAMES.worktrees)
44618
+ config: join10(root2, PATH_NAMES.projectConfig),
44619
+ localConfig: join10(root2, PATH_NAMES.projectLocalConfig),
44620
+ configExample: join10(root2, PATH_NAMES.projectConfigExample),
44621
+ workflows: join10(root2, PATH_NAMES.workflows),
44622
+ worktrees: join10(root2, PATH_NAMES.worktrees)
44528
44623
  };
44529
44624
  }
44530
44625
  function gitRuntimePaths(gitDir) {
44531
- const root2 = join9(gitDir, PATH_NAMES.gitRuntime);
44626
+ const root2 = join10(gitDir, PATH_NAMES.gitRuntime);
44532
44627
  return {
44533
44628
  root: root2,
44534
- meta: join9(root2, PATH_NAMES.worktreeMeta),
44535
- runtimeEnv: join9(root2, PATH_NAMES.runtimeEnv),
44536
- controlEnv: join9(root2, PATH_NAMES.controlEnv),
44537
- pullRequests: join9(root2, PATH_NAMES.pullRequests),
44538
- archiveState: join9(root2, PATH_NAMES.archiveState),
44539
- openSessionsState: join9(root2, PATH_NAMES.openSessionsState),
44540
- agentControl: join9(root2, RUNTIME_IDENTITY.agentControlBinary)
44629
+ meta: join10(root2, PATH_NAMES.worktreeMeta),
44630
+ runtimeEnv: join10(root2, PATH_NAMES.runtimeEnv),
44631
+ controlEnv: join10(root2, PATH_NAMES.controlEnv),
44632
+ pullRequests: join10(root2, PATH_NAMES.pullRequests),
44633
+ archiveState: join10(root2, PATH_NAMES.archiveState),
44634
+ openSessionsState: join10(root2, PATH_NAMES.openSessionsState),
44635
+ agentControl: join10(root2, RUNTIME_IDENTITY.agentControlBinary)
44541
44636
  };
44542
44637
  }
44543
44638
  var init_paths2 = __esm({
@@ -44549,29 +44644,29 @@ var init_paths2 = __esm({
44549
44644
 
44550
44645
  // ../host/src/token.ts
44551
44646
  import { randomBytes as randomBytes6 } from "node:crypto";
44552
- import { chmodSync as chmodSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync6 } from "node:fs";
44553
- import { dirname as dirname6, join as join10 } from "node:path";
44647
+ import { chmodSync as chmodSync6, mkdirSync as mkdirSync6, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync6 } from "node:fs";
44648
+ import { dirname as dirname6, join as join11 } from "node:path";
44554
44649
  function hostStateDir(root2) {
44555
- return join10(root2, HOST_STATE_DIR2);
44650
+ return join11(root2, HOST_STATE_DIR2);
44556
44651
  }
44557
44652
  function resolveHostStateDir(root2, env) {
44558
44653
  return env["PORTTA_HOST_STATE_DIR"]?.trim() || hostStateDir(root2);
44559
44654
  }
44560
44655
  function hostTokenFile(stateDir) {
44561
- return join10(stateDir, "token");
44656
+ return join11(stateDir, "token");
44562
44657
  }
44563
44658
  function newToken() {
44564
44659
  return randomBytes6(32).toString("base64url");
44565
44660
  }
44566
44661
  function readOrCreateToken(file2) {
44567
- mkdirSync5(dirname6(file2), { recursive: true, mode: 448 });
44662
+ mkdirSync6(dirname6(file2), { recursive: true, mode: 448 });
44568
44663
  try {
44569
44664
  writeFileSync6(file2, `${newToken()}
44570
44665
  `, { flag: "wx", mode: 384 });
44571
44666
  } catch (error61) {
44572
44667
  if (error61.code !== "EEXIST") throw error61;
44573
44668
  }
44574
- if ((statSync4(file2).mode & 63) !== 0) chmodSync5(file2, 384);
44669
+ if ((statSync4(file2).mode & 63) !== 0) chmodSync6(file2, 384);
44575
44670
  const token = readFileSync9(file2, "utf8").trim();
44576
44671
  if (token === "") throw new Error(`${file2} is empty; remove it and start the host daemon again`);
44577
44672
  return token;
@@ -44580,7 +44675,7 @@ var HOST_STATE_DIR2;
44580
44675
  var init_token = __esm({
44581
44676
  "../host/src/token.ts"() {
44582
44677
  "use strict";
44583
- HOST_STATE_DIR2 = join10("state", "host");
44678
+ HOST_STATE_DIR2 = join11("state", "host");
44584
44679
  }
44585
44680
  });
44586
44681
 
@@ -51924,7 +52019,6 @@ function parseWorktreeRoot(raw2, fallback) {
51924
52019
  if (isRecord2(raw2.worktrees) && typeof raw2.worktrees.root === "string" && raw2.worktrees.root.trim()) {
51925
52020
  return raw2.worktrees.root.trim();
51926
52021
  }
51927
- if (typeof raw2.worktreeRoot === "string" && raw2.worktreeRoot.trim()) return raw2.worktreeRoot.trim();
51928
52022
  return fallback;
51929
52023
  }
51930
52024
  function parseExposure(raw2) {
@@ -52036,18 +52130,15 @@ function parseProfile(raw2, fallbackRuntime) {
52036
52130
  ...typeof raw2.environment.cwd === "string" && raw2.environment.cwd.trim() ? { cwd: raw2.environment.cwd.trim() } : {},
52037
52131
  ...typeof raw2.environment.stopCommand === "string" && raw2.environment.stopCommand.trim() ? { stopCommand: raw2.environment.stopCommand.trim() } : {}
52038
52132
  } : void 0;
52039
- const legacyRuntimePane = environment && (environment.provider === "host" || environment.provider === "auto") && !environment.command ? panes.find((pane) => pane.id === "app" && pane.kind === "command" && Boolean(pane.command)) : void 0;
52040
- const effectiveEnvironment = legacyRuntimePane ? { ...environment, command: legacyRuntimePane.command } : environment;
52041
- const effectivePanes = legacyRuntimePane ? panes.filter((pane) => pane !== legacyRuntimePane) : panes;
52042
52133
  return {
52043
52134
  runtime: runtime2,
52044
52135
  envPassthrough,
52045
52136
  ...raw2.yolo === true ? { yolo: true } : {},
52046
- panes: effectivePanes,
52137
+ panes,
52047
52138
  ...typeof raw2.systemPrompt === "string" && raw2.systemPrompt.length > 0 ? { systemPrompt: raw2.systemPrompt } : {},
52048
52139
  ...image ? { image } : {},
52049
52140
  ...mounts ? { mounts } : {},
52050
- ...effectiveEnvironment && Object.keys(effectiveEnvironment).length > 0 ? { environment: effectiveEnvironment } : {}
52141
+ ...environment && Object.keys(environment).length > 0 ? { environment } : {}
52051
52142
  };
52052
52143
  }
52053
52144
  function parseProfiles(raw2, includeDefaultProfile) {
@@ -52210,12 +52301,6 @@ function parseLinearIntegration(parsed) {
52210
52301
  const defaults = DEFAULT_CONFIG.integrations.linear;
52211
52302
  const linear = isRecord2(parsed.integrations) && isRecord2(parsed.integrations.linear) ? parsed.integrations.linear : null;
52212
52303
  if (!linear) return { ...defaults };
52213
- if (typeof linear.teamId === "string" && !warnedLegacyLinearTeamId) {
52214
- warnedLegacyLinearTeamId = true;
52215
- log.warn(
52216
- "[config] integrations.linear.teamId is no longer used \u2014 the ticket team is now picked at creation time in the dashboard"
52217
- );
52218
- }
52219
52304
  const watchTeams = parseTeamKeyList(linear.watchTeams);
52220
52305
  return {
52221
52306
  enabled: typeof linear.enabled === "boolean" ? linear.enabled : defaults.enabled,
@@ -52436,14 +52521,13 @@ async function removeLocalCustomAgent(dir, agentId2) {
52436
52521
  function expandTemplate(template, env) {
52437
52522
  return template.replace(/\$\{(\w+)\}/g, (_, key) => env[key] ?? "");
52438
52523
  }
52439
- var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG, warnedLegacyLinearTeamId;
52524
+ var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG;
52440
52525
  var init_config5 = __esm({
52441
52526
  "../host/src/modules/taskflow/adapters/config.ts"() {
52442
52527
  "use strict";
52443
52528
  init_config2();
52444
52529
  init_paths2();
52445
52530
  import_yaml = __toESM(require_dist(), 1);
52446
- init_log2();
52447
52531
  DEFAULT_PANES = [
52448
52532
  { id: "agent", kind: "agent", focus: true },
52449
52533
  { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" }
@@ -52477,7 +52561,6 @@ var init_config5 = __esm({
52477
52561
  autoName: null,
52478
52562
  oneshot: { systemPrompt: DEFAULT_ONESHOT_SYSTEM_PROMPT() }
52479
52563
  };
52480
- warnedLegacyLinearTeamId = false;
52481
52564
  }
52482
52565
  });
52483
52566
 
@@ -52738,7 +52821,7 @@ var init_process_runner = __esm({
52738
52821
 
52739
52822
  // ../host/src/modules/taskflow/adapters/worktree-git-mount.ts
52740
52823
  import { access, readFile, realpath, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
52741
- import { basename as basename3, isAbsolute as isAbsolute2, join as join11, posix as posix3, relative, resolve as resolve3, sep } from "node:path";
52824
+ import { basename as basename3, isAbsolute as isAbsolute2, join as join12, posix as posix3, relative, resolve as resolve3, sep } from "node:path";
52742
52825
  function repairCommand(workspacePath) {
52743
52826
  return `git -C ${workspacePath} worktree repair --relative-paths`;
52744
52827
  }
@@ -52788,7 +52871,7 @@ function linkTarget(content) {
52788
52871
  return target.length > 0 ? target : null;
52789
52872
  }
52790
52873
  async function worktreeLink(workspacePath) {
52791
- const content = await readRaw(join11(workspacePath, ".git"));
52874
+ const content = await readRaw(join12(workspacePath, ".git"));
52792
52875
  return content === null ? null : linkTarget(content);
52793
52876
  }
52794
52877
  async function porttaOwned(runner, workspacePath, gitDir) {
@@ -52801,9 +52884,9 @@ async function porttaOwned(runner, workspacePath, gitDir) {
52801
52884
  return result.exit.code === 0 && result.stdout.trim().length > 0;
52802
52885
  }
52803
52886
  async function planRelativeRelink(workspacePath, dirs) {
52804
- const forwardPath = join11(workspacePath, ".git");
52805
- const backPath = join11(dirs.gitDir, BACK_LINK);
52806
- if (join11(dirs.commonDir, "worktrees", basename3(dirs.gitDir)) !== dirs.gitDir)
52887
+ const forwardPath = join12(workspacePath, ".git");
52888
+ const backPath = join12(dirs.gitDir, BACK_LINK);
52889
+ if (join12(dirs.commonDir, "worktrees", basename3(dirs.gitDir)) !== dirs.gitDir)
52807
52890
  return {
52808
52891
  ok: false,
52809
52892
  reason: `its Git dir ${dirs.gitDir} is not <common dir>/worktrees/<id> under ${dirs.commonDir}`
@@ -52864,7 +52947,7 @@ async function worktreeGitMountArgs(input2) {
52864
52947
  );
52865
52948
  }
52866
52949
  let link = await worktreeLink(workspacePath);
52867
- const backLink = await readRaw(join11(dirs.gitDir, BACK_LINK));
52950
+ const backLink = await readRaw(join12(dirs.gitDir, BACK_LINK));
52868
52951
  if (link !== null && isAbsolute2(link) || backLink !== null && isAbsolute2(backLink.trim())) {
52869
52952
  if (!await porttaOwned(runner, workspacePath, dirs.gitDir)) {
52870
52953
  throw new Error(
@@ -52920,7 +53003,7 @@ var init_worktree_git_mount = __esm({
52920
53003
  import { createHash as createHash5 } from "node:crypto";
52921
53004
  import { access as access2, readdir, readFile as readFile2 } from "node:fs/promises";
52922
53005
  import { createRequire } from "node:module";
52923
- import { dirname as dirname8, join as join12, relative as relative2, resolve as resolve4 } from "node:path";
53006
+ import { dirname as dirname8, join as join13, relative as relative2, resolve as resolve4 } from "node:path";
52924
53007
  function hash2(value3) {
52925
53008
  return createHash5("sha256").update(value3).digest("hex");
52926
53009
  }
@@ -52936,16 +53019,16 @@ async function exists2(path7) {
52936
53019
  }
52937
53020
  }
52938
53021
  async function findDevcontainerConfigs(workspacePath) {
52939
- const rootConfig = join12(workspacePath, ".devcontainer.json");
52940
- const directory = join12(workspacePath, ".devcontainer");
53022
+ const rootConfig = join13(workspacePath, ".devcontainer.json");
53023
+ const directory = join13(workspacePath, ".devcontainer");
52941
53024
  const configs = [];
52942
53025
  if (await exists2(rootConfig)) configs.push(rootConfig);
52943
- if (await exists2(join12(directory, "devcontainer.json"))) configs.push(join12(directory, "devcontainer.json"));
53026
+ if (await exists2(join13(directory, "devcontainer.json"))) configs.push(join13(directory, "devcontainer.json"));
52944
53027
  if (await exists2(directory)) {
52945
53028
  const entries = await readdir(directory, { withFileTypes: true });
52946
53029
  for (const entry of entries) {
52947
53030
  if (!entry.isDirectory()) continue;
52948
- const candidate = join12(directory, entry.name, "devcontainer.json");
53031
+ const candidate = join13(directory, entry.name, "devcontainer.json");
52949
53032
  if (await exists2(candidate)) configs.push(candidate);
52950
53033
  }
52951
53034
  }
@@ -53099,7 +53182,7 @@ var init_devcontainer_environment = __esm({
53099
53182
  }
53100
53183
  const packagePath = createRequire(import.meta.url).resolve("@devcontainers/cli/package.json");
53101
53184
  this.cli = process.execPath;
53102
- this.cliPrefix = [join12(dirname8(packagePath), "devcontainer.js")];
53185
+ this.cliPrefix = [join13(dirname8(packagePath), "devcontainer.js")];
53103
53186
  }
53104
53187
  args(args) {
53105
53188
  return [...this.cliPrefix, ...args];
@@ -53166,7 +53249,7 @@ var init_devcontainer_environment = __esm({
53166
53249
  this.workspaceMounts.set(config3, merged.workspaceMount);
53167
53250
  else this.workspaceMounts.delete(config3);
53168
53251
  const compose4 = await resolveComposeConfiguration(this.runner, config3, merged);
53169
- const lockfile = join12(dirname8(config3), "devcontainer-lock.json");
53252
+ const lockfile = join13(dirname8(config3), "devcontainer-lock.json");
53170
53253
  const lockfileExists = await exists2(lockfile);
53171
53254
  const lockfileContents = lockfileExists ? await readFile2(lockfile, "utf8") : "";
53172
53255
  return {
@@ -53433,11 +53516,11 @@ exec ${argv.join(" ")} "$cwd" ${quoteShell(executable2)} "$@"
53433
53516
 
53434
53517
  // ../host/src/modules/taskflow/adapters/dockerfile-environment.ts
53435
53518
  import { createHash as createHash6 } from "node:crypto";
53436
- import { existsSync as existsSync7, readFileSync as readFileSync11 } from "node:fs";
53519
+ import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
53437
53520
  import { resolve as resolve5 } from "node:path";
53438
53521
  function dockerfileFor(context) {
53439
53522
  const dockerfile = resolve5(context.workspacePath, context.configRef ?? "Dockerfile");
53440
- if (!existsSync7(dockerfile)) throw new Error(`Dockerfile does not exist: ${context.configRef ?? "Dockerfile"}`);
53523
+ if (!existsSync8(dockerfile)) throw new Error(`Dockerfile does not exist: ${context.configRef ?? "Dockerfile"}`);
53441
53524
  return dockerfile;
53442
53525
  }
53443
53526
  function imageTag(id) {
@@ -53472,10 +53555,10 @@ var init_dockerfile_environment = __esm({
53472
53555
  const dockerfile = resolve5(context.workspacePath, "Dockerfile");
53473
53556
  return {
53474
53557
  provider: this.id,
53475
- available: version3.exit.code === 0 && existsSync7(dockerfile),
53476
- configRefs: existsSync7(dockerfile) ? [dockerfile] : [],
53558
+ available: version3.exit.code === 0 && existsSync8(dockerfile),
53559
+ configRefs: existsSync8(dockerfile) ? [dockerfile] : [],
53477
53560
  ...version3.exit.code === 0 ? { version: version3.stdout.trim() } : {},
53478
- diagnostics: version3.exit.code === 0 ? existsSync7(dockerfile) ? [] : ["No Dockerfile was found"] : [version3.stderr.trim() || "Docker is unavailable"]
53561
+ diagnostics: version3.exit.code === 0 ? existsSync8(dockerfile) ? [] : ["No Dockerfile was found"] : [version3.stderr.trim() || "Docker is unavailable"]
53479
53562
  };
53480
53563
  }
53481
53564
  async resolve(context) {
@@ -53699,13 +53782,13 @@ var init_sqlite = __esm({
53699
53782
  });
53700
53783
 
53701
53784
  // ../host/src/modules/taskflow/adapters/environment-store.ts
53702
- import { mkdirSync as mkdirSync6 } from "node:fs";
53785
+ import { mkdirSync as mkdirSync7 } from "node:fs";
53703
53786
  import { dirname as dirname9 } from "node:path";
53704
53787
  function parseEnvironmentRecord(value3) {
53705
53788
  return environmentRecordSchema.parse(value3);
53706
53789
  }
53707
53790
  function createEnvironmentStore(path7) {
53708
- mkdirSync6(dirname9(path7), { recursive: true });
53791
+ mkdirSync7(dirname9(path7), { recursive: true });
53709
53792
  const database = openDatabase(path7);
53710
53793
  database.pragma("journal_mode = WAL");
53711
53794
  database.exec(`
@@ -53944,7 +54027,7 @@ exec ${JSON.stringify(executable2)} "$@"
53944
54027
  });
53945
54028
 
53946
54029
  // ../host/src/modules/taskflow/adapters/projects-registry.ts
53947
- import { mkdirSync as mkdirSync7, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "node:fs";
54030
+ import { mkdirSync as mkdirSync8, readFileSync as readFileSync12, renameSync as renameSync3, writeFileSync as writeFileSync7 } from "node:fs";
53948
54031
  import { dirname as dirname10 } from "node:path";
53949
54032
  function defaultRegistryFile() {
53950
54033
  return globalPaths().projectsRegistry;
@@ -53968,7 +54051,7 @@ function createProjectsRegistry(file2 = defaultRegistryFile()) {
53968
54051
  return parsed.filter(isProjectEntry);
53969
54052
  }
53970
54053
  function write4(entries) {
53971
- mkdirSync7(dirname10(file2), { recursive: true });
54054
+ mkdirSync8(dirname10(file2), { recursive: true });
53972
54055
  const tmpPath = `${file2}.${process.pid}.${Date.now()}.tmp`;
53973
54056
  writeFileSync7(tmpPath, `${JSON.stringify(entries, null, 2)}
53974
54057
  `);
@@ -54682,20 +54765,20 @@ var init_tmux = __esm({
54682
54765
  });
54683
54766
 
54684
54767
  // ../host/src/modules/taskflow/assets.ts
54685
- import { existsSync as existsSync8 } from "node:fs";
54686
- import { join as join13, resolve as resolve7 } from "node:path";
54768
+ import { existsSync as existsSync9 } from "node:fs";
54769
+ import { join as join14, resolve as resolve7 } from "node:path";
54687
54770
  function taskflowAssets(env = process.env, directory = import.meta.dirname) {
54688
- const bundled = join13(directory, "assets");
54689
- if (existsSync8(join13(bundled, "workflows"))) {
54771
+ const bundled = join14(directory, "assets");
54772
+ if (existsSync9(join14(bundled, "workflows"))) {
54690
54773
  return {
54691
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(bundled, "workflows"),
54692
- workflowSkill: join13(bundled, "skills", "portta-workflows", "SKILL.md")
54774
+ workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join14(bundled, "workflows"),
54775
+ workflowSkill: join14(bundled, "skills", "portta-workflows", "SKILL.md")
54693
54776
  };
54694
54777
  }
54695
54778
  const repository = resolve7(directory, "../../../../..");
54696
54779
  return {
54697
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(repository, "packages", "host", "workflows"),
54698
- workflowSkill: join13(repository, "skills", "portta-workflows", "SKILL.md")
54780
+ workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join14(repository, "packages", "host", "workflows"),
54781
+ workflowSkill: join14(repository, "skills", "portta-workflows", "SKILL.md")
54699
54782
  };
54700
54783
  }
54701
54784
  var init_assets = __esm({
@@ -54914,7 +54997,7 @@ var init_environment_service_discovery = __esm({
54914
54997
  // ../host/src/modules/taskflow/adapters/git.ts
54915
54998
  import { spawnSync as spawnSync5 } from "node:child_process";
54916
54999
  import { readdirSync as readdirSync2, realpathSync as realpathSync2, rmSync, statSync as statSync5 } from "node:fs";
54917
- import { basename as basename5, dirname as dirname11, join as join14, resolve as resolve8 } from "node:path";
55000
+ import { basename as basename5, dirname as dirname11, join as join15, resolve as resolve8 } from "node:path";
54918
55001
  function canonicalizeFsPath(input2) {
54919
55002
  const resolved2 = resolve8(input2);
54920
55003
  try {
@@ -54926,7 +55009,7 @@ function canonicalizeFsPath(input2) {
54926
55009
  missing.unshift(basename5(current));
54927
55010
  current = dirname11(current);
54928
55011
  try {
54929
- return join14(realpathSync2(current), ...missing);
55012
+ return join15(realpathSync2(current), ...missing);
54930
55013
  } catch {
54931
55014
  }
54932
55015
  }
@@ -55018,7 +55101,7 @@ function resolveRepoRoot(dir) {
55018
55101
  return null;
55019
55102
  }
55020
55103
  for (const entry of entries) {
55021
- const child = join14(dir, entry);
55104
+ const child = join15(dir, entry);
55022
55105
  try {
55023
55106
  if (!statSync5(child).isDirectory()) continue;
55024
55107
  } catch {
@@ -55952,7 +56035,7 @@ var init_herdr = __esm({
55952
56035
 
55953
56036
  // ../host/src/modules/taskflow/adapters/hooks.ts
55954
56037
  import { access as access3 } from "node:fs/promises";
55955
- import { join as join15 } from "node:path";
56038
+ import { join as join16 } from "node:path";
55956
56039
  function buildErrorMessage(name, exitCode, stdout2, stderr2) {
55957
56040
  const output2 = stderr2.trim() || stdout2.trim();
55958
56041
  if (output2) {
@@ -56003,7 +56086,7 @@ var init_hooks = __esm({
56003
56086
  }
56004
56087
  async hasEnvrc(cwd) {
56005
56088
  try {
56006
- await access3(join15(cwd, ".envrc"));
56089
+ await access3(join16(cwd, ".envrc"));
56007
56090
  return true;
56008
56091
  } catch {
56009
56092
  return false;
@@ -56102,7 +56185,7 @@ var init_type_guards = __esm({
56102
56185
 
56103
56186
  // ../host/src/modules/taskflow/adapters/claude-cli.ts
56104
56187
  import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
56105
- import { basename as basename6, join as join16 } from "node:path";
56188
+ import { basename as basename6, join as join17 } from "node:path";
56106
56189
  function isRecord5(raw2) {
56107
56190
  return typeof raw2 === "object" && raw2 !== null && !Array.isArray(raw2);
56108
56191
  }
@@ -56285,19 +56368,19 @@ function readClaudeProjectsRoot() {
56285
56368
  if (!home2) {
56286
56369
  throw new Error("HOME is required to resolve Claude sessions");
56287
56370
  }
56288
- return join16(home2, ".claude", "projects");
56371
+ return join17(home2, ".claude", "projects");
56289
56372
  }
56290
56373
  async function listJsonlFiles(dir) {
56291
56374
  try {
56292
56375
  const entries = await readdir2(dir, { withFileTypes: true });
56293
- return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => join16(dir, entry.name));
56376
+ return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".jsonl")).map((entry) => join17(dir, entry.name));
56294
56377
  } catch {
56295
56378
  return [];
56296
56379
  }
56297
56380
  }
56298
56381
  async function findClaudeSessionPath(sessionId, cwd) {
56299
56382
  const projectsRoot = readClaudeProjectsRoot();
56300
- const primaryPath = join16(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56383
+ const primaryPath = join17(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56301
56384
  try {
56302
56385
  await stat2(primaryPath);
56303
56386
  return primaryPath;
@@ -56306,7 +56389,7 @@ async function findClaudeSessionPath(sessionId, cwd) {
56306
56389
  const projectDirs2 = await readdir2(projectsRoot, { withFileTypes: true }).catch(() => []);
56307
56390
  for (const entry of projectDirs2) {
56308
56391
  if (!entry.isDirectory()) continue;
56309
- const candidate = join16(projectsRoot, entry.name, `${sessionId}.jsonl`);
56392
+ const candidate = join17(projectsRoot, entry.name, `${sessionId}.jsonl`);
56310
56393
  try {
56311
56394
  await stat2(candidate);
56312
56395
  return candidate;
@@ -56449,7 +56532,7 @@ var init_claude_cli = __esm({
56449
56532
  }
56450
56533
  async listSessions(cwd) {
56451
56534
  const projectsRoot = readClaudeProjectsRoot();
56452
- const primaryDir = join16(projectsRoot, encodeClaudeProjectDir(cwd));
56535
+ const primaryDir = join17(projectsRoot, encodeClaudeProjectDir(cwd));
56453
56536
  const primaryFiles = await listJsonlFiles(primaryDir);
56454
56537
  if (primaryFiles.length > 0) {
56455
56538
  return await this.summarizeSessionFiles(primaryFiles, cwd);
@@ -56458,7 +56541,7 @@ var init_claude_cli = __esm({
56458
56541
  const matchedFiles = [];
56459
56542
  for (const entry of projectDirs2) {
56460
56543
  if (!entry.isDirectory()) continue;
56461
- const files = await listJsonlFiles(join16(projectsRoot, entry.name));
56544
+ const files = await listJsonlFiles(join17(projectsRoot, entry.name));
56462
56545
  for (const filePath of files) {
56463
56546
  const session = await this.readSessionFile(filePath);
56464
56547
  if (session?.cwd === cwd) {
@@ -56637,7 +56720,7 @@ var init_claude_cli = __esm({
56637
56720
 
56638
56721
  // ../host/src/modules/taskflow/adapters/session-discovery.ts
56639
56722
  import { open as open2, readdir as readdir3, stat as stat3 } from "node:fs/promises";
56640
- import { basename as basename7, join as join17 } from "node:path";
56723
+ import { basename as basename7, join as join18 } from "node:path";
56641
56724
  import { setTimeout as sleep3 } from "node:timers/promises";
56642
56725
  function home() {
56643
56726
  const value3 = process.env.HOME;
@@ -56648,11 +56731,11 @@ function newestFirst(sessions3) {
56648
56731
  return sessions3.sort((left, right) => right.mtimeMs - left.mtimeMs).map((entry) => entry.sessionId);
56649
56732
  }
56650
56733
  async function listClaudeSessionIds(cwd) {
56651
- const dir = join17(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56734
+ const dir = join18(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56652
56735
  const names = await readdir3(dir).catch(() => []);
56653
56736
  const stamped = await Promise.all(
56654
56737
  names.filter((name) => name.endsWith(".jsonl")).map(async (name) => {
56655
- const info = await stat3(join17(dir, name)).catch(() => null);
56738
+ const info = await stat3(join18(dir, name)).catch(() => null);
56656
56739
  return info ? { sessionId: basename7(name, ".jsonl"), mtimeMs: info.mtimeMs } : null;
56657
56740
  })
56658
56741
  );
@@ -56688,7 +56771,7 @@ async function readCodexSessionCwdId(path7) {
56688
56771
  }
56689
56772
  }
56690
56773
  async function listCodexSessionIds(cwd) {
56691
- const root2 = join17(home(), ".codex", "sessions");
56774
+ const root2 = join18(home(), ".codex", "sessions");
56692
56775
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56693
56776
  const rollouts = relPaths.filter((rel) => {
56694
56777
  const name = basename7(rel);
@@ -56696,7 +56779,7 @@ async function listCodexSessionIds(cwd) {
56696
56779
  });
56697
56780
  const stamped = await Promise.all(
56698
56781
  rollouts.map(async (rel) => {
56699
- const path7 = join17(root2, rel);
56782
+ const path7 = join18(root2, rel);
56700
56783
  const meta3 = await readCodexSessionCwdId(path7);
56701
56784
  if (!meta3 || meta3.cwd !== cwd) return null;
56702
56785
  const info = await stat3(path7).catch(() => null);
@@ -56706,11 +56789,11 @@ async function listCodexSessionIds(cwd) {
56706
56789
  return newestFirst(stamped.filter((entry) => entry !== null));
56707
56790
  }
56708
56791
  async function findCodexSessionPath(sessionId, cwd) {
56709
- const root2 = join17(home(), ".codex", "sessions");
56792
+ const root2 = join18(home(), ".codex", "sessions");
56710
56793
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56711
56794
  for (const rel of relPaths) {
56712
56795
  if (!basename7(rel).endsWith(`${sessionId}.jsonl`)) continue;
56713
- const path7 = join17(root2, rel);
56796
+ const path7 = join18(root2, rel);
56714
56797
  const meta3 = await readCodexSessionCwdId(path7);
56715
56798
  if (meta3?.id === sessionId && meta3.cwd === cwd) return path7;
56716
56799
  }
@@ -56800,7 +56883,7 @@ var init_session_discovery = __esm({
56800
56883
 
56801
56884
  // ../host/src/modules/taskflow/adapters/fs.ts
56802
56885
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
56803
- import { join as join18 } from "node:path";
56886
+ import { join as join19 } from "node:path";
56804
56887
  function stringifyAllocatedPorts(ports) {
56805
56888
  const entries = Object.entries(ports).map(([key, value3]) => [key, String(value3)]);
56806
56889
  return Object.fromEntries(entries);
@@ -56829,7 +56912,7 @@ function parseDotenv(content) {
56829
56912
  }
56830
56913
  async function loadDotenvLocal(worktreePath) {
56831
56914
  try {
56832
- const content = await readFile4(join18(worktreePath, ".env.local"), "utf8");
56915
+ const content = await readFile4(join19(worktreePath, ".env.local"), "utf8");
56833
56916
  return parseDotenv(content);
56834
56917
  } catch {
56835
56918
  return {};
@@ -56970,25 +57053,21 @@ function isRecord6(raw2) {
56970
57053
  function normalizeConversationMeta(raw2) {
56971
57054
  if (!raw2) return raw2;
56972
57055
  if (raw2.provider === "codexAppServer") {
56973
- const conversationId2 = raw2.conversationId || raw2.threadId;
56974
- const threadId = raw2.threadId || raw2.conversationId;
56975
- if (!conversationId2 || !threadId) return void 0;
57056
+ if (!raw2.conversationId || !raw2.threadId) return void 0;
56976
57057
  const normalized2 = {
56977
57058
  provider: "codexAppServer",
56978
- conversationId: conversationId2,
56979
- threadId,
57059
+ conversationId: raw2.conversationId,
57060
+ threadId: raw2.threadId,
56980
57061
  cwd: raw2.cwd,
56981
57062
  lastSeenAt: raw2.lastSeenAt
56982
57063
  };
56983
57064
  return normalized2;
56984
57065
  }
56985
- const conversationId = raw2.conversationId || raw2.sessionId;
56986
- const sessionId = raw2.sessionId || raw2.conversationId;
56987
- if (!conversationId || !sessionId) return void 0;
57066
+ if (!raw2.conversationId || !raw2.sessionId) return void 0;
56988
57067
  const normalized = {
56989
57068
  provider: "claudeCode",
56990
- conversationId,
56991
- sessionId,
57069
+ conversationId: raw2.conversationId,
57070
+ sessionId: raw2.sessionId,
56992
57071
  cwd: raw2.cwd,
56993
57072
  lastSeenAt: raw2.lastSeenAt
56994
57073
  };
@@ -57418,7 +57497,7 @@ ${stderr2}`;
57418
57497
 
57419
57498
  // ../host/src/modules/taskflow/adapters/agent-runtime.ts
57420
57499
  import { chmod, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
57421
- import { dirname as dirname12, join as join19, resolve as resolve10 } from "node:path";
57500
+ import { dirname as dirname12, join as join20, resolve as resolve10 } from "node:path";
57422
57501
  function shellQuote(value3) {
57423
57502
  return `'${value3.replaceAll("'", "'\\''")}'`;
57424
57503
  }
@@ -57871,7 +57950,7 @@ async function mergeCodexHooksFile(hooksPath, hookSettings, agentCtlPath) {
57871
57950
  }
57872
57951
  async function resolveGitCommonDir(gitDir) {
57873
57952
  try {
57874
- const commonDir = (await readFile5(join19(gitDir, "commondir"), "utf8")).trim();
57953
+ const commonDir = (await readFile5(join20(gitDir, "commondir"), "utf8")).trim();
57875
57954
  if (!commonDir) return gitDir;
57876
57955
  return commonDir.startsWith("/") ? commonDir : resolve10(gitDir, commonDir);
57877
57956
  } catch {
@@ -57880,7 +57959,7 @@ async function resolveGitCommonDir(gitDir) {
57880
57959
  }
57881
57960
  async function ensureGeneratedAgentFilesIgnored(gitDir) {
57882
57961
  const commonDir = await resolveGitCommonDir(gitDir);
57883
- const excludePath = join19(commonDir, "info", "exclude");
57962
+ const excludePath = join20(commonDir, "info", "exclude");
57884
57963
  let existing = "";
57885
57964
  try {
57886
57965
  existing = await readFile5(excludePath, "utf8");
@@ -57898,9 +57977,9 @@ async function ensureGeneratedAgentFilesIgnored(gitDir) {
57898
57977
  async function ensureAgentRuntimeArtifacts(input2) {
57899
57978
  const storagePaths = getWorktreeStoragePaths(input2.gitDir);
57900
57979
  const artifacts = {
57901
- agentCtlPath: join19(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
57902
- claudeSettingsPath: join19(input2.worktreePath, ".claude", "settings.local.json"),
57903
- codexHooksPath: join19(input2.worktreePath, ".codex", "hooks.json")
57980
+ agentCtlPath: join20(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
57981
+ claudeSettingsPath: join20(input2.worktreePath, ".claude", "settings.local.json"),
57982
+ codexHooksPath: join20(input2.worktreePath, ".codex", "hooks.json")
57904
57983
  };
57905
57984
  await mkdir3(dirname12(artifacts.claudeSettingsPath), { recursive: true });
57906
57985
  await mkdir3(dirname12(artifacts.codexHooksPath), { recursive: true });
@@ -58044,7 +58123,7 @@ var init_agent_registry = __esm({
58044
58123
  });
58045
58124
 
58046
58125
  // ../host/src/modules/taskflow/services/agent-service.ts
58047
- import { dirname as dirname13, join as join20 } from "node:path";
58126
+ import { dirname as dirname13, join as join21 } from "node:path";
58048
58127
  function quoteShell3(value3) {
58049
58128
  return `'${value3.replaceAll("'", "'\\''")}'`;
58050
58129
  }
@@ -58056,7 +58135,7 @@ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
58056
58135
  }
58057
58136
  function buildCodexNotifyFlag(runtimeEnvPath) {
58058
58137
  if (!runtimeEnvPath) return "";
58059
- const agentCtlPath = join20(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
58138
+ const agentCtlPath = join21(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
58060
58139
  return ` -c ${quoteShell3(`notify=${JSON.stringify([agentCtlPath, "codex-notify"])}`)}`;
58061
58140
  }
58062
58141
  function buildBuiltInAgentInvocation(input2) {
@@ -59521,10 +59600,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59521
59600
  return panes.length > 0 ? panes : [{ id: "runtime", kind: "runtime", cwd: "worktree" }];
59522
59601
  }
59523
59602
  if (panes.some((pane) => pane.kind === "runtime")) return panes;
59524
- const legacyShell = panes.findIndex((pane) => pane.id === "shell" && pane.kind === "shell");
59525
- const runtimePane = { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" };
59526
- if (legacyShell >= 0) panes.splice(legacyShell, 1, runtimePane);
59527
- else panes.push(runtimePane);
59603
+ panes.push({ id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" });
59528
59604
  return panes;
59529
59605
  }
59530
59606
  requireDockerProfile(profile) {
@@ -60476,7 +60552,6 @@ var DEFAULT_TERMINAL_TTL_MS, ProjectInitTracker;
60476
60552
  var init_project_init_service = __esm({
60477
60553
  "../host/src/modules/taskflow/services/project-init-service.ts"() {
60478
60554
  "use strict";
60479
- init_log2();
60480
60555
  DEFAULT_TERMINAL_TTL_MS = 6e4;
60481
60556
  ProjectInitTracker = class {
60482
60557
  inits = /* @__PURE__ */ new Map();
@@ -69089,10 +69164,10 @@ var init_native_terminal_service = __esm({
69089
69164
  });
69090
69165
 
69091
69166
  // ../host/src/modules/taskflow/server/routes/worktrees.ts
69092
- import { mkdirSync as mkdirSync8 } from "node:fs";
69167
+ import { mkdirSync as mkdirSync9 } from "node:fs";
69093
69168
  import { writeFile as writeFile6 } from "node:fs/promises";
69094
69169
  import { tmpdir } from "node:os";
69095
- import { join as join21, resolve as resolve16 } from "node:path";
69170
+ import { join as join22, resolve as resolve16 } from "node:path";
69096
69171
  async function apiGetNativeTerminalLaunch(project2, branch) {
69097
69172
  touchDashboardActivity();
69098
69173
  project2.ensureBranchNotBusy(branch);
@@ -69426,8 +69501,8 @@ async function apiUploadFiles(project2, name, req) {
69426
69501
  }
69427
69502
  const entries = formData.getAll("files");
69428
69503
  if (entries.length === 0) return errorResponse("No files provided", 400);
69429
- const uploadDir = join21(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69430
- mkdirSync8(uploadDir, { recursive: true });
69504
+ const uploadDir = join22(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69505
+ mkdirSync9(uploadDir, { recursive: true });
69431
69506
  const results = [];
69432
69507
  for (const entry of entries) {
69433
69508
  if (!(entry instanceof File)) continue;
@@ -69438,7 +69513,7 @@ async function apiUploadFiles(project2, name, req) {
69438
69513
  return errorResponse(`File too large: ${entry.name} (max 10MB)`, 400);
69439
69514
  }
69440
69515
  const safeName = `${Date.now()}_${sanitizeFilename(entry.name)}`;
69441
- const destPath = join21(uploadDir, safeName);
69516
+ const destPath = join22(uploadDir, safeName);
69442
69517
  if (!resolve16(destPath).startsWith(`${uploadDir}/`)) {
69443
69518
  return errorResponse("Invalid filename", 400);
69444
69519
  }
@@ -70174,7 +70249,7 @@ var init_codex_app_server = __esm({
70174
70249
  });
70175
70250
 
70176
70251
  // ../host/src/modules/taskflow/adapters/run-store.ts
70177
- import { mkdirSync as mkdirSync9 } from "node:fs";
70252
+ import { mkdirSync as mkdirSync10 } from "node:fs";
70178
70253
  import { dirname as dirname15 } from "node:path";
70179
70254
  function defaultRunStorePath() {
70180
70255
  return globalPaths().database;
@@ -70335,7 +70410,7 @@ function isConstraint(error61, target) {
70335
70410
  return error61 instanceof Error && error61.message.includes(target);
70336
70411
  }
70337
70412
  function createRunStore(path7 = defaultRunStorePath()) {
70338
- mkdirSync9(dirname15(path7), { recursive: true });
70413
+ mkdirSync10(dirname15(path7), { recursive: true });
70339
70414
  const database = openDatabase(path7);
70340
70415
  database.pragma("foreign_keys = ON");
70341
70416
  database.pragma("journal_mode = WAL");
@@ -70755,10 +70830,15 @@ var init_run_store = __esm({
70755
70830
  input_json TEXT NOT NULL,
70756
70831
  status TEXT NOT NULL CHECK(status IN ('queued', 'provisioning', 'running', 'waiting_input', 'completed', 'failed', 'cancelled', 'interrupted')),
70757
70832
  workspace_policy TEXT NOT NULL CHECK(workspace_policy IN ('none', 'run')),
70833
+ workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch')),
70834
+ workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write')),
70758
70835
  workflow_snapshot_id TEXT,
70759
70836
  workspace_id TEXT,
70760
70837
  worktree_path TEXT,
70761
70838
  canonical_workspace_path TEXT,
70839
+ checkout_canonical_path TEXT,
70840
+ checkout_branch TEXT,
70841
+ environment_id TEXT,
70762
70842
  branch TEXT,
70763
70843
  base_branch TEXT,
70764
70844
  base_commit TEXT,
@@ -70786,6 +70866,7 @@ var init_run_store = __esm({
70786
70866
  path TEXT NOT NULL,
70787
70867
  content_hash TEXT NOT NULL,
70788
70868
  engine_version TEXT NOT NULL,
70869
+ key_version TEXT NOT NULL DEFAULT 'v1',
70789
70870
  source TEXT NOT NULL,
70790
70871
  metadata_json TEXT NOT NULL,
70791
70872
  created_at TEXT NOT NULL
@@ -70810,6 +70891,7 @@ var init_run_store = __esm({
70810
70891
  error TEXT,
70811
70892
  session_id TEXT,
70812
70893
  capabilities_json TEXT,
70894
+ checkpoint_json TEXT,
70813
70895
  started_at TEXT,
70814
70896
  completed_at TEXT,
70815
70897
  UNIQUE(run_id, node_key, attempt)
@@ -70821,10 +70903,7 @@ var init_run_store = __esm({
70821
70903
  source TEXT NOT NULL,
70822
70904
  updated_at TEXT NOT NULL
70823
70905
  );
70824
- `,
70825
- "ALTER TABLE executions ADD COLUMN checkpoint_json TEXT;",
70826
- "ALTER TABLE workflow_snapshots ADD COLUMN key_version TEXT NOT NULL DEFAULT 'v1';",
70827
- `
70906
+
70828
70907
  CREATE TABLE IF NOT EXISTS run_events (
70829
70908
  id TEXT PRIMARY KEY,
70830
70909
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70837,8 +70916,7 @@ var init_run_store = __esm({
70837
70916
  payload_json TEXT NOT NULL,
70838
70917
  UNIQUE(run_id, sequence)
70839
70918
  );
70840
- `,
70841
- `
70919
+
70842
70920
  CREATE TABLE IF NOT EXISTS workspace_leases (
70843
70921
  id TEXT PRIMARY KEY,
70844
70922
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70856,12 +70934,7 @@ var init_run_store = __esm({
70856
70934
  updated_at TEXT NOT NULL,
70857
70935
  released_at TEXT
70858
70936
  );
70859
- `,
70860
- "ALTER TABLE runs ADD COLUMN workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch'));",
70861
- "ALTER TABLE runs ADD COLUMN workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write'));",
70862
- "ALTER TABLE runs ADD COLUMN checkout_canonical_path TEXT;",
70863
- "ALTER TABLE runs ADD COLUMN checkout_branch TEXT;",
70864
- `
70937
+
70865
70938
  CREATE TABLE IF NOT EXISTS checkout_claims (
70866
70939
  run_id TEXT PRIMARY KEY REFERENCES runs(id),
70867
70940
  project_id TEXT NOT NULL,
@@ -70870,8 +70943,7 @@ var init_run_store = __esm({
70870
70943
  created_at TEXT NOT NULL
70871
70944
  );
70872
70945
  CREATE INDEX IF NOT EXISTS checkout_claims_path_idx ON checkout_claims(project_id, canonical_path);
70873
- `,
70874
- "ALTER TABLE runs ADD COLUMN environment_id TEXT;"
70946
+ `
70875
70947
  ];
70876
70948
  }
70877
70949
  });
@@ -71124,26 +71196,26 @@ var init_types2 = __esm({
71124
71196
  });
71125
71197
 
71126
71198
  // ../host/src/modules/taskflow/workflows/runtime/journal.ts
71127
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
71128
- import { dirname as dirname16, join as join22 } from "node:path";
71199
+ import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync11, readdirSync as readdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
71200
+ import { dirname as dirname16, join as join23 } from "node:path";
71129
71201
  function dataRoot(roots = {}) {
71130
71202
  return roots.dataRoot ?? globalPaths().root;
71131
71203
  }
71132
71204
  function runDir(runId, roots = {}) {
71133
- return join22(dataRoot(roots), "runs", runId);
71205
+ return join23(dataRoot(roots), "runs", runId);
71134
71206
  }
71135
71207
  function journalPath(runId, roots = {}) {
71136
- return join22(runDir(runId, roots), "journal.jsonl");
71208
+ return join23(runDir(runId, roots), "journal.jsonl");
71137
71209
  }
71138
71210
  function ensureRunDir(runId, roots = {}) {
71139
71211
  const dir = runDir(runId, roots);
71140
- mkdirSync10(dir, { recursive: true });
71212
+ mkdirSync11(dir, { recursive: true });
71141
71213
  return dir;
71142
71214
  }
71143
71215
  function listRunIds(roots = {}) {
71144
- const dir = join22(dataRoot(roots), "runs");
71145
- if (!existsSync9(dir)) return [];
71146
- return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync9(join22(dir, e.name, "journal.jsonl"))).map((e) => e.name).sort().reverse();
71216
+ const dir = join23(dataRoot(roots), "runs");
71217
+ if (!existsSync10(dir)) return [];
71218
+ return readdirSync3(dir, { withFileTypes: true }).filter((e) => e.isDirectory() && existsSync10(join23(dir, e.name, "journal.jsonl"))).map((e) => e.name).sort().reverse();
71147
71219
  }
71148
71220
  function checkResumePreconditions(meta3, current) {
71149
71221
  if (!meta3) return;
@@ -71169,7 +71241,7 @@ function canonicalArgs(value3) {
71169
71241
  }
71170
71242
  function writeResult(runId, value3, roots = {}) {
71171
71243
  const dir = ensureRunDir(runId, roots);
71172
- writeFileSync8(join22(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71244
+ writeFileSync8(join23(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71173
71245
  }
71174
71246
  var JournalNotFoundError, ResumePreconditionError, Journal;
71175
71247
  var init_journal = __esm({
@@ -71197,7 +71269,7 @@ var init_journal = __esm({
71197
71269
  path;
71198
71270
  constructor(runId, roots = {}) {
71199
71271
  this.path = journalPath(runId, roots);
71200
- mkdirSync10(dirname16(this.path), { recursive: true });
71272
+ mkdirSync11(dirname16(this.path), { recursive: true });
71201
71273
  }
71202
71274
  append(entry) {
71203
71275
  appendFileSync2(this.path, `${JSON.stringify(entry)}
@@ -71205,12 +71277,12 @@ var init_journal = __esm({
71205
71277
  }
71206
71278
  /** True if a journal file exists for this run id (vs. a typo'd / absent run). */
71207
71279
  static exists(runId, roots = {}) {
71208
- return existsSync9(journalPath(runId, roots));
71280
+ return existsSync10(journalPath(runId, roots));
71209
71281
  }
71210
71282
  static load(runId, roots = {}) {
71211
71283
  const path7 = journalPath(runId, roots);
71212
71284
  const out = { results: /* @__PURE__ */ new Map(), indexByKey: /* @__PURE__ */ new Map() };
71213
- if (!existsSync9(path7)) return out;
71285
+ if (!existsSync10(path7)) return out;
71214
71286
  const text = readFileSync13(path7, "utf8");
71215
71287
  for (const line4 of text.split("\n")) {
71216
71288
  const trimmed = line4.trim();
@@ -71613,9 +71685,9 @@ var init_sandbox = __esm({
71613
71685
  });
71614
71686
 
71615
71687
  // ../host/src/modules/taskflow/workflows/runtime/registry.ts
71616
- import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync6 } from "node:fs";
71688
+ import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync14, statSync as statSync6 } from "node:fs";
71617
71689
  import { homedir as homedir4 } from "node:os";
71618
- import { dirname as dirname17, join as join23, resolve as resolve17 } from "node:path";
71690
+ import { dirname as dirname17, join as join24, resolve as resolve17 } from "node:path";
71619
71691
  import { fileURLToPath as fileURLToPath4 } from "node:url";
71620
71692
  function builtinDir() {
71621
71693
  const here = dirname17(fileURLToPath4(import.meta.url));
@@ -71624,10 +71696,10 @@ function builtinDir() {
71624
71696
  ["..", "..", "builtins"],
71625
71697
  ["..", "..", "..", "..", "..", "workflows"]
71626
71698
  ]) {
71627
- const candidate = join23(here, ...rel);
71628
- if (existsSync10(candidate)) return candidate;
71699
+ const candidate = join24(here, ...rel);
71700
+ if (existsSync11(candidate)) return candidate;
71629
71701
  }
71630
- return join23(here, "..", "builtins");
71702
+ return join24(here, "..", "builtins");
71631
71703
  }
71632
71704
  function projectDirs(cwd) {
71633
71705
  const dirs = [];
@@ -71635,8 +71707,8 @@ function projectDirs(cwd) {
71635
71707
  let dir = resolve17(cwd);
71636
71708
  for (; ; ) {
71637
71709
  const workflows = projectPaths(dir).workflows;
71638
- if (existsSync10(workflows)) dirs.push(workflows);
71639
- if (existsSync10(join23(dir, ".git"))) break;
71710
+ if (existsSync11(workflows)) dirs.push(workflows);
71711
+ if (existsSync11(join24(dir, ".git"))) break;
71640
71712
  const parent = dirname17(dir);
71641
71713
  if (dir === home2 || parent === dir) break;
71642
71714
  dir = parent;
@@ -71650,7 +71722,7 @@ function workflowDirs(cwd, roots) {
71650
71722
  tier: "project",
71651
71723
  dir: resolve17(dir)
71652
71724
  })),
71653
- { tier: "user", dir: roots.globalDir ?? join23(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71725
+ { tier: "user", dir: roots.globalDir ?? join24(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71654
71726
  { tier: "builtin", dir: roots.builtinDir ?? builtinDir() }
71655
71727
  ];
71656
71728
  }
@@ -71670,7 +71742,7 @@ function scanDir(tier, dir) {
71670
71742
  const entries = [];
71671
71743
  for (const file2 of names) {
71672
71744
  if (!file2.endsWith(".js")) continue;
71673
- const filePath = join23(dir, file2);
71745
+ const filePath = join24(dir, file2);
71674
71746
  try {
71675
71747
  if (statSync6(filePath).size > MAX_WORKFLOW_BYTES) continue;
71676
71748
  const { meta: meta3 } = parseWorkflow(readFileSync14(filePath, "utf8"));
@@ -78730,7 +78802,7 @@ var init_schema = __esm({
78730
78802
  // ../host/src/modules/taskflow/workflows/worker/claude.ts
78731
78803
  import { readlinkSync, realpathSync as realpathSync3 } from "node:fs";
78732
78804
  import { homedir as homedir5 } from "node:os";
78733
- import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute3, join as join24, relative as relative4, resolve as resolve18 } from "node:path";
78805
+ import { basename as basename9, dirname as dirname18, isAbsolute as isAbsolute3, join as join25, relative as relative4, resolve as resolve18 } from "node:path";
78734
78806
  function toClaudeEffort(effort) {
78735
78807
  return effort === "none" || effort === "minimal" ? "low" : effort;
78736
78808
  }
@@ -78769,7 +78841,7 @@ function realpathUpward(p) {
78769
78841
  for (let hops = 0; hops < 40; hops++) {
78770
78842
  try {
78771
78843
  const real = realpathSync3(existing);
78772
- return suffix ? join24(real, suffix) : real;
78844
+ return suffix ? join25(real, suffix) : real;
78773
78845
  } catch {
78774
78846
  }
78775
78847
  try {
@@ -78780,7 +78852,7 @@ function realpathUpward(p) {
78780
78852
  }
78781
78853
  const parent = dirname18(existing);
78782
78854
  if (parent === existing) return p;
78783
- suffix = suffix ? join24(basename9(existing), suffix) : basename9(existing);
78855
+ suffix = suffix ? join25(basename9(existing), suffix) : basename9(existing);
78784
78856
  existing = parent;
78785
78857
  }
78786
78858
  return p;
@@ -78874,7 +78946,7 @@ function unquote(s) {
78874
78946
  }
78875
78947
  function expandHome(p) {
78876
78948
  if (p === "~") return homedir5();
78877
- if (p.startsWith("~/")) return join24(homedir5(), p.slice(2));
78949
+ if (p.startsWith("~/")) return join25(homedir5(), p.slice(2));
78878
78950
  return p;
78879
78951
  }
78880
78952
  function usageFromResult(last) {
@@ -79506,7 +79578,7 @@ ${tail}` : message;
79506
79578
 
79507
79579
  // ../host/src/modules/taskflow/workflows/worker/codex.ts
79508
79580
  import { copyFile, writeFile as writeFile7 } from "node:fs/promises";
79509
- import { basename as basename10, join as join25 } from "node:path";
79581
+ import { basename as basename10, join as join26 } from "node:path";
79510
79582
  function textInput(text) {
79511
79583
  return [{ type: "text", text, text_elements: [] }];
79512
79584
  }
@@ -79922,7 +79994,7 @@ var init_codex = __esm({
79922
79994
  const id = basename10(rawId) || "image";
79923
79995
  const savedPath = typeof item.savedPath === "string" ? item.savedPath : void 0;
79924
79996
  const b64 = typeof item.result === "string" ? item.result : void 0;
79925
- const dest = join25(state3.cwd, `${id}.png`);
79997
+ const dest = join26(state3.cwd, `${id}.png`);
79926
79998
  const write4 = (async () => {
79927
79999
  try {
79928
80000
  if (savedPath) await copyFile(savedPath, dest);
@@ -80713,7 +80785,7 @@ __export(pi_exports, {
80713
80785
  });
80714
80786
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
80715
80787
  import { tmpdir as tmpdir2 } from "node:os";
80716
- import { join as join26 } from "node:path";
80788
+ import { join as join27 } from "node:path";
80717
80789
  function extractionPrompt2(spec, workingText) {
80718
80790
  return `Earlier you produced this answer:
80719
80791
 
@@ -80877,7 +80949,7 @@ var init_pi = __esm({
80877
80949
  return this.versionCheck;
80878
80950
  }
80879
80951
  async checkVersion() {
80880
- const scratch = mkdtempSync(join26(tmpdir2(), `${APP_SLUG}-pi-version-`));
80952
+ const scratch = mkdtempSync(join27(tmpdir2(), `${APP_SLUG}-pi-version-`));
80881
80953
  let out;
80882
80954
  try {
80883
80955
  out = await captureStdout({
@@ -81084,7 +81156,7 @@ var init_factory = __esm({
81084
81156
  });
81085
81157
 
81086
81158
  // ../host/src/modules/taskflow/workflows/runtime/jsonl-writer.ts
81087
- import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync11 } from "node:fs";
81159
+ import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync12 } from "node:fs";
81088
81160
  function dirOf(filePath) {
81089
81161
  const i3 = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
81090
81162
  return i3 <= 0 ? "." : filePath.slice(0, i3);
@@ -81097,7 +81169,7 @@ var init_jsonl_writer = __esm({
81097
81169
  stream;
81098
81170
  dead = false;
81099
81171
  constructor(filePath, opts = {}) {
81100
- mkdirSync11(dirOf(filePath), { recursive: true });
81172
+ mkdirSync12(dirOf(filePath), { recursive: true });
81101
81173
  this.stream = createWriteStream2(filePath, { flags: opts.flags ?? "a" });
81102
81174
  this.stream.on("error", (err2) => {
81103
81175
  this.dead = true;
@@ -81138,7 +81210,7 @@ var init_jsonl_writer = __esm({
81138
81210
  });
81139
81211
 
81140
81212
  // ../host/src/modules/taskflow/workflows/runtime/event-sink.ts
81141
- import { join as join27 } from "node:path";
81213
+ import { join as join28 } from "node:path";
81142
81214
  var FileEventSink;
81143
81215
  var init_event_sink = __esm({
81144
81216
  "../host/src/modules/taskflow/workflows/runtime/event-sink.ts"() {
@@ -81150,7 +81222,7 @@ var init_event_sink = __esm({
81150
81222
  listeners;
81151
81223
  clock;
81152
81224
  constructor(runId, opts = {}) {
81153
- this.writer = new JsonlWriter(join27(runDir(runId, opts.roots), "events.jsonl"), { flags: "a" });
81225
+ this.writer = new JsonlWriter(join28(runDir(runId, opts.roots), "events.jsonl"), { flags: "a" });
81154
81226
  this.listeners = opts.listeners ?? [];
81155
81227
  this.clock = opts.clock ?? (() => globalThis.Date.now());
81156
81228
  }
@@ -81252,15 +81324,15 @@ var init_semaphore = __esm({
81252
81324
  });
81253
81325
 
81254
81326
  // ../host/src/modules/taskflow/workflows/runtime/transcript.ts
81255
- import { join as join28 } from "node:path";
81327
+ import { join as join29 } from "node:path";
81256
81328
  function agentsDir(runId, roots = {}) {
81257
- return join28(runDir(runId, roots), "agents");
81329
+ return join29(runDir(runId, roots), "agents");
81258
81330
  }
81259
81331
  function agentTranscriptPath(runId, index, roots = {}) {
81260
- return join28(agentsDir(runId, roots), `${index}.jsonl`);
81332
+ return join29(agentsDir(runId, roots), `${index}.jsonl`);
81261
81333
  }
81262
81334
  function agentTranscriptPathByName(runId, name, roots = {}) {
81263
- return join28(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81335
+ return join29(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81264
81336
  }
81265
81337
  function truncate2(s, max) {
81266
81338
  if (s.length <= max) return s;
@@ -81349,8 +81421,8 @@ var init_transcript = __esm({
81349
81421
 
81350
81422
  // ../host/src/modules/taskflow/workflows/runtime/worktree.ts
81351
81423
  import { execFile } from "node:child_process";
81352
- import { existsSync as existsSync11, rmSync as rmSync3 } from "node:fs";
81353
- import { join as join29 } from "node:path";
81424
+ import { existsSync as existsSync12, rmSync as rmSync3 } from "node:fs";
81425
+ import { join as join30 } from "node:path";
81354
81426
  import { promisify as promisify3 } from "node:util";
81355
81427
  async function git3(cwd, args) {
81356
81428
  const { stdout: stdout2 } = await exec("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
@@ -81366,7 +81438,7 @@ async function findGitRoot(cwd) {
81366
81438
  async function createWorktree(args) {
81367
81439
  const name = `${args.runId}-${args.index}`;
81368
81440
  const branch = args.branch ?? `aw/${name}`;
81369
- const path7 = join29(projectPaths(args.gitRoot).worktrees, name);
81441
+ const path7 = join30(projectPaths(args.gitRoot).worktrees, name);
81370
81442
  const base2 = await git3(args.gitRoot, ["rev-parse", "HEAD"]);
81371
81443
  await pruneStaleWorktree(args.gitRoot, path7);
81372
81444
  await git3(args.gitRoot, ["worktree", "add", "--relative-paths", "--detach", path7, base2]);
@@ -81388,7 +81460,7 @@ async function pruneStaleWorktree(gitRoot2, path7) {
81388
81460
  });
81389
81461
  await git3(gitRoot2, ["worktree", "prune"]).catch(() => {
81390
81462
  });
81391
- if (existsSync11(path7)) {
81463
+ if (existsSync12(path7)) {
81392
81464
  try {
81393
81465
  rmSync3(path7, { recursive: true, force: true });
81394
81466
  } catch {
@@ -82121,7 +82193,7 @@ ${e.status === "completed" ? "\u2713" : "\u2717"} ${e.status}${e.error ? `: ${e.
82121
82193
  // ../host/src/modules/taskflow/workflows/runtime/run.ts
82122
82194
  import { createHash as createHash10, randomBytes as randomBytes7 } from "node:crypto";
82123
82195
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
82124
- import { join as join30, resolve as resolve19 } from "node:path";
82196
+ import { join as join31, resolve as resolve19 } from "node:path";
82125
82197
  async function runWorkflow(opts) {
82126
82198
  const filePath = resolve19(opts.file);
82127
82199
  const source = readFileSync15(filePath, "utf8");
@@ -82181,7 +82253,7 @@ async function runWorkflow(opts) {
82181
82253
  if (opts.signal?.aborted) ac.abort();
82182
82254
  else opts.signal?.addEventListener("abort", onSig, { once: true });
82183
82255
  events.emit({ type: "run", status: "started", runId, workflowFile: filePath });
82184
- const heartbeatFile = join30(runDir(runId, opts.roots), ".heartbeat");
82256
+ const heartbeatFile = join31(runDir(runId, opts.roots), ".heartbeat");
82185
82257
  const beat = () => {
82186
82258
  try {
82187
82259
  writeFileSync9(heartbeatFile, String(Date.now()));
@@ -83382,9 +83454,9 @@ var init_environment_diagnostics_service = __esm({
83382
83454
  });
83383
83455
 
83384
83456
  // ../host/src/modules/taskflow/services/environment-worker-factory.ts
83385
- import { chmodSync as chmodSync6, mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
83457
+ import { chmodSync as chmodSync7, mkdtempSync as mkdtempSync2, rmSync as rmSync4, writeFileSync as writeFileSync10 } from "node:fs";
83386
83458
  import { tmpdir as tmpdir3 } from "node:os";
83387
- import { join as join31, posix as posix4, relative as relative5 } from "node:path";
83459
+ import { join as join32, posix as posix4, relative as relative5 } from "node:path";
83388
83460
  function mapAgentSpecToEnvironment(spec, hostWorkspace, containerWorkspace) {
83389
83461
  const suffix = relative5(hostWorkspace, spec.cwd);
83390
83462
  if (suffix.startsWith("..")) {
@@ -83437,12 +83509,12 @@ var init_environment_worker_factory = __esm({
83437
83509
  this.handle = handle2;
83438
83510
  const containerWorkspace = handle2.workspace.containerPath;
83439
83511
  if (!containerWorkspace) throw new Error(`Environment has no container workspace: ${handle2.id}`);
83440
- this.directory = mkdtempSync2(join31(tmpdir3(), "taskflow-environment-workers-"));
83512
+ this.directory = mkdtempSync2(join32(tmpdir3(), "taskflow-environment-workers-"));
83441
83513
  const paths3 = Object.fromEntries(
83442
83514
  Object.entries(executableByProvider).map(([provider, executable2]) => {
83443
- const path7 = join31(this.directory, provider);
83515
+ const path7 = join32(this.directory, provider);
83444
83516
  writeFileSync10(path7, transport.executableShim(handle2, executable2), { encoding: "utf8", mode: 448 });
83445
- chmodSync6(path7, 448);
83517
+ chmodSync7(path7, 448);
83446
83518
  return [provider, path7];
83447
83519
  })
83448
83520
  );
@@ -84514,7 +84586,7 @@ var init_run_presentation_service = __esm({
84514
84586
  });
84515
84587
 
84516
84588
  // ../host/src/modules/taskflow/services/workspace-facade.ts
84517
- import { join as join32 } from "node:path";
84589
+ import { join as join33 } from "node:path";
84518
84590
  function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, baseCommit, workspace2, access5) {
84519
84591
  const segment3 = runId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "run";
84520
84592
  if (workspace2.strategy !== "isolated_worktree") {
@@ -84531,7 +84603,7 @@ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, bas
84531
84603
  };
84532
84604
  }
84533
84605
  const name = `${APP_SLUG}-run-${segment3}`;
84534
- const path7 = join32(workspaceRoot, name);
84606
+ const path7 = join33(workspaceRoot, name);
84535
84607
  return {
84536
84608
  workspaceId: `workspace_${runId}`,
84537
84609
  path: path7,
@@ -84549,7 +84621,7 @@ function slugSegment(value3, fallback) {
84549
84621
  function forkBindingFor(run2, workspaceRoot, slug2) {
84550
84622
  const runSegment = slugSegment(run2.id, "run");
84551
84623
  const forkSegment = slugSegment(slug2, "fork");
84552
- const path7 = join32(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84624
+ const path7 = join33(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84553
84625
  return {
84554
84626
  workspaceId: `workspace_lease_${run2.id}_${forkSegment}`,
84555
84627
  path: path7,
@@ -84851,7 +84923,7 @@ var init_workspace_facade = __esm({
84851
84923
 
84852
84924
  // ../host/src/modules/taskflow/services/run-service.ts
84853
84925
  import { readFile as readFile9 } from "node:fs/promises";
84854
- import { join as join33 } from "node:path";
84926
+ import { join as join34 } from "node:path";
84855
84927
  function provisioningReason(reason) {
84856
84928
  return reason === "branch_conflict" || reason === "workspace_path_conflict" || reason === "checkout_busy" || reason === "dirty_workspace" || reason === "detached_head" ? reason : "workspace_provision_failed";
84857
84929
  }
@@ -85510,7 +85582,7 @@ var init_run_service = __esm({
85510
85582
  root2,
85511
85583
  terminal.cursor,
85512
85584
  terminal.type === "completed" ? "completed" : active.cancelling ? "cancelled" : "failed",
85513
- terminal.type === "completed" ? { resultPath: join33(root2.dataRoot, "runs", engineRunId, "result.json") } : null
85585
+ terminal.type === "completed" ? { resultPath: join34(root2.dataRoot, "runs", engineRunId, "result.json") } : null
85514
85586
  );
85515
85587
  const completedAt = this.now().toISOString();
85516
85588
  if (terminal.type === "completed") {
@@ -85622,7 +85694,7 @@ var init_run_service = __esm({
85622
85694
  async completedResult(engineRunId, dataRoot2) {
85623
85695
  try {
85624
85696
  const result = JsonValueSchema.safeParse(
85625
- JSON.parse(await readFile9(join33(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85697
+ JSON.parse(await readFile9(join34(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85626
85698
  );
85627
85699
  return result.success ? result.data : null;
85628
85700
  } catch {
@@ -86027,7 +86099,7 @@ var init_taskflow_direct_session_service = __esm({
86027
86099
  // ../host/src/modules/taskflow/services/workflow-catalog-service.ts
86028
86100
  import { createHash as createHash11 } from "node:crypto";
86029
86101
  import { readdir as readdir4, readFile as readFile10, stat as stat4 } from "node:fs/promises";
86030
- import { join as join34, resolve as resolve21 } from "node:path";
86102
+ import { join as join35, resolve as resolve21 } from "node:path";
86031
86103
  function hash3(value3) {
86032
86104
  return `sha256:${createHash11("sha256").update(value3).digest("hex")}`;
86033
86105
  }
@@ -86071,7 +86143,7 @@ function duplicateDiagnostic(name, origin) {
86071
86143
  function rootsFor(config3) {
86072
86144
  return [
86073
86145
  { origin: "project", directory: projectPaths(resolve21(config3.projectRoot)).workflows, priority: 0 },
86074
- { origin: "global", directory: join34(resolve21(config3.taskflowHome), PATH_NAMES.workflows), priority: 1 },
86146
+ { origin: "global", directory: join35(resolve21(config3.taskflowHome), PATH_NAMES.workflows), priority: 1 },
86075
86147
  { origin: "builtin", directory: resolve21(config3.builtinRoot), priority: 2 }
86076
86148
  ];
86077
86149
  }
@@ -86185,7 +86257,7 @@ var init_workflow_catalog_service = __esm({
86185
86257
  return { candidates, diagnostics, invalidEntries };
86186
86258
  }
86187
86259
  for (const name of names) {
86188
- const path7 = join34(root2.directory, name);
86260
+ const path7 = join35(root2.directory, name);
86189
86261
  try {
86190
86262
  if ((await stat4(path7)).size > MAX_WORKFLOW_BYTES2) {
86191
86263
  const diagnostic = {
@@ -86230,7 +86302,7 @@ var init_workflow_catalog_service = __esm({
86230
86302
  });
86231
86303
 
86232
86304
  // ../host/src/modules/taskflow/services/workflow-event-bridge.ts
86233
- import { join as join35 } from "node:path";
86305
+ import { join as join36 } from "node:path";
86234
86306
  function record5(value3) {
86235
86307
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return null;
86236
86308
  const output2 = {};
@@ -86320,7 +86392,7 @@ function executionFor(run2, existing, details, context) {
86320
86392
  key: details.key,
86321
86393
  index: details.index,
86322
86394
  phaseIndex: details.phaseIndex,
86323
- transcriptPath: context ? join35(context.dataRoot, "runs", context.engineRunId, "agents", `${details.index}.jsonl`) : null
86395
+ transcriptPath: context ? join36(context.dataRoot, "runs", context.engineRunId, "agents", `${details.index}.jsonl`) : null
86324
86396
  },
86325
86397
  workspaceId: run2.workspaceId,
86326
86398
  input: existing?.input ?? null,
@@ -86388,7 +86460,7 @@ var init_workflow_event_bridge = __esm({
86388
86460
 
86389
86461
  // ../host/src/modules/taskflow/services/workflow-runner.ts
86390
86462
  import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
86391
- import { join as join36 } from "node:path";
86463
+ import { join as join37 } from "node:path";
86392
86464
  function envelope(spec, message) {
86393
86465
  return {
86394
86466
  ...message,
@@ -86428,9 +86500,9 @@ var init_workflow_runner = __esm({
86428
86500
  const pid = process.pid;
86429
86501
  let heartbeat;
86430
86502
  const done = (async () => {
86431
- const runDirectory = join36(spec.spec.dataRoot, "runs", spec.engineRunId);
86503
+ const runDirectory = join37(spec.spec.dataRoot, "runs", spec.engineRunId);
86432
86504
  await mkdir5(runDirectory, { recursive: true });
86433
- const snapshotPath = join36(runDirectory, "workflow.js");
86505
+ const snapshotPath = join37(runDirectory, "workflow.js");
86434
86506
  await writeFile8(snapshotPath, spec.spec.source, "utf8");
86435
86507
  emit(envelope(spec, { type: "started", pid }));
86436
86508
  heartbeat = setInterval(() => {
@@ -87117,15 +87189,15 @@ var init_worktree_conversation_service = __esm({
87117
87189
 
87118
87190
  // ../host/src/modules/taskflow/adapters/docker-compose-environment.ts
87119
87191
  import { createHash as createHash12 } from "node:crypto";
87120
- import { existsSync as existsSync12, readFileSync as readFileSync16 } from "node:fs";
87192
+ import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
87121
87193
  import { resolve as resolve22 } from "node:path";
87122
87194
  function composeFile(workspacePath, configured) {
87123
87195
  if (configured) {
87124
87196
  const candidate = resolve22(workspacePath, configured);
87125
- if (existsSync12(candidate)) return candidate;
87197
+ if (existsSync13(candidate)) return candidate;
87126
87198
  throw new Error(`Docker Compose file does not exist: ${configured}`);
87127
87199
  }
87128
- const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync12);
87200
+ const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync13);
87129
87201
  if (!found) throw new Error("No Docker Compose file was found");
87130
87202
  return found;
87131
87203
  }
@@ -87154,7 +87226,7 @@ var init_docker_compose_environment = __esm({
87154
87226
  }
87155
87227
  async probe(context) {
87156
87228
  const version3 = await runCaptured(this.runner, { command: "docker", args: ["compose", "version", "--short"] });
87157
- const configs = COMPOSE_FILENAMES.map((file2) => resolve22(context.workspacePath, file2)).filter(existsSync12);
87229
+ const configs = COMPOSE_FILENAMES.map((file2) => resolve22(context.workspacePath, file2)).filter(existsSync13);
87158
87230
  return {
87159
87231
  provider: this.id,
87160
87232
  available: version3.exit.code === 0 && configs.length > 0,
@@ -88501,8 +88573,8 @@ var init_project_environments = __esm({
88501
88573
  // ../host/src/modules/taskflow/server/project-app.ts
88502
88574
  import { spawn as spawn8 } from "node:child_process";
88503
88575
  import { randomUUID as randomUUID6 } from "node:crypto";
88504
- import { existsSync as existsSync13 } from "node:fs";
88505
- import { dirname as dirname20, join as join37, resolve as resolve23 } from "node:path";
88576
+ import { existsSync as existsSync14 } from "node:fs";
88577
+ import { dirname as dirname20, join as join38, resolve as resolve23 } from "node:path";
88506
88578
  import { fileURLToPath as fileURLToPath5 } from "node:url";
88507
88579
  function workflowAgentRuntimeConfig(value3) {
88508
88580
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
@@ -88533,7 +88605,7 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88533
88605
  const reconciliationService = runtime2.reconciliationService;
88534
88606
  const codexAppServerClient = new CodexAppServerClient({
88535
88607
  clientName: RUNTIME_IDENTITY.codexClientName,
88536
- clientVersion: "0.0.0"
88608
+ clientVersion: PORTTA_FLOW_VERSION
88537
88609
  });
88538
88610
  const claudeCliClient = new ClaudeCliClient();
88539
88611
  const worktreeConversationService = new WorktreeConversationService({
@@ -88586,14 +88658,14 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88586
88658
  const workflowEvents = new WorkflowEventBridge({ store: runStore, publisher: runEventPublisher });
88587
88659
  const workspaces = new WorkspaceFacade({ store: runStore, git: git4 });
88588
88660
  const workflowDataRoot = globalPaths().root;
88589
- const supervisorSocket = join37(workflowDataRoot, "runtime", "supervisor.sock");
88661
+ const supervisorSocket = join38(workflowDataRoot, "runtime", "supervisor.sock");
88590
88662
  const supervisor = new AgentSupervisorClient({
88591
88663
  socketPath: supervisorSocket,
88592
88664
  startDaemon: () => {
88593
88665
  const directory = dirname20(fileURLToPath5(import.meta.url));
88594
- const builtEntry = join37(directory, "supervisor.js");
88595
- const sourceEntry = join37(directory, "supervisor.ts");
88596
- const child = existsSync13(builtEntry) ? spawn8(process.execPath, [builtEntry], { detached: true, stdio: "ignore" }) : spawn8(process.execPath, ["--import", "tsx", sourceEntry], { detached: true, stdio: "ignore" });
88666
+ const builtEntry = join38(directory, "supervisor.js");
88667
+ const sourceEntry = join38(directory, "supervisor.ts");
88668
+ const child = existsSync14(builtEntry) ? spawn8(process.execPath, [builtEntry], { detached: true, stdio: "ignore" }) : spawn8(process.execPath, ["--import", "tsx", sourceEntry], { detached: true, stdio: "ignore" });
88597
88669
  child.unref();
88598
88670
  }
88599
88671
  });
@@ -90036,7 +90108,7 @@ var init_upgrade = __esm({
90036
90108
  });
90037
90109
 
90038
90110
  // ../host/src/modules/taskflow/server/host.ts
90039
- import { existsSync as existsSync14 } from "node:fs";
90111
+ import { existsSync as existsSync15 } from "node:fs";
90040
90112
  function createTaskflowHost(options) {
90041
90113
  const apps = /* @__PURE__ */ new Map();
90042
90114
  const manager = new ProjectManager({
@@ -90066,8 +90138,8 @@ function createTaskflowHost(options) {
90066
90138
  manager,
90067
90139
  apps,
90068
90140
  allowlist: options.projectAllowlist,
90069
- // Tracks leftover on-add setup records for API compatibility. Registration
90070
- // no longer scaffolds or launches an agent; `taskflow init` remains the authoring path.
90141
+ // Backs the project-setup status listing. Registration itself does not
90142
+ // scaffold or launch an agent; `taskflow init` is the authoring path.
90071
90143
  initTracker: new ProjectInitTracker(),
90072
90144
  closeSockets: (prefix) => sockets.closeProject(prefix)
90073
90145
  });
@@ -90080,7 +90152,7 @@ function createTaskflowHost(options) {
90080
90152
  if (!isGitRepo(cwd)) return;
90081
90153
  const repoRoot = canonicalizeFsPath(projectRoot(cwd));
90082
90154
  const paths3 = projectPaths(repoRoot);
90083
- if (!existsSync14(paths3.config) && !existsSync14(paths3.localConfig)) return;
90155
+ if (!existsSync15(paths3.config) && !existsSync15(paths3.localConfig)) return;
90084
90156
  try {
90085
90157
  manager.addEphemeral(repoRoot);
90086
90158
  } catch (err2) {
@@ -90095,7 +90167,7 @@ function createTaskflowHost(options) {
90095
90167
  }
90096
90168
  };
90097
90169
  }
90098
- var init_host2 = __esm({
90170
+ var init_host = __esm({
90099
90171
  "../host/src/modules/taskflow/server/host.ts"() {
90100
90172
  "use strict";
90101
90173
  init_paths2();
@@ -90151,7 +90223,7 @@ function createDaemonTaskflowHost(context) {
90151
90223
  port: hostListen(env).port,
90152
90224
  workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
90153
90225
  version: env.PORTTA_VERSION || "0.0.0-local",
90154
- buildDate: true ? "2026-09-18T00:56:55Z" : (/* @__PURE__ */ new Date()).toISOString(),
90226
+ buildDate: true ? "2026-09-18T02:50:11Z" : (/* @__PURE__ */ new Date()).toISOString(),
90155
90227
  environmentStore: createEnvironmentStore(paths3.database),
90156
90228
  hostEnvironmentProvider: new HostEnvironmentProvider(),
90157
90229
  devContainerProvider: new DevContainerProvider(),
@@ -90222,9 +90294,8 @@ var init_taskflow4 = __esm({
90222
90294
  init_user_shell_env();
90223
90295
  init_environment_service_discovery();
90224
90296
  init_project_allowlist();
90225
- init_host2();
90297
+ init_host();
90226
90298
  init_host_projects();
90227
- init_runtime();
90228
90299
  TASKFLOW_SOCKET_MOUNT_PATH = `/ws/modules/${taskflowModule.id}`;
90229
90300
  taskflowHostModule = createTaskflowHostModule();
90230
90301
  }
@@ -91098,7 +91169,7 @@ var require_util2 = __commonJS({
91098
91169
  function getFilesInPath(source) {
91099
91170
  const lstatSync = fs.lstatSync;
91100
91171
  const readdirSync11 = fs.readdirSync;
91101
- const join70 = path7.join;
91172
+ const join71 = path7.join;
91102
91173
  function isDirectory2(source2) {
91103
91174
  return lstatSync(source2).isDirectory();
91104
91175
  }
@@ -91107,12 +91178,12 @@ var require_util2 = __commonJS({
91107
91178
  }
91108
91179
  function getDirectories(source2) {
91109
91180
  return readdirSync11(source2).map((name) => {
91110
- return join70(source2, name);
91181
+ return join71(source2, name);
91111
91182
  }).filter(isDirectory2);
91112
91183
  }
91113
91184
  function getFiles(source2) {
91114
91185
  return readdirSync11(source2).map((name) => {
91115
- return join70(source2, name);
91186
+ return join71(source2, name);
91116
91187
  }).filter(isFile);
91117
91188
  }
91118
91189
  function getFilesRecursively(source2) {
@@ -100747,7 +100818,7 @@ var require_network = __commonJS({
100747
100818
  var exec3 = __require("child_process").exec;
100748
100819
  var execSync = __require("child_process").execSync;
100749
100820
  var execFileSync2 = __require("child_process").execFileSync;
100750
- var readFileSync38 = __require("fs").readFileSync;
100821
+ var readFileSync37 = __require("fs").readFileSync;
100751
100822
  var fs = __require("fs");
100752
100823
  var util2 = require_util2();
100753
100824
  var _platform = process.platform;
@@ -101235,7 +101306,7 @@ var require_network = __commonJS({
101235
101306
  return result;
101236
101307
  }
101237
101308
  try {
101238
- const content = readFileSync38(file2, { encoding: "utf8" });
101309
+ const content = readFileSync37(file2, { encoding: "utf8" });
101239
101310
  const lines = content.split("\n").filter((l) => /iface|source/.test(l));
101240
101311
  lines.forEach((line4) => {
101241
101312
  const parts2 = line4.replace(/\s+/g, " ").trim().split(" ");
@@ -101402,7 +101473,7 @@ var require_network = __commonJS({
101402
101473
  return false;
101403
101474
  }
101404
101475
  }
101405
- function networkInterfaces2(callback, rescan, defaultString) {
101476
+ function networkInterfaces(callback, rescan, defaultString) {
101406
101477
  if (typeof callback === "string") {
101407
101478
  defaultString = callback;
101408
101479
  rescan = true;
@@ -101817,7 +101888,7 @@ var require_network = __commonJS({
101817
101888
  });
101818
101889
  });
101819
101890
  }
101820
- exports.networkInterfaces = networkInterfaces2;
101891
+ exports.networkInterfaces = networkInterfaces;
101821
101892
  function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) {
101822
101893
  const result = {
101823
101894
  iface,
@@ -101890,7 +101961,7 @@ var require_network = __commonJS({
101890
101961
  const workload = [];
101891
101962
  if (ifacesArray.length && ifacesArray[0].trim() === "*") {
101892
101963
  ifacesArray = [];
101893
- networkInterfaces2(false).then((allIFaces) => {
101964
+ networkInterfaces(false).then((allIFaces) => {
101894
101965
  for (let iface of allIFaces) {
101895
101966
  ifacesArray.push(iface.iface);
101896
101967
  }
@@ -102056,7 +102127,7 @@ var require_network = __commonJS({
102056
102127
  const psections = stdout2.toString().split(/\n\s*\n/);
102057
102128
  perfData = parseLinesWindowsPerfData(psections);
102058
102129
  }
102059
- networkInterfaces2(false).then((interfaces) => {
102130
+ networkInterfaces(false).then((interfaces) => {
102060
102131
  rx_bytes = 0;
102061
102132
  tx_bytes = 0;
102062
102133
  perfData.forEach((detail2) => {
@@ -103513,7 +103584,7 @@ var require_processes = __commonJS({
103513
103584
  }
103514
103585
  exec3(cmd, { maxBuffer: 1024 * 102400 }, function(error61, stdout3) {
103515
103586
  let curr_processes = stdout3.toString().split("\n");
103516
- let all = parseProcStat2(curr_processes.shift());
103587
+ let all = parseProcStat(curr_processes.shift());
103517
103588
  let list_new = {};
103518
103589
  let resultProcess = {};
103519
103590
  curr_processes.forEach((element) => {
@@ -103691,7 +103762,7 @@ var require_processes = __commonJS({
103691
103762
  });
103692
103763
  }
103693
103764
  exports.services = services;
103694
- function parseProcStat2(line4) {
103765
+ function parseProcStat(line4) {
103695
103766
  const parts2 = line4.replace(/ +/g, " ").split(" ");
103696
103767
  const user = parts2.length >= 2 ? parseInt(parts2[1]) : 0;
103697
103768
  const nice = parts2.length >= 3 ? parseInt(parts2[2]) : 0;
@@ -104031,7 +104102,7 @@ var require_processes = __commonJS({
104031
104102
  });
104032
104103
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error62, stdout3) => {
104033
104104
  let curr_processes = stdout3.toString().split("\n");
104034
- let all = parseProcStat2(curr_processes.shift());
104105
+ let all = parseProcStat(curr_processes.shift());
104035
104106
  let list_new = {};
104036
104107
  let resultProcess = {};
104037
104108
  curr_processes.forEach((element) => {
@@ -104486,7 +104557,7 @@ var require_processes = __commonJS({
104486
104557
  }
104487
104558
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error61, stdout3) => {
104488
104559
  let curr_processes = stdout3.toString().split("\n");
104489
- let all = parseProcStat2(curr_processes.shift());
104560
+ let all = parseProcStat(curr_processes.shift());
104490
104561
  let list_new = {};
104491
104562
  let resultProcess = {};
104492
104563
  curr_processes.forEach((element) => {
@@ -108560,7 +108631,7 @@ var require_lib = __commonJS({
108560
108631
  });
108561
108632
 
108562
108633
  // src/commands/flow/daemon.ts
108563
- import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
108634
+ import { existsSync as existsSync25, readFileSync as readFileSync23 } from "node:fs";
108564
108635
  function flowStateDir(env = process.env) {
108565
108636
  const configured = env[ENV_NAMES.hostStateDir]?.trim();
108566
108637
  if (configured) return configured;
@@ -108578,7 +108649,7 @@ function daemonToken(env = process.env) {
108578
108649
  const file2 = hostTokenFile(flowStateDir(env));
108579
108650
  if (existsSync25(file2)) {
108580
108651
  try {
108581
- const token = readFileSync24(file2, "utf8").trim();
108652
+ const token = readFileSync23(file2, "utf8").trim();
108582
108653
  if (token) return token;
108583
108654
  } catch {
108584
108655
  }
@@ -108681,8 +108752,8 @@ var init_server_port = __esm({
108681
108752
 
108682
108753
  // ../host/src/modules/taskflow/lib/shell.ts
108683
108754
  import { spawnSync as spawnSync8 } from "node:child_process";
108684
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
108685
- import { basename as basename16, join as join48 } from "node:path";
108755
+ import { existsSync as existsSync26, readFileSync as readFileSync24 } from "node:fs";
108756
+ import { basename as basename16, join as join49 } from "node:path";
108686
108757
  function run(cmd, args, opts) {
108687
108758
  const resolved2 = resolveHostTool(cmd) ?? cmd;
108688
108759
  const result = spawnSync8(resolved2, args, {
@@ -108702,10 +108773,10 @@ function getGitRoot() {
108702
108773
  return result.stdout.toString().trim();
108703
108774
  }
108704
108775
  function detectProjectName(gitRoot2) {
108705
- const pkgPath = join48(gitRoot2, "package.json");
108776
+ const pkgPath = join49(gitRoot2, "package.json");
108706
108777
  if (existsSync26(pkgPath)) {
108707
108778
  try {
108708
- const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
108779
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
108709
108780
  if (pkg.name) return pkg.name;
108710
108781
  } catch {
108711
108782
  }
@@ -108860,36 +108931,6 @@ var init_project_env2 = __esm({
108860
108931
  }
108861
108932
  });
108862
108933
 
108863
- // src/commands/flow/process.ts
108864
- async function runProcess3(file2, args = [], options = {}) {
108865
- const execaOptions = {
108866
- cwd: options.cwd,
108867
- env: options.env,
108868
- input: options.input,
108869
- reject: options.reject ?? true,
108870
- shell: false,
108871
- timeout: options.timeout,
108872
- stdio: options.input !== void 0 ? ["pipe", options.stdio ?? "pipe", options.stdio ?? "pipe"] : options.stdio
108873
- };
108874
- const result = await execa(file2, [...args], execaOptions);
108875
- const notStarted = result.failed && result.exitCode === void 0 && !result.signal && !result.timedOut;
108876
- return {
108877
- stdout: typeof result.stdout === "string" ? result.stdout : "",
108878
- stderr: typeof result.stderr === "string" ? result.stderr : "",
108879
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
108880
- failed: result.failed,
108881
- ...notStarted && "originalMessage" in result ? { error: String(result.originalMessage) } : {}
108882
- };
108883
- }
108884
- var PROCESS_POLICY2;
108885
- var init_process = __esm({
108886
- "src/commands/flow/process.ts"() {
108887
- "use strict";
108888
- init_execa();
108889
- PROCESS_POLICY2 = Object.freeze({ shell: false, argumentArraysOnly: true });
108890
- }
108891
- });
108892
-
108893
108934
  // src/commands/flow/completions.ts
108894
108935
  var completions_exports = {};
108895
108936
  __export(completions_exports, {
@@ -108922,7 +108963,7 @@ function completionTree(command) {
108922
108963
  };
108923
108964
  }
108924
108965
  async function defaultRunGit(args) {
108925
- const result = await runProcess3("git", args, { reject: false });
108966
+ const result = await runProcess("git", args, { reject: false });
108926
108967
  return { exitCode: result.exitCode, stdout: result.stdout.trim() };
108927
108968
  }
108928
108969
  async function listWorktreeBranches(deps = { runGit: defaultRunGit }) {
@@ -110211,9 +110252,9 @@ ${f}
110211
110252
  });
110212
110253
 
110213
110254
  // ../host/src/modules/taskflow/services/init-authoring.ts
110214
- import { existsSync as existsSync28, readFileSync as readFileSync26, rmSync as rmSync8 } from "node:fs";
110255
+ import { existsSync as existsSync28, readFileSync as readFileSync25, rmSync as rmSync8 } from "node:fs";
110215
110256
  import { tmpdir as tmpdir4 } from "node:os";
110216
- import { join as join49 } from "node:path";
110257
+ import { join as join50 } from "node:path";
110217
110258
  function isRecord8(value3) {
110218
110259
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
110219
110260
  }
@@ -110221,9 +110262,9 @@ function readString4(value3) {
110221
110262
  return typeof value3 === "string" && value3.trim().length > 0 ? value3 : null;
110222
110263
  }
110223
110264
  function detectPackageManager(gitRoot2) {
110224
- if (existsSync28(join49(gitRoot2, "bun.lock")) || existsSync28(join49(gitRoot2, "bun.lockb"))) return "bun";
110225
- if (existsSync28(join49(gitRoot2, "pnpm-lock.yaml"))) return "pnpm";
110226
- if (existsSync28(join49(gitRoot2, "yarn.lock"))) return "yarn";
110265
+ if (existsSync28(join50(gitRoot2, "bun.lock")) || existsSync28(join50(gitRoot2, "bun.lockb"))) return "bun";
110266
+ if (existsSync28(join50(gitRoot2, "pnpm-lock.yaml"))) return "pnpm";
110267
+ if (existsSync28(join50(gitRoot2, "yarn.lock"))) return "yarn";
110227
110268
  return "npm";
110228
110269
  }
110229
110270
  function detectMainBranch(gitRoot2) {
@@ -110260,17 +110301,17 @@ function detectInitProjectContext(gitRoot2, defaultAgent) {
110260
110301
  }
110261
110302
  function detectInitEnvironment(gitRoot2, requested = "auto") {
110262
110303
  const devcontainerConfigs = [".devcontainer.json", ".devcontainer/devcontainer.json"].filter(
110263
- (path7) => existsSync28(join49(gitRoot2, path7))
110304
+ (path7) => existsSync28(join50(gitRoot2, path7))
110264
110305
  );
110265
110306
  const composeFiles2 = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].filter(
110266
- (path7) => existsSync28(join49(gitRoot2, path7))
110307
+ (path7) => existsSync28(join50(gitRoot2, path7))
110267
110308
  );
110268
- const selectedRuntime = requested !== "auto" ? requested : devcontainerConfigs.length === 1 ? "devcontainer" : composeFiles2.length > 0 ? "compose" : existsSync28(join49(gitRoot2, "Dockerfile")) ? "dockerfile" : "host";
110309
+ const selectedRuntime = requested !== "auto" ? requested : devcontainerConfigs.length === 1 ? "devcontainer" : composeFiles2.length > 0 ? "compose" : existsSync28(join50(gitRoot2, "Dockerfile")) ? "dockerfile" : "host";
110269
110310
  return {
110270
110311
  devcontainerConfigs,
110271
110312
  composeFiles: composeFiles2,
110272
- dockerfile: existsSync28(join49(gitRoot2, "Dockerfile")),
110273
- packageJson: existsSync28(join49(gitRoot2, "package.json")),
110313
+ dockerfile: existsSync28(join50(gitRoot2, "Dockerfile")),
110314
+ packageJson: existsSync28(join50(gitRoot2, "package.json")),
110274
110315
  selectedRuntime
110275
110316
  };
110276
110317
  }
@@ -110291,7 +110332,7 @@ function buildInitPromptSpec(context) {
110291
110332
  "workspace.mainBranch: infer from git",
110292
110333
  `workspace.worktrees.root: keep ${APP_DEFAULTS.worktreeRoot} unless there is clear evidence of an existing alternative`,
110293
110334
  "Do not copy detected Compose services or ports into config unless the user needs an explicit override.",
110294
- "Preserve the commented services example: it is for Taskflow-managed host or legacy Docker processes, not discovered Dev Container or Compose services.",
110335
+ "Preserve the commented services example: it is for Taskflow-managed host or Docker profile processes, not discovered Dev Container or Compose services.",
110295
110336
  "profiles.default.environment.provider: auto unless the user chose a runtime override. If no Dev Container, Compose, or Dockerfile exists, set it to host.",
110296
110337
  "For a host project, put its one managed development command in profiles.default.environment.command; never add a third app command pane for it.",
110297
110338
  "Only declare services when a host command has a proven port and supports the injected port environment variable. When the port is uncertain, keep the command but omit services.",
@@ -110336,7 +110377,7 @@ function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`)
110336
110377
  ]
110337
110378
  };
110338
110379
  }
110339
- const summaryPath = join49(tmpdir4(), `${outputPrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`);
110380
+ const summaryPath = join50(tmpdir4(), `${outputPrefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}.txt`);
110340
110381
  return {
110341
110382
  agent,
110342
110383
  cmd: "codex",
@@ -110592,7 +110633,7 @@ function finalizeAgentRun(spec, exitCode, stdoutResult, stderr2) {
110592
110633
  let summary = stdoutResult.assistantText.trim();
110593
110634
  if (spec.summaryPath && existsSync28(spec.summaryPath)) {
110594
110635
  try {
110595
- summary = readFileSync26(spec.summaryPath, "utf8").trim() || summary;
110636
+ summary = readFileSync25(spec.summaryPath, "utf8").trim() || summary;
110596
110637
  } finally {
110597
110638
  rmSync8(spec.summaryPath, { force: true });
110598
110639
  }
@@ -110627,7 +110668,7 @@ workspace:
110627
110668
  # intervalSeconds: 300
110628
110669
 
110629
110670
  # Taskflow discovers Dev Container, Compose, and Dockerfile services from the resolved runtime.
110630
- # Declare services here only for a process started by a host or legacy Docker pane
110671
+ # Declare services here only for a process started by a host or Docker profile pane
110631
110672
  # that accepts an injected port environment variable. Do not duplicate discovered services.
110632
110673
  services:
110633
110674
  # Example app service with a predictable port per worktree.
@@ -110653,8 +110694,8 @@ exposure:
110653
110694
  # Profiles define runtime, permissions, and tmux pane layout.
110654
110695
  profiles:
110655
110696
  default:
110656
- # Legacy panes run on the host; the environment provider controls the
110657
- # development runtime and is automatically resolved from Dev Container, Compose, or Dockerfile.
110697
+ # Panes run on the host; the environment provider controls the development
110698
+ # runtime and is automatically resolved from Dev Container, Compose, or Dockerfile.
110658
110699
  runtime: host
110659
110700
  environment:
110660
110701
  provider: ${environmentProvider}
@@ -112348,7 +112389,7 @@ async function defaultConfirmPrune(worktreeCount) {
112348
112389
  }
112349
112390
  async function attachToHerdr() {
112350
112391
  if (process.env.HERDR_PANE_ID || process.env.HERDR_ENV) return;
112351
- const result = await runProcess3("herdr", [], { stdio: "inherit", reject: false });
112392
+ const result = await runProcess("herdr", [], { stdio: "inherit", reject: false });
112352
112393
  if (result.exitCode !== 0) {
112353
112394
  console.error("Warning: failed to attach to herdr");
112354
112395
  }
@@ -112371,12 +112412,12 @@ async function defaultSwitchToSessionWindow(projectDir, _branch, multiplexer) {
112371
112412
  }
112372
112413
  const sessionName = buildProjectSessionName(resolve30(projectDir));
112373
112414
  if (process.env.TMUX) {
112374
- const result = await runProcess3("tmux", ["switch-client", "-t", sessionName], { reject: false });
112415
+ const result = await runProcess("tmux", ["switch-client", "-t", sessionName], { reject: false });
112375
112416
  if (result.exitCode !== 0) {
112376
112417
  console.error(`Warning: failed to switch tmux client to ${sessionName}`);
112377
112418
  }
112378
112419
  } else {
112379
- const result = await runProcess3("tmux", ["attach-session", "-t", sessionName], { stdio: "inherit", reject: false });
112420
+ const result = await runProcess("tmux", ["attach-session", "-t", sessionName], { stdio: "inherit", reject: false });
112380
112421
  if (result.exitCode !== 0) {
112381
112422
  console.error(`Warning: failed to attach to tmux session ${sessionName}`);
112382
112423
  }
@@ -112844,7 +112885,7 @@ function environmentBaseUrlFromControlUrl(value3) {
112844
112885
  }
112845
112886
  }
112846
112887
  async function runInherited(invocation2) {
112847
- const result = await runProcess3(invocation2.command, invocation2.args, {
112888
+ const result = await runProcess(invocation2.command, invocation2.args, {
112848
112889
  cwd: invocation2.cwd,
112849
112890
  stdio: "inherit",
112850
112891
  reject: false
@@ -112855,7 +112896,7 @@ async function runInherited(invocation2) {
112855
112896
  async function writeClipboard(value3) {
112856
112897
  const command = process.platform === "darwin" ? "pbcopy" : process.platform === "win32" ? "clip" : "xclip";
112857
112898
  const args = process.platform === "linux" ? ["-selection", "clipboard"] : [];
112858
- return (await runProcess3(command, args, { input: value3, reject: false })).exitCode === 0;
112899
+ return (await runProcess(command, args, { input: value3, reject: false })).exitCode === 0;
112859
112900
  }
112860
112901
  async function runEnvironmentCommand(request2, port, projectDir, stdout2 = console.log, stderr2 = console.error, dependencies = defaultEnvironmentCommandDependencies) {
112861
112902
  try {
@@ -112917,7 +112958,7 @@ async function runEnvironmentCommand(request2, port, projectDir, stdout2 = conso
112917
112958
  } else {
112918
112959
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
112919
112960
  const openerArgs = process.platform === "win32" ? ["/c", "start", "", endpoint.url] : [endpoint.url];
112920
- if ((await runProcess3(opener, openerArgs, { reject: false })).exitCode !== 0) {
112961
+ if ((await runProcess(opener, openerArgs, { reject: false })).exitCode !== 0) {
112921
112962
  throw new Error("Browser open command failed");
112922
112963
  }
112923
112964
  }
@@ -113182,10 +113223,10 @@ var init_tail = __esm({
113182
113223
  import { createReadStream as createReadStream2, existsSync as existsSync30 } from "node:fs";
113183
113224
  import { readdir as readdir5, readFile as readFile13, realpath as realpath2, stat as stat6, watch } from "node:fs/promises";
113184
113225
  import { createServer as createServer2 } from "node:http";
113185
- import { basename as basename19, dirname as dirname27, extname, join as join50, normalize as normalize3, sep as sep2 } from "node:path";
113226
+ import { basename as basename19, dirname as dirname27, extname, join as join51, normalize as normalize3, sep as sep2 } from "node:path";
113186
113227
  import { fileURLToPath as fileURLToPath6 } from "node:url";
113187
113228
  function runsDir() {
113188
- return join50(dataRoot(), "runs");
113229
+ return join51(dataRoot(), "runs");
113189
113230
  }
113190
113231
  function parseEvents(text) {
113191
113232
  const out = [];
@@ -113201,7 +113242,7 @@ function parseEvents(text) {
113201
113242
  }
113202
113243
  async function readEvents(runId) {
113203
113244
  try {
113204
- const text = await readFile13(join50(runsDir(), runId, "events.jsonl"), "utf8");
113245
+ const text = await readFile13(join51(runsDir(), runId, "events.jsonl"), "utf8");
113205
113246
  return parseEvents(text);
113206
113247
  } catch {
113207
113248
  return [];
@@ -113303,7 +113344,7 @@ function applyDeadman(status, startedAt, lastBeat) {
113303
113344
  }
113304
113345
  async function heartbeatMtime(runId) {
113305
113346
  try {
113306
- return (await stat6(join50(runsDir(), runId, ".heartbeat"))).mtimeMs;
113347
+ return (await stat6(join51(runsDir(), runId, ".heartbeat"))).mtimeMs;
113307
113348
  } catch {
113308
113349
  return 0;
113309
113350
  }
@@ -113334,7 +113375,7 @@ async function listRuns() {
113334
113375
  seen.add(runId);
113335
113376
  let eventsStat;
113336
113377
  try {
113337
- eventsStat = await stat6(join50(runsDir(), runId, "events.jsonl"));
113378
+ eventsStat = await stat6(join51(runsDir(), runId, "events.jsonl"));
113338
113379
  } catch {
113339
113380
  eventsStat = void 0;
113340
113381
  }
@@ -113350,7 +113391,7 @@ async function listRuns() {
113350
113391
  if (events.length === 0) {
113351
113392
  let mtime = 0;
113352
113393
  try {
113353
- mtime = (await stat6(join50(runsDir(), runId))).mtimeMs;
113394
+ mtime = (await stat6(join51(runsDir(), runId))).mtimeMs;
113354
113395
  } catch {
113355
113396
  }
113356
113397
  summaries.push({ summary: { runId, status: "unknown", agents: 0 }, mtime });
@@ -113377,7 +113418,7 @@ async function listRuns() {
113377
113418
  }
113378
113419
  function serveStatic(res, fileName) {
113379
113420
  const safe2 = normalize3(fileName).replace(/^(\.\.(?:[/\\]|$))+/, "");
113380
- const full = join50(WEB_DIR, safe2);
113421
+ const full = join51(WEB_DIR, safe2);
113381
113422
  if (!full.startsWith(WEB_DIR + sep2) && full !== WEB_DIR) {
113382
113423
  sendText(res, 403, "forbidden");
113383
113424
  return;
@@ -113526,10 +113567,10 @@ function sleepUnlessClosed(ms, isClosed) {
113526
113567
  });
113527
113568
  }
113528
113569
  function streamRun(req, res, runId) {
113529
- return tailJsonl(req, res, join50(runsDir(), runId, "events.jsonl"));
113570
+ return tailJsonl(req, res, join51(runsDir(), runId, "events.jsonl"));
113530
113571
  }
113531
113572
  function streamAgent(req, res, runId, index) {
113532
- return tailJsonl(req, res, join50(runsDir(), runId, "agents", `${index}.jsonl`));
113573
+ return tailJsonl(req, res, join51(runsDir(), runId, "agents", `${index}.jsonl`));
113533
113574
  }
113534
113575
  function parseChunks(text) {
113535
113576
  const out = [];
@@ -113545,7 +113586,7 @@ function parseChunks(text) {
113545
113586
  }
113546
113587
  async function readAgentChunks(runId, index) {
113547
113588
  try {
113548
- const text = await readFile13(join50(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113589
+ const text = await readFile13(join51(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113549
113590
  return parseChunks(text);
113550
113591
  } catch {
113551
113592
  return null;
@@ -113609,7 +113650,7 @@ async function handle(req, res) {
113609
113650
  const events = await readEvents(runId);
113610
113651
  if (events.length === 0) {
113611
113652
  try {
113612
- await stat6(join50(runsDir(), runId));
113653
+ await stat6(join51(runsDir(), runId));
113613
113654
  } catch {
113614
113655
  sendJson(res, 404, { error: "run not found", runId });
113615
113656
  return;
@@ -113686,8 +113727,8 @@ var init_serve = __esm({
113686
113727
  init_journal();
113687
113728
  init_tail();
113688
113729
  __dirname = dirname27(fileURLToPath6(import.meta.url));
113689
- WEB_CANDIDATES = [join50(__dirname, "web"), join50(__dirname, "..", "..", "viewer", "dist")];
113690
- WEB_DIR = WEB_CANDIDATES.find((path7) => existsSync30(path7)) ?? join50(__dirname, "web");
113730
+ WEB_CANDIDATES = [join51(__dirname, "web"), join51(__dirname, "..", "..", "viewer", "dist")];
113731
+ WEB_DIR = WEB_CANDIDATES.find((path7) => existsSync30(path7)) ?? join51(__dirname, "web");
113691
113732
  sseClients = 0;
113692
113733
  STALE_MS = 2e4;
113693
113734
  summaryCache = /* @__PURE__ */ new Map();
@@ -113721,15 +113762,15 @@ import { spawn as spawn9 } from "node:child_process";
113721
113762
  import {
113722
113763
  copyFileSync as copyFileSync3,
113723
113764
  existsSync as existsSync31,
113724
- mkdirSync as mkdirSync17,
113765
+ mkdirSync as mkdirSync18,
113725
113766
  readdirSync as readdirSync5,
113726
- readFileSync as readFileSync27,
113767
+ readFileSync as readFileSync26,
113727
113768
  realpathSync as realpathSync6,
113728
113769
  rmSync as rmSync9,
113729
113770
  statSync as statSync10
113730
113771
  } from "node:fs";
113731
113772
  import { get as httpGet } from "node:http";
113732
- import { dirname as dirname28, join as join51, resolve as resolve31, sep as sep3 } from "node:path";
113773
+ import { dirname as dirname28, join as join52, resolve as resolve31, sep as sep3 } from "node:path";
113733
113774
  import { fileURLToPath as fileURLToPath7 } from "node:url";
113734
113775
  function parseArgs(argv) {
113735
113776
  const flags = { _: [] };
@@ -113833,8 +113874,6 @@ async function main(argv = process.argv.slice(2), options = {}) {
113833
113874
  return cmdValidate(flags, options.registryRoots);
113834
113875
  case "doctor":
113835
113876
  return cmdDoctor();
113836
- case "install-skill":
113837
- return cmdInstallSkillRetired();
113838
113877
  case "guide":
113839
113878
  return cmdGuide(options.skillPath);
113840
113879
  case void 0:
@@ -113864,7 +113903,7 @@ async function cmdServe(flags) {
113864
113903
  }
113865
113904
  });
113866
113905
  process.stderr.write(
113867
- `viewer: ${url2} (reading ${join51(dataRoot(), "runs")})
113906
+ `viewer: ${url2} (reading ${join52(dataRoot(), "runs")})
113868
113907
  ${idleShutdown ? "idle-shutdown on; " : ""}ctrl-c to stop
113869
113908
  `
113870
113909
  );
@@ -113924,7 +113963,7 @@ function openBrowser(url2) {
113924
113963
  }
113925
113964
  }
113926
113965
  async function cmdRuns(flags) {
113927
- const dir = join51(dataRoot(), "runs");
113966
+ const dir = join52(dataRoot(), "runs");
113928
113967
  if (!existsSync31(dir)) {
113929
113968
  console.log("(no runs yet)");
113930
113969
  return;
@@ -113932,12 +113971,12 @@ async function cmdRuns(flags) {
113932
113971
  const ids = readdirSync5(dir).filter((d) => d.startsWith("wf_"));
113933
113972
  if (flags.prune === true) {
113934
113973
  const keep = intFlag(flags, "keep") ?? 50;
113935
- const byAge = ids.map((id) => ({ id, at: statSync10(join51(dir, id)).mtimeMs })).sort((a3, b) => b.at - a3.at);
113974
+ const byAge = ids.map((id) => ({ id, at: statSync10(join52(dir, id)).mtimeMs })).sort((a3, b) => b.at - a3.at);
113936
113975
  const remove = byAge.slice(keep);
113937
113976
  let bytes = 0;
113938
113977
  for (const r2 of remove) {
113939
- bytes += dirSize(join51(dir, r2.id));
113940
- rmSync9(join51(dir, r2.id), { recursive: true, force: true });
113978
+ bytes += dirSize(join52(dir, r2.id));
113979
+ rmSync9(join52(dir, r2.id), { recursive: true, force: true });
113941
113980
  }
113942
113981
  console.log(
113943
113982
  `pruned ${remove.length} run(s) (${(bytes / 1e6).toFixed(1)} MB); kept ${Math.min(keep, byAge.length)} newest`
@@ -113948,8 +113987,8 @@ async function cmdRuns(flags) {
113948
113987
  const stale2 = ids.filter((id) => isStaleRun(dir, id));
113949
113988
  let bytes = 0;
113950
113989
  for (const id of stale2) {
113951
- bytes += dirSize(join51(dir, id));
113952
- rmSync9(join51(dir, id), { recursive: true, force: true });
113990
+ bytes += dirSize(join52(dir, id));
113991
+ rmSync9(join52(dir, id), { recursive: true, force: true });
113953
113992
  }
113954
113993
  console.log(`pruned ${stale2.length} stale run(s) (${(bytes / 1e6).toFixed(1)} MB)`);
113955
113994
  return;
@@ -113958,7 +113997,7 @@ async function cmdRuns(flags) {
113958
113997
  const loaded = Journal.load(id);
113959
113998
  const name = loaded.meta?.workflowFile?.split("/").pop() ?? "";
113960
113999
  const agents = loaded.results.size;
113961
- const resultPath = join51(dir, id, "result.json");
114000
+ const resultPath = join52(dir, id, "result.json");
113962
114001
  const done = existsSync31(resultPath);
113963
114002
  const status = done ? "completed" : isStaleRun(dir, id) ? "stale" : "?";
113964
114003
  return { id, name, agents, status, at: loaded.meta?.createdAt ?? 0 };
@@ -113967,10 +114006,10 @@ async function cmdRuns(flags) {
113967
114006
  for (const r2 of rows) console.log(`${r2.id} ${r2.status.padEnd(10)} ${String(r2.agents).padStart(3)} agents ${r2.name}`);
113968
114007
  }
113969
114008
  function isStaleRun(runsBase, id) {
113970
- const rd = join51(runsBase, id);
114009
+ const rd = join52(runsBase, id);
113971
114010
  let lastRunStatus;
113972
114011
  try {
113973
- const lines = readFileSync27(join51(rd, "events.jsonl"), "utf8").trim().split("\n");
114012
+ const lines = readFileSync26(join52(rd, "events.jsonl"), "utf8").trim().split("\n");
113974
114013
  for (let i3 = lines.length - 1; i3 >= 0; i3--) {
113975
114014
  const m = lines[i3]?.match(/"type":"run","status":"([a-z]+)"/);
113976
114015
  if (m) {
@@ -113984,7 +114023,7 @@ function isStaleRun(runsBase, id) {
113984
114023
  if (lastRunStatus !== "started") return false;
113985
114024
  let beat = 0;
113986
114025
  try {
113987
- beat = statSync10(join51(rd, ".heartbeat")).mtimeMs;
114026
+ beat = statSync10(join52(rd, ".heartbeat")).mtimeMs;
113988
114027
  } catch {
113989
114028
  }
113990
114029
  return Date.now() - beat > 2e4;
@@ -113992,7 +114031,7 @@ function isStaleRun(runsBase, id) {
113992
114031
  function dirSize(dir) {
113993
114032
  let total = 0;
113994
114033
  for (const e of readdirSync5(dir, { withFileTypes: true })) {
113995
- const p = join51(dir, e.name);
114034
+ const p = join52(dir, e.name);
113996
114035
  total += e.isDirectory() ? dirSize(p) : statSync10(p).size;
113997
114036
  }
113998
114037
  return total;
@@ -114008,7 +114047,7 @@ async function cmdRun(flags, registryRoots) {
114008
114047
  }
114009
114048
  const resolvedFile = resolveFileOrName(file2, registryRoots);
114010
114049
  const overrides = {};
114011
- const provider = enumFlag(flags, "provider", PROVIDERS2);
114050
+ const provider = enumFlag(flags, "provider", PROVIDERS);
114012
114051
  if (provider) overrides.provider = provider;
114013
114052
  const model = str(flags.model);
114014
114053
  if (model) overrides.model = model;
@@ -114037,7 +114076,7 @@ async function cmdRun(flags, registryRoots) {
114037
114076
  if (argsFile) {
114038
114077
  let raw2;
114039
114078
  try {
114040
- raw2 = readFileSync27(resolve31(argsFile), "utf8");
114079
+ raw2 = readFileSync26(resolve31(argsFile), "utf8");
114041
114080
  } catch {
114042
114081
  throw new UsageError2(`--args-file not found: ${argsFile}`);
114043
114082
  }
@@ -114101,7 +114140,7 @@ async function cmdValidate(flags, registryRoots) {
114101
114140
  process.exitCode = 1;
114102
114141
  return;
114103
114142
  }
114104
- const source = readFileSync27(resolveFileOrName(file2, registryRoots), "utf8");
114143
+ const source = readFileSync26(resolveFileOrName(file2, registryRoots), "utf8");
114105
114144
  const { meta: meta3 } = parseWorkflow(source);
114106
114145
  console.log(`ok: "${meta3.name}" \u2014 ${meta3.description}`);
114107
114146
  if (meta3.phases) console.log(`phases: ${meta3.phases.map((p) => p.title).join(" \u2192 ")}`);
@@ -114139,20 +114178,20 @@ async function cmdSave(flags) {
114139
114178
  }
114140
114179
  const absFile = resolve31(file2);
114141
114180
  if (!existsSync31(absFile)) throw new UsageError2(`file not found: ${file2}`);
114142
- const { meta: meta3 } = parseWorkflow(readFileSync27(absFile, "utf8"));
114181
+ const { meta: meta3 } = parseWorkflow(readFileSync26(absFile, "utf8"));
114143
114182
  const name = meta3.name;
114144
114183
  if (name.includes("/") || name.includes("\\") || name.includes("..") || name.startsWith(".") || name.includes("\0")) {
114145
114184
  throw new UsageError2(`meta.name is not a safe filename: "${name}"`);
114146
114185
  }
114147
114186
  const useProject = flags.project === true;
114148
114187
  const destDir = useProject ? projectPaths(process.cwd()).workflows : globalPaths().workflows;
114149
- const dest = join51(destDir, `${name}.workflow.js`);
114188
+ const dest = join52(destDir, `${name}.workflow.js`);
114150
114189
  if (existsSync31(dest) && flags.force !== true) {
114151
114190
  throw new UsageError2(
114152
114191
  `${useProject ? "project" : "user"} workflow "${name}" already exists at ${dest} \u2014 use --force to overwrite`
114153
114192
  );
114154
114193
  }
114155
- mkdirSync17(destDir, { recursive: true });
114194
+ mkdirSync18(destDir, { recursive: true });
114156
114195
  copyFileSync3(absFile, dest);
114157
114196
  console.log(`saved "${name}" \u2192 ${dest}`);
114158
114197
  }
@@ -114183,7 +114222,7 @@ async function cmdDoctor() {
114183
114222
  const codexBin = process.env.CODEX_BIN ?? "codex";
114184
114223
  const opencodeBin = process.env.OPENCODE_BIN ?? "opencode";
114185
114224
  const piBin = process.env.PI_BIN ?? "pi";
114186
- const piScratch = mkdtempSync4(join51(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114225
+ const piScratch = mkdtempSync4(join52(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114187
114226
  let piOut;
114188
114227
  try {
114189
114228
  piOut = check4(piBin, ["--version"], { env: { ...process.env, PI_CODING_AGENT_DIR: piScratch }, cwd: tmpdir6() });
@@ -114201,31 +114240,20 @@ async function cmdDoctor() {
114201
114240
  console.log(` data dir : ${dataRoot()}`);
114202
114241
  }
114203
114242
  function readSkill(skillPath) {
114204
- if (skillPath) return readFileSync27(skillPath, "utf8");
114243
+ if (skillPath) return readFileSync26(skillPath, "utf8");
114205
114244
  const here = dirname28(fileURLToPath7(import.meta.url));
114206
114245
  const candidates = [
114207
- join51(here, "..", "skills", "portta-workflows", "SKILL.md"),
114208
- join51(here, "..", "..", "..", "skills", "portta-workflows", "SKILL.md"),
114209
- join51(here, "..", "..", "..", "..", "..", "..", "skills", "portta-workflows", "SKILL.md")
114246
+ join52(here, "..", "skills", "portta-workflows", "SKILL.md"),
114247
+ join52(here, "..", "..", "..", "skills", "portta-workflows", "SKILL.md"),
114248
+ join52(here, "..", "..", "..", "..", "..", "..", "skills", "portta-workflows", "SKILL.md")
114210
114249
  ];
114211
114250
  const src = candidates.find((candidate) => existsSync31(candidate));
114212
114251
  if (!src) throw new Error(`skill source not found at ${candidates.join(" or ")}`);
114213
- return readFileSync27(src, "utf8");
114252
+ return readFileSync26(src, "utf8");
114214
114253
  }
114215
114254
  async function cmdGuide(skillPath) {
114216
114255
  process.stdout.write(readSkill(skillPath).replace(/^---\n[\s\S]*?\n---\n+/, ""));
114217
114256
  }
114218
- function cmdInstallSkillRetired() {
114219
- console.error(
114220
- `${CLI_NAME} workflows install-skill has been retired. Install the skill with the Skills CLI instead:
114221
-
114222
- npx skills add codions-labs/portta --skill portta-workflows -g
114223
-
114224
- It supports Claude Code, Codex, OpenCode, Cursor, Zed and others, symlinks by default,
114225
- and \`npx skills update\` keeps every agent current. See https://www.skills.sh.`
114226
- );
114227
- process.exitCode = 1;
114228
- }
114229
114257
  function printHelp() {
114230
114258
  console.log(`${APP_NAME} workflows \u2014 run JS workflow files that orchestrate coding agents
114231
114259
 
@@ -114286,7 +114314,7 @@ function invokedDirectly() {
114286
114314
  return false;
114287
114315
  }
114288
114316
  }
114289
- var UsageError2, BOOLEAN_FLAGS, PROVIDERS2, SANDBOXES, EFFORTS;
114317
+ var UsageError2, BOOLEAN_FLAGS, PROVIDERS, SANDBOXES, EFFORTS;
114290
114318
  var init_cli = __esm({
114291
114319
  "../host/src/modules/taskflow/workflows/cli.ts"() {
114292
114320
  "use strict";
@@ -114321,7 +114349,7 @@ var init_cli = __esm({
114321
114349
  "project",
114322
114350
  "force"
114323
114351
  ]);
114324
- PROVIDERS2 = PROVIDER_IDS;
114352
+ PROVIDERS = PROVIDER_IDS;
114325
114353
  SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
114326
114354
  EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
114327
114355
  if (invokedDirectly()) {
@@ -116413,7 +116441,7 @@ var RemovalPreview = named(
116413
116441
  "RemovalPreview"
116414
116442
  );
116415
116443
  var LiveEventKind = named(
116416
- external_exports.enum(["container", "network", "bridge", "health", "project", "config", "hello", "task", "session", "activity", "repository"]),
116444
+ external_exports.enum(["container", "network", "bridge", "health", "project", "config", "hello", "session", "activity", "repository"]),
116417
116445
  "LiveEventKind"
116418
116446
  );
116419
116447
  var LiveEvent = named(
@@ -117449,131 +117477,7 @@ var {
117449
117477
 
117450
117478
  // src/cli.ts
117451
117479
  init_errors3();
117452
-
117453
- // src/process.ts
117454
- init_execa();
117455
- import { spawn as spawn2 } from "node:child_process";
117456
- import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
117457
- var reporting = {};
117458
- function setProcessReporter(options) {
117459
- reporting = options;
117460
- }
117461
- function effectiveStdio(requested) {
117462
- if (requested === "inherit") return "inherit";
117463
- if (reporting.quiet) return "pipe";
117464
- if (reporting.verbose) return "stream";
117465
- return requested;
117466
- }
117467
- function outputTargets(mode) {
117468
- if (mode !== "stream") return { stdio: mode };
117469
- return {
117470
- stdin: "pipe",
117471
- stdout: reporting.json ? "pipe" : ["pipe", "inherit"],
117472
- stderr: ["pipe", "inherit"]
117473
- };
117474
- }
117475
- var HEARTBEAT_FIRST_MS = 1e4;
117476
- var HEARTBEAT_EVERY_MS = 3e4;
117477
- var HEARTBEAT_HINT_MS = 18e4;
117478
- function elapsed(sinceMs) {
117479
- const seconds = Math.round((Date.now() - sinceMs) / 1e3);
117480
- if (seconds < 60) return `${seconds}s`;
117481
- return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, "0")}s`;
117482
- }
117483
- function describeCommand(file2, args, limit = 88) {
117484
- const words = [];
117485
- for (let index = 0; index < args.length; index += 1) {
117486
- const argument = args[index] ?? "";
117487
- if (argument === "-f" || argument === "--file") {
117488
- index += 1;
117489
- continue;
117490
- }
117491
- words.push(argument);
117492
- }
117493
- const line4 = [file2, ...words].join(" ");
117494
- return line4.length <= limit ? line4 : `${line4.slice(0, limit - 1)}\u2026`;
117495
- }
117496
- function startHeartbeat(file2, args) {
117497
- if (reporting.quiet) return () => {
117498
- };
117499
- const started = Date.now();
117500
- const label3 = describeCommand(file2, args);
117501
- let hinted = false;
117502
- const announce = () => {
117503
- process.stderr.write(`wait still running: ${label3} (${elapsed(started)})
117504
- `);
117505
- if (!hinted && Date.now() - started >= HEARTBEAT_HINT_MS) {
117506
- hinted = true;
117507
- process.stderr.write(" -> a first build of the panel image takes several minutes; Ctrl-C is safe, and --verbose shows its output\n");
117508
- }
117509
- };
117510
- let repeat;
117511
- const first = setTimeout(() => {
117512
- announce();
117513
- repeat = setInterval(announce, HEARTBEAT_EVERY_MS);
117514
- repeat.unref?.();
117515
- }, HEARTBEAT_FIRST_MS);
117516
- first.unref?.();
117517
- return () => {
117518
- clearTimeout(first);
117519
- if (repeat) clearInterval(repeat);
117520
- };
117521
- }
117522
- async function runProcess(file2, args = [], options = {}) {
117523
- const mode = effectiveStdio(options.stdio ?? "pipe");
117524
- const execaOptions = {
117525
- cwd: options.cwd,
117526
- env: options.env,
117527
- input: options.input,
117528
- reject: options.reject ?? true,
117529
- shell: false,
117530
- timeout: options.timeout,
117531
- ...outputTargets(mode)
117532
- };
117533
- const stopHeartbeat = mode === "pipe" ? startHeartbeat(file2, args) : () => {
117534
- };
117535
- try {
117536
- const result = await execa(file2, [...args], execaOptions);
117537
- return {
117538
- stdout: typeof result.stdout === "string" ? result.stdout : "",
117539
- stderr: typeof result.stderr === "string" ? result.stderr : "",
117540
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
117541
- failed: result.failed
117542
- };
117543
- } finally {
117544
- stopHeartbeat();
117545
- }
117546
- }
117547
- var PROCESS_POLICY = Object.freeze({ shell: false, argumentArraysOnly: true });
117548
- async function runForeground(file2, args, options = {}) {
117549
- const child = execa(file2, [...args], { cwd: options.cwd, env: options.env, stdio: "inherit", reject: false, shell: false });
117550
- const forwarded = ["SIGINT", "SIGTERM", "SIGHUP"].map((signal) => [signal, () => {
117551
- child.kill(signal);
117552
- }]);
117553
- for (const [signal, forward] of forwarded) process.on(signal, forward);
117554
- try {
117555
- const result = await child;
117556
- return result.exitCode ?? (result.signal ? 1 : 0);
117557
- } finally {
117558
- for (const [signal, forward] of forwarded) process.off(signal, forward);
117559
- }
117560
- }
117561
- function spawnDetached(file2, args, options = {}) {
117562
- const log3 = options.logFile ? openSync2(options.logFile, "a", 384) : null;
117563
- try {
117564
- const child = spawn2(file2, [...args], {
117565
- cwd: options.cwd,
117566
- env: options.env,
117567
- shell: false,
117568
- detached: true,
117569
- stdio: log3 === null ? "ignore" : ["ignore", log3, log3]
117570
- });
117571
- child.unref();
117572
- return child.pid;
117573
- } finally {
117574
- if (log3 !== null) closeSync2(log3);
117575
- }
117576
- }
117480
+ init_process();
117577
117481
 
117578
117482
  // src/commands/access.ts
117579
117483
  init_src();
@@ -117601,6 +117505,7 @@ init_context();
117601
117505
  // src/docker.ts
117602
117506
  init_zod();
117603
117507
  init_errors3();
117508
+ init_process();
117604
117509
  var Identifier = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
117605
117510
  function identifier(value3, kind = "Docker identifier") {
117606
117511
  if (!Identifier.test(value3)) throw new UsageError(`invalid ${kind}: ${value3}`);
@@ -117618,12 +117523,10 @@ var InspectSchema = external_exports.object({
117618
117523
  Ports: external_exports.record(external_exports.string(), external_exports.array(external_exports.object({ HostIp: external_exports.string().optional(), HostPort: external_exports.string().optional() })).nullable()).nullable().optional()
117619
117524
  }).passthrough()
117620
117525
  }).passthrough();
117621
- async function dockerAvailable() {
117622
- const result = await runProcess("docker", ["info"], { reject: false });
117623
- return result.exitCode === 0;
117624
- }
117625
117526
  async function requireDocker() {
117626
- if (!await dockerAvailable()) throw new PreconditionError("cannot talk to the Docker daemon", "start Docker or check DOCKER_HOST");
117527
+ const result = await runProcess("docker", ["info"], { reject: false });
117528
+ if (result.error) throw new PreconditionError("the docker CLI is not installed", "install Docker Engine 24 or newer; Portta never installs Docker or invokes a system package manager");
117529
+ if (result.exitCode !== 0) throw new PreconditionError("cannot talk to the Docker daemon", "start Docker or check DOCKER_HOST");
117627
117530
  }
117628
117531
  async function dockerOperatingSystem() {
117629
117532
  const result = await runProcess("docker", ["info", "--format", "{{.OperatingSystem}}"], { reject: false, timeout: 8e3 });
@@ -117693,6 +117596,7 @@ async function isManagedContainer(id) {
117693
117596
 
117694
117597
  // src/commands/access.ts
117695
117598
  init_errors3();
117599
+ init_process();
117696
117600
  function globals(command) {
117697
117601
  return command.optsWithGlobals();
117698
117602
  }
@@ -117872,21 +117776,50 @@ async function serviceUnpublish(alias, options, command) {
117872
117776
  }
117873
117777
 
117874
117778
  // src/commands/clients.ts
117875
- import { copyFileSync as copyFileSync2, existsSync as existsSync22, mkdirSync as mkdirSync14, rmSync as rmSync5, statSync as statSync9 } from "node:fs";
117876
- import { basename as basename13, dirname as dirname22, join as join45 } from "node:path";
117779
+ import { copyFileSync as copyFileSync2, existsSync as existsSync22, mkdirSync as mkdirSync15, rmSync as rmSync5, statSync as statSync9 } from "node:fs";
117780
+ import { basename as basename13, dirname as dirname22, join as join46 } from "node:path";
117877
117781
 
117878
117782
  // src/commands/web.ts
117879
117783
  init_src();
117880
117784
  init_src();
117881
117785
  init_context();
117882
- import { chmodSync as chmodSync8, mkdirSync as mkdirSync13 } from "node:fs";
117883
- import { join as join44 } from "node:path";
117786
+ import { mkdirSync as mkdirSync14 } from "node:fs";
117787
+ import { join as join45 } from "node:path";
117884
117788
  init_errors3();
117789
+ init_process();
117790
+
117791
+ // src/installation-directories.ts
117792
+ import { chmodSync as chmodSync4, existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
117793
+ import { join as join6 } from "node:path";
117794
+ var INSTALLATION_DIRECTORIES = [
117795
+ { path: "config/traefik/dynamic", mode: 493 },
117796
+ { path: "config/tls", mode: 493 },
117797
+ { path: "state/auth", mode: 448 },
117798
+ { path: "state/ssh", mode: 448 },
117799
+ { path: "state/runner", mode: 448 },
117800
+ { path: "state/cloudflared", mode: 448 },
117801
+ { path: "state/traefik/acme", mode: 448 },
117802
+ { path: "state/access", mode: 493 },
117803
+ { path: "state/tailscale", mode: 493 },
117804
+ { path: "state/git", mode: 493 },
117805
+ { path: "state/metrics", mode: 493 },
117806
+ { path: "state/environment", mode: 493 },
117807
+ { path: "state/logs", mode: 493 }
117808
+ ];
117809
+ function ensureInstallationDirectories(root2) {
117810
+ for (const { path: path7, mode } of INSTALLATION_DIRECTORIES) {
117811
+ const full = join6(root2, path7);
117812
+ const created = !existsSync5(full);
117813
+ mkdirSync4(full, { recursive: true });
117814
+ if (created || mode === 448) chmodSync4(full, mode);
117815
+ }
117816
+ }
117885
117817
 
117886
117818
  // src/local-release.ts
117887
117819
  init_src();
117888
117820
  init_errors3();
117889
- import { join as join6 } from "node:path";
117821
+ init_process();
117822
+ import { join as join7 } from "node:path";
117890
117823
  async function requireLocalRelease(context) {
117891
117824
  if (context.env["PORTTA_LOCAL_RELEASE"] !== "true") return;
117892
117825
  const missing = [];
@@ -117900,7 +117833,7 @@ async function requireLocalRelease(context) {
117900
117833
  }
117901
117834
  function selectLocalRelease(context) {
117902
117835
  const image = porttaImages(context.version).runtime;
117903
- patchEnvFile(join6(context.root, ".env"), {
117836
+ patchEnvFile(join7(context.root, ".env"), {
117904
117837
  PORTTA_AUTH_IMAGE: image,
117905
117838
  PORTTA_WEB_IMAGE: image,
117906
117839
  PORTTA_WEB_BUILD: "false",
@@ -117911,13 +117844,15 @@ function selectLocalRelease(context) {
117911
117844
  // src/commands/repos.ts
117912
117845
  init_src();
117913
117846
  import { createHash as createHash2 } from "node:crypto";
117914
- import { chmodSync as chmodSync4, existsSync as existsSync6, mkdirSync as mkdirSync4, readdirSync, readFileSync as readFileSync8, realpathSync, statSync as statSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
117915
- import { basename, join as join7 } from "node:path";
117847
+ import { chmodSync as chmodSync5, existsSync as existsSync7, mkdirSync as mkdirSync5, readdirSync, readFileSync as readFileSync8, realpathSync, statSync as statSync2, unlinkSync as unlinkSync4, writeFileSync as writeFileSync5 } from "node:fs";
117848
+ import { basename, join as join8 } from "node:path";
117916
117849
  init_context();
117917
117850
  init_errors3();
117851
+ init_process();
117918
117852
 
117919
117853
  // src/commands/git.ts
117920
- import { existsSync as existsSync5 } from "node:fs";
117854
+ init_process();
117855
+ import { existsSync as existsSync6 } from "node:fs";
117921
117856
  async function git(cwd, args) {
117922
117857
  const result = await runProcess("git", ["-C", cwd, ...args], { reject: false });
117923
117858
  return result.exitCode === 0 ? result.stdout.trim() : null;
@@ -117968,7 +117903,7 @@ function normalizePulls(raw2) {
117968
117903
  async function collectGitProject(project2, path7, declaredRemote = "", withPrs = false, cachedForge) {
117969
117904
  const collectedAt = Math.floor(Date.now() / 1e3);
117970
117905
  const base2 = { project: project2, workingDir: path7, collectedAt };
117971
- if (!await git(path7, ["rev-parse", "--is-inside-work-tree"])) return { ...base2, git: null, reason: existsSync5(path7) ? "not a git repository" : "directory not readable from the host" };
117906
+ if (!await git(path7, ["rev-parse", "--is-inside-work-tree"])) return { ...base2, git: null, reason: existsSync6(path7) ? "not a git repository" : "directory not readable from the host" };
117972
117907
  const branchName = await git(path7, ["rev-parse", "--abbrev-ref", "HEAD"]);
117973
117908
  const detached = branchName === "HEAD";
117974
117909
  const sha = await git(path7, ["rev-parse", "HEAD"]) ?? "";
@@ -118090,7 +118025,7 @@ async function findCandidates(options, env, registered = []) {
118090
118025
  }
118091
118026
  if (!options.environment && !options.path) {
118092
118027
  for (const path7 of registered) {
118093
- if (!existsSync6(path7)) continue;
118028
+ if (!existsSync7(path7)) continue;
118094
118029
  const root2 = await gitRootOf(path7);
118095
118030
  if (root2) add(root2);
118096
118031
  }
@@ -118104,7 +118039,7 @@ async function findCandidates(options, env, registered = []) {
118104
118039
  home2 = null;
118105
118040
  }
118106
118041
  }
118107
- if (home2 && !options.environment && !options.path && existsSync6(home2)) {
118042
+ if (home2 && !options.environment && !options.path && existsSync7(home2)) {
118108
118043
  let entries = [];
118109
118044
  try {
118110
118045
  entries = readdirSync(home2);
@@ -118113,9 +118048,9 @@ async function findCandidates(options, env, registered = []) {
118113
118048
  }
118114
118049
  for (const entry of entries) {
118115
118050
  if (!firstLevelCandidateName(entry)) continue;
118116
- const path7 = join7(home2, entry);
118051
+ const path7 = join8(home2, entry);
118117
118052
  if (!isDirectory(path7)) continue;
118118
- if (existsSync6(join7(path7, ".git"))) {
118053
+ if (existsSync7(join8(path7, ".git"))) {
118119
118054
  const root2 = await gitRootOf(path7);
118120
118055
  if (root2) add(root2);
118121
118056
  continue;
@@ -118128,8 +118063,8 @@ async function findCandidates(options, env, registered = []) {
118128
118063
  }
118129
118064
  for (const child of children) {
118130
118065
  if (!firstLevelCandidateName(child)) continue;
118131
- const childPath = join7(path7, child);
118132
- if (!isDirectory(childPath) || !existsSync6(join7(childPath, ".git"))) continue;
118066
+ const childPath = join8(path7, child);
118067
+ if (!isDirectory(childPath) || !existsSync7(join8(childPath, ".git"))) continue;
118133
118068
  const root2 = await gitRootOf(childPath);
118134
118069
  if (root2) add(root2);
118135
118070
  }
@@ -118150,8 +118085,8 @@ function sha256(content) {
118150
118085
  async function collectInstructions(root2) {
118151
118086
  const paths3 = [...INSTRUCTION_FILES];
118152
118087
  for (const { directory, extension } of INSTRUCTION_DIRECTORIES) {
118153
- const dir = join7(root2, directory);
118154
- if (!existsSync6(dir)) continue;
118088
+ const dir = join8(root2, directory);
118089
+ if (!existsSync7(dir)) continue;
118155
118090
  try {
118156
118091
  for (const entry of readdirSync(dir).sort()) {
118157
118092
  if (entry.endsWith(extension)) paths3.push(`${directory}/${entry}`);
@@ -118162,8 +118097,8 @@ async function collectInstructions(root2) {
118162
118097
  const files = [];
118163
118098
  for (const relative6 of paths3) {
118164
118099
  if (!isInstructionPath(relative6)) continue;
118165
- const absolute = join7(root2, relative6);
118166
- if (!existsSync6(absolute)) continue;
118100
+ const absolute = join8(root2, relative6);
118101
+ if (!existsSync7(absolute)) continue;
118167
118102
  let size;
118168
118103
  let modifiedAt;
118169
118104
  try {
@@ -118212,7 +118147,7 @@ async function collectRepository(candidate, options, cachedForge) {
118212
118147
  function writeSecret(path7, value3) {
118213
118148
  writeFileSync5(path7, `${JSON.stringify(value3, null, 2)}
118214
118149
  `, { mode: 384 });
118215
- chmodSync4(path7, 384);
118150
+ chmodSync5(path7, 384);
118216
118151
  }
118217
118152
  function readJson(path7) {
118218
118153
  try {
@@ -118224,18 +118159,18 @@ function readJson(path7) {
118224
118159
  async function scanRepositories(options = {}, profile, output2 = new Output({ quiet: true })) {
118225
118160
  if (options.forgeTtl !== void 0 && !/^\d+$/.test(options.forgeTtl)) throw new UsageError("--forge-ttl must be a number of seconds");
118226
118161
  const context = gatewayContext({ profile });
118227
- const directory = join7(context.root, "state/git");
118228
- mkdirSync4(directory, { recursive: true, mode: 448 });
118162
+ const directory = join8(context.root, "state/git");
118163
+ mkdirSync5(directory, { recursive: true, mode: 448 });
118229
118164
  const partial2 = Boolean(options.environment || options.path);
118230
118165
  const registered = partial2 ? [] : await registeredRepositoryPaths(context, (line4) => output2.detail(line4));
118231
118166
  const { candidates, home: home2 } = await findCandidates(options, context.env, registered);
118232
118167
  if (candidates.size > 0) {
118233
- output2.progress(`scanning ${candidates.size} ${candidates.size === 1 ? "repository" : "repositories"}${home2 && existsSync6(home2) ? ` under ${home2}` : ""}`);
118168
+ output2.progress(`scanning ${candidates.size} ${candidates.size === 1 ? "repository" : "repositories"}${home2 && existsSync7(home2) ? ` under ${home2}` : ""}`);
118234
118169
  }
118235
118170
  const forgeTtl = Number(options.forgeTtl ?? 300);
118236
118171
  const now = Math.floor(Date.now() / 1e3);
118237
118172
  const homeReal = home2 ? safeRealpath(home2) : null;
118238
- const previous = partial2 ? readJson(join7(directory, SCAN_INDEX_FILE)) : null;
118173
+ const previous = partial2 ? readJson(join8(directory, SCAN_INDEX_FILE)) : null;
118239
118174
  const entries = /* @__PURE__ */ new Map();
118240
118175
  const environments = {};
118241
118176
  if (previous && previous.version === SCAN_VERSION) {
@@ -118245,9 +118180,9 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118245
118180
  const repositories = [];
118246
118181
  for (const candidate of candidates.values()) {
118247
118182
  const key = repositoryKey(candidate.root);
118248
- const target = join7(directory, `${key}.json`);
118183
+ const target = join8(directory, `${key}.json`);
118249
118184
  let cachedForge;
118250
- if (options.withPrs && forgeTtl > 0 && existsSync6(target)) {
118185
+ if (options.withPrs && forgeTtl > 0 && existsSync7(target)) {
118251
118186
  const forge = readJson(target)?.["forge"];
118252
118187
  if (forge && now - Number(forge["collectedAt"] ?? 0) < forgeTtl) cachedForge = forge;
118253
118188
  }
@@ -118276,7 +118211,7 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118276
118211
  repositories: [...entries.values()].sort((a3, b) => a3.name.localeCompare(b.name)),
118277
118212
  environments
118278
118213
  };
118279
- writeSecret(join7(directory, SCAN_INDEX_FILE), index);
118214
+ writeSecret(join8(directory, SCAN_INDEX_FILE), index);
118280
118215
  return { index, repositories };
118281
118216
  }
118282
118217
  async function reposScan(options, command) {
@@ -118286,8 +118221,8 @@ async function reposScan(options, command) {
118286
118221
  else output2.progress(`scanned ${result.repositories.length} repositor${result.repositories.length === 1 ? "y" : "ies"}`);
118287
118222
  }
118288
118223
  function readScanIndex(root2) {
118289
- const path7 = join7(root2, "state/git", SCAN_INDEX_FILE);
118290
- if (!existsSync6(path7)) return null;
118224
+ const path7 = join8(root2, "state/git", SCAN_INDEX_FILE);
118225
+ if (!existsSync7(path7)) return null;
118291
118226
  const value3 = readJson(path7);
118292
118227
  if (value3 === null) throw new CliError(`${path7} is not readable JSON`, void 0, "run `portta repos scan` to rewrite it");
118293
118228
  return value3["version"] === SCAN_VERSION ? value3 : null;
@@ -118298,7 +118233,7 @@ async function reposStatus(command) {
118298
118233
  const output2 = new Output(globals2(command));
118299
118234
  const now = Math.floor(Date.now() / 1e3);
118300
118235
  const repositories = (index?.repositories ?? []).map((entry) => {
118301
- const scan = readJson(join7(context.root, "state/git", `${entry.key}.json`));
118236
+ const scan = readJson(join8(context.root, "state/git", `${entry.key}.json`));
118302
118237
  const gitInfo = scan?.["git"] ?? null;
118303
118238
  return {
118304
118239
  ...entry,
@@ -118322,12 +118257,12 @@ async function reposStatus(command) {
118322
118257
  }
118323
118258
  async function reposClear(command) {
118324
118259
  const context = gatewayContext({ profile: globals2(command).profile });
118325
- const directory = join7(context.root, "state/git");
118326
- if (!existsSync6(directory)) return;
118260
+ const directory = join8(context.root, "state/git");
118261
+ if (!existsSync7(directory)) return;
118327
118262
  let count2 = 0;
118328
118263
  for (const file2 of readdirSync(directory)) {
118329
118264
  if (file2.endsWith(".json")) {
118330
- unlinkSync4(join7(directory, file2));
118265
+ unlinkSync4(join8(directory, file2));
118331
118266
  count2++;
118332
118267
  }
118333
118268
  }
@@ -118345,9 +118280,11 @@ async function refreshRepositories(profile, output2) {
118345
118280
  init_src();
118346
118281
  init_src2();
118347
118282
  init_context();
118283
+ init_version();
118348
118284
  init_errors3();
118285
+ init_process();
118349
118286
  import { existsSync as existsSync21 } from "node:fs";
118350
- import { join as join43 } from "node:path";
118287
+ import { join as join44 } from "node:path";
118351
118288
 
118352
118289
  // src/metrics/collect.ts
118353
118290
  init_src();
@@ -118356,46 +118293,46 @@ import { loadavg } from "node:os";
118356
118293
 
118357
118294
  // src/metrics/store.ts
118358
118295
  init_src();
118359
- import { chmodSync as chmodSync7, existsSync as existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync17, renameSync as renameSync4, statSync as statSync7, writeFileSync as writeFileSync11 } from "node:fs";
118296
+ import { chmodSync as chmodSync8, existsSync as existsSync16, mkdirSync as mkdirSync13, readFileSync as readFileSync17, renameSync as renameSync4, statSync as statSync7, writeFileSync as writeFileSync11 } from "node:fs";
118360
118297
  import { dirname as dirname21 } from "node:path";
118361
118298
  import { randomUUID as randomUUID8 } from "node:crypto";
118362
118299
 
118363
118300
  // src/metrics/paths.ts
118364
- import { join as join38 } from "node:path";
118301
+ import { join as join39 } from "node:path";
118365
118302
  function metricsDir(root2) {
118366
- return join38(root2, "state/metrics");
118303
+ return join39(root2, "state/metrics");
118367
118304
  }
118368
118305
  function currentFile(root2) {
118369
- return join38(metricsDir(root2), "current.json");
118306
+ return join39(metricsDir(root2), "current.json");
118370
118307
  }
118371
118308
  function historyFile(root2) {
118372
- return join38(metricsDir(root2), "history.jsonl");
118309
+ return join39(metricsDir(root2), "history.jsonl");
118373
118310
  }
118374
118311
  function instanceFile(root2) {
118375
- return join38(metricsDir(root2), "instance.json");
118312
+ return join39(metricsDir(root2), "instance.json");
118376
118313
  }
118377
118314
  function pidFile(root2) {
118378
- return join38(metricsDir(root2), "collector.pid");
118315
+ return join39(metricsDir(root2), "collector.pid");
118379
118316
  }
118380
118317
  function logFile(root2) {
118381
- return join38(root2, "state/logs/host-metrics.log");
118318
+ return join39(root2, "state/logs/host-metrics.log");
118382
118319
  }
118383
118320
  function environmentReportFile(root2) {
118384
- return join38(root2, "state/environment/report.json");
118321
+ return join39(root2, "state/environment/report.json");
118385
118322
  }
118386
118323
 
118387
118324
  // src/metrics/store.ts
118388
118325
  var LOG_LIMIT_BYTES = 256 * 1024;
118389
118326
  function writeAtomic2(path7, text) {
118390
- mkdirSync12(dirname21(path7), { recursive: true });
118327
+ mkdirSync13(dirname21(path7), { recursive: true });
118391
118328
  const temporary = `${path7}.${process.pid}.tmp`;
118392
118329
  writeFileSync11(temporary, text, { mode: 384 });
118393
118330
  renameSync4(temporary, path7);
118394
- chmodSync7(path7, 384);
118331
+ chmodSync8(path7, 384);
118395
118332
  }
118396
118333
  function loadInstance(root2, hostname4) {
118397
118334
  const path7 = instanceFile(root2);
118398
- if (existsSync15(path7)) {
118335
+ if (existsSync16(path7)) {
118399
118336
  try {
118400
118337
  const parsed = JSON.parse(readFileSync17(path7, "utf8"));
118401
118338
  if (typeof parsed.id === "string" && parsed.id !== "") {
@@ -118425,14 +118362,14 @@ function writeCurrent(root2, snapshot) {
118425
118362
  }
118426
118363
  function appendHistory(root2, snapshot) {
118427
118364
  const path7 = historyFile(root2);
118428
- mkdirSync12(dirname21(path7), { recursive: true });
118429
- const existing = existsSync15(path7) ? readFileSync17(path7, "utf8") : "";
118365
+ mkdirSync13(dirname21(path7), { recursive: true });
118366
+ const existing = existsSync16(path7) ? readFileSync17(path7, "utf8") : "";
118430
118367
  const merged = mergeHistoryLines(existing, historyPointFrom(snapshot), snapshot.collectedAt);
118431
118368
  writeAtomic2(path7, merged);
118432
118369
  }
118433
118370
  function readCurrent(root2) {
118434
118371
  const path7 = currentFile(root2);
118435
- if (!existsSync15(path7)) return null;
118372
+ if (!existsSync16(path7)) return null;
118436
118373
  try {
118437
118374
  return JSON.parse(readFileSync17(path7, "utf8"));
118438
118375
  } catch {
@@ -118441,8 +118378,8 @@ function readCurrent(root2) {
118441
118378
  }
118442
118379
  function appendLog(root2, line4) {
118443
118380
  const path7 = logFile(root2);
118444
- mkdirSync12(dirname21(path7), { recursive: true });
118445
- if (existsSync15(path7) && statSync7(path7).size > LOG_LIMIT_BYTES) {
118381
+ mkdirSync13(dirname21(path7), { recursive: true });
118382
+ if (existsSync16(path7) && statSync7(path7).size > LOG_LIMIT_BYTES) {
118446
118383
  renameSync4(path7, `${path7}.old`);
118447
118384
  }
118448
118385
  writeFileSync11(path7, `${(/* @__PURE__ */ new Date()).toISOString()} ${line4}
@@ -118545,17 +118482,18 @@ async function collectSnapshot(root2, now = Date.now()) {
118545
118482
 
118546
118483
  // src/metrics/lifecycle.ts
118547
118484
  init_src();
118548
- import { existsSync as existsSync20, readFileSync as readFileSync21, unlinkSync as unlinkSync5 } from "node:fs";
118485
+ import { existsSync as existsSync20, readFileSync as readFileSync20, unlinkSync as unlinkSync5 } from "node:fs";
118486
+ init_process();
118549
118487
 
118550
118488
  // src/environment/index.ts
118551
118489
  init_src();
118552
118490
  import { homedir as homedir8 } from "node:os";
118553
118491
 
118554
118492
  // src/host.ts
118555
- init_src();
118556
- import { homedir as homedir7, loadavg as loadavg2, networkInterfaces, uptime } from "node:os";
118557
- import { accessSync as accessSync3, constants as constants7, existsSync as existsSync16, globSync, readFileSync as readFileSync18, statfsSync, statSync as statSync8 } from "node:fs";
118558
- import { join as join39 } from "node:path";
118493
+ init_process();
118494
+ import { homedir as homedir7 } from "node:os";
118495
+ import { accessSync as accessSync3, constants as constants7, globSync, statSync as statSync8 } from "node:fs";
118496
+ import { join as join40 } from "node:path";
118559
118497
  function isTailscaleRange(address) {
118560
118498
  const [a3, b] = address.split(".").map(Number);
118561
118499
  return a3 === 100 && b !== void 0 && b >= 64 && b <= 127;
@@ -118584,19 +118522,19 @@ async function locate(tool) {
118584
118522
  if (!onPath.failed && direct) return direct;
118585
118523
  const home2 = homedir7();
118586
118524
  for (const candidate of [
118587
- join39(home2, ".local/bin", tool),
118588
- join39(home2, ".bun/bin", tool),
118589
- join39(home2, ".cargo/bin", tool),
118590
- join39(home2, ".deno/bin", tool),
118591
- join39("/usr/local/bin", tool),
118592
- join39("/opt/homebrew/bin", tool),
118593
- join39(home2, ".volta/bin", tool)
118525
+ join40(home2, ".local/bin", tool),
118526
+ join40(home2, ".bun/bin", tool),
118527
+ join40(home2, ".cargo/bin", tool),
118528
+ join40(home2, ".deno/bin", tool),
118529
+ join40("/usr/local/bin", tool),
118530
+ join40("/opt/homebrew/bin", tool),
118531
+ join40(home2, ".volta/bin", tool)
118594
118532
  ]) {
118595
118533
  if (executable(candidate)) return candidate;
118596
118534
  }
118597
118535
  for (const pattern of [
118598
- join39(home2, ".nvm/versions/node/*/bin", tool),
118599
- join39(home2, ".local/share/fnm/node-versions/*/installation/bin", tool)
118536
+ join40(home2, ".nvm/versions/node/*/bin", tool),
118537
+ join40(home2, ".local/share/fnm/node-versions/*/installation/bin", tool)
118600
118538
  ]) {
118601
118539
  for (const match2 of globSync(pattern)) if (executable(match2)) return match2;
118602
118540
  }
@@ -118610,6 +118548,9 @@ function fileMode(path7) {
118610
118548
  }
118611
118549
  }
118612
118550
 
118551
+ // src/environment/index.ts
118552
+ init_process();
118553
+
118613
118554
  // src/environment/agents.ts
118614
118555
  init_src();
118615
118556
 
@@ -118812,7 +118753,7 @@ ${daemon.stdout}`);
118812
118753
  // src/environment/ssh.ts
118813
118754
  init_src();
118814
118755
  import { existsSync as existsSync17 } from "node:fs";
118815
- import { join as join40 } from "node:path";
118756
+ import { join as join41 } from "node:path";
118816
118757
  var SSH_ID = "tools.ssh";
118817
118758
  var TMUX_ID = "tools.tmux";
118818
118759
  var sshProbe = {
@@ -118828,7 +118769,7 @@ var sshProbe = {
118828
118769
  fix: "install an OpenSSH client for remote and repository workflows"
118829
118770
  })];
118830
118771
  }
118831
- const directory = join40(context.homeDir, ".ssh");
118772
+ const directory = join41(context.homeDir, ".ssh");
118832
118773
  const mode = context.fileMode(directory);
118833
118774
  const agent = context.environment["SSH_AUTH_SOCK"] ? await context.run("ssh-add", ["-l"], { reject: false, timeout: PROBE_TIMEOUT_MS2 }) : null;
118834
118775
  const details = [
@@ -118911,12 +118852,12 @@ function writeEnvironmentReport(root2, report) {
118911
118852
  // src/environment/security/index.ts
118912
118853
  init_src();
118913
118854
  import { platform as platform2 } from "node:os";
118914
- import { existsSync as existsSync19, readFileSync as readFileSync20 } from "node:fs";
118915
- import { join as join41 } from "node:path";
118855
+ import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
118856
+ import { join as join42 } from "node:path";
118916
118857
 
118917
118858
  // src/environment/security/probes.ts
118918
118859
  init_src();
118919
- import { existsSync as existsSync18, readFileSync as readFileSync19 } from "node:fs";
118860
+ import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
118920
118861
  function emptySshd(state3, reason) {
118921
118862
  return { state: state3, reason, source: null, port: null, permitRootLogin: null, passwordAuthentication: null, pubkeyAuthentication: null, usePam: null };
118922
118863
  }
@@ -118934,7 +118875,7 @@ ${result.stdout}`);
118934
118875
  for (const path7 of ["/etc/ssh/sshd_config", "/private/etc/ssh/sshd_config"]) {
118935
118876
  if (!existsSync18(path7)) continue;
118936
118877
  try {
118937
- const parsed = parseSshdConfig(readFileSync19(path7, "utf8"), "file");
118878
+ const parsed = parseSshdConfig(readFileSync18(path7, "utf8"), "file");
118938
118879
  return parsed.state === "present" ? parsed : emptySshd("unknown", "the SSH configuration file could not be interpreted");
118939
118880
  } catch {
118940
118881
  return emptySshd("unknown", "could not be checked: this user cannot read the SSH configuration");
@@ -118985,7 +118926,7 @@ ${jail.stderr}`);
118985
118926
  // src/environment/security/index.ts
118986
118927
  function hostSecurityContext(root2, profileOverride) {
118987
118928
  const snapshot = readCurrent(root2);
118988
- const file2 = existsSync19(join41(root2, ".env")) ? parseEnv(readFileSync20(join41(root2, ".env"), "utf8")) : /* @__PURE__ */ new Map();
118929
+ const file2 = existsSync19(join42(root2, ".env")) ? parseEnv(readFileSync19(join42(root2, ".env"), "utf8")) : /* @__PURE__ */ new Map();
118989
118930
  const environment = mergeEnvironment(file2, process.env);
118990
118931
  const profile = profileOverride ?? environment["PORTTA_PROFILE"] ?? "local";
118991
118932
  return {
@@ -119005,7 +118946,7 @@ async function collectHostSecurityFacts(context, securityContext) {
119005
118946
  }
119006
118947
  async function collectHostSecurityChecks(root2, probeContext = defaultProbeContext(), securityContext = hostSecurityContext(root2)) {
119007
118948
  const checks = securityVerdicts(await collectHostSecurityFacts(probeContext, securityContext), securityContext);
119008
- const sshDirectory = join41(root2, "state/ssh");
118949
+ const sshDirectory = join42(root2, "state/ssh");
119009
118950
  const mode = probeContext.fileMode(sshDirectory);
119010
118951
  checks.push({
119011
118952
  ...check2(
@@ -119033,9 +118974,9 @@ async function collectHostSecurityReport(root2, probeContext = defaultProbeConte
119033
118974
  }
119034
118975
 
119035
118976
  // src/environment/security/store.ts
119036
- import { join as join42 } from "node:path";
118977
+ import { join as join43 } from "node:path";
119037
118978
  function securityReportFile(root2) {
119038
- return join42(root2, "state/environment/security.json");
118979
+ return join43(root2, "state/environment/security.json");
119039
118980
  }
119040
118981
  function writeHostSecurityReport(root2, report) {
119041
118982
  const path7 = securityReportFile(root2);
@@ -119048,7 +118989,7 @@ function writeHostSecurityReport(root2, report) {
119048
118989
  function readCollectorPid(root2) {
119049
118990
  const path7 = pidFile(root2);
119050
118991
  if (!existsSync20(path7)) return null;
119051
- const parsed = Number(readFileSync21(path7, "utf8").trim());
118992
+ const parsed = Number(readFileSync20(path7, "utf8").trim());
119052
118993
  return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
119053
118994
  }
119054
118995
  function pidAlive(pid) {
@@ -119061,7 +119002,7 @@ function pidAlive(pid) {
119061
119002
  }
119062
119003
  function commandLine(pid) {
119063
119004
  try {
119064
- return readFileSync21(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
119005
+ return readFileSync20(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
119065
119006
  } catch {
119066
119007
  return "";
119067
119008
  }
@@ -119276,10 +119217,10 @@ function ensureHostToken(context) {
119276
119217
  return file2;
119277
119218
  }
119278
119219
  function hostDaemonEntry(directory = import.meta.dirname) {
119279
- return join43(directory, "host.js");
119220
+ return join44(directory, "host.js");
119280
119221
  }
119281
119222
  function hostDaemonLog(stateDir) {
119282
- return join43(stateDir, "daemon.log");
119223
+ return join44(stateDir, "daemon.log");
119283
119224
  }
119284
119225
  async function hostAnswers(listen) {
119285
119226
  const host2 = listen.host === "0.0.0.0" || listen.host === "::" ? "127.0.0.1" : listen.host;
@@ -119294,7 +119235,9 @@ async function hostServe(command) {
119294
119235
  const options = globals3(command);
119295
119236
  const context = gatewayContext({ profile: options.profile });
119296
119237
  const entry = hostDaemonEntry();
119297
- if (!existsSync21(entry)) throw new PreconditionError(`the host daemon is not built: ${entry}`, "npm run build --workspace=@codions/portta");
119238
+ if (!existsSync21(entry)) {
119239
+ throw new PreconditionError(`the host daemon is not built: ${entry}`, CLI_VERSION === LOCAL_DEV_VERSION ? "npm run build --workspace=@codions/portta" : `the copy under ${join44(context.root, "bin")} serves the applier only; run this with the CLI from npm: npm install -g @codions/portta`);
119240
+ }
119298
119241
  const stateDir = resolveHostStateDir(context.root, context.env);
119299
119242
  const listen = hostListen(context.env);
119300
119243
  const output2 = new Output(options);
@@ -119321,16 +119264,16 @@ function globals4(command) {
119321
119264
  return command.optsWithGlobals();
119322
119265
  }
119323
119266
  function setValues(root2, values) {
119324
- const path7 = join44(root2, ".env");
119267
+ const path7 = join45(root2, ".env");
119325
119268
  patchEnvFile(path7, values);
119326
119269
  }
119327
119270
  function syncForwardAuth(root2) {
119328
- const storePath = join44(root2, "state/auth/protections.json");
119271
+ const storePath = join45(root2, "state/auth/protections.json");
119329
119272
  const store = readProtectionStore(storePath);
119330
119273
  writeProtectionStore(storePath, store);
119331
- const dynamic = join44(root2, "config/traefik/dynamic");
119332
- mkdirSync13(dynamic, { recursive: true });
119333
- writeEnvFile(join44(dynamic, "portta-auth.yaml"), renderAuthDynamic(store));
119274
+ const dynamic = join45(root2, "config/traefik/dynamic");
119275
+ mkdirSync14(dynamic, { recursive: true });
119276
+ writeEnvFile(join45(dynamic, "portta-auth.yaml"), renderAuthDynamic(store));
119334
119277
  }
119335
119278
  var PANEL_OVERRIDES = { PORTTA_WEB: "true" };
119336
119279
  async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
@@ -119338,7 +119281,7 @@ async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
119338
119281
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: { ...context.env, ...extraEnv }, stdio });
119339
119282
  }
119340
119283
  function prepareWebUp(options, command) {
119341
- prepareEnvFile(join44(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119284
+ prepareEnvFile(join45(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119342
119285
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: globals4(command).profile }));
119343
119286
  const initial = gatewayContext({ profile: globals4(command).profile });
119344
119287
  const expose = options.expose ?? initial.config.webExpose;
@@ -119390,16 +119333,7 @@ function prepareWebUp(options, command) {
119390
119333
  options.port ? String(Number(options.port)) : String(initial.config.webPort)
119391
119334
  );
119392
119335
  setValues(initial.root, values);
119393
- mkdirSync13(join44(initial.root, "state/git"), { recursive: true });
119394
- mkdirSync13(join44(initial.root, "state/github"), { recursive: true });
119395
- mkdirSync13(join44(initial.root, "state/metrics"), { recursive: true });
119396
- mkdirSync13(join44(initial.root, "state/environment"), { recursive: true });
119397
- mkdirSync13(join44(initial.root, "state/logs"), { recursive: true });
119398
- mkdirSync13(join44(initial.root, "state/auth"), { recursive: true, mode: 448 });
119399
- chmodSync8(join44(initial.root, "state/auth"), 448);
119400
- mkdirSync13(join44(initial.root, "state/ssh"), { recursive: true, mode: 448 });
119401
- chmodSync8(join44(initial.root, "state/ssh"), 448);
119402
- mkdirSync13(join44(initial.root, "config/traefik/dynamic"), { recursive: true });
119336
+ ensureInstallationDirectories(initial.root);
119403
119337
  syncForwardAuth(initial.root);
119404
119338
  const context = gatewayContext({ profile: globals4(command).profile, overrides: values });
119405
119339
  const output2 = new Output(globals4(command));
@@ -119415,7 +119349,7 @@ async function webUp(options, command) {
119415
119349
  ensureHostToken(context);
119416
119350
  output2.progress("pulling alpine/socat:1.8.1.3");
119417
119351
  await runProcess("docker", ["pull", "alpine/socat:1.8.1.3"], { reject: false, stdio: "stream" });
119418
- mkdirSync13(join44(context.root, "state", "panel"), { recursive: true });
119352
+ mkdirSync14(join45(context.root, "state", "panel"), { recursive: true });
119419
119353
  const services = ["portta-auth", "web", "web-socket-proxy"];
119420
119354
  const buildArgs = context.config.webDev || context.config.webBuild ? ["--build"] : [];
119421
119355
  output2.progress(buildArgs.length > 0 ? `starting ${services.join(", ")}, building the panel image` : `starting ${services.join(", ")}`);
@@ -119613,6 +119547,7 @@ async function webOpen(command) {
119613
119547
  // src/commands/clients.ts
119614
119548
  init_context();
119615
119549
  init_errors3();
119550
+ init_process();
119616
119551
  init_src();
119617
119552
  function globals5(command) {
119618
119553
  return command.optsWithGlobals();
@@ -119622,7 +119557,7 @@ async function ensureToolbox(command) {
119622
119557
  const image = porttaImages(context.version).toolbox;
119623
119558
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
119624
119559
  if (present.exitCode === 0) return image;
119625
- await runProcess("docker", ["build", "-q", "--build-arg", `PORTTA_VERSION=${context.version}`, "-t", image, join45(context.root, "docker", "images", "toolbox")], { stdio: "inherit" });
119560
+ await runProcess("docker", ["build", "-q", "--build-arg", `PORTTA_VERSION=${context.version}`, "-t", image, join46(context.root, "docker", "images", "toolbox")], { stdio: "inherit" });
119626
119561
  return image;
119627
119562
  }
119628
119563
  async function containerEnvironment(id) {
@@ -119753,7 +119688,7 @@ async function dbRestore(file2, command) {
119753
119688
  );
119754
119689
  }
119755
119690
  await confirm(`replace ${path7} with ${file2}? The current panel data is discarded.`, globals5(command).yes === true);
119756
- mkdirSync14(dirname22(path7), { recursive: true });
119691
+ mkdirSync15(dirname22(path7), { recursive: true });
119757
119692
  for (const candidate of databaseFiles(path7)) rmSync5(candidate, { force: true });
119758
119693
  copyFileSync2(file2, path7);
119759
119694
  new Output(globals5(command)).progress(`panel database restored from ${file2}`);
@@ -119763,11 +119698,12 @@ async function dbRestore(file2, command) {
119763
119698
  init_src();
119764
119699
  var import_yaml2 = __toESM(require_dist(), 1);
119765
119700
  init_zod();
119766
- import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync22, realpathSync as realpathSync4, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
119701
+ import { existsSync as existsSync23, mkdirSync as mkdirSync16, readFileSync as readFileSync21, realpathSync as realpathSync4, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
119767
119702
  import { createHash as createHash15 } from "node:crypto";
119768
- import { basename as basename14, dirname as dirname23, join as join46, resolve as resolve24 } from "node:path";
119703
+ import { basename as basename14, dirname as dirname23, join as join47, resolve as resolve24 } from "node:path";
119769
119704
  init_context();
119770
119705
  init_errors3();
119706
+ init_process();
119771
119707
  function globals6(command) {
119772
119708
  return command.optsWithGlobals();
119773
119709
  }
@@ -119878,7 +119814,7 @@ function labelsOf(service2) {
119878
119814
  return Object.fromEntries(Object.entries(service2.labels ?? {}).map(([key, value3]) => [key, String(value3)]));
119879
119815
  }
119880
119816
  function composeCandidates(path7) {
119881
- return ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].map((file2) => join46(path7, file2)).filter(existsSync23);
119817
+ return ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].map((file2) => join47(path7, file2)).filter(existsSync23);
119882
119818
  }
119883
119819
  async function hostContainers() {
119884
119820
  try {
@@ -119896,20 +119832,20 @@ function safeRealpath2(path7) {
119896
119832
  }
119897
119833
  function declaredComposeName(file2) {
119898
119834
  try {
119899
- const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync22(file2, "utf8"));
119835
+ const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync21(file2, "utf8"));
119900
119836
  return match2?.[1] ?? null;
119901
119837
  } catch {
119902
119838
  return null;
119903
119839
  }
119904
119840
  }
119905
119841
  function readProjectConfig(root2) {
119906
- const path7 = join46(root2, PROJECT_CONFIG_PATH);
119842
+ const path7 = join47(root2, PROJECT_CONFIG_PATH);
119907
119843
  if (!existsSync23(path7)) {
119908
119844
  return { source: "defaults", path: PROJECT_CONFIG_PATH, config: defaultProjectConfig(), issues: [] };
119909
119845
  }
119910
119846
  let document;
119911
119847
  try {
119912
- document = (0, import_yaml2.parse)(readFileSync22(path7, "utf8"));
119848
+ document = (0, import_yaml2.parse)(readFileSync21(path7, "utf8"));
119913
119849
  } catch (error61) {
119914
119850
  const message = error61 instanceof Error ? error61.message : String(error61);
119915
119851
  return { source: "file", path: PROJECT_CONFIG_PATH, config: null, issues: [{ path: "", message }] };
@@ -119932,8 +119868,8 @@ async function analyze(pathValue, options = {}, containers) {
119932
119868
  let result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json"], { cwd: path7, reject: false });
119933
119869
  if (result.exitCode !== 0) result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json", "--no-interpolate"], { cwd: path7 });
119934
119870
  const model = ComposeSchema.parse(JSON.parse(result.stdout));
119935
- const overlay2 = ["compose.portta.yaml", "compose.portta.yml"].map((file2) => join46(".portta", file2)).find((file2) => existsSync23(join46(path7, file2))) ?? ["compose.portta.yaml", "compose.portta.yml"].find((file2) => existsSync23(join46(path7, file2))) ?? null;
119936
- const projectFromEnv = existsSync23(join46(path7, ".env")) ? parseEnv(readFileSync22(join46(path7, ".env"), "utf8")).get("COMPOSE_PROJECT_NAME") : void 0;
119871
+ const overlay2 = ["compose.portta.yaml", "compose.portta.yml"].map((file2) => join47(".portta", file2)).find((file2) => existsSync23(join47(path7, file2))) ?? ["compose.portta.yaml", "compose.portta.yml"].find((file2) => existsSync23(join47(path7, file2))) ?? null;
119872
+ const projectFromEnv = existsSync23(join47(path7, ".env")) ? parseEnv(readFileSync21(join47(path7, ".env"), "utf8")).get("COMPOSE_PROJECT_NAME") : void 0;
119937
119873
  const declaredName = declaredComposeName(composeFile2);
119938
119874
  const project2 = projectFromEnv || composeNamespace(declaredName ?? model.name ?? basename14(path7));
119939
119875
  const services = Object.entries(model.services).map(([name, service2]) => ({
@@ -120110,7 +120046,7 @@ async function initCommand(pathValue, options, command) {
120110
120046
  }));
120111
120047
  const content = renderOverlay(report.project.name, overlayServices, context.config.network, options.project);
120112
120048
  const runtimeId = createHash15("sha256").update(safeRealpath2(report.path)).digest("hex").slice(0, 16);
120113
- const destination = options.output ? resolve24(report.path, options.output) : join46(context.root, "runtime", "compose", runtimeId, "compose.portta.yaml");
120049
+ const destination = options.output ? resolve24(report.path, options.output) : join47(context.root, "runtime", "compose", runtimeId, "compose.portta.yaml");
120114
120050
  const output2 = new Output(globals6(command));
120115
120051
  if (options.dryRun) {
120116
120052
  output2.data(content);
@@ -120118,12 +120054,12 @@ async function initCommand(pathValue, options, command) {
120118
120054
  }
120119
120055
  if (existsSync23(destination) && !options.force) throw new RefusedError(`${destination} already exists`, "pass --force to replace it while keeping a backup");
120120
120056
  await confirm(`write ${destination}?`, globals6(command).yes === true);
120121
- mkdirSync15(dirname23(destination), { recursive: true, mode: 493 });
120057
+ mkdirSync16(dirname23(destination), { recursive: true, mode: 493 });
120122
120058
  if (existsSync23(destination)) renameSync5(destination, `${destination}.bak.${Date.now()}`);
120123
120059
  const temporary = `${destination}.${process.pid}.tmp`;
120124
120060
  writeFileSync12(temporary, content, { mode: 420 });
120125
120061
  try {
120126
- const validated = await runProcess("docker", ["compose", "-f", join46(report.path, report.compose_file), "-f", temporary, "config", "--format", "json"], { cwd: report.path, reject: false });
120062
+ const validated = await runProcess("docker", ["compose", "-f", join47(report.path, report.compose_file), "-f", temporary, "config", "--format", "json"], { cwd: report.path, reject: false });
120127
120063
  if (validated.exitCode !== 0) throw new RefusedError("generated runtime overlay is not valid Compose", validated.stderr.trim() || validated.stdout.trim());
120128
120064
  ComposeSchema.parse(JSON.parse(validated.stdout));
120129
120065
  renameSync5(temporary, destination);
@@ -120201,8 +120137,9 @@ init_zod();
120201
120137
  init_context();
120202
120138
  init_errors3();
120203
120139
  import { createHash as createHash16 } from "node:crypto";
120204
- import { existsSync as existsSync24, mkdirSync as mkdirSync16, readFileSync as readFileSync23, renameSync as renameSync6, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "node:fs";
120205
- import { basename as basename15, delimiter as delimiter3, isAbsolute as isAbsolute5, join as join47, resolve as resolve25 } from "node:path";
120140
+ import { existsSync as existsSync24, mkdirSync as mkdirSync17, readFileSync as readFileSync22, renameSync as renameSync6, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "node:fs";
120141
+ import { basename as basename15, delimiter as delimiter3, isAbsolute as isAbsolute5, join as join48, resolve as resolve25 } from "node:path";
120142
+ init_process();
120206
120143
  var Manifest = external_exports.object({
120207
120144
  schemaVersion: external_exports.literal(1),
120208
120145
  driver: external_exports.literal("compose").default("compose"),
@@ -120235,25 +120172,25 @@ function idFor(workspace2) {
120235
120172
  return createHash16("sha256").update(workspace2).digest("hex").slice(0, 16);
120236
120173
  }
120237
120174
  function digest(path7) {
120238
- return createHash16("sha256").update(readFileSync23(path7)).digest("hex");
120175
+ return createHash16("sha256").update(readFileSync22(path7)).digest("hex");
120239
120176
  }
120240
120177
  function digestIfPresent(path7) {
120241
120178
  return existsSync24(path7) ? digest(path7) : null;
120242
120179
  }
120243
120180
  function runtimeDirectory(root2, id) {
120244
- return join47(root2, "runtime", "compose", id);
120181
+ return join48(root2, "runtime", "compose", id);
120245
120182
  }
120246
120183
  function planPath(root2, id) {
120247
- return join47(runtimeDirectory(root2, id), "plan.json");
120184
+ return join48(runtimeDirectory(root2, id), "plan.json");
120248
120185
  }
120249
120186
  function manifestPath(root2, id) {
120250
- return join47(runtimeDirectory(root2, id), "runtime.json");
120187
+ return join48(runtimeDirectory(root2, id), "runtime.json");
120251
120188
  }
120252
120189
  function composeCandidates2(workspace2) {
120253
- return ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].map((file2) => join47(workspace2, file2)).filter(existsSync24);
120190
+ return ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].map((file2) => join48(workspace2, file2)).filter(existsSync24);
120254
120191
  }
120255
120192
  function hasComposeRuntime(workspace2 = process.cwd()) {
120256
- return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join47(resolve25(workspace2), "VERSION"));
120193
+ return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join48(resolve25(workspace2), "VERSION"));
120257
120194
  }
120258
120195
  function networks(value3) {
120259
120196
  return Array.isArray(value3) ? value3 : Object.keys(value3 ?? {});
@@ -120312,22 +120249,22 @@ networks:
120312
120249
  `;
120313
120250
  }
120314
120251
  function manifestPaths(workspace2, root2, id) {
120315
- return { local: join47(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120252
+ return { local: join48(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120316
120253
  }
120317
120254
  function loadManifest(workspace2, root2, id) {
120318
120255
  const { local, stored } = manifestPaths(workspace2, root2, id);
120319
120256
  const file2 = existsSync24(local) ? local : existsSync24(stored) ? stored : null;
120320
- return file2 ? Manifest.parse(JSON.parse(readFileSync23(file2, "utf8"))) : Manifest.parse({ schemaVersion: 1 });
120257
+ return file2 ? Manifest.parse(JSON.parse(readFileSync22(file2, "utf8"))) : Manifest.parse({ schemaVersion: 1 });
120321
120258
  }
120322
120259
  function inputFiles(workspace2, manifest) {
120323
120260
  if (manifest.compose.files?.length) return manifest.compose.files.map((file2) => resolve25(workspace2, file2));
120324
- const envFile = join47(workspace2, ".env");
120325
- const env = envFile && existsSync24(envFile) ? parseEnv(readFileSync23(envFile, "utf8")) : /* @__PURE__ */ new Map();
120261
+ const envFile = join48(workspace2, ".env");
120262
+ const env = envFile && existsSync24(envFile) ? parseEnv(readFileSync22(envFile, "utf8")) : /* @__PURE__ */ new Map();
120326
120263
  const configured = process.env.COMPOSE_FILE ?? env.get("COMPOSE_FILE");
120327
120264
  if (configured) return configured.split(delimiter3).map((file2) => isAbsolute5(file2) ? file2 : resolve25(workspace2, file2));
120328
120265
  const base2 = composeCandidates2(workspace2)[0];
120329
120266
  if (!base2) throw new UsageError(`no Compose file found in ${workspace2}`);
120330
- const override = ["compose.override.yaml", "compose.override.yml"].map((file2) => join47(workspace2, file2)).find(existsSync24);
120267
+ const override = ["compose.override.yaml", "compose.override.yml"].map((file2) => join48(workspace2, file2)).find(existsSync24);
120331
120268
  return override ? [base2, override] : [base2];
120332
120269
  }
120333
120270
  function versionAtLeast2(value3, minimum = [2, 24, 4]) {
@@ -120358,7 +120295,7 @@ async function stale(plan) {
120358
120295
  function readPlan(root2, workspace2) {
120359
120296
  const path7 = planPath(root2, idFor(workspace2));
120360
120297
  if (!existsSync24(path7)) throw new UsageError("no Runtime Plan exists for this workspace", "run `portta prepare` first");
120361
- return JSON.parse(readFileSync23(path7, "utf8"));
120298
+ return JSON.parse(readFileSync22(path7, "utf8"));
120362
120299
  }
120363
120300
  function manifestWithOptions(manifest, options) {
120364
120301
  return Manifest.parse({
@@ -120427,14 +120364,14 @@ async function prepareComposeRuntime(options, command) {
120427
120364
  const unsupported = findings.filter((finding2) => finding2.code === "network_mode");
120428
120365
  const outcome = unsupported.length ? "not_supported" : manifest.compose.mode === "manual" ? "manual" : pending.length ? "not_supported" : "isolated";
120429
120366
  const directory = runtimeDirectory(context.root, id);
120430
- const generatedOverlay = join47(directory, "compose.portta.yaml");
120367
+ const generatedOverlay = join48(directory, "compose.portta.yaml");
120431
120368
  const manifests = manifestPaths(workspace2, context.root, id);
120432
- const envFile = join47(workspace2, ".env");
120369
+ const envFile = join48(workspace2, ".env");
120433
120370
  const plan = { version: 1, driver: "compose", id, workspace: workspace2, createdAt: (/* @__PURE__ */ new Date()).toISOString(), inputs: [...files, ...existsSync24(envFile) ? [envFile] : []].map((file2) => ({ path: file2, digest: digest(file2) })), capabilities: { composeVersion }, manifest: { local: { path: manifests.local, digest: digestIfPresent(manifests.local) }, stored: { path: manifests.stored, digest: digestIfPresent(manifests.stored) } }, compose: { projectName, projectDirectory: workspace2, files, profiles: manifest.compose.profiles, mode: manifest.compose.mode, generatedOverlay }, outcome, compatibility: manifest.compatibility, pending, services, findings };
120434
120371
  const content = manifest.compose.mode === "manual" ? "# Manual Compose integration; Portta adds no runtime mutations.\nservices: {}\n" : overlay(plan, context.config.network);
120435
120372
  if (!options.dryRun) {
120436
120373
  if (outcome === "not_supported") throw new RefusedError("environment is not ready for isolated Compose runtime", [...unsupported, ...pending].map((finding2) => finding2.detail).join("; "));
120437
- mkdirSync16(directory, { recursive: true, mode: 448 });
120374
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120438
120375
  const temporary = `${generatedOverlay}.${process.pid}.tmp`;
120439
120376
  writeFileSync13(temporary, content, { mode: 384 });
120440
120377
  const final = await runProcess("docker", [...composeArgs(plan, temporary), "config", "--format", "json"], { cwd: workspace2, reject: false });
@@ -120474,7 +120411,7 @@ async function initComposeRuntime(options, command) {
120474
120411
  const files = inputFiles(workspace2, Manifest.parse({ schemaVersion: 1 }));
120475
120412
  const manifest = { schemaVersion: 1, driver: "compose", compose: { files: files.map((file2) => file2.startsWith(`${workspace2}/`) ? file2.slice(workspace2.length + 1) : file2), profiles: [], mode: options.manual ? "manual" : "auto" }, services, compatibility: { removeContainerNames: options.removeContainerName ?? [], allowSharedNetworks: options.allowSharedNetworks ?? false, allowSharedVolumes: options.allowSharedVolumes ?? false } };
120476
120413
  const directory = runtimeDirectory(context.root, id);
120477
- mkdirSync16(directory, { recursive: true, mode: 448 });
120414
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120478
120415
  writeFileSync13(manifestPath(context.root, id), `${JSON.stringify(manifest, null, 2)}
120479
120416
  `, { mode: 384 });
120480
120417
  return prepareComposeRuntime({ path: workspace2, project: options.project }, command);
@@ -120505,23 +120442,25 @@ async function runtimeAction(action, options, command) {
120505
120442
  init_src();
120506
120443
  init_src();
120507
120444
  init_context();
120508
- import { chmodSync as chmodSync9, existsSync as existsSync38, mkdirSync as mkdirSync18, readFileSync as readFileSync30, readdirSync as readdirSync8, rmSync as rmSync10 } from "node:fs";
120509
- import { join as join58 } from "node:path";
120445
+ import { chmodSync as chmodSync9, existsSync as existsSync38, mkdirSync as mkdirSync19, readFileSync as readFileSync29, readdirSync as readdirSync8, rmSync as rmSync10 } from "node:fs";
120446
+ import { join as join59 } from "node:path";
120510
120447
  init_errors3();
120448
+ init_process();
120511
120449
  init_version();
120512
120450
 
120513
120451
  // src/doctor.ts
120514
120452
  init_src();
120515
120453
  init_context();
120516
120454
  import { existsSync as existsSync33 } from "node:fs";
120517
- import { join as join53 } from "node:path";
120455
+ import { join as join54 } from "node:path";
120456
+ init_process();
120518
120457
 
120519
120458
  // src/modules/index.ts
120520
120459
  init_src();
120521
120460
  init_modules();
120522
120461
  init_context();
120523
- import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
120524
- import { join as join52 } from "node:path";
120462
+ import { existsSync as existsSync32, readFileSync as readFileSync27 } from "node:fs";
120463
+ import { join as join53 } from "node:path";
120525
120464
 
120526
120465
  // src/modules/taskflow.ts
120527
120466
  init_modules();
@@ -120537,8 +120476,7 @@ var WORKFLOW_ENGINE_ACTIONS = [
120537
120476
  ["validate", "Validate a workflow file or registered workflow"],
120538
120477
  ["save", "Save a workflow file into the registry"],
120539
120478
  ["doctor", "Check the standalone workflow engine"],
120540
- ["guide", "Print the workflow authoring guide"],
120541
- ["install-skill", "Retired \u2014 install with: npx skills add codions-labs/portta --skill portta-workflows -g"]
120479
+ ["guide", "Print the workflow authoring guide"]
120542
120480
  ];
120543
120481
  var USAGE_HINT = "(run with --help for usage)";
120544
120482
  function parsePort2(value3) {
@@ -120974,10 +120912,10 @@ var taskflowCliModule = {
120974
120912
  // src/modules/index.ts
120975
120913
  var CLI_MODULES = [taskflowCliModule];
120976
120914
  function moduleEnvironment(root2 = findGatewayRoot()) {
120977
- const file2 = root2 ? join52(root2, ".env") : null;
120915
+ const file2 = root2 ? join53(root2, ".env") : null;
120978
120916
  if (!file2 || !existsSync32(file2)) return { ...process.env };
120979
120917
  try {
120980
- return mergeEnvironment(parseEnv(readFileSync28(file2, "utf8")), process.env);
120918
+ return mergeEnvironment(parseEnv(readFileSync27(file2, "utf8")), process.env);
120981
120919
  } catch {
120982
120920
  return { ...process.env };
120983
120921
  }
@@ -121031,7 +120969,7 @@ async function runDoctor(context) {
121031
120969
  const env = context.env;
121032
120970
  const config3 = context.config;
121033
120971
  const root2 = context.root;
121034
- const stateDir = env["PORTTA_STATE_DIR"] || join53(root2, "state");
120972
+ const stateDir = env["PORTTA_STATE_DIR"] || join54(root2, "state");
121035
120973
  const add = (...entries) => {
121036
120974
  for (const entry of entries) if (entry) checks.push(entry);
121037
120975
  };
@@ -121043,7 +120981,7 @@ async function runDoctor(context) {
121043
120981
  `unknown profile '${env["PORTTA_PROFILE"]}'`,
121044
120982
  "set PORTTA_PROFILE to one of: local remote-private remote-public"
121045
120983
  ));
121046
- const envPath = join53(root2, ".env");
120984
+ const envPath = join54(root2, ".env");
121047
120985
  if (existsSync33(envPath)) {
121048
120986
  add(check2("config.env", "pass", ".env", "present"));
121049
120987
  add(envPermissionVerdict(fileMode(envPath)));
@@ -121185,10 +121123,10 @@ async function runDoctor(context) {
121185
121123
  `portta up ${config3.profile}`
121186
121124
  ));
121187
121125
  }
121188
- add(existsSync33(join53(stateDir, "tailscale")) ? check2("tailscale.state.dir", "pass", "tailscale state", "persisted under state/tailscale") : check2("tailscale.state.dir", "warn", "tailscale state", "state directory missing", "portta bootstrap"));
121126
+ add(existsSync33(join54(stateDir, "tailscale")) ? check2("tailscale.state.dir", "pass", "tailscale state", "persisted under state/tailscale") : check2("tailscale.state.dir", "warn", "tailscale state", "state directory missing", "portta bootstrap"));
121189
121127
  }
121190
121128
  const hasKey = Boolean(env["TS_AUTHKEY"]);
121191
- add(!hasKey && !existsSync33(join53(stateDir, "tailscale/tailscaled.state")) ? check2(
121129
+ add(!hasKey && !existsSync33(join54(stateDir, "tailscale/tailscaled.state")) ? check2(
121192
121130
  "tailscale.authkey",
121193
121131
  "fail",
121194
121132
  "tailscale auth",
@@ -121218,7 +121156,7 @@ async function runDoctor(context) {
121218
121156
  "portta bootstrap (generates it without printing it)"
121219
121157
  ));
121220
121158
  const auth2 = gatewayContainer(containers, "auth");
121221
- const authStore = join53(root2, "state/auth/protections.json");
121159
+ const authStore = join54(root2, "state/auth/protections.json");
121222
121160
  add(authStoreVerdict(existsSync33(authStore), fileMode(authStore), Boolean(auth2)));
121223
121161
  add(componentVerdict("auth.service", "authentication service", Boolean(auth2), auth2?.state ?? null, auth2?.health ?? null, "portta logs portta-auth"));
121224
121162
  const gh = await locate("gh");
@@ -121368,7 +121306,7 @@ async function runDoctor(context) {
121368
121306
  "set CF_DNS_API_TOKEN, or use ACME_CHALLENGE=http for per-hostname certificates"
121369
121307
  ));
121370
121308
  }
121371
- const store = join53(stateDir, "traefik/acme/acme.json");
121309
+ const store = join54(stateDir, "traefik/acme/acme.json");
121372
121310
  if (existsSync33(store)) {
121373
121311
  const mode = fileMode(store);
121374
121312
  add(mode === "600" ? check2("tls.acme.perms", "pass", "ACME store permissions", mode) : check2(
@@ -121570,8 +121508,9 @@ async function resolveIpv4(hostname4) {
121570
121508
 
121571
121509
  // src/commands/apply.ts
121572
121510
  init_src();
121511
+ init_process();
121573
121512
  import { existsSync as existsSync34 } from "node:fs";
121574
- import { join as join54 } from "node:path";
121513
+ import { join as join55 } from "node:path";
121575
121514
  async function label(name) {
121576
121515
  const result = await runProcess(
121577
121516
  "docker",
@@ -121610,9 +121549,9 @@ async function ensureApplier(context) {
121610
121549
  if (await label("portta.apply.spec") === spec) return { action: "kept" };
121611
121550
  if (!await removeApplier()) return { action: "failed", reason: "the running applier could not be replaced" };
121612
121551
  }
121613
- const context_dir = join54(context.root, "docker", "images", "apply");
121552
+ const context_dir = join55(context.root, "docker", "images", "apply");
121614
121553
  const image = porttaImages(context.version).apply;
121615
- if (!existsSync34(join54(context_dir, "Dockerfile"))) {
121554
+ if (!existsSync34(join55(context_dir, "Dockerfile"))) {
121616
121555
  return { action: "failed", reason: `no applier image source at ${context_dir}` };
121617
121556
  }
121618
121557
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121626,8 +121565,9 @@ async function ensureApplier(context) {
121626
121565
 
121627
121566
  // src/commands/runner.ts
121628
121567
  init_src();
121568
+ init_process();
121629
121569
  import { existsSync as existsSync35 } from "node:fs";
121630
- import { join as join55 } from "node:path";
121570
+ import { join as join56 } from "node:path";
121631
121571
  async function label2(name) {
121632
121572
  const result = await runProcess(
121633
121573
  "docker",
@@ -121666,9 +121606,9 @@ async function ensureRunner(context) {
121666
121606
  if (await label2("portta.runner.spec") === spec) return { action: "kept" };
121667
121607
  if (!await removeRunner()) return { action: "failed", reason: "the running runner could not be replaced" };
121668
121608
  }
121669
- const context_dir = join55(context.root, "docker", "images", "apply");
121609
+ const context_dir = join56(context.root, "docker", "images", "apply");
121670
121610
  const image = porttaImages(context.version).apply;
121671
- if (!existsSync35(join55(context_dir, "Dockerfile"))) {
121611
+ if (!existsSync35(join56(context_dir, "Dockerfile"))) {
121672
121612
  return { action: "failed", reason: `no runner image source at ${context_dir}` };
121673
121613
  }
121674
121614
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121681,20 +121621,22 @@ async function ensureRunner(context) {
121681
121621
  }
121682
121622
 
121683
121623
  // src/checkout-cli.ts
121624
+ init_process();
121684
121625
  import { existsSync as existsSync36, readdirSync as readdirSync6, statSync as statSync11 } from "node:fs";
121685
- import { join as join56 } from "node:path";
121626
+ import { join as join57 } from "node:path";
121686
121627
  var CHECKOUT_CLI_SOURCES = [
121687
121628
  "packages/cli/src",
121688
121629
  "packages/cli/scripts",
121689
121630
  "packages/cli/package.json",
121690
121631
  "packages/core/src",
121691
- "packages/contracts/src"
121632
+ "packages/contracts/src",
121633
+ "packages/host/src"
121692
121634
  ];
121693
121635
  function checkoutCliDist(root2) {
121694
- return join56(root2, "packages/cli/dist/cli.js");
121636
+ return join57(root2, "packages/cli/dist/cli.js");
121695
121637
  }
121696
121638
  function isCheckout(root2) {
121697
- return existsSync36(join56(root2, "packages/cli/src/cli.ts")) && existsSync36(join56(root2, "package.json"));
121639
+ return existsSync36(join57(root2, "packages/cli/src/cli.ts")) && existsSync36(join57(root2, "package.json"));
121698
121640
  }
121699
121641
  function newestSourceMtime(path7) {
121700
121642
  if (!existsSync36(path7)) return 0;
@@ -121702,7 +121644,7 @@ function newestSourceMtime(path7) {
121702
121644
  if (info.isFile()) return /\.(ts|mjs|json)$/.test(path7) ? info.mtimeMs : 0;
121703
121645
  let newest = 0;
121704
121646
  for (const entry of readdirSync6(path7, { withFileTypes: true })) {
121705
- newest = Math.max(newest, newestSourceMtime(join56(path7, entry.name)));
121647
+ newest = Math.max(newest, newestSourceMtime(join57(path7, entry.name)));
121706
121648
  }
121707
121649
  return newest;
121708
121650
  }
@@ -121711,7 +121653,7 @@ function checkoutCliNeedsBuild(root2) {
121711
121653
  const dist = checkoutCliDist(root2);
121712
121654
  if (!existsSync36(dist)) return true;
121713
121655
  const distTime = statSync11(dist).mtimeMs;
121714
- return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join56(root2, tree)) > distTime);
121656
+ return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join57(root2, tree)) > distTime);
121715
121657
  }
121716
121658
  async function ensureCheckoutCli(root2, output2) {
121717
121659
  if (!checkoutCliNeedsBuild(root2)) return false;
@@ -121732,8 +121674,9 @@ async function reexecBuiltCli(root2) {
121732
121674
  init_src();
121733
121675
  init_context();
121734
121676
  init_errors3();
121735
- import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync29 } from "node:fs";
121736
- import { basename as basename20, join as join57 } from "node:path";
121677
+ import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync28 } from "node:fs";
121678
+ import { basename as basename20, join as join58 } from "node:path";
121679
+ init_process();
121737
121680
  var PORTTA_DIRECTORY = ".portta";
121738
121681
  var OVERLAY_FILE = "compose.portta.yaml";
121739
121682
  var COMPOSE_FILE = "compose.yaml";
@@ -121743,17 +121686,17 @@ var DEMO_DIRECTORY_PREFIX = "portta-demo-";
121743
121686
  var MANIFEST_FILE = "portta.example.json";
121744
121687
  function demoDirectories(home2) {
121745
121688
  if (!existsSync37(home2)) return [];
121746
- return readdirSync7(home2, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith(DEMO_DIRECTORY_PREFIX)).map((entry) => join57(home2, entry.name)).sort();
121689
+ return readdirSync7(home2, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith(DEMO_DIRECTORY_PREFIX)).map((entry) => join58(home2, entry.name)).sort();
121747
121690
  }
121748
121691
  function findDemoStacks(home2) {
121749
121692
  return demoDirectories(home2).map((stackDir) => {
121750
- if (!existsSync37(join57(stackDir, COMPOSE_FILE))) return null;
121751
- const localOverlay = join57(PORTTA_DIRECTORY, OVERLAY_FILE);
121752
- const overlay2 = existsSync37(join57(stackDir, localOverlay)) || existsSync37(join57(stackDir, OVERLAY_FILE));
121693
+ if (!existsSync37(join58(stackDir, COMPOSE_FILE))) return null;
121694
+ const localOverlay = join58(PORTTA_DIRECTORY, OVERLAY_FILE);
121695
+ const overlay2 = existsSync37(join58(stackDir, localOverlay)) || existsSync37(join58(stackDir, OVERLAY_FILE));
121753
121696
  return {
121754
121697
  name: basename20(stackDir),
121755
121698
  dir: stackDir,
121756
- files: overlay2 ? [COMPOSE_FILE, existsSync37(join57(stackDir, localOverlay)) ? localOverlay : OVERLAY_FILE] : [COMPOSE_FILE],
121699
+ files: overlay2 ? [COMPOSE_FILE, existsSync37(join58(stackDir, localOverlay)) ? localOverlay : OVERLAY_FILE] : [COMPOSE_FILE],
121757
121700
  overlay: overlay2
121758
121701
  };
121759
121702
  }).filter((stack) => stack !== null).sort((left, right) => left.name.localeCompare(right.name));
@@ -121764,10 +121707,10 @@ function demoComposeArgs(stack, action) {
121764
121707
  return ["compose", ...files, "down", "-v"];
121765
121708
  }
121766
121709
  function readDemoProject(stackDir) {
121767
- const path7 = join57(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121710
+ const path7 = join58(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121768
121711
  if (!existsSync37(path7)) return null;
121769
121712
  try {
121770
- const manifest = JSON.parse(readFileSync29(path7, "utf8"));
121713
+ const manifest = JSON.parse(readFileSync28(path7, "utf8"));
121771
121714
  const project2 = manifest.project;
121772
121715
  if (typeof project2?.["slug"] !== "string" || typeof project2["name"] !== "string") return null;
121773
121716
  const repositories = (Array.isArray(manifest.repositories) ? manifest.repositories : []).filter((repository) => typeof repository?.["name"] === "string" && typeof repository["relativePath"] === "string").map((repository) => ({
@@ -121932,7 +121875,7 @@ function checkoutLocalEnv() {
121932
121875
  };
121933
121876
  }
121934
121877
  function persistEnv(root2, values) {
121935
- const path7 = join58(root2, ".env");
121878
+ const path7 = join59(root2, ".env");
121936
121879
  patchEnvFile(path7, values);
121937
121880
  }
121938
121881
  function buildsLocally(command) {
@@ -121948,10 +121891,10 @@ async function compose2(command, args, stdio = "inherit", extra = {}) {
121948
121891
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: context.env, stdio, reject: extra.reject });
121949
121892
  }
121950
121893
  function ensureAuthState(root2) {
121951
- const authDirectory = join58(root2, "state/auth");
121952
- mkdirSync18(authDirectory, { recursive: true, mode: 448 });
121894
+ const authDirectory = join59(root2, "state/auth");
121895
+ mkdirSync19(authDirectory, { recursive: true, mode: 448 });
121953
121896
  chmodSync9(authDirectory, 448);
121954
- const path7 = join58(root2, ".env");
121897
+ const path7 = join59(root2, ".env");
121955
121898
  prepareEnvFile(path7);
121956
121899
  syncForwardAuth(root2);
121957
121900
  }
@@ -122003,7 +121946,7 @@ async function versionCommand(command) {
122003
121946
  output2.line(` panel ${panel.detail}`);
122004
121947
  if (!compatible) {
122005
121948
  output2.warning(`this CLI is ${cli} and the installation is ${gateway}`);
122006
- output2.hint("update the installation by re-running the installer, or install the matching CLI: npm i -g portta@" + gateway);
121949
+ output2.hint(`update the installation with portta setup, or install the matching CLI: npm install -g @codions/portta@${gateway}`);
122007
121950
  }
122008
121951
  }
122009
121952
  async function bootstrapCommand(options, command) {
@@ -122014,9 +121957,8 @@ async function bootstrapCommand(options, command) {
122014
121957
  await requireDocker();
122015
121958
  const composeVersion = await runProcess("docker", ["compose", "version", "--short"], { reject: false });
122016
121959
  if (composeVersion.exitCode !== 0) throw new CliError("Docker Compose v2 is required", EXIT.precondition);
122017
- prepareEnvFile(join58(context.root, ".env"));
122018
- for (const directory of ["state", "state/auth", "state/ssh", "state/git", "state/github", "state/metrics", "state/environment", "state/logs", "config/tls", "config/traefik/dynamic"]) mkdirSync18(join58(context.root, directory), { recursive: true });
122019
- chmodSync9(join58(context.root, "state/ssh"), 448);
121960
+ prepareEnvFile(join59(context.root, ".env"));
121961
+ ensureInstallationDirectories(context.root);
122020
121962
  ensureAuthState(context.root);
122021
121963
  const network2 = await ensureNetwork(context.config.network);
122022
121964
  output2.progress(`${network2.padEnd(8)} shared network ${context.config.network}`);
@@ -122025,7 +121967,7 @@ async function bootstrapCommand(options, command) {
122025
121967
  }
122026
121968
  async function upCommand(profile, options, command) {
122027
121969
  if (profile) command.setOptionValueWithSource("profile", profile, "cli");
122028
- prepareEnvFile(join58(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
121970
+ prepareEnvFile(join59(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
122029
121971
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: profile ?? globals8(command).profile }));
122030
121972
  const context = gatewayContext({ profile: profile ?? globals8(command).profile });
122031
121973
  if (options.localRelease) context.env["PORTTA_LOCAL_RELEASE"] = "true";
@@ -122089,7 +122031,7 @@ async function devCommand(profile, options, command) {
122089
122031
  return;
122090
122032
  }
122091
122033
  if (options.demo) requireDemoStacks(command);
122092
- const needsBootstrap = !existsSync38(join58(existing.root, ".env"));
122034
+ const needsBootstrap = !existsSync38(join59(existing.root, ".env"));
122093
122035
  output2.progress(`dev runs: ${[
122094
122036
  ...options.reset ? ["wipe Portta-managed containers and volumes"] : [],
122095
122037
  ...needsBootstrap ? ["prepare the checkout"] : [],
@@ -122127,10 +122069,10 @@ var REGENERABLE_STATE_DIRS = ["state/git", "state/metrics", "state/environment"]
122127
122069
  function clearRegenerableState(root2) {
122128
122070
  const cleared = [];
122129
122071
  for (const relative6 of REGENERABLE_STATE_DIRS) {
122130
- const directory = join58(root2, relative6);
122072
+ const directory = join59(root2, relative6);
122131
122073
  if (!existsSync38(directory)) continue;
122132
122074
  for (const entry of readdirSync8(directory, { withFileTypes: true })) {
122133
- rmSync10(join58(directory, entry.name), { recursive: true, force: true });
122075
+ rmSync10(join59(directory, entry.name), { recursive: true, force: true });
122134
122076
  }
122135
122077
  cleared.push(relative6);
122136
122078
  }
@@ -122209,7 +122151,7 @@ async function logsCommand(service2, options, command) {
122209
122151
  } else await compose2(command, ["logs", ...options.follow === false ? [] : ["--follow"], "--tail", options.tail ?? "200", ...service2 ? [service2] : []]);
122210
122152
  }
122211
122153
  async function updateCommand(command) {
122212
- prepareEnvFile(join58(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122154
+ prepareEnvFile(join59(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122213
122155
  await compose2(command, ["config", "--quiet"]);
122214
122156
  await compose2(command, ["pull", "--ignore-buildable"]);
122215
122157
  await confirm("recreate gateway components with the pulled images?", globals8(command).yes === true);
@@ -122271,7 +122213,7 @@ async function doctorCommand(command) {
122271
122213
  ...entry.fix ? { fix: entry.fix } : {}
122272
122214
  }));
122273
122215
  for (const file2 of context.composeFiles) {
122274
- checks.push({ id: `compose:${file2}`, status: existsSync38(join58(context.root, file2)) ? "pass" : "fail", message: `${file2} exists` });
122216
+ checks.push({ id: `compose:${file2}`, status: existsSync38(join59(context.root, file2)) ? "pass" : "fail", message: `${file2} exists` });
122275
122217
  }
122276
122218
  const aliases = readAliases(context.root);
122277
122219
  if (aliases.length > 0) {
@@ -122289,10 +122231,10 @@ async function doctorCommand(command) {
122289
122231
  if (failed.length) throw new CliError(`${failed.length} doctor check(s) failed`);
122290
122232
  }
122291
122233
  function readAliases(root2) {
122292
- const path7 = join58(root2, "config/traefik/dynamic/portta-aliases.yaml");
122234
+ const path7 = join59(root2, "config/traefik/dynamic/portta-aliases.yaml");
122293
122235
  if (!existsSync38(path7)) return [];
122294
122236
  try {
122295
- return parseAliases(readFileSync30(path7, "utf8"));
122237
+ return parseAliases(readFileSync29(path7, "utf8"));
122296
122238
  } catch {
122297
122239
  return [];
122298
122240
  }
@@ -122321,9 +122263,10 @@ async function urlsCommand(options, command) {
122321
122263
  // src/commands/network.ts
122322
122264
  init_src();
122323
122265
  import { lookup } from "node:dns/promises";
122324
- import { join as join59 } from "node:path";
122266
+ import { join as join60 } from "node:path";
122325
122267
  init_context();
122326
122268
  init_errors3();
122269
+ init_process();
122327
122270
  function globals9(command) {
122328
122271
  return command.optsWithGlobals();
122329
122272
  }
@@ -122359,7 +122302,7 @@ async function publicStatus(command) {
122359
122302
  }
122360
122303
  async function writeSetting(key, value3, command) {
122361
122304
  const context = gatewayContext({ profile: globals9(command).profile });
122362
- const path7 = join59(context.root, ".env");
122305
+ const path7 = join60(context.root, ".env");
122363
122306
  patchEnvFile(path7, { [key]: value3 });
122364
122307
  }
122365
122308
  async function publicEnable(command) {
@@ -122445,18 +122388,19 @@ async function dnsSetup(options, command) {
122445
122388
 
122446
122389
  // src/commands/host-service.ts
122447
122390
  init_config2();
122448
- import { chmodSync as chmodSync10, existsSync as existsSync39, mkdirSync as mkdirSync19, readFileSync as readFileSync31, realpathSync as realpathSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "node:fs";
122391
+ import { chmodSync as chmodSync10, existsSync as existsSync39, mkdirSync as mkdirSync20, readFileSync as readFileSync30, realpathSync as realpathSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "node:fs";
122449
122392
  import { homedir as homedir9 } from "node:os";
122450
- import { dirname as dirname29, join as join60 } from "node:path";
122393
+ import { dirname as dirname29, join as join61 } from "node:path";
122451
122394
  init_context();
122452
122395
  init_errors3();
122396
+ init_process();
122453
122397
  var AUTO_PICKUP_ENV_VARS = ["LINEAR_API_KEY"];
122454
122398
  var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PATH", "PORTTA_ROOT"]);
122455
122399
  function logFile2() {
122456
- return join60(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122400
+ return join61(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122457
122401
  }
122458
122402
  function serviceFilePath(platform4, home2 = homedir9()) {
122459
- return platform4 === "linux" ? join60(home2, ".config", "systemd", "user", `${SERVICE_IDENTITY.name}.service`) : join60(home2, "Library", "LaunchAgents", `${SERVICE_IDENTITY.launchdLabel}.plist`);
122403
+ return platform4 === "linux" ? join61(home2, ".config", "systemd", "user", `${SERVICE_IDENTITY.name}.service`) : join61(home2, "Library", "LaunchAgents", `${SERVICE_IDENTITY.launchdLabel}.plist`);
122460
122404
  }
122461
122405
  function escapePlistText(value3) {
122462
122406
  return value3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -122526,7 +122470,7 @@ var LAUNCHD_ENV_ENTRY_RE = /<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g;
122526
122470
  function readEnvVarsFromUnit(filePath, platform4) {
122527
122471
  let text;
122528
122472
  try {
122529
- text = readFileSync31(filePath, "utf8");
122473
+ text = readFileSync30(filePath, "utf8");
122530
122474
  } catch {
122531
122475
  return {};
122532
122476
  }
@@ -122657,7 +122601,7 @@ async function hostService(action, command) {
122657
122601
  ${notes.join("\n")}`);
122658
122602
  await confirm(`${installed ? "Reinstall" : "Install"} the ${SERVICE_IDENTITY.name} service?`, Boolean(options.yes));
122659
122603
  if (installed) await runAll(serviceCommands("uninstall", platform4, filePath), output2, true);
122660
- mkdirSync19(dirname29(filePath), { recursive: true });
122604
+ mkdirSync20(dirname29(filePath), { recursive: true });
122661
122605
  writeFileSync14(filePath, content);
122662
122606
  if (Object.keys(envVars).length > 0) chmodSync10(filePath, 384);
122663
122607
  await runAll(serviceCommands("install", platform4, filePath), output2);
@@ -122698,7 +122642,8 @@ init_src();
122698
122642
  init_src();
122699
122643
  init_context();
122700
122644
  init_errors3();
122701
- import { join as join61 } from "node:path";
122645
+ import { join as join62 } from "node:path";
122646
+ init_process();
122702
122647
  function globals10(command) {
122703
122648
  return command.optsWithGlobals();
122704
122649
  }
@@ -122740,7 +122685,7 @@ function setting(name) {
122740
122685
  return found;
122741
122686
  }
122742
122687
  function write2(root2, values) {
122743
- const path7 = join61(root2, ".env");
122688
+ const path7 = join62(root2, ".env");
122744
122689
  patchEnvFile(path7, values);
122745
122690
  }
122746
122691
  async function configList(command) {
@@ -122950,18 +122895,19 @@ async function configSet(name, value3, options, command) {
122950
122895
  }
122951
122896
  function configPrepare(command) {
122952
122897
  const context = gatewayContext({ profile: globals10(command).profile });
122953
- prepareEnvFile(join61(context.root, ".env"));
122898
+ prepareEnvFile(join62(context.root, ".env"));
122954
122899
  new Output(globals10(command)).progress("configuration prepared from .env.example; existing values preserved");
122955
122900
  }
122956
122901
 
122957
122902
  // src/commands/setup.ts
122958
122903
  init_src();
122959
122904
  init_context();
122960
- import { chmodSync as chmodSync11, copyFileSync as copyFileSync4, cpSync, existsSync as existsSync40, mkdirSync as mkdirSync20, readdirSync as readdirSync9, realpathSync as realpathSync8, rmSync as rmSync11 } from "node:fs";
122905
+ import { chmodSync as chmodSync11, copyFileSync as copyFileSync4, cpSync, existsSync as existsSync40, mkdirSync as mkdirSync21, readdirSync as readdirSync9, realpathSync as realpathSync8, rmSync as rmSync11 } from "node:fs";
122961
122906
  import { homedir as homedir10 } from "node:os";
122962
- import { dirname as dirname30, join as join62, resolve as resolve32 } from "node:path";
122907
+ import { dirname as dirname30, join as join63, resolve as resolve32 } from "node:path";
122963
122908
  import { fileURLToPath as fileURLToPath8 } from "node:url";
122964
122909
  init_errors3();
122910
+ init_process();
122965
122911
  function globals11(command) {
122966
122912
  return command.optsWithGlobals();
122967
122913
  }
@@ -122975,14 +122921,14 @@ async function available(file2, args) {
122975
122921
  function packagedRuntime() {
122976
122922
  const explicit = process.env["PORTTA_RUNTIME_ROOT"];
122977
122923
  if (explicit) return resolve32(explicit);
122978
- const candidates = [join62(import.meta.dirname, "runtime"), join62(import.meta.dirname, "..", "runtime")];
122979
- const found = candidates.find((candidate) => existsSync40(join62(candidate, "VERSION")));
122980
- if (!found) throw new PreconditionError("the Portta package does not contain its runtime assets", "reinstall the `portta` npm package");
122924
+ const candidates = [join63(import.meta.dirname, "runtime"), join63(import.meta.dirname, "..", "runtime")];
122925
+ const found = candidates.find((candidate) => existsSync40(join63(candidate, "VERSION")));
122926
+ if (!found) throw new PreconditionError("the Portta package does not contain its runtime assets", "reinstall the `@codions/portta` npm package");
122981
122927
  return found;
122982
122928
  }
122983
122929
  function installRuntime(source, target) {
122984
- mkdirSync20(target, { recursive: true });
122985
- const cache2 = join62(target, "runtime");
122930
+ mkdirSync21(target, { recursive: true });
122931
+ const cache2 = join63(target, "runtime");
122986
122932
  const sameCache = existsSync40(cache2) && realpathSync8(source) === realpathSync8(cache2);
122987
122933
  if (!sameCache) {
122988
122934
  rmSync11(cache2, { recursive: true, force: true });
@@ -122990,32 +122936,32 @@ function installRuntime(source, target) {
122990
122936
  }
122991
122937
  for (const entry of readdirSync9(source)) {
122992
122938
  if (entry === "config") continue;
122993
- const destination = join62(target, entry);
122939
+ const destination = join63(target, entry);
122994
122940
  rmSync11(destination, { recursive: true, force: true });
122995
- cpSync(join62(source, entry), destination, { recursive: true, force: true });
122941
+ cpSync(join63(source, entry), destination, { recursive: true, force: true });
122996
122942
  }
122997
- const defaults = join62(source, "config", "traefik", "dynamic");
122998
- const dynamic = join62(target, "config", "traefik", "dynamic");
122999
- mkdirSync20(dynamic, { recursive: true });
122943
+ const defaults = join63(source, "config", "traefik", "dynamic");
122944
+ const dynamic = join63(target, "config", "traefik", "dynamic");
122945
+ mkdirSync21(dynamic, { recursive: true });
123000
122946
  for (const entry of readdirSync9(defaults)) {
123001
- const destination = join62(dynamic, entry);
123002
- if (!existsSync40(destination)) copyFileSync4(join62(defaults, entry), destination);
122947
+ const destination = join63(dynamic, entry);
122948
+ if (!existsSync40(destination)) copyFileSync4(join63(defaults, entry), destination);
123003
122949
  }
123004
- const bin = join62(target, "bin");
123005
- mkdirSync20(bin, { recursive: true });
122950
+ const bin = join63(target, "bin");
122951
+ mkdirSync21(bin, { recursive: true });
123006
122952
  const executable2 = fileURLToPath8(import.meta.url);
123007
- const installed = join62(bin, "portta");
122953
+ const installed = join63(bin, "portta");
123008
122954
  if (resolve32(executable2) !== resolve32(installed)) copyFileSync4(executable2, installed);
123009
122955
  chmodSync11(installed, 493);
123010
- const docs2 = join62(import.meta.dirname, "documentation.json");
123011
- if (existsSync40(docs2)) copyFileSync4(docs2, join62(bin, "documentation.json"));
122956
+ const docs2 = join63(import.meta.dirname, "documentation.json");
122957
+ if (existsSync40(docs2)) copyFileSync4(docs2, join63(bin, "documentation.json"));
123012
122958
  }
123013
122959
  async function setupCommand(options, command) {
123014
122960
  const global3 = globals11(command);
123015
122961
  const output2 = new Output(global3);
123016
122962
  if (process.platform === "win32") throw new PreconditionError("setup requires a POSIX host");
123017
122963
  const currentRoot = findGatewayRoot();
123018
- const target = resolve32(options.dir ?? currentRoot ?? join62(homedir10(), "portta"));
122964
+ const target = resolve32(options.dir ?? currentRoot ?? join63(homedir10(), "portta"));
123019
122965
  const profile = options.profile ?? global3.profile ?? "local";
123020
122966
  const runtime2 = packagedRuntime();
123021
122967
  const steps = [];
@@ -123024,8 +122970,9 @@ async function setupCommand(options, command) {
123024
122970
  if (!output2.json) output2.progress(`${status.padEnd(8)} ${detail2}`);
123025
122971
  };
123026
122972
  const nodeVersion = process.versions.node;
123027
- if (major(nodeVersion) < 24) throw new PreconditionError(`Node ${nodeVersion} is too old`, "Node 24 or newer is required for the full CLI");
122973
+ if (major(nodeVersion) < 24) throw new PreconditionError(`Node ${nodeVersion} is too old`, "Node 24 or newer is required");
123028
122974
  record6("node", "ok", `Node ${nodeVersion}`);
122975
+ await requireDocker();
123029
122976
  const docker = await available("docker", ["version", "--format", "{{.Server.Version}}"]);
123030
122977
  if (!docker.ok || major(docker.value) < 24) throw new PreconditionError("Docker Engine 24 or newer is required", "setup never installs Docker or invokes a system package manager");
123031
122978
  const compose4 = await available("docker", ["compose", "version", "--short"]);
@@ -123033,25 +122980,24 @@ async function setupCommand(options, command) {
123033
122980
  record6("docker", "ok", `Docker ${docker.value}, Compose ${compose4.value}`);
123034
122981
  if (options.dryRun) {
123035
122982
  record6("runtime", "planned", `install packaged runtime in ${target}`);
123036
- record6("environment", "planned", `create .env only if absent in ${target}`);
122983
+ record6("environment", "planned", `prepare .env from .env.example in ${target}, keeping set values`);
123037
122984
  record6("network", "planned", "ensure the shared gateway network");
123038
122985
  record6("gateway", "planned", `pull pinned images and start profile ${profile}`);
123039
122986
  if (output2.json) output2.data({ dryRun: true, target, steps });
123040
122987
  return;
123041
122988
  }
123042
122989
  await confirm(`set up Portta in ${target}?`, global3.yes === true);
123043
- if (existsSync40(target) && readdirSync9(target).length > 0 && !existsSync40(join62(target, "docker", "compose", "compose.yaml"))) {
122990
+ if (existsSync40(target) && readdirSync9(target).length > 0 && !existsSync40(join63(target, "docker", "compose", "compose.yaml"))) {
123044
122991
  throw new RefusedError(`${target} exists and is not a Portta installation`, "choose an empty --dir; setup never overwrites an unrelated directory");
123045
122992
  }
123046
- mkdirSync20(dirname30(target), { recursive: true });
123047
- const updating = existsSync40(join62(target, "VERSION"));
122993
+ mkdirSync21(dirname30(target), { recursive: true });
122994
+ const updating = existsSync40(join63(target, "VERSION"));
123048
122995
  installRuntime(runtime2, target);
123049
122996
  record6("runtime", updating ? "updated" : "created", `${target}`);
123050
- const envFile = join62(target, ".env");
122997
+ const envFile = join63(target, ".env");
123051
122998
  prepareEnvFile(envFile);
123052
122999
  record6("environment", "updated", "environment prepared from .env.example");
123053
- for (const directory of ["state", "state/auth", "state/ssh", "state/runner", "state/access", "state/cloudflared", "state/git", "state/metrics", "state/environment", "state/logs", "config/tls", "config/traefik/dynamic"]) mkdirSync20(join62(target, directory), { recursive: true });
123054
- for (const directory of ["state/auth", "state/ssh", "state/runner", "state/cloudflared"]) chmodSync11(join62(target, directory), 448);
123000
+ ensureInstallationDirectories(target);
123055
123001
  record6("directories", "ok", "gateway state directories");
123056
123002
  const context = gatewayContext({ root: target, profile });
123057
123003
  const network2 = await ensureNetwork(context.config.network);
@@ -123066,13 +123012,21 @@ async function setupCommand(options, command) {
123066
123012
  const running = await runProcess("docker", ["compose", ...composeArguments(context), "ps", "--status", "running", "--quiet"], { cwd: target, env: context.env });
123067
123013
  if (!running.stdout.trim()) throw new PreconditionError("gateway started but no component remained running", `run portta doctor inside ${target}`);
123068
123014
  record6("doctor", "ok", "gateway components are running");
123069
- if (output2.json) output2.data({ dryRun: false, target, steps });
123015
+ if (output2.json) {
123016
+ output2.data({ dryRun: false, target, steps });
123017
+ return;
123018
+ }
123019
+ output2.progress("");
123020
+ output2.progress(`Portta is installed in ${target}.`);
123021
+ if (resolve32(target) !== resolve32(join63(homedir10(), "portta"))) output2.progress(`Run portta from anywhere with PORTTA_HOME=${target} exported, or from inside that directory.`);
123022
+ output2.progress(`The panel is off by default: portta web up starts it on http://127.0.0.1:${context.config.webPort}`);
123023
+ output2.progress("portta doctor checks the installation.");
123070
123024
  }
123071
123025
 
123072
123026
  // src/commands/auth.ts
123073
123027
  init_context();
123074
123028
  init_errors3();
123075
- import { readFileSync as readFileSync32 } from "node:fs";
123029
+ import { readFileSync as readFileSync31 } from "node:fs";
123076
123030
  function globals12(command) {
123077
123031
  return command.optsWithGlobals();
123078
123032
  }
@@ -123087,7 +123041,7 @@ function panelUrlFor2(command) {
123087
123041
  }
123088
123042
  async function authBootstrap(options, command) {
123089
123043
  if (!options.name || !options.email) throw new UsageError("--name and --email are required");
123090
- const password = options.passwordStdin ? readFileSync32(0, "utf8").trim() : "";
123044
+ const password = options.passwordStdin ? readFileSync31(0, "utf8").trim() : "";
123091
123045
  if (!password) throw new UsageError("the password is read from stdin", 'printf %s "$PASSWORD" | portta auth bootstrap --name \u2026 --email \u2026 --password-stdin');
123092
123046
  if (password.length < 10) throw new UsageError("the password must be at least 10 characters");
123093
123047
  const { client, output: output2 } = clientFor(command, { actor: void 0, actorKind: "human" });
@@ -123120,7 +123074,7 @@ async function authLogin(options, command) {
123120
123074
  }
123121
123075
  async function readSecret() {
123122
123076
  if (!process.stdin.isTTY) {
123123
- const piped = readFileSync32(0, "utf8").trim();
123077
+ const piped = readFileSync31(0, "utf8").trim();
123124
123078
  if (piped) return piped;
123125
123079
  throw new UsageError("no token on stdin", "pass --token, or run this in a terminal");
123126
123080
  }
@@ -123259,23 +123213,23 @@ init_src();
123259
123213
  init_context();
123260
123214
  init_errors3();
123261
123215
  import { randomBytes as randomBytes8 } from "node:crypto";
123262
- import { chmodSync as chmodSync12, mkdirSync as mkdirSync21, readFileSync as readFileSync33 } from "node:fs";
123263
- import { dirname as dirname31, join as join63 } from "node:path";
123216
+ import { chmodSync as chmodSync12, mkdirSync as mkdirSync22, readFileSync as readFileSync32 } from "node:fs";
123217
+ import { dirname as dirname31, join as join64 } from "node:path";
123264
123218
  function globals13(command) {
123265
123219
  return command.optsWithGlobals();
123266
123220
  }
123267
123221
  function paths(command) {
123268
123222
  const root2 = gatewayContext({ profile: globals13(command).profile }).root;
123269
123223
  return {
123270
- store: join63(root2, "state/auth/protections.json"),
123271
- dynamic: join63(root2, "config/traefik/dynamic/portta-auth.yaml")
123224
+ store: join64(root2, "state/auth/protections.json"),
123225
+ dynamic: join64(root2, "config/traefik/dynamic/portta-auth.yaml")
123272
123226
  };
123273
123227
  }
123274
123228
  function save(command, store) {
123275
123229
  const target = paths(command);
123276
- mkdirSync21(dirname31(target.store), { recursive: true, mode: 448 });
123230
+ mkdirSync22(dirname31(target.store), { recursive: true, mode: 448 });
123277
123231
  chmodSync12(dirname31(target.store), 448);
123278
- mkdirSync21(dirname31(target.dynamic), { recursive: true });
123232
+ mkdirSync22(dirname31(target.dynamic), { recursive: true });
123279
123233
  writeProtectionStore(target.store, store);
123280
123234
  writeEnvFile(target.dynamic, renderAuthDynamic(store));
123281
123235
  }
@@ -123291,7 +123245,7 @@ async function protectHost(hostInput, options, command) {
123291
123245
  const entryPoint = options.entrypoint ?? (gatewayContext({ profile: globals13(command).profile }).config.tlsEnabled ? "websecure" : "web");
123292
123246
  if (!/^[A-Za-z0-9_-]+$/.test(entryPoint)) throw new UsageError(`invalid entrypoint: ${entryPoint}`);
123293
123247
  const generated = options.passwordStdin !== true;
123294
- const password = generated ? randomBytes8(20).toString("base64url").slice(0, 20).match(/.{1,5}/g).join("-") : readFileSync33(0, "utf8").trim();
123248
+ const password = generated ? randomBytes8(20).toString("base64url").slice(0, 20).match(/.{1,5}/g).join("-") : readFileSync32(0, "utf8").trim();
123295
123249
  if (!password) throw new UsageError("no password on stdin");
123296
123250
  const target = paths(command);
123297
123251
  const existing = readProtectionStore(target.store);
@@ -123344,11 +123298,12 @@ async function protectStatus(hostInput, command) {
123344
123298
  init_src();
123345
123299
  init_errors3();
123346
123300
  init_context();
123347
- import { readFileSync as readFileSync34 } from "node:fs";
123301
+ import { readFileSync as readFileSync33 } from "node:fs";
123348
123302
  import { randomBytes as randomBytes9 } from "node:crypto";
123303
+ init_process();
123349
123304
  function passwordFrom(options) {
123350
123305
  if (options.passwordStdin) {
123351
- const password2 = readFileSync34(0, "utf8").trim();
123306
+ const password2 = readFileSync33(0, "utf8").trim();
123352
123307
  if (!password2) throw new UsageError("no password on stdin");
123353
123308
  if (password2.length < 10) throw new UsageError("the password must be at least 10 characters");
123354
123309
  return { password: password2, generated: false };
@@ -123476,13 +123431,13 @@ init_zod();
123476
123431
  init_context();
123477
123432
  init_errors3();
123478
123433
  import { existsSync as existsSync41 } from "node:fs";
123479
- import { join as join64 } from "node:path";
123434
+ import { join as join65 } from "node:path";
123480
123435
  var Share2 = external_exports.object({ id: external_exports.string(), mode: external_exports.enum(["public", "protected"]), host: external_exports.string(), entryPoint: external_exports.string(), container: external_exports.string(), port: external_exports.number(), expiresAt: external_exports.number(), user: external_exports.string().nullable().optional() }).passthrough();
123481
123436
  function globals14(command) {
123482
123437
  return command.optsWithGlobals();
123483
123438
  }
123484
123439
  function path6(command) {
123485
- return join64(gatewayContext({ profile: globals14(command).profile }).root, "config/traefik/dynamic/portta-shares.yaml");
123440
+ return join65(gatewayContext({ profile: globals14(command).profile }).root, "config/traefik/dynamic/portta-shares.yaml");
123486
123441
  }
123487
123442
  function root(command) {
123488
123443
  return gatewayContext({ profile: globals14(command).profile }).root;
@@ -123498,11 +123453,11 @@ function write3(command, shares) {
123498
123453
  }
123499
123454
  function removeScopes(command, scopes) {
123500
123455
  const gateway = root(command);
123501
- const storePath = join64(gateway, "state/auth/protections.json");
123456
+ const storePath = join65(gateway, "state/auth/protections.json");
123502
123457
  const store = readProtectionStore(storePath);
123503
123458
  const next = { ...store, protections: store.protections.filter((protection) => !scopes.has(protection.scope)) };
123504
123459
  writeProtectionStore(storePath, next);
123505
- writeEnvFile(join64(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123460
+ writeEnvFile(join65(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123506
123461
  }
123507
123462
  async function shareList(command) {
123508
123463
  const shares = read(command);
@@ -123533,14 +123488,16 @@ async function shareGc(command) {
123533
123488
  // src/commands/tls.ts
123534
123489
  init_src();
123535
123490
  init_context();
123536
- import { chmodSync as chmodSync13, existsSync as existsSync42, mkdirSync as mkdirSync22, writeFileSync as writeFileSync15 } from "node:fs";
123491
+ import { chmodSync as chmodSync13, existsSync as existsSync42, mkdirSync as mkdirSync23, writeFileSync as writeFileSync15 } from "node:fs";
123537
123492
  import { platform as platform3 } from "node:os";
123538
- import { join as join65 } from "node:path";
123493
+ import { join as join66 } from "node:path";
123539
123494
  init_errors3();
123495
+ init_process();
123540
123496
 
123541
123497
  // src/toolbox.ts
123542
123498
  init_errors3();
123543
123499
  init_src();
123500
+ init_process();
123544
123501
  init_context();
123545
123502
  async function toolboxExists(image) {
123546
123503
  return !(await runProcess("docker", ["image", "inspect", image], { reject: false })).failed;
@@ -123570,14 +123527,14 @@ function globals15(command) {
123570
123527
  return command.optsWithGlobals();
123571
123528
  }
123572
123529
  function tlsPaths(root2) {
123573
- const directory = join65(root2, "config/tls");
123530
+ const directory = join66(root2, "config/tls");
123574
123531
  return {
123575
123532
  directory,
123576
- caKey: join65(directory, "portta-ca.key"),
123577
- caCertificate: join65(directory, "portta-ca.crt"),
123578
- leafKey: join65(directory, "wildcard.key"),
123579
- leafCertificate: join65(directory, "wildcard.crt"),
123580
- dynamic: join65(root2, "config/traefik/dynamic/local-tls.yaml")
123533
+ caKey: join66(directory, "portta-ca.key"),
123534
+ caCertificate: join66(directory, "portta-ca.crt"),
123535
+ leafKey: join66(directory, "wildcard.key"),
123536
+ leafCertificate: join66(directory, "wildcard.crt"),
123537
+ dynamic: join66(root2, "config/traefik/dynamic/local-tls.yaml")
123581
123538
  };
123582
123539
  }
123583
123540
  function localTlsDynamic() {
@@ -123654,7 +123611,7 @@ async function tlsInit(command) {
123654
123611
  await requireDocker();
123655
123612
  const paths3 = tlsPaths(context.root);
123656
123613
  const domain2 = context.config.domain;
123657
- mkdirSync22(paths3.directory, { recursive: true });
123614
+ mkdirSync23(paths3.directory, { recursive: true });
123658
123615
  chmodSync13(paths3.directory, 448);
123659
123616
  if (existsSync42(paths3.caKey)) {
123660
123617
  output2.progress("reusing the existing local CA");
@@ -123685,7 +123642,7 @@ async function tlsInit(command) {
123685
123642
  }
123686
123643
  output2.progress(`issued ${paths3.leafCertificate} for *.${domain2}`);
123687
123644
  writeFileSync15(paths3.dynamic, localTlsDynamic());
123688
- const envPath = join65(context.root, ".env");
123645
+ const envPath = join66(context.root, ".env");
123689
123646
  patchEnvFile(envPath, { TLS_ENABLED: "true", TLS_MODE: "local" });
123690
123647
  output2.progress("TLS enabled in .env");
123691
123648
  output2.line("");
@@ -123734,22 +123691,23 @@ async function tlsUntrust(command) {
123734
123691
  output2.line(`To delete the key material as well: rm -rf ${paths2(context.root)}`);
123735
123692
  }
123736
123693
  function paths2(root2) {
123737
- return join65(root2, "config/tls");
123694
+ return join66(root2, "config/tls");
123738
123695
  }
123739
123696
 
123740
123697
  // src/commands/maintenance.ts
123741
123698
  init_src();
123742
123699
  init_context();
123743
123700
  init_errors3();
123744
- import { chmodSync as chmodSync14, copyFileSync as copyFileSync5, cpSync as cpSync2, existsSync as existsSync43, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync35, rmSync as rmSync12, statSync as statSync12, writeFileSync as writeFileSync16 } from "node:fs";
123701
+ import { chmodSync as chmodSync14, copyFileSync as copyFileSync5, cpSync as cpSync2, existsSync as existsSync43, mkdirSync as mkdirSync24, mkdtempSync as mkdtempSync3, readFileSync as readFileSync34, rmSync as rmSync12, statSync as statSync12, writeFileSync as writeFileSync16 } from "node:fs";
123745
123702
  import { hostname as hostname3, tmpdir as tmpdir5 } from "node:os";
123746
- import { dirname as dirname32, join as join66 } from "node:path";
123703
+ import { dirname as dirname32, join as join67 } from "node:path";
123704
+ init_process();
123747
123705
  function globals16(command) {
123748
123706
  return command.optsWithGlobals();
123749
123707
  }
123750
123708
  var BACKUP_VERSION = 1;
123751
123709
  function backupPaths(root2) {
123752
- return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join66(root2, path7)));
123710
+ return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join67(root2, path7)));
123753
123711
  }
123754
123712
  function renderManifest(manifest) {
123755
123713
  return `${JSON.stringify(manifest)}
@@ -123784,11 +123742,11 @@ async function backupCommand(options, command) {
123784
123742
  const output2 = new Output(global3);
123785
123743
  const context = gatewayContext({ profile: global3.profile });
123786
123744
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123787
- const target = options.output ?? join66(context.root, `portta-backup-${stamp}.tar.gz`);
123788
- const staging = mkdtempSync3(join66(tmpdir5(), "portta-backup-"));
123745
+ const target = options.output ?? join67(context.root, `portta-backup-${stamp}.tar.gz`);
123746
+ const staging = mkdtempSync3(join67(tmpdir5(), "portta-backup-"));
123789
123747
  chmodSync14(staging, 448);
123790
123748
  try {
123791
- writeFileSync16(join66(staging, "portta-backup.json"), renderManifest({
123749
+ writeFileSync16(join67(staging, "portta-backup.json"), renderManifest({
123792
123750
  version: BACKUP_VERSION,
123793
123751
  portta: context.version,
123794
123752
  created: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z"),
@@ -123796,12 +123754,12 @@ async function backupCommand(options, command) {
123796
123754
  }));
123797
123755
  const paths3 = backupPaths(context.root);
123798
123756
  for (const path7 of paths3) {
123799
- mkdirSync23(join66(staging, "tree", dirname32(path7)), { recursive: true });
123800
- cpSync2(join66(context.root, path7), join66(staging, "tree", path7), { recursive: true });
123757
+ mkdirSync24(join67(staging, "tree", dirname32(path7)), { recursive: true });
123758
+ cpSync2(join67(context.root, path7), join67(staging, "tree", path7), { recursive: true });
123801
123759
  }
123802
123760
  let database = false;
123803
123761
  if (options.database !== false) {
123804
- database = await dumpDatabase(context, join66(staging, "panel.db"));
123762
+ database = await dumpDatabase(context, join67(staging, "panel.db"));
123805
123763
  if (!database) {
123806
123764
  output2.warning("the panel database was not included");
123807
123765
  output2.hint("it exists once the panel has started, and copying it needs sqlite3 on this host; --no-database silences this");
@@ -123846,14 +123804,14 @@ async function restoreCommand(archive, options, command) {
123846
123804
  const context = gatewayContext({ profile: global3.profile });
123847
123805
  if (!archive) throw new UsageError("which backup?", "portta restore <file>");
123848
123806
  if (!existsSync43(archive)) throw new UsageError(`no such file: ${archive}`);
123849
- const staging = mkdtempSync3(join66(tmpdir5(), "portta-restore-"));
123807
+ const staging = mkdtempSync3(join67(tmpdir5(), "portta-restore-"));
123850
123808
  chmodSync14(staging, 448);
123851
123809
  try {
123852
123810
  const extracted = await runProcess("tar", ["-xzf", archive, "-C", staging], { reject: false });
123853
123811
  if (extracted.failed) throw new UsageError("that file is not a Portta backup");
123854
- const manifestPath2 = join66(staging, "portta-backup.json");
123812
+ const manifestPath2 = join67(staging, "portta-backup.json");
123855
123813
  if (!existsSync43(manifestPath2)) throw new UsageError("that archive has no Portta manifest");
123856
- const manifest = parseManifest(readFileSync35(manifestPath2, "utf8"));
123814
+ const manifest = parseManifest(readFileSync34(manifestPath2, "utf8"));
123857
123815
  if (!manifest) throw new UsageError("that archive has an unreadable Portta manifest");
123858
123816
  output2.progress(`restoring a backup taken from Portta ${manifest.portta}`);
123859
123817
  if (!options.force && await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-traefik-1`)) {
@@ -123863,23 +123821,23 @@ async function restoreCommand(archive, options, command) {
123863
123821
  );
123864
123822
  }
123865
123823
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123866
- const safety = join66(context.root, "state", `restore-${stamp}`);
123867
- mkdirSync23(safety, { recursive: true });
123824
+ const safety = join67(context.root, "state", `restore-${stamp}`);
123825
+ mkdirSync24(safety, { recursive: true });
123868
123826
  for (const path7 of [".env", "config"]) {
123869
- if (existsSync43(join66(context.root, path7))) {
123870
- cpSync2(join66(context.root, path7), join66(safety, path7), { recursive: true });
123827
+ if (existsSync43(join67(context.root, path7))) {
123828
+ cpSync2(join67(context.root, path7), join67(safety, path7), { recursive: true });
123871
123829
  }
123872
123830
  }
123873
123831
  output2.progress(`kept what was there under ${safety}`);
123874
- const tree = join66(staging, "tree");
123832
+ const tree = join67(staging, "tree");
123875
123833
  if (existsSync43(tree)) {
123876
123834
  for (const path7 of backupPaths(tree)) {
123877
- cpSync2(join66(tree, path7), join66(context.root, path7), { recursive: true, force: true });
123835
+ cpSync2(join67(tree, path7), join67(context.root, path7), { recursive: true, force: true });
123878
123836
  }
123879
123837
  output2.progress("configuration and state restored");
123880
123838
  }
123881
- if (existsSync43(join66(context.root, ".env"))) chmodSync14(join66(context.root, ".env"), 384);
123882
- const dump = join66(staging, "panel.db");
123839
+ if (existsSync43(join67(context.root, ".env"))) chmodSync14(join67(context.root, ".env"), 384);
123840
+ const dump = join67(staging, "panel.db");
123883
123841
  if (existsSync43(dump)) {
123884
123842
  const panelUp = await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-web-1`);
123885
123843
  const target = databaseFileFor(context.root);
@@ -123887,7 +123845,7 @@ async function restoreCommand(archive, options, command) {
123887
123845
  output2.warning("the panel is running, so its database was not replaced");
123888
123846
  output2.hint(`portta web down then: portta restore ${archive} --force`);
123889
123847
  } else {
123890
- mkdirSync23(dirname32(target), { recursive: true });
123848
+ mkdirSync24(dirname32(target), { recursive: true });
123891
123849
  for (const file2 of databaseFiles(target)) rmSync12(file2, { force: true });
123892
123850
  copyFileSync5(dump, target);
123893
123851
  chmodSync14(target, 384);
@@ -123901,21 +123859,6 @@ async function restoreCommand(archive, options, command) {
123901
123859
  rmSync12(staging, { recursive: true, force: true });
123902
123860
  }
123903
123861
  }
123904
- var REPAIR_DIRECTORIES = [
123905
- { path: "config/traefik/dynamic", mode: 493 },
123906
- { path: "config/tls", mode: 493 },
123907
- { path: "state/traefik/acme", mode: 448 },
123908
- { path: "state/tailscale", mode: 493 },
123909
- { path: "state/access", mode: 493 },
123910
- { path: "state/git", mode: 493 },
123911
- { path: "state/github", mode: 493 },
123912
- { path: "state/ssh", mode: 448 },
123913
- { path: "state/metrics", mode: 493 },
123914
- { path: "state/environment", mode: 493 },
123915
- { path: "state/logs", mode: 493 },
123916
- { path: "state/runner", mode: 448 },
123917
- { path: "state/cloudflared", mode: 448 }
123918
- ];
123919
123862
  var REPAIR_MODES = [
123920
123863
  { path: ".env", mode: 384 },
123921
123864
  { path: "state/traefik/acme", mode: 448 },
@@ -123923,7 +123866,8 @@ var REPAIR_MODES = [
123923
123866
  { path: "state/cloudflared", mode: 448 },
123924
123867
  { path: "state/cloudflared/credentials.json", mode: 384 },
123925
123868
  { path: "state/runner", mode: 448 },
123926
- { path: "state/ssh", mode: 448 }
123869
+ { path: "state/ssh", mode: 448 },
123870
+ { path: "state/auth", mode: 448 }
123927
123871
  ];
123928
123872
  async function repairCommand2(options, command) {
123929
123873
  const global3 = globals16(command);
@@ -123932,20 +123876,20 @@ async function repairCommand2(options, command) {
123932
123876
  const dry = options.dryRun ?? false;
123933
123877
  const changes = [];
123934
123878
  output2.progress("Repair");
123935
- for (const { path: path7, mode } of REPAIR_DIRECTORIES) {
123936
- const full = join66(context.root, path7);
123879
+ for (const { path: path7, mode } of INSTALLATION_DIRECTORIES) {
123880
+ const full = join67(context.root, path7);
123937
123881
  if (existsSync43(full)) continue;
123938
123882
  changes.push(`create ${path7}`);
123939
123883
  if (dry) {
123940
123884
  output2.line(` would create ${path7}`);
123941
123885
  continue;
123942
123886
  }
123943
- mkdirSync23(full, { recursive: true });
123887
+ mkdirSync24(full, { recursive: true });
123944
123888
  chmodSync14(full, mode);
123945
123889
  output2.progress(`created ${path7}`);
123946
123890
  }
123947
123891
  for (const { path: path7, mode } of REPAIR_MODES) {
123948
- const full = join66(context.root, path7);
123892
+ const full = join67(context.root, path7);
123949
123893
  if (!existsSync43(full)) continue;
123950
123894
  const have = fileMode(full);
123951
123895
  const want = mode.toString(8);
@@ -128928,7 +128872,8 @@ async function activityCommand(options, command) {
128928
128872
  // src/commands/build.ts
128929
128873
  init_src();
128930
128874
  init_context();
128931
- import { join as join67 } from "node:path";
128875
+ import { join as join68 } from "node:path";
128876
+ init_process();
128932
128877
  function globals18(command) {
128933
128878
  return command.optsWithGlobals();
128934
128879
  }
@@ -128941,11 +128886,11 @@ function localReleaseBuilds(root2, version3) {
128941
128886
  },
128942
128887
  {
128943
128888
  image: images.apply,
128944
- args: ["build", "--build-arg", `PORTTA_VERSION=${version3}`, "-t", images.apply, join67(root2, "docker", "images", "apply")]
128889
+ args: ["build", "--build-arg", `PORTTA_VERSION=${version3}`, "-t", images.apply, join68(root2, "docker", "images", "apply")]
128945
128890
  },
128946
128891
  {
128947
128892
  image: images.toolbox,
128948
- args: ["build", "--build-arg", `PORTTA_VERSION=${version3}`, "-t", images.toolbox, join67(root2, "docker", "images", "toolbox")]
128893
+ args: ["build", "--build-arg", `PORTTA_VERSION=${version3}`, "-t", images.toolbox, join68(root2, "docker", "images", "toolbox")]
128949
128894
  }
128950
128895
  ];
128951
128896
  }
@@ -128965,12 +128910,13 @@ async function buildCommand(command) {
128965
128910
 
128966
128911
  // src/commands/remote.ts
128967
128912
  init_src();
128968
- import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync36, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
128969
- import { basename as basename21, join as join68 } from "node:path";
128913
+ import { existsSync as existsSync44, mkdirSync as mkdirSync25, readFileSync as readFileSync35, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
128914
+ import { basename as basename21, join as join69 } from "node:path";
128970
128915
  import { createServer as createServer3 } from "node:net";
128971
128916
  import { randomBytes as randomBytes10 } from "node:crypto";
128972
128917
  init_context();
128973
128918
  init_errors3();
128919
+ init_process();
128974
128920
  function globals19(command) {
128975
128921
  return command.optsWithGlobals();
128976
128922
  }
@@ -129143,7 +129089,7 @@ async function remoteBootstrap(target, options, command) {
129143
129089
  output2.progress(" ./bin/portta network status confirm what is exposed");
129144
129090
  }
129145
129091
  function tunnelStateDir(root2) {
129146
- return join68(root2, "state/access/tunnels");
129092
+ return join69(root2, "state/access/tunnels");
129147
129093
  }
129148
129094
  function parseTunnelRecord(id, text) {
129149
129095
  try {
@@ -129174,9 +129120,9 @@ function readTunnels(root2) {
129174
129120
  if (!existsSync44(directory)) return [];
129175
129121
  const records = [];
129176
129122
  for (const name of readdirSync10(directory).filter((entry) => entry.endsWith(".json"))) {
129177
- const path7 = join68(directory, name);
129123
+ const path7 = join69(directory, name);
129178
129124
  try {
129179
- const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync36(path7, "utf8"));
129125
+ const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync35(path7, "utf8"));
129180
129126
  if (record6) records.push(record6);
129181
129127
  } catch {
129182
129128
  }
@@ -129228,7 +129174,7 @@ async function remoteAccessOpen(target, options, command) {
129228
129174
  const localPort = options.localPort ? Number(options.localPort) : await freeLocalPort();
129229
129175
  output2.progress("Opening the tunnel");
129230
129176
  const directoryPath = tunnelStateDir(context.root);
129231
- mkdirSync24(directoryPath, { recursive: true });
129177
+ mkdirSync25(directoryPath, { recursive: true });
129232
129178
  const id = randomBytes10(3).toString("hex");
129233
129179
  const pid = spawnDetached("ssh", sshArguments(target, context.env, [
129234
129180
  "-o",
@@ -129245,7 +129191,7 @@ async function remoteAccessOpen(target, options, command) {
129245
129191
  throw new PreconditionError("the SSH tunnel exited immediately", `check that ${target} is reachable and that ${localPort} is free locally`);
129246
129192
  }
129247
129193
  const record6 = { id, pid, target, project: options.project, service: options.service, remotePort, localPort, started: Math.floor(Date.now() / 1e3) };
129248
- writeFileSync17(join68(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129194
+ writeFileSync17(join69(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129249
129195
  if (output2.json) {
129250
129196
  output2.data({ ...record6, address: `127.0.0.1:${localPort}` });
129251
129197
  return;
@@ -129298,7 +129244,7 @@ async function remoteAccessClose(id, options, command) {
129298
129244
  } catch {
129299
129245
  }
129300
129246
  }
129301
- rmSync13(join68(directory, `${record6.id}.json`), { force: true });
129247
+ rmSync13(join69(directory, `${record6.id}.json`), { force: true });
129302
129248
  output2.progress(`the bridge on ${record6.target} is still open; close it there if you are done:`);
129303
129249
  output2.hint(`portta remote exec ${record6.target} -- 'cd portta && ./bin/portta access close --project ${record6.project}'`);
129304
129250
  }
@@ -129310,15 +129256,16 @@ init_src();
129310
129256
  init_src();
129311
129257
  init_context();
129312
129258
  init_errors3();
129313
- import { chmodSync as chmodSync15, closeSync as closeSync3, existsSync as existsSync45, mkdirSync as mkdirSync25, openSync as openSync3, readFileSync as readFileSync37, rmSync as rmSync14, writeFileSync as writeFileSync18 } from "node:fs";
129259
+ import { chmodSync as chmodSync15, closeSync as closeSync3, existsSync as existsSync45, mkdirSync as mkdirSync26, openSync as openSync3, readFileSync as readFileSync36, rmSync as rmSync14, writeFileSync as writeFileSync18 } from "node:fs";
129314
129260
  import { ReadStream } from "node:tty";
129315
- import { join as join69 } from "node:path";
129261
+ import { join as join70 } from "node:path";
129262
+ init_process();
129316
129263
  function globals20(command) {
129317
129264
  return command.optsWithGlobals();
129318
129265
  }
129319
129266
  function tunnelPaths(root2) {
129320
- const directory = join69(root2, "state/cloudflared");
129321
- return { directory, config: join69(directory, "config.yml"), credentials: join69(directory, "credentials.json") };
129267
+ const directory = join70(root2, "state/cloudflared");
129268
+ return { directory, config: join70(directory, "config.yml"), credentials: join70(directory, "credentials.json") };
129322
129269
  }
129323
129270
  function tunnelContainer(env) {
129324
129271
  return `${env["PORTTA_PROJECT_NAME"] || "portta"}-cloudflared-1`;
@@ -129453,13 +129400,13 @@ async function tunnelSetup(options, command) {
129453
129400
  let token;
129454
129401
  if (options.tokenFile) {
129455
129402
  if (!existsSync45(options.tokenFile)) throw new UsageError(`no such file: ${options.tokenFile}`);
129456
- token = readFileSync37(options.tokenFile, "utf8").replace(/\s+/g, "");
129403
+ token = readFileSync36(options.tokenFile, "utf8").replace(/\s+/g, "");
129457
129404
  } else {
129458
129405
  token = await promptForToken();
129459
129406
  }
129460
129407
  if (!token) throw new UsageError("no token was given");
129461
129408
  const paths3 = tunnelPaths(context.root);
129462
- mkdirSync25(paths3.directory, { recursive: true });
129409
+ mkdirSync26(paths3.directory, { recursive: true });
129463
129410
  chmodSync15(paths3.directory, 448);
129464
129411
  let credentials;
129465
129412
  try {
@@ -129475,7 +129422,7 @@ async function tunnelSetup(options, command) {
129475
129422
  const origin = options.origin || defaultOrigin(context);
129476
129423
  const config3 = { id: credentials.TunnelID, zone: options.zone, origin, credentialsFile: "/etc/cloudflared/credentials.json", includeApex: options.apex ?? false };
129477
129424
  writeFileSync18(paths3.config, renderTunnelConfig(config3));
129478
- const envPath = join69(context.root, ".env");
129425
+ const envPath = join70(context.root, ".env");
129479
129426
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ZONE: options.zone, CLOUDFLARE_TUNNEL_ID: credentials.TunnelID });
129480
129427
  if (output2.json) {
129481
129428
  output2.data({ zone: options.zone, tunnel: credentials.TunnelID, origin, routes: describeTunnel(config3), dns: { type: "CNAME", name: `*.${options.zone}`, target: tunnelDnsTarget(credentials.TunnelID), proxied: true } });
@@ -129504,7 +129451,7 @@ async function tunnelEnable(command) {
129504
129451
  if (!tunnelConfigured(context.root)) {
129505
129452
  throw new PreconditionError("the connector is not configured", "portta tunnel setup --zone <domain>");
129506
129453
  }
129507
- const envPath = join69(context.root, ".env");
129454
+ const envPath = join70(context.root, ".env");
129508
129455
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ENABLED: "true" });
129509
129456
  output2.progress("Cloudflare Tunnel enabled");
129510
129457
  output2.progress("starting the connector");
@@ -129527,7 +129474,7 @@ async function tunnelDisable(options, command) {
129527
129474
  ["compose", ...composeArguments(running), "rm", "-sf", "cloudflared"],
129528
129475
  { cwd: running.root, env: running.env, reject: false }
129529
129476
  );
129530
- const envPath = join69(running.root, ".env");
129477
+ const envPath = join70(running.root, ".env");
129531
129478
  const values = { CLOUDFLARE_TUNNEL_ENABLED: "false" };
129532
129479
  if (options.forget) {
129533
129480
  const paths3 = tunnelPaths(running.root);