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