@codions/portta 0.0.0-next.167.sha-e1101be → 0.0.0-next.173.sha-2bd7dd1

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 +969 -875
  9. package/dist/documentation.json +1 -1
  10. package/dist/host.js +111 -99
  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;
@@ -21311,6 +21278,113 @@ var init_password = __esm({
21311
21278
  }
21312
21279
  });
21313
21280
 
21281
+ // ../core/src/project-config.ts
21282
+ function hostShape(value3) {
21283
+ if (/:\/\//.test(value3)) return "looks like a URL";
21284
+ if (value3.startsWith("//")) return "looks like a URL";
21285
+ if (value3.startsWith("/")) return "is an absolute path";
21286
+ if (/^[a-z]:[\\/]/i.test(value3)) return "is an absolute path";
21287
+ if (value3.startsWith("~")) return "is a home-relative path, which differs per machine";
21288
+ if (/^\d{1,5}:\d{1,5}$/.test(value3)) return "looks like a published host port";
21289
+ return null;
21290
+ }
21291
+ function defaultProjectConfig() {
21292
+ return {
21293
+ version: 1,
21294
+ name: null,
21295
+ mainBranch: null,
21296
+ worktrees: {
21297
+ root: PROJECT_CONFIG_DEFAULTS.worktreeRoot,
21298
+ branchPattern: PROJECT_CONFIG_DEFAULTS.branchPattern
21299
+ },
21300
+ stack: [],
21301
+ instructions: []
21302
+ };
21303
+ }
21304
+ function parseProjectConfig(document) {
21305
+ if (document === null || document === void 0) {
21306
+ return { ok: false, issues: [{ path: "", message: `${PROJECT_CONFIG_FILE} is empty` }] };
21307
+ }
21308
+ const parsed = Schema.safeParse(document);
21309
+ if (!parsed.success) {
21310
+ return {
21311
+ ok: false,
21312
+ issues: parsed.error.issues.map((issue2) => ({
21313
+ path: issue2.path.join("."),
21314
+ message: issue2.message
21315
+ }))
21316
+ };
21317
+ }
21318
+ const value3 = parsed.data;
21319
+ const defaults = defaultProjectConfig();
21320
+ return {
21321
+ ok: true,
21322
+ config: {
21323
+ version: 1,
21324
+ name: value3.name ?? null,
21325
+ mainBranch: value3.mainBranch ?? null,
21326
+ worktrees: {
21327
+ root: value3.worktrees?.root ?? defaults.worktrees.root,
21328
+ branchPattern: value3.worktrees?.branchPattern ?? defaults.worktrees.branchPattern
21329
+ },
21330
+ stack: value3.stack ?? [],
21331
+ instructions: value3.instructions ?? []
21332
+ }
21333
+ };
21334
+ }
21335
+ var PROJECT_CONFIG_FILE, PROJECT_CONFIG_PATH, PROJECT_CONFIG_DEFAULTS, BRANCH_PATTERN_PLACEHOLDERS, portable, repoRelativePath, branchPattern, Schema;
21336
+ var init_project_config = __esm({
21337
+ "../core/src/project-config.ts"() {
21338
+ "use strict";
21339
+ init_zod();
21340
+ PROJECT_CONFIG_FILE = "project.yaml";
21341
+ PROJECT_CONFIG_PATH = `.portta/${PROJECT_CONFIG_FILE}`;
21342
+ PROJECT_CONFIG_DEFAULTS = {
21343
+ worktreeRoot: ".portta/worktrees",
21344
+ branchPattern: "{type}/{slug}"
21345
+ };
21346
+ BRANCH_PATTERN_PLACEHOLDERS = ["type", "slug"];
21347
+ portable = (label3) => external_exports.string().trim().min(1).superRefine((value3, ctx) => {
21348
+ const shape = hostShape(value3);
21349
+ if (shape) {
21350
+ ctx.addIssue({
21351
+ code: "custom",
21352
+ message: `${label3} ${shape}; that belongs to the host, not to the project (ADR 0052)`
21353
+ });
21354
+ }
21355
+ });
21356
+ repoRelativePath = (label3) => portable(label3).superRefine((value3, ctx) => {
21357
+ const normalized = value3.replaceAll("\\", "/");
21358
+ if (normalized.split("/").includes("..")) {
21359
+ ctx.addIssue({ code: "custom", message: `${label3} escapes the repository with '..'` });
21360
+ }
21361
+ });
21362
+ branchPattern = portable("the branch pattern").superRefine((value3, ctx) => {
21363
+ const used = [...value3.matchAll(/\{([^}]*)\}/g)].map((match2) => match2[1] ?? "");
21364
+ const allowed = new Set(BRANCH_PATTERN_PLACEHOLDERS);
21365
+ for (const placeholder of used) {
21366
+ if (!allowed.has(placeholder)) {
21367
+ ctx.addIssue({
21368
+ code: "custom",
21369
+ message: `unknown placeholder {${placeholder}}; the branch pattern accepts ${BRANCH_PATTERN_PLACEHOLDERS.map((name) => `{${name}}`).join(" and ")}`
21370
+ });
21371
+ }
21372
+ }
21373
+ });
21374
+ Schema = external_exports.strictObject({
21375
+ version: external_exports.literal(1),
21376
+ name: portable("the project name").optional(),
21377
+ mainBranch: portable("the main branch").optional(),
21378
+ worktrees: external_exports.strictObject({
21379
+ root: repoRelativePath("the worktree root").optional(),
21380
+ branchPattern: branchPattern.optional()
21381
+ }).optional(),
21382
+ stack: external_exports.array(external_exports.string().trim().min(1).regex(/^[a-z0-9][a-z0-9.+-]*$/i, "a stack entry is a plain identifier such as node or mysql")).optional(),
21383
+ instructions: external_exports.array(repoRelativePath("an instruction path")).optional()
21384
+ });
21385
+ }
21386
+ });
21387
+
21314
21388
  // ../core/src/project-order.ts
21315
21389
  function parseDependsOn(label3) {
21316
21390
  if (!label3 || label3.trim() === "") return [];
@@ -21757,6 +21831,14 @@ var init_runner = __esm({
21757
21831
  }
21758
21832
  });
21759
21833
 
21834
+ // ../core/src/module-endpoints.ts
21835
+ var init_module_endpoints = __esm({
21836
+ "../core/src/module-endpoints.ts"() {
21837
+ "use strict";
21838
+ init_dynamic();
21839
+ }
21840
+ });
21841
+
21760
21842
  // ../core/src/shares.ts
