@codions/portta 0.0.0-develop.169.sha-64ee68c → 0.0.0-develop.172.sha-10ce987

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 +960 -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 [];
@@ -22317,7 +22391,6 @@ var init_src = __esm({
22317
22391
  init_endpoints();
22318
22392
  init_env();
22319
22393
  init_hostname();
22320
- init_host();
22321
22394
  init_host_security();
22322
22395
  init_images();
22323
22396
  init_metrics();
@@ -22326,6 +22399,7 @@ var init_src = __esm({
22326
22399
  init_namespace();
22327
22400
  init_paths();
22328
22401
  init_password();
22402
+ init_project_config();
22329
22403
  init_project_order();
22330
22404
  init_projects_home();
22331
22405
  init_protections();
@@ -22393,7 +22467,7 @@ var init_package = __esm({
22393
22467
  "package.json"() {
22394
22468
  package_default = {
22395
22469
  name: "@codions/portta",
22396
- version: "0.0.0-develop.169.sha-64ee68c",
22470
+ version: "0.0.0-develop.172.sha-10ce987",
22397
22471
  description: "Machine-first CLI for a shared Docker development gateway",
22398
22472
  license: "MIT",
22399
22473
  type: "module",
@@ -22412,10 +22486,7 @@ var init_package = __esm({
22412
22486
  typecheck: "tsc -p tsconfig.json --noEmit",
22413
22487
  test: "vitest run",
22414
22488
  prepack: "npm run build",
22415
- prepublishOnly: "npm run typecheck && npm test",
22416
- preversion: "node scripts/git-version.mjs check",
22417
- version: "node scripts/git-version.mjs sync",
22418
- postversion: "node scripts/git-version.mjs verify"
22489
+ prepublishOnly: "npm run typecheck && npm test"
22419
22490
  },
22420
22491
  engines: {
22421
22492
  node: ">=24"
@@ -22467,7 +22538,7 @@ var init_version = __esm({
22467
22538
  "use strict";
22468
22539
  init_package();
22469
22540
  CLI_VERSION = package_default.version;
22470
- CLI_BUILD_DATE = true ? "2026-09-18T00:48:59Z" : void 0;
22541
+ CLI_BUILD_DATE = true ? "2026-09-18T02:24:34Z" : void 0;
22471
22542
  }
22472
22543
  });
22473
22544
 
@@ -22483,12 +22554,13 @@ function versionForRoot(root2) {
22483
22554
  if (existsSync4(generated)) return readFileSync4(generated, "utf8").trim();
22484
22555
  const manifest = join5(root2, "packages", "cli", "package.json");
22485
22556
  if (existsSync4(manifest)) return LOCAL_DEV_VERSION;
22486
- 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");
22487
22558
  }
22488
22559
  function wellKnownRoots() {
22489
22560
  const home2 = process.env["HOME"];
22490
22561
  return [
22491
22562
  process.env["PORTTA_HOME"],
22563
+ home2 ? join5(home2, "portta") : void 0,
22492
22564
  "/opt/portta",
22493
22565
  home2 ? join5(home2, ".portta") : void 0,
22494
22566
  "/var/lib/portta"
@@ -22528,7 +22600,7 @@ function gatewayContext(options = {}) {
22528
22600
  const config3 = loadGatewayConfig(env);
22529
22601
  env["PORTTA_DOMAIN"] = config3.domain;
22530
22602
  env["PORTTA_BIND_ADDRESS"] = config3.bindAddress;
22531
- const files = composeFilesForRoot(config3, root2);
22603
+ const files = composeFiles(config3);
22532
22604
  for (const fileName of files) {
22533
22605
  if (!existsSync4(join5(root2, fileName))) throw new PreconditionError(`missing compose file: ${fileName}`);
22534
22606
  }
@@ -34233,6 +34305,138 @@ var init_execa = __esm({
34233
34305
  }
34234
34306
  });
34235
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
+
34236
34440
  // ../../node_modules/hono/dist/compose.js
34237
34441
  var compose;
34238
34442
  var init_compose = __esm({
@@ -36704,7 +36908,7 @@ var init_user_shell_env = __esm({
36704
36908
  // ../host/src/modules/taskflow/lib/host-tools.ts
36705
36909
  import { spawnSync as spawnSync2 } from "node:child_process";
36706
36910
  import { accessSync as accessSync2, constants as constants5, statSync as statSync3 } from "node:fs";
36707
- 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";
36708
36912
  function defaultIsExecutableFile(candidate) {
36709
36913
  try {
36710
36914
  accessSync2(candidate, constants5.X_OK);
@@ -36718,20 +36922,20 @@ function firstExecutable(candidates, isExecutable) {
36718
36922
  }
36719
36923
  function pathCandidates(tool, pathEnv) {
36720
36924
  if (!pathEnv) return [];
36721
- return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join8(entry, tool));
36925
+ return pathEnv.split(delimiter2).filter(Boolean).map((entry) => join9(entry, tool));
36722
36926
  }
36723
36927
  function wellKnownBinDirectories(input2) {
36724
36928
  const directories = [];
36725
36929
  const home2 = input2.env.HOME?.trim();
36726
36930
  if (home2) {
36727
36931
  directories.push(
36728
- join8(home2, ".local", "bin"),
36729
- join8(home2, ".cargo", "bin"),
36730
- join8(home2, ".bun", "bin"),
36731
- join8(home2, ".volta", "bin"),
36732
- join8(home2, ".asdf", "shims"),
36733
- join8(home2, ".local", "share", "mise", "shims"),
36734
- 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")
36735
36939
  );
36736
36940
  }
36737
36941
  directories.push(dirname5(input2.execPath));
@@ -36742,7 +36946,7 @@ function wellKnownBinDirectories(input2) {
36742
36946
  }
36743
36947
  function wellKnownToolPaths(tool, env) {
36744
36948
  const home2 = env.HOME?.trim();
36745
- if (tool === "claude" && home2) return [join8(home2, ".claude", "local", "claude")];
36949
+ if (tool === "claude" && home2) return [join9(home2, ".claude", "local", "claude")];
36746
36950
  return [];
36747
36951
  }
36748
36952
  function loginWhichCommand(tool) {
@@ -36789,7 +36993,7 @@ function resolveNpmGlobalBin(input2) {
36789
36993
  env: input2.env,
36790
36994
  execPath: input2.execPath,
36791
36995
  platform: input2.platform
36792
- }).map((directory) => join8(directory, "npm")),
36996
+ }).map((directory) => join9(directory, "npm")),
36793
36997
  input2.isExecutable
36794
36998
  );
36795
36999
  if (!npm) return null;
@@ -36801,7 +37005,7 @@ function resolveNpmGlobalBin(input2) {
36801
37005
  });
36802
37006
  if (result.error || result.status !== 0) return null;
36803
37007
  const prefix = (result.stdout ?? "").trim().split(/\r?\n/u)[0]?.trim();
36804
- return prefix ? join8(prefix, "bin") : null;
37008
+ return prefix ? join9(prefix, "bin") : null;
36805
37009
  }
36806
37010
  function createHostToolResolver(options = {}) {
36807
37011
  const env = options.env ?? process.env;
@@ -36830,7 +37034,7 @@ function createHostToolResolver(options = {}) {
36830
37034
  npmGlobalBin = resolveNpmGlobalBin({ env, execPath: execPath2, isExecutable, platform: platform4 });
36831
37035
  }
36832
37036
  const wellKnown = wellKnownBinDirectories({ env, execPath: execPath2, npmGlobalBin, platform: platform4 }).map(
36833
- (directory) => join8(directory, name)
37037
+ (directory) => join9(directory, name)
36834
37038
  );
36835
37039
  const wellKnownHit = firstExecutable(wellKnown, isExecutable);
36836
37040
  if (wellKnownHit) return wellKnownHit;
@@ -36943,7 +37147,7 @@ function agentTemplatePlaceholder(variable) {
36943
37147
  function hostPortFromEnv(env) {
36944
37148
  return parseInt(env[ENV_NAMES.hostPort] || env.PORT || String(APP_DEFAULTS.port), 10);
36945
37149
  }
36946
- 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;
36947
37151
  var init_config2 = __esm({
36948
37152
  "../core/src/taskflow/config.ts"() {
36949
37153
  "use strict";
@@ -36972,7 +37176,7 @@ var init_config2 = __esm({
36972
37176
  archiveState: "archive.json",
36973
37177
  openSessionsState: "open-sessions.json"
36974
37178
  };
36975
- PROJECT_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
37179
+ PROJECT_CONFIG_PATH2 = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
36976
37180
  PROJECT_LOCAL_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectLocalConfig}`;
36977
37181
  APP_DEFAULTS = {
36978
37182
  port: 5111,
@@ -37020,7 +37224,6 @@ var init_config2 = __esm({
37020
37224
  tmuxBufferPrefix: `${APP_SLUG}-prompt`,
37021
37225
  dockerContainerPrefix: APP_SLUG,
37022
37226
  tempUploadDir: `${APP_SLUG}-uploads`,
37023
- dockerImage: "portta-sandbox",
37024
37227
  gitBaseConfigKey: `${APP_SLUG}.base`
37025
37228
  };
37026
37229
  SERVICE_IDENTITY = {
@@ -44388,48 +44591,48 @@ var init_main2 = __esm({
44388
44591
 
44389
44592
  // ../core/src/taskflow/paths.ts
44390
44593
  import { homedir as homedir2 } from "node:os";
44391
- import { join as join9 } from "node:path";
44594
+ import { join as join10 } from "node:path";
44392
44595
  function globalConfigDir(options = {}) {
44393
44596
  const env = options.env ?? process.env;
44394
44597
  const override = env[ENV_NAMES.home]?.trim();
44395
- return override || join9(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44598
+ return override || join10(options.home ?? env.HOME ?? homedir2(), GLOBAL_CONFIG_DIR);
44396
44599
  }
44397
44600
  function globalPaths(options = {}) {
44398
44601
  const home2 = globalConfigDir(options);
44399
44602
  const env = options.env ?? process.env;
44400
- 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);
44401
44604
  return {
44402
44605
  root: root2,
44403
- env: join9(home2, PATH_NAMES.env),
44404
- controlToken: join9(root2, PATH_NAMES.controlToken),
44405
- projectsRegistry: join9(root2, PATH_NAMES.projectsRegistry),
44406
- database: join9(root2, PATH_NAMES.database),
44407
- runs: join9(root2, PATH_NAMES.runs),
44408
- 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)
44409
44612
  };
44410
44613
  }
44411
44614
  function projectPaths(projectRoot2) {
44412
- const root2 = join9(projectRoot2, PROJECT_CONFIG_DIR);
44615
+ const root2 = join10(projectRoot2, PROJECT_CONFIG_DIR);
44413
44616
  return {
44414
44617
  root: root2,
44415
- config: join9(root2, PATH_NAMES.projectConfig),
44416
- localConfig: join9(root2, PATH_NAMES.projectLocalConfig),
44417
- configExample: join9(root2, PATH_NAMES.projectConfigExample),
44418
- workflows: join9(root2, PATH_NAMES.workflows),
44419
- 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)
44420
44623
  };
44421
44624
  }
44422
44625
  function gitRuntimePaths(gitDir) {
44423
- const root2 = join9(gitDir, PATH_NAMES.gitRuntime);
44626
+ const root2 = join10(gitDir, PATH_NAMES.gitRuntime);
44424
44627
  return {
44425
44628
  root: root2,
44426
- meta: join9(root2, PATH_NAMES.worktreeMeta),
44427
- runtimeEnv: join9(root2, PATH_NAMES.runtimeEnv),
44428
- controlEnv: join9(root2, PATH_NAMES.controlEnv),
44429
- pullRequests: join9(root2, PATH_NAMES.pullRequests),
44430
- archiveState: join9(root2, PATH_NAMES.archiveState),
44431
- openSessionsState: join9(root2, PATH_NAMES.openSessionsState),
44432
- 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)
44433
44636
  };
44434
44637
  }
44435
44638
  var init_paths2 = __esm({
@@ -44441,29 +44644,29 @@ var init_paths2 = __esm({
44441
44644
 
44442
44645
  // ../host/src/token.ts
44443
44646
  import { randomBytes as randomBytes6 } from "node:crypto";
44444
- import { chmodSync as chmodSync5, mkdirSync as mkdirSync5, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync6 } from "node:fs";
44445
- 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";
44446
44649
  function hostStateDir(root2) {
44447
- return join10(root2, HOST_STATE_DIR2);
44650
+ return join11(root2, HOST_STATE_DIR2);
44448
44651
  }
44449
44652
  function resolveHostStateDir(root2, env) {
44450
44653
  return env["PORTTA_HOST_STATE_DIR"]?.trim() || hostStateDir(root2);
44451
44654
  }
44452
44655
  function hostTokenFile(stateDir) {
44453
- return join10(stateDir, "token");
44656
+ return join11(stateDir, "token");
44454
44657
  }
44455
44658
  function newToken() {
44456
44659
  return randomBytes6(32).toString("base64url");
44457
44660
  }
44458
44661
  function readOrCreateToken(file2) {
44459
- mkdirSync5(dirname6(file2), { recursive: true, mode: 448 });
44662
+ mkdirSync6(dirname6(file2), { recursive: true, mode: 448 });
44460
44663
  try {
44461
44664
  writeFileSync6(file2, `${newToken()}
44462
44665
  `, { flag: "wx", mode: 384 });
44463
44666
  } catch (error61) {
44464
44667
  if (error61.code !== "EEXIST") throw error61;
44465
44668
  }
44466
- if ((statSync4(file2).mode & 63) !== 0) chmodSync5(file2, 384);
44669
+ if ((statSync4(file2).mode & 63) !== 0) chmodSync6(file2, 384);
44467
44670
  const token = readFileSync9(file2, "utf8").trim();
44468
44671
  if (token === "") throw new Error(`${file2} is empty; remove it and start the host daemon again`);
44469
44672
  return token;
@@ -44472,7 +44675,7 @@ var HOST_STATE_DIR2;
44472
44675
  var init_token = __esm({
44473
44676
  "../host/src/token.ts"() {
44474
44677
  "use strict";
44475
- HOST_STATE_DIR2 = join10("state", "host");
44678
+ HOST_STATE_DIR2 = join11("state", "host");
44476
44679
  }
44477
44680
  });
44478
44681
 
@@ -47734,7 +47937,7 @@ var require_Schema = __commonJS({
47734
47937
  var string4 = require_string();
47735
47938
  var tags = require_tags();
47736
47939
  var sortMapEntriesByKey = (a3, b) => a3.key < b.key ? -1 : a3.key > b.key ? 1 : 0;
47737
- var Schema = class _Schema {
47940
+ var Schema2 = class _Schema {
47738
47941
  constructor({ compat, customTags, merge: merge2, resolveKnownTags, schema, sortMapEntries, toStringDefaults }) {
47739
47942
  this.compat = Array.isArray(compat) ? tags.getTags(compat, "compat") : compat ? tags.getTags(null, compat) : null;
47740
47943
  this.name = typeof schema === "string" && schema || "core";
@@ -47752,7 +47955,7 @@ var require_Schema = __commonJS({
47752
47955
  return copy;
47753
47956
  }
47754
47957
  };
47755
- exports.Schema = Schema;
47958
+ exports.Schema = Schema2;
47756
47959
  }
47757
47960
  });
47758
47961
 
@@ -47845,7 +48048,7 @@ var require_Document = __commonJS({
47845
48048
  var identity3 = require_identity();
47846
48049
  var Pair = require_Pair();
47847
48050
  var toJS = require_toJS();
47848
- var Schema = require_Schema();
48051
+ var Schema2 = require_Schema();
47849
48052
  var stringifyDocument = require_stringifyDocument();
47850
48053
  var anchors = require_anchors();
47851
48054
  var applyReviver = require_applyReviver();
@@ -48096,7 +48299,7 @@ var require_Document = __commonJS({
48096
48299
  if (options.schema instanceof Object)
48097
48300
  this.schema = options.schema;
48098
48301
  else if (opt)
48099
- this.schema = new Schema.Schema(Object.assign(opt, options));
48302
+ this.schema = new Schema2.Schema(Object.assign(opt, options));
48100
48303
  else
48101
48304
  throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
48102
48305
  }
@@ -51760,7 +51963,7 @@ var require_dist = __commonJS({
51760
51963
  "use strict";
51761
51964
  var composer = require_composer();
51762
51965
  var Document = require_Document();
51763
- var Schema = require_Schema();
51966
+ var Schema2 = require_Schema();
51764
51967
  var errors = require_errors();
51765
51968
  var Alias = require_Alias();
51766
51969
  var identity3 = require_identity();
@@ -51776,7 +51979,7 @@ var require_dist = __commonJS({
51776
51979
  var visit2 = require_visit();
51777
51980
  exports.Composer = composer.Composer;
51778
51981
  exports.Document = Document.Document;
51779
- exports.Schema = Schema.Schema;
51982
+ exports.Schema = Schema2.Schema;
51780
51983
  exports.YAMLError = errors.YAMLError;
51781
51984
  exports.YAMLParseError = errors.YAMLParseError;
51782
51985
  exports.YAMLWarning = errors.YAMLWarning;
@@ -51816,7 +52019,6 @@ function parseWorktreeRoot(raw2, fallback) {
51816
52019
  if (isRecord2(raw2.worktrees) && typeof raw2.worktrees.root === "string" && raw2.worktrees.root.trim()) {
51817
52020
  return raw2.worktrees.root.trim();
51818
52021
  }
51819
- if (typeof raw2.worktreeRoot === "string" && raw2.worktreeRoot.trim()) return raw2.worktreeRoot.trim();
51820
52022
  return fallback;
51821
52023
  }
51822
52024
  function parseExposure(raw2) {
@@ -51928,18 +52130,15 @@ function parseProfile(raw2, fallbackRuntime) {
51928
52130
  ...typeof raw2.environment.cwd === "string" && raw2.environment.cwd.trim() ? { cwd: raw2.environment.cwd.trim() } : {},
51929
52131
  ...typeof raw2.environment.stopCommand === "string" && raw2.environment.stopCommand.trim() ? { stopCommand: raw2.environment.stopCommand.trim() } : {}
51930
52132
  } : void 0;
51931
- 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;
51932
- const effectiveEnvironment = legacyRuntimePane ? { ...environment, command: legacyRuntimePane.command } : environment;
51933
- const effectivePanes = legacyRuntimePane ? panes.filter((pane) => pane !== legacyRuntimePane) : panes;
51934
52133
  return {
51935
52134
  runtime: runtime2,
51936
52135
  envPassthrough,
51937
52136
  ...raw2.yolo === true ? { yolo: true } : {},
51938
- panes: effectivePanes,
52137
+ panes,
51939
52138
  ...typeof raw2.systemPrompt === "string" && raw2.systemPrompt.length > 0 ? { systemPrompt: raw2.systemPrompt } : {},
51940
52139
  ...image ? { image } : {},
51941
52140
  ...mounts ? { mounts } : {},
51942
- ...effectiveEnvironment && Object.keys(effectiveEnvironment).length > 0 ? { environment: effectiveEnvironment } : {}
52141
+ ...environment && Object.keys(environment).length > 0 ? { environment } : {}
51943
52142
  };
51944
52143
  }
51945
52144
  function parseProfiles(raw2, includeDefaultProfile) {
@@ -52061,7 +52260,7 @@ function parseConfigDocument(text) {
52061
52260
  const parsed = (0, import_yaml.parse)(text);
52062
52261
  return isRecord2(parsed) ? parsed : {};
52063
52262
  }
52064
- function parseProjectConfig(parsed) {
52263
+ function parseProjectConfig2(parsed) {
52065
52264
  const worktreeRoot = parseWorktreeRoot(parsed.workspace, DEFAULT_CONFIG.workspace.worktreeRoot);
52066
52265
  return {
52067
52266
  name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : DEFAULT_CONFIG.name,
@@ -52091,7 +52290,7 @@ function parseProjectConfig(parsed) {
52091
52290
  };
52092
52291
  }
52093
52292
  function defaultConfig() {
52094
- return parseProjectConfig({});
52293
+ return parseProjectConfig2({});
52095
52294
  }
52096
52295
  function parseTeamKeyList(raw2) {
52097
52296
  if (!Array.isArray(raw2)) return void 0;
@@ -52102,12 +52301,6 @@ function parseLinearIntegration(parsed) {
52102
52301
  const defaults = DEFAULT_CONFIG.integrations.linear;
52103
52302
  const linear = isRecord2(parsed.integrations) && isRecord2(parsed.integrations.linear) ? parsed.integrations.linear : null;
52104
52303
  if (!linear) return { ...defaults };
52105
- if (typeof linear.teamId === "string" && !warnedLegacyLinearTeamId) {
52106
- warnedLegacyLinearTeamId = true;
52107
- log.warn(
52108
- "[config] integrations.linear.teamId is no longer used \u2014 the ticket team is now picked at creation time in the dashboard"
52109
- );
52110
- }
52111
52304
  const watchTeams = parseTeamKeyList(linear.watchTeams);
52112
52305
  return {
52113
52306
  enabled: typeof linear.enabled === "boolean" ? linear.enabled : defaults.enabled,
@@ -52226,7 +52419,7 @@ function loadConfig(dir, options = {}) {
52226
52419
  let projectConfig;
52227
52420
  try {
52228
52421
  const text = readConfigFile(root2).trim();
52229
- projectConfig = text ? parseProjectConfig(parseConfigDocument(text)) : defaultConfig();
52422
+ projectConfig = text ? parseProjectConfig2(parseConfigDocument(text)) : defaultConfig();
52230
52423
  } catch {
52231
52424
  projectConfig = defaultConfig();
52232
52425
  }
@@ -52328,14 +52521,13 @@ async function removeLocalCustomAgent(dir, agentId2) {
52328
52521
  function expandTemplate(template, env) {
52329
52522
  return template.replace(/\$\{(\w+)\}/g, (_, key) => env[key] ?? "");
52330
52523
  }
52331
- var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG, warnedLegacyLinearTeamId;
52524
+ var import_yaml, DEFAULT_PANES, DEFAULT_PROFILE, DEFAULT_CONFIG;
52332
52525
  var init_config5 = __esm({
52333
52526
  "../host/src/modules/taskflow/adapters/config.ts"() {
52334
52527
  "use strict";
52335
52528
  init_config2();
52336
52529
  init_paths2();
52337
52530
  import_yaml = __toESM(require_dist(), 1);
52338
- init_log2();
52339
52531
  DEFAULT_PANES = [
52340
52532
  { id: "agent", kind: "agent", focus: true },
52341
52533
  { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" }
@@ -52369,7 +52561,6 @@ var init_config5 = __esm({
52369
52561
  autoName: null,
52370
52562
  oneshot: { systemPrompt: DEFAULT_ONESHOT_SYSTEM_PROMPT() }
52371
52563
  };
52372
- warnedLegacyLinearTeamId = false;
52373
52564
  }
52374
52565
  });
52375
52566
 
@@ -52630,7 +52821,7 @@ var init_process_runner = __esm({
52630
52821
 
52631
52822
  // ../host/src/modules/taskflow/adapters/worktree-git-mount.ts
52632
52823
  import { access, readFile, realpath, rename, unlink, writeFile as writeFile2 } from "node:fs/promises";
52633
- 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";
52634
52825
  function repairCommand(workspacePath) {
52635
52826
  return `git -C ${workspacePath} worktree repair --relative-paths`;
52636
52827
  }
@@ -52680,7 +52871,7 @@ function linkTarget(content) {
52680
52871
  return target.length > 0 ? target : null;
52681
52872
  }
52682
52873
  async function worktreeLink(workspacePath) {
52683
- const content = await readRaw(join11(workspacePath, ".git"));
52874
+ const content = await readRaw(join12(workspacePath, ".git"));
52684
52875
  return content === null ? null : linkTarget(content);
52685
52876
  }
52686
52877
  async function porttaOwned(runner, workspacePath, gitDir) {
@@ -52693,9 +52884,9 @@ async function porttaOwned(runner, workspacePath, gitDir) {
52693
52884
  return result.exit.code === 0 && result.stdout.trim().length > 0;
52694
52885
  }
52695
52886
  async function planRelativeRelink(workspacePath, dirs) {
52696
- const forwardPath = join11(workspacePath, ".git");
52697
- const backPath = join11(dirs.gitDir, BACK_LINK);
52698
- 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)
52699
52890
  return {
52700
52891
  ok: false,
52701
52892
  reason: `its Git dir ${dirs.gitDir} is not <common dir>/worktrees/<id> under ${dirs.commonDir}`
@@ -52756,7 +52947,7 @@ async function worktreeGitMountArgs(input2) {
52756
52947
  );
52757
52948
  }
52758
52949
  let link = await worktreeLink(workspacePath);
52759
- const backLink = await readRaw(join11(dirs.gitDir, BACK_LINK));
52950
+ const backLink = await readRaw(join12(dirs.gitDir, BACK_LINK));
52760
52951
  if (link !== null && isAbsolute2(link) || backLink !== null && isAbsolute2(backLink.trim())) {
52761
52952
  if (!await porttaOwned(runner, workspacePath, dirs.gitDir)) {
52762
52953
  throw new Error(
@@ -52812,7 +53003,7 @@ var init_worktree_git_mount = __esm({
52812
53003
  import { createHash as createHash5 } from "node:crypto";
52813
53004
  import { access as access2, readdir, readFile as readFile2 } from "node:fs/promises";
52814
53005
  import { createRequire } from "node:module";
52815
- 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";
52816
53007
  function hash2(value3) {
52817
53008
  return createHash5("sha256").update(value3).digest("hex");
52818
53009
  }
@@ -52828,16 +53019,16 @@ async function exists2(path7) {
52828
53019
  }
52829
53020
  }
52830
53021
  async function findDevcontainerConfigs(workspacePath) {
52831
- const rootConfig = join12(workspacePath, ".devcontainer.json");
52832
- const directory = join12(workspacePath, ".devcontainer");
53022
+ const rootConfig = join13(workspacePath, ".devcontainer.json");
53023
+ const directory = join13(workspacePath, ".devcontainer");
52833
53024
  const configs = [];
52834
53025
  if (await exists2(rootConfig)) configs.push(rootConfig);
52835
- 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"));
52836
53027
  if (await exists2(directory)) {
52837
53028
  const entries = await readdir(directory, { withFileTypes: true });
52838
53029
  for (const entry of entries) {
52839
53030
  if (!entry.isDirectory()) continue;
52840
- const candidate = join12(directory, entry.name, "devcontainer.json");
53031
+ const candidate = join13(directory, entry.name, "devcontainer.json");
52841
53032
  if (await exists2(candidate)) configs.push(candidate);
52842
53033
  }
52843
53034
  }
@@ -52991,7 +53182,7 @@ var init_devcontainer_environment = __esm({
52991
53182
  }
52992
53183
  const packagePath = createRequire(import.meta.url).resolve("@devcontainers/cli/package.json");
52993
53184
  this.cli = process.execPath;
52994
- this.cliPrefix = [join12(dirname8(packagePath), "devcontainer.js")];
53185
+ this.cliPrefix = [join13(dirname8(packagePath), "devcontainer.js")];
52995
53186
  }
52996
53187
  args(args) {
52997
53188
  return [...this.cliPrefix, ...args];
@@ -53058,7 +53249,7 @@ var init_devcontainer_environment = __esm({
53058
53249
  this.workspaceMounts.set(config3, merged.workspaceMount);
53059
53250
  else this.workspaceMounts.delete(config3);
53060
53251
  const compose4 = await resolveComposeConfiguration(this.runner, config3, merged);
53061
- const lockfile = join12(dirname8(config3), "devcontainer-lock.json");
53252
+ const lockfile = join13(dirname8(config3), "devcontainer-lock.json");
53062
53253
  const lockfileExists = await exists2(lockfile);
53063
53254
  const lockfileContents = lockfileExists ? await readFile2(lockfile, "utf8") : "";
53064
53255
  return {
@@ -53325,11 +53516,11 @@ exec ${argv.join(" ")} "$cwd" ${quoteShell(executable2)} "$@"
53325
53516
 
53326
53517
  // ../host/src/modules/taskflow/adapters/dockerfile-environment.ts
53327
53518
  import { createHash as createHash6 } from "node:crypto";
53328
- import { existsSync as existsSync7, readFileSync as readFileSync11 } from "node:fs";
53519
+ import { existsSync as existsSync8, readFileSync as readFileSync11 } from "node:fs";
53329
53520
  import { resolve as resolve5 } from "node:path";
53330
53521
  function dockerfileFor(context) {
53331
53522
  const dockerfile = resolve5(context.workspacePath, context.configRef ?? "Dockerfile");
53332
- 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"}`);
53333
53524
  return dockerfile;
53334
53525
  }
53335
53526
  function imageTag(id) {
@@ -53364,10 +53555,10 @@ var init_dockerfile_environment = __esm({
53364
53555
  const dockerfile = resolve5(context.workspacePath, "Dockerfile");
53365
53556
  return {
53366
53557
  provider: this.id,
53367
- available: version3.exit.code === 0 && existsSync7(dockerfile),
53368
- configRefs: existsSync7(dockerfile) ? [dockerfile] : [],
53558
+ available: version3.exit.code === 0 && existsSync8(dockerfile),
53559
+ configRefs: existsSync8(dockerfile) ? [dockerfile] : [],
53369
53560
  ...version3.exit.code === 0 ? { version: version3.stdout.trim() } : {},
53370
- 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"]
53371
53562
  };
53372
53563
  }
53373
53564
  async resolve(context) {
@@ -53591,13 +53782,13 @@ var init_sqlite = __esm({
53591
53782
  });
53592
53783
 
53593
53784
  // ../host/src/modules/taskflow/adapters/environment-store.ts
53594
- import { mkdirSync as mkdirSync6 } from "node:fs";
53785
+ import { mkdirSync as mkdirSync7 } from "node:fs";
53595
53786
  import { dirname as dirname9 } from "node:path";
53596
53787
  function parseEnvironmentRecord(value3) {
53597
53788
  return environmentRecordSchema.parse(value3);
53598
53789
  }
53599
53790
  function createEnvironmentStore(path7) {
53600
- mkdirSync6(dirname9(path7), { recursive: true });
53791
+ mkdirSync7(dirname9(path7), { recursive: true });
53601
53792
  const database = openDatabase(path7);
53602
53793
  database.pragma("journal_mode = WAL");
53603
53794
  database.exec(`
@@ -53836,7 +54027,7 @@ exec ${JSON.stringify(executable2)} "$@"
53836
54027
  });
53837
54028
 
53838
54029
  // ../host/src/modules/taskflow/adapters/projects-registry.ts
53839
- 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";
53840
54031
  import { dirname as dirname10 } from "node:path";
53841
54032
  function defaultRegistryFile() {
53842
54033
  return globalPaths().projectsRegistry;
@@ -53860,7 +54051,7 @@ function createProjectsRegistry(file2 = defaultRegistryFile()) {
53860
54051
  return parsed.filter(isProjectEntry);
53861
54052
  }
53862
54053
  function write4(entries) {
53863
- mkdirSync7(dirname10(file2), { recursive: true });
54054
+ mkdirSync8(dirname10(file2), { recursive: true });
53864
54055
  const tmpPath = `${file2}.${process.pid}.${Date.now()}.tmp`;
53865
54056
  writeFileSync7(tmpPath, `${JSON.stringify(entries, null, 2)}
53866
54057
  `);
@@ -54574,20 +54765,20 @@ var init_tmux = __esm({
54574
54765
  });
54575
54766
 
54576
54767
  // ../host/src/modules/taskflow/assets.ts
54577
- import { existsSync as existsSync8 } from "node:fs";
54578
- 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";
54579
54770
  function taskflowAssets(env = process.env, directory = import.meta.dirname) {
54580
- const bundled = join13(directory, "assets");
54581
- if (existsSync8(join13(bundled, "workflows"))) {
54771
+ const bundled = join14(directory, "assets");
54772
+ if (existsSync9(join14(bundled, "workflows"))) {
54582
54773
  return {
54583
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(bundled, "workflows"),
54584
- 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")
54585
54776
  };
54586
54777
  }
54587
54778
  const repository = resolve7(directory, "../../../../..");
54588
54779
  return {
54589
- workflowBuiltinsDir: env[ENV_NAMES.workflowBuiltinsDir] || join13(repository, "packages", "host", "workflows"),
54590
- 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")
54591
54782
  };
54592
54783
  }
54593
54784
  var init_assets = __esm({
@@ -54806,7 +54997,7 @@ var init_environment_service_discovery = __esm({
54806
54997
  // ../host/src/modules/taskflow/adapters/git.ts
54807
54998
  import { spawnSync as spawnSync5 } from "node:child_process";
54808
54999
  import { readdirSync as readdirSync2, realpathSync as realpathSync2, rmSync, statSync as statSync5 } from "node:fs";
54809
- 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";
54810
55001
  function canonicalizeFsPath(input2) {
54811
55002
  const resolved2 = resolve8(input2);
54812
55003
  try {
@@ -54818,7 +55009,7 @@ function canonicalizeFsPath(input2) {
54818
55009
  missing.unshift(basename5(current));
54819
55010
  current = dirname11(current);
54820
55011
  try {
54821
- return join14(realpathSync2(current), ...missing);
55012
+ return join15(realpathSync2(current), ...missing);
54822
55013
  } catch {
54823
55014
  }
54824
55015
  }
@@ -54910,7 +55101,7 @@ function resolveRepoRoot(dir) {
54910
55101
  return null;
54911
55102
  }
54912
55103
  for (const entry of entries) {
54913
- const child = join14(dir, entry);
55104
+ const child = join15(dir, entry);
54914
55105
  try {
54915
55106
  if (!statSync5(child).isDirectory()) continue;
54916
55107
  } catch {
@@ -55844,7 +56035,7 @@ var init_herdr = __esm({
55844
56035
 
55845
56036
  // ../host/src/modules/taskflow/adapters/hooks.ts
55846
56037
  import { access as access3 } from "node:fs/promises";
55847
- import { join as join15 } from "node:path";
56038
+ import { join as join16 } from "node:path";
55848
56039
  function buildErrorMessage(name, exitCode, stdout2, stderr2) {
55849
56040
  const output2 = stderr2.trim() || stdout2.trim();
55850
56041
  if (output2) {
@@ -55895,7 +56086,7 @@ var init_hooks = __esm({
55895
56086
  }
55896
56087
  async hasEnvrc(cwd) {
55897
56088
  try {
55898
- await access3(join15(cwd, ".envrc"));
56089
+ await access3(join16(cwd, ".envrc"));
55899
56090
  return true;
55900
56091
  } catch {
55901
56092
  return false;
@@ -55994,7 +56185,7 @@ var init_type_guards = __esm({
55994
56185
 
55995
56186
  // ../host/src/modules/taskflow/adapters/claude-cli.ts
55996
56187
  import { readdir as readdir2, readFile as readFile3, stat as stat2 } from "node:fs/promises";
55997
- import { basename as basename6, join as join16 } from "node:path";
56188
+ import { basename as basename6, join as join17 } from "node:path";
55998
56189
  function isRecord5(raw2) {
55999
56190
  return typeof raw2 === "object" && raw2 !== null && !Array.isArray(raw2);
56000
56191
  }
@@ -56177,19 +56368,19 @@ function readClaudeProjectsRoot() {
56177
56368
  if (!home2) {
56178
56369
  throw new Error("HOME is required to resolve Claude sessions");
56179
56370
  }
56180
- return join16(home2, ".claude", "projects");
56371
+ return join17(home2, ".claude", "projects");
56181
56372
  }
56182
56373
  async function listJsonlFiles(dir) {
56183
56374
  try {
56184
56375
  const entries = await readdir2(dir, { withFileTypes: true });
56185
- 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));
56186
56377
  } catch {
56187
56378
  return [];
56188
56379
  }
56189
56380
  }
56190
56381
  async function findClaudeSessionPath(sessionId, cwd) {
56191
56382
  const projectsRoot = readClaudeProjectsRoot();
56192
- const primaryPath = join16(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56383
+ const primaryPath = join17(projectsRoot, encodeClaudeProjectDir(cwd), `${sessionId}.jsonl`);
56193
56384
  try {
56194
56385
  await stat2(primaryPath);
56195
56386
  return primaryPath;
@@ -56198,7 +56389,7 @@ async function findClaudeSessionPath(sessionId, cwd) {
56198
56389
  const projectDirs2 = await readdir2(projectsRoot, { withFileTypes: true }).catch(() => []);
56199
56390
  for (const entry of projectDirs2) {
56200
56391
  if (!entry.isDirectory()) continue;
56201
- const candidate = join16(projectsRoot, entry.name, `${sessionId}.jsonl`);
56392
+ const candidate = join17(projectsRoot, entry.name, `${sessionId}.jsonl`);
56202
56393
  try {
56203
56394
  await stat2(candidate);
56204
56395
  return candidate;
@@ -56341,7 +56532,7 @@ var init_claude_cli = __esm({
56341
56532
  }
56342
56533
  async listSessions(cwd) {
56343
56534
  const projectsRoot = readClaudeProjectsRoot();
56344
- const primaryDir = join16(projectsRoot, encodeClaudeProjectDir(cwd));
56535
+ const primaryDir = join17(projectsRoot, encodeClaudeProjectDir(cwd));
56345
56536
  const primaryFiles = await listJsonlFiles(primaryDir);
56346
56537
  if (primaryFiles.length > 0) {
56347
56538
  return await this.summarizeSessionFiles(primaryFiles, cwd);
@@ -56350,7 +56541,7 @@ var init_claude_cli = __esm({
56350
56541
  const matchedFiles = [];
56351
56542
  for (const entry of projectDirs2) {
56352
56543
  if (!entry.isDirectory()) continue;
56353
- const files = await listJsonlFiles(join16(projectsRoot, entry.name));
56544
+ const files = await listJsonlFiles(join17(projectsRoot, entry.name));
56354
56545
  for (const filePath of files) {
56355
56546
  const session = await this.readSessionFile(filePath);
56356
56547
  if (session?.cwd === cwd) {
@@ -56529,7 +56720,7 @@ var init_claude_cli = __esm({
56529
56720
 
56530
56721
  // ../host/src/modules/taskflow/adapters/session-discovery.ts
56531
56722
  import { open as open2, readdir as readdir3, stat as stat3 } from "node:fs/promises";
56532
- import { basename as basename7, join as join17 } from "node:path";
56723
+ import { basename as basename7, join as join18 } from "node:path";
56533
56724
  import { setTimeout as sleep3 } from "node:timers/promises";
56534
56725
  function home() {
56535
56726
  const value3 = process.env.HOME;
@@ -56540,11 +56731,11 @@ function newestFirst(sessions3) {
56540
56731
  return sessions3.sort((left, right) => right.mtimeMs - left.mtimeMs).map((entry) => entry.sessionId);
56541
56732
  }
56542
56733
  async function listClaudeSessionIds(cwd) {
56543
- const dir = join17(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56734
+ const dir = join18(home(), ".claude", "projects", encodeClaudeProjectDir(cwd));
56544
56735
  const names = await readdir3(dir).catch(() => []);
56545
56736
  const stamped = await Promise.all(
56546
56737
  names.filter((name) => name.endsWith(".jsonl")).map(async (name) => {
56547
- const info = await stat3(join17(dir, name)).catch(() => null);
56738
+ const info = await stat3(join18(dir, name)).catch(() => null);
56548
56739
  return info ? { sessionId: basename7(name, ".jsonl"), mtimeMs: info.mtimeMs } : null;
56549
56740
  })
56550
56741
  );
@@ -56580,7 +56771,7 @@ async function readCodexSessionCwdId(path7) {
56580
56771
  }
56581
56772
  }
56582
56773
  async function listCodexSessionIds(cwd) {
56583
- const root2 = join17(home(), ".codex", "sessions");
56774
+ const root2 = join18(home(), ".codex", "sessions");
56584
56775
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56585
56776
  const rollouts = relPaths.filter((rel) => {
56586
56777
  const name = basename7(rel);
@@ -56588,7 +56779,7 @@ async function listCodexSessionIds(cwd) {
56588
56779
  });
56589
56780
  const stamped = await Promise.all(
56590
56781
  rollouts.map(async (rel) => {
56591
- const path7 = join17(root2, rel);
56782
+ const path7 = join18(root2, rel);
56592
56783
  const meta3 = await readCodexSessionCwdId(path7);
56593
56784
  if (!meta3 || meta3.cwd !== cwd) return null;
56594
56785
  const info = await stat3(path7).catch(() => null);
@@ -56598,11 +56789,11 @@ async function listCodexSessionIds(cwd) {
56598
56789
  return newestFirst(stamped.filter((entry) => entry !== null));
56599
56790
  }
56600
56791
  async function findCodexSessionPath(sessionId, cwd) {
56601
- const root2 = join17(home(), ".codex", "sessions");
56792
+ const root2 = join18(home(), ".codex", "sessions");
56602
56793
  const relPaths = await readdir3(root2, { recursive: true }).catch(() => []);
56603
56794
  for (const rel of relPaths) {
56604
56795
  if (!basename7(rel).endsWith(`${sessionId}.jsonl`)) continue;
56605
- const path7 = join17(root2, rel);
56796
+ const path7 = join18(root2, rel);
56606
56797
  const meta3 = await readCodexSessionCwdId(path7);
56607
56798
  if (meta3?.id === sessionId && meta3.cwd === cwd) return path7;
56608
56799
  }
@@ -56692,7 +56883,7 @@ var init_session_discovery = __esm({
56692
56883
 
56693
56884
  // ../host/src/modules/taskflow/adapters/fs.ts
56694
56885
  import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
56695
- import { join as join18 } from "node:path";
56886
+ import { join as join19 } from "node:path";
56696
56887
  function stringifyAllocatedPorts(ports) {
56697
56888
  const entries = Object.entries(ports).map(([key, value3]) => [key, String(value3)]);
56698
56889
  return Object.fromEntries(entries);
@@ -56721,7 +56912,7 @@ function parseDotenv(content) {
56721
56912
  }
56722
56913
  async function loadDotenvLocal(worktreePath) {
56723
56914
  try {
56724
- const content = await readFile4(join18(worktreePath, ".env.local"), "utf8");
56915
+ const content = await readFile4(join19(worktreePath, ".env.local"), "utf8");
56725
56916
  return parseDotenv(content);
56726
56917
  } catch {
56727
56918
  return {};
@@ -56862,25 +57053,21 @@ function isRecord6(raw2) {
56862
57053
  function normalizeConversationMeta(raw2) {
56863
57054
  if (!raw2) return raw2;
56864
57055
  if (raw2.provider === "codexAppServer") {
56865
- const conversationId2 = raw2.conversationId || raw2.threadId;
56866
- const threadId = raw2.threadId || raw2.conversationId;
56867
- if (!conversationId2 || !threadId) return void 0;
57056
+ if (!raw2.conversationId || !raw2.threadId) return void 0;
56868
57057
  const normalized2 = {
56869
57058
  provider: "codexAppServer",
56870
- conversationId: conversationId2,
56871
- threadId,
57059
+ conversationId: raw2.conversationId,
57060
+ threadId: raw2.threadId,
56872
57061
  cwd: raw2.cwd,
56873
57062
  lastSeenAt: raw2.lastSeenAt
56874
57063
  };
56875
57064
  return normalized2;
56876
57065
  }
56877
- const conversationId = raw2.conversationId || raw2.sessionId;
56878
- const sessionId = raw2.sessionId || raw2.conversationId;
56879
- if (!conversationId || !sessionId) return void 0;
57066
+ if (!raw2.conversationId || !raw2.sessionId) return void 0;
56880
57067
  const normalized = {
56881
57068
  provider: "claudeCode",
56882
- conversationId,
56883
- sessionId,
57069
+ conversationId: raw2.conversationId,
57070
+ sessionId: raw2.sessionId,
56884
57071
  cwd: raw2.cwd,
56885
57072
  lastSeenAt: raw2.lastSeenAt
56886
57073
  };
@@ -57310,7 +57497,7 @@ ${stderr2}`;
57310
57497
 
57311
57498
  // ../host/src/modules/taskflow/adapters/agent-runtime.ts
57312
57499
  import { chmod, mkdir as mkdir3, readFile as readFile5, writeFile as writeFile4 } from "node:fs/promises";
57313
- 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";
57314
57501
  function shellQuote(value3) {
57315
57502
  return `'${value3.replaceAll("'", "'\\''")}'`;
57316
57503
  }
@@ -57763,7 +57950,7 @@ async function mergeCodexHooksFile(hooksPath, hookSettings, agentCtlPath) {
57763
57950
  }
57764
57951
  async function resolveGitCommonDir(gitDir) {
57765
57952
  try {
57766
- const commonDir = (await readFile5(join19(gitDir, "commondir"), "utf8")).trim();
57953
+ const commonDir = (await readFile5(join20(gitDir, "commondir"), "utf8")).trim();
57767
57954
  if (!commonDir) return gitDir;
57768
57955
  return commonDir.startsWith("/") ? commonDir : resolve10(gitDir, commonDir);
57769
57956
  } catch {
@@ -57772,7 +57959,7 @@ async function resolveGitCommonDir(gitDir) {
57772
57959
  }
57773
57960
  async function ensureGeneratedAgentFilesIgnored(gitDir) {
57774
57961
  const commonDir = await resolveGitCommonDir(gitDir);
57775
- const excludePath = join19(commonDir, "info", "exclude");
57962
+ const excludePath = join20(commonDir, "info", "exclude");
57776
57963
  let existing = "";
57777
57964
  try {
57778
57965
  existing = await readFile5(excludePath, "utf8");
@@ -57790,9 +57977,9 @@ async function ensureGeneratedAgentFilesIgnored(gitDir) {
57790
57977
  async function ensureAgentRuntimeArtifacts(input2) {
57791
57978
  const storagePaths = getWorktreeStoragePaths(input2.gitDir);
57792
57979
  const artifacts = {
57793
- agentCtlPath: join19(storagePaths.taskflowDir, RUNTIME_IDENTITY.agentControlBinary),
57794
- claudeSettingsPath: join19(input2.worktreePath, ".claude", "settings.local.json"),
57795
- 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")
57796
57983
  };
57797
57984
  await mkdir3(dirname12(artifacts.claudeSettingsPath), { recursive: true });
57798
57985
  await mkdir3(dirname12(artifacts.codexHooksPath), { recursive: true });
@@ -57936,7 +58123,7 @@ var init_agent_registry = __esm({
57936
58123
  });
57937
58124
 
57938
58125
  // ../host/src/modules/taskflow/services/agent-service.ts
57939
- import { dirname as dirname13, join as join20 } from "node:path";
58126
+ import { dirname as dirname13, join as join21 } from "node:path";
57940
58127
  function quoteShell3(value3) {
57941
58128
  return `'${value3.replaceAll("'", "'\\''")}'`;
57942
58129
  }
@@ -57948,7 +58135,7 @@ function buildDockerRuntimeBootstrap(runtimeEnvPath) {
57948
58135
  }
57949
58136
  function buildCodexNotifyFlag(runtimeEnvPath) {
57950
58137
  if (!runtimeEnvPath) return "";
57951
- const agentCtlPath = join20(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
58138
+ const agentCtlPath = join21(dirname13(runtimeEnvPath), RUNTIME_IDENTITY.agentControlBinary);
57952
58139
  return ` -c ${quoteShell3(`notify=${JSON.stringify([agentCtlPath, "codex-notify"])}`)}`;
57953
58140
  }
57954
58141
  function buildBuiltInAgentInvocation(input2) {
@@ -59413,10 +59600,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59413
59600
  return panes.length > 0 ? panes : [{ id: "runtime", kind: "runtime", cwd: "worktree" }];
59414
59601
  }
59415
59602
  if (panes.some((pane) => pane.kind === "runtime")) return panes;
59416
- const legacyShell = panes.findIndex((pane) => pane.id === "shell" && pane.kind === "shell");
59417
- const runtimePane = { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" };
59418
- if (legacyShell >= 0) panes.splice(legacyShell, 1, runtimePane);
59419
- else panes.push(runtimePane);
59603
+ panes.push({ id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" });
59420
59604
  return panes;
59421
59605
  }
59422
59606
  requireDockerProfile(profile) {
@@ -60368,7 +60552,6 @@ var DEFAULT_TERMINAL_TTL_MS, ProjectInitTracker;
60368
60552
  var init_project_init_service = __esm({
60369
60553
  "../host/src/modules/taskflow/services/project-init-service.ts"() {
60370
60554
  "use strict";
60371
- init_log2();
60372
60555
  DEFAULT_TERMINAL_TTL_MS = 6e4;
60373
60556
  ProjectInitTracker = class {
60374
60557
  inits = /* @__PURE__ */ new Map();
@@ -68981,10 +69164,10 @@ var init_native_terminal_service = __esm({
68981
69164
  });
68982
69165
 
68983
69166
  // ../host/src/modules/taskflow/server/routes/worktrees.ts
68984
- import { mkdirSync as mkdirSync8 } from "node:fs";
69167
+ import { mkdirSync as mkdirSync9 } from "node:fs";
68985
69168
  import { writeFile as writeFile6 } from "node:fs/promises";
68986
69169
  import { tmpdir } from "node:os";
68987
- import { join as join21, resolve as resolve16 } from "node:path";
69170
+ import { join as join22, resolve as resolve16 } from "node:path";
68988
69171
  async function apiGetNativeTerminalLaunch(project2, branch) {
68989
69172
  touchDashboardActivity();
68990
69173
  project2.ensureBranchNotBusy(branch);
@@ -69318,8 +69501,8 @@ async function apiUploadFiles(project2, name, req) {
69318
69501
  }
69319
69502
  const entries = formData.getAll("files");
69320
69503
  if (entries.length === 0) return errorResponse("No files provided", 400);
69321
- const uploadDir = join21(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69322
- mkdirSync8(uploadDir, { recursive: true });
69504
+ const uploadDir = join22(tmpdir(), RUNTIME_IDENTITY.tempUploadDir, sanitizeFilename(name));
69505
+ mkdirSync9(uploadDir, { recursive: true });
69323
69506
  const results = [];
69324
69507
  for (const entry of entries) {
69325
69508
  if (!(entry instanceof File)) continue;
@@ -69330,7 +69513,7 @@ async function apiUploadFiles(project2, name, req) {
69330
69513
  return errorResponse(`File too large: ${entry.name} (max 10MB)`, 400);
69331
69514
  }
69332
69515
  const safeName = `${Date.now()}_${sanitizeFilename(entry.name)}`;
69333
- const destPath = join21(uploadDir, safeName);
69516
+ const destPath = join22(uploadDir, safeName);
69334
69517
  if (!resolve16(destPath).startsWith(`${uploadDir}/`)) {
69335
69518
  return errorResponse("Invalid filename", 400);
69336
69519
  }
@@ -70066,7 +70249,7 @@ var init_codex_app_server = __esm({
70066
70249
  });
70067
70250
 
70068
70251
  // ../host/src/modules/taskflow/adapters/run-store.ts
70069
- import { mkdirSync as mkdirSync9 } from "node:fs";
70252
+ import { mkdirSync as mkdirSync10 } from "node:fs";
70070
70253
  import { dirname as dirname15 } from "node:path";
70071
70254
  function defaultRunStorePath() {
70072
70255
  return globalPaths().database;
@@ -70227,7 +70410,7 @@ function isConstraint(error61, target) {
70227
70410
  return error61 instanceof Error && error61.message.includes(target);
70228
70411
  }
70229
70412
  function createRunStore(path7 = defaultRunStorePath()) {
70230
- mkdirSync9(dirname15(path7), { recursive: true });
70413
+ mkdirSync10(dirname15(path7), { recursive: true });
70231
70414
  const database = openDatabase(path7);
70232
70415
  database.pragma("foreign_keys = ON");
70233
70416
  database.pragma("journal_mode = WAL");
@@ -70647,10 +70830,15 @@ var init_run_store = __esm({
70647
70830
  input_json TEXT NOT NULL,
70648
70831
  status TEXT NOT NULL CHECK(status IN ('queued', 'provisioning', 'running', 'waiting_input', 'completed', 'failed', 'cancelled', 'interrupted')),
70649
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')),
70650
70835
  workflow_snapshot_id TEXT,
70651
70836
  workspace_id TEXT,
70652
70837
  worktree_path TEXT,
70653
70838
  canonical_workspace_path TEXT,
70839
+ checkout_canonical_path TEXT,
70840
+ checkout_branch TEXT,
70841
+ environment_id TEXT,
70654
70842
  branch TEXT,
70655
70843
  base_branch TEXT,
70656
70844
  base_commit TEXT,
@@ -70678,6 +70866,7 @@ var init_run_store = __esm({
70678
70866
  path TEXT NOT NULL,
70679
70867
  content_hash TEXT NOT NULL,
70680
70868
  engine_version TEXT NOT NULL,
70869
+ key_version TEXT NOT NULL DEFAULT 'v1',
70681
70870
  source TEXT NOT NULL,
70682
70871
  metadata_json TEXT NOT NULL,
70683
70872
  created_at TEXT NOT NULL
@@ -70702,6 +70891,7 @@ var init_run_store = __esm({
70702
70891
  error TEXT,
70703
70892
  session_id TEXT,
70704
70893
  capabilities_json TEXT,
70894
+ checkpoint_json TEXT,
70705
70895
  started_at TEXT,
70706
70896
  completed_at TEXT,
70707
70897
  UNIQUE(run_id, node_key, attempt)
@@ -70713,10 +70903,7 @@ var init_run_store = __esm({
70713
70903
  source TEXT NOT NULL,
70714
70904
  updated_at TEXT NOT NULL
70715
70905
  );
70716
- `,
70717
- "ALTER TABLE executions ADD COLUMN checkpoint_json TEXT;",
70718
- "ALTER TABLE workflow_snapshots ADD COLUMN key_version TEXT NOT NULL DEFAULT 'v1';",
70719
- `
70906
+
70720
70907
  CREATE TABLE IF NOT EXISTS run_events (
70721
70908
  id TEXT PRIMARY KEY,
70722
70909
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70729,8 +70916,7 @@ var init_run_store = __esm({
70729
70916
  payload_json TEXT NOT NULL,
70730
70917
  UNIQUE(run_id, sequence)
70731
70918
  );
70732
- `,
70733
- `
70919
+
70734
70920
  CREATE TABLE IF NOT EXISTS workspace_leases (
70735
70921
  id TEXT PRIMARY KEY,
70736
70922
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -70748,12 +70934,7 @@ var init_run_store = __esm({
70748
70934
  updated_at TEXT NOT NULL,
70749
70935
  released_at TEXT
70750
70936
  );
70751
- `,
70752
- "ALTER TABLE runs ADD COLUMN workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch'));",
70753
- "ALTER TABLE runs ADD COLUMN workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write'));",
70754
- "ALTER TABLE runs ADD COLUMN checkout_canonical_path TEXT;",
70755
- "ALTER TABLE runs ADD COLUMN checkout_branch TEXT;",
70756
- `
70937
+
70757
70938
  CREATE TABLE IF NOT EXISTS checkout_claims (
70758
70939
  run_id TEXT PRIMARY KEY REFERENCES runs(id),
70759
70940
  project_id TEXT NOT NULL,
@@ -70762,8 +70943,7 @@ var init_run_store = __esm({
70762
70943
  created_at TEXT NOT NULL
70763
70944
  );
70764
70945
  CREATE INDEX IF NOT EXISTS checkout_claims_path_idx ON checkout_claims(project_id, canonical_path);
70765
- `,
70766
- "ALTER TABLE runs ADD COLUMN environment_id TEXT;"
70946
+ `
70767
70947
  ];
70768
70948
  }
70769
70949
  });
@@ -71016,26 +71196,26 @@ var init_types2 = __esm({
71016
71196
  });
71017
71197
 
71018
71198
  // ../host/src/modules/taskflow/workflows/runtime/journal.ts
71019
- import { appendFileSync as appendFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync10, readdirSync as readdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "node:fs";
71020
- 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";
71021
71201
  function dataRoot(roots = {}) {
71022
71202
  return roots.dataRoot ?? globalPaths().root;
71023
71203
  }
71024
71204
  function runDir(runId, roots = {}) {
71025
- return join22(dataRoot(roots), "runs", runId);
71205
+ return join23(dataRoot(roots), "runs", runId);
71026
71206
  }
71027
71207
  function journalPath(runId, roots = {}) {
71028
- return join22(runDir(runId, roots), "journal.jsonl");
71208
+ return join23(runDir(runId, roots), "journal.jsonl");
71029
71209
  }
71030
71210
  function ensureRunDir(runId, roots = {}) {
71031
71211
  const dir = runDir(runId, roots);
71032
- mkdirSync10(dir, { recursive: true });
71212
+ mkdirSync11(dir, { recursive: true });
71033
71213
  return dir;
71034
71214
  }
71035
71215
  function listRunIds(roots = {}) {
71036
- const dir = join22(dataRoot(roots), "runs");
71037
- if (!existsSync9(dir)) return [];
71038
- 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();
71039
71219
  }
71040
71220
  function checkResumePreconditions(meta3, current) {
71041
71221
  if (!meta3) return;
@@ -71061,7 +71241,7 @@ function canonicalArgs(value3) {
71061
71241
  }
71062
71242
  function writeResult(runId, value3, roots = {}) {
71063
71243
  const dir = ensureRunDir(runId, roots);
71064
- writeFileSync8(join22(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71244
+ writeFileSync8(join23(dir, "result.json"), JSON.stringify(value3, null, 2), "utf8");
71065
71245
  }
71066
71246
  var JournalNotFoundError, ResumePreconditionError, Journal;
71067
71247
  var init_journal = __esm({
@@ -71089,7 +71269,7 @@ var init_journal = __esm({
71089
71269
  path;
71090
71270
  constructor(runId, roots = {}) {
71091
71271
  this.path = journalPath(runId, roots);
71092
- mkdirSync10(dirname16(this.path), { recursive: true });
71272
+ mkdirSync11(dirname16(this.path), { recursive: true });
71093
71273
  }
71094
71274
  append(entry) {
71095
71275
  appendFileSync2(this.path, `${JSON.stringify(entry)}
@@ -71097,12 +71277,12 @@ var init_journal = __esm({
71097
71277
  }
71098
71278
  /** True if a journal file exists for this run id (vs. a typo'd / absent run). */
71099
71279
  static exists(runId, roots = {}) {
71100
- return existsSync9(journalPath(runId, roots));
71280
+ return existsSync10(journalPath(runId, roots));
71101
71281
  }
71102
71282
  static load(runId, roots = {}) {
71103
71283
  const path7 = journalPath(runId, roots);
71104
71284
  const out = { results: /* @__PURE__ */ new Map(), indexByKey: /* @__PURE__ */ new Map() };
71105
- if (!existsSync9(path7)) return out;
71285
+ if (!existsSync10(path7)) return out;
71106
71286
  const text = readFileSync13(path7, "utf8");
71107
71287
  for (const line4 of text.split("\n")) {
71108
71288
  const trimmed = line4.trim();
@@ -71505,9 +71685,9 @@ var init_sandbox = __esm({
71505
71685
  });
71506
71686
 
71507
71687
  // ../host/src/modules/taskflow/workflows/runtime/registry.ts
71508
- 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";
71509
71689
  import { homedir as homedir4 } from "node:os";
71510
- 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";
71511
71691
  import { fileURLToPath as fileURLToPath4 } from "node:url";
71512
71692
  function builtinDir() {
71513
71693
  const here = dirname17(fileURLToPath4(import.meta.url));
@@ -71516,10 +71696,10 @@ function builtinDir() {
71516
71696
  ["..", "..", "builtins"],
71517
71697
  ["..", "..", "..", "..", "..", "workflows"]
71518
71698
  ]) {
71519
- const candidate = join23(here, ...rel);
71520
- if (existsSync10(candidate)) return candidate;
71699
+ const candidate = join24(here, ...rel);
71700
+ if (existsSync11(candidate)) return candidate;
71521
71701
  }
71522
- return join23(here, "..", "builtins");
71702
+ return join24(here, "..", "builtins");
71523
71703
  }
71524
71704
  function projectDirs(cwd) {
71525
71705
  const dirs = [];
@@ -71527,8 +71707,8 @@ function projectDirs(cwd) {
71527
71707
  let dir = resolve17(cwd);
71528
71708
  for (; ; ) {
71529
71709
  const workflows = projectPaths(dir).workflows;
71530
- if (existsSync10(workflows)) dirs.push(workflows);
71531
- if (existsSync10(join23(dir, ".git"))) break;
71710
+ if (existsSync11(workflows)) dirs.push(workflows);
71711
+ if (existsSync11(join24(dir, ".git"))) break;
71532
71712
  const parent = dirname17(dir);
71533
71713
  if (dir === home2 || parent === dir) break;
71534
71714
  dir = parent;
@@ -71542,7 +71722,7 @@ function workflowDirs(cwd, roots) {
71542
71722
  tier: "project",
71543
71723
  dir: resolve17(dir)
71544
71724
  })),
71545
- { tier: "user", dir: roots.globalDir ?? join23(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71725
+ { tier: "user", dir: roots.globalDir ?? join24(dataRoot({ dataRoot: roots.dataRoot }), "workflows") },
71546
71726
  { tier: "builtin", dir: roots.builtinDir ?? builtinDir() }
71547
71727
  ];
71548
71728
  }
@@ -71562,7 +71742,7 @@ function scanDir(tier, dir) {
71562
71742
  const entries = [];
71563
71743
  for (const file2 of names) {
71564
71744
  if (!file2.endsWith(".js")) continue;
71565
- const filePath = join23(dir, file2);
71745
+ const filePath = join24(dir, file2);
71566
71746
  try {
71567
71747
  if (statSync6(filePath).size > MAX_WORKFLOW_BYTES) continue;
71568
71748
  const { meta: meta3 } = parseWorkflow(readFileSync14(filePath, "utf8"));
@@ -78622,7 +78802,7 @@ var init_schema = __esm({
78622
78802
  // ../host/src/modules/taskflow/workflows/worker/claude.ts
78623
78803
  import { readlinkSync, realpathSync as realpathSync3 } from "node:fs";
78624
78804
  import { homedir as homedir5 } from "node:os";
78625
- 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";
78626
78806
  function toClaudeEffort(effort) {
78627
78807
  return effort === "none" || effort === "minimal" ? "low" : effort;
78628
78808
  }
@@ -78661,7 +78841,7 @@ function realpathUpward(p) {
78661
78841
  for (let hops = 0; hops < 40; hops++) {
78662
78842
  try {
78663
78843
  const real = realpathSync3(existing);
78664
- return suffix ? join24(real, suffix) : real;
78844
+ return suffix ? join25(real, suffix) : real;
78665
78845
  } catch {
78666
78846
  }
78667
78847
  try {
@@ -78672,7 +78852,7 @@ function realpathUpward(p) {
78672
78852
  }
78673
78853
  const parent = dirname18(existing);
78674
78854
  if (parent === existing) return p;
78675
- suffix = suffix ? join24(basename9(existing), suffix) : basename9(existing);
78855
+ suffix = suffix ? join25(basename9(existing), suffix) : basename9(existing);
78676
78856
  existing = parent;
78677
78857
  }
78678
78858
  return p;
@@ -78766,7 +78946,7 @@ function unquote(s) {
78766
78946
  }
78767
78947
  function expandHome(p) {
78768
78948
  if (p === "~") return homedir5();
78769
- if (p.startsWith("~/")) return join24(homedir5(), p.slice(2));
78949
+ if (p.startsWith("~/")) return join25(homedir5(), p.slice(2));
78770
78950
  return p;
78771
78951
  }
78772
78952
  function usageFromResult(last) {
@@ -79398,7 +79578,7 @@ ${tail}` : message;
79398
79578
 
79399
79579
  // ../host/src/modules/taskflow/workflows/worker/codex.ts
79400
79580
  import { copyFile, writeFile as writeFile7 } from "node:fs/promises";
79401
- import { basename as basename10, join as join25 } from "node:path";
79581
+ import { basename as basename10, join as join26 } from "node:path";
79402
79582
  function textInput(text) {
79403
79583
  return [{ type: "text", text, text_elements: [] }];
79404
79584
  }
@@ -79814,7 +79994,7 @@ var init_codex = __esm({
79814
79994
  const id = basename10(rawId) || "image";
79815
79995
  const savedPath = typeof item.savedPath === "string" ? item.savedPath : void 0;
79816
79996
  const b64 = typeof item.result === "string" ? item.result : void 0;
79817
- const dest = join25(state3.cwd, `${id}.png`);
79997
+ const dest = join26(state3.cwd, `${id}.png`);
79818
79998
  const write4 = (async () => {
79819
79999
  try {
79820
80000
  if (savedPath) await copyFile(savedPath, dest);
@@ -80605,7 +80785,7 @@ __export(pi_exports, {
80605
80785
  });
80606
80786
  import { mkdtempSync, rmSync as rmSync2 } from "node:fs";
80607
80787
  import { tmpdir as tmpdir2 } from "node:os";
80608
- import { join as join26 } from "node:path";
80788
+ import { join as join27 } from "node:path";
80609
80789
  function extractionPrompt2(spec, workingText) {
80610
80790
  return `Earlier you produced this answer:
80611
80791
 
@@ -80769,7 +80949,7 @@ var init_pi = __esm({
80769
80949
  return this.versionCheck;
80770
80950
  }
80771
80951
  async checkVersion() {
80772
- const scratch = mkdtempSync(join26(tmpdir2(), `${APP_SLUG}-pi-version-`));
80952
+ const scratch = mkdtempSync(join27(tmpdir2(), `${APP_SLUG}-pi-version-`));
80773
80953
  let out;
80774
80954
  try {
80775
80955
  out = await captureStdout({
@@ -80976,7 +81156,7 @@ var init_factory = __esm({
80976
81156
  });
80977
81157
 
80978
81158
  // ../host/src/modules/taskflow/workflows/runtime/jsonl-writer.ts
80979
- import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync11 } from "node:fs";
81159
+ import { createWriteStream as createWriteStream2, mkdirSync as mkdirSync12 } from "node:fs";
80980
81160
  function dirOf(filePath) {
80981
81161
  const i3 = Math.max(filePath.lastIndexOf("/"), filePath.lastIndexOf("\\"));
80982
81162
  return i3 <= 0 ? "." : filePath.slice(0, i3);
@@ -80989,7 +81169,7 @@ var init_jsonl_writer = __esm({
80989
81169
  stream;
80990
81170
  dead = false;
80991
81171
  constructor(filePath, opts = {}) {
80992
- mkdirSync11(dirOf(filePath), { recursive: true });
81172
+ mkdirSync12(dirOf(filePath), { recursive: true });
80993
81173
  this.stream = createWriteStream2(filePath, { flags: opts.flags ?? "a" });
80994
81174
  this.stream.on("error", (err2) => {
80995
81175
  this.dead = true;
@@ -81030,7 +81210,7 @@ var init_jsonl_writer = __esm({
81030
81210
  });
81031
81211
 
81032
81212
  // ../host/src/modules/taskflow/workflows/runtime/event-sink.ts
81033
- import { join as join27 } from "node:path";
81213
+ import { join as join28 } from "node:path";
81034
81214
  var FileEventSink;
81035
81215
  var init_event_sink = __esm({
81036
81216
  "../host/src/modules/taskflow/workflows/runtime/event-sink.ts"() {
@@ -81042,7 +81222,7 @@ var init_event_sink = __esm({
81042
81222
  listeners;
81043
81223
  clock;
81044
81224
  constructor(runId, opts = {}) {
81045
- 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" });
81046
81226
  this.listeners = opts.listeners ?? [];
81047
81227
  this.clock = opts.clock ?? (() => globalThis.Date.now());
81048
81228
  }
@@ -81144,15 +81324,15 @@ var init_semaphore = __esm({
81144
81324
  });
81145
81325
 
81146
81326
  // ../host/src/modules/taskflow/workflows/runtime/transcript.ts
81147
- import { join as join28 } from "node:path";
81327
+ import { join as join29 } from "node:path";
81148
81328
  function agentsDir(runId, roots = {}) {
81149
- return join28(runDir(runId, roots), "agents");
81329
+ return join29(runDir(runId, roots), "agents");
81150
81330
  }
81151
81331
  function agentTranscriptPath(runId, index, roots = {}) {
81152
- return join28(agentsDir(runId, roots), `${index}.jsonl`);
81332
+ return join29(agentsDir(runId, roots), `${index}.jsonl`);
81153
81333
  }
81154
81334
  function agentTranscriptPathByName(runId, name, roots = {}) {
81155
- return join28(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81335
+ return join29(agentsDir(runId, roots), `${sanitizeName(name)}.jsonl`);
81156
81336
  }
81157
81337
  function truncate2(s, max) {
81158
81338
  if (s.length <= max) return s;
@@ -81241,8 +81421,8 @@ var init_transcript = __esm({
81241
81421
 
81242
81422
  // ../host/src/modules/taskflow/workflows/runtime/worktree.ts
81243
81423
  import { execFile } from "node:child_process";
81244
- import { existsSync as existsSync11, rmSync as rmSync3 } from "node:fs";
81245
- 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";
81246
81426
  import { promisify as promisify3 } from "node:util";
81247
81427
  async function git3(cwd, args) {
81248
81428
  const { stdout: stdout2 } = await exec("git", args, { cwd, maxBuffer: 64 * 1024 * 1024 });
@@ -81258,7 +81438,7 @@ async function findGitRoot(cwd) {
81258
81438
  async function createWorktree(args) {
81259
81439
  const name = `${args.runId}-${args.index}`;
81260
81440
  const branch = args.branch ?? `aw/${name}`;
81261
- const path7 = join29(projectPaths(args.gitRoot).worktrees, name);
81441
+ const path7 = join30(projectPaths(args.gitRoot).worktrees, name);
81262
81442
  const base2 = await git3(args.gitRoot, ["rev-parse", "HEAD"]);
81263
81443
  await pruneStaleWorktree(args.gitRoot, path7);
81264
81444
  await git3(args.gitRoot, ["worktree", "add", "--relative-paths", "--detach", path7, base2]);
@@ -81280,7 +81460,7 @@ async function pruneStaleWorktree(gitRoot2, path7) {
81280
81460
  });
81281
81461
  await git3(gitRoot2, ["worktree", "prune"]).catch(() => {
81282
81462
  });
81283
- if (existsSync11(path7)) {
81463
+ if (existsSync12(path7)) {
81284
81464
  try {
81285
81465
  rmSync3(path7, { recursive: true, force: true });
81286
81466
  } catch {
@@ -82013,7 +82193,7 @@ ${e.status === "completed" ? "\u2713" : "\u2717"} ${e.status}${e.error ? `: ${e.
82013
82193
  // ../host/src/modules/taskflow/workflows/runtime/run.ts
82014
82194
  import { createHash as createHash10, randomBytes as randomBytes7 } from "node:crypto";
82015
82195
  import { readFileSync as readFileSync15, writeFileSync as writeFileSync9 } from "node:fs";
82016
- import { join as join30, resolve as resolve19 } from "node:path";
82196
+ import { join as join31, resolve as resolve19 } from "node:path";
82017
82197
  async function runWorkflow(opts) {
82018
82198
  const filePath = resolve19(opts.file);
82019
82199
  const source = readFileSync15(filePath, "utf8");
@@ -82073,7 +82253,7 @@ async function runWorkflow(opts) {
82073
82253
  if (opts.signal?.aborted) ac.abort();
82074
82254
  else opts.signal?.addEventListener("abort", onSig, { once: true });
82075
82255
  events.emit({ type: "run", status: "started", runId, workflowFile: filePath });
82076
- const heartbeatFile = join30(runDir(runId, opts.roots), ".heartbeat");
82256
+ const heartbeatFile = join31(runDir(runId, opts.roots), ".heartbeat");
82077
82257
  const beat = () => {
82078
82258
  try {
82079
82259
  writeFileSync9(heartbeatFile, String(Date.now()));
@@ -83274,9 +83454,9 @@ var init_environment_diagnostics_service = __esm({
83274
83454
  });
83275
83455
 
83276
83456
  // ../host/src/modules/taskflow/services/environment-worker-factory.ts
83277
- 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";
83278
83458
  import { tmpdir as tmpdir3 } from "node:os";
83279
- 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";
83280
83460
  function mapAgentSpecToEnvironment(spec, hostWorkspace, containerWorkspace) {
83281
83461
  const suffix = relative5(hostWorkspace, spec.cwd);
83282
83462
  if (suffix.startsWith("..")) {
@@ -83329,12 +83509,12 @@ var init_environment_worker_factory = __esm({
83329
83509
  this.handle = handle2;
83330
83510
  const containerWorkspace = handle2.workspace.containerPath;
83331
83511
  if (!containerWorkspace) throw new Error(`Environment has no container workspace: ${handle2.id}`);
83332
- this.directory = mkdtempSync2(join31(tmpdir3(), "taskflow-environment-workers-"));
83512
+ this.directory = mkdtempSync2(join32(tmpdir3(), "taskflow-environment-workers-"));
83333
83513
  const paths3 = Object.fromEntries(
83334
83514
  Object.entries(executableByProvider).map(([provider, executable2]) => {
83335
- const path7 = join31(this.directory, provider);
83515
+ const path7 = join32(this.directory, provider);
83336
83516
  writeFileSync10(path7, transport.executableShim(handle2, executable2), { encoding: "utf8", mode: 448 });
83337
- chmodSync6(path7, 448);
83517
+ chmodSync7(path7, 448);
83338
83518
  return [provider, path7];
83339
83519
  })
83340
83520
  );
@@ -84406,7 +84586,7 @@ var init_run_presentation_service = __esm({
84406
84586
  });
84407
84587
 
84408
84588
  // ../host/src/modules/taskflow/services/workspace-facade.ts
84409
- import { join as join32 } from "node:path";
84589
+ import { join as join33 } from "node:path";
84410
84590
  function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, baseCommit, workspace2, access5) {
84411
84591
  const segment3 = runId.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "run";
84412
84592
  if (workspace2.strategy !== "isolated_worktree") {
@@ -84423,7 +84603,7 @@ function workspaceBindingFor(runId, projectRoot2, workspaceRoot, baseBranch, bas
84423
84603
  };
84424
84604
  }
84425
84605
  const name = `${APP_SLUG}-run-${segment3}`;
84426
- const path7 = join32(workspaceRoot, name);
84606
+ const path7 = join33(workspaceRoot, name);
84427
84607
  return {
84428
84608
  workspaceId: `workspace_${runId}`,
84429
84609
  path: path7,
@@ -84441,7 +84621,7 @@ function slugSegment(value3, fallback) {
84441
84621
  function forkBindingFor(run2, workspaceRoot, slug2) {
84442
84622
  const runSegment = slugSegment(run2.id, "run");
84443
84623
  const forkSegment = slugSegment(slug2, "fork");
84444
- const path7 = join32(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84624
+ const path7 = join33(workspaceRoot, `${APP_SLUG}-run-${runSegment}-fork-${forkSegment}`);
84445
84625
  return {
84446
84626
  workspaceId: `workspace_lease_${run2.id}_${forkSegment}`,
84447
84627
  path: path7,
@@ -84743,7 +84923,7 @@ var init_workspace_facade = __esm({
84743
84923
 
84744
84924
  // ../host/src/modules/taskflow/services/run-service.ts
84745
84925
  import { readFile as readFile9 } from "node:fs/promises";
84746
- import { join as join33 } from "node:path";
84926
+ import { join as join34 } from "node:path";
84747
84927
  function provisioningReason(reason) {
84748
84928
  return reason === "branch_conflict" || reason === "workspace_path_conflict" || reason === "checkout_busy" || reason === "dirty_workspace" || reason === "detached_head" ? reason : "workspace_provision_failed";
84749
84929
  }
@@ -85402,7 +85582,7 @@ var init_run_service = __esm({
85402
85582
  root2,
85403
85583
  terminal.cursor,
85404
85584
  terminal.type === "completed" ? "completed" : active.cancelling ? "cancelled" : "failed",
85405
- 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
85406
85586
  );
85407
85587
  const completedAt = this.now().toISOString();
85408
85588
  if (terminal.type === "completed") {
@@ -85514,7 +85694,7 @@ var init_run_service = __esm({
85514
85694
  async completedResult(engineRunId, dataRoot2) {
85515
85695
  try {
85516
85696
  const result = JsonValueSchema.safeParse(
85517
- JSON.parse(await readFile9(join33(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85697
+ JSON.parse(await readFile9(join34(dataRoot2, "runs", engineRunId, "result.json"), "utf8"))
85518
85698
  );
85519
85699
  return result.success ? result.data : null;
85520
85700
  } catch {
@@ -85919,7 +86099,7 @@ var init_taskflow_direct_session_service = __esm({
85919
86099
  // ../host/src/modules/taskflow/services/workflow-catalog-service.ts
85920
86100
  import { createHash as createHash11 } from "node:crypto";
85921
86101
  import { readdir as readdir4, readFile as readFile10, stat as stat4 } from "node:fs/promises";
85922
- import { join as join34, resolve as resolve21 } from "node:path";
86102
+ import { join as join35, resolve as resolve21 } from "node:path";
85923
86103
  function hash3(value3) {
85924
86104
  return `sha256:${createHash11("sha256").update(value3).digest("hex")}`;
85925
86105
  }
@@ -85963,7 +86143,7 @@ function duplicateDiagnostic(name, origin) {
85963
86143
  function rootsFor(config3) {
85964
86144
  return [
85965
86145
  { origin: "project", directory: projectPaths(resolve21(config3.projectRoot)).workflows, priority: 0 },
85966
- { 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 },
85967
86147
  { origin: "builtin", directory: resolve21(config3.builtinRoot), priority: 2 }
85968
86148
  ];
85969
86149
  }
@@ -86077,7 +86257,7 @@ var init_workflow_catalog_service = __esm({
86077
86257
  return { candidates, diagnostics, invalidEntries };
86078
86258
  }
86079
86259
  for (const name of names) {
86080
- const path7 = join34(root2.directory, name);
86260
+ const path7 = join35(root2.directory, name);
86081
86261
  try {
86082
86262
  if ((await stat4(path7)).size > MAX_WORKFLOW_BYTES2) {
86083
86263
  const diagnostic = {
@@ -86122,7 +86302,7 @@ var init_workflow_catalog_service = __esm({
86122
86302
  });
86123
86303
 
86124
86304
  // ../host/src/modules/taskflow/services/workflow-event-bridge.ts
86125
- import { join as join35 } from "node:path";
86305
+ import { join as join36 } from "node:path";
86126
86306
  function record5(value3) {
86127
86307
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) return null;
86128
86308
  const output2 = {};
@@ -86212,7 +86392,7 @@ function executionFor(run2, existing, details, context) {
86212
86392
  key: details.key,
86213
86393
  index: details.index,
86214
86394
  phaseIndex: details.phaseIndex,
86215
- 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
86216
86396
  },
86217
86397
  workspaceId: run2.workspaceId,
86218
86398
  input: existing?.input ?? null,
@@ -86280,7 +86460,7 @@ var init_workflow_event_bridge = __esm({
86280
86460
 
86281
86461
  // ../host/src/modules/taskflow/services/workflow-runner.ts
86282
86462
  import { mkdir as mkdir5, writeFile as writeFile8 } from "node:fs/promises";
86283
- import { join as join36 } from "node:path";
86463
+ import { join as join37 } from "node:path";
86284
86464
  function envelope(spec, message) {
86285
86465
  return {
86286
86466
  ...message,
@@ -86320,9 +86500,9 @@ var init_workflow_runner = __esm({
86320
86500
  const pid = process.pid;
86321
86501
  let heartbeat;
86322
86502
  const done = (async () => {
86323
- const runDirectory = join36(spec.spec.dataRoot, "runs", spec.engineRunId);
86503
+ const runDirectory = join37(spec.spec.dataRoot, "runs", spec.engineRunId);
86324
86504
  await mkdir5(runDirectory, { recursive: true });
86325
- const snapshotPath = join36(runDirectory, "workflow.js");
86505
+ const snapshotPath = join37(runDirectory, "workflow.js");
86326
86506
  await writeFile8(snapshotPath, spec.spec.source, "utf8");
86327
86507
  emit(envelope(spec, { type: "started", pid }));
86328
86508
  heartbeat = setInterval(() => {
@@ -87009,15 +87189,15 @@ var init_worktree_conversation_service = __esm({
87009
87189
 
87010
87190
  // ../host/src/modules/taskflow/adapters/docker-compose-environment.ts
87011
87191
  import { createHash as createHash12 } from "node:crypto";
87012
- import { existsSync as existsSync12, readFileSync as readFileSync16 } from "node:fs";
87192
+ import { existsSync as existsSync13, readFileSync as readFileSync16 } from "node:fs";
87013
87193
  import { resolve as resolve22 } from "node:path";
87014
87194
  function composeFile(workspacePath, configured) {
87015
87195
  if (configured) {
87016
87196
  const candidate = resolve22(workspacePath, configured);
87017
- if (existsSync12(candidate)) return candidate;
87197
+ if (existsSync13(candidate)) return candidate;
87018
87198
  throw new Error(`Docker Compose file does not exist: ${configured}`);
87019
87199
  }
87020
- const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync12);
87200
+ const found = COMPOSE_FILENAMES.map((file2) => resolve22(workspacePath, file2)).find(existsSync13);
87021
87201
  if (!found) throw new Error("No Docker Compose file was found");
87022
87202
  return found;
87023
87203
  }
@@ -87046,7 +87226,7 @@ var init_docker_compose_environment = __esm({
87046
87226
  }
87047
87227
  async probe(context) {
87048
87228
  const version3 = await runCaptured(this.runner, { command: "docker", args: ["compose", "version", "--short"] });
87049
- 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);
87050
87230
  return {
87051
87231
  provider: this.id,
87052
87232
  available: version3.exit.code === 0 && configs.length > 0,
@@ -88393,8 +88573,8 @@ var init_project_environments = __esm({
88393
88573
  // ../host/src/modules/taskflow/server/project-app.ts
88394
88574
  import { spawn as spawn8 } from "node:child_process";
88395
88575
  import { randomUUID as randomUUID6 } from "node:crypto";
88396
- import { existsSync as existsSync13 } from "node:fs";
88397
- 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";
88398
88578
  import { fileURLToPath as fileURLToPath5 } from "node:url";
88399
88579
  function workflowAgentRuntimeConfig(value3) {
88400
88580
  if (typeof value3 !== "object" || value3 === null || Array.isArray(value3)) {
@@ -88425,7 +88605,7 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88425
88605
  const reconciliationService = runtime2.reconciliationService;
88426
88606
  const codexAppServerClient = new CodexAppServerClient({
88427
88607
  clientName: RUNTIME_IDENTITY.codexClientName,
88428
- clientVersion: "0.0.0"
88608
+ clientVersion: PORTTA_FLOW_VERSION
88429
88609
  });
88430
88610
  const claudeCliClient = new ClaudeCliClient();
88431
88611
  const worktreeConversationService = new WorktreeConversationService({
@@ -88478,14 +88658,14 @@ function createProjectApp(runtime2, instancePrefix, host2) {
88478
88658
  const workflowEvents = new WorkflowEventBridge({ store: runStore, publisher: runEventPublisher });
88479
88659
  const workspaces = new WorkspaceFacade({ store: runStore, git: git4 });
88480
88660
  const workflowDataRoot = globalPaths().root;
88481
- const supervisorSocket = join37(workflowDataRoot, "runtime", "supervisor.sock");
88661
+ const supervisorSocket = join38(workflowDataRoot, "runtime", "supervisor.sock");
88482
88662
  const supervisor = new AgentSupervisorClient({
88483
88663
  socketPath: supervisorSocket,
88484
88664
  startDaemon: () => {
88485
88665
  const directory = dirname20(fileURLToPath5(import.meta.url));
88486
- const builtEntry = join37(directory, "supervisor.js");
88487
- const sourceEntry = join37(directory, "supervisor.ts");
88488
- 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" });
88489
88669
  child.unref();
88490
88670
  }
88491
88671
  });
@@ -89928,7 +90108,7 @@ var init_upgrade = __esm({
89928
90108
  });
89929
90109
 
89930
90110
  // ../host/src/modules/taskflow/server/host.ts
89931
- import { existsSync as existsSync14 } from "node:fs";
90111
+ import { existsSync as existsSync15 } from "node:fs";
89932
90112
  function createTaskflowHost(options) {
89933
90113
  const apps = /* @__PURE__ */ new Map();
89934
90114
  const manager = new ProjectManager({
@@ -89958,8 +90138,8 @@ function createTaskflowHost(options) {
89958
90138
  manager,
89959
90139
  apps,
89960
90140
  allowlist: options.projectAllowlist,
89961
- // Tracks leftover on-add setup records for API compatibility. Registration
89962
- // 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.
89963
90143
  initTracker: new ProjectInitTracker(),
89964
90144
  closeSockets: (prefix) => sockets.closeProject(prefix)
89965
90145
  });
@@ -89972,7 +90152,7 @@ function createTaskflowHost(options) {
89972
90152
  if (!isGitRepo(cwd)) return;
89973
90153
  const repoRoot = canonicalizeFsPath(projectRoot(cwd));
89974
90154
  const paths3 = projectPaths(repoRoot);
89975
- if (!existsSync14(paths3.config) && !existsSync14(paths3.localConfig)) return;
90155
+ if (!existsSync15(paths3.config) && !existsSync15(paths3.localConfig)) return;
89976
90156
  try {
89977
90157
  manager.addEphemeral(repoRoot);
89978
90158
  } catch (err2) {
@@ -89987,7 +90167,7 @@ function createTaskflowHost(options) {
89987
90167
  }
89988
90168
  };
89989
90169
  }
89990
- var init_host2 = __esm({
90170
+ var init_host = __esm({
89991
90171
  "../host/src/modules/taskflow/server/host.ts"() {
89992
90172
  "use strict";
89993
90173
  init_paths2();
@@ -90043,7 +90223,7 @@ function createDaemonTaskflowHost(context) {
90043
90223
  port: hostListen(env).port,
90044
90224
  workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
90045
90225
  version: env.PORTTA_VERSION || "0.0.0-local",
90046
- buildDate: true ? "2026-09-18T00:48:59Z" : (/* @__PURE__ */ new Date()).toISOString(),
90226
+ buildDate: true ? "2026-09-18T02:24:34Z" : (/* @__PURE__ */ new Date()).toISOString(),
90047
90227
  environmentStore: createEnvironmentStore(paths3.database),
90048
90228
  hostEnvironmentProvider: new HostEnvironmentProvider(),
90049
90229
  devContainerProvider: new DevContainerProvider(),
@@ -90114,9 +90294,8 @@ var init_taskflow4 = __esm({
90114
90294
  init_user_shell_env();
90115
90295
  init_environment_service_discovery();
90116
90296
  init_project_allowlist();
90117
- init_host2();
90297
+ init_host();
90118
90298
  init_host_projects();
90119
- init_runtime();
90120
90299
  TASKFLOW_SOCKET_MOUNT_PATH = `/ws/modules/${taskflowModule.id}`;
90121
90300
  taskflowHostModule = createTaskflowHostModule();
90122
90301
  }
@@ -90990,7 +91169,7 @@ var require_util2 = __commonJS({
90990
91169
  function getFilesInPath(source) {
90991
91170
  const lstatSync = fs.lstatSync;
90992
91171
  const readdirSync11 = fs.readdirSync;
90993
- const join70 = path7.join;
91172
+ const join71 = path7.join;
90994
91173
  function isDirectory2(source2) {
90995
91174
  return lstatSync(source2).isDirectory();
90996
91175
  }
@@ -90999,12 +91178,12 @@ var require_util2 = __commonJS({
90999
91178
  }
91000
91179
  function getDirectories(source2) {
91001
91180
  return readdirSync11(source2).map((name) => {
91002
- return join70(source2, name);
91181
+ return join71(source2, name);
91003
91182
  }).filter(isDirectory2);
91004
91183
  }
91005
91184
  function getFiles(source2) {
91006
91185
  return readdirSync11(source2).map((name) => {
91007
- return join70(source2, name);
91186
+ return join71(source2, name);
91008
91187
  }).filter(isFile);
91009
91188
  }
91010
91189
  function getFilesRecursively(source2) {
@@ -100639,7 +100818,7 @@ var require_network = __commonJS({
100639
100818
  var exec3 = __require("child_process").exec;
100640
100819
  var execSync = __require("child_process").execSync;
100641
100820
  var execFileSync2 = __require("child_process").execFileSync;
100642
- var readFileSync38 = __require("fs").readFileSync;
100821
+ var readFileSync37 = __require("fs").readFileSync;
100643
100822
  var fs = __require("fs");
100644
100823
  var util2 = require_util2();
100645
100824
  var _platform = process.platform;
@@ -101127,7 +101306,7 @@ var require_network = __commonJS({
101127
101306
  return result;
101128
101307
  }
101129
101308
  try {
101130
- const content = readFileSync38(file2, { encoding: "utf8" });
101309
+ const content = readFileSync37(file2, { encoding: "utf8" });
101131
101310
  const lines = content.split("\n").filter((l) => /iface|source/.test(l));
101132
101311
  lines.forEach((line4) => {
101133
101312
  const parts2 = line4.replace(/\s+/g, " ").trim().split(" ");
@@ -101294,7 +101473,7 @@ var require_network = __commonJS({
101294
101473
  return false;
101295
101474
  }
101296
101475
  }
101297
- function networkInterfaces2(callback, rescan, defaultString) {
101476
+ function networkInterfaces(callback, rescan, defaultString) {
101298
101477
  if (typeof callback === "string") {
101299
101478
  defaultString = callback;
101300
101479
  rescan = true;
@@ -101709,7 +101888,7 @@ var require_network = __commonJS({
101709
101888
  });
101710
101889
  });
101711
101890
  }
101712
- exports.networkInterfaces = networkInterfaces2;
101891
+ exports.networkInterfaces = networkInterfaces;
101713
101892
  function calcNetworkSpeed(iface, rx_bytes, tx_bytes, operstate, rx_dropped, rx_errors, tx_dropped, tx_errors) {
101714
101893
  const result = {
101715
101894
  iface,
@@ -101782,7 +101961,7 @@ var require_network = __commonJS({
101782
101961
  const workload = [];
101783
101962
  if (ifacesArray.length && ifacesArray[0].trim() === "*") {
101784
101963
  ifacesArray = [];
101785
- networkInterfaces2(false).then((allIFaces) => {
101964
+ networkInterfaces(false).then((allIFaces) => {
101786
101965
  for (let iface of allIFaces) {
101787
101966
  ifacesArray.push(iface.iface);
101788
101967
  }
@@ -101948,7 +102127,7 @@ var require_network = __commonJS({
101948
102127
  const psections = stdout2.toString().split(/\n\s*\n/);
101949
102128
  perfData = parseLinesWindowsPerfData(psections);
101950
102129
  }
101951
- networkInterfaces2(false).then((interfaces) => {
102130
+ networkInterfaces(false).then((interfaces) => {
101952
102131
  rx_bytes = 0;
101953
102132
  tx_bytes = 0;
101954
102133
  perfData.forEach((detail2) => {
@@ -103405,7 +103584,7 @@ var require_processes = __commonJS({
103405
103584
  }
103406
103585
  exec3(cmd, { maxBuffer: 1024 * 102400 }, function(error61, stdout3) {
103407
103586
  let curr_processes = stdout3.toString().split("\n");
103408
- let all = parseProcStat2(curr_processes.shift());
103587
+ let all = parseProcStat(curr_processes.shift());
103409
103588
  let list_new = {};
103410
103589
  let resultProcess = {};
103411
103590
  curr_processes.forEach((element) => {
@@ -103583,7 +103762,7 @@ var require_processes = __commonJS({
103583
103762
  });
103584
103763
  }
103585
103764
  exports.services = services;
103586
- function parseProcStat2(line4) {
103765
+ function parseProcStat(line4) {
103587
103766
  const parts2 = line4.replace(/ +/g, " ").split(" ");
103588
103767
  const user = parts2.length >= 2 ? parseInt(parts2[1]) : 0;
103589
103768
  const nice = parts2.length >= 3 ? parseInt(parts2[2]) : 0;
@@ -103923,7 +104102,7 @@ var require_processes = __commonJS({
103923
104102
  });
103924
104103
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error62, stdout3) => {
103925
104104
  let curr_processes = stdout3.toString().split("\n");
103926
- let all = parseProcStat2(curr_processes.shift());
104105
+ let all = parseProcStat(curr_processes.shift());
103927
104106
  let list_new = {};
103928
104107
  let resultProcess = {};
103929
104108
  curr_processes.forEach((element) => {
@@ -104378,7 +104557,7 @@ var require_processes = __commonJS({
104378
104557
  }
104379
104558
  exec3(cmd, { maxBuffer: 1024 * 102400 }, (error61, stdout3) => {
104380
104559
  let curr_processes = stdout3.toString().split("\n");
104381
- let all = parseProcStat2(curr_processes.shift());
104560
+ let all = parseProcStat(curr_processes.shift());
104382
104561
  let list_new = {};
104383
104562
  let resultProcess = {};
104384
104563
  curr_processes.forEach((element) => {
@@ -108452,7 +108631,7 @@ var require_lib = __commonJS({
108452
108631
  });
108453
108632
 
108454
108633
  // src/commands/flow/daemon.ts
108455
- import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
108634
+ import { existsSync as existsSync25, readFileSync as readFileSync23 } from "node:fs";
108456
108635
  function flowStateDir(env = process.env) {
108457
108636
  const configured = env[ENV_NAMES.hostStateDir]?.trim();
108458
108637
  if (configured) return configured;
@@ -108470,7 +108649,7 @@ function daemonToken(env = process.env) {
108470
108649
  const file2 = hostTokenFile(flowStateDir(env));
108471
108650
  if (existsSync25(file2)) {
108472
108651
  try {
108473
- const token = readFileSync24(file2, "utf8").trim();
108652
+ const token = readFileSync23(file2, "utf8").trim();
108474
108653
  if (token) return token;
108475
108654
  } catch {
108476
108655
  }
@@ -108573,8 +108752,8 @@ var init_server_port = __esm({
108573
108752
 
108574
108753
  // ../host/src/modules/taskflow/lib/shell.ts
108575
108754
  import { spawnSync as spawnSync8 } from "node:child_process";
108576
- import { existsSync as existsSync26, readFileSync as readFileSync25 } from "node:fs";
108577
- 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";
108578
108757
  function run(cmd, args, opts) {
108579
108758
  const resolved2 = resolveHostTool(cmd) ?? cmd;
108580
108759
  const result = spawnSync8(resolved2, args, {
@@ -108594,10 +108773,10 @@ function getGitRoot() {
108594
108773
  return result.stdout.toString().trim();
108595
108774
  }
108596
108775
  function detectProjectName(gitRoot2) {
108597
- const pkgPath = join48(gitRoot2, "package.json");
108776
+ const pkgPath = join49(gitRoot2, "package.json");
108598
108777
  if (existsSync26(pkgPath)) {
108599
108778
  try {
108600
- const pkg = JSON.parse(readFileSync25(pkgPath, "utf-8"));
108779
+ const pkg = JSON.parse(readFileSync24(pkgPath, "utf-8"));
108601
108780
  if (pkg.name) return pkg.name;
108602
108781
  } catch {
108603
108782
  }
@@ -108752,36 +108931,6 @@ var init_project_env2 = __esm({
108752
108931
  }
108753
108932
  });
108754
108933
 
108755
- // src/commands/flow/process.ts
108756
- async function runProcess3(file2, args = [], options = {}) {
108757
- const execaOptions = {
108758
- cwd: options.cwd,
108759
- env: options.env,
108760
- input: options.input,
108761
- reject: options.reject ?? true,
108762
- shell: false,
108763
- timeout: options.timeout,
108764
- stdio: options.input !== void 0 ? ["pipe", options.stdio ?? "pipe", options.stdio ?? "pipe"] : options.stdio
108765
- };
108766
- const result = await execa(file2, [...args], execaOptions);
108767
- const notStarted = result.failed && result.exitCode === void 0 && !result.signal && !result.timedOut;
108768
- return {
108769
- stdout: typeof result.stdout === "string" ? result.stdout : "",
108770
- stderr: typeof result.stderr === "string" ? result.stderr : "",
108771
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
108772
- failed: result.failed,
108773
- ...notStarted && "originalMessage" in result ? { error: String(result.originalMessage) } : {}
108774
- };
108775
- }
108776
- var PROCESS_POLICY2;
108777
- var init_process = __esm({
108778
- "src/commands/flow/process.ts"() {
108779
- "use strict";
108780
- init_execa();
108781
- PROCESS_POLICY2 = Object.freeze({ shell: false, argumentArraysOnly: true });
108782
- }
108783
- });
108784
-
108785
108934
  // src/commands/flow/completions.ts
108786
108935
  var completions_exports = {};
108787
108936
  __export(completions_exports, {
@@ -108814,7 +108963,7 @@ function completionTree(command) {
108814
108963
  };
108815
108964
  }
108816
108965
  async function defaultRunGit(args) {
108817
- const result = await runProcess3("git", args, { reject: false });
108966
+ const result = await runProcess("git", args, { reject: false });
108818
108967
  return { exitCode: result.exitCode, stdout: result.stdout.trim() };
108819
108968
  }
108820
108969
  async function listWorktreeBranches(deps = { runGit: defaultRunGit }) {
@@ -110103,9 +110252,9 @@ ${f}
110103
110252
  });
110104
110253
 
110105
110254
  // ../host/src/modules/taskflow/services/init-authoring.ts
110106
- 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";
110107
110256
  import { tmpdir as tmpdir4 } from "node:os";
110108
- import { join as join49 } from "node:path";
110257
+ import { join as join50 } from "node:path";
110109
110258
  function isRecord8(value3) {
110110
110259
  return typeof value3 === "object" && value3 !== null && !Array.isArray(value3);
110111
110260
  }
@@ -110113,9 +110262,9 @@ function readString4(value3) {
110113
110262
  return typeof value3 === "string" && value3.trim().length > 0 ? value3 : null;
110114
110263
  }
110115
110264
  function detectPackageManager(gitRoot2) {
110116
- if (existsSync28(join49(gitRoot2, "bun.lock")) || existsSync28(join49(gitRoot2, "bun.lockb"))) return "bun";
110117
- if (existsSync28(join49(gitRoot2, "pnpm-lock.yaml"))) return "pnpm";
110118
- 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";
110119
110268
  return "npm";
110120
110269
  }
110121
110270
  function detectMainBranch(gitRoot2) {
@@ -110152,25 +110301,25 @@ function detectInitProjectContext(gitRoot2, defaultAgent) {
110152
110301
  }
110153
110302
  function detectInitEnvironment(gitRoot2, requested = "auto") {
110154
110303
  const devcontainerConfigs = [".devcontainer.json", ".devcontainer/devcontainer.json"].filter(
110155
- (path7) => existsSync28(join49(gitRoot2, path7))
110304
+ (path7) => existsSync28(join50(gitRoot2, path7))
110156
110305
  );
110157
110306
  const composeFiles2 = ["compose.yaml", "compose.yml", "docker-compose.yaml", "docker-compose.yml"].filter(
110158
- (path7) => existsSync28(join49(gitRoot2, path7))
110307
+ (path7) => existsSync28(join50(gitRoot2, path7))
110159
110308
  );
110160
- 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";
110161
110310
  return {
110162
110311
  devcontainerConfigs,
110163
110312
  composeFiles: composeFiles2,
110164
- dockerfile: existsSync28(join49(gitRoot2, "Dockerfile")),
110165
- packageJson: existsSync28(join49(gitRoot2, "package.json")),
110313
+ dockerfile: existsSync28(join50(gitRoot2, "Dockerfile")),
110314
+ packageJson: existsSync28(join50(gitRoot2, "package.json")),
110166
110315
  selectedRuntime
110167
110316
  };
110168
110317
  }
110169
110318
  function buildInitPromptSpec(context) {
110170
110319
  const systemPrompt = [
110171
110320
  `You are bootstrapping a local repository for ${APP_NAME}.`,
110172
- `A starter \`${PROJECT_CONFIG_PATH}\` already exists at the repo root.`,
110173
- `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.`,
110174
110323
  "Do not modify any other file.",
110175
110324
  "Do not ask the user questions. Infer the config from the repository contents.",
110176
110325
  "Be efficient: inspect only the files needed to determine the project name, main branch, service layout, dev commands, and ports.",
@@ -110183,7 +110332,7 @@ function buildInitPromptSpec(context) {
110183
110332
  "workspace.mainBranch: infer from git",
110184
110333
  `workspace.worktrees.root: keep ${APP_DEFAULTS.worktreeRoot} unless there is clear evidence of an existing alternative`,
110185
110334
  "Do not copy detected Compose services or ports into config unless the user needs an explicit override.",
110186
- "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.",
110187
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.",
110188
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.",
110189
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.",
@@ -110195,11 +110344,11 @@ function buildInitPromptSpec(context) {
110195
110344
  "Only include optional sections like auto_name, lifecycleHooks, sandbox/docker config, mounts, or systemPrompt if the repository gives clear evidence they are needed.",
110196
110345
  "Prefer editing the existing keys over replacing the file with a completely different shape.",
110197
110346
  "Preserve the existing template structure and comments unless a specific change requires updating them.",
110198
- `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.`
110199
110348
  ].join("\n");
110200
110349
  return {
110201
110350
  systemPrompt,
110202
- userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH}\` for this repository.`
110351
+ userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH2}\` for this repository.`
110203
110352
  };
110204
110353
  }
110205
110354
  function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`) {
@@ -110228,7 +110377,7 @@ function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`)
110228
110377
  ]
110229
110378
  };
110230
110379
  }
110231
- 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`);
110232
110381
  return {
110233
110382
  agent,
110234
110383
  cmd: "codex",
@@ -110484,7 +110633,7 @@ function finalizeAgentRun(spec, exitCode, stdoutResult, stderr2) {
110484
110633
  let summary = stdoutResult.assistantText.trim();
110485
110634
  if (spec.summaryPath && existsSync28(spec.summaryPath)) {
110486
110635
  try {
110487
- summary = readFileSync26(spec.summaryPath, "utf8").trim() || summary;
110636
+ summary = readFileSync25(spec.summaryPath, "utf8").trim() || summary;
110488
110637
  } finally {
110489
110638
  rmSync8(spec.summaryPath, { force: true });
110490
110639
  }
@@ -110519,7 +110668,7 @@ workspace:
110519
110668
  # intervalSeconds: 300
110520
110669
 
110521
110670
  # Taskflow discovers Dev Container, Compose, and Dockerfile services from the resolved runtime.
110522
- # 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
110523
110672
  # that accepts an injected port environment variable. Do not duplicate discovered services.
110524
110673
  services:
110525
110674
  # Example app service with a predictable port per worktree.
@@ -110545,8 +110694,8 @@ exposure:
110545
110694
  # Profiles define runtime, permissions, and tmux pane layout.
110546
110695
  profiles:
110547
110696
  default:
110548
- # Legacy panes run on the host; the environment provider controls the
110549
- # 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.
110550
110699
  runtime: host
110551
110700
  environment:
110552
110701
  provider: ${environmentProvider}
@@ -110751,13 +110900,13 @@ var init_init_deps = __esm({
110751
110900
  tool: "claude",
110752
110901
  args: ["--version"],
110753
110902
  required: false,
110754
- 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}`
110755
110904
  },
110756
110905
  {
110757
110906
  tool: "codex",
110758
110907
  args: ["--version"],
110759
110908
  required: false,
110760
- 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}`
110761
110910
  },
110762
110911
  { tool: "docker", args: ["--version"], required: false, hint: "https://docs.docker.com/get-started/get-docker/" }
110763
110912
  ];
@@ -110962,7 +111111,7 @@ async function runInit(options) {
110962
111111
  let selectedAnalyze = resolveInitAnalysis(options, selectedRuntime);
110963
111112
  const configExists = existsSync29(taskflowYaml);
110964
111113
  if (configExists) {
110965
- log2.info(`${PROJECT_CONFIG_PATH} already exists`);
111114
+ log2.info(`${PROJECT_CONFIG_PATH2} already exists`);
110966
111115
  } else if (needsInteractiveAnalysisFallback(options, selectedRuntime)) {
110967
111116
  selectedAnalyze = await selectFallbackAgent();
110968
111117
  }
@@ -110983,7 +111132,7 @@ async function runInit(options) {
110983
111132
  environmentProvider: detection.selectedRuntime
110984
111133
  })
110985
111134
  );
110986
- log2.success(`${PROJECT_CONFIG_PATH} created from deterministic detection`);
111135
+ log2.success(`${PROJECT_CONFIG_PATH2} created from deterministic detection`);
110987
111136
  } else {
110988
111137
  const available2 = isInitAgentSelectable(
110989
111138
  depStatuses.find((status) => status.tool === selectedAnalyze) ?? { found: false }
@@ -111006,11 +111155,11 @@ async function runInit(options) {
111006
111155
  const prompt = buildInitPromptSpec({ ...context, defaultAgent: selectedAnalyze });
111007
111156
  const command = buildInitAgentCommand(selectedAnalyze, prompt);
111008
111157
  const streamPrinter = createAgentStreamPrinter(label3);
111009
- log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH}...`);
111158
+ log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH2}...`);
111010
111159
  const result = await runInitAgentCommand(command, gitRoot2, { onEvent: streamPrinter.onEvent });
111011
111160
  streamPrinter.finish();
111012
111161
  if (!existsSync29(taskflowYaml)) {
111013
- log2.error(`${label3} removed ${PROJECT_CONFIG_PATH}`);
111162
+ log2.error(`${label3} removed ${PROJECT_CONFIG_PATH2}`);
111014
111163
  const details = [
111015
111164
  result.summary ? `Summary:
111016
111165
  ${result.summary}` : "",
@@ -111027,12 +111176,12 @@ ${result.stderr.trim()}` : ""
111027
111176
  const finalYaml = await readFile12(taskflowYaml, "utf8");
111028
111177
  const changedTemplate = configExists || finalYaml !== starterTemplate;
111029
111178
  if (result.exitCode === 0 && changedTemplate) {
111030
- log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH}`);
111179
+ log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH2}`);
111031
111180
  } else if (result.exitCode === 0) {
111032
111181
  log2.warning(`${label3} left the starter template unchanged`);
111033
- 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.`);
111034
111183
  } else if (changedTemplate) {
111035
- log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH}`);
111184
+ log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH2}`);
111036
111185
  log2.warning(`${label3} exited with code ${result.exitCode}. Review the generated file before using it.`);
111037
111186
  } else {
111038
111187
  log2.warning(`${label3} left the starter template in place`);
@@ -111055,7 +111204,7 @@ ${result.stderr.trim()}` : ""
111055
111204
  );
111056
111205
  outro("You're all set! Next steps:");
111057
111206
  console.log();
111058
- 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`);
111059
111208
  console.log(" 2. Keep the host daemon running: portta host serve --detach (or portta host service install)");
111060
111209
  console.log(` 3. Enable tab completion: eval "$(${flowInvocation()} completion zsh)" (or bash)`);
111061
111210
  console.log();
@@ -111913,7 +112062,7 @@ import { setTimeout as delay4 } from "node:timers/promises";
111913
112062
  function projectSetupPhaseLabel(phase) {
111914
112063
  switch (phase) {
111915
112064
  case "creating_config":
111916
- return `Creating ${PROJECT_CONFIG_PATH}`;
112065
+ return `Creating ${PROJECT_CONFIG_PATH2}`;
111917
112066
  case "analyzing":
111918
112067
  return "Analyzing project structure";
111919
112068
  case "ready":
@@ -112240,7 +112389,7 @@ async function defaultConfirmPrune(worktreeCount) {
112240
112389
  }
112241
112390
  async function attachToHerdr() {
112242
112391
  if (process.env.HERDR_PANE_ID || process.env.HERDR_ENV) return;
112243
- const result = await runProcess3("herdr", [], { stdio: "inherit", reject: false });
112392
+ const result = await runProcess("herdr", [], { stdio: "inherit", reject: false });
112244
112393
  if (result.exitCode !== 0) {
112245
112394
  console.error("Warning: failed to attach to herdr");
112246
112395
  }
@@ -112263,12 +112412,12 @@ async function defaultSwitchToSessionWindow(projectDir, _branch, multiplexer) {
112263
112412
  }
112264
112413
  const sessionName = buildProjectSessionName(resolve30(projectDir));
112265
112414
  if (process.env.TMUX) {
112266
- const result = await runProcess3("tmux", ["switch-client", "-t", sessionName], { reject: false });
112415
+ const result = await runProcess("tmux", ["switch-client", "-t", sessionName], { reject: false });
112267
112416
  if (result.exitCode !== 0) {
112268
112417
  console.error(`Warning: failed to switch tmux client to ${sessionName}`);
112269
112418
  }
112270
112419
  } else {
112271
- 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 });
112272
112421
  if (result.exitCode !== 0) {
112273
112422
  console.error(`Warning: failed to attach to tmux session ${sessionName}`);
112274
112423
  }
@@ -112736,7 +112885,7 @@ function environmentBaseUrlFromControlUrl(value3) {
112736
112885
  }
112737
112886
  }
112738
112887
  async function runInherited(invocation2) {
112739
- const result = await runProcess3(invocation2.command, invocation2.args, {
112888
+ const result = await runProcess(invocation2.command, invocation2.args, {
112740
112889
  cwd: invocation2.cwd,
112741
112890
  stdio: "inherit",
112742
112891
  reject: false
@@ -112747,7 +112896,7 @@ async function runInherited(invocation2) {
112747
112896
  async function writeClipboard(value3) {
112748
112897
  const command = process.platform === "darwin" ? "pbcopy" : process.platform === "win32" ? "clip" : "xclip";
112749
112898
  const args = process.platform === "linux" ? ["-selection", "clipboard"] : [];
112750
- return (await runProcess3(command, args, { input: value3, reject: false })).exitCode === 0;
112899
+ return (await runProcess(command, args, { input: value3, reject: false })).exitCode === 0;
112751
112900
  }
112752
112901
  async function runEnvironmentCommand(request2, port, projectDir, stdout2 = console.log, stderr2 = console.error, dependencies = defaultEnvironmentCommandDependencies) {
112753
112902
  try {
@@ -112809,7 +112958,7 @@ async function runEnvironmentCommand(request2, port, projectDir, stdout2 = conso
112809
112958
  } else {
112810
112959
  const opener = process.platform === "darwin" ? "open" : process.platform === "win32" ? "cmd" : "xdg-open";
112811
112960
  const openerArgs = process.platform === "win32" ? ["/c", "start", "", endpoint.url] : [endpoint.url];
112812
- if ((await runProcess3(opener, openerArgs, { reject: false })).exitCode !== 0) {
112961
+ if ((await runProcess(opener, openerArgs, { reject: false })).exitCode !== 0) {
112813
112962
  throw new Error("Browser open command failed");
112814
112963
  }
112815
112964
  }
@@ -113074,10 +113223,10 @@ var init_tail = __esm({
113074
113223
  import { createReadStream as createReadStream2, existsSync as existsSync30 } from "node:fs";
113075
113224
  import { readdir as readdir5, readFile as readFile13, realpath as realpath2, stat as stat6, watch } from "node:fs/promises";
113076
113225
  import { createServer as createServer2 } from "node:http";
113077
- 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";
113078
113227
  import { fileURLToPath as fileURLToPath6 } from "node:url";
113079
113228
  function runsDir() {
113080
- return join50(dataRoot(), "runs");
113229
+ return join51(dataRoot(), "runs");
113081
113230
  }
113082
113231
  function parseEvents(text) {
113083
113232
  const out = [];
@@ -113093,7 +113242,7 @@ function parseEvents(text) {
113093
113242
  }
113094
113243
  async function readEvents(runId) {
113095
113244
  try {
113096
- const text = await readFile13(join50(runsDir(), runId, "events.jsonl"), "utf8");
113245
+ const text = await readFile13(join51(runsDir(), runId, "events.jsonl"), "utf8");
113097
113246
  return parseEvents(text);
113098
113247
  } catch {
113099
113248
  return [];
@@ -113195,7 +113344,7 @@ function applyDeadman(status, startedAt, lastBeat) {
113195
113344
  }
113196
113345
  async function heartbeatMtime(runId) {
113197
113346
  try {
113198
- return (await stat6(join50(runsDir(), runId, ".heartbeat"))).mtimeMs;
113347
+ return (await stat6(join51(runsDir(), runId, ".heartbeat"))).mtimeMs;
113199
113348
  } catch {
113200
113349
  return 0;
113201
113350
  }
@@ -113226,7 +113375,7 @@ async function listRuns() {
113226
113375
  seen.add(runId);
113227
113376
  let eventsStat;
113228
113377
  try {
113229
- eventsStat = await stat6(join50(runsDir(), runId, "events.jsonl"));
113378
+ eventsStat = await stat6(join51(runsDir(), runId, "events.jsonl"));
113230
113379
  } catch {
113231
113380
  eventsStat = void 0;
113232
113381
  }
@@ -113242,7 +113391,7 @@ async function listRuns() {
113242
113391
  if (events.length === 0) {
113243
113392
  let mtime = 0;
113244
113393
  try {
113245
- mtime = (await stat6(join50(runsDir(), runId))).mtimeMs;
113394
+ mtime = (await stat6(join51(runsDir(), runId))).mtimeMs;
113246
113395
  } catch {
113247
113396
  }
113248
113397
  summaries.push({ summary: { runId, status: "unknown", agents: 0 }, mtime });
@@ -113269,7 +113418,7 @@ async function listRuns() {
113269
113418
  }
113270
113419
  function serveStatic(res, fileName) {
113271
113420
  const safe2 = normalize3(fileName).replace(/^(\.\.(?:[/\\]|$))+/, "");
113272
- const full = join50(WEB_DIR, safe2);
113421
+ const full = join51(WEB_DIR, safe2);
113273
113422
  if (!full.startsWith(WEB_DIR + sep2) && full !== WEB_DIR) {
113274
113423
  sendText(res, 403, "forbidden");
113275
113424
  return;
@@ -113418,10 +113567,10 @@ function sleepUnlessClosed(ms, isClosed) {
113418
113567
  });
113419
113568
  }
113420
113569
  function streamRun(req, res, runId) {
113421
- return tailJsonl(req, res, join50(runsDir(), runId, "events.jsonl"));
113570
+ return tailJsonl(req, res, join51(runsDir(), runId, "events.jsonl"));
113422
113571
  }
113423
113572
  function streamAgent(req, res, runId, index) {
113424
- return tailJsonl(req, res, join50(runsDir(), runId, "agents", `${index}.jsonl`));
113573
+ return tailJsonl(req, res, join51(runsDir(), runId, "agents", `${index}.jsonl`));
113425
113574
  }
113426
113575
  function parseChunks(text) {
113427
113576
  const out = [];
@@ -113437,7 +113586,7 @@ function parseChunks(text) {
113437
113586
  }
113438
113587
  async function readAgentChunks(runId, index) {
113439
113588
  try {
113440
- const text = await readFile13(join50(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113589
+ const text = await readFile13(join51(runsDir(), runId, "agents", `${index}.jsonl`), "utf8");
113441
113590
  return parseChunks(text);
113442
113591
  } catch {
113443
113592
  return null;
@@ -113501,7 +113650,7 @@ async function handle(req, res) {
113501
113650
  const events = await readEvents(runId);
113502
113651
  if (events.length === 0) {
113503
113652
  try {
113504
- await stat6(join50(runsDir(), runId));
113653
+ await stat6(join51(runsDir(), runId));
113505
113654
  } catch {
113506
113655
  sendJson(res, 404, { error: "run not found", runId });
113507
113656
  return;
@@ -113578,8 +113727,8 @@ var init_serve = __esm({
113578
113727
  init_journal();
113579
113728
  init_tail();
113580
113729
  __dirname = dirname27(fileURLToPath6(import.meta.url));
113581
- WEB_CANDIDATES = [join50(__dirname, "web"), join50(__dirname, "..", "..", "viewer", "dist")];
113582
- 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");
113583
113732
  sseClients = 0;
113584
113733
  STALE_MS = 2e4;
113585
113734
  summaryCache = /* @__PURE__ */ new Map();
@@ -113613,15 +113762,15 @@ import { spawn as spawn9 } from "node:child_process";
113613
113762
  import {
113614
113763
  copyFileSync as copyFileSync3,
113615
113764
  existsSync as existsSync31,
113616
- mkdirSync as mkdirSync17,
113765
+ mkdirSync as mkdirSync18,
113617
113766
  readdirSync as readdirSync5,
113618
- readFileSync as readFileSync27,
113767
+ readFileSync as readFileSync26,
113619
113768
  realpathSync as realpathSync6,
113620
113769
  rmSync as rmSync9,
113621
113770
  statSync as statSync10
113622
113771
  } from "node:fs";
113623
113772
  import { get as httpGet } from "node:http";
113624
- 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";
113625
113774
  import { fileURLToPath as fileURLToPath7 } from "node:url";
113626
113775
  function parseArgs(argv) {
113627
113776
  const flags = { _: [] };
@@ -113725,8 +113874,6 @@ async function main(argv = process.argv.slice(2), options = {}) {
113725
113874
  return cmdValidate(flags, options.registryRoots);
113726
113875
  case "doctor":
113727
113876
  return cmdDoctor();
113728
- case "install-skill":
113729
- return cmdInstallSkillRetired();
113730
113877
  case "guide":
113731
113878
  return cmdGuide(options.skillPath);
113732
113879
  case void 0:
@@ -113756,7 +113903,7 @@ async function cmdServe(flags) {
113756
113903
  }
113757
113904
  });
113758
113905
  process.stderr.write(
113759
- `viewer: ${url2} (reading ${join51(dataRoot(), "runs")})
113906
+ `viewer: ${url2} (reading ${join52(dataRoot(), "runs")})
113760
113907
  ${idleShutdown ? "idle-shutdown on; " : ""}ctrl-c to stop
113761
113908
  `
113762
113909
  );
@@ -113816,7 +113963,7 @@ function openBrowser(url2) {
113816
113963
  }
113817
113964
  }
113818
113965
  async function cmdRuns(flags) {
113819
- const dir = join51(dataRoot(), "runs");
113966
+ const dir = join52(dataRoot(), "runs");
113820
113967
  if (!existsSync31(dir)) {
113821
113968
  console.log("(no runs yet)");
113822
113969
  return;
@@ -113824,12 +113971,12 @@ async function cmdRuns(flags) {
113824
113971
  const ids = readdirSync5(dir).filter((d) => d.startsWith("wf_"));
113825
113972
  if (flags.prune === true) {
113826
113973
  const keep = intFlag(flags, "keep") ?? 50;
113827
- 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);
113828
113975
  const remove = byAge.slice(keep);
113829
113976
  let bytes = 0;
113830
113977
  for (const r2 of remove) {
113831
- bytes += dirSize(join51(dir, r2.id));
113832
- 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 });
113833
113980
  }
113834
113981
  console.log(
113835
113982
  `pruned ${remove.length} run(s) (${(bytes / 1e6).toFixed(1)} MB); kept ${Math.min(keep, byAge.length)} newest`
@@ -113840,8 +113987,8 @@ async function cmdRuns(flags) {
113840
113987
  const stale2 = ids.filter((id) => isStaleRun(dir, id));
113841
113988
  let bytes = 0;
113842
113989
  for (const id of stale2) {
113843
- bytes += dirSize(join51(dir, id));
113844
- rmSync9(join51(dir, id), { recursive: true, force: true });
113990
+ bytes += dirSize(join52(dir, id));
113991
+ rmSync9(join52(dir, id), { recursive: true, force: true });
113845
113992
  }
113846
113993
  console.log(`pruned ${stale2.length} stale run(s) (${(bytes / 1e6).toFixed(1)} MB)`);
113847
113994
  return;
@@ -113850,7 +113997,7 @@ async function cmdRuns(flags) {
113850
113997
  const loaded = Journal.load(id);
113851
113998
  const name = loaded.meta?.workflowFile?.split("/").pop() ?? "";
113852
113999
  const agents = loaded.results.size;
113853
- const resultPath = join51(dir, id, "result.json");
114000
+ const resultPath = join52(dir, id, "result.json");
113854
114001
  const done = existsSync31(resultPath);
113855
114002
  const status = done ? "completed" : isStaleRun(dir, id) ? "stale" : "?";
113856
114003
  return { id, name, agents, status, at: loaded.meta?.createdAt ?? 0 };
@@ -113859,10 +114006,10 @@ async function cmdRuns(flags) {
113859
114006
  for (const r2 of rows) console.log(`${r2.id} ${r2.status.padEnd(10)} ${String(r2.agents).padStart(3)} agents ${r2.name}`);
113860
114007
  }
113861
114008
  function isStaleRun(runsBase, id) {
113862
- const rd = join51(runsBase, id);
114009
+ const rd = join52(runsBase, id);
113863
114010
  let lastRunStatus;
113864
114011
  try {
113865
- const lines = readFileSync27(join51(rd, "events.jsonl"), "utf8").trim().split("\n");
114012
+ const lines = readFileSync26(join52(rd, "events.jsonl"), "utf8").trim().split("\n");
113866
114013
  for (let i3 = lines.length - 1; i3 >= 0; i3--) {
113867
114014
  const m = lines[i3]?.match(/"type":"run","status":"([a-z]+)"/);
113868
114015
  if (m) {
@@ -113876,7 +114023,7 @@ function isStaleRun(runsBase, id) {
113876
114023
  if (lastRunStatus !== "started") return false;
113877
114024
  let beat = 0;
113878
114025
  try {
113879
- beat = statSync10(join51(rd, ".heartbeat")).mtimeMs;
114026
+ beat = statSync10(join52(rd, ".heartbeat")).mtimeMs;
113880
114027
  } catch {
113881
114028
  }
113882
114029
  return Date.now() - beat > 2e4;
@@ -113884,7 +114031,7 @@ function isStaleRun(runsBase, id) {
113884
114031
  function dirSize(dir) {
113885
114032
  let total = 0;
113886
114033
  for (const e of readdirSync5(dir, { withFileTypes: true })) {
113887
- const p = join51(dir, e.name);
114034
+ const p = join52(dir, e.name);
113888
114035
  total += e.isDirectory() ? dirSize(p) : statSync10(p).size;
113889
114036
  }
113890
114037
  return total;
@@ -113900,7 +114047,7 @@ async function cmdRun(flags, registryRoots) {
113900
114047
  }
113901
114048
  const resolvedFile = resolveFileOrName(file2, registryRoots);
113902
114049
  const overrides = {};
113903
- const provider = enumFlag(flags, "provider", PROVIDERS2);
114050
+ const provider = enumFlag(flags, "provider", PROVIDERS);
113904
114051
  if (provider) overrides.provider = provider;
113905
114052
  const model = str(flags.model);
113906
114053
  if (model) overrides.model = model;
@@ -113929,7 +114076,7 @@ async function cmdRun(flags, registryRoots) {
113929
114076
  if (argsFile) {
113930
114077
  let raw2;
113931
114078
  try {
113932
- raw2 = readFileSync27(resolve31(argsFile), "utf8");
114079
+ raw2 = readFileSync26(resolve31(argsFile), "utf8");
113933
114080
  } catch {
113934
114081
  throw new UsageError2(`--args-file not found: ${argsFile}`);
113935
114082
  }
@@ -113993,7 +114140,7 @@ async function cmdValidate(flags, registryRoots) {
113993
114140
  process.exitCode = 1;
113994
114141
  return;
113995
114142
  }
113996
- const source = readFileSync27(resolveFileOrName(file2, registryRoots), "utf8");
114143
+ const source = readFileSync26(resolveFileOrName(file2, registryRoots), "utf8");
113997
114144
  const { meta: meta3 } = parseWorkflow(source);
113998
114145
  console.log(`ok: "${meta3.name}" \u2014 ${meta3.description}`);
113999
114146
  if (meta3.phases) console.log(`phases: ${meta3.phases.map((p) => p.title).join(" \u2192 ")}`);
@@ -114031,20 +114178,20 @@ async function cmdSave(flags) {
114031
114178
  }
114032
114179
  const absFile = resolve31(file2);
114033
114180
  if (!existsSync31(absFile)) throw new UsageError2(`file not found: ${file2}`);
114034
- const { meta: meta3 } = parseWorkflow(readFileSync27(absFile, "utf8"));
114181
+ const { meta: meta3 } = parseWorkflow(readFileSync26(absFile, "utf8"));
114035
114182
  const name = meta3.name;
114036
114183
  if (name.includes("/") || name.includes("\\") || name.includes("..") || name.startsWith(".") || name.includes("\0")) {
114037
114184
  throw new UsageError2(`meta.name is not a safe filename: "${name}"`);
114038
114185
  }
114039
114186
  const useProject = flags.project === true;
114040
114187
  const destDir = useProject ? projectPaths(process.cwd()).workflows : globalPaths().workflows;
114041
- const dest = join51(destDir, `${name}.workflow.js`);
114188
+ const dest = join52(destDir, `${name}.workflow.js`);
114042
114189
  if (existsSync31(dest) && flags.force !== true) {
114043
114190
  throw new UsageError2(
114044
114191
  `${useProject ? "project" : "user"} workflow "${name}" already exists at ${dest} \u2014 use --force to overwrite`
114045
114192
  );
114046
114193
  }
114047
- mkdirSync17(destDir, { recursive: true });
114194
+ mkdirSync18(destDir, { recursive: true });
114048
114195
  copyFileSync3(absFile, dest);
114049
114196
  console.log(`saved "${name}" \u2192 ${dest}`);
114050
114197
  }
@@ -114075,7 +114222,7 @@ async function cmdDoctor() {
114075
114222
  const codexBin = process.env.CODEX_BIN ?? "codex";
114076
114223
  const opencodeBin = process.env.OPENCODE_BIN ?? "opencode";
114077
114224
  const piBin = process.env.PI_BIN ?? "pi";
114078
- const piScratch = mkdtempSync4(join51(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114225
+ const piScratch = mkdtempSync4(join52(tmpdir6(), `${APP_SLUG}-doctor-pi-`));
114079
114226
  let piOut;
114080
114227
  try {
114081
114228
  piOut = check4(piBin, ["--version"], { env: { ...process.env, PI_CODING_AGENT_DIR: piScratch }, cwd: tmpdir6() });
@@ -114093,31 +114240,20 @@ async function cmdDoctor() {
114093
114240
  console.log(` data dir : ${dataRoot()}`);
114094
114241
  }
114095
114242
  function readSkill(skillPath) {
114096
- if (skillPath) return readFileSync27(skillPath, "utf8");
114243
+ if (skillPath) return readFileSync26(skillPath, "utf8");
114097
114244
  const here = dirname28(fileURLToPath7(import.meta.url));
114098
114245
  const candidates = [
114099
- join51(here, "..", "skills", "portta-workflows", "SKILL.md"),
114100
- join51(here, "..", "..", "..", "skills", "portta-workflows", "SKILL.md"),
114101
- 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")
114102
114249
  ];
114103
114250
  const src = candidates.find((candidate) => existsSync31(candidate));
114104
114251
  if (!src) throw new Error(`skill source not found at ${candidates.join(" or ")}`);
114105
- return readFileSync27(src, "utf8");
114252
+ return readFileSync26(src, "utf8");
114106
114253
  }
114107
114254
  async function cmdGuide(skillPath) {
114108
114255
  process.stdout.write(readSkill(skillPath).replace(/^---\n[\s\S]*?\n---\n+/, ""));
114109
114256
  }
114110
- function cmdInstallSkillRetired() {
114111
- console.error(
114112
- `${CLI_NAME} workflows install-skill has been retired. Install the skill with the Skills CLI instead:
114113
-
114114
- npx skills add codions-labs/portta --skill portta-workflows -g
114115
-
114116
- It supports Claude Code, Codex, OpenCode, Cursor, Zed and others, symlinks by default,
114117
- and \`npx skills update\` keeps every agent current. See https://www.skills.sh.`
114118
- );
114119
- process.exitCode = 1;
114120
- }
114121
114257
  function printHelp() {
114122
114258
  console.log(`${APP_NAME} workflows \u2014 run JS workflow files that orchestrate coding agents
114123
114259
 
@@ -114178,7 +114314,7 @@ function invokedDirectly() {
114178
114314
  return false;
114179
114315
  }
114180
114316
  }
114181
- var UsageError2, BOOLEAN_FLAGS, PROVIDERS2, SANDBOXES, EFFORTS;
114317
+ var UsageError2, BOOLEAN_FLAGS, PROVIDERS, SANDBOXES, EFFORTS;
114182
114318
  var init_cli = __esm({
114183
114319
  "../host/src/modules/taskflow/workflows/cli.ts"() {
114184
114320
  "use strict";
@@ -114213,7 +114349,7 @@ var init_cli = __esm({
114213
114349
  "project",
114214
114350
  "force"
114215
114351
  ]);
114216
- PROVIDERS2 = PROVIDER_IDS;
114352
+ PROVIDERS = PROVIDER_IDS;
114217
114353
  SANDBOXES = ["read-only", "workspace-write", "danger-full-access"];
114218
114354
  EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh", "max"];
114219
114355
  if (invokedDirectly()) {
@@ -116305,7 +116441,7 @@ var RemovalPreview = named(
116305
116441
  "RemovalPreview"
116306
116442
  );
116307
116443
  var LiveEventKind = named(
116308
- 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"]),
116309
116445
  "LiveEventKind"
116310
116446
  );
116311
116447
  var LiveEvent = named(
@@ -117341,131 +117477,7 @@ var {
117341
117477
 
117342
117478
  // src/cli.ts
117343
117479
  init_errors3();
117344
-
117345
- // src/process.ts
117346
- init_execa();
117347
- import { spawn as spawn2 } from "node:child_process";
117348
- import { closeSync as closeSync2, openSync as openSync2 } from "node:fs";
117349
- var reporting = {};
117350
- function setProcessReporter(options) {
117351
- reporting = options;
117352
- }
117353
- function effectiveStdio(requested) {
117354
- if (requested === "inherit") return "inherit";
117355
- if (reporting.quiet) return "pipe";
117356
- if (reporting.verbose) return "stream";
117357
- return requested;
117358
- }
117359
- function outputTargets(mode) {
117360
- if (mode !== "stream") return { stdio: mode };
117361
- return {
117362
- stdin: "pipe",
117363
- stdout: reporting.json ? "pipe" : ["pipe", "inherit"],
117364
- stderr: ["pipe", "inherit"]
117365
- };
117366
- }
117367
- var HEARTBEAT_FIRST_MS = 1e4;
117368
- var HEARTBEAT_EVERY_MS = 3e4;
117369
- var HEARTBEAT_HINT_MS = 18e4;
117370
- function elapsed(sinceMs) {
117371
- const seconds = Math.round((Date.now() - sinceMs) / 1e3);
117372
- if (seconds < 60) return `${seconds}s`;
117373
- return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, "0")}s`;
117374
- }
117375
- function describeCommand(file2, args, limit = 88) {
117376
- const words = [];
117377
- for (let index = 0; index < args.length; index += 1) {
117378
- const argument = args[index] ?? "";
117379
- if (argument === "-f" || argument === "--file") {
117380
- index += 1;
117381
- continue;
117382
- }
117383
- words.push(argument);
117384
- }
117385
- const line4 = [file2, ...words].join(" ");
117386
- return line4.length <= limit ? line4 : `${line4.slice(0, limit - 1)}\u2026`;
117387
- }
117388
- function startHeartbeat(file2, args) {
117389
- if (reporting.quiet) return () => {
117390
- };
117391
- const started = Date.now();
117392
- const label3 = describeCommand(file2, args);
117393
- let hinted = false;
117394
- const announce = () => {
117395
- process.stderr.write(`wait still running: ${label3} (${elapsed(started)})
117396
- `);
117397
- if (!hinted && Date.now() - started >= HEARTBEAT_HINT_MS) {
117398
- hinted = true;
117399
- process.stderr.write(" -> a first build of the panel image takes several minutes; Ctrl-C is safe, and --verbose shows its output\n");
117400
- }
117401
- };
117402
- let repeat;
117403
- const first = setTimeout(() => {
117404
- announce();
117405
- repeat = setInterval(announce, HEARTBEAT_EVERY_MS);
117406
- repeat.unref?.();
117407
- }, HEARTBEAT_FIRST_MS);
117408
- first.unref?.();
117409
- return () => {
117410
- clearTimeout(first);
117411
- if (repeat) clearInterval(repeat);
117412
- };
117413
- }
117414
- async function runProcess(file2, args = [], options = {}) {
117415
- const mode = effectiveStdio(options.stdio ?? "pipe");
117416
- const execaOptions = {
117417
- cwd: options.cwd,
117418
- env: options.env,
117419
- input: options.input,
117420
- reject: options.reject ?? true,
117421
- shell: false,
117422
- timeout: options.timeout,
117423
- ...outputTargets(mode)
117424
- };
117425
- const stopHeartbeat = mode === "pipe" ? startHeartbeat(file2, args) : () => {
117426
- };
117427
- try {
117428
- const result = await execa(file2, [...args], execaOptions);
117429
- return {
117430
- stdout: typeof result.stdout === "string" ? result.stdout : "",
117431
- stderr: typeof result.stderr === "string" ? result.stderr : "",
117432
- exitCode: result.exitCode ?? (result.failed ? 1 : 0),
117433
- failed: result.failed
117434
- };
117435
- } finally {
117436
- stopHeartbeat();
117437
- }
117438
- }
117439
- var PROCESS_POLICY = Object.freeze({ shell: false, argumentArraysOnly: true });
117440
- async function runForeground(file2, args, options = {}) {
117441
- const child = execa(file2, [...args], { cwd: options.cwd, env: options.env, stdio: "inherit", reject: false, shell: false });
117442
- const forwarded = ["SIGINT", "SIGTERM", "SIGHUP"].map((signal) => [signal, () => {
117443
- child.kill(signal);
117444
- }]);
117445
- for (const [signal, forward] of forwarded) process.on(signal, forward);
117446
- try {
117447
- const result = await child;
117448
- return result.exitCode ?? (result.signal ? 1 : 0);
117449
- } finally {
117450
- for (const [signal, forward] of forwarded) process.off(signal, forward);
117451
- }
117452
- }
117453
- function spawnDetached(file2, args, options = {}) {
117454
- const log3 = options.logFile ? openSync2(options.logFile, "a", 384) : null;
117455
- try {
117456
- const child = spawn2(file2, [...args], {
117457
- cwd: options.cwd,
117458
- env: options.env,
117459
- shell: false,
117460
- detached: true,
117461
- stdio: log3 === null ? "ignore" : ["ignore", log3, log3]
117462
- });
117463
- child.unref();
117464
- return child.pid;
117465
- } finally {
117466
- if (log3 !== null) closeSync2(log3);
117467
- }
117468
- }
117480
+ init_process();
117469
117481
 
117470
117482
  // src/commands/access.ts
117471
117483
  init_src();
@@ -117493,6 +117505,7 @@ init_context();
117493
117505
  // src/docker.ts
117494
117506
  init_zod();
117495
117507
  init_errors3();
117508
+ init_process();
117496
117509
  var Identifier = /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/;
117497
117510
  function identifier(value3, kind = "Docker identifier") {
117498
117511
  if (!Identifier.test(value3)) throw new UsageError(`invalid ${kind}: ${value3}`);
@@ -117510,12 +117523,10 @@ var InspectSchema = external_exports.object({
117510
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()
117511
117524
  }).passthrough()
117512
117525
  }).passthrough();
117513
- async function dockerAvailable() {
117514
- const result = await runProcess("docker", ["info"], { reject: false });
117515
- return result.exitCode === 0;
117516
- }
117517
117526
  async function requireDocker() {
117518
- 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");
117519
117530
  }
117520
117531
  async function dockerOperatingSystem() {
117521
117532
  const result = await runProcess("docker", ["info", "--format", "{{.OperatingSystem}}"], { reject: false, timeout: 8e3 });
@@ -117585,6 +117596,7 @@ async function isManagedContainer(id) {
117585
117596
 
117586
117597
  // src/commands/access.ts
117587
117598
  init_errors3();
117599
+ init_process();
117588
117600
  function globals(command) {
117589
117601
  return command.optsWithGlobals();
117590
117602
  }
@@ -117764,21 +117776,50 @@ async function serviceUnpublish(alias, options, command) {
117764
117776
  }
117765
117777
 
117766
117778
  // src/commands/clients.ts
117767
- import { copyFileSync as copyFileSync2, existsSync as existsSync22, mkdirSync as mkdirSync14, rmSync as rmSync5, statSync as statSync9 } from "node:fs";
117768
- 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";
117769
117781
 
117770
117782
  // src/commands/web.ts
117771
117783
  init_src();
117772
117784
  init_src();
117773
117785
  init_context();
117774
- import { chmodSync as chmodSync8, mkdirSync as mkdirSync13 } from "node:fs";
117775
- import { join as join44 } from "node:path";
117786
+ import { mkdirSync as mkdirSync14 } from "node:fs";
117787
+ import { join as join45 } from "node:path";
117776
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
+ }
117777
117817
 
117778
117818
  // src/local-release.ts
117779
117819
  init_src();
117780
117820
  init_errors3();
117781
- import { join as join6 } from "node:path";
117821
+ init_process();
117822
+ import { join as join7 } from "node:path";
117782
117823
  async function requireLocalRelease(context) {
117783
117824
  if (context.env["PORTTA_LOCAL_RELEASE"] !== "true") return;
117784
117825
  const missing = [];
@@ -117792,7 +117833,7 @@ async function requireLocalRelease(context) {
117792
117833
  }
117793
117834
  function selectLocalRelease(context) {
117794
117835
  const image = porttaImages(context.version).runtime;
117795
- patchEnvFile(join6(context.root, ".env"), {
117836
+ patchEnvFile(join7(context.root, ".env"), {
117796
117837
  PORTTA_AUTH_IMAGE: image,
117797
117838
  PORTTA_WEB_IMAGE: image,
117798
117839
  PORTTA_WEB_BUILD: "false",
@@ -117803,13 +117844,15 @@ function selectLocalRelease(context) {
117803
117844
  // src/commands/repos.ts
117804
117845
  init_src();
117805
117846
  import { createHash as createHash2 } from "node:crypto";
117806
- 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";
117807
- 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";
117808
117849
  init_context();
117809
117850
  init_errors3();
117851
+ init_process();
117810
117852
 
117811
117853
  // src/commands/git.ts
117812
- import { existsSync as existsSync5 } from "node:fs";
117854
+ init_process();
117855
+ import { existsSync as existsSync6 } from "node:fs";
117813
117856
  async function git(cwd, args) {
117814
117857
  const result = await runProcess("git", ["-C", cwd, ...args], { reject: false });
117815
117858
  return result.exitCode === 0 ? result.stdout.trim() : null;
@@ -117860,7 +117903,7 @@ function normalizePulls(raw2) {
117860
117903
  async function collectGitProject(project2, path7, declaredRemote = "", withPrs = false, cachedForge) {
117861
117904
  const collectedAt = Math.floor(Date.now() / 1e3);
117862
117905
  const base2 = { project: project2, workingDir: path7, collectedAt };
117863
- 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" };
117864
117907
  const branchName = await git(path7, ["rev-parse", "--abbrev-ref", "HEAD"]);
117865
117908
  const detached = branchName === "HEAD";
117866
117909
  const sha = await git(path7, ["rev-parse", "HEAD"]) ?? "";
@@ -117982,7 +118025,7 @@ async function findCandidates(options, env, registered = []) {
117982
118025
  }
117983
118026
  if (!options.environment && !options.path) {
117984
118027
  for (const path7 of registered) {
117985
- if (!existsSync6(path7)) continue;
118028
+ if (!existsSync7(path7)) continue;
117986
118029
  const root2 = await gitRootOf(path7);
117987
118030
  if (root2) add(root2);
117988
118031
  }
@@ -117996,7 +118039,7 @@ async function findCandidates(options, env, registered = []) {
117996
118039
  home2 = null;
117997
118040
  }
117998
118041
  }
117999
- if (home2 && !options.environment && !options.path && existsSync6(home2)) {
118042
+ if (home2 && !options.environment && !options.path && existsSync7(home2)) {
118000
118043
  let entries = [];
118001
118044
  try {
118002
118045
  entries = readdirSync(home2);
@@ -118005,9 +118048,9 @@ async function findCandidates(options, env, registered = []) {
118005
118048
  }
118006
118049
  for (const entry of entries) {
118007
118050
  if (!firstLevelCandidateName(entry)) continue;
118008
- const path7 = join7(home2, entry);
118051
+ const path7 = join8(home2, entry);
118009
118052
  if (!isDirectory(path7)) continue;
118010
- if (existsSync6(join7(path7, ".git"))) {
118053
+ if (existsSync7(join8(path7, ".git"))) {
118011
118054
  const root2 = await gitRootOf(path7);
118012
118055
  if (root2) add(root2);
118013
118056
  continue;
@@ -118020,8 +118063,8 @@ async function findCandidates(options, env, registered = []) {
118020
118063
  }
118021
118064
  for (const child of children) {
118022
118065
  if (!firstLevelCandidateName(child)) continue;
118023
- const childPath = join7(path7, child);
118024
- if (!isDirectory(childPath) || !existsSync6(join7(childPath, ".git"))) continue;
118066
+ const childPath = join8(path7, child);
118067
+ if (!isDirectory(childPath) || !existsSync7(join8(childPath, ".git"))) continue;
118025
118068
  const root2 = await gitRootOf(childPath);
118026
118069
  if (root2) add(root2);
118027
118070
  }
@@ -118042,8 +118085,8 @@ function sha256(content) {
118042
118085
  async function collectInstructions(root2) {
118043
118086
  const paths3 = [...INSTRUCTION_FILES];
118044
118087
  for (const { directory, extension } of INSTRUCTION_DIRECTORIES) {
118045
- const dir = join7(root2, directory);
118046
- if (!existsSync6(dir)) continue;
118088
+ const dir = join8(root2, directory);
118089
+ if (!existsSync7(dir)) continue;
118047
118090
  try {
118048
118091
  for (const entry of readdirSync(dir).sort()) {
118049
118092
  if (entry.endsWith(extension)) paths3.push(`${directory}/${entry}`);
@@ -118054,8 +118097,8 @@ async function collectInstructions(root2) {
118054
118097
  const files = [];
118055
118098
  for (const relative6 of paths3) {
118056
118099
  if (!isInstructionPath(relative6)) continue;
118057
- const absolute = join7(root2, relative6);
118058
- if (!existsSync6(absolute)) continue;
118100
+ const absolute = join8(root2, relative6);
118101
+ if (!existsSync7(absolute)) continue;
118059
118102
  let size;
118060
118103
  let modifiedAt;
118061
118104
  try {
@@ -118104,7 +118147,7 @@ async function collectRepository(candidate, options, cachedForge) {
118104
118147
  function writeSecret(path7, value3) {
118105
118148
  writeFileSync5(path7, `${JSON.stringify(value3, null, 2)}
118106
118149
  `, { mode: 384 });
118107
- chmodSync4(path7, 384);
118150
+ chmodSync5(path7, 384);
118108
118151
  }
118109
118152
  function readJson(path7) {
118110
118153
  try {
@@ -118116,18 +118159,18 @@ function readJson(path7) {
118116
118159
  async function scanRepositories(options = {}, profile, output2 = new Output({ quiet: true })) {
118117
118160
  if (options.forgeTtl !== void 0 && !/^\d+$/.test(options.forgeTtl)) throw new UsageError("--forge-ttl must be a number of seconds");
118118
118161
  const context = gatewayContext({ profile });
118119
- const directory = join7(context.root, "state/git");
118120
- mkdirSync4(directory, { recursive: true, mode: 448 });
118162
+ const directory = join8(context.root, "state/git");
118163
+ mkdirSync5(directory, { recursive: true, mode: 448 });
118121
118164
  const partial2 = Boolean(options.environment || options.path);
118122
118165
  const registered = partial2 ? [] : await registeredRepositoryPaths(context, (line4) => output2.detail(line4));
118123
118166
  const { candidates, home: home2 } = await findCandidates(options, context.env, registered);
118124
118167
  if (candidates.size > 0) {
118125
- 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}` : ""}`);
118126
118169
  }
118127
118170
  const forgeTtl = Number(options.forgeTtl ?? 300);
118128
118171
  const now = Math.floor(Date.now() / 1e3);
118129
118172
  const homeReal = home2 ? safeRealpath(home2) : null;
118130
- const previous = partial2 ? readJson(join7(directory, SCAN_INDEX_FILE)) : null;
118173
+ const previous = partial2 ? readJson(join8(directory, SCAN_INDEX_FILE)) : null;
118131
118174
  const entries = /* @__PURE__ */ new Map();
118132
118175
  const environments = {};
118133
118176
  if (previous && previous.version === SCAN_VERSION) {
@@ -118137,9 +118180,9 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118137
118180
  const repositories = [];
118138
118181
  for (const candidate of candidates.values()) {
118139
118182
  const key = repositoryKey(candidate.root);
118140
- const target = join7(directory, `${key}.json`);
118183
+ const target = join8(directory, `${key}.json`);
118141
118184
  let cachedForge;
118142
- if (options.withPrs && forgeTtl > 0 && existsSync6(target)) {
118185
+ if (options.withPrs && forgeTtl > 0 && existsSync7(target)) {
118143
118186
  const forge = readJson(target)?.["forge"];
118144
118187
  if (forge && now - Number(forge["collectedAt"] ?? 0) < forgeTtl) cachedForge = forge;
118145
118188
  }
@@ -118168,7 +118211,7 @@ async function scanRepositories(options = {}, profile, output2 = new Output({ qu
118168
118211
  repositories: [...entries.values()].sort((a3, b) => a3.name.localeCompare(b.name)),
118169
118212
  environments
118170
118213
  };
118171
- writeSecret(join7(directory, SCAN_INDEX_FILE), index);
118214
+ writeSecret(join8(directory, SCAN_INDEX_FILE), index);
118172
118215
  return { index, repositories };
118173
118216
  }
118174
118217
  async function reposScan(options, command) {
@@ -118178,8 +118221,8 @@ async function reposScan(options, command) {
118178
118221
  else output2.progress(`scanned ${result.repositories.length} repositor${result.repositories.length === 1 ? "y" : "ies"}`);
118179
118222
  }
118180
118223
  function readScanIndex(root2) {
118181
- const path7 = join7(root2, "state/git", SCAN_INDEX_FILE);
118182
- if (!existsSync6(path7)) return null;
118224
+ const path7 = join8(root2, "state/git", SCAN_INDEX_FILE);
118225
+ if (!existsSync7(path7)) return null;
118183
118226
  const value3 = readJson(path7);
118184
118227
  if (value3 === null) throw new CliError(`${path7} is not readable JSON`, void 0, "run `portta repos scan` to rewrite it");
118185
118228
  return value3["version"] === SCAN_VERSION ? value3 : null;
@@ -118190,7 +118233,7 @@ async function reposStatus(command) {
118190
118233
  const output2 = new Output(globals2(command));
118191
118234
  const now = Math.floor(Date.now() / 1e3);
118192
118235
  const repositories = (index?.repositories ?? []).map((entry) => {
118193
- const scan = readJson(join7(context.root, "state/git", `${entry.key}.json`));
118236
+ const scan = readJson(join8(context.root, "state/git", `${entry.key}.json`));
118194
118237
  const gitInfo = scan?.["git"] ?? null;
118195
118238
  return {
118196
118239
  ...entry,
@@ -118214,12 +118257,12 @@ async function reposStatus(command) {
118214
118257
  }
118215
118258
  async function reposClear(command) {
118216
118259
  const context = gatewayContext({ profile: globals2(command).profile });
118217
- const directory = join7(context.root, "state/git");
118218
- if (!existsSync6(directory)) return;
118260
+ const directory = join8(context.root, "state/git");
118261
+ if (!existsSync7(directory)) return;
118219
118262
  let count2 = 0;
118220
118263
  for (const file2 of readdirSync(directory)) {
118221
118264
  if (file2.endsWith(".json")) {
118222
- unlinkSync4(join7(directory, file2));
118265
+ unlinkSync4(join8(directory, file2));
118223
118266
  count2++;
118224
118267
  }
118225
118268
  }
@@ -118237,9 +118280,11 @@ async function refreshRepositories(profile, output2) {
118237
118280
  init_src();
118238
118281
  init_src2();
118239
118282
  init_context();
118283
+ init_version();
118240
118284
  init_errors3();
118285
+ init_process();
118241
118286
  import { existsSync as existsSync21 } from "node:fs";
118242
- import { join as join43 } from "node:path";
118287
+ import { join as join44 } from "node:path";
118243
118288
 
118244
118289
  // src/metrics/collect.ts
118245
118290
  init_src();
@@ -118248,46 +118293,46 @@ import { loadavg } from "node:os";
118248
118293
 
118249
118294
  // src/metrics/store.ts
118250
118295
  init_src();
118251
- 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";
118252
118297
  import { dirname as dirname21 } from "node:path";
118253
118298
  import { randomUUID as randomUUID8 } from "node:crypto";
118254
118299
 
118255
118300
  // src/metrics/paths.ts
118256
- import { join as join38 } from "node:path";
118301
+ import { join as join39 } from "node:path";
118257
118302
  function metricsDir(root2) {
118258
- return join38(root2, "state/metrics");
118303
+ return join39(root2, "state/metrics");
118259
118304
  }
118260
118305
  function currentFile(root2) {
118261
- return join38(metricsDir(root2), "current.json");
118306
+ return join39(metricsDir(root2), "current.json");
118262
118307
  }
118263
118308
  function historyFile(root2) {
118264
- return join38(metricsDir(root2), "history.jsonl");
118309
+ return join39(metricsDir(root2), "history.jsonl");
118265
118310
  }
118266
118311
  function instanceFile(root2) {
118267
- return join38(metricsDir(root2), "instance.json");
118312
+ return join39(metricsDir(root2), "instance.json");
118268
118313
  }
118269
118314
  function pidFile(root2) {
118270
- return join38(metricsDir(root2), "collector.pid");
118315
+ return join39(metricsDir(root2), "collector.pid");
118271
118316
  }
118272
118317
  function logFile(root2) {
118273
- return join38(root2, "state/logs/host-metrics.log");
118318
+ return join39(root2, "state/logs/host-metrics.log");
118274
118319
  }
118275
118320
  function environmentReportFile(root2) {
118276
- return join38(root2, "state/environment/report.json");
118321
+ return join39(root2, "state/environment/report.json");
118277
118322
  }
118278
118323
 
118279
118324
  // src/metrics/store.ts
118280
118325
  var LOG_LIMIT_BYTES = 256 * 1024;
118281
118326
  function writeAtomic2(path7, text) {
118282
- mkdirSync12(dirname21(path7), { recursive: true });
118327
+ mkdirSync13(dirname21(path7), { recursive: true });
118283
118328
  const temporary = `${path7}.${process.pid}.tmp`;
118284
118329
  writeFileSync11(temporary, text, { mode: 384 });
118285
118330
  renameSync4(temporary, path7);
118286
- chmodSync7(path7, 384);
118331
+ chmodSync8(path7, 384);
118287
118332
  }
118288
118333
  function loadInstance(root2, hostname4) {
118289
118334
  const path7 = instanceFile(root2);
118290
- if (existsSync15(path7)) {
118335
+ if (existsSync16(path7)) {
118291
118336
  try {
118292
118337
  const parsed = JSON.parse(readFileSync17(path7, "utf8"));
118293
118338
  if (typeof parsed.id === "string" && parsed.id !== "") {
@@ -118317,14 +118362,14 @@ function writeCurrent(root2, snapshot) {
118317
118362
  }
118318
118363
  function appendHistory(root2, snapshot) {
118319
118364
  const path7 = historyFile(root2);
118320
- mkdirSync12(dirname21(path7), { recursive: true });
118321
- const existing = existsSync15(path7) ? readFileSync17(path7, "utf8") : "";
118365
+ mkdirSync13(dirname21(path7), { recursive: true });
118366
+ const existing = existsSync16(path7) ? readFileSync17(path7, "utf8") : "";
118322
118367
  const merged = mergeHistoryLines(existing, historyPointFrom(snapshot), snapshot.collectedAt);
118323
118368
  writeAtomic2(path7, merged);
118324
118369
  }
118325
118370
  function readCurrent(root2) {
118326
118371
  const path7 = currentFile(root2);
118327
- if (!existsSync15(path7)) return null;
118372
+ if (!existsSync16(path7)) return null;
118328
118373
  try {
118329
118374
  return JSON.parse(readFileSync17(path7, "utf8"));
118330
118375
  } catch {
@@ -118333,8 +118378,8 @@ function readCurrent(root2) {
118333
118378
  }
118334
118379
  function appendLog(root2, line4) {
118335
118380
  const path7 = logFile(root2);
118336
- mkdirSync12(dirname21(path7), { recursive: true });
118337
- 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) {
118338
118383
  renameSync4(path7, `${path7}.old`);
118339
118384
  }
118340
118385
  writeFileSync11(path7, `${(/* @__PURE__ */ new Date()).toISOString()} ${line4}
@@ -118437,17 +118482,18 @@ async function collectSnapshot(root2, now = Date.now()) {
118437
118482
 
118438
118483
  // src/metrics/lifecycle.ts
118439
118484
  init_src();
118440
- 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();
118441
118487
 
118442
118488
  // src/environment/index.ts
118443
118489
  init_src();
118444
118490
  import { homedir as homedir8 } from "node:os";
118445
118491
 
118446
118492
  // src/host.ts
118447
- init_src();
118448
- import { homedir as homedir7, loadavg as loadavg2, networkInterfaces, uptime } from "node:os";
118449
- import { accessSync as accessSync3, constants as constants7, existsSync as existsSync16, globSync, readFileSync as readFileSync18, statfsSync, statSync as statSync8 } from "node:fs";
118450
- 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";
118451
118497
  function isTailscaleRange(address) {
118452
118498
  const [a3, b] = address.split(".").map(Number);
118453
118499
  return a3 === 100 && b !== void 0 && b >= 64 && b <= 127;
@@ -118476,19 +118522,19 @@ async function locate(tool) {
118476
118522
  if (!onPath.failed && direct) return direct;
118477
118523
  const home2 = homedir7();
118478
118524
  for (const candidate of [
118479
- join39(home2, ".local/bin", tool),
118480
- join39(home2, ".bun/bin", tool),
118481
- join39(home2, ".cargo/bin", tool),
118482
- join39(home2, ".deno/bin", tool),
118483
- join39("/usr/local/bin", tool),
118484
- join39("/opt/homebrew/bin", tool),
118485
- 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)
118486
118532
  ]) {
118487
118533
  if (executable(candidate)) return candidate;
118488
118534
  }
118489
118535
  for (const pattern of [
118490
- join39(home2, ".nvm/versions/node/*/bin", tool),
118491
- 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)
118492
118538
  ]) {
118493
118539
  for (const match2 of globSync(pattern)) if (executable(match2)) return match2;
118494
118540
  }
@@ -118502,6 +118548,9 @@ function fileMode(path7) {
118502
118548
  }
118503
118549
  }
118504
118550
 
118551
+ // src/environment/index.ts
118552
+ init_process();
118553
+
118505
118554
  // src/environment/agents.ts
118506
118555
  init_src();
118507
118556
 
@@ -118704,7 +118753,7 @@ ${daemon.stdout}`);
118704
118753
  // src/environment/ssh.ts
118705
118754
  init_src();
118706
118755
  import { existsSync as existsSync17 } from "node:fs";
118707
- import { join as join40 } from "node:path";
118756
+ import { join as join41 } from "node:path";
118708
118757
  var SSH_ID = "tools.ssh";
118709
118758
  var TMUX_ID = "tools.tmux";
118710
118759
  var sshProbe = {
@@ -118720,7 +118769,7 @@ var sshProbe = {
118720
118769
  fix: "install an OpenSSH client for remote and repository workflows"
118721
118770
  })];
118722
118771
  }
118723
- const directory = join40(context.homeDir, ".ssh");
118772
+ const directory = join41(context.homeDir, ".ssh");
118724
118773
  const mode = context.fileMode(directory);
118725
118774
  const agent = context.environment["SSH_AUTH_SOCK"] ? await context.run("ssh-add", ["-l"], { reject: false, timeout: PROBE_TIMEOUT_MS2 }) : null;
118726
118775
  const details = [
@@ -118803,12 +118852,12 @@ function writeEnvironmentReport(root2, report) {
118803
118852
  // src/environment/security/index.ts
118804
118853
  init_src();
118805
118854
  import { platform as platform2 } from "node:os";
118806
- import { existsSync as existsSync19, readFileSync as readFileSync20 } from "node:fs";
118807
- 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";
118808
118857
 
118809
118858
  // src/environment/security/probes.ts
118810
118859
  init_src();
118811
- import { existsSync as existsSync18, readFileSync as readFileSync19 } from "node:fs";
118860
+ import { existsSync as existsSync18, readFileSync as readFileSync18 } from "node:fs";
118812
118861
  function emptySshd(state3, reason) {
118813
118862
  return { state: state3, reason, source: null, port: null, permitRootLogin: null, passwordAuthentication: null, pubkeyAuthentication: null, usePam: null };
118814
118863
  }
@@ -118826,7 +118875,7 @@ ${result.stdout}`);
118826
118875
  for (const path7 of ["/etc/ssh/sshd_config", "/private/etc/ssh/sshd_config"]) {
118827
118876
  if (!existsSync18(path7)) continue;
118828
118877
  try {
118829
- const parsed = parseSshdConfig(readFileSync19(path7, "utf8"), "file");
118878
+ const parsed = parseSshdConfig(readFileSync18(path7, "utf8"), "file");
118830
118879
  return parsed.state === "present" ? parsed : emptySshd("unknown", "the SSH configuration file could not be interpreted");
118831
118880
  } catch {
118832
118881
  return emptySshd("unknown", "could not be checked: this user cannot read the SSH configuration");
@@ -118877,7 +118926,7 @@ ${jail.stderr}`);
118877
118926
  // src/environment/security/index.ts
118878
118927
  function hostSecurityContext(root2, profileOverride) {
118879
118928
  const snapshot = readCurrent(root2);
118880
- 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();
118881
118930
  const environment = mergeEnvironment(file2, process.env);
118882
118931
  const profile = profileOverride ?? environment["PORTTA_PROFILE"] ?? "local";
118883
118932
  return {
@@ -118897,7 +118946,7 @@ async function collectHostSecurityFacts(context, securityContext) {
118897
118946
  }
118898
118947
  async function collectHostSecurityChecks(root2, probeContext = defaultProbeContext(), securityContext = hostSecurityContext(root2)) {
118899
118948
  const checks = securityVerdicts(await collectHostSecurityFacts(probeContext, securityContext), securityContext);
118900
- const sshDirectory = join41(root2, "state/ssh");
118949
+ const sshDirectory = join42(root2, "state/ssh");
118901
118950
  const mode = probeContext.fileMode(sshDirectory);
118902
118951
  checks.push({
118903
118952
  ...check2(
@@ -118925,9 +118974,9 @@ async function collectHostSecurityReport(root2, probeContext = defaultProbeConte
118925
118974
  }
118926
118975
 
118927
118976
  // src/environment/security/store.ts
118928
- import { join as join42 } from "node:path";
118977
+ import { join as join43 } from "node:path";
118929
118978
  function securityReportFile(root2) {
118930
- return join42(root2, "state/environment/security.json");
118979
+ return join43(root2, "state/environment/security.json");
118931
118980
  }
118932
118981
  function writeHostSecurityReport(root2, report) {
118933
118982
  const path7 = securityReportFile(root2);
@@ -118940,7 +118989,7 @@ function writeHostSecurityReport(root2, report) {
118940
118989
  function readCollectorPid(root2) {
118941
118990
  const path7 = pidFile(root2);
118942
118991
  if (!existsSync20(path7)) return null;
118943
- const parsed = Number(readFileSync21(path7, "utf8").trim());
118992
+ const parsed = Number(readFileSync20(path7, "utf8").trim());
118944
118993
  return Number.isInteger(parsed) && parsed > 0 ? parsed : null;
118945
118994
  }
118946
118995
  function pidAlive(pid) {
@@ -118953,7 +119002,7 @@ function pidAlive(pid) {
118953
119002
  }
118954
119003
  function commandLine(pid) {
118955
119004
  try {
118956
- return readFileSync21(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
119005
+ return readFileSync20(`/proc/${pid}/cmdline`, "utf8").replace(/\0/g, " ");
118957
119006
  } catch {
118958
119007
  return "";
118959
119008
  }
@@ -119168,10 +119217,10 @@ function ensureHostToken(context) {
119168
119217
  return file2;
119169
119218
  }
119170
119219
  function hostDaemonEntry(directory = import.meta.dirname) {
119171
- return join43(directory, "host.js");
119220
+ return join44(directory, "host.js");
119172
119221
  }
119173
119222
  function hostDaemonLog(stateDir) {
119174
- return join43(stateDir, "daemon.log");
119223
+ return join44(stateDir, "daemon.log");
119175
119224
  }
119176
119225
  async function hostAnswers(listen) {
119177
119226
  const host2 = listen.host === "0.0.0.0" || listen.host === "::" ? "127.0.0.1" : listen.host;
@@ -119186,7 +119235,9 @@ async function hostServe(command) {
119186
119235
  const options = globals3(command);
119187
119236
  const context = gatewayContext({ profile: options.profile });
119188
119237
  const entry = hostDaemonEntry();
119189
- 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
+ }
119190
119241
  const stateDir = resolveHostStateDir(context.root, context.env);
119191
119242
  const listen = hostListen(context.env);
119192
119243
  const output2 = new Output(options);
@@ -119213,16 +119264,16 @@ function globals4(command) {
119213
119264
  return command.optsWithGlobals();
119214
119265
  }
119215
119266
  function setValues(root2, values) {
119216
- const path7 = join44(root2, ".env");
119267
+ const path7 = join45(root2, ".env");
119217
119268
  patchEnvFile(path7, values);
119218
119269
  }
119219
119270
  function syncForwardAuth(root2) {
119220
- const storePath = join44(root2, "state/auth/protections.json");
119271
+ const storePath = join45(root2, "state/auth/protections.json");
119221
119272
  const store = readProtectionStore(storePath);
119222
119273
  writeProtectionStore(storePath, store);
119223
- const dynamic = join44(root2, "config/traefik/dynamic");
119224
- mkdirSync13(dynamic, { recursive: true });
119225
- 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));
119226
119277
  }
119227
119278
  var PANEL_OVERRIDES = { PORTTA_WEB: "true" };
119228
119279
  async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
@@ -119230,7 +119281,7 @@ async function webCompose(command, args, extraEnv = {}, stdio = "inherit") {
119230
119281
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: { ...context.env, ...extraEnv }, stdio });
119231
119282
  }
119232
119283
  function prepareWebUp(options, command) {
119233
- prepareEnvFile(join44(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119284
+ prepareEnvFile(join45(gatewayContext({ profile: globals4(command).profile }).root, ".env"));
119234
119285
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: globals4(command).profile }));
119235
119286
  const initial = gatewayContext({ profile: globals4(command).profile });
119236
119287
  const expose = options.expose ?? initial.config.webExpose;
@@ -119282,16 +119333,7 @@ function prepareWebUp(options, command) {
119282
119333
  options.port ? String(Number(options.port)) : String(initial.config.webPort)
119283
119334
  );
119284
119335
  setValues(initial.root, values);
119285
- mkdirSync13(join44(initial.root, "state/git"), { recursive: true });
119286
- mkdirSync13(join44(initial.root, "state/github"), { recursive: true });
119287
- mkdirSync13(join44(initial.root, "state/metrics"), { recursive: true });
119288
- mkdirSync13(join44(initial.root, "state/environment"), { recursive: true });
119289
- mkdirSync13(join44(initial.root, "state/logs"), { recursive: true });
119290
- mkdirSync13(join44(initial.root, "state/auth"), { recursive: true, mode: 448 });
119291
- chmodSync8(join44(initial.root, "state/auth"), 448);
119292
- mkdirSync13(join44(initial.root, "state/ssh"), { recursive: true, mode: 448 });
119293
- chmodSync8(join44(initial.root, "state/ssh"), 448);
119294
- mkdirSync13(join44(initial.root, "config/traefik/dynamic"), { recursive: true });
119336
+ ensureInstallationDirectories(initial.root);
119295
119337
  syncForwardAuth(initial.root);
119296
119338
  const context = gatewayContext({ profile: globals4(command).profile, overrides: values });
119297
119339
  const output2 = new Output(globals4(command));
@@ -119307,7 +119349,7 @@ async function webUp(options, command) {
119307
119349
  ensureHostToken(context);
119308
119350
  output2.progress("pulling alpine/socat:1.8.1.3");
119309
119351
  await runProcess("docker", ["pull", "alpine/socat:1.8.1.3"], { reject: false, stdio: "stream" });
119310
- mkdirSync13(join44(context.root, "state", "panel"), { recursive: true });
119352
+ mkdirSync14(join45(context.root, "state", "panel"), { recursive: true });
119311
119353
  const services = ["portta-auth", "web", "web-socket-proxy"];
119312
119354
  const buildArgs = context.config.webDev || context.config.webBuild ? ["--build"] : [];
119313
119355
  output2.progress(buildArgs.length > 0 ? `starting ${services.join(", ")}, building the panel image` : `starting ${services.join(", ")}`);
@@ -119505,6 +119547,7 @@ async function webOpen(command) {
119505
119547
  // src/commands/clients.ts
119506
119548
  init_context();
119507
119549
  init_errors3();
119550
+ init_process();
119508
119551
  init_src();
119509
119552
  function globals5(command) {
119510
119553
  return command.optsWithGlobals();
@@ -119514,7 +119557,7 @@ async function ensureToolbox(command) {
119514
119557
  const image = porttaImages(context.version).toolbox;
119515
119558
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
119516
119559
  if (present.exitCode === 0) return image;
119517
- 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" });
119518
119561
  return image;
119519
119562
  }
119520
119563
  async function containerEnvironment(id) {
@@ -119645,7 +119688,7 @@ async function dbRestore(file2, command) {
119645
119688
  );
119646
119689
  }
119647
119690
  await confirm(`replace ${path7} with ${file2}? The current panel data is discarded.`, globals5(command).yes === true);
119648
- mkdirSync14(dirname22(path7), { recursive: true });
119691
+ mkdirSync15(dirname22(path7), { recursive: true });
119649
119692
  for (const candidate of databaseFiles(path7)) rmSync5(candidate, { force: true });
119650
119693
  copyFileSync2(file2, path7);
119651
119694
  new Output(globals5(command)).progress(`panel database restored from ${file2}`);
@@ -119653,12 +119696,14 @@ async function dbRestore(file2, command) {
119653
119696
 
119654
119697
  // src/commands/projects.ts
119655
119698
  init_src();
119699
+ var import_yaml2 = __toESM(require_dist(), 1);
119656
119700
  init_zod();
119657
- 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";
119658
119702
  import { createHash as createHash15 } from "node:crypto";
119659
- 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";
119660
119704
  init_context();
119661
119705
  init_errors3();
119706
+ init_process();
119662
119707
  function globals6(command) {
119663
119708
  return command.optsWithGlobals();
119664
119709
  }
@@ -119769,7 +119814,7 @@ function labelsOf(service2) {
119769
119814
  return Object.fromEntries(Object.entries(service2.labels ?? {}).map(([key, value3]) => [key, String(value3)]));
119770
119815
  }
119771
119816
  function composeCandidates(path7) {
119772
- 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);
119773
119818
  }
119774
119819
  async function hostContainers() {
119775
119820
  try {
@@ -119787,12 +119832,27 @@ function safeRealpath2(path7) {
119787
119832
  }
119788
119833
  function declaredComposeName(file2) {
119789
119834
  try {
119790
- const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync22(file2, "utf8"));
119835
+ const match2 = /^name:[ \t]*["']?([^"'\s#]+)/m.exec(readFileSync21(file2, "utf8"));
119791
119836
  return match2?.[1] ?? null;
119792
119837
  } catch {
119793
119838
  return null;
119794
119839
  }
119795
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
+ }
119796
119856
  async function analyze(pathValue, options = {}, containers) {
119797
119857
  const base2 = resolve24(pathValue);
119798
119858
  let composeFile2;
@@ -119808,8 +119868,8 @@ async function analyze(pathValue, options = {}, containers) {
119808
119868
  let result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json"], { cwd: path7, reject: false });
119809
119869
  if (result.exitCode !== 0) result = await runProcess("docker", ["compose", "-f", composeFile2, "config", "--format", "json", "--no-interpolate"], { cwd: path7 });
119810
119870
  const model = ComposeSchema.parse(JSON.parse(result.stdout));
119811
- 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;
119812
- 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;
119813
119873
  const declaredName = declaredComposeName(composeFile2);
119814
119874
  const project2 = projectFromEnv || composeNamespace(declaredName ?? model.name ?? basename14(path7));
119815
119875
  const services = Object.entries(model.services).map(([name, service2]) => ({
@@ -119843,6 +119903,7 @@ async function analyze(pathValue, options = {}, containers) {
119843
119903
  path: path7,
119844
119904
  compose_file: basename14(composeFile2),
119845
119905
  gateway_overlay: overlay2,
119906
+ project_config: readProjectConfig(path7),
119846
119907
  project: { name: project2, source: projectFromEnv ? ".env" : declaredName ? "compose name:" : "directory name (implicit)" },
119847
119908
  domain: gatewayContext({ required: false }).config.domain,
119848
119909
  services,
@@ -119874,6 +119935,19 @@ async function analyzeCommand(path7, options, command) {
119874
119935
  output2.line(` project namespace ${report.project.name} (${report.project.source})`);
119875
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}`)))];
119876
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
+ }
119877
119951
  output2.line("\nServices");
119878
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(",") || "-"}`);
119879
119953
  output2.line("\nFindings");
@@ -119972,7 +120046,7 @@ async function initCommand(pathValue, options, command) {
119972
120046
  }));
119973
120047
  const content = renderOverlay(report.project.name, overlayServices, context.config.network, options.project);
119974
120048
  const runtimeId = createHash15("sha256").update(safeRealpath2(report.path)).digest("hex").slice(0, 16);
119975
- 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");
119976
120050
  const output2 = new Output(globals6(command));
119977
120051
  if (options.dryRun) {
119978
120052
  output2.data(content);
@@ -119980,12 +120054,12 @@ async function initCommand(pathValue, options, command) {
119980
120054
  }
119981
120055
  if (existsSync23(destination) && !options.force) throw new RefusedError(`${destination} already exists`, "pass --force to replace it while keeping a backup");
119982
120056
  await confirm(`write ${destination}?`, globals6(command).yes === true);
119983
- mkdirSync15(dirname23(destination), { recursive: true, mode: 493 });
120057
+ mkdirSync16(dirname23(destination), { recursive: true, mode: 493 });
119984
120058
  if (existsSync23(destination)) renameSync5(destination, `${destination}.bak.${Date.now()}`);
119985
120059
  const temporary = `${destination}.${process.pid}.tmp`;
119986
120060
  writeFileSync12(temporary, content, { mode: 420 });
119987
120061
  try {
119988
- 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 });
119989
120063
  if (validated.exitCode !== 0) throw new RefusedError("generated runtime overlay is not valid Compose", validated.stderr.trim() || validated.stdout.trim());
119990
120064
  ComposeSchema.parse(JSON.parse(validated.stdout));
119991
120065
  renameSync5(temporary, destination);
@@ -120063,8 +120137,9 @@ init_zod();
120063
120137
  init_context();
120064
120138
  init_errors3();
120065
120139
  import { createHash as createHash16 } from "node:crypto";
120066
- import { existsSync as existsSync24, mkdirSync as mkdirSync16, readFileSync as readFileSync23, renameSync as renameSync6, rmSync as rmSync7, writeFileSync as writeFileSync13 } from "node:fs";
120067
- 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();
120068
120143
  var Manifest = external_exports.object({
120069
120144
  schemaVersion: external_exports.literal(1),
120070
120145
  driver: external_exports.literal("compose").default("compose"),
@@ -120097,25 +120172,25 @@ function idFor(workspace2) {
120097
120172
  return createHash16("sha256").update(workspace2).digest("hex").slice(0, 16);
120098
120173
  }
120099
120174
  function digest(path7) {
120100
- return createHash16("sha256").update(readFileSync23(path7)).digest("hex");
120175
+ return createHash16("sha256").update(readFileSync22(path7)).digest("hex");
120101
120176
  }
120102
120177
  function digestIfPresent(path7) {
120103
120178
  return existsSync24(path7) ? digest(path7) : null;
120104
120179
  }
120105
120180
  function runtimeDirectory(root2, id) {
120106
- return join47(root2, "runtime", "compose", id);
120181
+ return join48(root2, "runtime", "compose", id);
120107
120182
  }
120108
120183
  function planPath(root2, id) {
120109
- return join47(runtimeDirectory(root2, id), "plan.json");
120184
+ return join48(runtimeDirectory(root2, id), "plan.json");
120110
120185
  }
120111
120186
  function manifestPath(root2, id) {
120112
- return join47(runtimeDirectory(root2, id), "runtime.json");
120187
+ return join48(runtimeDirectory(root2, id), "runtime.json");
120113
120188
  }
120114
120189
  function composeCandidates2(workspace2) {
120115
- 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);
120116
120191
  }
120117
120192
  function hasComposeRuntime(workspace2 = process.cwd()) {
120118
- return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join47(resolve25(workspace2), "VERSION"));
120193
+ return composeCandidates2(resolve25(workspace2)).length > 0 && !existsSync24(join48(resolve25(workspace2), "VERSION"));
120119
120194
  }
120120
120195
  function networks(value3) {
120121
120196
  return Array.isArray(value3) ? value3 : Object.keys(value3 ?? {});
@@ -120174,22 +120249,22 @@ networks:
120174
120249
  `;
120175
120250
  }
120176
120251
  function manifestPaths(workspace2, root2, id) {
120177
- return { local: join47(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120252
+ return { local: join48(workspace2, ".portta", "runtime.json"), stored: manifestPath(root2, id) };
120178
120253
  }
120179
120254
  function loadManifest(workspace2, root2, id) {
120180
120255
  const { local, stored } = manifestPaths(workspace2, root2, id);
120181
120256
  const file2 = existsSync24(local) ? local : existsSync24(stored) ? stored : null;
120182
- 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 });
120183
120258
  }
120184
120259
  function inputFiles(workspace2, manifest) {
120185
120260
  if (manifest.compose.files?.length) return manifest.compose.files.map((file2) => resolve25(workspace2, file2));
120186
- const envFile = join47(workspace2, ".env");
120187
- 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();
120188
120263
  const configured = process.env.COMPOSE_FILE ?? env.get("COMPOSE_FILE");
120189
120264
  if (configured) return configured.split(delimiter3).map((file2) => isAbsolute5(file2) ? file2 : resolve25(workspace2, file2));
120190
120265
  const base2 = composeCandidates2(workspace2)[0];
120191
120266
  if (!base2) throw new UsageError(`no Compose file found in ${workspace2}`);
120192
- 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);
120193
120268
  return override ? [base2, override] : [base2];
120194
120269
  }
120195
120270
  function versionAtLeast2(value3, minimum = [2, 24, 4]) {
@@ -120220,7 +120295,7 @@ async function stale(plan) {
120220
120295
  function readPlan(root2, workspace2) {
120221
120296
  const path7 = planPath(root2, idFor(workspace2));
120222
120297
  if (!existsSync24(path7)) throw new UsageError("no Runtime Plan exists for this workspace", "run `portta prepare` first");
120223
- return JSON.parse(readFileSync23(path7, "utf8"));
120298
+ return JSON.parse(readFileSync22(path7, "utf8"));
120224
120299
  }
120225
120300
  function manifestWithOptions(manifest, options) {
120226
120301
  return Manifest.parse({
@@ -120289,14 +120364,14 @@ async function prepareComposeRuntime(options, command) {
120289
120364
  const unsupported = findings.filter((finding2) => finding2.code === "network_mode");
120290
120365
  const outcome = unsupported.length ? "not_supported" : manifest.compose.mode === "manual" ? "manual" : pending.length ? "not_supported" : "isolated";
120291
120366
  const directory = runtimeDirectory(context.root, id);
120292
- const generatedOverlay = join47(directory, "compose.portta.yaml");
120367
+ const generatedOverlay = join48(directory, "compose.portta.yaml");
120293
120368
  const manifests = manifestPaths(workspace2, context.root, id);
120294
- const envFile = join47(workspace2, ".env");
120369
+ const envFile = join48(workspace2, ".env");
120295
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 };
120296
120371
  const content = manifest.compose.mode === "manual" ? "# Manual Compose integration; Portta adds no runtime mutations.\nservices: {}\n" : overlay(plan, context.config.network);
120297
120372
  if (!options.dryRun) {
120298
120373
  if (outcome === "not_supported") throw new RefusedError("environment is not ready for isolated Compose runtime", [...unsupported, ...pending].map((finding2) => finding2.detail).join("; "));
120299
- mkdirSync16(directory, { recursive: true, mode: 448 });
120374
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120300
120375
  const temporary = `${generatedOverlay}.${process.pid}.tmp`;
120301
120376
  writeFileSync13(temporary, content, { mode: 384 });
120302
120377
  const final = await runProcess("docker", [...composeArgs(plan, temporary), "config", "--format", "json"], { cwd: workspace2, reject: false });
@@ -120336,7 +120411,7 @@ async function initComposeRuntime(options, command) {
120336
120411
  const files = inputFiles(workspace2, Manifest.parse({ schemaVersion: 1 }));
120337
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 } };
120338
120413
  const directory = runtimeDirectory(context.root, id);
120339
- mkdirSync16(directory, { recursive: true, mode: 448 });
120414
+ mkdirSync17(directory, { recursive: true, mode: 448 });
120340
120415
  writeFileSync13(manifestPath(context.root, id), `${JSON.stringify(manifest, null, 2)}
120341
120416
  `, { mode: 384 });
120342
120417
  return prepareComposeRuntime({ path: workspace2, project: options.project }, command);
@@ -120367,23 +120442,25 @@ async function runtimeAction(action, options, command) {
120367
120442
  init_src();
120368
120443
  init_src();
120369
120444
  init_context();
120370
- import { chmodSync as chmodSync9, existsSync as existsSync38, mkdirSync as mkdirSync18, readFileSync as readFileSync30, readdirSync as readdirSync8, rmSync as rmSync10 } from "node:fs";
120371
- 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";
120372
120447
  init_errors3();
120448
+ init_process();
120373
120449
  init_version();
120374
120450
 
120375
120451
  // src/doctor.ts
120376
120452
  init_src();
120377
120453
  init_context();
120378
120454
  import { existsSync as existsSync33 } from "node:fs";
120379
- import { join as join53 } from "node:path";
120455
+ import { join as join54 } from "node:path";
120456
+ init_process();
120380
120457
 
120381
120458
  // src/modules/index.ts
120382
120459
  init_src();
120383
120460
  init_modules();
120384
120461
  init_context();
120385
- import { existsSync as existsSync32, readFileSync as readFileSync28 } from "node:fs";
120386
- 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";
120387
120464
 
120388
120465
  // src/modules/taskflow.ts
120389
120466
  init_modules();
@@ -120399,8 +120476,7 @@ var WORKFLOW_ENGINE_ACTIONS = [
120399
120476
  ["validate", "Validate a workflow file or registered workflow"],
120400
120477
  ["save", "Save a workflow file into the registry"],
120401
120478
  ["doctor", "Check the standalone workflow engine"],
120402
- ["guide", "Print the workflow authoring guide"],
120403
- ["install-skill", "Retired \u2014 install with: npx skills add codions-labs/portta --skill portta-workflows -g"]
120479
+ ["guide", "Print the workflow authoring guide"]
120404
120480
  ];
120405
120481
  var USAGE_HINT = "(run with --help for usage)";
120406
120482
  function parsePort2(value3) {
@@ -120416,7 +120492,7 @@ function helpAfter(command, text) {
120416
120492
  ${text(commandInvocation(context.command))}`);
120417
120493
  }
120418
120494
  function runOptions(command) {
120419
- 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(
120420
120496
  new Option("--workspace <strategy>", "Execution workspace (default: workflow policy or worktree)").choices([
120421
120497
  "worktree",
120422
120498
  "branch",
@@ -120486,12 +120562,12 @@ ${environment.map(([name = "", text]) => ` ${name.padEnd(width)} ${text}`).joi
120486
120562
  Analysis: --analyze=auto uses the default agent only when runtime detection falls back to host.
120487
120563
  --analyze=claude | --analyze=codex always run that agent.`
120488
120564
  );
120489
- 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(
120490
120566
  "--from-linear <issue-id>",
120491
120567
  `Bootstrap from a Linear issue, plus any saved ${APP_NAME} session or linked PR`
120492
120568
  ).option("--branch <name>", "Override the branch when --from-linear resolves to one");
120493
120569
  helpAfter(
120494
- 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(
120495
120571
  "--linear <id|team>",
120496
120572
  "Tie this oneshot to Linear: ENG-123 loads the issue and posts back; ENG creates an issue when done"
120497
120573
  ).option("--branch <name>", "Override the branch when --linear resolves to one"),
@@ -120524,7 +120600,7 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
120524
120600
  "--profile <name>",
120525
120601
  "Profile name (alternative to positional arg)"
120526
120602
  ),
120527
- () => `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
120528
120604
  worktree is restarted with the new pane layout and commands; a closed
120529
120605
  one picks the new profile up on its next open.`
120530
120606
  );
@@ -120836,10 +120912,10 @@ var taskflowCliModule = {
120836
120912
  // src/modules/index.ts
120837
120913
  var CLI_MODULES = [taskflowCliModule];
120838
120914
  function moduleEnvironment(root2 = findGatewayRoot()) {
120839
- const file2 = root2 ? join52(root2, ".env") : null;
120915
+ const file2 = root2 ? join53(root2, ".env") : null;
120840
120916
  if (!file2 || !existsSync32(file2)) return { ...process.env };
120841
120917
  try {
120842
- return mergeEnvironment(parseEnv(readFileSync28(file2, "utf8")), process.env);
120918
+ return mergeEnvironment(parseEnv(readFileSync27(file2, "utf8")), process.env);
120843
120919
  } catch {
120844
120920
  return { ...process.env };
120845
120921
  }
@@ -120893,7 +120969,7 @@ async function runDoctor(context) {
120893
120969
  const env = context.env;
120894
120970
  const config3 = context.config;
120895
120971
  const root2 = context.root;
120896
- const stateDir = env["PORTTA_STATE_DIR"] || join53(root2, "state");
120972
+ const stateDir = env["PORTTA_STATE_DIR"] || join54(root2, "state");
120897
120973
  const add = (...entries) => {
120898
120974
  for (const entry of entries) if (entry) checks.push(entry);
120899
120975
  };
@@ -120905,7 +120981,7 @@ async function runDoctor(context) {
120905
120981
  `unknown profile '${env["PORTTA_PROFILE"]}'`,
120906
120982
  "set PORTTA_PROFILE to one of: local remote-private remote-public"
120907
120983
  ));
120908
- const envPath = join53(root2, ".env");
120984
+ const envPath = join54(root2, ".env");
120909
120985
  if (existsSync33(envPath)) {
120910
120986
  add(check2("config.env", "pass", ".env", "present"));
120911
120987
  add(envPermissionVerdict(fileMode(envPath)));
@@ -121047,10 +121123,10 @@ async function runDoctor(context) {
121047
121123
  `portta up ${config3.profile}`
121048
121124
  ));
121049
121125
  }
121050
- 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"));
121051
121127
  }
121052
121128
  const hasKey = Boolean(env["TS_AUTHKEY"]);
121053
- add(!hasKey && !existsSync33(join53(stateDir, "tailscale/tailscaled.state")) ? check2(
121129
+ add(!hasKey && !existsSync33(join54(stateDir, "tailscale/tailscaled.state")) ? check2(
121054
121130
  "tailscale.authkey",
121055
121131
  "fail",
121056
121132
  "tailscale auth",
@@ -121080,7 +121156,7 @@ async function runDoctor(context) {
121080
121156
  "portta bootstrap (generates it without printing it)"
121081
121157
  ));
121082
121158
  const auth2 = gatewayContainer(containers, "auth");
121083
- const authStore = join53(root2, "state/auth/protections.json");
121159
+ const authStore = join54(root2, "state/auth/protections.json");
121084
121160
  add(authStoreVerdict(existsSync33(authStore), fileMode(authStore), Boolean(auth2)));
121085
121161
  add(componentVerdict("auth.service", "authentication service", Boolean(auth2), auth2?.state ?? null, auth2?.health ?? null, "portta logs portta-auth"));
121086
121162
  const gh = await locate("gh");
@@ -121230,7 +121306,7 @@ async function runDoctor(context) {
121230
121306
  "set CF_DNS_API_TOKEN, or use ACME_CHALLENGE=http for per-hostname certificates"
121231
121307
  ));
121232
121308
  }
121233
- const store = join53(stateDir, "traefik/acme/acme.json");
121309
+ const store = join54(stateDir, "traefik/acme/acme.json");
121234
121310
  if (existsSync33(store)) {
121235
121311
  const mode = fileMode(store);
121236
121312
  add(mode === "600" ? check2("tls.acme.perms", "pass", "ACME store permissions", mode) : check2(
@@ -121432,8 +121508,9 @@ async function resolveIpv4(hostname4) {
121432
121508
 
121433
121509
  // src/commands/apply.ts
121434
121510
  init_src();
121511
+ init_process();
121435
121512
  import { existsSync as existsSync34 } from "node:fs";
121436
- import { join as join54 } from "node:path";
121513
+ import { join as join55 } from "node:path";
121437
121514
  async function label(name) {
121438
121515
  const result = await runProcess(
121439
121516
  "docker",
@@ -121472,9 +121549,9 @@ async function ensureApplier(context) {
121472
121549
  if (await label("portta.apply.spec") === spec) return { action: "kept" };
121473
121550
  if (!await removeApplier()) return { action: "failed", reason: "the running applier could not be replaced" };
121474
121551
  }
121475
- const context_dir = join54(context.root, "docker", "images", "apply");
121552
+ const context_dir = join55(context.root, "docker", "images", "apply");
121476
121553
  const image = porttaImages(context.version).apply;
121477
- if (!existsSync34(join54(context_dir, "Dockerfile"))) {
121554
+ if (!existsSync34(join55(context_dir, "Dockerfile"))) {
121478
121555
  return { action: "failed", reason: `no applier image source at ${context_dir}` };
121479
121556
  }
121480
121557
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121488,8 +121565,9 @@ async function ensureApplier(context) {
121488
121565
 
121489
121566
  // src/commands/runner.ts
121490
121567
  init_src();
121568
+ init_process();
121491
121569
  import { existsSync as existsSync35 } from "node:fs";
121492
- import { join as join55 } from "node:path";
121570
+ import { join as join56 } from "node:path";
121493
121571
  async function label2(name) {
121494
121572
  const result = await runProcess(
121495
121573
  "docker",
@@ -121528,9 +121606,9 @@ async function ensureRunner(context) {
121528
121606
  if (await label2("portta.runner.spec") === spec) return { action: "kept" };
121529
121607
  if (!await removeRunner()) return { action: "failed", reason: "the running runner could not be replaced" };
121530
121608
  }
121531
- const context_dir = join55(context.root, "docker", "images", "apply");
121609
+ const context_dir = join56(context.root, "docker", "images", "apply");
121532
121610
  const image = porttaImages(context.version).apply;
121533
- if (!existsSync35(join55(context_dir, "Dockerfile"))) {
121611
+ if (!existsSync35(join56(context_dir, "Dockerfile"))) {
121534
121612
  return { action: "failed", reason: `no runner image source at ${context_dir}` };
121535
121613
  }
121536
121614
  const present = await runProcess("docker", ["image", "inspect", image], { reject: false });
@@ -121543,20 +121621,22 @@ async function ensureRunner(context) {
121543
121621
  }
121544
121622
 
121545
121623
  // src/checkout-cli.ts
121624
+ init_process();
121546
121625
  import { existsSync as existsSync36, readdirSync as readdirSync6, statSync as statSync11 } from "node:fs";
121547
- import { join as join56 } from "node:path";
121626
+ import { join as join57 } from "node:path";
121548
121627
  var CHECKOUT_CLI_SOURCES = [
121549
121628
  "packages/cli/src",
121550
121629
  "packages/cli/scripts",
121551
121630
  "packages/cli/package.json",
121552
121631
  "packages/core/src",
121553
- "packages/contracts/src"
121632
+ "packages/contracts/src",
121633
+ "packages/host/src"
121554
121634
  ];
121555
121635
  function checkoutCliDist(root2) {
121556
- return join56(root2, "packages/cli/dist/cli.js");
121636
+ return join57(root2, "packages/cli/dist/cli.js");
121557
121637
  }
121558
121638
  function isCheckout(root2) {
121559
- 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"));
121560
121640
  }
121561
121641
  function newestSourceMtime(path7) {
121562
121642
  if (!existsSync36(path7)) return 0;
@@ -121564,7 +121644,7 @@ function newestSourceMtime(path7) {
121564
121644
  if (info.isFile()) return /\.(ts|mjs|json)$/.test(path7) ? info.mtimeMs : 0;
121565
121645
  let newest = 0;
121566
121646
  for (const entry of readdirSync6(path7, { withFileTypes: true })) {
121567
- newest = Math.max(newest, newestSourceMtime(join56(path7, entry.name)));
121647
+ newest = Math.max(newest, newestSourceMtime(join57(path7, entry.name)));
121568
121648
  }
121569
121649
  return newest;
121570
121650
  }
@@ -121573,7 +121653,7 @@ function checkoutCliNeedsBuild(root2) {
121573
121653
  const dist = checkoutCliDist(root2);
121574
121654
  if (!existsSync36(dist)) return true;
121575
121655
  const distTime = statSync11(dist).mtimeMs;
121576
- return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join56(root2, tree)) > distTime);
121656
+ return CHECKOUT_CLI_SOURCES.some((tree) => newestSourceMtime(join57(root2, tree)) > distTime);
121577
121657
  }
121578
121658
  async function ensureCheckoutCli(root2, output2) {
121579
121659
  if (!checkoutCliNeedsBuild(root2)) return false;
@@ -121594,8 +121674,9 @@ async function reexecBuiltCli(root2) {
121594
121674
  init_src();
121595
121675
  init_context();
121596
121676
  init_errors3();
121597
- import { existsSync as existsSync37, readdirSync as readdirSync7, readFileSync as readFileSync29 } from "node:fs";
121598
- 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();
121599
121680
  var PORTTA_DIRECTORY = ".portta";
121600
121681
  var OVERLAY_FILE = "compose.portta.yaml";
121601
121682
  var COMPOSE_FILE = "compose.yaml";
@@ -121605,17 +121686,17 @@ var DEMO_DIRECTORY_PREFIX = "portta-demo-";
121605
121686
  var MANIFEST_FILE = "portta.example.json";
121606
121687
  function demoDirectories(home2) {
121607
121688
  if (!existsSync37(home2)) return [];
121608
- 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();
121609
121690
  }
121610
121691
  function findDemoStacks(home2) {
121611
121692
  return demoDirectories(home2).map((stackDir) => {
121612
- if (!existsSync37(join57(stackDir, COMPOSE_FILE))) return null;
121613
- const localOverlay = join57(PORTTA_DIRECTORY, OVERLAY_FILE);
121614
- 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));
121615
121696
  return {
121616
121697
  name: basename20(stackDir),
121617
121698
  dir: stackDir,
121618
- 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],
121619
121700
  overlay: overlay2
121620
121701
  };
121621
121702
  }).filter((stack) => stack !== null).sort((left, right) => left.name.localeCompare(right.name));
@@ -121626,10 +121707,10 @@ function demoComposeArgs(stack, action) {
121626
121707
  return ["compose", ...files, "down", "-v"];
121627
121708
  }
121628
121709
  function readDemoProject(stackDir) {
121629
- const path7 = join57(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121710
+ const path7 = join58(stackDir, PORTTA_DIRECTORY, MANIFEST_FILE);
121630
121711
  if (!existsSync37(path7)) return null;
121631
121712
  try {
121632
- const manifest = JSON.parse(readFileSync29(path7, "utf8"));
121713
+ const manifest = JSON.parse(readFileSync28(path7, "utf8"));
121633
121714
  const project2 = manifest.project;
121634
121715
  if (typeof project2?.["slug"] !== "string" || typeof project2["name"] !== "string") return null;
121635
121716
  const repositories = (Array.isArray(manifest.repositories) ? manifest.repositories : []).filter((repository) => typeof repository?.["name"] === "string" && typeof repository["relativePath"] === "string").map((repository) => ({
@@ -121794,7 +121875,7 @@ function checkoutLocalEnv() {
121794
121875
  };
121795
121876
  }
121796
121877
  function persistEnv(root2, values) {
121797
- const path7 = join58(root2, ".env");
121878
+ const path7 = join59(root2, ".env");
121798
121879
  patchEnvFile(path7, values);
121799
121880
  }
121800
121881
  function buildsLocally(command) {
@@ -121810,10 +121891,10 @@ async function compose2(command, args, stdio = "inherit", extra = {}) {
121810
121891
  return runProcess("docker", ["compose", ...composeArguments(context), ...args], { cwd: context.root, env: context.env, stdio, reject: extra.reject });
121811
121892
  }
121812
121893
  function ensureAuthState(root2) {
121813
- const authDirectory = join58(root2, "state/auth");
121814
- mkdirSync18(authDirectory, { recursive: true, mode: 448 });
121894
+ const authDirectory = join59(root2, "state/auth");
121895
+ mkdirSync19(authDirectory, { recursive: true, mode: 448 });
121815
121896
  chmodSync9(authDirectory, 448);
121816
- const path7 = join58(root2, ".env");
121897
+ const path7 = join59(root2, ".env");
121817
121898
  prepareEnvFile(path7);
121818
121899
  syncForwardAuth(root2);
121819
121900
  }
@@ -121865,7 +121946,7 @@ async function versionCommand(command) {
121865
121946
  output2.line(` panel ${panel.detail}`);
121866
121947
  if (!compatible) {
121867
121948
  output2.warning(`this CLI is ${cli} and the installation is ${gateway}`);
121868
- 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}`);
121869
121950
  }
121870
121951
  }
121871
121952
  async function bootstrapCommand(options, command) {
@@ -121876,9 +121957,8 @@ async function bootstrapCommand(options, command) {
121876
121957
  await requireDocker();
121877
121958
  const composeVersion = await runProcess("docker", ["compose", "version", "--short"], { reject: false });
121878
121959
  if (composeVersion.exitCode !== 0) throw new CliError("Docker Compose v2 is required", EXIT.precondition);
121879
- prepareEnvFile(join58(context.root, ".env"));
121880
- 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 });
121881
- chmodSync9(join58(context.root, "state/ssh"), 448);
121960
+ prepareEnvFile(join59(context.root, ".env"));
121961
+ ensureInstallationDirectories(context.root);
121882
121962
  ensureAuthState(context.root);
121883
121963
  const network2 = await ensureNetwork(context.config.network);
121884
121964
  output2.progress(`${network2.padEnd(8)} shared network ${context.config.network}`);
@@ -121887,7 +121967,7 @@ async function bootstrapCommand(options, command) {
121887
121967
  }
121888
121968
  async function upCommand(profile, options, command) {
121889
121969
  if (profile) command.setOptionValueWithSource("profile", profile, "cli");
121890
- prepareEnvFile(join58(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
121970
+ prepareEnvFile(join59(gatewayContext({ profile: profile ?? globals8(command).profile }).root, ".env"));
121891
121971
  if (options.localRelease) selectLocalRelease(gatewayContext({ profile: profile ?? globals8(command).profile }));
121892
121972
  const context = gatewayContext({ profile: profile ?? globals8(command).profile });
121893
121973
  if (options.localRelease) context.env["PORTTA_LOCAL_RELEASE"] = "true";
@@ -121951,7 +122031,7 @@ async function devCommand(profile, options, command) {
121951
122031
  return;
121952
122032
  }
121953
122033
  if (options.demo) requireDemoStacks(command);
121954
- const needsBootstrap = !existsSync38(join58(existing.root, ".env"));
122034
+ const needsBootstrap = !existsSync38(join59(existing.root, ".env"));
121955
122035
  output2.progress(`dev runs: ${[
121956
122036
  ...options.reset ? ["wipe Portta-managed containers and volumes"] : [],
121957
122037
  ...needsBootstrap ? ["prepare the checkout"] : [],
@@ -121989,10 +122069,10 @@ var REGENERABLE_STATE_DIRS = ["state/git", "state/metrics", "state/environment"]
121989
122069
  function clearRegenerableState(root2) {
121990
122070
  const cleared = [];
121991
122071
  for (const relative6 of REGENERABLE_STATE_DIRS) {
121992
- const directory = join58(root2, relative6);
122072
+ const directory = join59(root2, relative6);
121993
122073
  if (!existsSync38(directory)) continue;
121994
122074
  for (const entry of readdirSync8(directory, { withFileTypes: true })) {
121995
- rmSync10(join58(directory, entry.name), { recursive: true, force: true });
122075
+ rmSync10(join59(directory, entry.name), { recursive: true, force: true });
121996
122076
  }
121997
122077
  cleared.push(relative6);
121998
122078
  }
@@ -122071,7 +122151,7 @@ async function logsCommand(service2, options, command) {
122071
122151
  } else await compose2(command, ["logs", ...options.follow === false ? [] : ["--follow"], "--tail", options.tail ?? "200", ...service2 ? [service2] : []]);
122072
122152
  }
122073
122153
  async function updateCommand(command) {
122074
- prepareEnvFile(join58(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122154
+ prepareEnvFile(join59(gatewayContext({ profile: globals8(command).profile }).root, ".env"));
122075
122155
  await compose2(command, ["config", "--quiet"]);
122076
122156
  await compose2(command, ["pull", "--ignore-buildable"]);
122077
122157
  await confirm("recreate gateway components with the pulled images?", globals8(command).yes === true);
@@ -122133,7 +122213,7 @@ async function doctorCommand(command) {
122133
122213
  ...entry.fix ? { fix: entry.fix } : {}
122134
122214
  }));
122135
122215
  for (const file2 of context.composeFiles) {
122136
- 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` });
122137
122217
  }
122138
122218
  const aliases = readAliases(context.root);
122139
122219
  if (aliases.length > 0) {
@@ -122151,10 +122231,10 @@ async function doctorCommand(command) {
122151
122231
  if (failed.length) throw new CliError(`${failed.length} doctor check(s) failed`);
122152
122232
  }
122153
122233
  function readAliases(root2) {
122154
- const path7 = join58(root2, "config/traefik/dynamic/portta-aliases.yaml");
122234
+ const path7 = join59(root2, "config/traefik/dynamic/portta-aliases.yaml");
122155
122235
  if (!existsSync38(path7)) return [];
122156
122236
  try {
122157
- return parseAliases(readFileSync30(path7, "utf8"));
122237
+ return parseAliases(readFileSync29(path7, "utf8"));
122158
122238
  } catch {
122159
122239
  return [];
122160
122240
  }
@@ -122183,9 +122263,10 @@ async function urlsCommand(options, command) {
122183
122263
  // src/commands/network.ts
122184
122264
  init_src();
122185
122265
  import { lookup } from "node:dns/promises";
122186
- import { join as join59 } from "node:path";
122266
+ import { join as join60 } from "node:path";
122187
122267
  init_context();
122188
122268
  init_errors3();
122269
+ init_process();
122189
122270
  function globals9(command) {
122190
122271
  return command.optsWithGlobals();
122191
122272
  }
@@ -122221,7 +122302,7 @@ async function publicStatus(command) {
122221
122302
  }
122222
122303
  async function writeSetting(key, value3, command) {
122223
122304
  const context = gatewayContext({ profile: globals9(command).profile });
122224
- const path7 = join59(context.root, ".env");
122305
+ const path7 = join60(context.root, ".env");
122225
122306
  patchEnvFile(path7, { [key]: value3 });
122226
122307
  }
122227
122308
  async function publicEnable(command) {
@@ -122307,18 +122388,19 @@ async function dnsSetup(options, command) {
122307
122388
 
122308
122389
  // src/commands/host-service.ts
122309
122390
  init_config2();
122310
- 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";
122311
122392
  import { homedir as homedir9 } from "node:os";
122312
- import { dirname as dirname29, join as join60 } from "node:path";
122393
+ import { dirname as dirname29, join as join61 } from "node:path";
122313
122394
  init_context();
122314
122395
  init_errors3();
122396
+ init_process();
122315
122397
  var AUTO_PICKUP_ENV_VARS = ["LINEAR_API_KEY"];
122316
122398
  var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PATH", "PORTTA_ROOT"]);
122317
122399
  function logFile2() {
122318
- return join60(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122400
+ return join61(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122319
122401
  }
122320
122402
  function serviceFilePath(platform4, home2 = homedir9()) {
122321
- 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`);
122322
122404
  }
122323
122405
  function escapePlistText(value3) {
122324
122406
  return value3.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -122388,7 +122470,7 @@ var LAUNCHD_ENV_ENTRY_RE = /<key>([^<]+)<\/key>\s*<string>([^<]*)<\/string>/g;
122388
122470
  function readEnvVarsFromUnit(filePath, platform4) {
122389
122471
  let text;
122390
122472
  try {
122391
- text = readFileSync31(filePath, "utf8");
122473
+ text = readFileSync30(filePath, "utf8");
122392
122474
  } catch {
122393
122475
  return {};
122394
122476
  }
@@ -122519,7 +122601,7 @@ async function hostService(action, command) {
122519
122601
  ${notes.join("\n")}`);
122520
122602
  await confirm(`${installed ? "Reinstall" : "Install"} the ${SERVICE_IDENTITY.name} service?`, Boolean(options.yes));
122521
122603
  if (installed) await runAll(serviceCommands("uninstall", platform4, filePath), output2, true);
122522
- mkdirSync19(dirname29(filePath), { recursive: true });
122604
+ mkdirSync20(dirname29(filePath), { recursive: true });
122523
122605
  writeFileSync14(filePath, content);
122524
122606
  if (Object.keys(envVars).length > 0) chmodSync10(filePath, 384);
122525
122607
  await runAll(serviceCommands("install", platform4, filePath), output2);
@@ -122560,7 +122642,8 @@ init_src();
122560
122642
  init_src();
122561
122643
  init_context();
122562
122644
  init_errors3();
122563
- import { join as join61 } from "node:path";
122645
+ import { join as join62 } from "node:path";
122646
+ init_process();
122564
122647
  function globals10(command) {
122565
122648
  return command.optsWithGlobals();
122566
122649
  }
@@ -122602,7 +122685,7 @@ function setting(name) {
122602
122685
  return found;
122603
122686
  }
122604
122687
  function write2(root2, values) {
122605
- const path7 = join61(root2, ".env");
122688
+ const path7 = join62(root2, ".env");
122606
122689
  patchEnvFile(path7, values);
122607
122690
  }
122608
122691
  async function configList(command) {
@@ -122812,18 +122895,19 @@ async function configSet(name, value3, options, command) {
122812
122895
  }
122813
122896
  function configPrepare(command) {
122814
122897
  const context = gatewayContext({ profile: globals10(command).profile });
122815
- prepareEnvFile(join61(context.root, ".env"));
122898
+ prepareEnvFile(join62(context.root, ".env"));
122816
122899
  new Output(globals10(command)).progress("configuration prepared from .env.example; existing values preserved");
122817
122900
  }
122818
122901
 
122819
122902
  // src/commands/setup.ts
122820
122903
  init_src();
122821
122904
  init_context();
122822
- 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";
122823
122906
  import { homedir as homedir10 } from "node:os";
122824
- 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";
122825
122908
  import { fileURLToPath as fileURLToPath8 } from "node:url";
122826
122909
  init_errors3();
122910
+ init_process();
122827
122911
  function globals11(command) {
122828
122912
  return command.optsWithGlobals();
122829
122913
  }
@@ -122837,14 +122921,14 @@ async function available(file2, args) {
122837
122921
  function packagedRuntime() {
122838
122922
  const explicit = process.env["PORTTA_RUNTIME_ROOT"];
122839
122923
  if (explicit) return resolve32(explicit);
122840
- const candidates = [join62(import.meta.dirname, "runtime"), join62(import.meta.dirname, "..", "runtime")];
122841
- const found = candidates.find((candidate) => existsSync40(join62(candidate, "VERSION")));
122842
- 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");
122843
122927
  return found;
122844
122928
  }
122845
122929
  function installRuntime(source, target) {
122846
- mkdirSync20(target, { recursive: true });
122847
- const cache2 = join62(target, "runtime");
122930
+ mkdirSync21(target, { recursive: true });
122931
+ const cache2 = join63(target, "runtime");
122848
122932
  const sameCache = existsSync40(cache2) && realpathSync8(source) === realpathSync8(cache2);
122849
122933
  if (!sameCache) {
122850
122934
  rmSync11(cache2, { recursive: true, force: true });
@@ -122852,32 +122936,32 @@ function installRuntime(source, target) {
122852
122936
  }
122853
122937
  for (const entry of readdirSync9(source)) {
122854
122938
  if (entry === "config") continue;
122855
- const destination = join62(target, entry);
122939
+ const destination = join63(target, entry);
122856
122940
  rmSync11(destination, { recursive: true, force: true });
122857
- cpSync(join62(source, entry), destination, { recursive: true, force: true });
122941
+ cpSync(join63(source, entry), destination, { recursive: true, force: true });
122858
122942
  }
122859
- const defaults = join62(source, "config", "traefik", "dynamic");
122860
- const dynamic = join62(target, "config", "traefik", "dynamic");
122861
- 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 });
122862
122946
  for (const entry of readdirSync9(defaults)) {
122863
- const destination = join62(dynamic, entry);
122864
- if (!existsSync40(destination)) copyFileSync4(join62(defaults, entry), destination);
122947
+ const destination = join63(dynamic, entry);
122948
+ if (!existsSync40(destination)) copyFileSync4(join63(defaults, entry), destination);
122865
122949
  }
122866
- const bin = join62(target, "bin");
122867
- mkdirSync20(bin, { recursive: true });
122950
+ const bin = join63(target, "bin");
122951
+ mkdirSync21(bin, { recursive: true });
122868
122952
  const executable2 = fileURLToPath8(import.meta.url);
122869
- const installed = join62(bin, "portta");
122953
+ const installed = join63(bin, "portta");
122870
122954
  if (resolve32(executable2) !== resolve32(installed)) copyFileSync4(executable2, installed);
122871
122955
  chmodSync11(installed, 493);
122872
- const docs2 = join62(import.meta.dirname, "documentation.json");
122873
- 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"));
122874
122958
  }
122875
122959
  async function setupCommand(options, command) {
122876
122960
  const global3 = globals11(command);
122877
122961
  const output2 = new Output(global3);
122878
122962
  if (process.platform === "win32") throw new PreconditionError("setup requires a POSIX host");
122879
122963
  const currentRoot = findGatewayRoot();
122880
- const target = resolve32(options.dir ?? currentRoot ?? join62(homedir10(), "portta"));
122964
+ const target = resolve32(options.dir ?? currentRoot ?? join63(homedir10(), "portta"));
122881
122965
  const profile = options.profile ?? global3.profile ?? "local";
122882
122966
  const runtime2 = packagedRuntime();
122883
122967
  const steps = [];
@@ -122886,8 +122970,9 @@ async function setupCommand(options, command) {
122886
122970
  if (!output2.json) output2.progress(`${status.padEnd(8)} ${detail2}`);
122887
122971
  };
122888
122972
  const nodeVersion = process.versions.node;
122889
- 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");
122890
122974
  record6("node", "ok", `Node ${nodeVersion}`);
122975
+ await requireDocker();
122891
122976
  const docker = await available("docker", ["version", "--format", "{{.Server.Version}}"]);
122892
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");
122893
122978
  const compose4 = await available("docker", ["compose", "version", "--short"]);
@@ -122895,25 +122980,24 @@ async function setupCommand(options, command) {
122895
122980
  record6("docker", "ok", `Docker ${docker.value}, Compose ${compose4.value}`);
122896
122981
  if (options.dryRun) {
122897
122982
  record6("runtime", "planned", `install packaged runtime in ${target}`);
122898
- record6("environment", "planned", `create .env only if absent in ${target}`);
122983
+ record6("environment", "planned", `prepare .env from .env.example in ${target}, keeping set values`);
122899
122984
  record6("network", "planned", "ensure the shared gateway network");
122900
122985
  record6("gateway", "planned", `pull pinned images and start profile ${profile}`);
122901
122986
  if (output2.json) output2.data({ dryRun: true, target, steps });
122902
122987
  return;
122903
122988
  }
122904
122989
  await confirm(`set up Portta in ${target}?`, global3.yes === true);
122905
- 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"))) {
122906
122991
  throw new RefusedError(`${target} exists and is not a Portta installation`, "choose an empty --dir; setup never overwrites an unrelated directory");
122907
122992
  }
122908
- mkdirSync20(dirname30(target), { recursive: true });
122909
- const updating = existsSync40(join62(target, "VERSION"));
122993
+ mkdirSync21(dirname30(target), { recursive: true });
122994
+ const updating = existsSync40(join63(target, "VERSION"));
122910
122995
  installRuntime(runtime2, target);
122911
122996
  record6("runtime", updating ? "updated" : "created", `${target}`);
122912
- const envFile = join62(target, ".env");
122997
+ const envFile = join63(target, ".env");
122913
122998
  prepareEnvFile(envFile);
122914
122999
  record6("environment", "updated", "environment prepared from .env.example");
122915
- 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 });
122916
- for (const directory of ["state/auth", "state/ssh", "state/runner", "state/cloudflared"]) chmodSync11(join62(target, directory), 448);
123000
+ ensureInstallationDirectories(target);
122917
123001
  record6("directories", "ok", "gateway state directories");
122918
123002
  const context = gatewayContext({ root: target, profile });
122919
123003
  const network2 = await ensureNetwork(context.config.network);
@@ -122928,13 +123012,21 @@ async function setupCommand(options, command) {
122928
123012
  const running = await runProcess("docker", ["compose", ...composeArguments(context), "ps", "--status", "running", "--quiet"], { cwd: target, env: context.env });
122929
123013
  if (!running.stdout.trim()) throw new PreconditionError("gateway started but no component remained running", `run portta doctor inside ${target}`);
122930
123014
  record6("doctor", "ok", "gateway components are running");
122931
- 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.");
122932
123024
  }
122933
123025
 
122934
123026
  // src/commands/auth.ts
122935
123027
  init_context();
122936
123028
  init_errors3();
122937
- import { readFileSync as readFileSync32 } from "node:fs";
123029
+ import { readFileSync as readFileSync31 } from "node:fs";
122938
123030
  function globals12(command) {
122939
123031
  return command.optsWithGlobals();
122940
123032
  }
@@ -122949,7 +123041,7 @@ function panelUrlFor2(command) {
122949
123041
  }
122950
123042
  async function authBootstrap(options, command) {
122951
123043
  if (!options.name || !options.email) throw new UsageError("--name and --email are required");
122952
- const password = options.passwordStdin ? readFileSync32(0, "utf8").trim() : "";
123044
+ const password = options.passwordStdin ? readFileSync31(0, "utf8").trim() : "";
122953
123045
  if (!password) throw new UsageError("the password is read from stdin", 'printf %s "$PASSWORD" | portta auth bootstrap --name \u2026 --email \u2026 --password-stdin');
122954
123046
  if (password.length < 10) throw new UsageError("the password must be at least 10 characters");
122955
123047
  const { client, output: output2 } = clientFor(command, { actor: void 0, actorKind: "human" });
@@ -122982,7 +123074,7 @@ async function authLogin(options, command) {
122982
123074
  }
122983
123075
  async function readSecret() {
122984
123076
  if (!process.stdin.isTTY) {
122985
- const piped = readFileSync32(0, "utf8").trim();
123077
+ const piped = readFileSync31(0, "utf8").trim();
122986
123078
  if (piped) return piped;
122987
123079
  throw new UsageError("no token on stdin", "pass --token, or run this in a terminal");
122988
123080
  }
@@ -123121,23 +123213,23 @@ init_src();
123121
123213
  init_context();
123122
123214
  init_errors3();
123123
123215
  import { randomBytes as randomBytes8 } from "node:crypto";
123124
- import { chmodSync as chmodSync12, mkdirSync as mkdirSync21, readFileSync as readFileSync33 } from "node:fs";
123125
- 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";
123126
123218
  function globals13(command) {
123127
123219
  return command.optsWithGlobals();
123128
123220
  }
123129
123221
  function paths(command) {
123130
123222
  const root2 = gatewayContext({ profile: globals13(command).profile }).root;
123131
123223
  return {
123132
- store: join63(root2, "state/auth/protections.json"),
123133
- 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")
123134
123226
  };
123135
123227
  }
123136
123228
  function save(command, store) {
123137
123229
  const target = paths(command);
123138
- mkdirSync21(dirname31(target.store), { recursive: true, mode: 448 });
123230
+ mkdirSync22(dirname31(target.store), { recursive: true, mode: 448 });
123139
123231
  chmodSync12(dirname31(target.store), 448);
123140
- mkdirSync21(dirname31(target.dynamic), { recursive: true });
123232
+ mkdirSync22(dirname31(target.dynamic), { recursive: true });
123141
123233
  writeProtectionStore(target.store, store);
123142
123234
  writeEnvFile(target.dynamic, renderAuthDynamic(store));
123143
123235
  }
@@ -123153,7 +123245,7 @@ async function protectHost(hostInput, options, command) {
123153
123245
  const entryPoint = options.entrypoint ?? (gatewayContext({ profile: globals13(command).profile }).config.tlsEnabled ? "websecure" : "web");
123154
123246
  if (!/^[A-Za-z0-9_-]+$/.test(entryPoint)) throw new UsageError(`invalid entrypoint: ${entryPoint}`);
123155
123247
  const generated = options.passwordStdin !== true;
123156
- 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();
123157
123249
  if (!password) throw new UsageError("no password on stdin");
123158
123250
  const target = paths(command);
123159
123251
  const existing = readProtectionStore(target.store);
@@ -123206,11 +123298,12 @@ async function protectStatus(hostInput, command) {
123206
123298
  init_src();
123207
123299
  init_errors3();
123208
123300
  init_context();
123209
- import { readFileSync as readFileSync34 } from "node:fs";
123301
+ import { readFileSync as readFileSync33 } from "node:fs";
123210
123302
  import { randomBytes as randomBytes9 } from "node:crypto";
123303
+ init_process();
123211
123304
  function passwordFrom(options) {
123212
123305
  if (options.passwordStdin) {
123213
- const password2 = readFileSync34(0, "utf8").trim();
123306
+ const password2 = readFileSync33(0, "utf8").trim();
123214
123307
  if (!password2) throw new UsageError("no password on stdin");
123215
123308
  if (password2.length < 10) throw new UsageError("the password must be at least 10 characters");
123216
123309
  return { password: password2, generated: false };
@@ -123338,13 +123431,13 @@ init_zod();
123338
123431
  init_context();
123339
123432
  init_errors3();
123340
123433
  import { existsSync as existsSync41 } from "node:fs";
123341
- import { join as join64 } from "node:path";
123434
+ import { join as join65 } from "node:path";
123342
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();
123343
123436
  function globals14(command) {
123344
123437
  return command.optsWithGlobals();
123345
123438
  }
123346
123439
  function path6(command) {
123347
- 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");
123348
123441
  }
123349
123442
  function root(command) {
123350
123443
  return gatewayContext({ profile: globals14(command).profile }).root;
@@ -123360,11 +123453,11 @@ function write3(command, shares) {
123360
123453
  }
123361
123454
  function removeScopes(command, scopes) {
123362
123455
  const gateway = root(command);
123363
- const storePath = join64(gateway, "state/auth/protections.json");
123456
+ const storePath = join65(gateway, "state/auth/protections.json");
123364
123457
  const store = readProtectionStore(storePath);
123365
123458
  const next = { ...store, protections: store.protections.filter((protection) => !scopes.has(protection.scope)) };
123366
123459
  writeProtectionStore(storePath, next);
123367
- writeEnvFile(join64(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123460
+ writeEnvFile(join65(gateway, "config/traefik/dynamic/portta-auth.yaml"), renderAuthDynamic(next));
123368
123461
  }
123369
123462
  async function shareList(command) {
123370
123463
  const shares = read(command);
@@ -123395,14 +123488,16 @@ async function shareGc(command) {
123395
123488
  // src/commands/tls.ts
123396
123489
  init_src();
123397
123490
  init_context();
123398
- 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";
123399
123492
  import { platform as platform3 } from "node:os";
123400
- import { join as join65 } from "node:path";
123493
+ import { join as join66 } from "node:path";
123401
123494
  init_errors3();
123495
+ init_process();
123402
123496
 
123403
123497
  // src/toolbox.ts
123404
123498
  init_errors3();
123405
123499
  init_src();
123500
+ init_process();
123406
123501
  init_context();
123407
123502
  async function toolboxExists(image) {
123408
123503
  return !(await runProcess("docker", ["image", "inspect", image], { reject: false })).failed;
@@ -123432,14 +123527,14 @@ function globals15(command) {
123432
123527
  return command.optsWithGlobals();
123433
123528
  }
123434
123529
  function tlsPaths(root2) {
123435
- const directory = join65(root2, "config/tls");
123530
+ const directory = join66(root2, "config/tls");
123436
123531
  return {
123437
123532
  directory,
123438
- caKey: join65(directory, "portta-ca.key"),
123439
- caCertificate: join65(directory, "portta-ca.crt"),
123440
- leafKey: join65(directory, "wildcard.key"),
123441
- leafCertificate: join65(directory, "wildcard.crt"),
123442
- 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")
123443
123538
  };
123444
123539
  }
123445
123540
  function localTlsDynamic() {
@@ -123516,7 +123611,7 @@ async function tlsInit(command) {
123516
123611
  await requireDocker();
123517
123612
  const paths3 = tlsPaths(context.root);
123518
123613
  const domain2 = context.config.domain;
123519
- mkdirSync22(paths3.directory, { recursive: true });
123614
+ mkdirSync23(paths3.directory, { recursive: true });
123520
123615
  chmodSync13(paths3.directory, 448);
123521
123616
  if (existsSync42(paths3.caKey)) {
123522
123617
  output2.progress("reusing the existing local CA");
@@ -123547,7 +123642,7 @@ async function tlsInit(command) {
123547
123642
  }
123548
123643
  output2.progress(`issued ${paths3.leafCertificate} for *.${domain2}`);
123549
123644
  writeFileSync15(paths3.dynamic, localTlsDynamic());
123550
- const envPath = join65(context.root, ".env");
123645
+ const envPath = join66(context.root, ".env");
123551
123646
  patchEnvFile(envPath, { TLS_ENABLED: "true", TLS_MODE: "local" });
123552
123647
  output2.progress("TLS enabled in .env");
123553
123648
  output2.line("");
@@ -123596,22 +123691,23 @@ async function tlsUntrust(command) {
123596
123691
  output2.line(`To delete the key material as well: rm -rf ${paths2(context.root)}`);
123597
123692
  }
123598
123693
  function paths2(root2) {
123599
- return join65(root2, "config/tls");
123694
+ return join66(root2, "config/tls");
123600
123695
  }
123601
123696
 
123602
123697
  // src/commands/maintenance.ts
123603
123698
  init_src();
123604
123699
  init_context();
123605
123700
  init_errors3();
123606
- 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";
123607
123702
  import { hostname as hostname3, tmpdir as tmpdir5 } from "node:os";
123608
- import { dirname as dirname32, join as join66 } from "node:path";
123703
+ import { dirname as dirname32, join as join67 } from "node:path";
123704
+ init_process();
123609
123705
  function globals16(command) {
123610
123706
  return command.optsWithGlobals();
123611
123707
  }
123612
123708
  var BACKUP_VERSION = 1;
123613
123709
  function backupPaths(root2) {
123614
- return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join66(root2, path7)));
123710
+ return [".env", "VERSION", "config", "state"].filter((path7) => existsSync43(join67(root2, path7)));
123615
123711
  }
123616
123712
  function renderManifest(manifest) {
123617
123713
  return `${JSON.stringify(manifest)}
@@ -123646,11 +123742,11 @@ async function backupCommand(options, command) {
123646
123742
  const output2 = new Output(global3);
123647
123743
  const context = gatewayContext({ profile: global3.profile });
123648
123744
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123649
- const target = options.output ?? join66(context.root, `portta-backup-${stamp}.tar.gz`);
123650
- 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-"));
123651
123747
  chmodSync14(staging, 448);
123652
123748
  try {
123653
- writeFileSync16(join66(staging, "portta-backup.json"), renderManifest({
123749
+ writeFileSync16(join67(staging, "portta-backup.json"), renderManifest({
123654
123750
  version: BACKUP_VERSION,
123655
123751
  portta: context.version,
123656
123752
  created: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z"),
@@ -123658,12 +123754,12 @@ async function backupCommand(options, command) {
123658
123754
  }));
123659
123755
  const paths3 = backupPaths(context.root);
123660
123756
  for (const path7 of paths3) {
123661
- mkdirSync23(join66(staging, "tree", dirname32(path7)), { recursive: true });
123662
- 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 });
123663
123759
  }
123664
123760
  let database = false;
123665
123761
  if (options.database !== false) {
123666
- database = await dumpDatabase(context, join66(staging, "panel.db"));
123762
+ database = await dumpDatabase(context, join67(staging, "panel.db"));
123667
123763
  if (!database) {
123668
123764
  output2.warning("the panel database was not included");
123669
123765
  output2.hint("it exists once the panel has started, and copying it needs sqlite3 on this host; --no-database silences this");
@@ -123708,14 +123804,14 @@ async function restoreCommand(archive, options, command) {
123708
123804
  const context = gatewayContext({ profile: global3.profile });
123709
123805
  if (!archive) throw new UsageError("which backup?", "portta restore <file>");
123710
123806
  if (!existsSync43(archive)) throw new UsageError(`no such file: ${archive}`);
123711
- const staging = mkdtempSync3(join66(tmpdir5(), "portta-restore-"));
123807
+ const staging = mkdtempSync3(join67(tmpdir5(), "portta-restore-"));
123712
123808
  chmodSync14(staging, 448);
123713
123809
  try {
123714
123810
  const extracted = await runProcess("tar", ["-xzf", archive, "-C", staging], { reject: false });
123715
123811
  if (extracted.failed) throw new UsageError("that file is not a Portta backup");
123716
- const manifestPath2 = join66(staging, "portta-backup.json");
123812
+ const manifestPath2 = join67(staging, "portta-backup.json");
123717
123813
  if (!existsSync43(manifestPath2)) throw new UsageError("that archive has no Portta manifest");
123718
- const manifest = parseManifest(readFileSync35(manifestPath2, "utf8"));
123814
+ const manifest = parseManifest(readFileSync34(manifestPath2, "utf8"));
123719
123815
  if (!manifest) throw new UsageError("that archive has an unreadable Portta manifest");
123720
123816
  output2.progress(`restoring a backup taken from Portta ${manifest.portta}`);
123721
123817
  if (!options.force && await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-traefik-1`)) {
@@ -123725,23 +123821,23 @@ async function restoreCommand(archive, options, command) {
123725
123821
  );
123726
123822
  }
123727
123823
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
123728
- const safety = join66(context.root, "state", `restore-${stamp}`);
123729
- mkdirSync23(safety, { recursive: true });
123824
+ const safety = join67(context.root, "state", `restore-${stamp}`);
123825
+ mkdirSync24(safety, { recursive: true });
123730
123826
  for (const path7 of [".env", "config"]) {
123731
- if (existsSync43(join66(context.root, path7))) {
123732
- 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 });
123733
123829
  }
123734
123830
  }
123735
123831
  output2.progress(`kept what was there under ${safety}`);
123736
- const tree = join66(staging, "tree");
123832
+ const tree = join67(staging, "tree");
123737
123833
  if (existsSync43(tree)) {
123738
123834
  for (const path7 of backupPaths(tree)) {
123739
- 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 });
123740
123836
  }
123741
123837
  output2.progress("configuration and state restored");
123742
123838
  }
123743
- if (existsSync43(join66(context.root, ".env"))) chmodSync14(join66(context.root, ".env"), 384);
123744
- 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");
123745
123841
  if (existsSync43(dump)) {
123746
123842
  const panelUp = await containerRunning(`${context.env["PORTTA_PROJECT_NAME"] || "portta"}-web-1`);
123747
123843
  const target = databaseFileFor(context.root);
@@ -123749,7 +123845,7 @@ async function restoreCommand(archive, options, command) {
123749
123845
  output2.warning("the panel is running, so its database was not replaced");
123750
123846
  output2.hint(`portta web down then: portta restore ${archive} --force`);
123751
123847
  } else {
123752
- mkdirSync23(dirname32(target), { recursive: true });
123848
+ mkdirSync24(dirname32(target), { recursive: true });
123753
123849
  for (const file2 of databaseFiles(target)) rmSync12(file2, { force: true });
123754
123850
  copyFileSync5(dump, target);
123755
123851
  chmodSync14(target, 384);
@@ -123763,21 +123859,6 @@ async function restoreCommand(archive, options, command) {
123763
123859
  rmSync12(staging, { recursive: true, force: true });
123764
123860
  }
123765
123861
  }
123766
- var REPAIR_DIRECTORIES = [
123767
- { path: "config/traefik/dynamic", mode: 493 },
123768
- { path: "config/tls", mode: 493 },
123769
- { path: "state/traefik/acme", mode: 448 },
123770
- { path: "state/tailscale", mode: 493 },
123771
- { path: "state/access", mode: 493 },
123772
- { path: "state/git", mode: 493 },
123773
- { path: "state/github", mode: 493 },
123774
- { path: "state/ssh", mode: 448 },
123775
- { path: "state/metrics", mode: 493 },
123776
- { path: "state/environment", mode: 493 },
123777
- { path: "state/logs", mode: 493 },
123778
- { path: "state/runner", mode: 448 },
123779
- { path: "state/cloudflared", mode: 448 }
123780
- ];
123781
123862
  var REPAIR_MODES = [
123782
123863
  { path: ".env", mode: 384 },
123783
123864
  { path: "state/traefik/acme", mode: 448 },
@@ -123785,7 +123866,8 @@ var REPAIR_MODES = [
123785
123866
  { path: "state/cloudflared", mode: 448 },
123786
123867
  { path: "state/cloudflared/credentials.json", mode: 384 },
123787
123868
  { path: "state/runner", mode: 448 },
123788
- { path: "state/ssh", mode: 448 }
123869
+ { path: "state/ssh", mode: 448 },
123870
+ { path: "state/auth", mode: 448 }
123789
123871
  ];
123790
123872
  async function repairCommand2(options, command) {
123791
123873
  const global3 = globals16(command);
@@ -123794,20 +123876,20 @@ async function repairCommand2(options, command) {
123794
123876
  const dry = options.dryRun ?? false;
123795
123877
  const changes = [];
123796
123878
  output2.progress("Repair");
123797
- for (const { path: path7, mode } of REPAIR_DIRECTORIES) {
123798
- const full = join66(context.root, path7);
123879
+ for (const { path: path7, mode } of INSTALLATION_DIRECTORIES) {
123880
+ const full = join67(context.root, path7);
123799
123881
  if (existsSync43(full)) continue;
123800
123882
  changes.push(`create ${path7}`);
123801
123883
  if (dry) {
123802
123884
  output2.line(` would create ${path7}`);
123803
123885
  continue;
123804
123886
  }
123805
- mkdirSync23(full, { recursive: true });
123887
+ mkdirSync24(full, { recursive: true });
123806
123888
  chmodSync14(full, mode);
123807
123889
  output2.progress(`created ${path7}`);
123808
123890
  }
123809
123891
  for (const { path: path7, mode } of REPAIR_MODES) {
123810
- const full = join66(context.root, path7);
123892
+ const full = join67(context.root, path7);
123811
123893
  if (!existsSync43(full)) continue;
123812
123894
  const have = fileMode(full);
123813
123895
  const want = mode.toString(8);
@@ -128790,7 +128872,8 @@ async function activityCommand(options, command) {
128790
128872
  // src/commands/build.ts
128791
128873
  init_src();
128792
128874
  init_context();
128793
- import { join as join67 } from "node:path";
128875
+ import { join as join68 } from "node:path";
128876
+ init_process();
128794
128877
  function globals18(command) {
128795
128878
  return command.optsWithGlobals();
128796
128879
  }
@@ -128803,11 +128886,11 @@ function localReleaseBuilds(root2, version3) {
128803
128886
  },
128804
128887
  {
128805
128888
  image: images.apply,
128806
- 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")]
128807
128890
  },
128808
128891
  {
128809
128892
  image: images.toolbox,
128810
- 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")]
128811
128894
  }
128812
128895
  ];
128813
128896
  }
@@ -128827,12 +128910,13 @@ async function buildCommand(command) {
128827
128910
 
128828
128911
  // src/commands/remote.ts
128829
128912
  init_src();
128830
- import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync36, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
128831
- 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";
128832
128915
  import { createServer as createServer3 } from "node:net";
128833
128916
  import { randomBytes as randomBytes10 } from "node:crypto";
128834
128917
  init_context();
128835
128918
  init_errors3();
128919
+ init_process();
128836
128920
  function globals19(command) {
128837
128921
  return command.optsWithGlobals();
128838
128922
  }
@@ -129005,7 +129089,7 @@ async function remoteBootstrap(target, options, command) {
129005
129089
  output2.progress(" ./bin/portta network status confirm what is exposed");
129006
129090
  }
129007
129091
  function tunnelStateDir(root2) {
129008
- return join68(root2, "state/access/tunnels");
129092
+ return join69(root2, "state/access/tunnels");
129009
129093
  }
129010
129094
  function parseTunnelRecord(id, text) {
129011
129095
  try {
@@ -129036,9 +129120,9 @@ function readTunnels(root2) {
129036
129120
  if (!existsSync44(directory)) return [];
129037
129121
  const records = [];
129038
129122
  for (const name of readdirSync10(directory).filter((entry) => entry.endsWith(".json"))) {
129039
- const path7 = join68(directory, name);
129123
+ const path7 = join69(directory, name);
129040
129124
  try {
129041
- const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync36(path7, "utf8"));
129125
+ const record6 = parseTunnelRecord(basename21(name, ".json"), readFileSync35(path7, "utf8"));
129042
129126
  if (record6) records.push(record6);
129043
129127
  } catch {
129044
129128
  }
@@ -129090,7 +129174,7 @@ async function remoteAccessOpen(target, options, command) {
129090
129174
  const localPort = options.localPort ? Number(options.localPort) : await freeLocalPort();
129091
129175
  output2.progress("Opening the tunnel");
129092
129176
  const directoryPath = tunnelStateDir(context.root);
129093
- mkdirSync24(directoryPath, { recursive: true });
129177
+ mkdirSync25(directoryPath, { recursive: true });
129094
129178
  const id = randomBytes10(3).toString("hex");
129095
129179
  const pid = spawnDetached("ssh", sshArguments(target, context.env, [
129096
129180
  "-o",
@@ -129107,7 +129191,7 @@ async function remoteAccessOpen(target, options, command) {
129107
129191
  throw new PreconditionError("the SSH tunnel exited immediately", `check that ${target} is reachable and that ${localPort} is free locally`);
129108
129192
  }
129109
129193
  const record6 = { id, pid, target, project: options.project, service: options.service, remotePort, localPort, started: Math.floor(Date.now() / 1e3) };
129110
- writeFileSync17(join68(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129194
+ writeFileSync17(join69(directoryPath, `${id}.json`), renderTunnelRecord(record6));
129111
129195
  if (output2.json) {
129112
129196
  output2.data({ ...record6, address: `127.0.0.1:${localPort}` });
129113
129197
  return;
@@ -129160,7 +129244,7 @@ async function remoteAccessClose(id, options, command) {
129160
129244
  } catch {
129161
129245
  }
129162
129246
  }
129163
- rmSync13(join68(directory, `${record6.id}.json`), { force: true });
129247
+ rmSync13(join69(directory, `${record6.id}.json`), { force: true });
129164
129248
  output2.progress(`the bridge on ${record6.target} is still open; close it there if you are done:`);
129165
129249
  output2.hint(`portta remote exec ${record6.target} -- 'cd portta && ./bin/portta access close --project ${record6.project}'`);
129166
129250
  }
@@ -129172,15 +129256,16 @@ init_src();
129172
129256
  init_src();
129173
129257
  init_context();
129174
129258
  init_errors3();
129175
- 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";
129176
129260
  import { ReadStream } from "node:tty";
129177
- import { join as join69 } from "node:path";
129261
+ import { join as join70 } from "node:path";
129262
+ init_process();
129178
129263
  function globals20(command) {
129179
129264
  return command.optsWithGlobals();
129180
129265
  }
129181
129266
  function tunnelPaths(root2) {
129182
- const directory = join69(root2, "state/cloudflared");
129183
- 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") };
129184
129269
  }
129185
129270
  function tunnelContainer(env) {
129186
129271
  return `${env["PORTTA_PROJECT_NAME"] || "portta"}-cloudflared-1`;
@@ -129315,13 +129400,13 @@ async function tunnelSetup(options, command) {
129315
129400
  let token;
129316
129401
  if (options.tokenFile) {
129317
129402
  if (!existsSync45(options.tokenFile)) throw new UsageError(`no such file: ${options.tokenFile}`);
129318
- token = readFileSync37(options.tokenFile, "utf8").replace(/\s+/g, "");
129403
+ token = readFileSync36(options.tokenFile, "utf8").replace(/\s+/g, "");
129319
129404
  } else {
129320
129405
  token = await promptForToken();
129321
129406
  }
129322
129407
  if (!token) throw new UsageError("no token was given");
129323
129408
  const paths3 = tunnelPaths(context.root);
129324
- mkdirSync25(paths3.directory, { recursive: true });
129409
+ mkdirSync26(paths3.directory, { recursive: true });
129325
129410
  chmodSync15(paths3.directory, 448);
129326
129411
  let credentials;
129327
129412
  try {
@@ -129337,7 +129422,7 @@ async function tunnelSetup(options, command) {
129337
129422
  const origin = options.origin || defaultOrigin(context);
129338
129423
  const config3 = { id: credentials.TunnelID, zone: options.zone, origin, credentialsFile: "/etc/cloudflared/credentials.json", includeApex: options.apex ?? false };
129339
129424
  writeFileSync18(paths3.config, renderTunnelConfig(config3));
129340
- const envPath = join69(context.root, ".env");
129425
+ const envPath = join70(context.root, ".env");
129341
129426
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ZONE: options.zone, CLOUDFLARE_TUNNEL_ID: credentials.TunnelID });
129342
129427
  if (output2.json) {
129343
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 } });
@@ -129366,7 +129451,7 @@ async function tunnelEnable(command) {
129366
129451
  if (!tunnelConfigured(context.root)) {
129367
129452
  throw new PreconditionError("the connector is not configured", "portta tunnel setup --zone <domain>");
129368
129453
  }
129369
- const envPath = join69(context.root, ".env");
129454
+ const envPath = join70(context.root, ".env");
129370
129455
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ENABLED: "true" });
129371
129456
  output2.progress("Cloudflare Tunnel enabled");
129372
129457
  output2.progress("starting the connector");
@@ -129389,7 +129474,7 @@ async function tunnelDisable(options, command) {
129389
129474
  ["compose", ...composeArguments(running), "rm", "-sf", "cloudflared"],
129390
129475
  { cwd: running.root, env: running.env, reject: false }
129391
129476
  );
129392
- const envPath = join69(running.root, ".env");
129477
+ const envPath = join70(running.root, ".env");
129393
129478
  const values = { CLOUDFLARE_TUNNEL_ENABLED: "false" };
129394
129479
  if (options.forget) {
129395
129480
  const paths3 = tunnelPaths(running.root);