@codions/portta 0.0.0-develop.169.sha-64ee68c → 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 +171 -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 [];
|
|
@@ -22326,6 +22433,7 @@ var init_src = __esm({
|
|
|
22326
22433
|
init_namespace();
|
|
22327
22434
|
init_paths();
|
|
22328
22435
|
init_password();
|
|
22436
|
+
init_project_config();
|
|
22329
22437
|
init_project_order();
|
|
22330
22438
|
init_projects_home();
|
|
22331
22439
|
init_protections();
|
|
@@ -22393,7 +22501,7 @@ var init_package = __esm({
|
|
|
22393
22501
|
"package.json"() {
|
|
22394
22502
|
package_default = {
|
|
22395
22503
|
name: "@codions/portta",
|
|
22396
|
-
version: "0.0.0-develop.
|
|
22504
|
+
version: "0.0.0-develop.171.sha-d749180",
|
|
22397
22505
|
description: "Machine-first CLI for a shared Docker development gateway",
|
|
22398
22506
|
license: "MIT",
|
|
22399
22507
|
type: "module",
|
|
@@ -22467,7 +22575,7 @@ var init_version = __esm({
|
|
|
22467
22575
|
"use strict";
|
|
22468
22576
|
init_package();
|
|
22469
22577
|
CLI_VERSION = package_default.version;
|
|
22470
|
-
CLI_BUILD_DATE = true ? "2026-09-18T00:
|
|
22578
|
+
CLI_BUILD_DATE = true ? "2026-09-18T00:56:55Z" : void 0;
|
|
22471
22579
|
}
|
|
22472
22580
|
});
|
|
22473
22581
|
|
|
@@ -36943,7 +37051,7 @@ function agentTemplatePlaceholder(variable) {
|
|
|
36943
37051
|
function hostPortFromEnv(env) {
|
|
36944
37052
|
return parseInt(env[ENV_NAMES.hostPort] || env.PORT || String(APP_DEFAULTS.port), 10);
|
|
36945
37053
|
}
|
|
36946
|
-
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;
|
|
36947
37055
|
var init_config2 = __esm({
|
|
36948
37056
|
"../core/src/taskflow/config.ts"() {
|
|
36949
37057
|
"use strict";
|
|
@@ -36972,7 +37080,7 @@ var init_config2 = __esm({
|
|
|
36972
37080
|
archiveState: "archive.json",
|
|
36973
37081
|
openSessionsState: "open-sessions.json"
|
|
36974
37082
|
};
|
|
36975
|
-
|
|
37083
|
+
PROJECT_CONFIG_PATH2 = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectConfig}`;
|
|
36976
37084
|
PROJECT_LOCAL_CONFIG_PATH = `${PROJECT_CONFIG_DIR}/${PATH_NAMES.projectLocalConfig}`;
|
|
36977
37085
|
APP_DEFAULTS = {
|
|
36978
37086
|
port: 5111,
|
|
@@ -47734,7 +47842,7 @@ var require_Schema = __commonJS({
|
|
|
47734
47842
|
var string4 = require_string();
|
|
47735
47843
|
var tags = require_tags();
|
|
47736
47844
|
var sortMapEntriesByKey = (a3, b) => a3.key < b.key ? -1 : a3.key > b.key ? 1 : 0;
|
|
47737
|
-
var
|
|
47845
|
+
var Schema2 = class _Schema {
|
|
47738
47846
|
constructor({ compat, customTags, merge: merge2, resolveKnownTags, schema, sortMapEntries, toStringDefaults }) {
|
|
47739
47847
|
this.compat = Array.isArray(compat) ? tags.getTags(compat, "compat") : compat ? tags.getTags(null, compat) : null;
|
|
47740
47848
|
this.name = typeof schema === "string" && schema || "core";
|
|
@@ -47752,7 +47860,7 @@ var require_Schema = __commonJS({
|
|
|
47752
47860
|
return copy;
|
|
47753
47861
|
}
|
|
47754
47862
|
};
|
|
47755
|
-
exports.Schema =
|
|
47863
|
+
exports.Schema = Schema2;
|
|
47756
47864
|
}
|
|
47757
47865
|
});
|
|
47758
47866
|
|
|
@@ -47845,7 +47953,7 @@ var require_Document = __commonJS({
|
|
|
47845
47953
|
var identity3 = require_identity();
|
|
47846
47954
|
var Pair = require_Pair();
|
|
47847
47955
|
var toJS = require_toJS();
|
|
47848
|
-
var
|
|
47956
|
+
var Schema2 = require_Schema();
|
|
47849
47957
|
var stringifyDocument = require_stringifyDocument();
|
|
47850
47958
|
var anchors = require_anchors();
|
|
47851
47959
|
var applyReviver = require_applyReviver();
|
|
@@ -48096,7 +48204,7 @@ var require_Document = __commonJS({
|
|
|
48096
48204
|
if (options.schema instanceof Object)
|
|
48097
48205
|
this.schema = options.schema;
|
|
48098
48206
|
else if (opt)
|
|
48099
|
-
this.schema = new
|
|
48207
|
+
this.schema = new Schema2.Schema(Object.assign(opt, options));
|
|
48100
48208
|
else
|
|
48101
48209
|
throw new Error(`With a null YAML version, the { schema: Schema } option is required`);
|
|
48102
48210
|
}
|
|
@@ -51760,7 +51868,7 @@ var require_dist = __commonJS({
|
|
|
51760
51868
|
"use strict";
|
|
51761
51869
|
var composer = require_composer();
|
|
51762
51870
|
var Document = require_Document();
|
|
51763
|
-
var
|
|
51871
|
+
var Schema2 = require_Schema();
|
|
51764
51872
|
var errors = require_errors();
|
|
51765
51873
|
var Alias = require_Alias();
|
|
51766
51874
|
var identity3 = require_identity();
|
|
@@ -51776,7 +51884,7 @@ var require_dist = __commonJS({
|
|
|
51776
51884
|
var visit2 = require_visit();
|
|
51777
51885
|
exports.Composer = composer.Composer;
|
|
51778
51886
|
exports.Document = Document.Document;
|
|
51779
|
-
exports.Schema =
|
|
51887
|
+
exports.Schema = Schema2.Schema;
|
|
51780
51888
|
exports.YAMLError = errors.YAMLError;
|
|
51781
51889
|
exports.YAMLParseError = errors.YAMLParseError;
|
|
51782
51890
|
exports.YAMLWarning = errors.YAMLWarning;
|
|
@@ -52061,7 +52169,7 @@ function parseConfigDocument(text) {
|
|
|
52061
52169
|
const parsed = (0, import_yaml.parse)(text);
|
|
52062
52170
|
return isRecord2(parsed) ? parsed : {};
|
|
52063
52171
|
}
|
|
52064
|
-
function
|
|
52172
|
+
function parseProjectConfig2(parsed) {
|
|
52065
52173
|
const worktreeRoot = parseWorktreeRoot(parsed.workspace, DEFAULT_CONFIG.workspace.worktreeRoot);
|
|
52066
52174
|
return {
|
|
52067
52175
|
name: typeof parsed.name === "string" && parsed.name.trim() ? parsed.name.trim() : DEFAULT_CONFIG.name,
|
|
@@ -52091,7 +52199,7 @@ function parseProjectConfig(parsed) {
|
|
|
52091
52199
|
};
|
|
52092
52200
|
}
|
|
52093
52201
|
function defaultConfig() {
|
|
52094
|
-
return
|
|
52202
|
+
return parseProjectConfig2({});
|
|
52095
52203
|
}
|
|
52096
52204
|
function parseTeamKeyList(raw2) {
|
|
52097
52205
|
if (!Array.isArray(raw2)) return void 0;
|
|
@@ -52226,7 +52334,7 @@ function loadConfig(dir, options = {}) {
|
|
|
52226
52334
|
let projectConfig;
|
|
52227
52335
|
try {
|
|
52228
52336
|
const text = readConfigFile(root2).trim();
|
|
52229
|
-
projectConfig = text ?
|
|
52337
|
+
projectConfig = text ? parseProjectConfig2(parseConfigDocument(text)) : defaultConfig();
|
|
52230
52338
|
} catch {
|
|
52231
52339
|
projectConfig = defaultConfig();
|
|
52232
52340
|
}
|
|
@@ -90043,7 +90151,7 @@ function createDaemonTaskflowHost(context) {
|
|
|
90043
90151
|
port: hostListen(env).port,
|
|
90044
90152
|
workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
|
|
90045
90153
|
version: env.PORTTA_VERSION || "0.0.0-local",
|
|
90046
|
-
buildDate: true ? "2026-09-18T00:
|
|
90154
|
+
buildDate: true ? "2026-09-18T00:56:55Z" : (/* @__PURE__ */ new Date()).toISOString(),
|
|
90047
90155
|
environmentStore: createEnvironmentStore(paths3.database),
|
|
90048
90156
|
hostEnvironmentProvider: new HostEnvironmentProvider(),
|
|
90049
90157
|
devContainerProvider: new DevContainerProvider(),
|
|
@@ -110169,8 +110277,8 @@ function detectInitEnvironment(gitRoot2, requested = "auto") {
|
|
|
110169
110277
|
function buildInitPromptSpec(context) {
|
|
110170
110278
|
const systemPrompt = [
|
|
110171
110279
|
`You are bootstrapping a local repository for ${APP_NAME}.`,
|
|
110172
|
-
`A starter \`${
|
|
110173
|
-
`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.`,
|
|
110174
110282
|
"Do not modify any other file.",
|
|
110175
110283
|
"Do not ask the user questions. Infer the config from the repository contents.",
|
|
110176
110284
|
"Be efficient: inspect only the files needed to determine the project name, main branch, service layout, dev commands, and ports.",
|
|
@@ -110195,11 +110303,11 @@ function buildInitPromptSpec(context) {
|
|
|
110195
110303
|
"Only include optional sections like auto_name, lifecycleHooks, sandbox/docker config, mounts, or systemPrompt if the repository gives clear evidence they are needed.",
|
|
110196
110304
|
"Prefer editing the existing keys over replacing the file with a completely different shape.",
|
|
110197
110305
|
"Preserve the existing template structure and comments unless a specific change requires updating them.",
|
|
110198
|
-
`Before finishing, verify that \`${
|
|
110306
|
+
`Before finishing, verify that \`${PROJECT_CONFIG_PATH2}\` exists and contains the final YAML.`
|
|
110199
110307
|
].join("\n");
|
|
110200
110308
|
return {
|
|
110201
110309
|
systemPrompt,
|
|
110202
|
-
userPrompt: `Adapt the existing starter \`${
|
|
110310
|
+
userPrompt: `Adapt the existing starter \`${PROJECT_CONFIG_PATH2}\` for this repository.`
|
|
110203
110311
|
};
|
|
110204
110312
|
}
|
|
110205
110313
|
function buildInitAgentCommand(agent, prompt, outputPrefix = `${APP_SLUG}-init`) {
|
|
@@ -110751,13 +110859,13 @@ var init_init_deps = __esm({
|
|
|
110751
110859
|
tool: "claude",
|
|
110752
110860
|
args: ["--version"],
|
|
110753
110861
|
required: false,
|
|
110754
|
-
hint: `Install the Claude Code CLI to let Claude scaffold ${
|
|
110862
|
+
hint: `Install the Claude Code CLI to let Claude scaffold ${PROJECT_CONFIG_PATH2}`
|
|
110755
110863
|
},
|
|
110756
110864
|
{
|
|
110757
110865
|
tool: "codex",
|
|
110758
110866
|
args: ["--version"],
|
|
110759
110867
|
required: false,
|
|
110760
|
-
hint: `Install the Codex CLI to let Codex scaffold ${
|
|
110868
|
+
hint: `Install the Codex CLI to let Codex scaffold ${PROJECT_CONFIG_PATH2}`
|
|
110761
110869
|
},
|
|
110762
110870
|
{ tool: "docker", args: ["--version"], required: false, hint: "https://docs.docker.com/get-started/get-docker/" }
|
|
110763
110871
|
];
|
|
@@ -110962,7 +111070,7 @@ async function runInit(options) {
|
|
|
110962
111070
|
let selectedAnalyze = resolveInitAnalysis(options, selectedRuntime);
|
|
110963
111071
|
const configExists = existsSync29(taskflowYaml);
|
|
110964
111072
|
if (configExists) {
|
|
110965
|
-
log2.info(`${
|
|
111073
|
+
log2.info(`${PROJECT_CONFIG_PATH2} already exists`);
|
|
110966
111074
|
} else if (needsInteractiveAnalysisFallback(options, selectedRuntime)) {
|
|
110967
111075
|
selectedAnalyze = await selectFallbackAgent();
|
|
110968
111076
|
}
|
|
@@ -110983,7 +111091,7 @@ async function runInit(options) {
|
|
|
110983
111091
|
environmentProvider: detection.selectedRuntime
|
|
110984
111092
|
})
|
|
110985
111093
|
);
|
|
110986
|
-
log2.success(`${
|
|
111094
|
+
log2.success(`${PROJECT_CONFIG_PATH2} created from deterministic detection`);
|
|
110987
111095
|
} else {
|
|
110988
111096
|
const available2 = isInitAgentSelectable(
|
|
110989
111097
|
depStatuses.find((status) => status.tool === selectedAnalyze) ?? { found: false }
|
|
@@ -111006,11 +111114,11 @@ async function runInit(options) {
|
|
|
111006
111114
|
const prompt = buildInitPromptSpec({ ...context, defaultAgent: selectedAnalyze });
|
|
111007
111115
|
const command = buildInitAgentCommand(selectedAnalyze, prompt);
|
|
111008
111116
|
const streamPrinter = createAgentStreamPrinter(label3);
|
|
111009
|
-
log2.step(`Running ${label3} to adapt ${
|
|
111117
|
+
log2.step(`Running ${label3} to adapt ${PROJECT_CONFIG_PATH2}...`);
|
|
111010
111118
|
const result = await runInitAgentCommand(command, gitRoot2, { onEvent: streamPrinter.onEvent });
|
|
111011
111119
|
streamPrinter.finish();
|
|
111012
111120
|
if (!existsSync29(taskflowYaml)) {
|
|
111013
|
-
log2.error(`${label3} removed ${
|
|
111121
|
+
log2.error(`${label3} removed ${PROJECT_CONFIG_PATH2}`);
|
|
111014
111122
|
const details = [
|
|
111015
111123
|
result.summary ? `Summary:
|
|
111016
111124
|
${result.summary}` : "",
|
|
@@ -111027,12 +111135,12 @@ ${result.stderr.trim()}` : ""
|
|
|
111027
111135
|
const finalYaml = await readFile12(taskflowYaml, "utf8");
|
|
111028
111136
|
const changedTemplate = configExists || finalYaml !== starterTemplate;
|
|
111029
111137
|
if (result.exitCode === 0 && changedTemplate) {
|
|
111030
|
-
log2.success(`${label3} adapted ${
|
|
111138
|
+
log2.success(`${label3} adapted ${PROJECT_CONFIG_PATH2}`);
|
|
111031
111139
|
} else if (result.exitCode === 0) {
|
|
111032
111140
|
log2.warning(`${label3} left the starter template unchanged`);
|
|
111033
|
-
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.`);
|
|
111034
111142
|
} else if (changedTemplate) {
|
|
111035
|
-
log2.warning(`${label3} updated ${
|
|
111143
|
+
log2.warning(`${label3} updated ${PROJECT_CONFIG_PATH2}`);
|
|
111036
111144
|
log2.warning(`${label3} exited with code ${result.exitCode}. Review the generated file before using it.`);
|
|
111037
111145
|
} else {
|
|
111038
111146
|
log2.warning(`${label3} left the starter template in place`);
|
|
@@ -111055,7 +111163,7 @@ ${result.stderr.trim()}` : ""
|
|
|
111055
111163
|
);
|
|
111056
111164
|
outro("You're all set! Next steps:");
|
|
111057
111165
|
console.log();
|
|
111058
|
-
console.log(` 1. Review ${
|
|
111166
|
+
console.log(` 1. Review ${PROJECT_CONFIG_PATH2} and adjust runtime and exposure overrides if needed`);
|
|
111059
111167
|
console.log(" 2. Keep the host daemon running: portta host serve --detach (or portta host service install)");
|
|
111060
111168
|
console.log(` 3. Enable tab completion: eval "$(${flowInvocation()} completion zsh)" (or bash)`);
|
|
111061
111169
|
console.log();
|
|
@@ -111913,7 +112021,7 @@ import { setTimeout as delay4 } from "node:timers/promises";
|
|
|
111913
112021
|
function projectSetupPhaseLabel(phase) {
|
|
111914
112022
|
switch (phase) {
|
|
111915
112023
|
case "creating_config":
|
|
111916
|
-
return `Creating ${
|
|
112024
|
+
return `Creating ${PROJECT_CONFIG_PATH2}`;
|
|
111917
112025
|
case "analyzing":
|
|
111918
112026
|
return "Analyzing project structure";
|
|
111919
112027
|
case "ready":
|
|
@@ -119653,6 +119761,7 @@ async function dbRestore(file2, command) {
|
|
|
119653
119761
|
|
|
119654
119762
|
// src/commands/projects.ts
|
|
119655
119763
|
init_src();
|
|
119764
|
+
var import_yaml2 = __toESM(require_dist(), 1);
|
|
119656
119765
|
init_zod();
|
|
119657
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";
|
|
119658
119767
|
import { createHash as createHash15 } from "node:crypto";
|
|
@@ -119793,6 +119902,21 @@ function declaredComposeName(file2) {
|
|
|
119793
119902
|
return null;
|
|
119794
119903
|
}
|
|
119795
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
|
+
}
|
|
119796
119920
|
async function analyze(pathValue, options = {}, containers) {
|
|
119797
119921
|
const base2 = resolve24(pathValue);
|
|
119798
119922
|
let composeFile2;
|
|
@@ -119843,6 +119967,7 @@ async function analyze(pathValue, options = {}, containers) {
|
|
|
119843
119967
|
path: path7,
|
|
119844
119968
|
compose_file: basename14(composeFile2),
|
|
119845
119969
|
gateway_overlay: overlay2,
|
|
119970
|
+
project_config: readProjectConfig(path7),
|
|
119846
119971
|
project: { name: project2, source: projectFromEnv ? ".env" : declaredName ? "compose name:" : "directory name (implicit)" },
|
|
119847
119972
|
domain: gatewayContext({ required: false }).config.domain,
|
|
119848
119973
|
services,
|
|
@@ -119874,6 +119999,19 @@ async function analyzeCommand(path7, options, command) {
|
|
|
119874
119999
|
output2.line(` project namespace ${report.project.name} (${report.project.source})`);
|
|
119875
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}`)))];
|
|
119876
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
|
+
}
|
|
119877
120015
|
output2.line("\nServices");
|
|
119878
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(",") || "-"}`);
|
|
119879
120017
|
output2.line("\nFindings");
|
|
@@ -120416,7 +120554,7 @@ function helpAfter(command, text) {
|
|
|
120416
120554
|
${text(commandInvocation(context.command))}`);
|
|
120417
120555
|
}
|
|
120418
120556
|
function runOptions(command) {
|
|
120419
|
-
return command.addOption(new Option("--input <text>", "Run input text").conflicts("inputJson")).option("--input-json <json>", "Run input as a JSON object").option("--profile <name>", `Profile from ${
|
|
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(
|
|
120420
120558
|
new Option("--workspace <strategy>", "Execution workspace (default: workflow policy or worktree)").choices([
|
|
120421
120559
|
"worktree",
|
|
120422
120560
|
"branch",
|
|
@@ -120486,12 +120624,12 @@ ${environment.map(([name = "", text]) => ` ${name.padEnd(width)} ${text}`).joi
|
|
|
120486
120624
|
Analysis: --analyze=auto uses the default agent only when runtime detection falls back to host.
|
|
120487
120625
|
--analyze=claude | --analyze=codex always run that agent.`
|
|
120488
120626
|
);
|
|
120489
|
-
leaf(flow, "add [branch]", "Create a worktree using the dashboard lifecycle").option("--existing", "Use an existing local or remote branch instead of creating a new one").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${
|
|
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(
|
|
120490
120628
|
"--from-linear <issue-id>",
|
|
120491
120629
|
`Bootstrap from a Linear issue, plus any saved ${APP_NAME} session or linked PR`
|
|
120492
120630
|
).option("--branch <name>", "Override the branch when --from-linear resolves to one");
|
|
120493
120631
|
helpAfter(
|
|
120494
|
-
leaf(flow, "oneshot [branch]", "Run a worktree start-to-finish, streaming logs to stdout").option("--resume <branch>", "Resume an existing local worktree instead of creating one").option("--prompt <text>", "Initial agent prompt (required; follow-up nudge when --resume)").option("--agent <id>", "Agent id to launch").option("--base <branch>", "Base branch for a new worktree (defaults to config)").option("--profile <name>", `Worktree profile from ${
|
|
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(
|
|
120495
120633
|
"--linear <id|team>",
|
|
120496
120634
|
"Tie this oneshot to Linear: ENG-123 loads the issue and posts back; ENG creates an issue when done"
|
|
120497
120635
|
).option("--branch <name>", "Override the branch when --linear resolves to one"),
|
|
@@ -120524,7 +120662,7 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
|
|
|
120524
120662
|
"--profile <name>",
|
|
120525
120663
|
"Profile name (alternative to positional arg)"
|
|
120526
120664
|
),
|
|
120527
|
-
() => `Switches the worktree to another profile from ${
|
|
120665
|
+
() => `Switches the worktree to another profile from ${PROJECT_CONFIG_PATH2}. An open
|
|
120528
120666
|
worktree is restarted with the new pane layout and commands; a closed
|
|
120529
120667
|
one picks the new profile up on its next open.`
|
|
120530
120668
|
);
|