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