@codions/portta 0.0.0-develop.166.sha-d31f10f → 0.0.0-develop.171.sha-d749180
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/cli.js +180 -33
- package/dist/documentation.json +1 -1
- package/dist/host.js +59 -7
- package/dist/runtime/VERSION +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -21311,6 +21311,113 @@ var init_password = __esm({
|
|
|
21311
21311
|
}
|
|
21312
21312
|
});
|
|
21313
21313
|
|
|
21314
|
+
// ../core/src/project-config.ts
|
|
21315
|
+
function hostShape(value3) {
|
|
21316
|
+
if (/:\/\//.test(value3)) return "looks like a URL";
|
|
21317
|
+
if (value3.startsWith("//")) return "looks like a URL";
|
|
21318
|
+
if (value3.startsWith("/")) return "is an absolute path";
|
|
21319
|
+
if (/^[a-z]:[\\/]/i.test(value3)) return "is an absolute path";
|
|
21320
|
+
if (value3.startsWith("~")) return "is a home-relative path, which differs per machine";
|
|
21321
|
+
if (/^\d{1,5}:\d{1,5}$/.test(value3)) return "looks like a published host port";
|
|
21322
|
+
return null;
|
|
21323
|
+
}
|
|
21324
|
+
function defaultProjectConfig() {
|
|
21325
|
+
return {
|
|
21326
|
+
version: 1,
|
|
21327
|
+
name: null,
|
|
21328
|
+
mainBranch: null,
|
|
21329
|
+
worktrees: {
|
|
21330
|
+
root: PROJECT_CONFIG_DEFAULTS.worktreeRoot,
|
|
21331
|
+
branchPattern: PROJECT_CONFIG_DEFAULTS.branchPattern
|
|
21332
|
+
},
|
|
21333
|
+
stack: [],
|
|
21334
|
+
instructions: []
|
|
21335
|
+
};
|
|
21336
|
+
}
|
|
21337
|
+
function parseProjectConfig(document) {
|
|
21338
|
+
if (document === null || document === void 0) {
|
|
21339
|
+
return { ok: false, issues: [{ path: "", message: `${PROJECT_CONFIG_FILE} is empty` }] };
|
|
21340
|
+
}
|
|
21341
|
+
const parsed = Schema.safeParse(document);
|
|
21342
|
+
if (!parsed.success) {
|
|
21343
|
+
return {
|
|
21344
|
+
ok: false,
|
|
21345
|
+
issues: parsed.error.issues.map((issue2) => ({
|
|
21346
|
+
path: issue2.path.join("."),
|
|
21347
|
+
message: issue2.message
|
|
21348
|
+
}))
|
|
21349
|
+
};
|
|
21350
|
+
}
|
|
21351
|
+
const value3 = parsed.data;
|
|
21352
|
+
const defaults = defaultProjectConfig();
|
|
21353
|
+
return {
|
|
21354
|
+
ok: true,
|
|
21355
|
+
config: {
|
|
21356
|
+
version: 1,
|
|
21357
|
+
name: value3.name ?? null,
|
|
21358
|
+
mainBranch: value3.mainBranch ?? null,
|
|
21359
|
+
worktrees: {
|
|
21360
|
+
root: value3.worktrees?.root ?? defaults.worktrees.root,
|
|
21361
|
+
branchPattern: value3.worktrees?.branchPattern ?? defaults.worktrees.branchPattern
|
|
21362
|
+
},
|
|
21363
|
+
stack: value3.stack ?? [],
|
|
21364
|
+
instructions: value3.instructions ?? []
|
|
21365
|
+
}
|
|
21366
|
+
};
|
|
21367
|
+
}
|
|
21368
|
+
var PROJECT_CONFIG_FILE, PROJECT_CONFIG_PATH, PROJECT_CONFIG_DEFAULTS, BRANCH_PATTERN_PLACEHOLDERS, portable, repoRelativePath, branchPattern, Schema;
|
|
21369
|
+
var init_project_config = __esm({
|
|
21370
|
+
"../core/src/project-config.ts"() {
|
|
21371
|
+
"use strict";
|
|
21372
|
+
init_zod();
|
|
21373
|
+
PROJECT_CONFIG_FILE = "project.yaml";
|
|
21374
|
+
PROJECT_CONFIG_PATH = `.portta/${PROJECT_CONFIG_FILE}`;
|
|
21375
|
+
PROJECT_CONFIG_DEFAULTS = {
|
|
21376
|
+
worktreeRoot: ".portta/worktrees",
|
|
21377
|
+
branchPattern: "{type}/{slug}"
|
|
21378
|
+
};
|
|
21379
|
+
BRANCH_PATTERN_PLACEHOLDERS = ["type", "slug"];
|
|
21380
|
+
portable = (label3) => external_exports.string().trim().min(1).superRefine((value3, ctx) => {
|
|
21381
|
+
const shape = hostShape(value3);
|
|
21382
|
+
if (shape) {
|
|
21383
|
+
ctx.addIssue({
|
|
21384
|
+
code: "custom",
|
|
21385
|
+
message: `${label3} ${shape}; that belongs to the host, not to the project (ADR 0052)`
|
|
21386
|
+
});
|
|
21387
|
+
}
|
|
21388
|
+
});
|
|
21389
|
+
repoRelativePath = (label3) => portable(label3).superRefine((value3, ctx) => {
|
|
21390
|
+
const normalized = value3.replaceAll("\\", "/");
|
|
21391
|
+
if (normalized.split("/").includes("..")) {
|
|
21392
|
+
ctx.addIssue({ code: "custom", message: `${label3} escapes the repository with '..'` });
|
|
21393
|
+
}
|
|
21394
|
+
});
|
|
21395
|
+
branchPattern = portable("the branch pattern").superRefine((value3, ctx) => {
|
|
21396
|
+
const used = [...value3.matchAll(/\{([^}]*)\}/g)].map((match2) => match2[1] ?? "");
|
|
21397
|
+
const allowed = new Set(BRANCH_PATTERN_PLACEHOLDERS);
|
|
21398
|
+
for (const placeholder of used) {
|
|
21399
|
+
if (!allowed.has(placeholder)) {
|
|
21400
|
+
ctx.addIssue({
|
|
21401
|
+
code: "custom",
|
|
21402
|
+
message: `unknown placeholder {${placeholder}}; the branch pattern accepts ${BRANCH_PATTERN_PLACEHOLDERS.map((name) => `{${name}}`).join(" and ")}`
|
|
21403
|
+
});
|
|
21404
|
+
}
|
|
21405
|
+
}
|
|
21406
|
+
});
|
|
21407
|
+
Schema = external_exports.strictObject({
|
|
21408
|
+
version: external_exports.literal(1),
|
|
21409
|
+
name: portable("the project name").optional(),
|
|
21410
|
+
mainBranch: portable("the main branch").optional(),
|
|
21411
|
+
worktrees: external_exports.strictObject({
|
|
21412
|
+
root: repoRelativePath("the worktree root").optional(),
|
|
21413
|
+
branchPattern: branchPattern.optional()
|
|
21414
|
+
}).optional(),
|
|
21415
|
+
stack: external_exports.array(external_exports.string().trim().min(1).regex(/^[a-z0-9][a-z0-9.+-]*$/i, "a stack entry is a plain identifier such as node or mysql")).optional(),
|
|
21416
|
+
instructions: external_exports.array(repoRelativePath("an instruction path")).optional()
|
|
21417
|
+
});
|
|
21418
|
+
}
|
|
21419
|
+
});
|
|
21420
|
+
|
|
21314
21421
|
// ../core/src/project-order.ts
|
|
21315
21422
|
function parseDependsOn(label3) {
|
|
21316
21423
|
if (!label3 || label3.trim() === "") return [];
|
|
@@ -21757,6 +21864,14 @@ var init_runner = __esm({
|
|
|
21757
21864
|
}
|
|
21758
21865
|
});
|
|
21759
21866
|
|
|
21867
|
+
// ../core/src/module-endpoints.ts
|
|
21868
|
+
var init_module_endpoints = __esm({
|
|
21869
|
+
"../core/src/module-endpoints.ts"() {
|
|
21870
|
+
"use strict";
|
|
21871
|
+
init_dynamic();
|
|
21872
|
+
}
|
|
21873
|
+
});
|
|
21874
|
+
|
|
21760
21875
|
// ../core/src/shares.ts
|
|
21761
21876
|
function shareRouterName(id) {
|
|
21762
21877
|
return `portta-share-${id}`;
|
|
@@ -22318,6 +22433,7 @@ var init_src = __esm({
|
|
|
22318
22433
|
init_namespace();
|
|
22319
22434
|
init_paths();
|
|
22320
22435
|
init_password();
|
|
22436
|
+
init_project_config();
|
|
22321
22437
|
init_project_order();
|
|
22322
22438
|
init_projects_home();
|
|
22323
22439
|
init_protections();
|
|
@@ -22326,6 +22442,7 @@ var init_src = __esm({
|
|
|
22326
22442
|
init_audit_actions();
|
|
22327
22443
|
init_roles();
|
|
22328
22444
|
init_runner();
|
|
22445
|
+
init_module_endpoints();
|
|
22329
22446
|
init_shares();
|
|
22330
22447
|
init_tunnel();
|
|
22331
22448
|
init_activity();
|
|
@@ -22384,7 +22501,7 @@ var init_package = __esm({
|
|
|
22384
22501
|
"package.json"() {
|
|
22385
22502
|
package_default = {
|
|
22386
22503
|
name: "@codions/portta",
|
|
22387
|
-
version: "0.0.0-develop.
|
|
22504
|
+
version: "0.0.0-develop.171.sha-d749180",
|
|
22388
22505
|
description: "Machine-first CLI for a shared Docker development gateway",
|
|
22389
22506
|
license: "MIT",
|
|
22390
22507
|
type: "module",
|
|
@@ -22458,7 +22575,7 @@ var init_version = __esm({
|
|
|
22458
22575
|
"use strict";
|
|
22459
22576
|
init_package();
|
|
22460
22577
|
CLI_VERSION = package_default.version;
|
|
22461
|
-
CLI_BUILD_DATE = true ? "2026-09-18T00:
|
|
22578
|
+
CLI_BUILD_DATE = true ? "2026-09-18T00:56:55Z" : void 0;
|
|
22462
22579
|
}
|
|
22463
22580
|
});
|
|
22464
22581
|
|
|
@@ -36934,7 +37051,7 @@ function agentTemplatePlaceholder(variable) {
|
|
|
36934
37051
|
function hostPortFromEnv(env) {
|
|
36935
37052
|
return parseInt(env[ENV_NAMES.hostPort] || env.PORT || String(APP_DEFAULTS.port), 10);
|
|
36936
37053
|
}
|
|
36937
|
-
var APP_NAME, APP_SLUG, CLI_NAME, GLOBAL_CONFIG_DIR, HOST_STATE_DIR, PROJECT_CONFIG_DIR, PATH_NAMES,
|
|
37054
|
+
var APP_NAME, APP_SLUG, CLI_NAME, GLOBAL_CONFIG_DIR, HOST_STATE_DIR, PROJECT_CONFIG_DIR, PATH_NAMES, PROJECT_CONFIG_PATH2, PROJECT_LOCAL_CONFIG_PATH, APP_DEFAULTS, ENV_NAMES, RUNTIME_IDENTITY, SERVICE_IDENTITY, LINEAR_IDENTITY;
|
|
36938
37055
|
var init_config2 = __esm({
|
|
36939
37056
|
"../core/src/taskflow/config.ts"() {
|
|
36940
37057
|
"use strict";
|
|
@@ -36963,7 +37080,7 @@ var init_config2 = __esm({
|
|
|
36963
37080
|
archiveState: "archive.json",
|
|
36964
37081
|
openSessionsState: "open-sessions.json"
|
|
36965
37082
|
};
|
|
36966
|
-
|
|
37083
|
+
PROJECT_CONFIG_PATH2 = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
|
|
36967
37084
|
PROJECT_LOCAL_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectLocalConfig}`;
|
|
36968
37085
|
APP_DEFAULTS = {
|
|
36969
37086
|
port: 5111,
|
|
@@ -47725,7 +47842,7 @@ var require_Schema = __commonJS({
|
|
|
47725
47842
|
var string4 = require_string();
|
|
47726
47843
|
var tags = require_tags();
|
|
47727
47844
|
var sortMapEntriesByKey = (a3, b) => a3.key < b.key ? -1 : a3.key > b.key ? 1 : 0;
|
|
47728
|
-
var
|
|
47845
|
+
var Schema2 = class _Schema {
|
|
47729
47846
|
constructor({ compat, customTags, merge: merge2, resolveKnownTags, schema, sortMapEntries, toStringDefaults }) {
|
|
47730
47847
|
this.compat = Array.isArray(compat) ? tags.getTags(compat, "compat") : compat ? tags.getTags(null, compat) : null;
|
|
47731
47848
|
this.name = typeof schema === "string" && schema || "core";
|
|
@@ -47743,7 +47860,7 @@ var require_Schema = __commonJS({
|
|
|
47743
47860
|
return copy;
|
|
47744
47861
|
}
|
|
47745
47862
|
};
|
|
47746
|
-
exports.Schema =
|
|
47863
|
+
exports.Schema = Schema2;
|
|
47747
47864
|
}
|
|
47748
47865
|
});
|
|
47749
47866
|
|
|
@@ -47836,7 +47953,7 @@ var require_Document = __commonJS({
|
|
|
47836
47953
|
var identity3 = require_identity();
|
|
47837
47954
|
var Pair = require_Pair();
|
|
47838
47955
|
var toJS = require_toJS();
|
|
47839
|
-
var
|
|
47956
|
+
var Schema2 = require_Schema();
|
|
47840
47957
|
var stringifyDocument = require_stringifyDocument();
|
|
47841
47958
|
var anchors = require_anchors();
|
|
47842
47959
|
var applyReviver = require_applyReviver();
|
|
@@ -48087,7 +48204,7 @@ var require_Document = __commonJS({
|
|
|
48087
48204
|
if (options.schema instanceof Object)
|
|
48088
48205
|
this.schema = options.schema;
|
|
48089
48206
|
else if (opt)
|
|
48090
|
-
this.schema = new
|
|
48207
|
+
this.schema = new Schema2.Schema(Object.assign(opt, options));
|
|
48091
48208
|
else
|
|
48092
48209
|
throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
|
|
48093
48210
|
}
|
|
@@ -51751,7 +51868,7 @@ var require_dist = __commonJS({
|
|
|
51751
51868
|
"use strict";
|
|
51752
51869
|
var composer = require_composer();
|
|
51753
51870
|
var Document = require_Document();
|
|
51754
|
-
var
|
|
51871
|
+
var Schema2 = require_Schema();
|
|
51755
51872
|
var errors = require_errors();
|
|
51756
51873
|
var Alias = require_Alias();
|
|
51757
51874
|
var identity3 = require_identity();
|
|
@@ -51767,7 +51884,7 @@ var require_dist = __commonJS({
|
|
|
51767
51884
|
var visit2 = require_visit();
|
|
51768
51885
|
exports.Composer = composer.Composer;
|
|
51769
51886
|
exports.Document = Document.Document;
|
|
51770
|
-
exports.Schema =
|
|
51887
|
+
exports.Schema = Schema2.Schema;
|
|
51771
51888
|
exports.YAMLError = errors.YAMLError;
|
|
51772
51889
|
exports.YAMLParseError = errors.YAMLParseError;
|
|
51773
51890
|
exports.YAMLWarning = errors.YAMLWarning;
|
|
@@ -52052,7 +52169,7 @@ function parseConfigDocument(text) {
|
|
|
52052
52169
|
const parsed = (0, import_yaml.parse)(text);
|
|
52053
52170
|
return isRecord2(parsed) ? parsed : {};
|
|
52054
52171
|
}
|
|
52055
|
-
function
|
|
52172
|
+
function parseProjectConfig2(parsed) {
|
|
52056
52173
|
const worktreeRoot = parseWorktreeRoot(parsed.workspace, DEFAULT_CONFIG.workspace.worktreeRoot);
|
|
52057
52174
|
return {
|
|
52058
52175
|
name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : DEFAULT_CONFIG.name,
|
|
@@ -52082,7 +52199,7 @@ function parseProjectConfig(parsed) {
|
|
|
52082
52199
|
};
|
|
52083
52200
|
}
|
|
52084
52201
|
function defaultConfig() {
|
|
52085
|
-
return
|
|
52202
|
+
return parseProjectConfig2({});
|
|
52086
52203
|
}
|
|
52087
52204
|
function parseTeamKeyList(raw2) {
|
|
52088
52205
|
if (!Array.isArray(raw2)) return void 0;
|
|
@@ -52217,7 +52334,7 @@ function loadConfig(dir, options = {}) {
|
|
|
52217
52334
|
let projectConfig;
|
|
52218
52335
|
try {
|
|
52219
52336
|
const text = readConfigFile(root2).trim();
|
|
52220
|
-
projectConfig = text ?
|
|
52337
|
+
projectConfig = text ? parseProjectConfig2(parseConfigDocument(text)) : defaultConfig();
|
|
52221
52338
|
} catch {
|
|
52222
52339
|
projectConfig = defaultConfig();
|
|
52223
52340
|
}
|
|
@@ -90034,7 +90151,7 @@ function createDaemonTaskflowHost(context) {
|
|
|
90034
90151
|
port: hostListen(env).port,
|
|
90035
90152
|
workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
|
|
90036
90153
|
version: env.PORTTA_VERSION || "0.0.0-local",
|
|
90037
|
-
buildDate: true ? "2026-09-18T00:
|
|
90154
|
+
buildDate: true ? "2026-09-18T00:56:55Z" : (/* @__PURE__ */ new Date()).toISOString(),
|
|
90038
90155
|
environmentStore: createEnvironmentStore(paths3.database),
|
|
90039
90156
|
hostEnvironmentProvider: new HostEnvironmentProvider(),
|
|
90040
90157
|
devContainerProvider: new DevContainerProvider(),
|
|
@@ -110160,8 +110277,8 @@ function detectInitEnvironment(gitRoot2, requested = "auto") {
|
|
|
110160
110277
|
function buildInitPromptSpec(context) {
|
|
110161
110278
|
const systemPrompt = [
|
|
110162
110279
|
`You are bootstrapping a local repository for ${APP_NAME}.`,
|
|
110163
|
-
`A starter \`${
|
|
110164
|
-
`Inspect the repository in the current working directory and edit that existing \`${
|
|
110280
|
+
`A starter \`${PROJECT_CONFIG_PATH2}\` already exists at the repo root.`,
|
|
110281
|
+
`Inspect the repository in the current working directory and edit that existing \`${PROJECT_CONFIG_PATH2}\` in place.`,
|
|
110165
110282
|
"Do not modify any other file.",
|
|
110166
110283
|
"Do not ask the user questions. Infer the config from the repository contents.",
|
|
110167
110284
|
"Be efficient: inspect only the files needed to determine the project name, main branch, service layout, dev commands, and ports.",
|
|
@@ -110186,11 +110303,11 @@ function buildInitPromptSpec(context) {
|
|
|
110186
110303
|
"Only include optional sections like auto_name, lifecycleHooks, sandbox/docker config, mounts, or systemPrompt if the repository gives clear evidence they are needed.",
|
|
110187
110304
|
"Prefer editing the existing keys over replacing the file with a completely different shape.",
|
|
110188
110305
|
"Preserve the existing template structure and comments unless a specific change requires updating them.",
|
|
110189
|
-
`Before finishing, verify that \`${
|
|
110306
|
+
`Before finishing, verify that \`${PROJECT_CONFIG_PATH2}\` exists and contains the final YAML.`
|
|
110190
110307
|
].join("\n");
|
|
110191
110308
|
return {
|
|
110192
110309
|
systemPrompt,
|
|
110193
|
-
userPrompt: `Adapt the existing starter \`${
|
|
110310
|
+
userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH2}\` for this repository.`
|
|
110194
110311
|
};
|
|
110195
110312
|
}
|
|
110196
110313
|
function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`) {
|
|
@@ -110742,13 +110859,13 @@ var init_init_deps = __esm({
|
|
|
110742
110859
|
tool: "claude",
|
|
110743
110860
|
args: ["--version"],
|
|
110744
110861
|
required: false,
|
|
110745
|
-
hint: `Install the Claude Code CLI to let Claude scaffold ${
|
|
110862
|
+
hint: `Install the Claude Code CLI to let Claude scaffold ${PROJECT_CONFIG_PATH2}`
|
|
110746
110863
|
},
|
|
110747
110864
|
{
|
|
110748
110865
|
tool: "codex",
|
|
110749
110866
|
args: ["--version"],
|
|
110750
110867
|
required: false,
|
|
110751
|
-
hint: `Install the Codex CLI to let Codex scaffold ${
|
|
110868
|
+
hint: `Install the Codex CLI to let Codex scaffold ${PROJECT_CONFIG_PATH2}`
|
|
110752
110869
|
},
|
|
110753
110870
|
{ tool: "docker", args: ["--version"], required: false, hint: "https://docs.docker.com/get-started/get-docker/" }
|
|
110754
110871
|
];
|
|
@@ -110953,7 +111070,7 @@ async function runInit(options) {
|
|
|
110953
111070
|
let selectedAnalyze = resolveInitAnalysis(options, selectedRuntime);
|
|
110954
111071
|
const configExists = existsSync29(taskflowYaml);
|
|
110955
111072
|
if (configExists) {
|
|
110956
|
-
log2.info(`${
|
|
111073
|
+
log2.info(`${PROJECT_CONFIG_PATH2} already exists`);
|
|
110957
111074
|
} else if (needsInteractiveAnalysisFallback(options, selectedRuntime)) {
|
|
110958
111075
|
selectedAnalyze = await selectFallbackAgent();
|
|
110959
111076
|
}
|
|
@@ -110974,7 +111091,7 @@ async function runInit(options) {
|
|
|
110974
111091
|
environmentProvider: detection.selectedRuntime
|
|
110975
111092
|
})
|
|
110976
111093
|
);
|
|
110977
|
-
log2.success(`${
|
|
111094
|
+
log2.success(`${PROJECT_CONFIG_PATH2} created from deterministic detection`);
|
|
110978
111095
|
} else {
|
|
110979
111096
|
const available2 = isInitAgentSelectable(
|
|
110980
111097
|
depStatuses.find((status) => status.tool === selectedAnalyze) ?? { found: false }
|
|
@@ -110997,11 +111114,11 @@ async function runInit(options) {
|
|
|
110997
111114
|
const prompt = buildInitPromptSpec({ ...context, defaultAgent: selectedAnalyze });
|
|
110998
111115
|
const command = buildInitAgentCommand(selectedAnalyze, prompt);
|
|
110999
111116
|
const streamPrinter = createAgentStreamPrinter(label3);
|
|
111000
|
-
log2.step(`Running ${label3} to adapt ${
|
|
111117
|
+
log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH2}...`);
|
|
111001
111118
|
const result = await runInitAgentCommand(command, gitRoot2, { onEvent: streamPrinter.onEvent });
|
|
111002
111119
|
streamPrinter.finish();
|
|
111003
111120
|
if (!existsSync29(taskflowYaml)) {
|
|
111004
|
-
log2.error(`${label3} removed ${
|
|
111121
|
+
log2.error(`${label3} removed ${PROJECT_CONFIG_PATH2}`);
|
|
111005
111122
|
const details = [
|
|
111006
111123
|
result.summary ? `Summary:
|
|
111007
111124
|
${result.summary}` : "",
|
|
@@ -111018,12 +111135,12 @@ ${result.stderr.trim()}` : ""
|
|
|
111018
111135
|
const finalYaml = await readFile12(taskflowYaml, "utf8");
|
|
111019
111136
|
const changedTemplate = configExists || finalYaml !== starterTemplate;
|
|
111020
111137
|
if (result.exitCode === 0 && changedTemplate) {
|
|
111021
|
-
log2.success(`${label3} adapted ${
|
|
111138
|
+
log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH2}`);
|
|
111022
111139
|
} else if (result.exitCode === 0) {
|
|
111023
111140
|
log2.warning(`${label3} left the starter template unchanged`);
|
|
111024
|
-
log2.warning(`${label3} did not change the starter template. Review ${
|
|
111141
|
+
log2.warning(`${label3} did not change the starter template. Review ${PROJECT_CONFIG_PATH2} manually.`);
|
|
111025
111142
|
} else if (changedTemplate) {
|
|
111026
|
-
log2.warning(`${label3} updated ${
|
|
111143
|
+
log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH2}`);
|
|
111027
111144
|
log2.warning(`${label3} exited with code ${result.exitCode}. Review the generated file before using it.`);
|
|
111028
111145
|
} else {
|
|
111029
111146
|
log2.warning(`${label3} left the starter template in place`);
|
|
@@ -111046,7 +111163,7 @@ ${result.stderr.trim()}` : ""
|
|
|
111046
111163
|
);
|
|
111047
111164
|
outro("You're all set! Next steps:");
|
|
111048
111165
|
console.log();
|
|
111049
|
-
console.log(` 1. Review ${
|
|
111166
|
+
console.log(` 1. Review ${PROJECT_CONFIG_PATH2} and adjust runtime and exposure overrides if needed`);
|
|
111050
111167
|
console.log(" 2. Keep the host daemon running: portta host serve --detach (or portta host service install)");
|
|
111051
111168
|
console.log(` 3. Enable tab completion: eval "$(${flowInvocation()} completion zsh)" (or bash)`);
|
|
111052
111169
|
console.log();
|
|
@@ -111904,7 +112021,7 @@ import { setTimeout as delay4 } from "node:timers/promises";
|
|
|
111904
112021
|
function projectSetupPhaseLabel(phase) {
|
|
111905
112022
|
switch (phase) {
|
|
111906
112023
|
case "creating_config":
|
|
111907
|
-
return `Creating ${
|
|
112024
|
+
return `Creating ${PROJECT_CONFIG_PATH2}`;
|
|
111908
112025
|
case "analyzing":
|
|
111909
112026
|
return "Analyzing project structure";
|
|
111910
112027
|
case "ready":
|
|
@@ -119644,6 +119761,7 @@ async function dbRestore(file2, command) {
|
|
|
119644
119761
|
|
|
119645
119762
|
// src/commands/projects.ts
|
|
119646
119763
|
init_src();
|
|
119764
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
119647
119765
|
init_zod();
|
|
119648
119766
|
import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync22, realpathSync as realpathSync4, renameSync as renameSync5, rmSync as rmSync6, writeFileSync as writeFileSync12 } from "node:fs";
|
|
119649
119767
|
import { createHash as createHash15 } from "node:crypto";
|
|
@@ -119784,6 +119902,21 @@ function declaredComposeName(file2) {
|
|
|
119784
119902
|
return null;
|
|
119785
119903
|
}
|
|
119786
119904
|
}
|
|
119905
|
+
function readProjectConfig(root2) {
|
|
119906
|
+
const path7 = join46(root2, PROJECT_CONFIG_PATH);
|
|
119907
|
+
if (!existsSync23(path7)) {
|
|
119908
|
+
return { source: "defaults", path: PROJECT_CONFIG_PATH, config: defaultProjectConfig(), issues: [] };
|
|
119909
|
+
}
|
|
119910
|
+
let document;
|
|
119911
|
+
try {
|
|
119912
|
+
document = (0, import_yaml2.parse)(readFileSync22(path7, "utf8"));
|
|
119913
|
+
} catch (error61) {
|
|
119914
|
+
const message = error61 instanceof Error ? error61.message : String(error61);
|
|
119915
|
+
return { source: "file", path: PROJECT_CONFIG_PATH, config: null, issues: [{ path: "", message }] };
|
|
119916
|
+
}
|
|
119917
|
+
const parsed = parseProjectConfig(document);
|
|
119918
|
+
return parsed.ok ? { source: "file", path: PROJECT_CONFIG_PATH, config: parsed.config, issues: [] } : { source: "file", path: PROJECT_CONFIG_PATH, config: null, issues: parsed.issues };
|
|
119919
|
+
}
|
|
119787
119920
|
async function analyze(pathValue, options = {}, containers) {
|
|
119788
119921
|
const base2 = resolve24(pathValue);
|
|
119789
119922
|
let composeFile2;
|
|
@@ -119834,6 +119967,7 @@ async function analyze(pathValue, options = {}, containers) {
|
|
|
119834
119967
|
path: path7,
|
|
119835
119968
|
compose_file: basename14(composeFile2),
|
|
119836
119969
|
gateway_overlay: overlay2,
|
|
119970
|
+
project_config: readProjectConfig(path7),
|
|
119837
119971
|
project: { name: project2, source: projectFromEnv ? ".env" : declaredName ? "compose name:" : "directory name (implicit)" },
|
|
119838
119972
|
domain: gatewayContext({ required: false }).config.domain,
|
|
119839
119973
|
services,
|
|
@@ -119865,6 +119999,19 @@ async function analyzeCommand(path7, options, command) {
|
|
|
119865
119999
|
output2.line(` project namespace ${report.project.name} (${report.project.source})`);
|
|
119866
120000
|
const identities = [...new Set(report.services.flatMap((service2) => Object.entries(service2.labels).filter(([key]) => key.startsWith("portta.project") || key.startsWith("portta.repo") || key.startsWith("portta.git.root")).map(([key, value3]) => `${key}=${value3}`)))];
|
|
119867
120001
|
output2.line(` declared identity ${identities.length ? identities.join(" ") : "none (inferred from the Compose labels)"}`);
|
|
120002
|
+
const declared = report.project_config;
|
|
120003
|
+
if (declared.issues.length) {
|
|
120004
|
+
output2.line(` project.yaml invalid, so its defaults are not applied:`);
|
|
120005
|
+
for (const issue2 of declared.issues) output2.line(` ${issue2.path ? `${issue2.path}: ` : ""}${issue2.message}`);
|
|
120006
|
+
} else if (declared.config) {
|
|
120007
|
+
const summary = [
|
|
120008
|
+
declared.config.name ? `name ${declared.config.name}` : null,
|
|
120009
|
+
declared.config.mainBranch ? `main branch ${declared.config.mainBranch}` : null,
|
|
120010
|
+
`worktrees ${declared.config.worktrees.root}`,
|
|
120011
|
+
`branches ${declared.config.worktrees.branchPattern}`
|
|
120012
|
+
].filter((part) => part !== null);
|
|
120013
|
+
output2.line(` project.yaml ${declared.source === "file" ? summary.join(", ") : `absent, so defaults apply: ${summary.join(", ")}`}`);
|
|
120014
|
+
}
|
|
119868
120015
|
output2.line("\nServices");
|
|
119869
120016
|
for (const service2 of report.services) output2.line(` ${service2.name} ${service2.image ?? "<built>"} ${service2.kind} ${service2.published_ports.map((port) => `${port.host}:${port.container}`).join(",") || "-"}`);
|
|
119870
120017
|
output2.line("\nFindings");
|
|
@@ -120407,7 +120554,7 @@ function helpAfter(command, text) {
|
|
|
120407
120554
|
${text(commandInvocation(context.command))}`);
|
|
120408
120555
|
}
|
|
120409
120556
|
function runOptions(command) {
|
|
120410
|
-
return command.addOption(new Option("--input <text>", "Run input text").conflicts("inputJson")).option("--input-json <json>", "Run input as a JSON object").option("--profile <name>", `Profile from ${
|
|
120557
|
+
return command.addOption(new Option("--input <text>", "Run input text").conflicts("inputJson")).option("--input-json <json>", "Run input as a JSON object").option("--profile <name>", `Profile from ${PROJECT_CONFIG_PATH2}`).addOption(
|
|
120411
120558
|
new Option("--workspace <strategy>", "Execution workspace (default: workflow policy or worktree)").choices([
|
|
120412
120559
|
"worktree",
|
|
120413
120560
|
"branch",
|
|
@@ -120477,12 +120624,12 @@ ${environment.map(([name = "", text]) => ` ${name.padEnd(width)} ${text}`).joi
|
|
|
120477
120624
|
Analysis: --analyze=auto uses the default agent only when runtime detection falls back to host.
|
|
120478
120625
|
--analyze=claude | --analyze=codex always run that agent.`
|
|
120479
120626
|
);
|
|
120480
|
-
leaf(flow, "add [branch]", "Create a worktree using the dashboard lifecycle").option("--existing", "Use an existing local or remote branch instead of creating a new one").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${
|
|
120627
|
+
leaf(flow, "add [branch]", "Create a worktree using the dashboard lifecycle").option("--existing", "Use an existing local or remote branch instead of creating a new one").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH2}`).option("--agent <id>", "Agent id to launch (repeatable)", collect).option("--prompt <text>", "Initial agent prompt").option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--interface <mode>", "Session UI: terminal or web-chat").option("-d, --detach", "Create worktree without switching to it").option(
|
|
120481
120628
|
"--from-linear <issue-id>",
|
|
120482
120629
|
`Bootstrap from a Linear issue, plus any saved ${APP_NAME} session or linked PR`
|
|
120483
120630
|
).option("--branch <name>", "Override the branch when --from-linear resolves to one");
|
|
120484
120631
|
helpAfter(
|
|
120485
|
-
leaf(flow, "oneshot [branch]", "Run a worktree start-to-finish, streaming logs to stdout").option("--resume <branch>", "Resume an existing local worktree instead of creating one").option("--prompt <text>", "Initial agent prompt (required; follow-up nudge when --resume)").option("--agent <id>", "Agent id to launch").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${
|
|
120632
|
+
leaf(flow, "oneshot [branch]", "Run a worktree start-to-finish, streaming logs to stdout").option("--resume <branch>", "Resume an existing local worktree instead of creating one").option("--prompt <text>", "Initial agent prompt (required; follow-up nudge when --resume)").option("--agent <id>", "Agent id to launch").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${PROJECT_CONFIG_PATH2}`).option("--env <KEY=VALUE>", "Runtime env override (repeatable)", collect).option("--keep-open", "Don't auto-close the worktree session when the agent finishes").option(
|
|
120486
120633
|
"--linear <id|team>",
|
|
120487
120634
|
"Tie this oneshot to Linear: ENG-123 loads the issue and posts back; ENG creates an issue when done"
|
|
120488
120635
|
).option("--branch <name>", "Override the branch when --linear resolves to one"),
|
|
@@ -120515,7 +120662,7 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
|
|
|
120515
120662
|
"--profile <name>",
|
|
120516
120663
|
"Profile name (alternative to positional arg)"
|
|
120517
120664
|
),
|
|
120518
|
-
() => `Switches the worktree to another profile from ${
|
|
120665
|
+
() => `Switches the worktree to another profile from ${PROJECT_CONFIG_PATH2}. An open
|
|
120519
120666
|
worktree is restarted with the new pane layout and commands; a closed
|
|
120520
120667
|
one picks the new profile up on its next open.`
|
|
120521
120668
|
);
|