21761
21843
  function shareRouterName(id) {
21762
21844
  return `portta-share-${id}`;
@@ -22309,7 +22391,6 @@ var init_src = __esm({
22309
22391
  init_endpoints();
22310
22392
  init_env();
22311
22393
  init_hostname();
22312
- init_host();
22313
22394
  init_host_security();
22314
22395
  init_images();
22315
22396
  init_metrics();
@@ -22318,6 +22399,7 @@ var init_src = __esm({
22318
22399
  init_namespace();
22319
22400
  init_paths();
22320
22401
  init_password();
22402
+ init_project_config();
22321
22403
  init_project_order();
22322
22404
  init_projects_home();
22323
22405
  init_protections();
@@ -22326,6 +22408,7 @@ var init_src = __esm({
22326
22408
  init_audit_actions();
22327
22409
  init_roles();
22328
22410
  init_runner();
22411
+ init_module_endpoints();
22329
22412
  init_shares();
22330
22413
  init_tunnel();
22331
22414
  init_activity();
@@ -22384,7 +22467,7 @@ var init_package = __esm({
22384
22467
  "package.json"() {
22385
22468
  package_default = {
22386
22469
  name: "@codions/portta",
22387
- version: "0.0.0-next.167.sha-e1101be",
22470
+ version: "0.0.0-next.173.sha-2bd7dd1",
22388
22471
  description: "Machine-first CLI for a shared Docker development gateway",
22389
22472
  license: "MIT",
22390
22473
  type: "module",
@@ -22403,10 +22486,7 @@ var init_package = __esm({
22403
22486
  typecheck: "tsc -p tsconfig.json --noEmit",
22404
22487
  test: "vitest run",
22405
22488
  prepack: "npm run build",
22406
- prepublishOnly: "npm run typecheck && npm test",
22407
- preversion: "node scripts/git-version.mjs check",
22408
- version: "node scripts/git-version.mjs sync",
22409
- postversion: "node scripts/git-version.mjs verify"
22489
+ prepublishOnly: "npm run typecheck && npm test"
22410
22490
  },
22411
22491
  engines: {
22412
22492
  node: ">=24"
@@ -22458,7 +22538,7 @@ var init_version = __esm({
22458
22538
  "use strict";
22459
22539
  init_package();
22460
22540
  CLI_VERSION = package_default.version;
22461
- CLI_BUILD_DATE = true ? "2026-09-18T00:15:44Z" : void 0;
22541
+ CLI_BUILD_DATE = true ? "2026-09-18T02:38:53Z" : void 0;
22462
22542
  }
22463
22543
  });
22464
22544
 
@@ -22474,12 +22554,13 @@ function versionForRoot(root2) {
22474
22554
  if (existsSync4(generated)) return readFileSync4(generated, "utf8").trim();
22475
22555
  const manifest = join5(root2, "packages", "cli", "package.json");
22476
22556
  if (existsSync4(manifest)) return LOCAL_DEV_VERSION;
22477
- 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");
22478
22558
  }
22479
22559
  function wellKnownRoots() {
22480
22560
  const home2 = process.env["HOME"];
22481
22561
  return [
22482
22562
  process.env["PORTTA_HOME"],
22563
+ home2 ? join5(home2, "portta") : void 0,
22483
22564
  "/opt/portta",
22484
22565
  home2 ? join5(home2, ".portta") : void 0,
22485
22566
  "/var/lib/portta"
@@ -22519,7 +22600,7 @@ function gatewayContext(options = {}) {
22519
22600
  const config3 = loadGatewayConfig(env);
22520
22601
  env["PORTTA_DOMAIN"] = config3.domain;
22521
22602
  env["PORTTA_BIND_ADDRESS"] = config3.bindAddress;
22522
- const files = composeFilesForRoot(config3, root2);
22603
+ const files = composeFiles(config3);
22523
22604
  for (const fileName of files) {
22524
22605
  if (!existsSync4(join5(root2, fileName))) throw new PreconditionError(`missing compose file: ${fileName}`);
22525
22606
  }
@@ -34224,6 +34305,138 @@ var init_execa = __esm({
34224
34305
  }
34225
34306
  });
34226
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
+
34227
34440
  // ../../node_modules/hono/dist/compose.js
34228
34441
  var compose;
34229
34442
  var init_compose = __esm({
@@ -36695,7 +36908,7 @@ var init_user_shell_env = __esm({
36695
36908
  // ../host/src/modules/taskflow/lib/host-tools.ts
36696
36909
  import { spawnSync as spawnSync2 } from "node:child_process";
36697
36910
  import { accessSync as accessSync2, constants as constants5, statSync as statSync3 } from "node:fs";
36698
- 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";
36699
36912
  function defaultIsExecutableFile(candidate) {
36700
36913
  try {
36701
36914
  accessSync2(candidate, constants5.X_OK);
@@ -36709,20 +36922,20 @@ function firstExecutable(candidates, isExecutable) {
36709
36922
  }
36710
36923
  function pathCandidates(tool, pathEnv) {
36711
36924
  if (!pathEnv) return [];
36712
- return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join8(entry, tool));
36925
+ return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join9(entry, tool));
36713
36926
  }
36714
36927
  function wellKnownBinDirectories(input2) {
36715
36928
  const directories = [];
36716
36929
  const home2 = input2.env.HOME?.trim();
36717
36930
  if (home2) {
36718
36931
  directories.push(
36719
- join8(home2, ".local", "bin"),
36720
- join8(home2, ".cargo", "bin"),
36721
- join8(home2, ".bun", "bin"),
36722
- join8(home2, ".volta", "bin"),
36723
- join8(home2, ".asdf", "shims"),
36724
- join8(home2, ".local", "share", "mise", "shims"),
36725
- 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")
36726
36939
  );
36727
36940
  }
36728
36941
  directories.push(dirname5(input2.execPath));
@@ -36733,7 +36946,7 @@ function wellKnownBinDirectories(input2) {
36733
36946
  }
36734
36947
  function wellKnownToolPaths(tool, env) {
36735
36948
  const home2 = env.HOME?.trim();
36736
- if (tool === "claude" && home2) return [join8(home2, ".claude", "local", "claude")];
36949
+ if (tool === "claude" && home2) return [join9(home2, ".claude", "local", "claude")];
36737
36950
  return [];
36738
36951
  }
36739
36952
  function loginWhichCommand(tool) {
@@ -36780,7 +36993,7 @@ function resolveNpmGlobalBin(input2) {
36780
36993
  env: input2.env,
36781
36994
  execPath: input2.execPath,
36782
36995
  platform: input2.platform
36783
- }).map((directory) => join8(directory, "npm")),
36996
+ }).map((directory) => join9(directory, "npm")),
36784
36997
  input2.isExecutable
36785
36998
  );
36786
36999
  if (!npm) return null;
@@ -36792,7 +37005,7 @@ function resolveNpmGlobalBin(input2) {
36792
37005
  });
36793
37006
  if (result.error || result.status !== 0) return null;
36794
37007
  const prefix = (result.stdout ?? "").trim().split(/\r?\n/u)[0]?.trim();
36795
- return prefix ? join8(prefix, "bin") : null;
37008
+ return prefix ? join9(prefix, "bin") : null;
36796
37009
  }
36797
37010
  function createHostToolResolver(options = {}) {
36798
37011
  const env = options.env ?? process.env;
@@ -36821,7 +37034,7 @@ function createHostToolResolver(options = {}) {
36821
37034
  npmGlobalBin = resolveNpmGlobalBin({ env, execPath: execPath2, isExecutable, platform: platform4 });
36822
37035
  }
36823
37036
  const wellKnown = wellKnownBinDirectories({ env, execPath: execPath2, npmGlobalBin, platform: platform4 }).map(
36824
- (directory) => join8(directory, name)
37037
+ (directory) => join9(directory, name)
36825
37038
  );
36826
37039
  const wellKnownHit = firstExecutable(wellKnown, isExecutable);
36827
37040
  if (wellKnownHit) return wellKnownHit;
@@ -36934,7 +37147,7 @@ function agentTemplatePlaceholder(variable) {
36934
37147
  function hostPortFromEnv(env) {
36935
37148
  return parseInt(env[ENV_NAMES.hostPort] || env.PORT || String(APP_DEFAULTS.port), 10);
36936
37149
  }
36937
- var APP_NAME, APP_SLUG, CLI_NAME, GLOBAL_CONFIG_DIR, HOST_STATE_DIR, PROJECT_CONFIG_DIR, PATH_NAMES, PROJECT_CONFIG_PATH, PROJECT_LOCAL_CONFIG_PATH, APP_DEFAULTS, ENV_NAMES, RUNTIME_IDENTITY, SERVICE_IDENTITY, LINEAR_IDENTITY;
37150
+ var APP_NAME, APP_SLUG, CLI_NAME, GLOBAL_CONFIG_DIR, HOST_STATE_DIR, PROJECT_CONFIG_DIR, PATH_NAMES, PROJECT_CONFIG_PATH2, PROJECT_LOCAL_CONFIG_PATH, APP_DEFAULTS, ENV_NAMES, RUNTIME_IDENTITY, SERVICE_IDENTITY, LINEAR_IDENTITY;
36938
37151
  var init_config2 = __esm({
36939
37152
  "../core/src/taskflow/config.ts"() {
36940
37153
  "use strict";
@@ -36963,7 +37176,7 @@ var init_config2 = __esm({
36963
37176
  archiveState: "archive.json",
36964
37177
  openSessionsState: "open-sessions.json"
36965
37178
  };
36966
- PROJECT_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
37179
+ PROJECT_CONFIG_PATH2 = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
36967
37180
  PROJECT_LOCAL_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectLocalConfig}`;
36968
37181
  APP_DEFAULTS = {
36969
37182
  port: 5111,
@@ -37011,7 +37224,6 @@ var init_config2 = __esm({
37011
37224
  tmuxBufferPrefix: `${APP_SLUG}-prompt`,
37012
37225
  dockerContainerPrefix: APP_SLUG,
37013
37226
  tempUploadDir: `${APP_SLUG}-uploads`,
37014
- dockerImage: "portta-sandbox",
37015
37227
  gitBaseConfigKey: `${APP_SLUG}.base`
37016
37228
  };
37017
37229
  SERVICE_IDENTITY = {
@@ -44379,48 +44591,48 @@ var init_main2 = __esm({
44379
44591
 
44380
44592
  // ../core/src/taskflow/paths.ts
44381
44593
  import { homedir as homedir2 } from "node:os";
44382
- import { join as join9 } from "node:path";
44594
+ import { join as join10 } from "node:path";
44383
44595
  function globalConfigDir(options = {}) {
44384
44596
  const env = options.env ?? process.env;
44385
44597
  const override = env[ENV_NAMES.home]?.trim();
44386
- return override || join9(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44598
+ return override || join10(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44387
44599
  }
44388
44600
  function globalPaths(options = {}) {
44389
44601
  const home2 = globalConfigDir(options);
44390
44602
  const env = options.env ?? process.env;
44391
- 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);
44392
44604
  return {
44393
44605
  root: root2,
44394
- env: join9(home2, PATH_NAMES.env),
44395
- controlToken: join9(root2, PATH_NAMES.controlToken),
44396
- projectsRegistry: join9(root2, PATH_NAMES.projectsRegistry),
44397
- database: join9(root2, PATH_NAMES.database),
44398
- runs: join9(root2, PATH_NAMES.runs),
44399
- 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)
44400
44612
  };
44401
44613
  }
44402
44614
  function projectPaths(projectRoot2) {
44403
- const root2 = join9(projectRoot2, PROJECT_CONFIG_DIR);
44615
+ const root2 = join10(projectRoot2, PROJECT_CONFIG_DIR);
44404
44616
  return {
44405
44617
  root: root2,
44406
- config: join9(root2, PATH_NAMES.projectConfig),
44407
- localConfig: join9(root2, PATH_NAMES.projectLocalConfig),
44408
- configExample: join9(root2, PATH_NAMES.projectConfigExample),
44409
- workflows: join9(root2, PATH_NAMES.workflows),
44410
- 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)
44411
44623
  };
44412
44624
  }
44413
44625
  function gitRuntimePaths(gitDir) {
44414
- const root2 = join9(gitDir, PATH_NAMES.gitRuntime);
44626
+ const root2 = join10(gitDir, PATH_NAMES.gitRuntime);
44415
44627
  return {
44416
44628
  root: root2,
44417
- meta: join9(root2, PATH_NAMES.worktreeMeta),
44418
- runtimeEnv: join9(root2, PATH_NAMES.runtimeEnv),
44419
- controlEnv: join9(root2, PATH_NAMES.controlEnv),
44420
- pullRequests: join9(root2, PATH_NAMES.pullRequests),
44421
- archiveState: join9(root2, PATH_NAMES.archiveState),
44422
- openSessionsState: join9(root2, PATH_NAMES.openSessionsState),
44423
- 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)
44424
44636
  };
44425
44637
  }
44426
44638
  var init_paths2 = __esm({
@@ -44432,29 +44644,29 @@ var init_paths2 = __esm({
44432
44644
 
44433
44645
  // ../host/src/token.ts
44434
44646
  import { randomBytes as randomBytes6 } from "node:crypto";
44435
- import { chmodSync as chmodSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync6 } from "node:fs";
44436
- 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";
44437
44649
  function hostStateDir(root2) {
44438
- return join10(root2, HOST_STATE_DIR2);
44650
+ return join11(root2, HOST_STATE_DIR2);
44439
44651
  }
44440
44652
  function resolveHostStateDir(root2, env) {
44441
44653
  return env["PORTTA_HOST_STATE_DIR"]?.trim() || hostStateDir(root2);
44442
44654
  }
44443
44655
  function hostTokenFile(stateDir) {
44444
- return join10(stateDir, "token");
44656
+ return join11(stateDir, "token");
44445
44657
  }
44446
44658
  function newToken() {
44447
44659
  return randomBytes6(32).toString("base64url");
44448
44660
  }
44449
44661
  function readOrCreateToken(file2) {
44450
- mkdirSync5(dirname6(file2), { recursive: true, mode: 448 });
44662
+ mkdirSync6(dirname6(file2), { recursive: true, mode: 448 });
44451
44663
  try {
44452
44664
  writeFileSync6(file2, `${newToken()}
44453
44665
  `, { flag: "wx", mode: 384 });
44454
44666
  } catch (error61) {
44455
44667
  if (error61.code !== "EEXIST") throw error61;
44456
44668
  }
44457
- if ((statSync4(file2).mode & 63) !== 0) chmodSync5(file2, 384);
44669
+ if ((statSync4(file2).mode & 63) !== 0) chmodSync6(file2, 384);
44458
44670
  const token = readFileSync9(file2, "utf8").trim();
44459
44671
  if (token === "") throw new Error(`${file2} is empty; remove it and start the host daemon again`);
44460
44672
  return token;
@@ -44463,7 +44675,7 @@ var HOST_STATE_DIR2;
44463
44675
  var init_token = __esm({
44464
44676
  "../host/src/token.ts"() {
44465
44677
  "use strict";
44466
- HOST_STATE_DIR2 = join10("state", "host");
44678
+ HOST_STATE_DIR2 = join11("state", "host");
44467
44679
  }
44468
44680
  });
44469
44681
 
@@ -47725,7 +47937,7 @@ var require_Schema = __commonJS({
47725
47937
  var string4 = require_string();
47726
47938
  var tags = require_tags();
47727
47939
  var sortMapEntriesByKey = (a3, b) => a3.key < b.key ? -1 : a3.key > b.key ? 1 : 0;
47728
- var Schema = class _Schema {
47940
+ var Schema2 = class _Schema {
47729
47941
  constructor({ compat, customTags, merge: merge2, resolveKnownTags, schema, sortMapEntries, toStringDefaults }) {
47730
47942
  this.compat = Array.isArray(compat) ? tags.getTags(compat, "compat") : compat ? tags.getTags(null, compat) : null;
47731
47943
  this.name = typeof schema === "string" && schema || "core";
@@ -47743,7 +47955,7 @@ var require_Schema = __commonJS({
47743
47955
  return copy;
47744
47956
  }
47745
47957
  };
47746
- exports.Schema = Schema;
47958
+ exports.Schema = Schema2;
47747
47959
  }
47748
47960
  });
47749
47961
 
@@ -47836,7 +48048,7 @@ var require_Document = __commonJS({
47836
48048
  var identity3 = require_identity();
47837
48049
  var Pair = require_Pair();
47838
48050
  var toJS = require_toJS();
47839
- var Schema = require_Schema();
48051
+ var Schema2 = require_Schema();
47840
48052
  var stringifyDocument = require_stringifyDocument();
47841
48053
  var anchors = require_anchors();
47842
48054
  var applyReviver = require_applyReviver();
@@ -48087,7 +48299,7 @@ var require_Document = __commonJS({
48087
48299
  if (options.schema instanceof Object)
48088
48300
  this.schema = options.schema;
48089
48301
  else if (opt)
48090
- this.schema = new Schema.Schema(Object.assign(opt, options));
48302
+ this.schema = new Schema2.Schema(Object.assign(opt, options));
48091
48303
  else
48092
48304
  throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
48093
48305
  }
@@ -51751,7 +51963,7 @@ var require_dist = __commonJS({
51751
51963
  "use strict";
51752
51964
  var composer = require_composer();
51753
51965
  var Document = require_Document();
51754
- var Schema = require_Schema();
51966
+ var Schema2 = require_Schema();
51755
51967
  var errors = require_errors();
51756
51968
  var Alias = require_Alias();
51757
51969
  var identity3 = require_identity();
@@ -51767,7 +51979,7 @@ var require_dist = __commonJS({
51767
51979
  var visit2 = require_visit();
51768
51980
  exports.Composer = composer.Composer;
51769
51981
  exports.Document = Document.Document;
51770
- exports.Schema = Schema.Schema;
51982
+ exports.Schema = Schema2.Schema;
51771
51983
  exports.YAMLError = errors.YAMLError;
51772
51984
  exports.YAMLParseError = errors.YAMLParseError;
51773
51985
  exports.YAMLWarning = errors.YAMLWarning;
@@ -51807,7 +52019,6 @@ function parseWorktreeRoot(raw2, fallback) {
51807
52019
  if (isRecord2(raw2.worktrees) && typeof raw2.worktrees.root === "string" && raw2.worktrees.root.trim()) {
51808
52020
  return raw2.worktrees.root.trim();
51809
52021
  }
51810
- if (typeof raw2.worktreeRoot === "string" && raw2.worktreeRoot.trim()) return raw2.worktreeRoot.trim();
51811
52022
  return fallback;
51812
52023
  }
51813
52024
  function parseExposure(raw2) {
@@ -51919,18 +52130,15 @@ function parseProfile(raw2, fallbackRuntime) {
51919
52130
  ...typeof raw2.environment.cwd === "string" && raw2.environment.cwd.trim() ? { cwd: raw2.environment.cwd.trim() } : {},
51920
52131
  ...typeof raw2.environment.stopCommand === "string" && raw2.environment.stopCommand.trim() ? { stopCommand: raw2.environment.stopCommand.trim() } : {}
51921
52132
  } : void 0;
51922
- 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;
51923
- const effectiveEnvironment = legacyRuntimePane ? { ...environment, command: legacyRuntimePane.command } : environment;
51924
- const effectivePanes = legacyRuntimePane ? panes.filter((pane) => pane !== legacyRuntimePane) : panes;
51925
52133
  return {
51926
52134
  runtime: runtime2,
51927
52135
  envPassthrough,
51928
52136
  ...raw2.yolo === true ? { yolo: true } : {},
51929
- panes: effectivePanes,
52137
+ panes,
51930
52138
  ...typeof raw2.systemPrompt === "string" && raw2.systemPrompt.length > 0 ? { systemPrompt: raw2.systemPrompt } : {},
51931
52139
  ...image ? { image } : {},
51932
52140
  ...mounts ? { mounts } : {},
51933
- ...effectiveEnvironment && Object.keys(effectiveEnvironment).length > 0 ? { environment: effectiveEnvironment } : {}
52141
+ ...environment && Object.keys(environment).length > 0 ? { environment } : {}
51934
52142
  };
51935
52143
  }
51936
52144
  function parseProfiles(raw2, includeDefaultProfile) {
@@ -52052,7 +52260,7 @@ function parseConfigDocument(text) {
52052
52260
  const parsed = (0, import_yaml.parse)(text);
52053
52261
  return isRecord2(parsed) ? parsed : {};
52054
52262
  }
52055
- function parseProjectConfig(parsed) {
52263
+ function parseProjectConfig2(parsed) {
52056
52264
  const worktreeRoot = parseWorktreeRoot(parsed.workspace, DEFAULT_CONFIG.workspace.worktreeRoot);
52057
52265
  return {
52058
52266
  name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : DEFAULT_CONFIG.name,
@@ -52082,7 +52290,7 @@ function parseProjectConfig(parsed) {
52082
52290
  };
52083
52291
  }
52084
52292
  function defaultConfig() {
52085
- return parseProjectConfig({});
52293
+ return parseProjectConfig2({});
52086
52294
  }
52087
52295
  function parseTeamKeyList(raw2) {
52088
52296
  if (!Array.isArray(raw2)) return void 0;
@@ -52093,12 +52301,6 @@ function parseLinearIntegration(parsed) {
52093
52301
  const defaults = DEFAULT_CONFIG.integrations.linear;
52094
52302
  const linear = isRecord2(parsed.integrations) && isRecord2(parsed.integrations.linear) ? parsed.integrations.linear : null;
52095
52303
  if (!linear) return { ...defaults };
52096
- if (typeof linear.teamId === "string" && !warnedLegacyLinearTeamId) {
52097
- warnedLegacyLinearTeamId = true;
52098
- log.warn(
52099
- "[config] integrations.linear.teamId is no longer used \u2014 the ticket team is now picked at creation time in the dashboard"
52100
- );
52101
- }
52102
52304
  const watchTeams = parseTeamKeyList(linear.watchTeams);
52103
52305
  return {
52104
52306
  enabled: typeof linear.enabled === "boolean" ? linear.enabled : defaults.enabled,
@@ -52217,7 +52419,7 @@ function loadConfig(dir, options = {}) {
52217
52419
  let projectConfig;
52218
52420
  try {
52219
52421
  const text = readConfigFile(root2).trim();
52220
- projectConfig = text ? parseProjectConfig(parseConfigDocument(text)) : defaultConfig();
52422
+ projectConfig = text ? parseProjectConfig2(parseConfigDocument(text)) : defaultConfig();
52221
52423
  } catch {
52222
52424
  projectConfig = defaultConfig();
52223
52425
  }
@@ -52319,14 +52521,13 @@ async function removeLocalCustomAgent(dir, agentId2) {
52319
52521
  function expandTemplate(template, env) {
52320
52522
  return template.replace(/\$\{(\w+)\}/g, (_, key) => env[key] ?? "");
52321
52523
  }
52322
- var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG, warnedLegacyLinearTeamId;
52524
+ var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG;
52323
52525
  var init_config5 = __esm({
52324
52526
  "../host/src/modules/taskflow/adapters/config.ts"() {
52325
52527
  "use strict";
52326
52528
  init_config2();
52327
52529
  init_paths2();
52328
52530
  import_yaml = __toESM(require_dist(), 1);
52329
- init_log2();
52330
52531
  DEFAULT_PANES = [
52331
52532
  { id: "agent", kind: "agent", focus: true },
52332
52533
  { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" }
@@ -52360,7 +52561,6 @@ var init_config5 = __esm({
52360
52561
  autoName: null,
52361
52562
  oneshot: { systemPrompt: DEFAULT_ONESHOT_SYSTEM_PROMPT() }
52362
52563
  };
52363
- warnedLegacyLinearTeamId = false;
52364
52564
  }
52365
52565
  });
52366
52566
 
@@ -52621,7 +52821,7 @@ var init_process_runner = __esm({
52621
52821
 
52622
52822
  // ../host/src/modules/taskflow/adapters/worktree-git-mount.ts
52623
52823
  import { access, readFile, realpath, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
52624
- 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";
52625
52825
  function repairCommand(workspacePath) {
52626
52826
  return `git -C ${workspacePath} worktree repair --relative-paths`;
52627
52827
  }
@@ -52671,7 +52871,7 @@ function linkTarget(content) {
52671
52871
  return target.length > 0 ? target : null;
52672
52872
  }
52673
52873
  async function worktreeLink(workspacePath) {
52674
- const content = await readRaw(join11(workspacePath, ".git"));
52874
+ const content = await readRaw(join12(workspacePath, ".git"));
52675
52875
  return content === null ? null : linkTarget(content);
52676
52876
  }
52677
52877
  async function porttaOwned(runner, workspacePath, gitDir) {
@@ -52684,9 +52884,9 @@ async function porttaOwned(runner, workspacePath, gitDir) {
52684
52884
  return result.exit.code === 0 && result.stdout.trim().length > 0;
52685
52885
  }
52686
52886
  async function planRelativeRelink(workspacePath, dirs) {
52687
- const forwardPath = join11(workspacePath, ".git");
52688
- const backPath = join11(dirs.gitDir, BACK_LINK);
52689
- 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)
52690
52890
  return {
52691
52891
  ok: false,
52692
52892
  reason: `its Git dir ${dirs.gitDir} is not <common dir>/worktrees/<id> under ${dirs.commonDir}`
@@ -52747,7 +52947,7 @@ async function worktreeGitMountArgs(input2) {
52747
52947
  );
52748
52948
  }
52749
52949
  let link = await worktreeLink(workspacePath);
52750
- const backLink = await readRaw(join11(dirs.gitDir, BACK_LINK));
52950
+ const backLink = await readRaw(join12(dirs.gitDir, BACK_LINK));
52751
52951
  if (link !== null && isAbsolute2(link) || backLink !== null && isAbsolute2(backLink.trim())) {
52752
52952
  if (!await porttaOwned(runner, workspacePath, dirs.gitDir)) {
52753
52953
  throw new Error(
@@ -52803,7 +53003,7 @@ var init_worktree_git_mount = __esm({
52803
53003
  import { createHash as createHash5 } from "node:crypto";
52804
53004
  import { access as access2, readdir, readFile as readFile2 } from "node:fs/promises";
52805
53005
  import { createRequire } from "node:module";
52806
- 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";
52807
53007
  function hash2(value3) {
52808
53008
  return createHash5("sha256").update(value3).digest("hex");
52809
53009
  }
@@ -52819,16 +53019,16 @@ async function exists2(path7) {
52819
53019
  }
52820
53020
  }
52821
53021
  async function findDevcontainerConfigs(workspacePath) {
52822
- const rootConfig = join12(workspacePath, ".devcontainer.json");
52823
- const directory = join12(workspacePath, ".devcontainer");
53022
+ const rootConfig = join13(workspacePath, ".devcontainer.json");
53023
+ const directory = join13(workspacePath, ".devcontainer");
52824
53024
  const configs = [];
52825
53025
  if (await exists2(rootConfig)) configs.push(rootConfig);
52826
- 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"));
52827
53027
  if (await exists2(directory)) {
52828
53028
  const entries = await readdir(directory, { withFileTypes: true });
52829
53029
  for (const entry of entries) {
52830
53030
  if (!entry.isDirectory()) continue;
52831
- const candidate = join12(directory, entry.name, "devcontainer.json");
53031
+ const candidate = join13(directory, entry.name, "devcontainer.json");
52832
53032
  if (await exists2(candidate)) configs.push(candidate);
52833
53033
  }
52834
53034
  }
@@ -52982,7 +53182,7 @@ var init_devcontainer_environment = __esm({
52982
53182
  }
52983
53183
  const packagePath = createRequire(import.meta.url).resolve("@devcontainers/cli/package.json");
52984
53184
  this.cli = process.execPath;
52985
- this.cliPrefix = [join12(dirname8(packagePath), "devcontainer.js")];
53185
+ this.cliPrefix = [join13(dirname8(packagePath), "devcontainer.js")];
52986
53186
  }
52987
53187
  args(args) {
52988
53188
  return [...this.cliPrefix, ...args];
@@ -53049,7 +53249,7 @@ var init_devcontainer_environment = __esm({
53049
53249
  this.workspaceMounts.set(config3, merged.workspaceMount);
53050
53250
  else this.workspaceMounts.delete(config3);
53051
53251
  const compose4 = await resolveComposeConfiguration(this.runner, config3, merged);
53052
- const lockfile = join12(dirname8(config3), "devcontainer-lock.json");
53252
+ const lockfile = join13(dirname8(config3), "devcontainer-lock.json");
53053
53253
  const lockfileExists = await exists2(lockfile);
53054
53254
  const lockfileContents = lockfileExists ? await readFile2(lockfile, "utf8") : "";
53055
53255
  return {
@@ -53316,11 +53516,11 @@ exec ${argv.join(" ")} "$cwd" ${quoteShell(executable2)} "$@"
53316
53516
 
53317
53517
  // ../host/src/modules/taskflow/adapters/dockerfile-environment.ts
53318
53518
  import { createHash as createHash6 } from "node:crypto";
53319
- import { existsSync as existsSync7, readFileSync as readFileSync11 } from "node:fs";
53519
+ import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
53320
53520
  import { resolve as resolve5 } from "node:path";
53321
53521
  function dockerfileFor(context) {
53322
53522
  const dockerfile = resolve5(context.workspacePath, context.configRef ?? "Dockerfile");
53323
- 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"}`);
53324
53524
  return dockerfile;
53325
53525
  }
53326
53526
  function imageTag(id) {
@@ -53355,10 +53555,10 @@ var init_dockerfile_environment = __esm({
53355
53555
  const dockerfile = resolve5(context.workspacePath, "Dockerfile");
53356
53556
  return {
53357
53557
  provider: this.id,
53358
- available: version3.exit.code === 0 && existsSync7(dockerfile),
53359
- configRefs: existsSync7(dockerfile) ? [dockerfile] : [],
53558
+ available: version3.exit.code === 0 && existsSync8(dockerfile),
53559
+ configRefs: existsSync8(dockerfile) ? [dockerfile] : [],
53360
53560
  ...version3.exit.code === 0 ? { version: version3.stdout.trim() } : {},
53361
- 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"]
53362
53562
  };
53363
53563
  }
53364
53564
  async resolve(context) {
@@ -53582,13 +53782,13 @@ var init_sqlite = __esm({
53582
53782
  });
53583
53783
 
53584
53784
  // ../host/src/modules/taskflow/adapters/environment-store.ts
53585
- import { mkdirSync as mkdirSync6 } from "node:fs";
53785
+ import { mkdirSync as mkdirSync7 } from "node:fs";
53586
53786
  import { dirname as dirname9 } from "node:path";
53587
53787
  function parseEnvironmentRecord(value3) {
53588
53788
  return environmentRecordSchema.parse(value3);
53589
53789
  }
53590
53790
  function createEnvironmentStore(path7) {
53591
- mkdirSync6(dirname9(path7), { recursive: true });
53791
+ mkdirSync7(dirname9(path7), { recursive: true });
53592
53792
  const database = openDatabase(path7);
53593
53793
  database.pragma("journal_mode = WAL");
53594
53794
  database.exec(`
@@ -53827,7 +54027,7 @@ exec ${JSON.stringify(executable2)} "$@"
53827
54027
  });
53828
54028
 
53829
54029
  // ../host/src/modules/taskflow/adapters/projects-registry.ts
53830
- 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";
53831
54031
  import { dirname as dirname10 } from "node:path";
53832
54032
  function defaultRegistryFile() {
53833
54033
  return globalPaths().projectsRegistry;
@@ -53851,7 +54051,7 @@ function createProjectsRegistry(file2 = defaultRegistryFile()) {
53851
54051
  return parsed.filter(isProjectEntry);
53852
54052
  }
53853
54053
  function write4(entries) {
53854
- mkdirSync7(dirname10(file2), { recursive: true });
54054
+ mkdirSync8(dirname10(file2), { recursive: true });
53855
54055
  const tmpPath = `${file2}.${process.pid}.${Date.now()}.tmp`;
53856
54056
  writeFileSync7(tmpPath, `${JSON.stringify(entries, null, 2)}
53857
54057
  `);
@@ -54565,20 +54765,20 @@ var init_tmux = __esm({
54565
54765
  });
54566
54766
 
54567
54767
  // ../host/src/modules/taskflow/assets.ts
54568
- import { existsSync as existsSync8 } from "node:fs";
54569
- 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";
54570
54770
  function taskflowAssets(env = process.env, directory = import.meta.dirname) {
54571
- const bundled = join13(directory, "assets");
54572
- if (existsSync8(join13(bundled, "workflows"))) {
54771
+ const bundled = join14(directory, "assets");
54772
+ if (existsSync9(join14(bundled, "workflows"))) {
54573
54773
  return {
54574
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(bundled, "workflows"),
54575
- 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")
54576
54776
  };
54577
54777
  }
54578
54778
  const repository = resolve7(directory, "../../../../..");
54579
54779
  return {
54580
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(repository, "packages", "host", "workflows"),
54581
- 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")
54582
54782
  };
54583
54783
  }
54584
54784
  var init_assets = __esm({
@@ -54797,7 +54997,7 @@ var init_environment_service_discovery = __esm({
54797
54997
  // ../host/src/modules/taskflow/adapters/git.ts
54798
54998
  import { spawnSync as spawnSync5 } from "node:child_process";
54799
54999
  import { readdirSync as readdirSync2, realpathSync as realpathSync2, rmSync, statSync as statSync5 } from "node:fs";
54800
- 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";
54801
55001
  function canonicalizeFsPath(input2) {
54802
55002
  const resolved2 = resolve8(input2);
54803
55003
  try {
@@ -54809,7 +55009,7 @@ function canonicalizeFsPath(input2) {
54809
55009
  missing.unshift(basename5(current));
54810
55010
  current = dirname11(current);
54811
55011
  try {
54812
- return join14(realpathSync2(current), ...missing);
55012
+ return join15(realpathSync2(current), ...missing);
54813
55013
  } catch {
54814
55014
  }
54815
55015
  }
@@ -54901,7 +55101,7 @@ function resolveRepoRoot(dir) {
54901
55101
  return null;
54902
55102
  }
54903
55103
  for (const entry of entries) {
54904
- const child = join14(dir, entry);
55104
+ const child = join15(dir, entry);
54905
55105
  try {
54906
55106
  if (!statSync5(child).isDirectory()) continue;
54907
55107
  } catch {
@@ -55835,7 +56035,7 @@ var init_herdr = __esm({
55835
56035
 
55836
56036
  // ../host/src/modules/taskflow/adapters/hooks.ts
55837
56037
  import { access as access3 } from "node:fs/promises";
55838
- import { join as join15 } from "node:path";
56038
+ import { join as join16 } from "node:path";
55839
56039
  function buildErrorMessage(name, exitCode, stdout2, stderr2) {
55840
56040
  const output2 = stderr2.trim() || stdout2.trim();
55841
56041
  if (output2) {
@@ -55886,7 +56086,7 @@ var init_hooks = __esm({
55886
56086
  }
55887
56087
  async hasEnvrc(cwd) {
55888
56088
  try {
55889
- await access3(join15(cwd, ".envrc"));
56089
+ await access3(join16(cwd, ".envrc"));
55890
56090
  return true;
55891
56091
  } catch {
55892
56092
  return false;
@@ -55985,7 +56185,7 @@ var init_type_guards = __esm({
55985
56185
 
55986
56186
  // ../host/src/modules/taskflow/adapters/claude-cli.ts
55987
56187
  import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
55988
- import { basename as basename6, join as join16 } from "node:path";
56188
+ import { basename as basename6, join as join17 } from "node:path";
55989
56189
  function isRecord5(raw2) {
55990
56190
  return typeof raw2 === "object" && raw2 !== null && !Array.isArray(raw2);
55991
56191
  }
@@ -56168,19 +56368,19 @@ function readClaudeProjectsRoot() {
56168
56368
  if (!home2) {
56169
56369
  throw new Error("HOME is required to resolve Claude sessions");
56170
56370
  }
56171
- return join16(home2, ".claude", "projects");
56371
+ return join17(home2, ".claude", "projects");
56172
56372
  }
56173
56373
  async function listJsonlFiles(dir) {
56174
56374
  try {
56175
56375
  const entries = await readdir2(dir, { withFileTypes: true });
56176
- 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));
56177
56377
  } catch {
56178
56378
  return [];
56179
56379
  }
56180
56380
  }
56181
56381
  async function findClaudeSessionPath(sessionId, cwd) {
56182
56382
  const projectsRoot = readClaudeProjectsRoot();
56183
- const primaryPath = join16(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56383
+ const primaryPath = join17(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56184
56384
  try {
56185
56385
  await stat2(primaryPath);
56186
56386
  return primaryPath;
@@ -56189,7 +56389,7 @@ async function findClaudeSessionPath(sessionId, cwd) {
56189
56389
  const projectDirs2 = await readdir2(projectsRoot, { withFileTypes: true }).catch(() => []);
56190
56390
  for (const entry of projectDirs2) {
56191
56391
  if (!entry.isDirectory()) continue;
56192
- const candidate = join16(projectsRoot, entry.name, `${sessionId}.jsonl`);
56392
+ const candidate = join17(projectsRoot, entry.name, `${sessionId}.jsonl`);
56193
56393
  try {
56194
56394
  await stat2(candidate);
56195
56395
  return candidate;
@@ -56332,7 +56532,7 @@ var init_claude_cli = __esm({
56332
56532
  }
56333
56533
  async listSessions(cwd) {
56334
56534
  const projectsRoot = readClaudeProjectsRoot();
56335
- const primaryDir = join16(projectsRoot, encodeClaudeProjectDir(cwd));
56535
+ const primaryDir = join17(projectsRoot, encodeClaudeProjectDir(cwd));
56336
56536
  const primaryFiles = await listJsonlFiles(primaryDir);
56337
56537
  if (primaryFiles.length > 0) {
56338
56538
  return await this.summarizeSessionFiles(primaryFiles, cwd);
@@ -56341,7 +56541,7 @@ var init_claude_cli = __esm({
56341
56541
  const matchedFiles = [];
56342
56542
  for (const entry of projectDirs2) {
56343
56543
  if (!entry.isDirectory()) continue;
56344
- const files = await listJsonlFiles(join16(projectsRoot, entry.name));
56544
+ const files = await listJsonlFiles(join17(projectsRoot, entry.name));
56345
56545
  for (const filePath of files) {
56346
56546
  const session = await this.readSessionFile(filePath);
56347
56547
  if (session?.cwd === cwd) {
@@ -56520,7 +56720,7 @@ var init_claude_cli = __esm({
56520
56720
 
56521
56721
  // ../host/src/modules/taskflow/adapters/session-discovery.ts
56522
56722
  import { open as open2, readdir as readdir3, stat as stat3 } from "node:fs/promises";
56523
- import { basename as basename7, join as join17 } from "node:path";
56723
+ import { basename as basename7, join as join18 } from "node:path";
56524
56724
  import { setTimeout as sleep3 } from "node:timers/promises";
56525
56725
  function home() {
56526
56726
  const value3 = process.env.HOME;
@@ -56531,11 +56731,11 @@ function newestFirst(sessions3) {
56531
56731
  return sessions3.sort((left, right) => right.mtimeMs - left.mtimeMs).map((entry) => entry.sessionId);
56532
56732
  }
56533
56733
  async function listClaudeSessionIds(cwd) {
56534
- const dir = join17(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56734
+ const dir = join18(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56535
56735
  const names = await readdir3(dir).catch(() => []);
56536
56736
  const stamped = await Promise.all(
56537
56737
  names.filter((name) => name.endsWith(".jsonl")).map(async (name) => {
56538
- const info = await stat3(join17(dir, name)).catch(() => null);
56738
+ const info = await stat3(join18(dir, name)).catch(() => null);
56539
56739
  return info ? { sessionId: basename7(name, ".jsonl"), mtimeMs: info.mtimeMs } : null;
56540
56740
  })
56541
56741
  );
@@ -56571,7 +56771,7 @@ async function readCodexSessionCwdId(path7) {
56571
56771
  }
56572
56772
  }
56573
56773
  async function listCodexSessionIds(cwd) {
56574
- const root2 = join17(home(), ".codex", "sessions");
56774
+ const root2 = join18(home(), ".codex", "sessions");
56575
56775
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56576
56776
  const rollouts = relPaths.filter((rel) => {
56577
56777
  const name = basename7(rel);
@@ -56579,7 +56779,7 @@ async function listCodexSessionIds(cwd) {
56579
56779
  });
56580
56780
  const stamped = await Promise.all(
56581
56781
  rollouts.map(async (rel) => {
56582
- const path7 = join17(root2, rel);
56782
+ const path7 = join18(root2, rel);
56583
56783
  const meta3 = await readCodexSessionCwdId(path7);
56584
56784
  if (!meta3 || meta3.cwd !== cwd) return null;
56585
56785
  const info = await stat3(path7).catch(() => null);
@@ -56589,11 +56789,11 @@ async function listCodexSessionIds(cwd) {
56589
56789
  return newestFirst(stamped.filter((entry) => entry !== null));
56590
56790
  }
56591
56791
  async function findCodexSessionPath(sessionId, cwd) {
56592
- const root2 = join17(home(), ".codex", "sessions");
56792
+ const root2 = join18(home(), ".codex", "sessions");
56593
56793
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56594
56794
  for (const rel of relPaths) {
56595
56795
  if (!basename7(rel).endsWith(`${sessionId}.jsonl`)) continue;
56596
- const path7 = join17(root2, rel);
56796
+ const path7 = join18(root2, rel);
56597
56797
  const meta3 = await readCodexSessionCwdId(path7);
56598
56798
  if (meta3?.id === sessionId && meta3.cwd === cwd) return path7;
56599
56799
  }
@@ -56683,7 +56883,7 @@ var init_session_discovery = __esm({
56683
56883
 
56684
56884
  // ../host/src/modules/taskflow/adapters/fs.ts
56685
56885
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
56686
- import { join as join18 } from "node:path";
56886
+ import { join as join19 } from "node:path";
56687
56887
  function stringifyAllocatedPorts(ports) {
56688
56888
  const entries = Object.entries(ports).map(([key, value3]) => [key, String(value3)]);
56689
56889
  return Object.fromEntries(entries);
@@ -56712,7 +56912,7 @@ function parseDotenv(content) {
56712
56912
  }
56713
56913
  async function loadDotenvLocal(worktreePath) {
56714
56914
  try {
56715
- const content = await readFile4(join18(worktreePath, ".env.local"), "utf8");
56915
+ const content = await readFile4(join19(worktreePath, ".env.local"), "utf8");
56716
56916
  return parseDotenv(content);
56717
56917
  } catch {
56718
56918
  return {};
@@ -56853,25 +57053,21 @@ function isRecord6(raw2) {
56853
57053
  function normalizeConversationMeta(raw2) {
56854
57054
  if (!raw2) return raw2;
56855
57055
  if (raw2.provider === "codexAppServer") {
56856
- const conversationId2 = raw2.conversationId || raw2.threadId;
56857
- const threadId = raw2.threadId || raw2.conversationId;
56858
- if (!conversationId2 || !threadId) return void 0;
57056
+ if (!raw2.conversationId || !raw2.threadId) return void 0;
56859
57057
  const normalized2 = {
56860
57058
  provider: "codexAppServer",
56861
- conversationId: conversationId2,
56862
- threadId,
57059
+ conversationId: raw2.conversationId,
57060
+ threadId: raw2.threadId,
56863
57061
  cwd: raw2.cwd,
56864
57062
  lastSeenAt: raw2.lastSeenAt
56865
57063
  };
56866
57064
  return normalized2;
56867
57065
  }
56868
- const conversationId = raw2.conversationId || raw2.sessionId;
56869
- const sessionId = raw2.sessionId || raw2.conversationId;
56870
- if (!conversationId || !sessionId) return void 0;
57066
+ if (!raw2.conversationId || !raw2.sessionId) return void 0;
56871
57067
  const normalized = {
56872
57068
  provider: "claudeCode",
56873
- conversationId,
56874
- sessionId,
57069
+ conversationId: raw2.conversationId,
57070
+ sessionId: raw2.sessionId,
56875
57071
  cwd: raw2.cwd,
56876
57072
  lastSeenAt: raw2.lastSeenAt
56877
57073
  };
@@ -57301,7 +57497,7 @@ ${stderr2}`;
57301
57497
 
57302
57498
  // ../host/src/modules/taskflow/adapters/agent-runtime.ts
57303
57499
  import { chmod, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
57304
- 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";
57305
57501
  function shellQuote(value3) {
57306
57502
  return `'${value3.replaceAll("'", "'\\''")}'`;
57307
57503
  }
@@ -57754,7 +57950,7 @@ async function mergeCodexHooksFile(hooksPath, hookSettings, agentCtlPath) {
57754
57950
  }
57755
57951
  async function resolveGitCommonDir(gitDir) {
57756
57952
  try {
57757
- const commonDir = (await readFile5(join19(gitDir, "commondir"), "utf8")).trim();
57953
+ const commonDir = (await readFile5(join20(gitDir, "commondir"), "utf8")).trim();
57758
57954
  if (!commonDir) return gitDir;
57759
57955
  return commonDir.startsWith("/") ? commonDir : resolve10(gitDir, commonDir);
57760
57956
  } catch {
@@ -57763,7 +57959,7 @@ async function resolveGitCommonDir(gitDir) {
57763
57959
  }
57764
57960
  async function ensureGeneratedAgentFilesIgnored(gitDir) {
57765
57961
  const commonDir = await resolveGitCommonDir(gitDir);
57766
- const excludePath = join19(commonDir, "info", "exclude");
57962
+ const excludePath = join20(commonDir, "info", "exclude");
57767
57963
  let existing = "";
57768
57964
  try {
57769
57965
  existing = await readFile5(excludePath, "utf8");
@@ -57781,9 +57977,9 @@ async function ensureGeneratedAgentFilesIgnored(gitDir) {
57781
57977
  async function ensureAgentRuntimeArtifacts(input2) {
57782
57978
  const storagePaths = getWorktreeStoragePaths(input2.gitDir);
57783
57979
  const artifacts = {
57784
- agentCtlPath: join19(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
57785
- claudeSettingsPath: join19(input2.worktreePath, ".claude", "settings.local.json"),
57786
- 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")
57787
57983
  };
57788
57984
  await mkdir3(dirname12(artifacts.claudeSettingsPath), { recursive: true });
57789
57985
  await mkdir3(dirname12(artifacts.codexHooksPath), { recursive: true });
@@ -57927,7 +58123,7 @@ var init_agent_registry = __esm({
57927
58123
  });
57928
58124
 
57929
58125
  // ../host/src/modules/taskflow/services/agent-service.ts
57930
- import { dirname as dirname13, join as join20 } from "node:path";
58126
+ import { dirname as dirname13, join as join21 } from "node:path";
57931
58127
  function quoteShell3(value3) {
57932
58128
  return `'${value3.replaceAll("'", "'\\''")}'`;
57933
58129
  }
@@ -57939,7 +58135,7 @@ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
57939
58135
  }
57940
58136
  function buildCodexNotifyFlag(runtimeEnvPath) {
57941
58137
  if (!runtimeEnvPath) return "";
57942
- const agentCtlPath = join20(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
58138
+ const agentCtlPath = join21(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
57943
58139
  return ` -c ${quoteShell3(`notify=${JSON.stringify([agentCtlPath, "codex-notify"])}`)}`;
57944
58140
  }
57945
58141
  function buildBuiltInAgentInvocation(input2) {
@@ -59404,10 +59600,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59404
59600
  return panes.length > 0 ? panes : [{ id: "runtime", kind: "runtime", cwd: "worktree" }];
59405
59601
  }
59406
59602
  if (panes.some((pane) => pane.kind === "runtime")) return panes;
59407
- const legacyShell = panes.findIndex((pane) => pane.id === "shell" && pane.kind === "shell");
59408
- const runtimePane = { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" };
59409
- if (legacyShell >= 0) panes.splice(legacyShell, 1, runtimePane);
59410
- else panes.push(runtimePane);
59603
+ panes.push({ id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" });
59411
59604
  return panes;
59412
59605
  }
59413
59606
  requireDockerProfile(profile) {
@@ -60359,7 +60552,6 @@ var DEFAULT_TERMINAL_TTL_MS, ProjectInitTracker;
60359
60552
  var init_project_init_service = __esm({
60360
60553
  "../host/src/modules/taskflow/services/project-init-service.ts"() {
60361
60554
  "use strict";
60362
- init_log2();
60363
60555
  DEFAULT_TERMINAL_TTL_MS = 6e4;
60364
60556
  ProjectInitTracker = class {
60365
60557
  inits = /* @__PURE__ */ new Map();
@@ -68972,10 +69164,10 @@ var init_native_terminal_service = __esm({
68972
69164
  });
68973
69165
 
68974
69166
  // ../host/src/modules/taskflow/server/routes/worktrees.ts
68975
- import { mkdirSync as mkdirSync8 } from "node:fs";
69167
+ import { mkdirSync as mkdirSync9 } from "node:fs";
68976
69168
  import { writeFile as writeFile6 } from "node:fs/promises";
68977
69169
  import { tmpdir } from "node:os";
68978
- import { join as join21, resolve as resolve16 } from "node:path";
69170
+ import { join as join22, resolve as resolve16 } from "node:path";
68979
69171
  async function apiGetNativeTerminalLaunch(project2, branch) {
68980
69172
  touchDashboardActivity();
68981
69173
  project2.ensureBranchNotBusy(branch);
@@ -69309,8 +69501,8 @@ async function apiUploadFiles(project2, name, req) {
69309
69501
  }
69310
69502
  const entries = formData.getAll("files");
69311
69503
  if (entries.length === 0) return errorResponse("No files provided", 400);
69312
- const uploadDir = join21(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69313
- mkdirSync8(uploadDir, { recursive: true });
69504
+ const uploadDir = join22(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69505
+ mkdirSync9(uploadDir, { recursive: true });
69314
69506
  const results = [];
69315
69507
  for (const entry of entries) {
69316
69508
  if (!(entry instanceof File)) continue;
@@ -69321,7 +69513,7 @@ async function apiUploadFiles(project2, name, req) {
69321
69513
  return errorResponse(`File too large: ${entry.name} (max 10MB)`, 400);
69322
69514
  }
69323
69515
  const safeName = `${Date.now()}_${sanitizeFilename(entry.name)}`;
69324
- const destPath = join21(uploadDir, safeName);
69516
+ const destPath = join22(uploadDir, safeName);
69325
69517
  if (!resolve16(destPath).startsWith(`${uploadDir}/`)) {
69326
69518
  return errorResponse("Invalid filename", 400);
69327
69519
  }
@@ -70057,7 +70249,7 @@ var init_codex_app_server = __esm({
70057
70249
  });
70058
70250
 
70059
70251
  // ../host/src/modules/taskflow/adapters/run-store.ts
70060
- import { mkdirSync as mkdirSync9 } from "node:fs";
70252
+ import { mkdirSync as mkdirSync10 } from "node:fs";
70061
70253
  import { dirname as dirname15 } from "node:path";
70062
70254
  function defaultRunStorePath() {
70063
70255
  return globalPaths().database;
@@ -70218,7 +70410,7 @@ function isConstraint(error61, target) {
70218
70410
  return error61 instanceof Error && error61.message.includes(target);
70219
70411
  }
70220
70412
  function createRunStore(path7 = defaultRunStorePath()) {
70221
- mkdirSync9(dirname15(path7), { recursive: true });
70413
+ mkdirSync10(dirname15(path7), { recursive: true });
70222
70414
  const database = openDatabase(path7);
70223
70415
  database.pragma("foreign_keys = ON");
70224
70416
  database.pragma("journal_mode = WAL");
@@ -70638,10 +70830,15 @@ var init_run_store = __esm({
70638
70830
  input_json TEXT NOT NULL,
70639
70831
  status TEXT NOT NULL CHECK(status IN ('queued', 'provisioning', 'running', 'waiting_input', 'completed', 'failed', 'cancelled', 'interrupted')),
70640
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')),
70641
70835
  workflow_snapshot_id TEXT,
70642
70836
  workspace_id TEXT,
70643
70837
  worktree_path TEXT,
70644
70838
  canonical_workspace_path TEXT,
70839
+ checkout_canonical_path TEXT,
70840
+ checkout_branch TEXT,
70841
+ environment_id TEXT,
70645
70842
  branch TEXT,
70646
70843
  base_branch TEXT,
70647
70844
  base_commit TEXT,
@@ -70669,6 +70866,7 @@ var init_run_store = __esm({
70669
70866
  path TEXT NOT NULL,
70670
70867
  content_hash TEXT NOT NULL,
70671
70868
  engine_version TEXT NOT NULL,
70869
+ key_version TEXT NOT NULL DEFAULT 'v1',
70672
70870
  source TEXT NOT NULL,
70673
70871
  metadata_json TEXT NOT NULL,
70674
70872
  created_at TEXT NOT NULL
@@ -70693,6 +70891,7 @@ var init_run_store = __esm({
70693
70891
  error TEXT,
70694
70892
  session_id TEXT,
70695
70893
  capabilities_json TEXT,
70894
+ checkpoint_json TEXT,
70696
70895
  started_at TEXT,
70697
70896
  completed_at TEXT,
70698
70897
  UNIQUE(run_id, node_key, attempt)
@@ -70704,10 +70903,7 @@ var init_run_store = __esm({
70704
70903
  source TEXT NOT NULL,
70705
70904
  updated_at TEXT NOT NULL
70706
70905
  );
70707
- `,
70708
- "ALTER TABLE executions ADD COLUMN checkpoint_json TEXT;",
70709
- "ALTER TABLE workflow_snapshots ADD COLUMN key_version TEXT NOT NULL DEFAULT 'v1';",
70710
- `
70906
+
70711
70907
  CREATE TABLE IF NOT EXISTS run_events (
70712
70908
  id TEXT PRIMARY KEY,
70713
70909
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70720,8 +70916,7 @@ var init_run_store = __esm({
70720
70916
  payload_json TEXT NOT NULL,
70721
70917
  UNIQUE(run_id, sequence)
70722
70918
  );
70723
- `,
70724
- `
70919
+
70725
70920
  CREATE TABLE IF NOT EXISTS workspace_leases (
70726
70921
  id TEXT PRIMARY KEY,
70727
70922
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70739,12 +70934,7 @@ var init_run_store = __esm({
70739
70934
  updated_at TEXT NOT NULL,
70740
70935
  released_at TEXT
70741
70936
  );
70742
- `,
70743
- "ALTER TABLE runs ADD COLUMN workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch'));",
70744
- "ALTER TABLE runs ADD COLUMN workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write'));",
70745
- "ALTER TABLE runs ADD COLUMN checkout_canonical_path TEXT;",
70746
- "ALTER TABLE runs ADD COLUMN checkout_branch TEXT;",
70747
- `
70937
+
70748
70938
  CREATE TABLE IF NOT EXISTS checkout_claims (
70749
70939
  run_id TEXT PRIMARY KEY REFERENCES runs(id),
70750
70940
  project_id TEXT NOT NULL,
@@ -70753,8 +70943,7 @@ var init_run_store = __esm({
70753
70943
  created_at TEXT NOT NULL
70754
70944
  );
70755
70945
  CREATE INDEX IF NOT EXISTS checkout_claims_path_idx ON checkout_claims(project_id, canonical_path);
70756
- `,
70757
- "ALTER TABLE runs ADD COLUMN environment_id TEXT;"
70946
+ `
70758
70947
  ];
70759
70948
  }
70760
70949
  });
@@ -71007,26 +71196,26 @@ var init_types2 = __esm({
71007
71196
  });
71008
71197
 
71009
71198
  // ../host/src/modules/taskflow/workflows/runtime/journal.ts
71010
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
71011
- 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";
71012
71201
  function dataRoot(roots = {}) {
71013
71202
  return roots.dataRoot ?? globalPaths().root;
71014
71203
  }
71015
71204
  function runDir(runId, roots = {}) {
71016
- return join22(dataRoot(roots), "runs", runId);
71205
+ return join23(dataRoot(roots), "runs", runId);
71017
71206
  }
71018
71207
  function journalPath(runId, roots = {}) {
71019
- return join22(runDir(runId, roots), "journal.jsonl");
71208
+ return join23(runDir(runId, roots), "journal.jsonl");
71020
71209
  }
71021
71210
  function ensureRunDir(runId, roots = {}) {
71022
71211
  const dir = runDir(runId, roots);
71023
- mkdirSync10(dir, { recursive: true });
71212
+ mkdirSync11(dir, { recursive: true });
71024
71213
  return dir;
71025
71214
  }
71026
71215
  function listRunIds(roots = {}) {
71027
- const dir = join22(dataRoot(roots), "runs");
71028
- if (!existsSync9(dir)) return [];
71029
- 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();
71030
71219
  }
71031
71220
  function checkResumePreconditions(meta3, current) {
71032
71221
  if (!meta3) return;
@@ -71052,7 +71241,7 @@ function canonicalArgs(value3) {
71052
71241
  }
71053
71242
  function writeResult(runId, value3, roots = {}) {
71054
71243
  const dir = ensureRunDir(runId, roots);
71055
- writeFileSync8(join22(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71244
+ writeFileSync8(join23(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71056
71245
  }
71057
71246
  var JournalNotFoundError, ResumePreconditionError, Journal;
71058
71247
  var init_journal = __esm({
@@ -71080,7 +71269,7 @@ var init_journal = __esm({
71080
71269
  path;
71081
71270
  constructor(runId, roots = {}) {
71082
71271
  this.path = journalPath(runId, roots);
71083
- mkdirSync10(dirname16(this.path), { recursive: true });
71272
+ mkdirSync11(dirname16(this.path), { recursive: true });
71084
71273
  }
71085
71274
  append(entry) {
71086
71275
  appendFileSync2(this.path, `${JSON.stringify(entry)}
@@ -71088,12 +71277,12 @@ var init_journal = __esm({
71088
71277
  }
71089
71278
  /** True if a journal file exists for this run id (vs. a typo'd / absent run). */
71090
71279
  static exists(runId, roots = {}) {
71091
- return existsSync9(journalPath(runId, roots));
71280
+ return existsSync10(journalPath(runId, roots));
71092
71281
  }
71093
71282
  static load(runId, roots = {}) {
71094
71283
  const path7 = journalPath(runId, roots);
71095
71284
  const out = { results: /* @__PURE__ */ new Map(), indexByKey: /* @__PURE__ */ new Map() };
71096
- if (!existsSync9(path7)) return out;
71285
+ if (!existsSync10(path7)) return out;
71097
71286
  const text = readFileSync13(path7, "utf8");
71098
71287
  for (const line4 of text.split("\n")) {
71099
71288
  const trimmed = line4.trim();
@@ -71496,9 +71685,9 @@ var init_sandbox = __esm({
71496
71685
  });
71497
71686
 
71498
71687
  // ../host/src/modules/taskflow/workflows/runtime/registry.ts
71499
- 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";
71500
71689
  import { homedir as homedir4 } from "node:os";
71501
- 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";
71502
71691
  import { fileURLToPath as fileURLToPath4 } from "node:url";
71503
71692
  function builtinDir() {
71504
71693
  const here = dirname17(fileURLToPath4(import.meta.url));
@@ -71507,10 +71696,10 @@ function builtinDir() {
71507
71696
  ["..", "..", "builtins"],
71508
71697
  ["..", "..", "..", "..", "..", "workflows"]
71509
71698
  ]) {
71510
- const candidate = join23(here, ...rel);
71511
- if (existsSync10(candidate)) return candidate;
71699
+ const candidate = join24(here, ...rel);
71700
+ if (existsSync11(candidate)) return candidate;
71512
71701
  }
71513
- return join23(here, "..", "builtins");
71702
+ return join24(here, "..", "builtins");
71514
71703
  }
71515
71704
  function projectDirs(cwd) {
71516
71705
  const dirs = [];
@@ -71518,8 +71707,8 @@ function projectDirs(cwd) {
71518
71707
  let dir = resolve17(cwd);
71519
71708
  for (; ; ) {
71520
71709
  const workflows = projectPaths(dir).workflows;
71521
- if (existsSync10(workflows)) dirs.push(workflows);
71522
- if (existsSync10(join23(dir, ".git"))) break;
71710
+ if (existsSync11(workflows)) dirs.push(workflows);
71711
+ if (existsSync11(join24(dir, ".git"))) break;
71523
71712
  const parent = dirname17(dir);
71524
71713
  if (dir === home2 || parent === dir) break;
71525
71714
  dir = parent;
@@ -71533,7 +71722,7 @@ function workflowDirs(cwd, roots) {
71533
71722
  tier: "project",
71534
71723
  dir: resolve17(dir)
71535
71724
  })),
71536
- { tier: "user", dir: roots.globalDir ?? join23(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71725
+ { tier: "user", dir: roots.globalDir ?? join24(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71537
71726
  { tier: "builtin", dir: roots.builtinDir ?? builtinDir() }
71538
71727
  ];
71539
71728
  }
@@ -71553,7 +71742,7 @@ function scanDir(tier, dir) {
71553
71742
  const entries = [];
71554
71743
  for (const file2 of names) {
71555
71744
  if (!file2.endsWith(".js")) continue;
71556
- const filePath = join23(dir, file2);
71745
+ const filePath = join24(dir, file2);
71557
71746
  try {
71558
71747
  if (statSync6(filePath).size > MAX_WORKFLOW_BYTES) continue;
71559
71748
  const { meta: meta3 } = parseWorkflow(readFileSync14(filePath, "utf8"));
@@ -78613,7 +78802,7 @@ var init_schema = __esm({
78613
78802
  // ../host/src/modules/taskflow/workflows/worker/claude.ts
78614
78803
  import { readlinkSync, realpathSync as realpathSync3 } from "node:fs";
78615
78804
  import { homedir as homedir5 } from "node:os";
78616
- 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";
78617
78806
  function toClaudeEffort(effort) {
78618
78807
  return effort === "none" || effort === "minimal" ? "low" : effort;
78619
78808
  }
@@ -78652,7 +78841,7 @@ function realpathUpward(p) {
78652
78841
  for (let hops = 0; hops < 40; hops++) {
78653
78842
  try {
78654
78843
  const real = realpathSync3(existing);
78655
- return suffix ? join24(real, suffix) : real;
78844
+ return suffix ? join25(real, suffix) : real;
78656
78845
  } catch {
78657
78846
  }
78658
78847
  try {
@@ -78663,7 +78852,7 @@ function realpathUpward(p) {
78663
78852
  }
78664
78853
  const parent = dirname18(existing);
78665
78854
  if (parent === existing) return p;
78666
- suffix = suffix ? join24(basename9(existing), suffix) : basename9(existing);
78855
+ suffix = suffix ? join25(basename9(existing), suffix) : basename9(existing);
78667
78856
  existing = parent;
78668
78857
  }
78669
78858
  return p;
@@ -78757,7 +78946,7 @@ function unquote(s) {
78757
78946
  }
78758
78947
  function expandHome(p) {
78759
78948
  if (p === "~") return homedir5();
78760
- if (p.startsWith("~/")) return join24(homedir5(), p.slice(2));
78949
+ if (p.startsWith("~/")) return join25(homedir5(), p.slice(2));
78761
78950
  return p;
78762
78951
  }
78763
78952
  function usageFromResult(last) {
@@ -79389,7 +79578,7 @@ ${tail}` : message;
79389
79578
 
79390
79579
  // ../host/src/modules/taskflow/workflows/worker/codex.ts
79391
79580
  import { copyFile, writeFile as writeFile7 } from "node:fs/promises";
79392
- import { basename as basename10, join as join25 } from "node:path";
79581
+ import { basename as basename10, join as join26 } from "node:path";
79393
79582
  function textInput(text) {
79394
79583
  return [{ type: "text", text, text_elements: [] }];
79395
79584
  }
@@ -79805,7 +79994,7 @@ var init_codex = __esm({
79805
79994
  const id = basename10(rawId) || "image";
79806
79995
  const savedPath = typeof item.savedPath === "string" ? item.savedPath : void 0;
79807
79996
  const b64 = typeof item.result === "string" ? item.result : void 0;
79808
- const dest = join25(state3.cwd, `${id}.png`);
79997
+ const dest = join26(state3.cwd, `${id}.png`);
79809
79998
  const write4 = (async () => {
79810
79999
  try {
79811
80000
  if (savedPath) await copyFile(savedPath, dest);
@@ -80596,7 +80785,7 @@ __export(pi_exports, {
80596
80785
  });
80597
80786
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
80598
80787
  import { tmpdir as tmpdir2 } from "node:os";
80599
- import { join as join26 } from "node:path";
80788
+ import { join as join27 } from "node:path";
80600
80789
  function extractionPrompt2(spec, workingText) {
80601
80790
  return `Earlier you produced this answer:
80602
80791
 
@@ -80760,7 +80949,7 @@ var init_pi = __esm({
80760
80949
  return this.versionCheck;
80761
80950
  }
80762
80951
  async checkVersion() {
80763
- const scratch = mkdtempSync(join26(tmpdir2(), `${APP_SLUG}-pi-version-`));
80952
+ const scratch = mkdtempSync(join27(tmpdir2(), `${APP_SLUG}-pi-version-`));
80764
80953
  let out;
80765
80954
  try {
80766
80955
  out = await captureStdout({
@@ -80967,7 +81156,7 @@ var init_factory = __esm({
80967
81156
  });
80968
81157
 
80969
81158
  // ../host/src/modules/taskflow/workflows/runtime/jsonl-writer.ts
80970
- import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync11 } from "node:fs";
81159
+ import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync12 } from "node:fs";
80971
81160
  function dirOf(filePath) {
80972
81161
  const i3 = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
80973
81162
  return i3 <= 0 ? "." : filePath.slice(0, i3);
@@ -80980,7 +81169,7 @@ var init_jsonl_writer = __esm({
80980
81169
  stream;
80981
81170
  dead = false;
80982
81171
  constructor(filePath, opts = {}) {
80983
- mkdirSync11(dirOf(filePath), { recursive: true });
81172
+ mkdirSync12(dirOf(filePath), { recursive: true });
80984
81173
  this.stream = createWriteStream2(filePath, { flags: opts.flags ?? "a" });
80985
81174
  this.stream.on("error", (err2) => {
80986
81175
  this.dead = true;
@@ -81021,7 +81210,7 @@ var init_jsonl_writer = __esm({
81021
81210
  });
81022
81211
 
81023
81212
  // ../host/src/modules/taskflow/workflows/runtime/event-sink.ts
81024
- import { join as join27 } from "node:path";
81213
+ import { join as join28 } from "node:path";
81025
81214
  var FileEventSink;
81026
81215
  var init_event_sink = __esm({
81027
81216
  "../host/src/modules/taskflow/workflows/runtime/event-sink.ts"() {
@@ -81033,7 +81222,7 @@ var init_event_sink = __esm({
81033
81222
  listeners;
81034
81223
  clock;
81035
81224
  constructor(runId, opts = {}) {
81036
- 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" });
81037
81226
  this.listeners = opts.listeners ?? [];
81038
81227
  this.clock = opts.clock ?? (() => globalThis.Date.now());
81039
81228
  }
@@ -81135,15 +81324,15 @@ var init_semaphore = __esm({
81135
81324
  });
81136
81325
 
81137
81326
  // ../host/src/modules/taskflow/workflows/runtime/transcript.ts
81138
- import { join as join28 } from "node:path";
81327
+ import { join as join29 } from "node:path";
81139
81328
  function agentsDir(runId, roots = {}) {
81140
- return join28(runDir(runId, roots), "agents");
81329
+ return join29(runDir(runId, roots), "agents");
81141
81330
  }
81142
81331
  function agentTranscriptPath(runId, index, roots = {}) {
81143
- return join28(agentsDir(runId, roots), `${index}.jsonl`);
81332
+ return join29(agentsDir(runId, roots), `${index}.jsonl`);
81144
81333
  }
81145
81334
  function agentTranscriptPathByName(runId, name, roots = {}) {
81146
- return join28(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81335
+ return join29(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81147
81336
  }
81148
81337
  function truncate2(s, max) {
81149
81338
  if (s.length <= max) return s;
@@ -81232,8 +81421,8 @@ var init_transcript = __esm({
81232
81421
 
81233
81422
  // ../host/src/modules/taskflow/workflows/runtime/worktree.ts
81234
81423
  import { execFile } from "node:child_process";
81235
- import { existsSync as existsSync11, rmSync as rmSync3 } from "node:fs";
81236
- 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";
81237
81426
  import { promisify as promisify3 } from "node:util";
81238
81427
  async function git3(cwd, args) {
81239
81428
  const { stdout: stdout2 } = await exec("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
@@ -81249,7 +81438,7 @@ async function findGitRoot(cwd) {
81249
81438
  async function createWorktree(args) {
81250
81439
  const name = `${args.runId}-${args.index}`;
81251
81440
  const branch = args.branch ?? `aw/${name}`;
81252
- const path7 = join29(projectPaths(args.gitRoot).worktrees, name);
81441
+ const path7 = join30(projectPaths(args.gitRoot).worktrees, name);
81253
81442
  const base2 = await git3(args.gitRoot, ["rev-parse", "HEAD"]);
81254
81443
  await pruneStaleWorktree(args.gitRoot, path7);
81255
81444
  await git3(args.gitRoot, ["worktree", "add", "--relative-paths", "--detach", path7, base2]);
@@ -81271,7 +81460,7 @@ async function pruneStaleWorktree(gitRoot2, path7) {
81271
81460
  });
81272
81461
  await git3(gitRoot2, ["worktree", "prune"]).catch(() => {
81273
81462
  });
81274
- if (existsSync11(path7)) {
81463
+ if (existsSync12(path7)) {
81275
81464
  try {
81276
81465
  rmSync3(path7, { recursive: true, force: true });
81277
81466
  } catch {
@@ -82004,7 +82193,7 @@ ${e.status === "completed" ? "\u2713" : "\u2717"} ${e.status}${e.error ? `: ${e.
82004
82193
  // ../host/src/modules/taskflow/workflows/runtime/run.ts
82005
82194
  import { createHash as createHash10, randomBytes as randomBytes7 } from "node:crypto";
82006
82195
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
82007
- import { join as join30, resolve as resolve19 } from "node:path";
82196
+ import { join as join31, resolve as resolve19 } from "node:path";
82008
82197
  async function runWorkflow(opts) {
82009
82198
  const filePath = resolve19(opts.file);
82010
82199
  const source = readFileSync15(filePath, "utf8");
@@ -82064,7 +82253,7 @@ async function runWorkflow(opts) {
82064
82253
  if (opts.signal?.aborted) ac.abort();
82065
82254
  else opts.signal?.addEventListener("abort", onSig, { once: true });
82066
82255
  events.emit({ type: "run", status: "started", runId, workflowFile: filePath });
82067
- const heartbeatFile = join30(runDir(runId, opts.roots), ".heartbeat");
82256
+ const heartbeatFile = join31(runDir(runId, opts.roots), ".heartbeat");
82068
82257
  const beat = () => {
82069
82258
  try {
82070
82259
  writeFileSync9(heartbeatFile, String(Date.now()));
@@ -83265,9 +83454,9 @@ var init_environment_diagnostics_service = __esm({
83265
83454
  });
83266
83455
 
83267
83456
  // ../host/src/modules/taskflow/services/environment-worker-factory.ts
83268
- 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";
83269
83458
  import { tmpdir as tmpdir3 } from "node:os";
83270
- 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";
83271
83460
  function mapAgentSpecToEnvironment(spec, hostWorkspace, containerWorkspace) {
83272
83461
  const suffix = relative5(hostWorkspace, spec.cwd);
83273
83462
  if (suffix.startsWith("..")) {
@@ -83320,12 +83509,12 @@ var init_environment_worker_factory = __esm({
83320
83509
  this.handle = handle2;
83321
83510
  const containerWorkspace = handle2.workspace.containerPath;
83322
83511
  if (!containerWorkspace) throw new Error(`Environment has no container workspace: ${handle2.id}`);
83323
- this.directory = mkdtempSync2(join31(tmpdir3(), "taskflow-environment-workers-"));
83512
+ this.directory = mkdtempSync2(join32(tmpdir3(), "taskflow-environment-workers-"));
83324
83513
  const paths3 = Object.fromEntries(
83325
83514
  Object.entries(executableByProvider).map(([provider, executable2]) => {
83326
- const path7 = join31(this.directory, provider);
83515
+ const path7 = join32(this.directory, provider);
83327
83516
  writeFileSync10(path7, transport.executableShim(handle2, executable2), { encoding: "utf8", mode: 448 });
83328
- chmodSync6(path7, 448);
83517
+ chmodSync7(path7, 448);
83329
83518
  return [provider, path7];
83330
83519
  })
83331
83520
  );
@@ -84397,7 +84586,7 @@ var init_run_presentation_service = __esm({
84397
84586
  });
84398
84587
 
84399
84588
  // ../host/src/modules/taskflow/services/workspace-facade.ts
84400
- import { join as join32 } from "node:path";
84589
+ import { join as join33 } from "node:path";
84401
84590
  function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, baseCommit, workspace2, access5) {
84402
84591
  const segment3 = runId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "run";
84403
84592
  if (workspace2.strategy !== "isolated_worktree") {
@@ -84414,7 +84603,7 @@ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, bas
84414
84603
  };
84415
84604
  }
84416
84605
  const name = `${APP_SLUG}-run-${segment3}`;
84417
- const path7 = join32(workspaceRoot, name);
84606
+ const path7 = join33(workspaceRoot, name);
84418
84607
  return {
84419
84608
  workspaceId: `workspace_${runId}`,
84420
84609
  path: path7,
@@ -84432,7 +84621,7 @@ function slugSegment(value3, fallback) {
84432
84621
  function forkBindingFor(run2, workspaceRoot, slug2) {
84433
84622
  const runSegment = slugSegment(run2.id, "run");
84434
84623
  const forkSegment = slugSegment(slug2, "fork");
84435
- const path7 = join32(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84624
+ const path7 = join33(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84436
84625
  return {
84437
84626
  workspaceId: `workspace_lease_${run2.id}_${forkSegment}`,
84438
84627
  path: path7,
@@ -84734,7 +84923,7 @@ var init_workspace_facade = __esm({
84734
84923
 
84735
84924
  // ../host/src/modules/taskflow/services/run-service.ts
84736
84925
  import { readFile as readFile9 } from "node:fs/promises";
84737
- import { join as join33 } from "node:path";
84926
+ import { join as join34 } from "node:path";
84738
84927
  function provisioningReason(reason) {
84739
84928
  return reason === "branch_conflict" || reason === "workspace_path_conflict" || reason === "checkout_busy" || reason === "dirty_workspace" || reason === "detached_head" ? reason : "workspace_provision_failed";
84740
84929
  }
@@ -85393,7 +85582,7 @@ var init_run_service = __esm({
85393
85582
  root2,
85394
85583
  terminal.cursor,
85395
85584
  terminal.type === "completed" ? "completed" : active.cancelling ? "cancelled" : "failed",
85396
- 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
85397
85586
  );
85398
85587
  const completedAt = this.now().toISOString();
85399
85588
  if (terminal.type === "completed") {
@@ -85505,7 +85694,7 @@ var init_run_service = __esm({
85505
85694
  async completedResult(engineRunId, dataRoot2) {
85506
85695
  try {
85507
85696
  const result = JsonValueSchema.safeParse(
85508
- JSON.parse(await readFile9(join33(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85697
+ JSON.parse(await readFile9(join34(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85509
85698
  );
85510
85699
  return result.success ? result.data : null;
85511
85700
  } catch {
@@ -85910,7 +86099,7 @@ var init_taskflow_direct_session_service = __esm({
85910
86099
  // ../host/src/modules/taskflow/services/workflow-catalog-service.ts
85911
86100
  import { createHash as createHash11 } from "node:crypto";
85912
86101
  import { readdir as readdir4, readFile as readFile10, stat as stat4 } from "node:fs/promises";
85913
- import { join as join34, resolve as resolve21 } from "node:path";
86102
+ import { join as join35, resolve as resolve21 } from "node:path";
85914
86103
  function hash3(value3) {
85915
86104
  return `sha256:${createHash11("sha256").update(value3).digest("hex")}`;
85916
86105
  }
@@ -85954,7 +86143,7 @@ function duplicateDiagnostic(name, origin) {
85954
86143
  function rootsFor(config3) {
85955
86144
  return [
85956
86145
  { origin: "project", directory: projectPaths(resolve21(config3.projectRoot)).workflows, priority: 0 },
85957
- { 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 },
85958
86147
  { origin: "builtin", directory: resolve21(config3.builtinRoot), priority: 2 }
85959
86148
  ];
85960
86149
  }
@@ -86068,7 +86257,7 @@ var init_workflow_catalog_service = __esm({
86068
86257
  return { candidates, diagnostics, invalidEntries };
86069
86258
  }
86070
86259
  for (const name of names) {
86071
- const path7 = join34(root2.directory, name);
86260
+ const path7 = join35(root2.directory, name);
86072
86261
  try {
86073
86262
  if ((await stat4(path7)).size > MAX_WORKFLOW_BYTES2) {
86074
86263
  const diagnostic = {
@@ -86113,7 +86302,7 @@ var init_workflow_catalog_service = __esm({
86113
86302
  });
86114
86303
 
86115
86304
  // ../host/src/modules/taskflow/services/workflow-event-bridge.ts
86116
- import { join as join35 } from "node:path";
86305
+ import { join as join36 } from "node:path";
86117
86306
  function record5(value3) {
86118
86307
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return null;
86119
86308
  const output2 = {};
@@ -86203,7 +86392,7 @@ function executionFor(run2, existing, details, context) {
86203
86392
  key: details.key,
86204
86393
  index: details.index,
86205
86394
  phaseIndex: details.phaseIndex,
86206
- 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
86207
86396
  },
86208
86397
  workspaceId: run2.workspaceId,
86209
86398
  input: existing?.input ?? null,
@@ -86271,7 +86460,7 @@ var init_workflow_event_bridge = __esm({
86271
86460
 
86272
86461
  // ../host/src/modules/taskflow/services/workflow-runner.ts
86273
86462
  import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
86274
- import { join as join36 } from "node:path";
86463
+ import { join as join37 } from "node:path";
86275
86464
  function envelope(spec, message) {
86276
86465
  return {
86277
86466
  ...message,
@@ -86311,9 +86500,9 @@ var init_workflow_runner = __esm({
86311
86500
  const pid = process.pid;
86312
86501
  let heartbeat;
86313
86502
  const done = (async () => {
86314
- const runDirectory = join36(spec.spec.dataRoot, "runs", spec.engineRunId);
86503
+ const runDirectory = join37(spec.spec.dataRoot, "runs", spec.engineRunId);
86315
86504
  await mkdir5(runDirectory, { recursive: true });
86316
- const snapshotPath = join36(runDirectory, "workflow.js");
86505
+ const snapshotPath = join37(runDirectory, "workflow.js");
86317
86506
  await writeFile8(snapshotPath, spec.spec.source, "utf8");
86318
86507
  emit(envelope(spec, { type: "started", pid }));
86319
86508
  heartbeat = setInterval(() => {
@@ -87000,15 +87189,15 @@ var init_worktree_conversation_service = __esm({
87000
87189
 
87001
87190
  // ../host/src/modules/taskflow/adapters/docker-compose-environment.ts
87002
87191
  import { createHash as createHash12 } from "node:crypto";
87003
- import { existsSync as existsSync12, readFileSync as readFileSync16 } from "node:fs";
87192
+ import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
87004
87193
  import { resolve as resolve22 } from "node:path";
87005
87194
  function composeFile(workspacePath, configured) {
87006
87195
  if (configured) {
87007
87196
  const candidate = resolve22(workspacePath, configured);
87008
- if (existsSync12(candidate)) return candidate;
87197
+ if (existsSync13(candidate)) return candidate;
87009
87198
  throw new Error(`Docker Compose file does not exist: ${configured}`);
87010
87199
  }
87011
- const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync12);
87200
+ const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync13);
87012
87201
  if (!found) throw new Error("No Docker Compose file was found");
87013
87202
  return found;
87014
87203
  }
@@ -87037,7 +87226,7 @@ var init_docker_compose_environment = __esm({
87037
87226
  }
87038
87227
  async probe(context) {
87039
87228
  const version3 = await runCaptured(this.runner, { command: "docker", args: ["compose", "version", "--short"] });
87040
- 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);
87041
87230
  return {
87042
87231
  provider: this.id,
87043
87232
  available: version3.exit.code === 0 && configs.length > 0,
@@ -88384,8 +88573,8 @@ var init_project_environments = __esm({
88384
88573
  // ../host/src/modules/taskflow/server/project-app.ts
88385
88574
  import { spawn as spawn8 } from "node:child_process";
88386
88575
  import { randomUUID as randomUUID6 } from "node:crypto";
88387
- import { existsSync as existsSync13 } from "node:fs";
88388
- 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";
88389
88578
  import { fileURLToPath as fileURLToPath5 } from "node:url";
88390
88579
  function workflowAgentRuntimeConfig(value3) {
88391
88580
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
@@ -88416,7 +88605,7 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88416
88605
  const reconciliationService = runtime2.reconciliationService;
88417
88606
  const codexAppServerClient = new CodexAppServerClient({
88418
88607
  clientName: RUNTIME_IDENTITY.codexClientName,
88419
- clientVersion: "0.0.0"
88608
+ clientVersion: PORTTA_FLOW_VERSION
88420
88609
  });
88421
88610
  const claudeCliClient = new ClaudeCliClient();
88422
88611
  const worktreeConversationService = new WorktreeConversationService({
@@ -88469,14 +88658,14 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88469
88658
  const workflowEvents = new WorkflowEventBridge({ store: runStore, publisher: runEventPublisher });
88470
88659
  const workspaces = new WorkspaceFacade({ store: runStore, git: git4 });
88471
88660
  const workflowDataRoot = globalPaths().root;
88472
- const supervisorSocket = join37(workflowDataRoot, "runtime", "supervisor.sock");
88661
+ const supervisorSocket = join38(workflowDataRoot, "runtime", "supervisor.sock");
88473
88662
  const supervisor = new AgentSupervisorClient({
88474
88663
  socketPath: supervisorSocket,
88475
88664
  startDaemon: () => {
88476
88665
  const directory = dirname20(fileURLToPath5(import.meta.url));
88477
- const builtEntry = join37(directory, "supervisor.js");
88478
- const sourceEntry = join37(directory, "supervisor.ts");
88479
- 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" });
88480
88669
  child.unref();
88481
88670
  }
88482
88671
  });
@@ -89919,7 +90108,7 @@ var init_upgrade = __esm({
89919
90108
  });
89920
90109
 
89921
90110
  // ../host/src/modules/taskflow/server/host.ts
89922
- import { existsSync as existsSync14 } from "node:fs";
90111
+ import { existsSync as existsSync15 } from "node:fs";
89923
90112
  function createTaskflowHost(options) {
89924
90113
  const apps = /* @__PURE__ */ new Map();
89925
90114
  const manager = new ProjectManager({
@@ -89949,8 +90138,8 @@ function createTaskflowHost(options) {
89949
90138
  manager,
89950
90139
  apps,
89951
90140
  allowlist: options.projectAllowlist,
89952
- // Tracks leftover on-add setup records for API compatibility. Registration
89953
- // 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.
89954
90143
  initTracker: new ProjectInitTracker(),
89955
90144
  closeSockets: (prefix) => sockets.closeProject(prefix)
89956
90145
  });
@@ -89963,7 +90152,7 @@ function createTaskflowHost(options) {
89963
90152
  if (!isGitRepo(cwd)) return;
89964
90153
  const repoRoot = canonicalizeFsPath(projectRoot(cwd));
89965
90154
  const paths3 = projectPaths(repoRoot);
89966
- if (!existsSync14(paths3.config) && !existsSync14(paths3.localConfig)) return;
90155
+ if (!existsSync15(paths3.config) && !existsSync15(paths3.localConfig)) return;
89967
90156
  try {
89968
90157
  manager.addEphemeral(repoRoot);
89969
90158
  } catch (err2) {
@@ -89978,7 +90167,7 @@ function createTaskflowHost(options) {
89978
90167
  }
89979
90168
  };
89980
90169
  }
89981
- var init_host2 = __esm({
90170
+ var init_host = __esm({
89982
90171
  "../host/src/modules/taskflow/server/host.ts"() {
89983
90172
  "use strict";
89984
90173
  init_paths2();
@@ -90034,7 +90223,7 @@ function createDaemonTaskflowHost(context) {
90034
90223
  port: hostListen(env).port,
90035
90224
  workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
90036
90225
  version: env.PORTTA_VERSION || "0.0.0-local",
90037
- buildDate: true ? "2026-09-18T00:15:44Z" : (/* @__PURE__ */ new Date()).toISOString(),
90226
+ buildDate: true ? "2026-09-18T02:38:53Z" : (/* @__PURE__ */ new Date()).toISOString(),
90038
90227
  environmentStore: createEnvironmentStore(paths3.database),
90039
90228
  hostEnvironmentProvider: new HostEnvironmentProvider(),
90040
90229
  devContainerProvider: new DevContainerProvider(),
@@ -90105,9 +90294,8 @@ var init_taskflow4 = __esm({
90105
90294
  init_user_shell_env();
90106
90295
  init_environment_service_discovery();
90107
90296
  init_project_allowlist();
90108
- init_host2();
90297
+ init_host();
90109
90298
  init_host_projects();
90110
- init_runtime();
90111
90299
  TASKFLOW_SOCKET_MOUNT_PATH = `/ws/modules/${taskflowModule.id}`;
90112
90300
  taskflowHostModule = createTaskflowHostModule();
90113
90301
  }
@@ -90981,7 +91169,7 @@ var require_util2 = __commonJS({
90981
91169
  function getFilesInPath(source) {
90982
91170
  const lstatSync = fs.lstatSync;
90983
91171
  const readdirSync11 = fs.readdirSync;
90984
- const join70 = path7.join;
91172
+ const join71 = path7.join;
90985
91173
  function isDirectory2(source2) {
90986
91174
  return lstatSync(source2).isDirectory();
90987
91175
  }
@@ -90990,12 +91178,12 @@ var require_util2 = __commonJS({
90990
91178
  }
90991
91179
  function getDirectories(source2) {
90992
91180
  return readdirSync11(source2).map((name) => {
90993
- return join70(source2, name);
91181
+ return join71(source2, name);
90994
91182
  }).filter(isDirectory2);
90995
91183
  }
90996
91184
  function getFiles(source2) {
90997
91185
  return readdirSync11(source2).map((name) => {
90998
- return join70(source2, name);
91186
+ return join71(source2, name);
90999
91187
  }).filter(isFile);
91000
91188
  }
91001
91189
  function getFilesRecursively(source2) {
@@ -100630,7 +100818,7 @@ var require_network = __commonJS({
100630
100818
  var exec3 = __require("child_process").exec;
100631
100819
  var execSync = __require("child_process").execSync;
100632
100820
  var execFileSync2 = __require("child_process").execFileSync;
100633
- var readFileSync38 = __require("fs").readFileSync;
100821
+ var readFileSync37 = __require("fs").readFileSync;
100634
100822
  var fs = __require("fs");
100635
100823
  var util2 = require_util2();
100636
100824
  var _platform = process.platform;
@@ -101118,7 +101306,7 @@ var require_network = __commonJS({
101118
101306
  return result;
101119
101307
  }
101120
101308
  try {
101121
- const content = readFileSync38(file2, { encoding: "utf8" });
101309
+ const content = readFileSync37(file2, { encoding: "utf8" });
101122
101310
  const lines = content.split("\n").filter((l) => /iface|source/.test(l));
101123
101311
  lines.forEach((line4) => {
101124
101312
  const parts2 = line4.replace(/\s+/g, " ").trim().split(" ");
@@ -101285,7 +101473,7 @@ var require_network = __commonJS({
101285
101473
  return false;
101286
101474
  }
101287
101475
  }
101288
- function networkInterfaces2(callback, rescan, defaultString) {
101476
+ function networkInterfaces(callback, rescan, defaultString) {
101289
101477
  if (typeof callback === "string") {
101290
101478
  defaultString = callback;
101291
101479
  rescan = true;
@@ -101700,7 +101888,7 @@ var require_network = __commonJS({
101700
101888
  });
101701
101889
  });
101702
101890
  }
101703
- exports.networkInterfaces = networkInterfaces2;
101891
+ exports.networkInterfaces = networkInterfaces;
101704
101892
  function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) {
101705
101893
  const result = {
101706
101894
  iface,
@@ -101773,7 +101961,7 @@ var require_network = __commonJS({
101773
101961
  const workload = [];
101774
101962
  if (ifacesArray.length && ifacesArray[0].trim() === "*") {
101775
101963
  ifacesArray = [];
101776
- networkInterfaces2(false).then((allIFaces) => {
101964
+ networkInterfaces(false).then((allIFaces) => {
101777
101965
  for (let iface of allIFaces) {
101778
101966
  ifacesArray.push(iface.iface);
101779
101967
  }
@@ -101939,7 +102127,7 @@ var require_network = __commonJS({
101939
102127
  const psections = stdout2.toString().split(/\n\s*\n/);
101940
102128
  perfData = parseLinesWindowsPerfData(psections);
101941
102129
  }
101942
- networkInterfaces2(false).then((interfaces) => {
102130
+ networkInterfaces(false).then((interfaces) => {
101943
102131
  rx_bytes = 0;
101944
102132
  tx_bytes = 0;
101945
102133
  perfData.forEach((detail2) => {
@@ -103396,7 +103584,7 @@ var require_processes = __commonJS({
103396
103584
  }
103397
103585
  exec3(cmd, { maxBuffer: 1024 * 102400 }, function(error61, stdout3) {
103398
103586
  let curr_processes = stdout3.toString().split("\n");
103399
- let all = parseProcStat2(curr_processes.shift());
103587
+ let all = parseProcStat(curr_processes.shift());
103400
103588
  let list_new = {};
103401
103589
  let resultProcess = {};
103402
103590
  curr_processes.forEach((element) => {
@@ -103574,7 +103762,7 @@ var require_processes = __commonJS({
103574
103762
  });
103575
103763
  }
103576
103764
  exports.services = services;
103577
- function parseProcStat2(line4) {
103765
+ function parseProcStat(line4) {
103578
103766
  const parts2 = line4.replace(/ +/g, " ").split(" ");
103579
103767
  const user = parts2.length >= 2 ? parseInt(parts2[1]) : 0;
103580
103768
  const nice = parts2.length >= 3 ? parseInt(parts2[2]) : 0;
@@ -103914,7 +104102,7 @@ var require_processes = __commonJS({
103914
104102
  });
103915
104103
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error62, stdout3) => {
103916
104104
  let curr_processes = stdout3.toString().split("\n");
103917
- let all = parseProcStat2(curr_processes.shift());
104105
+ let all = parseProcStat(curr_processes.shift());
103918
104106
  let list_new = {};
103919
104107
  let resultProcess = {};
103920
104108
  curr_processes.forEach((element) => {
@@ -104369,7 +104557,7 @@ var require_processes = __commonJS({
104369
104557
  }
104370
104558
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error61, stdout3) => {
104371
104559
  let curr_processes = stdout3.toString().split("\n");
104372
- let all = parseProcStat2(curr_processes.shift());
104560
+ let all = parseProcStat(curr_processes.shift());
104373
104561
  let list_new = {};
104374
104562
  let resultProcess = {};
104375
104563
  curr_processes.forEach((element) => {
@@ -108443,7 +108631,7 @@ var require_lib = __commonJS({
108443
108631
  });
108444
108632
 
108445
108633
  // src/commands/flow/daemon.ts
108446
- import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
108634
+ import { existsSync as existsSync25, readFileSync as readFileSync23 } from "node:fs";
108447
108635
  function flowStateDir(env = process.env) {
108448
108636
  const configured = env[ENV_NAMES.hostStateDir]?.trim();
108449
108637
  if (configured) return configured;
@@ -108461,7 +108649,7 @@ function daemonToken(env = process.env) {
108461
108649
  const file2 = hostTokenFile(flowStateDir(env));
108462
108650
  if (existsSync25(file2)) {
108463
108651
  try {
108464
- const token = readFileSync24(file2, "utf8").trim();
108652
+ const token = readFileSync23(file2, "utf8").trim();
108465
108653
  if (token) return token;
108466
108654
  } catch {
108467
108655
  }
@@ -108564,8 +108752,8 @@ var init_server_port = __esm({
108564
108752
 
108565
108753
  // ../host/src/modules/taskflow/lib/shell.ts
108566
108754
  import { spawnSync as spawnSync8 } from "node:child_process";
108567
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
108568
- 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";
108569
108757
  function run(cmd, args, opts) {
108570
108758
  const resolved2 = resolveHostTool(cmd) ?? cmd;
108571
108759
  const result = spawnSync8(resolved2, args, {
@@ -108585,10 +108773,10 @@ function getGitRoot() {
108585
108773
  return result.stdout.toString().trim();
108586
108774
  }
108587
108775
  function detectProjectName(gitRoot2) {
108588
- const pkgPath = join48(gitRoot2, "package.json");
108776
+ const pkgPath = join49(gitRoot2, "package.json");
108589
108777
  if (existsSync26(pkgPath)) {
108590
108778
  try {
108591
- const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
108779
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
108592
108780
  if (pkg.name) return pkg.name;
108593
108781
  } catch {
108594
108782
  }
@@ -108743,36 +108931,6 @@ var init_project_env2 = __esm({
108743
108931
  }
108744
108932
  });
108745
108933
 
108746
- // src/commands/flow/process.ts
108747
- async function runProcess3(file2, args = [], options = {}) {
108748
- const execaOptions = {
108749
- cwd: options.cwd,
108750
- env: options.env,
108751
- input: options.input,
108752
- reject: options.reject ?? true,
108753
- shell: false,
108754
- timeout: options.timeout,
108755
- stdio: options.input !== void 0 ? ["pipe", options.stdio ?? "pipe", options.stdio ?? "pipe"] : options.stdio
108756
- };
108757
- const result = await execa(file2, [...args], execaOptions);
108758
- const notStarted = result.failed && result.exitCode === void 0 && !result.signal && !result.timedOut;
108759
- return {
108760
- stdout: typeof result.stdout === "string" ? result.stdout : "",
108761
- stderr: typeof result.stderr === "string" ? result.stderr : "",
108762
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
108763
- failed: result.failed,
108764
- ...notStarted && "originalMessage" in result ? { error: String(result.originalMessage) } : {}
108765
- };
108766
- }
108767
- var PROCESS_POLICY2;
108768
- var init_process = __esm({
108769
- "src/commands/flow/process.ts"() {
108770
- "use strict";
108771
- init_execa();
108772
- PROCESS_POLICY2 = Object.freeze({ shell: false, argumentArraysOnly: true });
108773
- }
108774
- });
108775
-
108776
108934
  // src/commands/flow/completions.ts
108777
108935
  var completions_exports = {};
108778
108936
  __export(completions_exports, {
@@ -108805,7 +108963,7 @@ function completionTree(command) {
108805
108963
  };
108806
108964
  }
108807
108965
  async function defaultRunGit(args) {
108808
- const result = await runProcess3("git", args, { reject: false });
108966
+ const result = await runProcess("git", args, { reject: false });
108809
108967
  return { exitCode: result.exitCode, stdout: result.stdout.trim() };
108810
108968
  }
108811
108969
  async function listWorktreeBranches(deps = { runGit: defaultRunGit }) {
@@ -110094,9 +110252,9 @@ ${f}
110094
110252
  });
110095
110253
 
110096
110254
  // ../host/src/modules/taskflow/services/init-authoring.ts
110097
- 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";
110098
110256
  import { tmpdir as tmpdir4 } from "node:os";
110099
- import { join as join49 } from "node:path";
110257
+ import { join as join50 } from "node:path";
110100
110258
  function isRecord8(value3) {
110101
110259
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
110102
110260
  }
@@ -110104,9 +110262,9 @@ function readString4(value3) {
110104
110262
  return typeof value3 === "string" && value3.trim().length > 0 ? value3 : null;
110105
110263
  }
110106
110264
  function detectPackageManager(gitRoot2) {
110107
- if (existsSync28(join49(gitRoot2, "bun.lock")) || existsSync28(join49(gitRoot2, "bun.lockb"))) return "bun";
110108
- if (existsSync28(join49(gitRoot2, "pnpm-lock.yaml"))) return "pnpm";
110109
- 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";
110110
110268
  return "npm";
110111
110269
  }
110112
110270
  function detectMainBranch(gitRoot2) {
@@ -110143,25 +110301,25 @@ function detectInitProjectContext(gitRoot2, defaultAgent) {
110143
110301
  }
110144
110302
  function detectInitEnvironment(gitRoot2, requested = "auto") {
110145
110303
  const devcontainerConfigs = [".devcontainer.json", ".devcontainer/devcontainer.json"].filter(
110146
- (path7) => existsSync28(join49(gitRoot2, path7))
110304
+ (path7) => existsSync28(join50(gitRoot2, path7))
110147
110305
  );
110148
110306
  const composeFiles2 = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].filter(
110149
- (path7) => existsSync28(join49(gitRoot2, path7))
110307
+ (path7) => existsSync28(join50(gitRoot2, path7))
110150
110308
  );
110151
- 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";
110152
110310
  return {
110153
110311
  devcontainerConfigs,
110154
110312
  composeFiles: composeFiles2,
110155
- dockerfile: existsSync28(join49(gitRoot2, "Dockerfile")),
110156
- packageJson: existsSync28(join49(gitRoot2, "package.json")),
110313
+ dockerfile: existsSync28(join50(gitRoot2, "Dockerfile")),
110314
+ packageJson: existsSync28(join50(gitRoot2, "package.json")),
110157
110315
  selectedRuntime
110158
110316
  };
110159
110317
  }
110160
110318
  function buildInitPromptSpec(context) {
110161
110319
  const systemPrompt = [
110162
110320
  `You are bootstrapping a local repository for ${APP_NAME}.`,
110163
- `A starter \`${PROJECT_CONFIG_PATH}\` already exists at the repo root.`,
110164
- `Inspect the repository in the current working directory and edit that existing \`${PROJECT_CONFIG_PATH}\` in place.`,
110321
+ `A starter \`${PROJECT_CONFIG_PATH2}\` already exists at the repo root.`,
110322
+ `Inspect the repository in the current working directory and edit that existing \`${PROJECT_CONFIG_PATH2}\` in place.`,
110165
110323
  "Do not modify any other file.",
110166
110324
  "Do not ask the user questions. Infer the config from the repository contents.",
110167
110325
  "Be efficient: inspect only the files needed to determine the project name, main branch, service layout, dev commands, and ports.",
@@ -110174,7 +110332,7 @@ function buildInitPromptSpec(context) {
110174
110332
  "workspace.mainBranch: infer from git",
110175
110333
  `workspace.worktrees.root: keep ${APP_DEFAULTS.worktreeRoot} unless there is clear evidence of an existing alternative`,
110176
110334
  "Do not copy detected Compose services or ports into config unless the user needs an explicit override.",
110177
- "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.",
110178
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.",
110179
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.",
110180
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.",
@@ -110186,11 +110344,11 @@ function buildInitPromptSpec(context) {
110186
110344
  "Only include optional sections like auto_name, lifecycleHooks, sandbox/docker config, mounts, or systemPrompt if the repository gives clear evidence they are needed.",
110187
110345
  "Prefer editing the existing keys over replacing the file with a completely different shape.",
110188
110346
  "Preserve the existing template structure and comments unless a specific change requires updating them.",
110189
- `Before finishing, verify that \`${PROJECT_CONFIG_PATH}\` exists and contains the final YAML.`
110347
+ `Before finishing, verify that \`${PROJECT_CONFIG_PATH2}\` exists and contains the final YAML.`
110190
110348
  ].join("\n");
110191
110349
  return {
110192
110350
  systemPrompt,
110193
- userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH}\` for this repository.`
110351
+ userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH2}\` for this repository.`
110194
110352
  };
110195
110353
  }
110196
110354
  function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`) {
@@ -110219,7 +110377,7 @@ function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`)
110219
110377
  ]
110220
110378
  };
110221
110379
  }
110222
- 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`);
110223
110381
  return {
110224
110382
  agent,
110225
110383
  cmd: "codex",
@@ -110475,7 +110633,7 @@ function finalizeAgentRun(spec, exitCode, stdoutResult, stderr2) {
110475
110633
  let summary = stdoutResult.assistantText.trim();
110476
110634
  if (spec.summaryPath && existsSync28(spec.summaryPath)) {
110477
110635
  try {
110478
- summary = readFileSync26(spec.summaryPath, "utf8").trim() || summary;
110636
+ summary = readFileSync25(spec.summaryPath, "utf8").trim() || summary;
110479
110637
  } finally {
110480
110638
  rmSync8(spec.summaryPath, { force: true });
110481
110639
  }
@@ -110510,7 +110668,7 @@ workspace:
110510
110668
  # intervalSeconds: 300
110511
110669
 
110512
110670
  # Taskflow discovers Dev Container, Compose, and Dockerfile services from the resolved runtime.
110513
- # 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
110514
110672
  # that accepts an injected port environment variable. Do not duplicate discovered services.
110515
110673
  services:
110516
110674
  # Example app service with a predictable port per worktree.
@@ -110536,8 +110694,8 @@ exposure:
110536
110694
  # Profiles define runtime, permissions, and tmux pane layout.
110537
110695
  profiles:
110538
110696
  default:
110539
- # Legacy panes run on the host; the environment provider controls the
110540
- # 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.
110541
110699
  runtime: host
110542
110700
  environment:
110543
110701
  provider: ${environmentProvider}
@@ -110742,13 +110900,13 @@ var init_init_deps = __esm({
110742
110900
  tool: "claude",
110743
110901
  args: ["--version"],
110744
110902
  required: false,
110745
- hint: `Install the Claude Code CLI to let Claude scaffold ${PROJECT_CONFIG_PATH}`
110903
+ hint: `Install the Claude Code CLI to let Claude scaffold ${PROJECT_CONFIG_PATH2}`
110746
110904
  },
110747
110905
  {
110748
110906
  tool: "codex",
110749
110907
  args: ["--version"],
110750
110908
  required: false,
110751
- hint: `Install the Codex CLI to let Codex scaffold ${PROJECT_CONFIG_PATH}`
110909
+ hint: `Install the Codex CLI to let Codex scaffold ${PROJECT_CONFIG_PATH2}`
110752
110910
  },
110753
110911
  { tool: "docker", args: ["--version"], required: false, hint: "https://docs.docker.com/get-started/get-docker/" }
110754
110912
  ];
@@ -110953,7 +111111,7 @@ async function runInit(options) {
110953
111111
  let selectedAnalyze = resolveInitAnalysis(options, selectedRuntime);
110954
111112
  const configExists = existsSync29(taskflowYaml);
110955
111113
  if (configExists) {
110956
- log2.info(`${PROJECT_CONFIG_PATH} already exists`);
111114
+ log2.info(`${PROJECT_CONFIG_PATH2} already exists`);
110957
111115
  } else if (needsInteractiveAnalysisFallback(options, selectedRuntime)) {
110958
111116
  selectedAnalyze = await selectFallbackAgent();
110959
111117
  }
@@ -110974,7 +111132,7 @@ async function runInit(options) {
110974
111132
  environmentProvider: detection.selectedRuntime
110975
111133
  })
110976
111134
  );
110977
- log2.success(`${PROJECT_CONFIG_PATH} created from deterministic detection`);
111135
+ log2.success(`${PROJECT_CONFIG_PATH2} created from deterministic detection`);
110978
111136
  } else {
110979
111137
  const available2 = isInitAgentSelectable(
110980
111138
  depStatuses.find((status) => status.tool === selectedAnalyze) ?? { found: false }
@@ -110997,11 +111155,11 @@ async function runInit(options) {
110997
111155
  const prompt = buildInitPromptSpec({ ...context, defaultAgent: selectedAnalyze });
110998
111156
  const command = buildInitAgentCommand(selectedAnalyze, prompt);
110999
111157
  const streamPrinter = createAgentStreamPrinter(label3);
111000
- log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH}...`);
111158
+ log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH2}...`);
111001
111159
  const result = await runInitAgentCommand(command, gitRoot2, { onEvent: streamPrinter.onEvent });
111002
111160
  streamPrinter.finish();
111003
111161
  if (!existsSync29(taskflowYaml)) {
111004
- log2.error(`${label3} removed ${PROJECT_CONFIG_PATH}`);
111162
+ log2.error(`${label3} removed ${PROJECT_CONFIG_PATH2}`);
111005
111163
  const details = [
111006
111164
  result.summary ? `Summary:
111007
111165
  ${result.summary}` : "",
@@ -111018,12 +111176,12 @@ ${result.stderr.trim()}` : ""
111018
111176
  const finalYaml = await readFile12(taskflowYaml, "utf8");
111019
111177
  const changedTemplate = configExists || finalYaml !== starterTemplate;
111020
111178
  if (result.exitCode === 0 && changedTemplate) {
111021
- log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH}`);
111179
+ log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH2}`);
111022
111180
  } else if (result.exitCode === 0) {
111023
111181
  log2.warning(`${label3} left the starter template unchanged`);
111024
- log2.warning(`${label3} did not change the starter template. Review ${PROJECT_CONFIG_PATH} manually.`);
111182
+ log2.warning(`${label3} did not change the starter template. Review ${PROJECT_CONFIG_PATH2} manually.`);
111025
111183
  } else if (changedTemplate) {
111026
- log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH}`);
111184
+ log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH2}`);
111027
111185
  log2.warning(`${label3} exited with code ${result.exitCode}. Review the generated file before using it.`);
111028
111186
  } else {
111029
111187
  log2.warning(`${label3} left the starter template in place`);
@@ -111046,7 +111204,7 @@ ${result.stderr.trim()}` : ""
111046
111204
  );
111047
111205
  outro("You're all set! Next steps:");
111048
111206
  console.log();
111049
- console.log(` 1. Review ${PROJECT_CONFIG_PATH} and adjust runtime and exposure overrides if needed`);
111207
+ console.log(` 1. Review ${PROJECT_CONFIG_PATH2} and adjust runtime and exposure overrides if needed`);
111050
111208
  console.log(" 2. Keep the host daemon running: portta host serve --detach (or portta host service install)");
111051
111209
  console.log(` 3. Enable tab completion: eval "$(${flowInvocation()} completion zsh)" (or bash)`);
111052
111210
  console.log();
@@ -111904,7 +112062,7 @@ import { setTimeout as delay4 } from "node:timers/promises";
111904
112062
  function projectSetupPhaseLabel(phase) {
111905
112063
  switch (phase) {
111906
112064
  case "creating_config":
111907
- return `Creating ${PROJECT_CONFIG_PATH}`;
112065
+ return `Creating ${PROJECT_CONFIG_PATH2}`;
111908
112066
  case "analyzing":
111909
112067
  return "Analyzing project structure";
111910
112068
  case "ready":
@@ -112231,7 +112389,7 @@ async function defaultConfirmPrune(worktreeCount) {
112231
112389
  }
112232
112390
  async function attachToHerdr() {
112233
112391
  if (process.env.HERDR_PANE_ID || process.env.HERDR_ENV) return;
112234
- const result = await runProcess3("herdr", [], { stdio: "inherit", reject: false });
112392
+ const result = await runProcess("herdr", [], { stdio: "inherit", reject: false });
112235
112393
  if (result.exitCode !== 0) {
112236
112394
  console.error("Warning: failed to attach to herdr");
112237
112395
  }
@@ -112254,12 +112412,12 @@ async function defaultSwitchToSessionWindow(projectDir, _branch, multiplexer) {
112254
112412
  }
112255
112413
  const sessionName = buildProjectSessionName(resolve30(projectDir));
112256
112414
  if (process.env.TMUX) {
112257
- const result = await runProcess3("tmux", ["switch-client", "-t", sessionName], { reject: false });
112415
+ const result = await runProcess("tmux", ["switch-client", "-t", sessionName], { reject: false });
112258
112416
  if (result.exitCode !== 0) {
112259
112417
  console.error(`Warning: failed to switch tmux client to ${sessionName}`);
112260
112418
  }
112261
112419
  } else {
112262
- 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 });
112263
112421
  if (result.exitCode !== 0) {
112264
112422
  console.error(`Warning: failed to attach to tmux session ${sessionName}`);
112265
112423
  }
@@ -112727,7 +112885,7 @@ function environmentBaseUrlFromControlUrl(value3) {
112727
112885
  }
112728
112886
  }
112729
112887
  async function runInherited(invocation2) {
112730
- const result = await runProcess3(invocation2.command, invocation2.args, {
112888
+ const result = await runProcess(invocation2.command, invocation2.args, {
112731
112889
  cwd: invocation2.cwd,
112732
112890
  stdio: "inherit",
112733
112891
  reject: false
@@ -112738,7 +112896,7 @@ async function runInherited(invocation2) {
112738
112896
  async function writeClipboard(value3) {
112739
112897
  const command = process.platform === "darwin" ? "pbcopy" : process.platform === "win32" ? "clip" : "xclip";
112740
112898
  const args = process.platform === "linux" ? ["-selection", "clipboard"] : [];
112741
- return (await runProcess3(command, args, { input: value3, reject: false })).exitCode === 0;
112899
+ return (await runProcess(command, args, { input: value3, reject: false })).exitCode === 0;
112742
112900
  }
112743
112901
  async function runEnvironmentCommand(request2, port, projectDir, stdout2 = console.log, stderr2 = console.error, dependencies = defaultEnvironmentCommandDependencies) {
112744
112902
  try {
@@ -112800,7 +112958,7 @@ async function runEnvironmentCommand(request2, port, projectDir, stdout2 = conso
112800
112958
  } else {
112801
112959
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
112802
112960
  const openerArgs = process.platform === "win32" ? ["/c", "start", "", endpoint.url] : [endpoint.url];
112803
- if ((await runProcess3(opener, openerArgs, { reject: false })).exitCode !== 0) {
112961
+ if ((await runProcess(opener, openerArgs, { reject: false })).exitCode !== 0) {
112804
112962
  throw new Error("Browser open command failed");
112805
112963
  }
112806
112964
  }
@@ -113065,10 +113223,10 @@ var init_tail = __esm({
113065
113223
  import { createReadStream as createReadStream2, existsSync as existsSync30 } from "node:fs";
113066
113224
  import { readdir as readdir5, readFile as readFile13, realpath as realpath2, stat as stat6, watch } from "node:fs/promises";
113067
113225
  import { createServer as createServer2 } from "node:http";
113068
- 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";
113069
113227
  import { fileURLToPath as fileURLToPath6 } from "node:url";
113070
113228
  function runsDir() {
113071
- return join50(dataRoot(), "runs");
113229
+ return join51(dataRoot(), "runs");
113072
113230
  }
113073
113231
  function parseEvents(text) {
113074
113232
  const out = [];
@@ -113084,7 +113242,7 @@ function parseEvents(text) {
113084
113242
  }
113085
113243
  async function readEvents(runId) {
113086
113244
  try {
113087
- const text = await readFile13(join50(runsDir(), runId, "events.jsonl"), "utf8");
113245
+ const text = await readFile13(join51(runsDir(), runId, "events.jsonl"), "utf8");
113088
113246
  return parseEvents(text);
113089
113247
  } catch {
113090
113248
  return [];
@@ -113186,7 +113344,7 @@ function applyDeadman(status, startedAt, lastBeat) {
113186
113344
  }
113187
113345
  async function heartbeatMtime(runId) {
113188
113346
  try {
113189
- return (await stat6(join50(runsDir(), runId, ".heartbeat"))).mtimeMs;
113347
+ return (await stat6(join51(runsDir(), runId, ".heartbeat"))).mtimeMs;
113190
113348
  } catch {
113191
113349
  return 0;
113192
113350
  }
@@ -113217,7 +113375,7 @@ async function listRuns() {
113217
113375
  seen.add(runId);
113218
113376
  let eventsStat;
113219
113377
  try {
113220
- eventsStat = await stat6(join50(runsDir(), runId, "events.jsonl"));
113378
+ eventsStat = await stat6(join51(runsDir(), runId, "events.jsonl"));
113221
113379
  } catch {
113222
113380
  eventsStat = void 0;
113223
113381
  }
@@ -113233,7 +113391,7 @@ async function listRuns() {
113233
113391
  if (events.length === 0) {
113234
113392
  let mtime = 0;
113235
113393
  try {
113236
- mtime = (await stat6(join50(runsDir(), runId))).mtimeMs;
113394
+ mtime = (await stat6(join51(runsDir(), runId))).mtimeMs;
113237
113395
  } catch {
113238
113396
  }
113239
113397
  summaries.push({ summary: { runId, status: "unknown", agents: 0 }, mtime });
@@ -113260,7 +113418,7 @@ async function listRuns() {
113260
113418
  }
113261
113419
  function serveStatic(res, fileName) {
113262
113420
  const safe2 = normalize3(fileName).replace(/^(\.\.(?:[/\\]|$))+/, "");
113263
- const full = join50(WEB_DIR, safe2);
113421
+ const full = join51(WEB_DIR, safe2);
113264
113422
  if (!full.startsWith(WEB_DIR + sep2) && full !== WEB_DIR) {
113265
113423
  sendText(res, 403, "forbidden");
113266
113424
  return;
@@ -113409,10 +113567,10 @@ function sleepUnlessClosed(ms, isClosed) {
113409
113567
  });
113410
113568
  }
113411
113569
  function streamRun(req, res, runId) {
113412
- return tailJsonl(req, res, join50(runsDir(), runId, "events.jsonl"));
113570
+ return tailJsonl(req, res, join51(runsDir(), runId, "events.jsonl"));
113413
113571
  }
113414
113572
  function streamAgent(req, res, runId, index) {
113415
- return tailJsonl(req, res, join50(runsDir(), runId, "agents", `${index}.jsonl`));
113573
+ return tailJsonl(req, res, join51(runsDir(), runId, "agents", `${index}.jsonl`));
113416
113574
  }
113417
113575
  function parseChunks(text) {
113418
113576
  const out = [];
@@ -113428,7 +113586,7 @@ function parseChunks(text) {
113428
113586
  }
113429
113587
  async function readAgentChunks(runId, index) {
113430
113588
  try {
113431
- const text = await readFile13(join50(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113589
+ const text = await readFile13(join51(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113432
113590
  return parseChunks(text);
113433
113591
  } catch {
113434
113592
  return null;
@@ -113492,7 +113650,7 @@ async function handle(req, res) {
113492
113650
  const events = await readEvents(runId);
113493
113651
  if (events.length === 0) {
113494
113652
  try {
113495
- await stat6(join50(runsDir(), runId));
113653
+ await stat6(join51(runsDir(), runId));
113496
113654
  } catch {
113497
113655
  sendJson(res, 404, { error: "run not found", runId });
113498
113656
  return;
@@ -113569,8 +113727,8 @@ var init_serve = __esm({
113569
113727
  init_journal();
113570
113728
  init_tail();
113571
113729
  __dirname = dirname27(fileURLToPath6(import.meta.url));
113572
- WEB_CANDIDATES = [join50(__dirname, "web"), join50(__dirname, "..", "..", "viewer", "dist")];
113573
- 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");
113574
113732
  sseClients = 0;
113575
113733
  STALE_MS = 2e4;
113576
113734
  summaryCache = /* @__PURE__ */ new Map();
@@ -113604,15 +113762,15 @@ import { spawn as spawn9 } from "node:child_process";
113604
113762
  import {
113605
113763
  copyFileSync as copyFileSync3,
113606
113764
  existsSync as existsSync31,
113607
- mkdirSync as mkdirSync17,
113765
+ mkdirSync as mkdirSync18,
113608
113766
  readdirSync as readdirSync5,
113609
- readFileSync as readFileSync27,
113767
+ readFileSync as readFileSync26,
113610
113768
  realpathSync as realpathSync6,
113611
113769
  rmSync as rmSync9,
113612
113770
  statSync as statSync10
113613
113771
  } from "node:fs";
113614
113772
  import { get as httpGet } from "node:http";
113615
- 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";
113616
113774
  import { fileURLToPath as fileURLToPath7 } from "node:url";
113617
113775
  function parseArgs(argv) {
113618
113776
  const flags = { _: [] };
@@ -113716,8 +113874,6 @@ async function main(argv = process.argv.slice(2), options = {}) {
113716
113874
  return cmdValidate(flags, options.registryRoots);
113717
113875
  case "doctor":
113718
113876
  return cmdDoctor();
113719
- case "install-skill":
113720
- return cmdInstallSkillRetired();
113721
113877
  case "guide":
113722
113878
  return cmdGuide(options.skillPath);
113723
113879
  case void 0:
@@ -113747,7 +113903,7 @@ async function cmdServe(flags) {
113747
113903
  }
113748
113904
  });
113749
113905
  process.stderr.write(
113750
- `viewer: ${url2} (reading ${join51(dataRoot(), "runs")})
113906
+ `viewer: ${url2} (reading ${join52(dataRoot(), "runs")})
113751
113907
  ${idleShutdown ? "idle-shutdown on; " : ""}ctrl-c to stop
113752
113908
  `
113753
113909
  );
@@ -113807,7 +113963,7 @@ function openBrowser(url2) {
113807
113963
  }
113808
113964
  }
113809
113965
  async function cmdRuns(flags) {
113810
- const dir = join51(dataRoot(), "runs");
113966
+ const dir = join52(dataRoot(), "runs");
113811
113967
  if (!existsSync31(dir)) {
113812
113968
  console.log("(no runs yet)");
113813
113969
  return;
@@ -113815,12 +113971,12 @@ async function cmdRuns(flags) {
113815
113971
  const ids = readdirSync5(dir).filter((d) => d.startsWith("wf_"));
113816
113972
  if (flags.prune === true) {
113817
113973
  const keep = intFlag(flags, "keep") ?? 50;
113818
- 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);
113819
113975
  const remove = byAge.slice(keep);
113820
113976
  let bytes = 0;
113821
113977
  for (const r2 of remove) {
113822
- bytes += dirSize(join51(dir, r2.id));
113823
- 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 });
113824
113980
  }
113825
113981
  console.log(
113826
113982
  `pruned ${remove.length} run(s) (${(bytes / 1e6).toFixed(1)} MB); kept ${Math.min(keep, byAge.length)} newest`
@@ -113831,8 +113987,8 @@ async function cmdRuns(flags) {
113831
113987
  const stale2 = ids.filter((id) => isStaleRun(dir, id));
113832
113988
  let bytes = 0;
113833
113989
  for (const id of stale2) {
113834
- bytes += dirSize(join51(dir, id));
113835
- rmSync9(join51(dir, id), { recursive: true, force: true });
113990
+ bytes += dirSize(join52(dir, id));
113991
+ rmSync9(join52(dir, id), { recursive: true, force: true });
113836
113992
  }
113837
113993
  console.log(`pruned ${stale2.length} stale run(s) (${(bytes / 1e6).toFixed(1)} MB)`);
113838
113994
  return;
@@ -113841,7 +113997,7 @@ async function cmdRuns(flags) {
113841
113997
  const loaded = Journal.load(id);
113842
113998
  const name = loaded.meta?.workflowFile?.split("/").pop() ?? "";
113843
113999
  const agents = loaded.results.size;
113844
- const resultPath = join51(dir, id, "result.json");
114000
+ const resultPath = join52(dir, id, "result.json");
113845
114001
  const done = existsSync31(resultPath);
113846
114002
  const status = done ? "completed" : isStaleRun(dir, id) ? "stale" : "?";
113847
114003
  return { id, name, agents, status, at: loaded.meta?.createdAt ?? 0 };
@@ -113850,10 +114006,10 @@ async function cmdRuns(flags) {
113850
114006
  for (const r2 of rows) console.log(`${r2.id} ${r2.status.padEnd(10)} ${String(r2.agents).padStart(3)} agents ${r2.name}`);
113851
114007
  }
113852
114008
  function isStaleRun(runsBase, id) {
113853
- const rd = join51(runsBase, id);
114009
+ const rd = join52(runsBase, id);
113854
114010
  let lastRunStatus;
113855
114011
  try {
113856
- const lines = readFileSync27(join51(rd, "events.jsonl"), "utf8").trim().split("\n");
114012
+ const lines = readFileSync26(join52(rd, "events.jsonl"), "utf8").trim().split("\n");
113857
114013
  for (let i3 = lines.length - 1; i3 >= 0; i3--) {
113858
114014
  const m = lines[i3]?.match(/"type":"run","status":"([a-z]+)"/);
113859
114015
  if (m) {
@@ -113867,7 +114023,7 @@ function isStaleRun(runsBase, id) {
113867
114023
  if (lastRunStatus !== "started") return false;
113868
114024
  let beat = 0;
113869
114025
  try {
113870
- beat = statSync10(join51(rd, ".heartbeat")).mtimeMs;
114026
+ beat = statSync10(join52(rd, ".heartbeat")).mtimeMs;
113871
114027
  } catch {
113872
114028
  }
113873
114029
  return Date.now() - beat > 2e4;
@@ -113875,7 +114031,7 @@ function isStaleRun(runsBase, id) {
113875
114031
  function dirSize(dir) {
113876
114032
  let total = 0;
113877
114033
  for (const e of readdirSync5(dir, { withFileTypes: true })) {
113878
- const p = join51(dir, e.name);
114034
+ const p = join52(dir, e.name);
113879
114035
  total += e.isDirectory() ? dirSize(p) : statSync10(p).size;
113880
114036
  }
113881
114037
  return total;
@@ -113891,7 +114047,7 @@ async function cmdRun(flags, registryRoots) {
113891
114047
  }
113892
114048
  const resolvedFile = resolveFileOrName(file2, registryRoots);
113893
114049
  const overrides = {};
113894
- const provider = enumFlag(flags, "provider", PROVIDERS2);
114050
+ const provider = enumFlag(flags, "provider", PROVIDERS);
113895
114051
  if (provider) overrides.provider = provider;
113896
114052
  const model = str(flags.model);
113897
114053
  if (model) overrides.model = model;
@@ -113920,7 +114076,7 @@ async function cmdRun(flags, registryRoots) {
113920
114076
  if (argsFile) {
113921
114077
  let raw2;
113922
114078
  try {
113923
- raw2 = readFileSync27(resolve31(argsFile), "utf8");
114079
+ raw2 = readFileSync26(resolve31(argsFile), "utf8");
113924
114080
  } catch {
113925
114081
  throw new UsageError2(`--args-file not found: ${argsFile}`);
113926
114082
  }
@@ -113984,7 +114140,7 @@ async function cmdValidate(flags, registryRoots) {
113984
114140
  process.exitCode = 1;
113985
114141
  return;
113986
114142
  }
113987
- const source = readFileSync27(resolveFileOrName(file2, registryRoots), "utf8");
114143
+ const source = readFileSync26(resolveFileOrName(file2, registryRoots), "utf8");
113988
114144
  const { meta: meta3 } = parseWorkflow(source);
113989
114145
  console.log(`ok: "${meta3.name}" \u2014 ${meta3.description}`);
113990
114146
  if (meta3.phases) console.log(`phases: ${meta3.phases.map((p) => p.title).join(" \u2192 ")}`);
@@ -114022,20 +114178,20 @@ async function cmdSave(flags) {
114022
114178
  }
114023
114179
  const absFile = resolve31(file2);
114024
114180
  if (!existsSync31(absFile)) throw new UsageError2(`file not found: ${file2}`);
114025
- const { meta: meta3 } = parseWorkflow(readFileSync27(absFile, "utf8"));
114181
+ const { meta: meta3 } = parseWorkflow(readFileSync26(absFile, "utf8"));
114026
114182
  const name = meta3.name;
114027
114183
  if (name.includes("/") || name.includes("\\") || name.includes("..") || name.startsWith(".") || name.includes("\0")) {
114028
114184
  throw new UsageError2(`meta.name is not a safe filename: "${name}"`);
114029
114185
  }
114030
114186
  const useProject = flags.project === true;
114031
114187
  const destDir = useProject ? projectPaths(process.cwd()).workflows : globalPaths().workflows;
114032
- const dest = join51(destDir, `${name}.workflow.js`);
114188
+ const dest = join52(destDir, `${name}.workflow.js`);
114033
114189
  if (existsSync31(dest) && flags.force !== true) {
114034
114190
  throw new UsageError2(
114035
114191
  `${useProject ? "project" : "user"} workflow "${name}" already exists at ${dest} \u2014 use --force to overwrite`
114036
114192
  );
114037
114193
  }
114038
- mkdirSync17(destDir, { recursive: true });
114194
+ mkdirSync18(destDir, { recursive: true });
114039
114195
  copyFileSync3(absFile, dest);
114040
114196
  console.log(`saved "${name}" \u2192 ${dest}`);
114041
114197
  }
@@ -114066,7 +114222,7 @@ async function cmdDoctor() {
114066
114222
  const codexBin = process.env.CODEX_BIN ?? "codex";
114067
114223
  const opencodeBin = process.env.OPENCODE_BIN ?? "opencode";
114068
114224
  const piBin = process.env.PI_BIN ?? "pi";
114069
- const piScratch = mkdtempSync4(join51(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114225
+ const piScratch = mkdtempSync4(join52(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114070
114226
  let piOut;
114071
114227
  try {
114072
114228
  piOut = check4(piBin, ["--version"], { env: { ...process.env, PI_CODING_AGENT_DIR: piScratch }, cwd: tmpdir6() });
@@ -114084,31 +114240,20 @@ async function cmdDoctor() {
114084
114240
  console.log(` data dir : ${dataRoot()}`);
114085
114241
  }
114086
114242
  function readSkill(skillPath) {
114087
- if (skillPath) return readFileSync27(skillPath, "utf8");
114243
+ if (skillPath) return readFileSync26(skillPath, "utf8");
114088
114244
  const here = dirname28(fileURLToPath7(import.meta.url));
114089
114245
  const candidates = [
114090
- join51(here, "..", "skills", "portta-workflows", "SKILL.md"),
114091
- join51(here, "..", "..", "..", "skills", "portta-workflows", "SKILL.md"),
114092
- 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")
114093
114249
  ];
114094
114250
  const src = candidates.find((candidate) => existsSync31(candidate));
114095
114251
  if (!src) throw new Error(`skill source not found at ${candidates.join(" or ")}`);
114096
- return readFileSync27(src, "utf8");
114252
+ return readFileSync26(src, "utf8");
114097
114253
  }
114098
114254
  async function cmdGuide(skillPath) {
114099
114255
  process.stdout.write(readSkill(skillPath).replace(/^---\n[\s\S]*?\n---\n+/, ""));
114100
114256
  }
114101
- function cmdInstallSkillRetired() {
114102
- console.error(
114103
- `${CLI_NAME} workflows install-skill has been retired. Install the skill with the Skills CLI instead:
114104
-
114105
- npx skills add codions-labs/portta --skill portta-workflows -g
114106
-
114107
- It supports Claude Code, Codex, OpenCode, Cursor, Zed and others, symlinks by default,
114108
- and \`npx skills update\` keeps every agent current. See https://www.skills.sh.`
114109
- );
114110
- process.exitCode = 1;
114111
- }
114112
114257
  function printHelp() {
114113
114258
  console.log(`${APP_NAME} workflows \u2014 run JS workflow files that orchestrate coding agents
114114
114259
 
@@ -114169,7 +114314,7 @@ function invokedDirectly() {
114169
114314
  return false;
114170
114315
  }
114171
114316
  }
114172
- var UsageError2, BOOLEAN_FLAGS, PROVIDERS2, SANDBOXES, EFFORTS;
114317
+ var UsageError2, BOOLEAN_FLAGS, PROVIDERS, SANDBOXES, EFFORTS;
114173
114318
  var init_cli = __esm({
114174
114319
  "../host/src/modules/taskflow/workflows/cli.ts"() {
114175
114320
  "use strict";
@@ -114204,7 +114349,7 @@ var init_cli = __esm({
114204
114349
  "project",
114205
114350
  "force"
114206
114351
  ]);
114207
- PROVIDERS2 = PROVIDER_IDS;
114352
+ PROVIDERS = PROVIDER_IDS;
114208
114353
  SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
114209
114354
  EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
114210
114355
  if (invokedDirectly()) {
@@ -116296,7 +116441,7 @@ var RemovalPreview = named(
116296
116441
  "RemovalPreview"
116297
116442
  );
116298
116443
  var LiveEventKind = named(
116299
- 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"]),
116300
116445
  "LiveEventKind"
116301
116446
  );
116302
116447
  var LiveEvent = named(
@@ -117332,131 +117477,7 @@ var {
117332
117477
 
117333
117478
  // src/cli.ts
117334
117479
  init_errors3();
117335
-
117336
- // src/process.ts
117337
- init_execa();
117338
- import { spawn as spawn2 } from "node:child_process";
117339
- import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
117340
- var reporting = {};
117341
- function setProcessReporter(options) {
117342
- reporting = options;
117343
- }
117344
- function effectiveStdio(requested) {
117345
- if (requested === "inherit") return "inherit";
117346
- if (reporting.quiet) return "pipe";
117347
- if (reporting.verbose) return "stream";
117348
- return requested;
117349
- }
117350
- function outputTargets(mode) {
117351
- if (mode !== "stream") return { stdio: mode };
117352
- return {
117353
- stdin: "pipe",
117354
- stdout: reporting.json ? "pipe" : ["pipe", "inherit"],
117355
- stderr: ["pipe", "inherit"]
117356
- };
117357
- }
117358
- var HEARTBEAT_FIRST_MS = 1e4;
117359
- var HEARTBEAT_EVERY_MS = 3e4;
117360
- var HEARTBEAT_HINT_MS = 18e4;
117361
- function elapsed(sinceMs) {
117362
- const seconds = Math.round((Date.now() - sinceMs) / 1e3);
117363
- if (seconds < 60) return `${seconds}s`;
117364
- return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, "0")}s`;
117365
- }
117366
- function describeCommand(file2, args, limit = 88) {
117367
- const words = [];
117368
- for (let index = 0; index < args.length; index += 1) {
117369
- const argument = args[index] ?? "";
117370
- if (argument === "-f" || argument === "--file") {
117371
- index += 1;
117372
- continue;
117373
- }
117374
- words.push(argument);
117375
- }
117376
- const line4 = [file2, ...words].join(" ");
117377
- return line4.length <= limit ? line4 : `${line4.slice(0, limit - 1)}\u2026`;
117378
- }
117379
- function startHeartbeat(file2, args) {
117380
- if (reporting.quiet) return () => {
117381
- };
117382
- const started = Date.now();
117383
- const label3 = describeCommand(file2, args);
117384
- let hinted = false;
117385
- const announce = () => {
117386
- process.stderr.write(`wait still running: ${label3} (${elapsed(started)})
117387
- `);
117388
- if (!hinted && Date.now() - started >= HEARTBEAT_HINT_MS) {
117389
- hinted = true;
117390
- process.stderr.write(" -> a first build of the panel image takes several minutes; Ctrl-C is safe, and --verbose shows its output\n");
117391
- }
117392
- };
117393
- let repeat;
117394
- const first = setTimeout(() => {
117395
- announce();
117396
- repeat = setInterval(announce, HEARTBEAT_EVERY_MS);
117397
- repeat.unref?.();
117398
- }, HEARTBEAT_FIRST_MS);
117399
- first.unref?.();
117400
- return () => {
117401
- clearTimeout(first);
117402
- if (repeat) clearInterval(repeat);
117403
- };
117404
- }
117405
- async function runProcess(file2, args = [], options = {}) {
117406
- const mode = effectiveStdio(options.stdio ?? "pipe");
117407
- const execaOptions = {
117408
- cwd: options.cwd,
117409
- env: options.env,
117410
- input: options.input,
117411
- reject: options.reject ?? true,
117412
- shell: false,
117413
- timeout: options.timeout,
117414
- ...outputTargets(mode)
117415
- };
117416
- const stopHeartbeat = mode === "pipe" ? startHeartbeat(file2, args) : () => {
117417
- };
117418
- try {
117419
- const result = await execa(file2, [...args], execaOptions);
117420
- return {
117421
- stdout: typeof result.stdout === "string" ? result.stdout : "",
117422
- stderr: typeof result.stderr === "string" ? result.stderr : "",
117423
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
117424
- failed: result.failed
117425
- };
117426
- } finally {
117427
- stopHeartbeat();
117428
- }
117429
- }
117430
- var PROCESS_POLICY = Object.freeze({ shell: false, argumentArraysOnly: true });
117431
- async function runForeground(file2, args, options = {}) {
117432
- const child = execa(file2, [...args], { cwd: options.cwd, env: options.env, stdio: "inherit", reject: false, shell: false });
117433
- const forwarded = ["SIGINT", "SIGTERM", "SIGHUP"].map((signal) => [signal, () => {
117434
- child.kill(signal);
117435
- }]);
117436
- for (const [signal, forward] of forwarded) process.on(signal, forward);
117437
- try {
117438
- const result = await child;
117439
- return result.exitCode ?? (result.signal ? 1 : 0);
117440
- } finally {
117441
- for (const [signal, forward] of forwarded) process.off(signal, forward);
117442
- }
117443
- }
117444
- function spawnDetached(file2, args, options = {}) {
117445
- const log3 = options.logFile ? openSync2(options.logFile, "a", 384) : null;
117446
- try {
117447
- const child = spawn2(file2, [...args], {
117448
- cwd: options.cwd,
117449
- env: options.env,
117450
- shell: false,
117451
- detached: true,
117452
- stdio: log3 === null ? "ignore" : ["ignore", log3, log3]
117453
- });
117454
- child.unref();
117455
- return child.pid;
117456
- } finally {
117457
- if (log3 !== null) closeSync2(log3);
117458
- }
117459
- }
117480
+ init_process();
117460
117481
 
117461
117482
  // src/commands/access.ts
117462
117483
  init_src();
@@ -117484,6 +117505,7 @@ init_context();
117484
117505
  // src/docker.ts
117485
117506
  init_zod();
117486
117507
  init_errors3();
117508
+ init_process();
117487
117509
  var Identifier = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
117488
117510
  function identifier(value3, kind = "Docker identifier") {
117489
117511
  if (!Identifier.test(value3)) throw new UsageError(`invalid ${kind}: ${value3}`);
@@ -117501,12 +117523,10 @@ var InspectSchema = external_exports.object({
117501
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()
117502
117524
  }).passthrough()
117503
117525
  }).passthrough();
117504
- async function dockerAvailable() {
117505
- const result = await runProcess("docker", ["info"], { reject: false });
117506
- return result.exitCode === 0;
117507
- }
117508
117526
  async function requireDocker() {
117509
- 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");
117510
117530
  }
117511
117531
  async function dockerOperatingSystem() {
117512
117532
  const result = await runProcess("docker", ["info", "--format", "{{.OperatingSystem}}"], { reject: false, timeout: 8e3 });
@@ -117576,6 +117596,7 @@ async function isManagedContainer(id) {
117576
117596
 
117577
117597
  // src/commands/access.ts
117578
117598
  init_errors3();
117599
+ init_process();
117579
117600
  function globals(command) {
117580
117601
  return command.optsWithGlobals();
117581
117602
  }
@@ -117755,21 +117776,50 @@ async function serviceUnpublish(alias, options, command) {
117755
117776
  }
117756
117777
 
117757
117778
  // src/commands/clients.ts
117758
- import { copyFileSync as copyFileSync2, existsSync as existsSync22, mkdirSync as mkdirSync14, rmSync as rmSync5, statSync as statSync9 } from "node:fs";
117759
- 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";
117760
117781
 
117761
117782
  // src/commands/web.ts
117762
117783
  init_src();
117763
117784
  init_src();
117764
117785
  init_context();
117765
- import { chmodSync as chmodSync8, mkdirSync as mkdirSync13 } from "node:fs";
117766
- import { join as join44 } from "node:path";
117786
+ import { mkdirSync as mkdirSync14 } from "node:fs";
117787
+ import { join as join45 } from "node:path";
117767
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
+ }
117768
117817
 
117769
117818
  // src/local-release.ts
117770
117819
  init_src();
117771
117820
  init_errors3();
117772
- import { join as join6 } from "node:path";
117821
+ init_process();
117822
+ import { join as join7 } from "node:path";
117773
117823
  async function requireLocalRelease(context) {
117774
117824
  if (context.env["PORTTA_LOCAL_RELEASE"] !== "true") return;
117775
117825
  const missing = [];
@@ -117783,7 +117833,7 @@ async function requireLocalRelease(context) {
117783
117833
  }
117784
117834
  function selectLocalRelease(context) {
117785
117835
  const image = porttaImages(context.version).runtime;
117786
- patchEnvFile(join6(context.root, ".env"), {
117836
+ patchEnvFile(join7(context.root, ".env"), {
117787
117837
  PORTTA_AUTH_IMAGE: image,
117788
117838
  PORTTA_WEB_IMAGE: image,
117789
117839
  PORTTA_WEB_BUILD: "false",
@@ -117794,13 +117844,15 @@ function selectLocalRelease(context) {
117794
117844
  // src/commands/repos.ts
117795
117845
  init_src();
117796
117846
  import { createHash as createHash2 } from "node:crypto";
117797
- 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";
117798
- 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";
117799
117849
  init_context();
117800
117850
  init_errors3();
117851
+ init_process();
117801
117852
 
117802
117853
  // src/commands/git.ts
117803
- import { existsSync as existsSync5 } from "node:fs";
117854
+ init_process();
117855
+ import { existsSync as existsSync6 } from "node:fs";
117804
117856
  async function git(cwd, args) {
117805
117857
  const result = await runProcess("git", ["-C", cwd, ...args], { reject: false });
117806
117858
  return result.exitCode === 0 ? result.stdout.trim() : null;
@@ -117851,7 +117903,7 @@ function normalizePulls(raw2) {
117851
117903
  async function collectGitProject(project2, path7, declaredRemote = "", withPrs = false, cachedForge) {
117852
117904
  const collectedAt = Math.floor(Date.now() / 1e3);
117853
117905
  const base2 = { project: project2, workingDir: path7, collectedAt };
117854
- 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" };
117855
117907
  const branchName = await git(path7, ["rev-parse", "--abbrev-ref", "HEAD"]);
117856
117908
  const detached = branchName === "HEAD";
117857
117909
  const sha = await git(path7, ["rev-parse", "HEAD"]) ?? "";
@@ -117973,7 +118025,7 @@ async function findCandidates(options, env, registered = []) {
117973
118025
  }
117974
118026
  if (!options.environment && !options.path) {
117975
118027
  for (const path7 of registered) {
117976
- if (!existsSync6(path7)) continue;
118028
+ if (!existsSync7(path7)) continue;
117977
118029
  const root2 = await gitRootOf(path7);
117978
118030
  if (root2) add(root2);
117979
118031
  }
@@ -117987,7 +118039,7 @@ async function findCandidates(options, env, registered = []) {
117987
118039
  home2 = null;
117988
118040
  }
117989
118041
  }
117990
- if (home2 && !options.environment && !options.path && existsSync6(home2)) {
118042
+ if (home2 && !options.environment && !options.path && existsSync7(home2)) {
117991
118043
  let entries = [];
117992
118044
  try {
117993
118045
  entries = readdirSync(home2);
@@ -117996,9 +118048,9 @@ async function findCandidates(options, env, registered = []) {
117996
118048
  }
117997
118049
  for (const entry of entries) {
117998
118050
  if (!firstLevelCandidateName(entry)) continue;
117999
- const path7 = join7(home2, entry);
118051
+ const path7 = join8(home2, entry);
118000
118052
  if (!isDirectory(path7)) continue;
118001
- if (existsSync6(join7(path7, ".git"))) {
118053
+ if (existsSync7(join8(path7, ".git"))) {
118002
118054
  const root2 = await gitRootOf(path7);
118003
118055
  if (root2) add(root2);
118004
118056
  continue;
@@ -118011,8 +118063,8 @@ async function findCandidates(options, env, registered = []) {
118011
118063
  }
118012
118064
  for (const child of children) {
118013
118065
  if (!firstLevelCandidateName(child)) continue;
118014
- const childPath = join7(path7, child);
118015
- if (!isDirectory(childPath) || !existsSync6(join7(childPath, ".git"))) continue;
118066
+ const childPath = join8(path7, child);
118067
+ if (!isDirectory(childPath) || !existsSync7(join8(childPath, ".git"))) continue;
118016
118068
  const root2 = await gitRootOf(childPath);
118017
118069
  if (root2) add(root2);
118018
118070
  }
@@ -118033,8 +118085,8 @@ function sha256(content) {
118033
118085
  async function collectInstructions(root2) {
118034
118086
  const paths3 = [...INSTRUCTION_FILES];
118035
118087
  for (const { directory, extension } of INSTRUCTION_DIRECTORIES) {
118036
- const dir = join7(root2, directory);
118037
- if (!existsSync6(dir)) continue;
118088
+ const dir = join8(root2, directory);
118089
+ if (!existsSync7(dir)) continue;
118038
118090
  try {
118039
118091
  for (const entry of readdirSync(dir).sort()) {
118040
118092
  if (entry.endsWith(extension)) paths3.push(`${directory}/${entry}`);
@@ -118045,8 +118097,8 @@ async function collectInstructions(root2) {
118045
118097
  const files = [];
118046
118098
  for (const relative6 of paths3) {
118047
118099
  if (!isInstructionPath(relative6)) continue;
118048
- const absolute = join7(root2, relative6);
118049
- if (!existsSync6(absolute)) continue;
118100
+ const absolute = join8(root2, relative6);
118101
+ if (!existsSync7(absolute)) continue;
118050
118102
  let size;
118051
118103
  let modifiedAt;
118052
118104
  try {
@@ -118095,7 +118147,7 @@ async function collectRepository(candidate, options, cachedForge) {
118095
118147
  function writeSecret(path7, value3) {
118096
118148
  writeFileSync5(path7, `${JSON.stringify(value3, null, 2)}
118097
118149
  `, { mode: 384 });
118098
- chmodSync4(path7, 384);
118150
+ chmodSync5(path7, 384);
118099
118151
  }
118100
118152
  function readJson(path7) {
118101
118153
  try {
@@ -118107,18 +118159,18 @@ function readJson(path7) {
118107
118159
  async function scanRepositories(options = {}, profile, output2 = new Output({ quiet: true })) {
118108
118160
  if (options.forgeTtl !== void 0 && !/^\d+$/.test(options.forgeTtl)) throw new UsageError("--forge-ttl must be a number of seconds");
118109
118161
  const context = gatewayContext({ profile });
118110
- const directory = join7(context.root, "state/git");
118111
- mkdirSync4(directory, { recursive: true, mode: 448 });
118162
+ const directory = join8(context.root, "state/git");
118163
+ mkdirSync5(directory, { recursive: true, mode: 448 });
118112
118164
  const partial2 = Boolean(options.environment || options.path);
118113
118165
  const registered = partial2 ? [] : await registeredRepositoryPaths(context, (line4) => output2.detail(line4));
118114
118166
  const { candidates, home: home2 } = await findCandidates(options, context.env, registered);
118115
118167
  if (candidates.size > 0) {
118116
- 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}` : ""}`);
118117
118169
  }
118118
118170
  const forgeTtl = Number(options.forgeTtl ?? 300);
118119
118171
  const now = Math.floor(Date.now() / 1e3);
118120
118172
  const homeReal = home2 ? safeRealpath(home2) : null;
118121
- const previous = partial2 ? readJson(join7(directory, SCAN_INDEX_FILE)) : null;
118173
+ const previous = partial2 ? readJson(join8(directory, SCAN_INDEX_FILE)) : null;
118122
118174
  const entries = /* @__PURE__ */ new Map();
118123
118175
  const environments = {};
118124
118176
  if (previous && previous.version === SCAN_VERSION) {
@@ -118128,9 +118180,9 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118128
118180
  const repositories = [];
118129
118181
  for (const candidate of candidates.values()) {
118130
118182
  const key = repositoryKey(candidate.root);
118131
- const target = join7(directory, `${key}.json`);
118183
+ const target = join8(directory, `${key}.json`);
118132
118184
  let cachedForge;
118133
- if (options.withPrs && forgeTtl > 0 && existsSync6(target)) {
118185
+ if (options.withPrs && forgeTtl > 0 && existsSync7(target)) {
118134
118186
  const forge = readJson(target)?.["forge"];
118135
118187
  if (forge && now - Number(forge["collectedAt"] ?? 0) < forgeTtl) cachedForge = forge;
118136
118188
  }
@@ -118159,7 +118211,7 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118159
118211
  repositories: [...entries.values()].sort((a3, b) => a3.name.localeCompare(b.name)),
118160
118212
  environments
118161
118213
  };
118162
- writeSecret(join7(directory, SCAN_INDEX_FILE), index);
118214
+ writeSecret(join8(directory, SCAN_INDEX_FILE), index);
118163
118215
  return { index, repositories };
118164
118216
  }
118165
118217
  async function reposScan(options, command) {
@@ -118169,8 +118221,8 @@ async function reposScan(options, command) {
118169
118221
  else output2.progress(`scanned ${result.repositories.length} repositor${result.repositories.length === 1 ? "y" : "ies"}`);
118170
118222
  }
118171
118223
  function readScanIndex(root2) {
118172
- const path7 = join7(root2, "state/git", SCAN_INDEX_FILE);
118173
- if (!existsSync6(path7)) return null;
118224
+ const path7 = join8(root2, "state/git", SCAN_INDEX_FILE);
118225
+ if (!existsSync7(path7)) return null;
118174
118226
  const value3 = readJson(path7);
118175
118227
  if (value3 === null) throw new CliError(`${path7} is not readable JSON`, void 0, "run `portta repos scan` to rewrite it");
118176
118228
  return value3["version"] === SCAN_VERSION ? value3 : null;
@@ -118181,7 +118233,7 @@ async function reposStatus(command) {
118181
118233
  const output2 = new Output(globals2(command));
118182
118234
  const now = Math.floor(Date.now() / 1e3);
118183
118235
  const repositories = (index?.repositories ?? []).map((entry) => {
118184
- const scan = readJson(join7(context.root, "state/git", `${entry.key}.json`));
118236
+ const scan = readJson(join8(context.root, "state/git", `${entry.key}.json`));
118185
118237
  const gitInfo = scan?.["git"] ?? null;
118186
118238
  return {
118187
118239
  ...entry,
@@ -118205,12 +118257,12 @@ async function reposStatus(command) {
118205
118257
  }
118206
118258
  async function reposClear(command) {
118207
118259
  const context = gatewayContext({ profile: globals2(command).profile });
118208
- const directory = join7(context.root, "state/git");
118209
- if (!existsSync6(directory)) return;
118260
+ const directory = join8(context.root, "state/git");
118261
+ if (!existsSync7(directory)) return;
118210
118262
  let count2 = 0;
118211
118263
  for (const file2 of readdirSync(directory)) {
118212
118264
  if (file2.endsWith(".json")) {
118213
- unlinkSync4(join7(directory, file2));
118265
+ unlinkSync4(join8(directory, file2));
118214
118266
  count2++;
118215
118267
  }
118216
118268
  }
@@ -118228,9 +118280,11 @@ async function refreshRepositories(profile, output2) {
118228
118280
  init_src();
118229
118281
  init_src2();
118230
118282
  init_context();
118283
+ init_version();
118231
118284
  init_errors3();
118285
+ init_process();
118232
118286
  import { existsSync as existsSync21 } from "node:fs";
118233
- import { join as join43 } from "node:path";
118287
+ import { join as join44 } from "node:path";
118234
118288
 
118235
118289
  // src/metrics/collect.ts
118236
118290
  init_src();
@@ -118239,46 +118293,46 @@ import { loadavg } from "node:os";
118239
118293
 
118240
118294
  // src/metrics/store.ts
118241
118295
  init_src();
118242
- 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";
118243
118297
  import { dirname as dirname21 } from "node:path";
118244
118298
  import { randomUUID as randomUUID8 } from "node:crypto";
118245
118299
 
118246
118300
  // src/metrics/paths.ts
118247
- import { join as join38 } from "node:path";
118301
+ import { join as join39 } from "node:path";
118248
118302
  function metricsDir(root2) {
118249
- return join38(root2, "state/metrics");
118303
+ return join39(root2, "state/metrics");
118250
118304
  }
118251
118305
  function currentFile(root2) {
118252
- return join38(metricsDir(root2), "current.json");
118306
+ return join39(metricsDir(root2), "current.json");
118253
118307
  }
118254
118308
  function historyFile(root2) {
118255
- return join38(metricsDir(root2), "history.jsonl");
118309
+ return join39(metricsDir(root2), "history.jsonl");
118256
118310
  }
118257
118311
  function instanceFile(root2) {
118258
- return join38(metricsDir(root2), "instance.json");
118312
+ return join39(metricsDir(root2), "instance.json");
118259
118313
  }
118260
118314
  function pidFile(root2) {
118261
- return join38(metricsDir(root2), "collector.pid");
118315
+ return join39(metricsDir(root2), "collector.pid");
118262
118316
  }
118263
118317
  function logFile(root2) {
118264
- return join38(root2, "state/logs/host-metrics.log");
118318
+ return join39(root2, "state/logs/host-metrics.log");
118265
118319
  }
118266
118320
  function environmentReportFile(root2) {
118267
- return join38(root2, "state/environment/report.json");
118321
+ return join39(root2, "state/environment/report.json");
118268
118322
  }
118269
118323
 
118270
118324
  // src/metrics/store.ts
118271
118325
  var LOG_LIMIT_BYTES = 256 * 1024;
118272
118326
  function writeAtomic2(path7, text) {
118273
- mkdirSync12(dirname21(path7), { recursive: true });
118327
+ mkdirSync13(dirname21(path7), { recursive: true });
118274
118328
  const temporary = `${path7}.${process.pid}.tmp`;
118275
118329
  writeFileSync11(temporary, text, { mode: 384 });
118276
118330
  renameSync4(temporary, path7);
118277
- chmodSync7(path7, 384);
118331
+ chmodSync8(path7, 384);
118278
118332
  }
118279
118333
  function loadInstance(root2, hostname4) {
118280
118334
  const path7 = instanceFile(root2);
118281
- if (existsSync15(path7)) {
118335
+ if (existsSync16(path7)) {
118282
118336
  try {
118283
118337
  const parsed = JSON.parse(readFileSync17(path7, "utf8"));
118284
118338
  if (typeof parsed.id === "string" && parsed.id !== "") {
@@ -118308,14 +118362,14 @@ function writeCurrent(root2, snapshot) {
118308
118362
  }
118309
118363
  function appendHistory(root2, snapshot) {
118310
118364
  const path7 = historyFile(root2);
118311
- mkdirSync12(dirname21(path7), { recursive: true });
118312
- const existing = existsSync15(path7) ? readFileSync17(path7, "utf8") : "";
118365
+ mkdirSync13(dirname21(path7), { recursive: true });
118366
+ const existing = existsSync16(path7) ? readFileSync17(path7, "utf8") : "";
118313
118367
  const merged = mergeHistoryLines(existing, historyPointFrom(snapshot), snapshot.collectedAt);
118314
118368
  writeAtomic2(path7, merged);
118315
118369
  }
118316
118370
  function readCurrent(root2) {
118317
118371
  const path7 = currentFile(root2);
118318
- if (!existsSync15(path7)) return null;
118372
+ if (!existsSync16(path7)) return null;
118319
118373
  try {
118320
118374
  return JSON.parse(readFileSync17(path7, "utf8"));
118321
118375
  } catch {
@@ -118324,8 +118378,8 @@ function readCurrent(root2) {
118324
118378
  }
118325
118379
  function appendLog(root2, line4) {
118326
118380
  const path7 = logFile(root2);
118327
- mkdirSync12(dirname21(path7), { recursive: true });
118328
- 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) {
118329
118383
  renameSync4(path7, `${path7}.old`);
118330
118384
  }
118331
118385
  writeFileSync11(path7, `${(/* @__PURE__ */ new Date()).toISOString()} ${line4}
@@ -118428,17 +118482,18 @@ async function collectSnapshot(root2, now = Date.now()) {
118428
118482
 
118429
118483
  // src/metrics/lifecycle.ts
118430
118484
  init_src();
118431
- 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();
118432
118487
 
118433
118488
  // src/environment/index.ts
118434
118489
  init_src();
118435
118490
  import { homedir as homedir8 } from "node:os";
118436
118491
 
118437
118492
  // src/host.ts
118438
- init_src();
118439
- import { homedir as homedir7, loadavg as loadavg2, networkInterfaces, uptime } from "node:os";
118440
- import { accessSync as accessSync3, constants as constants7, existsSync as existsSync16, globSync, readFileSync as readFileSync18, statfsSync, statSync as statSync8 } from "node:fs";
118441
- 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";
118442
118497
  function isTailscaleRange(address) {
118443
118498
  const [a3, b] = address.split(".").map(Number);
118444
118499
  return a3 === 100 && b !== void 0 && b >= 64 && b <= 127;
@@ -118467,19 +118522,19 @@ async function locate(tool) {
118467
118522
  if (!onPath.failed && direct) return direct;
118468
118523
  const home2 = homedir7();
118469
118524
  for (const candidate of [
118470
- join39(home2, ".local/bin", tool),
118471
- join39(home2, ".bun/bin", tool),
118472
- join39(home2, ".cargo/bin", tool),
118473
- join39(home2, ".deno/bin", tool),
118474
- join39("/usr/local/bin", tool),
118475
- join39("/opt/homebrew/bin", tool),
118476
- 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)
118477
118532
  ]) {
118478
118533
  if (executable(candidate)) return candidate;
118479
118534
  }
118480
118535
  for (const pattern of [
118481
- join39(home2, ".nvm/versions/node/*/bin", tool),
118482
- 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)
118483
118538
  ]) {
118484
118539
  for (const match2 of globSync(pattern)) if (executable(match2)) return match2;
118485
118540
  }
@@ -118493,6 +118548,9 @@ function fileMode(path7) {
118493
118548
  }
118494
118549
  }
118495
118550
 
118551
+ // src/environment/index.ts
118552
+ init_process();
118553
+
118496
118554
  // src/environment/agents.ts
118497
118555
  init_src();
118498
118556
 
@@ -118695,7 +118753,7 @@ ${daemon.stdout}`);
118695
118753
  // src/environment/ssh.ts
118696
118754
  init_src();
118697
118755
  import { existsSync as existsSync17 } from "node:fs";
118698
- import { join as join40 } from "node:path";
118756
+ import { join as join41 } from "node:path";
118699
118757
  var SSH_ID = "tools.ssh";
118700
118758
  var TMUX_ID = "tools.tmux";
118701
118759
  var sshProbe = {
@@ -118711,7 +118769,7 @@ var sshProbe = {
118711
118769
  fix: "install an OpenSSH client for remote and repository workflows"
118712
118770
  })];
118713
118771
  }
118714
- const directory = join40(context.homeDir, ".ssh");
118772
+ const directory = join41(context.homeDir, ".ssh");
118715
118773
  const mode = context.fileMode(directory);
118716
118774
  const agent = context.environment["SSH_AUTH_SOCK"] ? await context.run("ssh-add", ["-l"], { reject: false, timeout: PROBE_TIMEOUT_MS2 }) : null;
118717
118775
  const details = [
@@ -118794,12 +118852,12 @@ function writeEnvironmentReport(root2, report) {
118794
118852
  // src/environment/security/index.ts
118795
118853
  init_src();
118796
118854
  import { platform as platform2 } from "node:os";
118797
- import { existsSync as existsSync19, readFileSync as readFileSync20 } from "node:fs";
118798
- 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";
118799
118857
 
118800
118858
  // src/environment/security/probes.ts
118801
118859
  init_src();
118802
- import { existsSync as existsSync18, readFileSync as readFileSync19 } from "node:fs";
118860
+ import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
118803
118861
  function emptySshd(state3, reason) {
118804
118862
  return { state: state3, reason, source: null, port: null, permitRootLogin: null, passwordAuthentication: null, pubkeyAuthentication: null, usePam: null };
118805
118863
  }
@@ -118817,7 +118875,7 @@ ${result.stdout}`);
118817
118875
  for (const path7 of ["/etc/ssh/sshd_config", "/private/etc/ssh/sshd_config"]) {
118818
118876
  if (!existsSync18(path7)) continue;
118819
118877
  try {
118820
- const parsed = parseSshdConfig(readFileSync19(path7, "utf8"), "file");
118878
+ const parsed = parseSshdConfig(readFileSync18(path7, "utf8"), "file");
118821
118879
  return parsed.state === "present" ? parsed : emptySshd("unknown", "the SSH configuration file could not be interpreted");
118822
118880
  } catch {
118823
118881
  return emptySshd("unknown", "could not be checked: this user cannot read the SSH configuration");
@@ -118868,7 +118926,7 @@ ${jail.stderr}`);
118868
118926
  // src/environment/security/index.ts
118869
118927
  function hostSecurityContext(root2, profileOverride) {
118870
118928
  const snapshot = readCurrent(root2);
118871
- 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();
118872
118930
  const environment = mergeEnvironment(file2, process.env);
118873
118931
  const profile = profileOverride ?? environment["PORTTA_PROFILE"] ?? "local";
118874
118932
  return {
@@ -118888,7 +118946,7 @@ async function collectHostSecurityFacts(context, securityContext) {
118888
118946
  }
118889
118947
  async function collectHostSecurityChecks(root2, probeContext = defaultProbeContext(), securityContext = hostSecurityContext(root2)) {
118890
118948
  const checks = securityVerdicts(await collectHostSecurityFacts(probeContext, securityContext), securityContext);
118891
- const sshDirectory = join41(root2, "state/ssh");
118949
+ const sshDirectory = join42(root2, "state/ssh");
118892
118950
  const mode = probeContext.fileMode(sshDirectory);
118893
118951
  checks.push({
118894
118952
  ...check2(
@@ -118916,9 +118974,9 @@ async function collectHostSecurityReport(root2, probeContext = defaultProbeConte
118916
118974
  }
118917
118975
 
118918
118976
  // src/environment/security/store.ts
118919
- import { join as join42 } from "node:path";
118977
+ import { join as join43 } from "node:path";
118920
118978
  function securityReportFile(root2) {
118921
- return join42(root2, "state/environment/security.json");
118979
+ return join43(root2, "state/environment/security.json");
118922
118980
  }
118923
118981
  function writeHostSecurityReport(root2, report) {
118924
118982
  const path7 = securityReportFile(root2);
@@ -118931,7 +118989,7 @@ function writeHostSecurityReport(root2, report) {
118931
118989
  function readCollectorPid(root2) {
118932
118990
  const path7 = pidFile(root2);
118933
118991
  if (!existsSync20(path7)) return null;
118934
- const parsed = Number(readFileSync21(path7, "utf8").trim());
118992
+ const parsed = Number(readFileSync20(path7, "utf8").trim());
118935
118993
  return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
118936
118994
  }
118937
118995
  function pidAlive(pid) {
@@ -118944,7 +119002,7 @@ function pidAlive(pid) {
118944
119002
  }
118945
119003
  function commandLine(pid) {
118946
119004
  try {
118947
- return readFileSync21(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
119005
+ return readFileSync20(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
118948
119006
  } catch {
118949
119007
  return "";
118950
119008
  }
@@ -119159,10 +119217,10 @@ function ensureHostToken(context) {
119159
119217
  return file2;
119160
119218
  }
119161
119219
  function hostDaemonEntry(directory = import.meta.dirname) {
119162
- return join43(directory, "host.js");
119220
+ return join44(directory, "host.js");
119163
119221
  }
119164
119222
  function hostDaemonLog(stateDir) {
119165
- return join43(stateDir, "daemon.log");
119223
+ return join44(stateDir, "daemon.log");
119166
119224
  }
119167
119225
  async function hostAnswers(listen) {
119168
119226
  const host2 = listen.host === "0.0.0.0" || listen.host === "::" ? "127.0.0.1" : listen.host;
@@ -119177,7 +119235,9 @@ async function hostServe(command) {
119177
119235
  const options = globals3(command);
119178
119236
  const context = gatewayContext({ profile: options.profile });
119179
119237
  const entry = hostDaemonEntry();
119180
- 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
+ }
119181
119241
  const stateDir = resolveHostStateDir(context.root, context.env);
119182
119242
  const listen = hostListen(context.env);
119183
119243
  const output2 = new Output(options);
@@ -119204,16 +119264,16 @@ function globals4(command) {
119204
119264
  return command.optsWithGlobals();
119205
119265
  }
119206
119266
  function setValues(root2, values) {
119207
- const path7 = join44(root2, ".env");
119267
+ const path7 = join45(root2, ".env");
119208
119268
  patchEnvFile(path7, values);
119209
119269
  }
119210
119270
  function syncForwardAuth(root2) {
119211
- const storePath = join44(root2, "state/auth/protections.json");
119271
+ const storePath = join45(root2, "state/auth/protections.json");
119212
119272
  const store = readProtectionStore(storePath);
119213
119273
  writeProtectionStore(storePath, store);
119214
- const dynamic = join44(root2, "config/traefik/dynamic");
119215
- mkdirSync13(dynamic, { recursive: true });
119216
- 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));
119217
119277
  }
119218
119278
  var PANEL_OVERRIDES = { PORTTA_WEB: "true" };
119219
119279
  async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
@@ -119221,7 +119281,7 @@ async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
119221
119281
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: { ...context.env, ...extraEnv }, stdio });
119222
119282
  }
119223
119283
  function prepareWebUp(options, command) {
119224
- prepareEnvFile(join44(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119284
+ prepareEnvFile(join45(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119225
119285
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: globals4(command).profile }));
119226
119286
  const initial = gatewayContext({ profile: globals4(command).profile });
119227
119287
  const expose = options.expose ?? initial.config.webExpose;
@@ -119273,16 +119333,7 @@ function prepareWebUp(options, command) {
119273
119333
  options.port ? String(Number(options.port)) : String(initial.config.webPort)
119274
119334
  );
119275
119335
  setValues(initial.root, values);
119276
- mkdirSync13(join44(initial.root, "state/git"), { recursive: true });
119277
- mkdirSync13(join44(initial.root, "state/github"), { recursive: true });
119278
- mkdirSync13(join44(initial.root, "state/metrics"), { recursive: true });
119279
- mkdirSync13(join44(initial.root, "state/environment"), { recursive: true });
119280
- mkdirSync13(join44(initial.root, "state/logs"), { recursive: true });
119281
- mkdirSync13(join44(initial.root, "state/auth"), { recursive: true, mode: 448 });
119282
- chmodSync8(join44(initial.root, "state/auth"), 448);
119283
- mkdirSync13(join44(initial.root, "state/ssh"), { recursive: true, mode: 448 });
119284
- chmodSync8(join44(initial.root, "state/ssh"), 448);
119285
- mkdirSync13(join44(initial.root, "config/traefik/dynamic"), { recursive: true });
119336
+ ensureInstallationDirectories(initial.root);
119286
119337
  syncForwardAuth(initial.root);
119287
119338
  const context = gatewayContext({ profile: globals4(command).profile, overrides: values });
119288
119339
  const output2 = new Output(globals4(command));
@@ -119298,7 +119349,7 @@ async function webUp(options, command) {
119298
119349
  ensureHostToken(context);
119299
119350
  output2.progress("pulling alpine/socat:1.8.1.3");
119300
119351
  await runProcess("docker", ["pull", "alpine/socat:1.8.1.3"], { reject: false, stdio: "stream" });
119301
- mkdirSync13(join44(context.root, "state", "panel"), { recursive: true });
119352
+ mkdirSync14(join45(context.root, "state", "panel"), { recursive: true });
119302
119353
  const services = ["portta-auth", "web", "web-socket-proxy"];
119303
119354
  const buildArgs = context.config.webDev || context.config.webBuild ? ["--build"] : [];
119304
119355
  output2.progress(buildArgs.length > 0 ? `starting ${services.join(", ")}, building the panel image` : `starting ${services.join(", ")}`);
@@ -119496,6 +119547,7 @@ async function webOpen(command) {
119496
119547
  // src/commands/clients.ts
119497
119548
  init_context();
119498
119549
  init_errors3();
119550
+ init_process();
119499
119551
  init_src();
119500
119552
  function globals5(command) {
119501
119553
  return command.optsWithGlobals();
@@ -119505,7 +119557,7 @@ async function ensureToolbox(command) {
119505
119557
  const image = porttaImages(context.version).toolbox;
119506
119558
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
119507
119559
  if (present.exitCode === 0) return image;
119508
- 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" });
119509
119561
  return image;
119510
119562
  }
119511
119563
  async function containerEnvironment(id) {
@@ -119636,7 +119688,7 @@ async function dbRestore(file2, command) {
119636
119688
  );
119637
119689
  }
119638
119690
  await confirm(`replace ${path7} with ${file2}? The current panel data is discarded.`, globals5(command).yes === true);
119639
- mkdirSync14(dirname22(path7), { recursive: true });
119691
+ mkdirSync15(dirname22(path7), { recursive: true });
119640
119692
  for (const candidate of databaseFiles(path7)) rmSync5(candidate, { force: true });
119641
119693
  copyFileSync2(file2, path7);
119642
119694
  new Output(globals5(command)).progress(`panel database restored from ${file2}`);
@@ -119644,12 +119696,14 @@ async function dbRestore(file2, command) {
119644
119696
 
119645
119697
  // src/commands/projects.ts
119646
119698
  init_src();
119699
+ var import_yaml2 = __toESM(require_dist(), 1);
119647
119700
  init_zod();
119648
- 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";
119649
119702
  import { createHash as createHash15 } from "node:crypto";
119650
- 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";
119651
119704
  init_context();
119652
119705
  init_errors3();
119706
+ init_process();
119653
119707
  function globals6(command) {
119654
119708
  return command.optsWithGlobals();
119655
119709
  }
@@ -119760,7 +119814,7 @@ function labelsOf(service2) {
119760
119814
  return Object.fromEntries(Object.entries(service2.labels ?? {}).map(([key, value3]) => [key, String(value3)]));
119761
119815
  }
119762
119816
  function composeCandidates(path7) {
119763
- 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);
119764
119818
  }
119765
119819
  async function hostContainers() {
119766
119820
  try {
@@ -119778,12 +119832,27 @@ function safeRealpath2(path7) {
119778
119832
  }
119779
119833
  function declaredComposeName(file2) {
119780
119834
  try {
119781
- const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync22(file2, "utf8"));
119835
+ const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync21(file2, "utf8"));
119782
119836
  return match2?.[1] ?? null;
119783
119837
  } catch {
119784
119838
  return null;
119785
119839
  }
119786
119840
  }
119841
+ function readProjectConfig(root2) {
119842
+ const path7 = join47(root2, PROJECT_CONFIG_PATH);
119843
+ if (!existsSync23(path7)) {
119844
+ return { source: "defaults", path: PROJECT_CONFIG_PATH, config: defaultProjectConfig(), issues: [] };
119845
+ }
119846
+ let document;
119847
+ try {
119848
+ document = (0, import_yaml2.parse)(readFileSync21(path7, "utf8"));
119849
+ } catch (error61) {
119850
+ const message = error61 instanceof Error ? error61.message : String(error61);
119851
+ return { source: "file", path: PROJECT_CONFIG_PATH, config: null, issues: [{ path: "", message }] };
119852
+ }
119853
+ const parsed = parseProjectConfig(document);
119854
+ return parsed.ok ? { source: "file", path: PROJECT_CONFIG_PATH, config: parsed.config, issues: [] } : { source: "file", path: PROJECT_CONFIG_PATH, config: null, issues: parsed.issues };
119855
+ }
119787
119856
  async function analyze(pathValue, options = {}, containers) {
119788
119857
  const base2 = resolve24(pathValue);
119789
119858
  let composeFile2;
@@ -119799,8 +119868,8 @@ async function analyze(pathValue, options = {}, containers) {
119799
119868
  let result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json"], { cwd: path7, reject: false });
119800
119869
  if (result.exitCode !== 0) result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json", "--no-interpolate"], { cwd: path7 });
119801
119870
  const model = ComposeSchema.parse(JSON.parse(result.stdout));
119802
- 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;
119803
- 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;
119804
119873
  const declaredName = declaredComposeName(composeFile2);
119805
119874
  const project2 = projectFromEnv || composeNamespace(declaredName ?? model.name ?? basename14(path7));
119806
119875
  const services = Object.entries(model.services).map(([name, service2]) => ({
@@ -119834,6 +119903,7 @@ async function analyze(pathValue, options = {}, containers) {
119834
119903
  path: path7,
119835
119904
  compose_file: basename14(composeFile2),
119836
119905
  gateway_overlay: overlay2,
119906
+ project_config: readProjectConfig(path7),
119837
119907
  project: { name: project2, source: projectFromEnv ? ".env" : declaredName ? "compose name:" : "directory name (implicit)" },
119838
119908
  domain: gatewayContext({ required: false }).config.domain,
119839
119909
  services,
@@ -119865,6 +119935,19 @@ async function analyzeCommand(path7, options, command) {
119865
119935
  output2.line(` project namespace ${report.project.name} (${report.project.source})`);
119866
119936
  const identities = [...new Set(report.services.flatMap((service2) => Object.entries(service2.labels).filter(([key]) => key.startsWith("portta.project") || key.startsWith("portta.repo") || key.startsWith("portta.git.root")).map(([key, value3]) => `${key}=${value3}`)))];
119867
119937
  output2.line(` declared identity ${identities.length ? identities.join(" ") : "none (inferred from the Compose labels)"}`);
119938
+ const declared = report.project_config;
119939
+ if (declared.issues.length) {
119940
+ output2.line(` project.yaml invalid, so its defaults are not applied:`);
119941
+ for (const issue2 of declared.issues) output2.line(` ${issue2.path ? `${issue2.path}: ` : ""}${issue2.message}`);
119942
+ } else if (declared.config) {
119943
+ const summary = [
119944
+ declared.config.name ? `name ${declared.config.name}` : null,
119945
+ declared.config.mainBranch ? `main branch ${declared.config.mainBranch}` : null,
119946
+ `worktrees ${declared.config.worktrees.root}`,
119947
+ `branches ${declared.config.worktrees.branchPattern}`
119948
+ ].filter((part) => part !== null);
119949
+ output2.line(` project.yaml ${declared.source === "file" ? summary.join(", ") : `absent, so defaults apply: ${summary.join(", ")}`}`);
119950
+ }
119868
119951
  output2.line("\nServices");
119869
119952
  for (const service2 of report.services) output2.line(` ${service2.name} ${service2.image ?? "<built>"} ${service2.kind} ${service2.published_ports.map((port) => `${port.host}:${port.container}`).join(",") || "-"}`);
119870
119953
  output2.line("\nFindings");
@@ -119963,7 +120046,7 @@ async function initCommand(pathValue, options, command) {
119963
120046
  }));
119964
120047
  const content = renderOverlay(report.project.name, overlayServices, context.config.network, options.project);
119965
120048
  const runtimeId = createHash15("sha256").update(safeRealpath2(report.path)).digest("hex").slice(0, 16);
119966
- 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");
119967
120050
  const output2 = new Output(globals6(command));
119968
120051
  if (options.dryRun) {
119969
120052
  output2.data(content);
@@ -119971,12 +120054,12 @@ async function initCommand(pathValue, options, command) {
119971
120054
  }
119972
120055
  if (existsSync23(destination) && !options.force) throw new RefusedError(`${destination} already exists`, "pass --force to replace it while keeping a backup");
119973
120056
  await confirm(`write ${destination}?`, globals6(command).yes === true);
119974
- mkdirSync15(dirname23(destination), { recursive: true, mode: 493 });
120057
+ mkdirSync16(dirname23(destination), { recursive: true, mode: 493 });
119975
120058
  if (existsSync23(destination)) renameSync5(destination, `${destination}.bak.${Date.now()}`);
119976
120059
  const temporary = `${destination}.${process.pid}.tmp`;
119977
120060
  writeFileSync12(temporary, content, { mode: 420 });
119978
120061
  try {
119979
- 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 });
119980
120063
  if (validated.exitCode !== 0) throw new RefusedError("generated runtime overlay is not valid Compose", validated.stderr.trim() || validated.stdout.trim());
119981
120064
  ComposeSchema.parse(JSON.parse(validated.stdout));
119982
120065
  renameSync5(temporary, destination);
@@ -120054,8 +120137,9 @@ init_zod();
120054
120137
  init_context();
120055
120138
  init_errors3();
120056
120139
  import { createHash as createHash16 } from "node:crypto";
120057
- import { existsSync as existsSync24, mkdirSync as mkdirSync16, readFileSync as readFileSync23, renameSync as renameSync6, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "node:fs";
120058
- 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();
120059
120143
  var Manifest = external_exports.object({
120060
120144
  schemaVersion: external_exports.literal(1),
120061
120145
  driver: external_exports.literal("compose").default("compose"),
@@ -120088,25 +120172,25 @@ function idFor(workspace2) {
120088
120172
  return createHash16("sha256").update(workspace2).digest("hex").slice(0, 16);
120089
120173
  }
120090
120174
  function digest(path7) {
120091
- return createHash16("sha256").update(readFileSync23(path7)).digest("hex");
120175
+ return createHash16("sha256").update(readFileSync22(path7)).digest("hex");
120092
120176
  }
120093
120177
  function digestIfPresent(path7) {
120094
120178
  return existsSync24(path7) ? digest(path7) : null;
120095
120179
  }
120096
120180
  function runtimeDirectory(root2, id) {
120097
- return join47(root2, "runtime", "compose", id);
120181
+ return join48(root2, "runtime", "compose", id);
120098
120182
  }
120099
120183
  function planPath(root2, id) {
120100
- return join47(runtimeDirectory(root2, id), "plan.json");
120184
+ return join48(runtimeDirectory(root2, id), "plan.json");
120101
120185
  }
120102
120186
  function manifestPath(root2, id) {
120103
- return join47(runtimeDirectory(root2, id), "runtime.json");
120187
+ return join48(runtimeDirectory(root2, id), "runtime.json");
120104
120188
  }
120105
120189
  function composeCandidates2(workspace2) {
120106
- 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);
120107
120191
  }
120108
120192
  function hasComposeRuntime(workspace2 = process.cwd()) {
120109
- return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join47(resolve25(workspace2), "VERSION"));
120193
+ return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join48(resolve25(workspace2), "VERSION"));
120110
120194
  }
120111
120195
  function networks(value3) {
120112
120196
  return Array.isArray(value3) ? value3 : Object.keys(value3 ?? {});
@@ -120165,22 +120249,22 @@ networks:
120165
120249
  `;
120166
120250
  }
120167
120251
  function manifestPaths(workspace2, root2, id) {
120168
- return { local: join47(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120252
+ return { local: join48(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120169
120253
  }
120170
120254
  function loadManifest(workspace2, root2, id) {
120171
120255
  const { local, stored } = manifestPaths(workspace2, root2, id);
120172
120256
  const file2 = existsSync24(local) ? local : existsSync24(stored) ? stored : null;
120173
- 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 });
120174
120258
  }
120175
120259
  function inputFiles(workspace2, manifest) {
120176
120260
  if (manifest.compose.files?.length) return manifest.compose.files.map((file2) => resolve25(workspace2, file2));
120177
- const envFile = join47(workspace2, ".env");
120178
- 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();
120179
120263
  const configured = process.env.COMPOSE_FILE ?? env.get("COMPOSE_FILE");
120180
120264
  if (configured) return configured.split(delimiter3).map((file2) => isAbsolute5(file2) ? file2 : resolve25(workspace2, file2));
120181
120265
  const base2 = composeCandidates2(workspace2)[0];
120182
120266
  if (!base2) throw new UsageError(`no Compose file found in ${workspace2}`);
120183
- 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);
120184
120268
  return override ? [base2, override] : [base2];
120185
120269
  }
120186
120270
  function versionAtLeast2(value3, minimum = [2, 24, 4]) {
@@ -120211,7 +120295,7 @@ async function stale(plan) {
120211
120295
  function readPlan(root2, workspace2) {
120212
120296
  const path7 = planPath(root2, idFor(workspace2));
120213
120297
  if (!existsSync24(path7)) throw new UsageError("no Runtime Plan exists for this workspace", "run `portta prepare` first");
120214
- return JSON.parse(readFileSync23(path7, "utf8"));
120298
+ return JSON.parse(readFileSync22(path7, "utf8"));
120215
120299
  }
120216
120300
  function manifestWithOptions(manifest, options) {
120217
120301
  return Manifest.parse({
@@ -120280,14 +120364,14 @@ async function prepareComposeRuntime(options, command) {
120280
120364
  const unsupported = findings.filter((finding2) => finding2.code === "network_mode");
120281
120365
  const outcome = unsupported.length ? "not_supported" : manifest.compose.mode === "manual" ? "manual" : pending.length ? "not_supported" : "isolated";
120282
120366
  const directory = runtimeDirectory(context.root, id);
120283
- const generatedOverlay = join47(directory, "compose.portta.yaml");
120367
+ const generatedOverlay = join48(directory, "compose.portta.yaml");
120284
120368
  const manifests = manifestPaths(workspace2, context.root, id);
120285
- const envFile = join47(workspace2, ".env");
120369
+ const envFile = join48(workspace2, ".env");
120286
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 };
120287
120371
  const content = manifest.compose.mode === "manual" ? "# Manual Compose integration; Portta adds no runtime mutations.\nservices: {}\n" : overlay(plan, context.config.network);
120288
120372
  if (!options.dryRun) {
120289
120373
  if (outcome === "not_supported") throw new RefusedError("environment is not ready for isolated Compose runtime", [...unsupported, ...pending].map((finding2) => finding2.detail).join("; "));
120290
- mkdirSync16(directory, { recursive: true, mode: 448 });
120374
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120291
120375
  const temporary = `${generatedOverlay}.${process.pid}.tmp`;
120292
120376
  writeFileSync13(temporary, content, { mode: 384 });
120293
120377
  const final = await runProcess("docker", [...composeArgs(plan, temporary), "config", "--format", "json"], { cwd: workspace2, reject: false });
@@ -120327,7 +120411,7 @@ async function initComposeRuntime(options, command) {
120327
120411
  const files = inputFiles(workspace2, Manifest.parse({ schemaVersion: 1 }));
120328
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 } };
120329
120413
  const directory = runtimeDirectory(context.root, id);
120330
- mkdirSync16(directory, { recursive: true, mode: 448 });
120414
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120331
120415
  writeFileSync13(manifestPath(context.root, id), `${JSON.stringify(manifest, null, 2)}
120332
120416
  `, { mode: 384 });
120333
120417
  return prepareComposeRuntime({ path: workspace2, project: options.project }, command);
@@ -120358,23 +120442,25 @@ async function runtimeAction(action, options, command) {
120358
120442
  init_src();
120359
120443
  init_src();
120360
120444
  init_context();
120361
- import { chmodSync as chmodSync9, existsSync as existsSync38, mkdirSync as mkdirSync18, readFileSync as readFileSync30, readdirSync as readdirSync8, rmSync as rmSync10 } from "node:fs";
120362
- 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";
120363
120447
  init_errors3();
120448
+ init_process();
120364
120449
  init_version();
120365
120450
 
120366
120451
  // src/doctor.ts
120367
120452
  init_src();
120368
120453
  init_context();
120369
120454
  import { existsSync as existsSync33 } from "node:fs";
120370
- import { join as join53 } from "node:path";
120455
+ import { join as join54 } from "node:path";
120456
+ init_process();
120371
120457
 
120372
120458
  // src/modules/index.ts
120373
120459
  init_src();
120374
120460
  init_modules();
120375
120461
  init_context();
120376
- import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
120377
- 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";
120378
120464
 
120379
120465
  // src/modules/taskflow.ts
120380
120466
  init_modules();
@@ -120390,8 +120476,7 @@ var WORKFLOW_ENGINE_ACTIONS = [
120390
120476
  ["validate", "Validate a workflow file or registered workflow"],
120391
120477
  ["save", "Save a workflow file into the registry"],
120392
120478
  ["doctor", "Check the standalone workflow engine"],
120393
- ["guide", "Print the workflow authoring guide"],
120394
- ["install-skill", "Retired \u2014 install with: npx skills add codions-labs/portta --skill portta-workflows -g"]
120479
+ ["guide", "Print the workflow authoring guide"]
120395
120480
  ];
120396
120481
  var USAGE_HINT = "(run with --help for usage)";
120397
120482
  function parsePort2(value3) {
@@ -120407,7 +120492,7 @@ function helpAfter(command, text) {
120407
120492
  ${text(commandInvocation(context.command))}`);
120408
120493
  }
120409
120494
  function runOptions(command) {
120410
- return command.addOption(new Option("--input <text>", "Run input text").conflicts("inputJson")).option("--input-json <json>", "Run input as a JSON object").option("--profile <name>", `Profile from ${PROJECT_CONFIG_PATH}`).addOption(
120495
+ return command.addOption(new Option("--input <text>", "Run input text").conflicts("inputJson")).option("--input-json <json>", "Run input as a JSON object").option("--profile <name>", `Profile from ${PROJECT_CONFIG_PATH2}`).addOption(
120411
120496
  new Option("--workspace <strategy>", "Execution workspace (default: workflow policy or worktree)").choices([
120412
120497
  "worktree",
120413
120498
  "branch",
@@ -120477,12 +120562,12 @@ ${environment.map(([name = "", text]) => ` ${name.padEnd(width)} ${text}`).joi
120477
120562
  Analysis: --analyze=auto uses the default agent only when runtime detection falls back to host.
120478
120563
  --analyze=claude | --analyze=codex always run that agent.`
120479
120564
  );
120480
- leaf(flow, "add [branch]", "Create a worktree using the dashboard lifecycle").option("--existing", "Use an existing local or remote branch instead of creating a new one").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH}`).option("--agent <id>", "Agent id to launch (repeatable)", collect).option("--prompt <text>", "Initial agent prompt").option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--interface <mode>", "Session UI: terminal or web-chat").option("-d, --detach", "Create worktree without switching to it").option(
120565
+ leaf(flow, "add [branch]", "Create a worktree using the dashboard lifecycle").option("--existing", "Use an existing local or remote branch instead of creating a new one").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH2}`).option("--agent <id>", "Agent id to launch (repeatable)", collect).option("--prompt <text>", "Initial agent prompt").option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--interface <mode>", "Session UI: terminal or web-chat").option("-d, --detach", "Create worktree without switching to it").option(
120481
120566
  "--from-linear <issue-id>",
120482
120567
  `Bootstrap from a Linear issue, plus any saved ${APP_NAME} session or linked PR`
120483
120568
  ).option("--branch <name>", "Override the branch when --from-linear resolves to one");
120484
120569
  helpAfter(
120485
- leaf(flow, "oneshot [branch]", "Run a worktree start-to-finish, streaming logs to stdout").option("--resume <branch>", "Resume an existing local worktree instead of creating one").option("--prompt <text>", "Initial agent prompt (required; follow-up nudge when --resume)").option("--agent <id>", "Agent id to launch").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH}`).option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--keep-open", "Don't auto-close the worktree session when the agent finishes").option(
120570
+ leaf(flow, "oneshot [branch]", "Run a worktree start-to-finish, streaming logs to stdout").option("--resume <branch>", "Resume an existing local worktree instead of creating one").option("--prompt <text>", "Initial agent prompt (required; follow-up nudge when --resume)").option("--agent <id>", "Agent id to launch").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH2}`).option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--keep-open", "Don't auto-close the worktree session when the agent finishes").option(
120486
120571
  "--linear <id|team>",
120487
120572
  "Tie this oneshot to Linear: ENG-123 loads the issue and posts back; ENG creates an issue when done"
120488
120573
  ).option("--branch <name>", "Override the branch when --linear resolves to one"),
@@ -120515,7 +120600,7 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
120515
120600
  "--profile <name>",
120516
120601
  "Profile name (alternative to positional arg)"
120517
120602
  ),
120518
- () => `Switches the worktree to another profile from ${PROJECT_CONFIG_PATH}. An open
120603
+ () => `Switches the worktree to another profile from ${PROJECT_CONFIG_PATH2}. An open
120519
120604
  worktree is restarted with the new pane layout and commands; a closed
120520
120605
  one picks the new profile up on its next open.`
120521
120606
  );
@@ -120827,10 +120912,10 @@ var taskflowCliModule = {
120827
120912
  // src/modules/index.ts
120828
120913
  var CLI_MODULES = [taskflowCliModule];
120829
120914
  function moduleEnvironment(root2 = findGatewayRoot()) {
120830
- const file2 = root2 ? join52(root2, ".env") : null;
120915
+ const file2 = root2 ? join53(root2, ".env") : null;
120831
120916
  if (!file2 || !existsSync32(file2)) return { ...process.env };
120832
120917
  try {
120833
- return mergeEnvironment(parseEnv(readFileSync28(file2, "utf8")), process.env);
120918
+ return mergeEnvironment(parseEnv(readFileSync27(file2, "utf8")), process.env);
120834
120919
  } catch {
120835
120920
  return { ...process.env };
120836
120921
  }
@@ -120884,7 +120969,7 @@ async function runDoctor(context) {
120884
120969
  const env = context.env;
120885
120970
  const config3 = context.config;
120886
120971
  const root2 = context.root;
120887
- const stateDir = env["PORTTA_STATE_DIR"] || join53(root2, "state");
120972
+ const stateDir = env["PORTTA_STATE_DIR"] || join54(root2, "state");
120888
120973
  const add = (...entries) => {
120889
120974
  for (const entry of entries) if (entry) checks.push(entry);
120890
120975
  };
@@ -120896,7 +120981,7 @@ async function runDoctor(context) {
120896
120981
  `unknown profile '${env["PORTTA_PROFILE"]}'`,
120897
120982
  "set PORTTA_PROFILE to one of: local remote-private remote-public"
120898
120983
  ));
120899
- const envPath = join53(root2, ".env");
120984
+ const envPath = join54(root2, ".env");
120900
120985
  if (existsSync33(envPath)) {
120901
120986
  add(check2("config.env", "pass", ".env", "present"));
120902
120987
  add(envPermissionVerdict(fileMode(envPath)));
@@ -121038,10 +121123,10 @@ async function runDoctor(context) {
121038
121123
  `portta up ${config3.profile}`
121039
121124
  ));
121040
121125
  }
121041
- 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"));
121042
121127
  }
121043
121128
  const hasKey = Boolean(env["TS_AUTHKEY"]);
121044
- add(!hasKey && !existsSync33(join53(stateDir, "tailscale/tailscaled.state")) ? check2(
121129
+ add(!hasKey && !existsSync33(join54(stateDir, "tailscale/tailscaled.state")) ? check2(
121045
121130
  "tailscale.authkey",
121046
121131
  "fail",
121047
121132
  "tailscale auth",
@@ -121071,7 +121156,7 @@ async function runDoctor(context) {
121071
121156
  "portta bootstrap (generates it without printing it)"
121072
121157
  ));
121073
121158
  const auth2 = gatewayContainer(containers, "auth");
121074
- const authStore = join53(root2, "state/auth/protections.json");
121159
+ const authStore = join54(root2, "state/auth/protections.json");
121075
121160
  add(authStoreVerdict(existsSync33(authStore), fileMode(authStore), Boolean(auth2)));
121076
121161
  add(componentVerdict("auth.service", "authentication service", Boolean(auth2), auth2?.state ?? null, auth2?.health ?? null, "portta logs portta-auth"));
121077
121162
  const gh = await locate("gh");
@@ -121221,7 +121306,7 @@ async function runDoctor(context) {
121221
121306
  "set CF_DNS_API_TOKEN, or use ACME_CHALLENGE=http for per-hostname certificates"
121222
121307
  ));
121223
121308
  }
121224
- const store = join53(stateDir, "traefik/acme/acme.json");
121309
+ const store = join54(stateDir, "traefik/acme/acme.json");
121225
121310
  if (existsSync33(store)) {
121226
121311
  const mode = fileMode(store);
121227
121312
  add(mode === "600" ? check2("tls.acme.perms", "pass", "ACME store permissions", mode) : check2(
@@ -121423,8 +121508,9 @@ async function resolveIpv4(hostname4) {
121423
121508
 
121424
121509
  // src/commands/apply.ts
121425
121510
  init_src();
121511
+ init_process();
121426
121512
  import { existsSync as existsSync34 } from "node:fs";
121427
- import { join as join54 } from "node:path";
121513
+ import { join as join55 } from "node:path";
121428
121514
  async function label(name) {
121429
121515
  const result = await runProcess(
121430
121516
  "docker",
@@ -121463,9 +121549,9 @@ async function ensureApplier(context) {
121463
121549
  if (await label("portta.apply.spec") === spec) return { action: "kept" };
121464
121550
  if (!await removeApplier()) return { action: "failed", reason: "the running applier could not be replaced" };
121465
121551
  }
121466
- const context_dir = join54(context.root, "docker", "images", "apply");
121552
+ const context_dir = join55(context.root, "docker", "images", "apply");
121467
121553
  const image = porttaImages(context.version).apply;
121468
- if (!existsSync34(join54(context_dir, "Dockerfile"))) {
121554
+ if (!existsSync34(join55(context_dir, "Dockerfile"))) {
121469
121555
  return { action: "failed", reason: `no applier image source at ${context_dir}` };
121470
121556
  }
121471
121557
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121479,8 +121565,9 @@ async function ensureApplier(context) {
121479
121565
 
121480
121566
  // src/commands/runner.ts
121481
121567
  init_src();
121568
+ init_process();
121482
121569
  import { existsSync as existsSync35 } from "node:fs";
121483
- import { join as join55 } from "node:path";
121570
+ import { join as join56 } from "node:path";
121484
121571
  async function label2(name) {
121485
121572
  const result = await runProcess(
121486
121573
  "docker",
@@ -121519,9 +121606,9 @@ async function ensureRunner(context) {
121519
121606
  if (await label2("portta.runner.spec") === spec) return { action: "kept" };
121520
121607
  if (!await removeRunner()) return { action: "failed", reason: "the running runner could not be replaced" };
121521
121608
  }
121522
- const context_dir = join55(context.root, "docker", "images", "apply");
121609
+ const context_dir = join56(context.root, "docker", "images", "apply");
121523
121610
  const image = porttaImages(context.version).apply;
121524
- if (!existsSync35(join55(context_dir, "Dockerfile"))) {
121611
+ if (!existsSync35(join56(context_dir, "Dockerfile"))) {
121525
121612
  return { action: "failed", reason: `no runner image source at ${context_dir}` };
121526
121613
  }
121527
121614
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121534,20 +121621,22 @@ async function ensureRunner(context) {
121534
121621
  }
121535
121622
 
121536
121623
  // src/checkout-cli.ts
121624
+ init_process();
121537
121625
  import { existsSync as existsSync36, readdirSync as readdirSync6, statSync as statSync11 } from "node:fs";
121538
- import { join as join56 } from "node:path";
121626
+ import { join as join57 } from "node:path";
121539
121627
  var CHECKOUT_CLI_SOURCES = [
121540
121628
  "packages/cli/src",
121541
121629
  "packages/cli/scripts",
121542
121630
  "packages/cli/package.json",
121543
121631
  "packages/core/src",
121544
- "packages/contracts/src"
121632
+ "packages/contracts/src",
121633
+ "packages/host/src"
121545
121634
  ];
121546
121635
  function checkoutCliDist(root2) {
121547
- return join56(root2, "packages/cli/dist/cli.js");
121636
+ return join57(root2, "packages/cli/dist/cli.js");
121548
121637
  }
121549
121638
  function isCheckout(root2) {
121550
- 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"));
121551
121640
  }
121552
121641
  function newestSourceMtime(path7) {
121553
121642
  if (!existsSync36(path7)) return 0;
@@ -121555,7 +121644,7 @@ function newestSourceMtime(path7) {
121555
121644
  if (info.isFile()) return /\.(ts|mjs|json)$/.test(path7) ? info.mtimeMs : 0;
121556
121645
  let newest = 0;
121557
121646
  for (const entry of readdirSync6(path7, { withFileTypes: true })) {
121558
- newest = Math.max(newest, newestSourceMtime(join56(path7, entry.name)));
121647
+ newest = Math.max(newest, newestSourceMtime(join57(path7, entry.name)));
121559
121648
  }
121560
121649
  return newest;
121561
121650
  }
@@ -121564,7 +121653,7 @@ function checkoutCliNeedsBuild(root2) {
121564
121653
  const dist = checkoutCliDist(root2);
121565
121654
  if (!existsSync36(dist)) return true;
121566
121655
  const distTime = statSync11(dist).mtimeMs;
121567
- return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join56(root2, tree)) > distTime);
121656
+ return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join57(root2, tree)) > distTime);
121568
121657
  }
121569
121658
  async function ensureCheckoutCli(root2, output2) {
121570
121659
  if (!checkoutCliNeedsBuild(root2)) return false;
@@ -121585,8 +121674,9 @@ async function reexecBuiltCli(root2) {
121585
121674
  init_src();
121586
121675
  init_context();
121587
121676
  init_errors3();
121588
- import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync29 } from "node:fs";
121589
- 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();
121590
121680
  var PORTTA_DIRECTORY = ".portta";
121591
121681
  var OVERLAY_FILE = "compose.portta.yaml";
121592
121682
  var COMPOSE_FILE = "compose.yaml";
@@ -121596,17 +121686,17 @@ var DEMO_DIRECTORY_PREFIX = "portta-demo-";
121596
121686
  var MANIFEST_FILE = "portta.example.json";
121597
121687
  function demoDirectories(home2) {
121598
121688
  if (!existsSync37(home2)) return [];
121599
- 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();
121600
121690
  }
121601
121691
  function findDemoStacks(home2) {
121602
121692
  return demoDirectories(home2).map((stackDir) => {
121603
- if (!existsSync37(join57(stackDir, COMPOSE_FILE))) return null;
121604
- const localOverlay = join57(PORTTA_DIRECTORY, OVERLAY_FILE);
121605
- 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));
121606
121696
  return {
121607
121697
  name: basename20(stackDir),
121608
121698
  dir: stackDir,
121609
- 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],
121610
121700
  overlay: overlay2
121611
121701
  };
121612
121702
  }).filter((stack) => stack !== null).sort((left, right) => left.name.localeCompare(right.name));
@@ -121617,10 +121707,10 @@ function demoComposeArgs(stack, action) {
121617
121707
  return ["compose", ...files, "down", "-v"];
121618
121708
  }
121619
121709
  function readDemoProject(stackDir) {
121620
- const path7 = join57(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121710
+ const path7 = join58(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121621
121711
  if (!existsSync37(path7)) return null;
121622
121712
  try {
121623
- const manifest = JSON.parse(readFileSync29(path7, "utf8"));
121713
+ const manifest = JSON.parse(readFileSync28(path7, "utf8"));
121624
121714
  const project2 = manifest.project;
121625
121715
  if (typeof project2?.["slug"] !== "string" || typeof project2["name"] !== "string") return null;
121626
121716
  const repositories = (Array.isArray(manifest.repositories) ? manifest.repositories : []).filter((repository) => typeof repository?.["name"] === "string" && typeof repository["relativePath"] === "string").map((repository) => ({
@@ -121785,7 +121875,7 @@ function checkoutLocalEnv() {
121785
121875
  };
121786
121876
  }
121787
121877
  function persistEnv(root2, values) {
121788
- const path7 = join58(root2, ".env");
121878
+ const path7 = join59(root2, ".env");
121789
121879
  patchEnvFile(path7, values);
121790
121880
  }
121791
121881
  function buildsLocally(command) {
@@ -121801,10 +121891,10 @@ async function compose2(command, args, stdio = "inherit", extra = {}) {
121801
121891
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: context.env, stdio, reject: extra.reject });
121802
121892
  }
121803
121893
  function ensureAuthState(root2) {
121804
- const authDirectory = join58(root2, "state/auth");
121805
- mkdirSync18(authDirectory, { recursive: true, mode: 448 });
121894
+ const authDirectory = join59(root2, "state/auth");
121895
+ mkdirSync19(authDirectory, { recursive: true, mode: 448 });
121806
121896
  chmodSync9(authDirectory, 448);
121807
- const path7 = join58(root2, ".env");
121897
+ const path7 = join59(root2, ".env");
121808
121898
  prepareEnvFile(path7);
121809
121899
  syncForwardAuth(root2);
121810
121900
  }
@@ -121856,7 +121946,7 @@ async function versionCommand(command) {
121856
121946
  output2.line(` panel ${panel.detail}`);
121857
121947
  if (!compatible) {
121858
121948
  output2.warning(`this CLI is ${cli} and the installation is ${gateway}`);
121859
- 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}`);
121860
121950
  }
121861
121951
  }
121862
121952
  async function bootstrapCommand(options, command) {
@@ -121867,9 +121957,8 @@ async function bootstrapCommand(options, command) {
121867
121957
  await requireDocker();
121868
121958
  const composeVersion = await runProcess("docker", ["compose", "version", "--short"], { reject: false });
121869
121959
  if (composeVersion.exitCode !== 0) throw new CliError("Docker Compose v2 is required", EXIT.precondition);
121870
- prepareEnvFile(join58(context.root, ".env"));
121871
- 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 });
121872
- chmodSync9(join58(context.root, "state/ssh"), 448);
121960
+ prepareEnvFile(join59(context.root, ".env"));
121961
+ ensureInstallationDirectories(context.root);
121873
121962
  ensureAuthState(context.root);
121874
121963
  const network2 = await ensureNetwork(context.config.network);
121875
121964
  output2.progress(`${network2.padEnd(8)} shared network ${context.config.network}`);
@@ -121878,7 +121967,7 @@ async function bootstrapCommand(options, command) {
121878
121967
  }
121879
121968
  async function upCommand(profile, options, command) {
121880
121969
  if (profile) command.setOptionValueWithSource("profile", profile, "cli");
121881
- prepareEnvFile(join58(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
121970
+ prepareEnvFile(join59(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
121882
121971
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: profile ?? globals8(command).profile }));
121883
121972
  const context = gatewayContext({ profile: profile ?? globals8(command).profile });
121884
121973
  if (options.localRelease) context.env["PORTTA_LOCAL_RELEASE"] = "true";
@@ -121942,7 +122031,7 @@ async function devCommand(profile, options, command) {
121942
122031
  return;
121943
122032
  }
121944
122033
  if (options.demo) requireDemoStacks(command);
121945
- const needsBootstrap = !existsSync38(join58(existing.root, ".env"));
122034
+ const needsBootstrap = !existsSync38(join59(existing.root, ".env"));
121946
122035
  output2.progress(`dev runs: ${[
121947
122036
  ...options.reset ? ["wipe Portta-managed containers and volumes"] : [],
121948
122037
  ...needsBootstrap ? ["prepare the checkout"] : [],
@@ -121980,10 +122069,10 @@ var REGENERABLE_STATE_DIRS = ["state/git", "state/metrics", "state/environment"]
121980
122069
  function clearRegenerableState(root2) {
121981
122070
  const cleared = [];
121982
122071
  for (const relative6 of REGENERABLE_STATE_DIRS) {
121983
- const directory = join58(root2, relative6);
122072
+ const directory = join59(root2, relative6);
121984
122073
  if (!existsSync38(directory)) continue;
121985
122074
  for (const entry of readdirSync8(directory, { withFileTypes: true })) {
121986
- rmSync10(join58(directory, entry.name), { recursive: true, force: true });
122075
+ rmSync10(join59(directory, entry.name), { recursive: true, force: true });
121987
122076
  }
121988
122077
  cleared.push(relative6);
121989
122078
  }
@@ -122062,7 +122151,7 @@ async function logsCommand(service2, options, command) {
122062
122151
  } else await compose2(command, ["logs", ...options.follow === false ? [] : ["--follow"], "--tail", options.tail ?? "200", ...service2 ? [service2] : []]);
122063
122152
  }
122064
122153
  async function updateCommand(command) {
122065
- prepareEnvFile(join58(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122154
+ prepareEnvFile(join59(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122066
122155
  await compose2(command, ["config", "--quiet"]);
122067
122156
  await compose2(command, ["pull", "--ignore-buildable"]);
122068
122157
  await confirm("recreate gateway components with the pulled images?", globals8(command).yes === true);
@@ -122124,7 +122213,7 @@ async function doctorCommand(command) {
122124
122213
  ...entry.fix ? { fix: entry.fix } : {}
122125
122214
  }));
122126
122215
  for (const file2 of context.composeFiles) {
122127
- 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` });
122128
122217
  }
122129
122218
  const aliases = readAliases(context.root);
122130
122219
  if (aliases.length > 0) {
@@ -122142,10 +122231,10 @@ async function doctorCommand(command) {
122142
122231
  if (failed.length) throw new CliError(`${failed.length} doctor check(s) failed`);
122143
122232
  }
122144
122233
  function readAliases(root2) {
122145
- const path7 = join58(root2, "config/traefik/dynamic/portta-aliases.yaml");
122234
+ const path7 = join59(root2, "config/traefik/dynamic/portta-aliases.yaml");
122146
122235
  if (!existsSync38(path7)) return [];
122147
122236
  try {
122148
- return parseAliases(readFileSync30(path7, "utf8"));
122237
+ return parseAliases(readFileSync29(path7, "utf8"));
122149
122238
  } catch {
122150
122239
  return [];
122151
122240
  }
@@ -122174,9 +122263,10 @@ async function urlsCommand(options, command) {
122174
122263
  // src/commands/network.ts
122175
122264
  init_src();
122176
122265
  import { lookup } from "node:dns/promises";
122177
- import { join as join59 } from "node:path";
122266
+ import { join as join60 } from "node:path";
122178
122267
  init_context();
122179
122268
  init_errors3();
122269
+ init_process();
122180
122270
  function globals9(command) {
122181
122271
  return command.optsWithGlobals();
122182
122272
  }
@@ -122212,7 +122302,7 @@ async function publicStatus(command) {
122212
122302
  }
122213
122303
  async function writeSetting(key, value3, command) {
122214
122304
  const context = gatewayContext({ profile: globals9(command).profile });
122215
- const path7 = join59(context.root, ".env");
122305
+ const path7 = join60(context.root, ".env");
122216
122306
  patchEnvFile(path7, { [key]: value3 });
122217
122307
  }
122218
122308
  async function publicEnable(command) {
@@ -122298,18 +122388,19 @@ async function dnsSetup(options, command) {
122298
122388
 
122299
122389
  // src/commands/host-service.ts
122300
122390
  init_config2();
122301
- 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";
122302
122392
  import { homedir as homedir9 } from "node:os";
122303
- import { dirname as dirname29, join as join60 } from "node:path";
122393
+ import { dirname as dirname29, join as join61 } from "node:path";
122304
122394
  init_context();
122305
122395
  init_errors3();
122396
+ init_process();
122306
122397
  var AUTO_PICKUP_ENV_VARS = ["LINEAR_API_KEY"];
122307
122398
  var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PATH", "PORTTA_ROOT"]);
122308
122399
  function logFile2() {
122309
- return join60(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122400
+ return join61(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122310
122401
  }
122311
122402
  function serviceFilePath(platform4, home2 = homedir9()) {
122312
- 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`);
122313
122404
  }
122314
122405
  function escapePlistText(value3) {
122315
122406
  return value3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -122379,7 +122470,7 @@ var LAUNCHD_ENV_ENTRY_RE = /<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g;
122379
122470
  function readEnvVarsFromUnit(filePath, platform4) {
122380
122471
  let text;
122381
122472
  try {
122382
- text = readFileSync31(filePath, "utf8");
122473
+ text = readFileSync30(filePath, "utf8");
122383
122474
  } catch {
122384
122475
  return {};
122385
122476
  }
@@ -122510,7 +122601,7 @@ async function hostService(action, command) {
122510
122601
  ${notes.join("\n")}`);
122511
122602
  await confirm(`${installed ? "Reinstall" : "Install"} the ${SERVICE_IDENTITY.name} service?`, Boolean(options.yes));
122512
122603
  if (installed) await runAll(serviceCommands("uninstall", platform4, filePath), output2, true);
122513
- mkdirSync19(dirname29(filePath), { recursive: true });
122604
+ mkdirSync20(dirname29(filePath), { recursive: true });
122514
122605
  writeFileSync14(filePath, content);
122515
122606
  if (Object.keys(envVars).length > 0) chmodSync10(filePath, 384);
122516
122607
  await runAll(serviceCommands("install", platform4, filePath), output2);
@@ -122551,7 +122642,8 @@ init_src();
122551
122642
  init_src();
122552
122643
  init_context();
122553
122644
  init_errors3();
122554
- import { join as join61 } from "node:path";
122645
+ import { join as join62 } from "node:path";
122646
+ init_process();
122555
122647
  function globals10(command) {
122556
122648
  return command.optsWithGlobals();
122557
122649
  }
@@ -122593,7 +122685,7 @@ function setting(name) {
122593
122685
  return found;
122594
122686
  }
122595
122687
  function write2(root2, values) {
122596
- const path7 = join61(root2, ".env");
122688
+ const path7 = join62(root2, ".env");
122597
122689
  patchEnvFile(path7, values);
122598
122690
  }
122599
122691
  async function configList(command) {
@@ -122803,18 +122895,19 @@ async function configSet(name, value3, options, command) {
122803
122895
  }
122804
122896
  function configPrepare(command) {
122805
122897
  const context = gatewayContext({ profile: globals10(command).profile });
122806
- prepareEnvFile(join61(context.root, ".env"));
122898
+ prepareEnvFile(join62(context.root, ".env"));
122807
122899
  new Output(globals10(command)).progress("configuration prepared from .env.example; existing values preserved");
122808
122900
  }
122809
122901
 
122810
122902
  // src/commands/setup.ts
122811
122903
  init_src();
122812
122904
  init_context();
122813
- 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";
122814
122906
  import { homedir as homedir10 } from "node:os";
122815
- 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";
122816
122908
  import { fileURLToPath as fileURLToPath8 } from "node:url";
122817
122909
  init_errors3();
122910
+ init_process();
122818
122911
  function globals11(command) {
122819
122912
  return command.optsWithGlobals();
122820
122913
  }
@@ -122828,14 +122921,14 @@ async function available(file2, args) {
122828
122921
  function packagedRuntime() {
122829
122922
  const explicit = process.env["PORTTA_RUNTIME_ROOT"];
122830
122923
  if (explicit) return resolve32(explicit);
122831
- const candidates = [join62(import.meta.dirname, "runtime"), join62(import.meta.dirname, "..", "runtime")];
122832
- const found = candidates.find((candidate) => existsSync40(join62(candidate, "VERSION")));
122833
- 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");
122834
122927
  return found;
122835
122928
  }
122836
122929
  function installRuntime(source, target) {
122837
- mkdirSync20(target, { recursive: true });
122838
- const cache2 = join62(target, "runtime");
122930
+ mkdirSync21(target, { recursive: true });
122931
+ const cache2 = join63(target, "runtime");
122839
122932
  const sameCache = existsSync40(cache2) && realpathSync8(source) === realpathSync8(cache2);
122840
122933
  if (!sameCache) {
122841
122934
  rmSync11(cache2, { recursive: true, force: true });
@@ -122843,32 +122936,32 @@ function installRuntime(source, target) {
122843
122936
  }
122844
122937
  for (const entry of readdirSync9(source)) {
122845
122938
  if (entry === "config") continue;
122846
- const destination = join62(target, entry);
122939
+ const destination = join63(target, entry);
122847
122940
  rmSync11(destination, { recursive: true, force: true });
122848
- cpSync(join62(source, entry), destination, { recursive: true, force: true });
122941
+ cpSync(join63(source, entry), destination, { recursive: true, force: true });
122849
122942
  }
122850
- const defaults = join62(source, "config", "traefik", "dynamic");
122851
- const dynamic = join62(target, "config", "traefik", "dynamic");
122852
- 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 });
122853
122946
  for (const entry of readdirSync9(defaults)) {
122854
- const destination = join62(dynamic, entry);
122855
- if (!existsSync40(destination)) copyFileSync4(join62(defaults, entry), destination);
122947
+ const destination = join63(dynamic, entry);
122948
+ if (!existsSync40(destination)) copyFileSync4(join63(defaults, entry), destination);
122856
122949
  }
122857
- const bin = join62(target, "bin");
122858
- mkdirSync20(bin, { recursive: true });
122950
+ const bin = join63(target, "bin");
122951
+ mkdirSync21(bin, { recursive: true });
122859
122952
  const executable2 = fileURLToPath8(import.meta.url);
122860
- const installed = join62(bin, "portta");
122953
+ const installed = join63(bin, "portta");
122861
122954
  if (resolve32(executable2) !== resolve32(installed)) copyFileSync4(executable2, installed);
122862
122955
  chmodSync11(installed, 493);
122863
- const docs2 = join62(import.meta.dirname, "documentation.json");
122864
- 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"));
122865
122958
  }
122866
122959
  async function setupCommand(options, command) {
122867
122960
  const global3 = globals11(command);
122868
122961
  const output2 = new Output(global3);
122869
122962
  if (process.platform === "win32") throw new PreconditionError("setup requires a POSIX host");
122870
122963
  const currentRoot = findGatewayRoot();
122871
- const target = resolve32(options.dir ?? currentRoot ?? join62(homedir10(), "portta"));
122964
+ const target = resolve32(options.dir ?? currentRoot ?? join63(homedir10(), "portta"));
122872
122965
  const profile = options.profile ?? global3.profile ?? "local";
122873
122966
  const runtime2 = packagedRuntime();
122874
122967
  const steps = [];
@@ -122877,8 +122970,9 @@ async function setupCommand(options, command) {
122877
122970
  if (!output2.json) output2.progress(`${status.padEnd(8)} ${detail2}`);
122878
122971
  };
122879
122972
  const nodeVersion = process.versions.node;
122880
- 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");
122881
122974
  record6("node", "ok", `Node ${nodeVersion}`);
122975
+ await requireDocker();
122882
122976
  const docker = await available("docker", ["version", "--format", "{{.Server.Version}}"]);
122883
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");
122884
122978
  const compose4 = await available("docker", ["compose", "version", "--short"]);
@@ -122886,25 +122980,24 @@ async function setupCommand(options, command) {
122886
122980
  record6("docker", "ok", `Docker ${docker.value}, Compose ${compose4.value}`);
122887
122981
  if (options.dryRun) {
122888
122982
  record6("runtime", "planned", `install packaged runtime in ${target}`);
122889
- record6("environment", "planned", `create .env only if absent in ${target}`);
122983
+ record6("environment", "planned", `prepare .env from .env.example in ${target}, keeping set values`);
122890
122984
  record6("network", "planned", "ensure the shared gateway network");
122891
122985
  record6("gateway", "planned", `pull pinned images and start profile ${profile}`);
122892
122986
  if (output2.json) output2.data({ dryRun: true, target, steps });
122893
122987
  return;
122894
122988
  }
122895
122989
  await confirm(`set up Portta in ${target}?`, global3.yes === true);
122896
- 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"))) {
122897
122991
  throw new RefusedError(`${target} exists and is not a Portta installation`, "choose an empty --dir; setup never overwrites an unrelated directory");
122898
122992
  }
122899
- mkdirSync20(dirname30(target), { recursive: true });
122900
- const updating = existsSync40(join62(target, "VERSION"));
122993
+ mkdirSync21(dirname30(target), { recursive: true });
122994
+ const updating = existsSync40(join63(target, "VERSION"));
122901
122995
  installRuntime(runtime2, target);
122902
122996
  record6("runtime", updating ? "updated" : "created", `${target}`);
122903
- const envFile = join62(target, ".env");
122997
+ const envFile = join63(target, ".env");
122904
122998
  prepareEnvFile(envFile);
122905
122999
  record6("environment", "updated", "environment prepared from .env.example");
122906
- 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 });
122907
- for (const directory of ["state/auth", "state/ssh", "state/runner", "state/cloudflared"]) chmodSync11(join62(target, directory), 448);
123000
+ ensureInstallationDirectories(target);
122908
123001
  record6("directories", "ok", "gateway state directories");
122909
123002
  const context = gatewayContext({ root: target, profile });
122910
123003
  const network2 = await ensureNetwork(context.config.network);
@@ -122919,13 +123012,21 @@ async function setupCommand(options, command) {
122919
123012
  const running = await runProcess("docker", ["compose", ...composeArguments(context), "ps", "--status", "running", "--quiet"], { cwd: target, env: context.env });
122920
123013
  if (!running.stdout.trim()) throw new PreconditionError("gateway started but no component remained running", `run portta doctor inside ${target}`);
122921
123014
  record6("doctor", "ok", "gateway components are running");
122922
- 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.");
122923
123024
  }
122924
123025
 
122925
123026
  // src/commands/auth.ts
122926
123027
  init_context();
122927
123028
  init_errors3();
122928
- import { readFileSync as readFileSync32 } from "node:fs";
123029
+ import { readFileSync as readFileSync31 } from "node:fs";
122929
123030
  function globals12(command) {
122930
123031
  return command.optsWithGlobals();
122931
123032
  }
@@ -122940,7 +123041,7 @@ function panelUrlFor2(command) {
122940
123041
  }
122941
123042
  async function authBootstrap(options, command) {
122942
123043
  if (!options.name || !options.email) throw new UsageError("--name and --email are required");
122943
- const password = options.passwordStdin ? readFileSync32(0, "utf8").trim() : "";
123044
+ const password = options.passwordStdin ? readFileSync31(0, "utf8").trim() : "";
122944
123045
  if (!password) throw new UsageError("the password is read from stdin", 'printf %s "$PASSWORD" | portta auth bootstrap --name \u2026 --email \u2026 --password-stdin');
122945
123046
  if (password.length < 10) throw new UsageError("the password must be at least 10 characters");
122946
123047
  const { client, output: output2 } = clientFor(command, { actor: void 0, actorKind: "human" });
@@ -122973,7 +123074,7 @@ async function authLogin(options, command) {
122973
123074
  }
122974
123075
  async function readSecret() {
122975
123076
  if (!process.stdin.isTTY) {
122976
- const piped = readFileSync32(0, "utf8").trim();
123077
+ const piped = readFileSync31(0, "utf8").trim();
122977
123078
  if (piped) return piped;
122978
123079
  throw new UsageError("no token on stdin", "pass --token, or run this in a terminal");
122979
123080
  }
@@ -123112,23 +123213,23 @@ init_src();
123112
123213
  init_context();
123113
123214
  init_errors3();
123114
123215
  import { randomBytes as randomBytes8 } from "node:crypto";
123115
- import { chmodSync as chmodSync12, mkdirSync as mkdirSync21, readFileSync as readFileSync33 } from "node:fs";
123116
- 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";
123117
123218
  function globals13(command) {
123118
123219
  return command.optsWithGlobals();
123119
123220
  }
123120
123221
  function paths(command) {
123121
123222
  const root2 = gatewayContext({ profile: globals13(command).profile }).root;
123122
123223
  return {
123123
- store: join63(root2, "state/auth/protections.json"),
123124
- 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")
123125
123226
  };
123126
123227
  }
123127
123228
  function save(command, store) {
123128
123229
  const target = paths(command);
123129
- mkdirSync21(dirname31(target.store), { recursive: true, mode: 448 });
123230
+ mkdirSync22(dirname31(target.store), { recursive: true, mode: 448 });
123130
123231
  chmodSync12(dirname31(target.store), 448);
123131
- mkdirSync21(dirname31(target.dynamic), { recursive: true });
123232
+ mkdirSync22(dirname31(target.dynamic), { recursive: true });
123132
123233
  writeProtectionStore(target.store, store);
123133
123234
  writeEnvFile(target.dynamic, renderAuthDynamic(store));
123134
123235
  }
@@ -123144,7 +123245,7 @@ async function protectHost(hostInput, options, command) {
123144
123245
  const entryPoint = options.entrypoint ?? (gatewayContext({ profile: globals13(command).profile }).config.tlsEnabled ? "websecure" : "web");
123145
123246
  if (!/^[A-Za-z0-9_-]+$/.test(entryPoint)) throw new UsageError(`invalid entrypoint: ${entryPoint}`);
123146
123247
  const generated = options.passwordStdin !== true;
123147
- 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();
123148
123249
  if (!password) throw new UsageError("no password on stdin");
123149
123250
  const target = paths(command);
123150
123251
  const existing = readProtectionStore(target.store);
@@ -123197,11 +123298,12 @@ async function protectStatus(hostInput, command) {
123197
123298
  init_src();
123198
123299
  init_errors3();
123199
123300
  init_context();
123200
- import { readFileSync as readFileSync34 } from "node:fs";
123301
+ import { readFileSync as readFileSync33 } from "node:fs";
123201
123302
  import { randomBytes as randomBytes9 } from "node:crypto";
123303
+ init_process();
123202
123304
  function passwordFrom(options) {
123203
123305
  if (options.passwordStdin) {
123204
- const password2 = readFileSync34(0, "utf8").trim();
123306
+ const password2 = readFileSync33(0, "utf8").trim();
123205
123307
  if (!password2) throw new UsageError("no password on stdin");
123206
123308
  if (password2.length < 10) throw new UsageError("the password must be at least 10 characters");
123207
123309
  return { password: password2, generated: false };
@@ -123329,13 +123431,13 @@ init_zod();
123329
123431
  init_context();
123330
123432
  init_errors3();
123331
123433
  import { existsSync as existsSync41 } from "node:fs";
123332
- import { join as join64 } from "node:path";
123434
+ import { join as join65 } from "node:path";
123333
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();
123334
123436
  function globals14(command) {
123335
123437
  return command.optsWithGlobals();
123336
123438
  }
123337
123439
  function path6(command) {
123338
- 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");
123339
123441
  }
123340
123442
  function root(command) {
123341
123443
  return gatewayContext({ profile: globals14(command).profile }).root;
@@ -123351,11 +123453,11 @@ function write3(command, shares) {
123351
123453
  }
123352
123454
  function removeScopes(command, scopes) {
123353
123455
  const gateway = root(command);
123354
- const storePath = join64(gateway, "state/auth/protections.json");
123456
+ const storePath = join65(gateway, "state/auth/protections.json");
123355
123457
  const store = readProtectionStore(storePath);
123356
123458
  const next = { ...store, protections: store.protections.filter((protection) => !scopes.has(protection.scope)) };
123357
123459
  writeProtectionStore(storePath, next);
123358
- writeEnvFile(join64(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123460
+ writeEnvFile(join65(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123359
123461
  }
123360
123462
  async function shareList(command) {
123361
123463
  const shares = read(command);
@@ -123386,14 +123488,16 @@ async function shareGc(command) {
123386
123488
  // src/commands/tls.ts
123387
123489
  init_src();
123388
123490
  init_context();
123389
- 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";
123390
123492
  import { platform as platform3 } from "node:os";
123391
- import { join as join65 } from "node:path";
123493
+ import { join as join66 } from "node:path";
123392
123494
  init_errors3();
123495
+ init_process();
123393
123496
 
123394
123497
  // src/toolbox.ts
123395
123498
  init_errors3();
123396
123499
  init_src();
123500
+ init_process();
123397
123501
  init_context();
123398
123502
  async function toolboxExists(image) {
123399
123503
  return !(await runProcess("docker", ["image", "inspect", image], { reject: false })).failed;
@@ -123423,14 +123527,14 @@ function globals15(command) {
123423
123527
  return command.optsWithGlobals();
123424
123528
  }
123425
123529
  function tlsPaths(root2) {
123426
- const directory = join65(root2, "config/tls");
123530
+ const directory = join66(root2, "config/tls");
123427
123531
  return {
123428
123532
  directory,
123429
- caKey: join65(directory, "portta-ca.key"),
123430
- caCertificate: join65(directory, "portta-ca.crt"),
123431
- leafKey: join65(directory, "wildcard.key"),
123432
- leafCertificate: join65(directory, "wildcard.crt"),
123433
- 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")
123434
123538
  };
123435
123539
  }
123436
123540
  function localTlsDynamic() {
@@ -123507,7 +123611,7 @@ async function tlsInit(command) {
123507
123611
  await requireDocker();
123508
123612
  const paths3 = tlsPaths(context.root);
123509
123613
  const domain2 = context.config.domain;
123510
- mkdirSync22(paths3.directory, { recursive: true });
123614
+ mkdirSync23(paths3.directory, { recursive: true });
123511
123615
  chmodSync13(paths3.directory, 448);
123512
123616
  if (existsSync42(paths3.caKey)) {
123513
123617
  output2.progress("reusing the existing local CA");
@@ -123538,7 +123642,7 @@ async function tlsInit(command) {
123538
123642
  }
123539
123643
  output2.progress(`issued ${paths3.leafCertificate} for *.${domain2}`);
123540
123644
  writeFileSync15(paths3.dynamic, localTlsDynamic());
123541
- const envPath = join65(context.root, ".env");
123645
+ const envPath = join66(context.root, ".env");
123542
123646
  patchEnvFile(envPath, { TLS_ENABLED: "true", TLS_MODE: "local" });
123543
123647
  output2.progress("TLS enabled in .env");
123544
123648
  output2.line("");
@@ -123587,22 +123691,23 @@ async function tlsUntrust(command) {
123587
123691
  output2.line(`To delete the key material as well: rm -rf ${paths2(context.root)}`);
123588
123692
  }
123589
123693
  function paths2(root2) {
123590
- return join65(root2, "config/tls");
123694
+ return join66(root2, "config/tls");
123591
123695
  }
123592
123696
 
123593
123697
  // src/commands/maintenance.ts
123594
123698
  init_src();
123595
123699
  init_context();
123596
123700
  init_errors3();
123597
- 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";
123598
123702
  import { hostname as hostname3, tmpdir as tmpdir5 } from "node:os";
123599
- import { dirname as dirname32, join as join66 } from "node:path";
123703
+ import { dirname as dirname32, join as join67 } from "node:path";
123704
+ init_process();
123600
123705
  function globals16(command) {
123601
123706
  return command.optsWithGlobals();
123602
123707
  }
123603
123708
  var BACKUP_VERSION = 1;
123604
123709
  function backupPaths(root2) {
123605
- return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join66(root2, path7)));
123710
+ return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join67(root2, path7)));
123606
123711
  }
123607
123712
  function renderManifest(manifest) {
123608
123713
  return `${JSON.stringify(manifest)}
@@ -123637,11 +123742,11 @@ async function backupCommand(options, command) {
123637
123742
  const output2 = new Output(global3);
123638
123743
  const context = gatewayContext({ profile: global3.profile });
123639
123744
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123640
- const target = options.output ?? join66(context.root, `portta-backup-${stamp}.tar.gz`);
123641
- 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-"));
123642
123747
  chmodSync14(staging, 448);
123643
123748
  try {
123644
- writeFileSync16(join66(staging, "portta-backup.json"), renderManifest({
123749
+ writeFileSync16(join67(staging, "portta-backup.json"), renderManifest({
123645
123750
  version: BACKUP_VERSION,
123646
123751
  portta: context.version,
123647
123752
  created: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z"),
@@ -123649,12 +123754,12 @@ async function backupCommand(options, command) {
123649
123754
  }));
123650
123755
  const paths3 = backupPaths(context.root);
123651
123756
  for (const path7 of paths3) {
123652
- mkdirSync23(join66(staging, "tree", dirname32(path7)), { recursive: true });
123653
- 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 });
123654
123759
  }
123655
123760
  let database = false;
123656
123761
  if (options.database !== false) {
123657
- database = await dumpDatabase(context, join66(staging, "panel.db"));
123762
+ database = await dumpDatabase(context, join67(staging, "panel.db"));
123658
123763
  if (!database) {
123659
123764
  output2.warning("the panel database was not included");
123660
123765
  output2.hint("it exists once the panel has started, and copying it needs sqlite3 on this host; --no-database silences this");
@@ -123699,14 +123804,14 @@ async function restoreCommand(archive, options, command) {
123699
123804
  const context = gatewayContext({ profile: global3.profile });
123700
123805
  if (!archive) throw new UsageError("which backup?", "portta restore <file>");
123701
123806
  if (!existsSync43(archive)) throw new UsageError(`no such file: ${archive}`);
123702
- const staging = mkdtempSync3(join66(tmpdir5(), "portta-restore-"));
123807
+ const staging = mkdtempSync3(join67(tmpdir5(), "portta-restore-"));
123703
123808
  chmodSync14(staging, 448);
123704
123809
  try {
123705
123810
  const extracted = await runProcess("tar", ["-xzf", archive, "-C", staging], { reject: false });
123706
123811
  if (extracted.failed) throw new UsageError("that file is not a Portta backup");
123707
- const manifestPath2 = join66(staging, "portta-backup.json");
123812
+ const manifestPath2 = join67(staging, "portta-backup.json");
123708
123813
  if (!existsSync43(manifestPath2)) throw new UsageError("that archive has no Portta manifest");
123709
- const manifest = parseManifest(readFileSync35(manifestPath2, "utf8"));
123814
+ const manifest = parseManifest(readFileSync34(manifestPath2, "utf8"));
123710
123815
  if (!manifest) throw new UsageError("that archive has an unreadable Portta manifest");
123711
123816
  output2.progress(`restoring a backup taken from Portta ${manifest.portta}`);
123712
123817
  if (!options.force && await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-traefik-1`)) {
@@ -123716,23 +123821,23 @@ async function restoreCommand(archive, options, command) {
123716
123821
  );
123717
123822
  }
123718
123823
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123719
- const safety = join66(context.root, "state", `restore-${stamp}`);
123720
- mkdirSync23(safety, { recursive: true });
123824
+ const safety = join67(context.root, "state", `restore-${stamp}`);
123825
+ mkdirSync24(safety, { recursive: true });
123721
123826
  for (const path7 of [".env", "config"]) {
123722
- if (existsSync43(join66(context.root, path7))) {
123723
- 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 });
123724
123829
  }
123725
123830
  }
123726
123831
  output2.progress(`kept what was there under ${safety}`);
123727
- const tree = join66(staging, "tree");
123832
+ const tree = join67(staging, "tree");
123728
123833
  if (existsSync43(tree)) {
123729
123834
  for (const path7 of backupPaths(tree)) {
123730
- 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 });
123731
123836
  }
123732
123837
  output2.progress("configuration and state restored");
123733
123838
  }
123734
- if (existsSync43(join66(context.root, ".env"))) chmodSync14(join66(context.root, ".env"), 384);
123735
- 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");
123736
123841
  if (existsSync43(dump)) {
123737
123842
  const panelUp = await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-web-1`);
123738
123843
  const target = databaseFileFor(context.root);
@@ -123740,7 +123845,7 @@ async function restoreCommand(archive, options, command) {
123740
123845
  output2.warning("the panel is running, so its database was not replaced");
123741
123846
  output2.hint(`portta web down then: portta restore ${archive} --force`);
123742
123847
  } else {
123743
- mkdirSync23(dirname32(target), { recursive: true });
123848
+ mkdirSync24(dirname32(target), { recursive: true });
123744
123849
  for (const file2 of databaseFiles(target)) rmSync12(file2, { force: true });
123745
123850
  copyFileSync5(dump, target);
123746
123851
  chmodSync14(target, 384);
@@ -123754,21 +123859,6 @@ async function restoreCommand(archive, options, command) {
123754
123859
  rmSync12(staging, { recursive: true, force: true });
123755
123860
  }
123756
123861
  }
123757
- var REPAIR_DIRECTORIES = [
123758
- { path: "config/traefik/dynamic", mode: 493 },
123759
- { path: "config/tls", mode: 493 },
123760
- { path: "state/traefik/acme", mode: 448 },
123761
- { path: "state/tailscale", mode: 493 },
123762
- { path: "state/access", mode: 493 },
123763
- { path: "state/git", mode: 493 },
123764
- { path: "state/github", mode: 493 },
123765
- { path: "state/ssh", mode: 448 },
123766
- { path: "state/metrics", mode: 493 },
123767
- { path: "state/environment", mode: 493 },
123768
- { path: "state/logs", mode: 493 },
123769
- { path: "state/runner", mode: 448 },
123770
- { path: "state/cloudflared", mode: 448 }
123771
- ];
123772
123862
  var REPAIR_MODES = [
123773
123863
  { path: ".env", mode: 384 },
123774
123864
  { path: "state/traefik/acme", mode: 448 },
@@ -123776,7 +123866,8 @@ var REPAIR_MODES = [
123776
123866
  { path: "state/cloudflared", mode: 448 },
123777
123867
  { path: "state/cloudflared/credentials.json", mode: 384 },
123778
123868
  { path: "state/runner", mode: 448 },
123779
- { path: "state/ssh", mode: 448 }
123869
+ { path: "state/ssh", mode: 448 },
123870
+ { path: "state/auth", mode: 448 }
123780
123871
  ];
123781
123872
  async function repairCommand2(options, command) {
123782
123873
  const global3 = globals16(command);
@@ -123785,20 +123876,20 @@ async function repairCommand2(options, command) {
123785
123876
  const dry = options.dryRun ?? false;
123786
123877
  const changes = [];
123787
123878
  output2.progress("Repair");
123788
- for (const { path: path7, mode } of REPAIR_DIRECTORIES) {
123789
- const full = join66(context.root, path7);
123879
+ for (const { path: path7, mode } of INSTALLATION_DIRECTORIES) {
123880
+ const full = join67(context.root, path7);
123790
123881
  if (existsSync43(full)) continue;
123791
123882
  changes.push(`create ${path7}`);
123792
123883
  if (dry) {
123793
123884
  output2.line(` would create ${path7}`);
123794
123885
  continue;
123795
123886
  }
123796
- mkdirSync23(full, { recursive: true });
123887
+ mkdirSync24(full, { recursive: true });
123797
123888
  chmodSync14(full, mode);
123798
123889
  output2.progress(`created ${path7}`);
123799
123890
  }
123800
123891
  for (const { path: path7, mode } of REPAIR_MODES) {
123801
- const full = join66(context.root, path7);
123892
+ const full = join67(context.root, path7);
123802
123893
  if (!existsSync43(full)) continue;
123803
123894
  const have = fileMode(full);
123804
123895
  const want = mode.toString(8);
@@ -128781,7 +128872,8 @@ async function activityCommand(options, command) {
128781
128872
  // src/commands/build.ts
128782
128873
  init_src();
128783
128874
  init_context();
128784
- import { join as join67 } from "node:path";
128875
+ import { join as join68 } from "node:path";
128876
+ init_process();
128785
128877
  function globals18(command) {
128786
128878
  return command.optsWithGlobals();
128787
128879
  }
@@ -128794,11 +128886,11 @@ function localReleaseBuilds(root2, version3) {
128794
128886
  },
128795
128887
  {
128796
128888
  image: images.apply,
128797
- 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")]
128798
128890
  },
128799
128891
  {
128800
128892
  image: images.toolbox,
128801
- 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")]
128802
128894
  }
128803
128895
  ];
128804
128896
  }
@@ -128818,12 +128910,13 @@ async function buildCommand(command) {
128818
128910
 
128819
128911
  // src/commands/remote.ts
128820
128912
  init_src();
128821
- import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync36, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
128822
- 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";
128823
128915
  import { createServer as createServer3 } from "node:net";
128824
128916
  import { randomBytes as randomBytes10 } from "node:crypto";
128825
128917
  init_context();
128826
128918
  init_errors3();
128919
+ init_process();
128827
128920
  function globals19(command) {
128828
128921
  return command.optsWithGlobals();
128829
128922
  }
@@ -128996,7 +129089,7 @@ async function remoteBootstrap(target, options, command) {
128996
129089
  output2.progress(" ./bin/portta network status confirm what is exposed");
128997
129090
  }
128998
129091
  function tunnelStateDir(root2) {
128999
- return join68(root2, "state/access/tunnels");
129092
+ return join69(root2, "state/access/tunnels");
129000
129093
  }
129001
129094
  function parseTunnelRecord(id, text) {
129002
129095
  try {
@@ -129027,9 +129120,9 @@ function readTunnels(root2) {
129027
129120
  if (!existsSync44(directory)) return [];
129028
129121
  const records = [];
129029
129122
  for (const name of readdirSync10(directory).filter((entry) => entry.endsWith(".json"))) {
129030
- const path7 = join68(directory, name);
129123
+ const path7 = join69(directory, name);
129031
129124
  try {
129032
- const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync36(path7, "utf8"));
129125
+ const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync35(path7, "utf8"));
129033
129126
  if (record6) records.push(record6);
129034
129127
  } catch {
129035
129128
  }
@@ -129081,7 +129174,7 @@ async function remoteAccessOpen(target, options, command) {
129081
129174
  const localPort = options.localPort ? Number(options.localPort) : await freeLocalPort();
129082
129175
  output2.progress("Opening the tunnel");
129083
129176
  const directoryPath = tunnelStateDir(context.root);
129084
- mkdirSync24(directoryPath, { recursive: true });
129177
+ mkdirSync25(directoryPath, { recursive: true });
129085
129178
  const id = randomBytes10(3).toString("hex");
129086
129179
  const pid = spawnDetached("ssh", sshArguments(target, context.env, [
129087
129180
  "-o",
@@ -129098,7 +129191,7 @@ async function remoteAccessOpen(target, options, command) {
129098
129191
  throw new PreconditionError("the SSH tunnel exited immediately", `check that ${target} is reachable and that ${localPort} is free locally`);
129099
129192
  }
129100
129193
  const record6 = { id, pid, target, project: options.project, service: options.service, remotePort, localPort, started: Math.floor(Date.now() / 1e3) };
129101
- writeFileSync17(join68(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129194
+ writeFileSync17(join69(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129102
129195
  if (output2.json) {
129103
129196
  output2.data({ ...record6, address: `127.0.0.1:${localPort}` });
129104
129197
  return;
@@ -129151,7 +129244,7 @@ async function remoteAccessClose(id, options, command) {
129151
129244
  } catch {
129152
129245
  }
129153
129246
  }
129154
- rmSync13(join68(directory, `${record6.id}.json`), { force: true });
129247
+ rmSync13(join69(directory, `${record6.id}.json`), { force: true });
129155
129248
  output2.progress(`the bridge on ${record6.target} is still open; close it there if you are done:`);
129156
129249
  output2.hint(`portta remote exec ${record6.target} -- 'cd portta && ./bin/portta access close --project ${record6.project}'`);
129157
129250
  }
@@ -129163,15 +129256,16 @@ init_src();
129163
129256
  init_src();
129164
129257
  init_context();
129165
129258
  init_errors3();
129166
- 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";
129167
129260
  import { ReadStream } from "node:tty";
129168
- import { join as join69 } from "node:path";
129261
+ import { join as join70 } from "node:path";
129262
+ init_process();
129169
129263
  function globals20(command) {
129170
129264
  return command.optsWithGlobals();
129171
129265
  }
129172
129266
  function tunnelPaths(root2) {
129173
- const directory = join69(root2, "state/cloudflared");
129174
- 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") };
129175
129269
  }
129176
129270
  function tunnelContainer(env) {
129177
129271
  return `${env["PORTTA_PROJECT_NAME"] || "portta"}-cloudflared-1`;
@@ -129306,13 +129400,13 @@ async function tunnelSetup(options, command) {
129306
129400
  let token;
129307
129401
  if (options.tokenFile) {
129308
129402
  if (!existsSync45(options.tokenFile)) throw new UsageError(`no such file: ${options.tokenFile}`);
129309
- token = readFileSync37(options.tokenFile, "utf8").replace(/\s+/g, "");
129403
+ token = readFileSync36(options.tokenFile, "utf8").replace(/\s+/g, "");
129310
129404
  } else {
129311
129405
  token = await promptForToken();
129312
129406
  }
129313
129407
  if (!token) throw new UsageError("no token was given");
129314
129408
  const paths3 = tunnelPaths(context.root);
129315
- mkdirSync25(paths3.directory, { recursive: true });
129409
+ mkdirSync26(paths3.directory, { recursive: true });
129316
129410
  chmodSync15(paths3.directory, 448);
129317
129411
  let credentials;
129318
129412
  try {
@@ -129328,7 +129422,7 @@ async function tunnelSetup(options, command) {
129328
129422
  const origin = options.origin || defaultOrigin(context);
129329
129423
  const config3 = { id: credentials.TunnelID, zone: options.zone, origin, credentialsFile: "/etc/cloudflared/credentials.json", includeApex: options.apex ?? false };
129330
129424
  writeFileSync18(paths3.config, renderTunnelConfig(config3));
129331
- const envPath = join69(context.root, ".env");
129425
+ const envPath = join70(context.root, ".env");
129332
129426
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ZONE: options.zone, CLOUDFLARE_TUNNEL_ID: credentials.TunnelID });
129333
129427
  if (output2.json) {
129334
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 } });
@@ -129357,7 +129451,7 @@ async function tunnelEnable(command) {
129357
129451
  if (!tunnelConfigured(context.root)) {
129358
129452
  throw new PreconditionError("the connector is not configured", "portta tunnel setup --zone <domain>");
129359
129453
  }
129360
- const envPath = join69(context.root, ".env");
129454
+ const envPath = join70(context.root, ".env");
129361
129455
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ENABLED: "true" });
129362
129456
  output2.progress("Cloudflare Tunnel enabled");
129363
129457
  output2.progress("starting the connector");
@@ -129380,7 +129474,7 @@ async function tunnelDisable(options, command) {
129380
129474
  ["compose", ...composeArguments(running), "rm", "-sf", "cloudflared"],
129381
129475
  { cwd: running.root, env: running.env, reject: false }
129382
129476
  );
129383
- const envPath = join69(running.root, ".env");
129477
+ const envPath = join70(running.root, ".env");
129384
129478
  const values = { CLOUDFLARE_TUNNEL_ENABLED: "false" };
129385
129479
  if (options.forget) {
129386
129480
  const paths3 = tunnelPaths(running.root);