@codions/portta 0.0.0-develop.157.sha-ae5ce5e → 0.0.0-develop.162.sha-7b40859

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.
@@ -1,8 +1,11 @@
1
1
  ---
2
- name: taskflow-workflows
2
+ name: portta-workflows
3
3
  description: Author and run custom multi-agent workflows with Taskflow — JavaScript files that orchestrate Codex, Claude Code, OpenCode, and Pi agents deterministically via agent()/parallel()/pipeline()/phase(). Use when a task should be decomposed across agents, independently verified, resumed durably, or managed as a reusable project workflow.
4
+ license: MIT
5
+ compatibility: Requires the portta CLI with the Taskflow module enabled, and at least one agent CLI (Codex, Claude Code, OpenCode or Pi).
4
6
  metadata:
5
- type: reference
7
+ author: codions-labs
8
+ version: "1"
6
9
  ---
7
10
 
8
11
  # Taskflow workflows
@@ -242,7 +245,6 @@ portta flow workflows save <file.workflow.js> [--project] [--force]
242
245
  portta flow workflows validate <file.workflow.js | name>
243
246
  portta flow workflows doctor
244
247
  portta flow workflows guide
245
- portta flow workflows install-skill [--claude] [--agents|--codex]
246
248
  ```
247
249
 
248
250
  Use `portta flow workflows validate <file>` before adding or changing a catalog workflow. `--fake` runs with a fake worker for a fast smoke test; `--json` prints `{runId, status, url, result, error}`. A standalone `run` auto-starts its live viewer and prints the URL; `--open` also opens it in a browser.
@@ -272,9 +274,12 @@ When you (an agent such as Claude Code or Codex) create or run a workflow on a u
272
274
 
273
275
  ## Installation
274
276
 
275
- Install this repository's skill with:
277
+ Install with the [Skills CLI](https://www.skills.sh):
278
+
276
279
  ```
277
- npx skills add <owner/repo> --skill taskflow-workflows
280
+ npx skills add codions-labs/portta --skill portta-workflows -g
278
281
  ```
279
282
 
280
- The Skills CLI can install it for Claude Code, Codex, OpenCode, Pi, and other supported agents. `portta flow workflows install-skill` remains available as a compatibility installer for Claude Code and the generic/Codex skill directory.
283
+ It installs into Claude Code, Codex, OpenCode, Cursor, Zed and the other agents it supports, symlinking by default so an update reaches every agent at once. `npx skills update` refreshes it; `npx skills remove` takes it out.
284
+
285
+ Pair it with `portta-method`, which carries the branching, worktree, commit and pull request rules this project follows.
package/dist/cli.js CHANGED
@@ -20141,6 +20141,26 @@ function isLoopbackAddress(address) {
20141
20141
  function isWildcardAddress(address) {
20142
20142
  return address === "0.0.0.0" || address === "::";
20143
20143
  }
20144
+ function isLoopbackIp(address) {
20145
+ return address === "::1" || /^127(\.\d{1,3}){3}$/.test(address);
20146
+ }
20147
+ function localhostDnsVerdict(addresses) {
20148
+ const hint = "see docs/product/guides/local-development.md#how-localhost-resolves";
20149
+ if (addresses.length === 0) return check2("dns.local", "warn", "local DNS", "could not confirm *.localhost resolution", hint);
20150
+ const stray = addresses.filter((address) => !isLoopbackIp(address));
20151
+ return stray.length === 0 ? check2("dns.local", "pass", "local DNS", "*.localhost resolves to loopback") : check2("dns.local", "warn", "local DNS", `*.localhost resolves to ${stray.join(", ")}, not loopback`, hint);
20152
+ }
20153
+ function loopbackDomainVerdict(domain2, resolved2, bind) {
20154
+ if (!isLoopbackIp(resolved2)) return null;
20155
+ const served = isWildcardAddress(bind) || bind === resolved2 || isLoopbackAddress(bind) && resolved2 === "127.0.0.1";
20156
+ return served ? check2("domain.reachable", "pass", "project hostnames", `*.${domain2} resolves to loopback, served on ${bind}`) : check2(
20157
+ "domain.reachable",
20158
+ "warn",
20159
+ "project hostnames",
20160
+ `*.${domain2} resolves to ${resolved2}, but Traefik listens on ${bind}`,
20161
+ "point the wildcard at an address Traefik listens on; see docs/product/guides/local-domains.md"
20162
+ );
20163
+ }
20144
20164
  function publishesSensitivePort(published) {
20145
20165
  return SENSITIVE_PORTS.some((port) => published.includes(`0.0.0.0:`) && published.includes(`->${port}`));
20146
20166
  }
@@ -22364,7 +22384,7 @@ var init_package = __esm({
22364
22384
  "package.json"() {
22365
22385
  package_default = {
22366
22386
  name: "@codions/portta",
22367
- version: "0.0.0-develop.157.sha-ae5ce5e",
22387
+ version: "0.0.0-develop.162.sha-7b40859",
22368
22388
  description: "Machine-first CLI for a shared Docker development gateway",
22369
22389
  license: "MIT",
22370
22390
  type: "module",
@@ -22438,7 +22458,7 @@ var init_version = __esm({
22438
22458
  "use strict";
22439
22459
  init_package();
22440
22460
  CLI_VERSION = package_default.version;
22441
- CLI_BUILD_DATE = true ? "2026-09-16T21:32:25Z" : void 0;
22461
+ CLI_BUILD_DATE = true ? "2026-09-17T23:23:40Z" : void 0;
22442
22462
  }
22443
22463
  });
22444
22464
 
@@ -37260,7 +37280,7 @@ function parseLinearTarget(raw2) {
37260
37280
  if (LinearTeamKeySchema.safeParse(trimmed).success) return { kind: "team", teamKey: trimmed };
37261
37281
  return { kind: "invalid", raw: trimmed };
37262
37282
  }
37263
- var BooleanLikeSchema, ErrorResponseSchema, OkResponseSchema, EnabledResponseSchema, DiagnosticCheckStatusSchema, DiagnosticCheckSchema, DiagnosticsResponseSchema, JsonValueSchema, TimestampSchema, PublicIdSchema, ConfigurationValueSchema, SequenceSchema, SequenceQuerySchema, RunIdSchema, ExecutionIdSchema, SessionIdSchema, WorkspaceIdSchema, WorkflowIdSchema, ProjectIdSchema, IdempotencyKeySchema, RunModeSchema, RunStatusSchema, ExecutionStatusSchema, AgentTransportSchema, AgentPermissionModeSchema, StdioMcpServerSchema, WorkspacePolicySchema, WorkspaceStrategySchema, WorkspaceAccessSchema, WorkspaceStateSchema, WorkflowOriginSchema, WorkflowAvailabilitySchema, EventSourceSchema, SessionCapabilitySchema, RunCapabilitySchema, WorkspaceSchema, WorkspaceSelectionSchema, WorkflowWorkspacePolicySchema, WorkflowPhaseSchema, WorkflowDefinitionSchema, WorkflowSnapshotSchema, ExecutionUsageSchema, ExecutionObservabilitySchema, ExecutionSchema, RunSchema, WorkflowProgressPhaseStatusSchema, WorkflowProgressPhaseSchema, WorkflowProgressSchema, RunArtifactSchema, RunDetailSchema, TranscriptChunkSchema, TranscriptEntrySchema, ExecutionTranscriptResponseSchema, CreateRunFields, CreateRunRequestSchema, CancelRunRequestSchema, ResumeRunRequestSchema, RespondRunPermissionRequestSchema, RunEventPayloadSchema, RunEventSchema, ProjectIdParamsSchema, TaskflowRunIdParamsSchema, ExecutionIdParamsSchema, RunEventsQuerySchema, ExecutionTranscriptQuerySchema, WorkflowListResponseSchema, RunWorkspaceContextSchema, RunListResponseSchema, RunDetailResponseSchema, RunEventsResponseSchema, BuiltInAgentIdSchema, AgentIdSchema, WorktreeCreateModeSchema, LinearIssueIdSchema, LinearTeamKeySchema, PostWorktreeToLinearTargetSchema, PostWorktreeToLinearRequestSchema, PostWorktreeToLinearResponseSchema, FromLinearInputSchema, OneshotConfigSchema, AgentCapabilitiesSchema, AgentSummarySchema, AgentDetailsSchema, AgentListResponseSchema, UpsertCustomAgentRequestSchema, AgentResponseSchema, ValidateCustomAgentResponseSchema, WorktreeCreationPhaseSchema, AvailableBranchSchema, AvailableBranchesQuerySchema, NumberLikePathParamSchema, BranchListResponseSchema, WorktreeSourceSchema, SessionInterfaceModeSchema, CreateWorktreeRequestSchema, OpenWorktreeRequestSchema, CreateWorktreeResponseSchema, SetWorktreeArchivedRequestSchema, SetWorktreeArchivedResponseSchema, SetWorktreeLabelRequestSchema, SetWorktreeLabelResponseSchema, SetWorktreeProfileRequestSchema, SetWorktreeProfileResponseSchema, ToggleEnabledRequestSchema, SendWorktreePromptRequestSchema, AgentsSendMessageRequestSchema, PullMainRequestSchema, PullMainStatusSchema, PullMainResponseSchema, ServiceStatusSchema, PrCommentSchema, CiCheckSchema, PrEntrySchema, LinearIssueLabelSchema, LinearIssueStateSchema, LinkedLinearIssueSchema, LinearIssueSchema, LinearIssueAvailabilitySchema, LinearIssuesResponseSchema, AutoNameProviderSchema, AutoNameConfigResponseSchema, WorktreeCreationStateSchema, AppNotificationSchema, WorktreeTabSchema, ProjectWorktreeSnapshotSchema, ProjectSnapshotSchema, WorktreeConversationProviderSchema, CodexWorktreeConversationRefSchema, ClaudeWorktreeConversationRefSchema, WorktreeConversationRefSchema, AgentsUiWorktreeSummarySchema, AgentsUiConversationMessageRoleSchema, AgentsUiConversationMessageStatusSchema, AgentsUiConversationMessageKindSchema, AgentsUiConversationMessageSchema, AgentsUiConversationStateSchema, AgentsUiWorktreeConversationResponseSchema, AgentsUiSendMessageResponseSchema, AgentsUiInterruptResponseSchema, AgentsUiConversationMessageDeltaEventSchema, AgentsUiConversationMessageUpsertEventSchema, AgentsUiConversationStatusEventSchema, AgentsUiConversationErrorEventSchema, AgentsUiConversationEventSchema, WorktreeListResponseSchema, UnpushedCommitSchema, WorktreeDiffResponseSchema, ServiceConfigSchema, EnvironmentIdParamsSchema, EnvironmentServiceParamsSchema, EnvironmentServiceActionRequestSchema, EndpointIdParamsSchema, EnvironmentStatusSchema, EnvironmentCapabilitiesSchema, EnvironmentSecuritySchema, EndpointSchema, EnvironmentServiceSchema, EnvironmentSchema, EnvironmentResponseSchema, EnvironmentServicesResponseSchema, EnvironmentExecRequestSchema, EnvironmentExecResponseSchema, EnvironmentTerminalResponseSchema, EnvironmentExposeRequestSchema, ProfileConfigSchema, LinkedRepoInfoSchema, MultiplexerKindSchema, BuildInfoSchema, AppConfigSchema, CiLogsResponseSchema, WorktreeNameParamsSchema, WorktreeTabParamsSchema, CreateTabResponseSchema, NotificationIdParamsSchema, AgentIdParamsSchema, RunIdParamsSchema, ProjectSummarySchema, ProjectsResponseSchema, AddProjectRequestSchema, AddProjectResponseSchema, ProjectInitPhaseSchema, ProjectInitStateSchema, ProjectInitsResponseSchema, ProjectPrefixParamsSchema;
37283
+ var BooleanLikeSchema, ErrorResponseSchema, OkResponseSchema, EnabledResponseSchema, DiagnosticCheckStatusSchema, DiagnosticCheckSchema, DiagnosticsResponseSchema, JsonValueSchema, TimestampSchema, PublicIdSchema, ConfigurationValueSchema, SequenceSchema, SequenceQuerySchema, RunIdSchema, ExecutionIdSchema, SessionIdSchema, WorkspaceIdSchema, WorkflowIdSchema, ProjectIdSchema, IdempotencyKeySchema, RunModeSchema, RunStatusSchema, ExecutionStatusSchema, AgentTransportSchema, AgentPermissionModeSchema, StdioMcpServerSchema, WorkspacePolicySchema, WorkspaceStrategySchema, WorkspaceAccessSchema, WorkspaceStateSchema, WorkflowOriginSchema, WorkflowAvailabilitySchema, EventSourceSchema, SessionCapabilitySchema, RunCapabilitySchema, WorkspaceSchema, WorkspaceSelectionSchema, WorkflowWorkspacePolicySchema, WorkflowPhaseSchema, WorkflowDefinitionSchema, WorkflowSnapshotSchema, ExecutionUsageSchema, ExecutionObservabilitySchema, ExecutionSchema, RunSchema, WorkflowProgressPhaseStatusSchema, WorkflowProgressPhaseSchema, WorkflowProgressSchema, RunArtifactSchema, RunDetailSchema, TranscriptChunkSchema, TranscriptEntrySchema, ExecutionTranscriptResponseSchema, CreateRunFields, CreateRunRequestSchema, CancelRunRequestSchema, ResumeRunRequestSchema, RespondRunPermissionRequestSchema, RunEventPayloadSchema, RunEventSchema, ProjectIdParamsSchema, TaskflowRunIdParamsSchema, ExecutionIdParamsSchema, RunEventsQuerySchema, ExecutionTranscriptQuerySchema, WorkflowListResponseSchema, RunWorkspaceContextSchema, RunListResponseSchema, RunDetailResponseSchema, RunEventsResponseSchema, BuiltInAgentIdSchema, AgentIdSchema, WorktreeCreateModeSchema, LinearIssueIdSchema, LinearTeamKeySchema, PostWorktreeToLinearTargetSchema, PostWorktreeToLinearRequestSchema, PostWorktreeToLinearResponseSchema, FromLinearInputSchema, OneshotConfigSchema, AgentCapabilitiesSchema, AgentSummarySchema, AgentDetailsSchema, AgentListResponseSchema, UpsertCustomAgentRequestSchema, AgentResponseSchema, ValidateCustomAgentResponseSchema, WorktreeCreationPhaseSchema, AvailableBranchSchema, AvailableBranchesQuerySchema, RemoveWorktreeQuerySchema, NumberLikePathParamSchema, BranchListResponseSchema, WorktreeSourceSchema, SessionInterfaceModeSchema, CreateWorktreeRequestSchema, OpenWorktreeRequestSchema, CreateWorktreeResponseSchema, SetWorktreeArchivedRequestSchema, SetWorktreeArchivedResponseSchema, SetWorktreeLabelRequestSchema, SetWorktreeLabelResponseSchema, SetWorktreeProfileRequestSchema, SetWorktreeProfileResponseSchema, ToggleEnabledRequestSchema, SendWorktreePromptRequestSchema, AgentsSendMessageRequestSchema, PullMainRequestSchema, PullMainStatusSchema, PullMainResponseSchema, ServiceStatusSchema, PrCommentSchema, CiCheckSchema, PrEntrySchema, LinearIssueLabelSchema, LinearIssueStateSchema, LinkedLinearIssueSchema, LinearIssueSchema, LinearIssueAvailabilitySchema, LinearIssuesResponseSchema, AutoNameProviderSchema, AutoNameConfigResponseSchema, WorktreeCreationStateSchema, AppNotificationSchema, WorktreeTabSchema, ProjectWorktreeSnapshotSchema, ProjectSnapshotSchema, WorktreeConversationProviderSchema, CodexWorktreeConversationRefSchema, ClaudeWorktreeConversationRefSchema, WorktreeConversationRefSchema, AgentsUiWorktreeSummarySchema, AgentsUiConversationMessageRoleSchema, AgentsUiConversationMessageStatusSchema, AgentsUiConversationMessageKindSchema, AgentsUiConversationMessageSchema, AgentsUiConversationStateSchema, AgentsUiWorktreeConversationResponseSchema, AgentsUiSendMessageResponseSchema, AgentsUiInterruptResponseSchema, AgentsUiConversationMessageDeltaEventSchema, AgentsUiConversationMessageUpsertEventSchema, AgentsUiConversationStatusEventSchema, AgentsUiConversationErrorEventSchema, AgentsUiConversationEventSchema, WorktreeListResponseSchema, UnpushedCommitSchema, WorktreeDiffResponseSchema, ServiceConfigSchema, EnvironmentIdParamsSchema, EnvironmentServiceParamsSchema, EnvironmentServiceActionRequestSchema, EndpointIdParamsSchema, EnvironmentStatusSchema, EnvironmentCapabilitiesSchema, EnvironmentSecuritySchema, EndpointSchema, EnvironmentServiceSchema, EnvironmentSchema, EnvironmentResponseSchema, EnvironmentServicesResponseSchema, EnvironmentExecRequestSchema, EnvironmentExecResponseSchema, EnvironmentTerminalResponseSchema, EnvironmentExposeRequestSchema, ProfileConfigSchema, LinkedRepoInfoSchema, MultiplexerKindSchema, BuildInfoSchema, AppConfigSchema, CiLogsResponseSchema, WorktreeNameParamsSchema, WorktreeTabParamsSchema, CreateTabResponseSchema, NotificationIdParamsSchema, AgentIdParamsSchema, RunIdParamsSchema, ProjectSummarySchema, ProjectsResponseSchema, AddProjectRequestSchema, AddProjectResponseSchema, ProjectInitPhaseSchema, ProjectInitStateSchema, ProjectInitsResponseSchema, ProjectPrefixParamsSchema;
37264
37284
  var init_schemas3 = __esm({
37265
37285
  "../contracts/src/taskflow/schemas.ts"() {
37266
37286
  "use strict";
@@ -37741,6 +37761,9 @@ var init_schemas3 = __esm({
37741
37761
  AvailableBranchesQuerySchema = external_exports.object({
37742
37762
  includeRemote: BooleanLikeSchema.optional()
37743
37763
  });
37764
+ RemoveWorktreeQuerySchema = external_exports.object({
37765
+ force: BooleanLikeSchema.optional()
37766
+ });
37744
37767
  NumberLikePathParamSchema = external_exports.union([
37745
37768
  external_exports.number().int().nonnegative(),
37746
37769
  external_exports.string().regex(/^\d+$/).transform((value3) => Number(value3))
@@ -38682,6 +38705,7 @@ var init_contract = __esm({
38682
38705
  summary: "Remove a worktree",
38683
38706
  path: apiPaths.removeWorktree,
38684
38707
  pathParams: WorktreeNameParamsSchema,
38708
+ query: RemoveWorktreeQuerySchema,
38685
38709
  responses: {
38686
38710
  200: OkResponseSchema,
38687
38711
  ...commonErrorResponses
@@ -54927,6 +54951,21 @@ var init_git = __esm({
54927
54951
  const result = tryRunGit(["diff", "HEAD", "--no-color"], cwd);
54928
54952
  return result.ok ? result.stdout : "";
54929
54953
  }
54954
+ /**
54955
+ * Commits reachable from HEAD and from nothing else that would survive this
54956
+ * worktree: not on an origin branch, not on the project's main branch. It
54957
+ * answers "would deleting this branch lose work", which `aheadCount` cannot:
54958
+ * with no upstream and no remote at all, every commit counts as ahead.
54959
+ */
54960
+ countUnsavedCommits(cwd, baseBranch) {
54961
+ const count2 = (args) => {
54962
+ const result = tryRunGit(args, cwd);
54963
+ return result.ok ? parseInt(result.stdout, 10) || 0 : null;
54964
+ };
54965
+ const excludingBase = baseBranch ? count2(["rev-list", "--count", "HEAD", "--not", "--remotes=origin", baseBranch]) : null;
54966
+ if (excludingBase !== null) return excludingBase;
54967
+ return count2(["rev-list", "--count", "HEAD", "--not", "--remotes=origin"]) ?? 0;
54968
+ }
54930
54969
  listUnpushedCommits(cwd) {
54931
54970
  let result = tryRunGit(["log", "--oneline", "@{upstream}..HEAD"], cwd);
54932
54971
  if (!result.ok) {
@@ -58702,9 +58741,23 @@ var init_lifecycle_service = __esm({
58702
58741
  throw this.wrapOperationError(error61);
58703
58742
  }
58704
58743
  }
58705
- async removeWorktree(branch) {
58744
+ /**
58745
+ * Removing a worktree deletes its branch with `--force`, so anything living
58746
+ * only there is gone. Uncommitted changes and unpushed commits therefore
58747
+ * refuse the removal unless the caller says to discard them.
58748
+ */
58749
+ async removeWorktree(branch, options = {}) {
58706
58750
  try {
58707
58751
  const resolved2 = await this.resolveExistingWorktree(branch);
58752
+ if (!options.force) {
58753
+ const unsaved = this.describeUnsavedWork(resolved2.entry);
58754
+ if (unsaved) {
58755
+ throw new LifecycleError(
58756
+ `Worktree has ${unsaved}: ${branch}. Commit or push them, or remove with --force to discard them.`,
58757
+ 409
58758
+ );
58759
+ }
58760
+ }
58708
58761
  await this.removeResolvedWorktree(resolved2);
58709
58762
  } catch (error61) {
58710
58763
  throw this.wrapOperationError(error61);
@@ -58715,15 +58768,21 @@ var init_lifecycle_service = __esm({
58715
58768
  const resolvedWorktrees = await this.resolveAllWorktrees();
58716
58769
  const sessionName = buildProjectSessionName(this.deps.projectRoot);
58717
58770
  const removedBranches = [];
58771
+ const keptBranches = [];
58718
58772
  for (const resolved2 of resolvedWorktrees) {
58719
58773
  const branch = resolved2.entry.branch ?? resolved2.entry.path;
58720
58774
  if (await this.deps.sessions.hasWindow(sessionName, buildWorktreeWindowName(branch))) {
58721
58775
  continue;
58722
58776
  }
58777
+ const unsaved = this.describeUnsavedWork(resolved2.entry);
58778
+ if (unsaved) {
58779
+ keptBranches.push({ branch, reason: unsaved });
58780
+ continue;
58781
+ }
58723
58782
  await this.removeResolvedWorktree(resolved2);
58724
58783
  removedBranches.push(branch);
58725
58784
  }
58726
- return { removedBranches };
58785
+ return { removedBranches, keptBranches };
58727
58786
  } catch (error61) {
58728
58787
  throw this.wrapOperationError(error61);
58729
58788
  }
@@ -59220,6 +59279,14 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59220
59279
  }
59221
59280
  return cleanupErrors.length > 0 ? cleanupErrors.join("; ") : null;
59222
59281
  }
59282
+ /** What this worktree holds that exists nowhere else, or null when it is safe to delete. */
59283
+ describeUnsavedWork(entry) {
59284
+ const status = this.deps.git.readWorktreeStatus(entry.path);
59285
+ if (status.dirty) return "uncommitted changes";
59286
+ const commits = this.deps.git.countUnsavedCommits(entry.path, this.deps.config.workspace.mainBranch);
59287
+ if (commits > 0) return `${commits} commit${commits === 1 ? "" : "s"} that are only here`;
59288
+ return null;
59289
+ }
59223
59290
  ensureNoUncommittedChanges(entry) {
59224
59291
  const status = this.deps.git.readWorktreeStatus(entry.path);
59225
59292
  if (status.dirty) {
@@ -59316,7 +59383,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59316
59383
  const cleanupErrors = [];
59317
59384
  for (const branch of [...branches].reverse()) {
59318
59385
  try {
59319
- await this.removeWorktree(branch);
59386
+ await this.removeWorktree(branch, { force: true });
59320
59387
  } catch (error61) {
59321
59388
  cleanupErrors.push(`rollback failed for ${branch}: ${toErrorMessage2(error61)}`);
59322
59389
  }
@@ -68913,14 +68980,14 @@ ${resolvedPrompt}` : conversationContext;
68913
68980
  201
68914
68981
  );
68915
68982
  }
68916
- async function apiDeleteWorktree(project2, name) {
68983
+ async function apiDeleteWorktree(project2, name, force) {
68917
68984
  return project2.withRemovingBranch(name, async () => {
68918
68985
  log.info(`[worktree:rm] name=${name}`);
68919
68986
  const worktree = project2.runtime.projectRuntime.getWorktreeByBranch(name);
68920
68987
  const environmentId = worktree ? environmentIdForWorkspace(project2.environments.projectEnvironments(), worktree.worktreeId) : null;
68921
68988
  const environment = environmentId ? project2.environments.environmentForProject(environmentId) : null;
68922
68989
  if (environment) await project2.environments.destroyEnvironmentRecord(environment);
68923
- await project2.runtime.lifecycleService.removeWorktree(name);
68990
+ await project2.runtime.lifecycleService.removeWorktree(name, { force });
68924
68991
  log.debug(`[worktree:rm] done name=${name}`);
68925
68992
  return jsonResponse({ ok: true });
68926
68993
  });
@@ -69107,9 +69174,9 @@ function worktreeRoutes(deps) {
69107
69174
  const app = projectRouter();
69108
69175
  projectRoute(app, deps, "fetchWorktrees", "Worktrees", (project2) => apiGetWorktrees(project2));
69109
69176
  projectRoute(app, deps, "createWorktree", "Worktrees", (project2, { body }) => apiCreateWorktree(project2, body));
69110
- projectRoute(app, deps, "removeWorktree", "Worktrees", (project2, { params }) => {
69177
+ projectRoute(app, deps, "removeWorktree", "Worktrees", (project2, { params, query: query2 }) => {
69111
69178
  const name = worktreeName(params.name);
69112
- return name instanceof Response ? name : apiDeleteWorktree(project2, name);
69179
+ return name instanceof Response ? name : apiDeleteWorktree(project2, name, query2.force === true);
69113
69180
  });
69114
69181
  projectRoute(app, deps, "openWorktree", "Worktrees", (project2, { params, body }) => {
69115
69182
  const name = worktreeName(params.name);
@@ -89799,7 +89866,7 @@ function createDaemonTaskflowHost(context) {
89799
89866
  port: hostListen(env).port,
89800
89867
  workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
89801
89868
  version: env.PORTTA_VERSION || "0.0.0-local",
89802
- buildDate: true ? "2026-09-16T21:32:25Z" : (/* @__PURE__ */ new Date()).toISOString(),
89869
+ buildDate: true ? "2026-09-17T23:23:40Z" : (/* @__PURE__ */ new Date()).toISOString(),
89803
89870
  environmentStore: createEnvironmentStore(paths3.database),
89804
89871
  hostEnvironmentProvider: new HostEnvironmentProvider(),
89805
89872
  devContainerProvider: new DevContainerProvider(),
@@ -111947,11 +112014,12 @@ function worktreeRequestFromCli(action) {
111947
112014
  branch: requireWorktreeName(first),
111948
112015
  ...options.interface !== void 0 ? { interfaceMode: parseInterfaceMode(options.interface) } : {}
111949
112016
  };
112017
+ case "remove":
112018
+ return { command, branch: requireWorktreeName(first), force: options.force === true };
111950
112019
  case "close":
111951
112020
  case "refresh":
111952
112021
  case "archive":
111953
112022
  case "unarchive":
111954
- case "remove":
111955
112023
  case "merge":
111956
112024
  return { command, branch: requireWorktreeName(first) };
111957
112025
  case "label":
@@ -112205,6 +112273,9 @@ ${parsed.input.prompt}` : seed.data.conversationMarkdown;
112205
112273
  return 0;
112206
112274
  }
112207
112275
  const result = await runtime3.lifecycleService.pruneWorktrees();
112276
+ for (const kept of result.keptBranches) {
112277
+ stdout2(`Kept ${kept.branch}: ${kept.reason}`);
112278
+ }
112208
112279
  if (result.removedBranches.length === 0) {
112209
112280
  stdout2("No closed worktrees to prune.");
112210
112281
  return 0;
@@ -112441,7 +112512,9 @@ ${parsed.input.prompt}` : seed.data.conversationMarkdown;
112441
112512
  stdout2(`Restored worktree ${branch}`);
112442
112513
  return 0;
112443
112514
  case "remove":
112444
- await runtime2.lifecycleService.removeWorktree(branch);
112515
+ await runtime2.lifecycleService.removeWorktree(branch, {
112516
+ force: request2.command === "remove" && request2.force
112517
+ });
112445
112518
  stdout2(`Removed worktree ${branch}`);
112446
112519
  return 0;
112447
112520
  case "merge":
@@ -113354,7 +113427,6 @@ var cli_exports = {};
113354
113427
  __export(cli_exports, {
113355
113428
  UsageError: () => UsageError2,
113356
113429
  browserOpenCommand: () => browserOpenCommand,
113357
- installTaskflowWorkflowSkill: () => installTaskflowWorkflowSkill,
113358
113430
  isUserFacingError: () => isUserFacingError,
113359
113431
  main: () => main,
113360
113432
  openBrowser: () => openBrowser,
@@ -113369,11 +113441,9 @@ import {
113369
113441
  readFileSync as readFileSync28,
113370
113442
  realpathSync as realpathSync6,
113371
113443
  rmSync as rmSync9,
113372
- statSync as statSync10,
113373
- writeFileSync as writeFileSync14
113444
+ statSync as statSync10
113374
113445
  } from "node:fs";
113375
113446
  import { get as httpGet } from "node:http";
113376
- import { homedir as homedir9 } from "node:os";
113377
113447
  import { dirname as dirname28, join as join50, resolve as resolve30, sep as sep3 } from "node:path";
113378
113448
  import { fileURLToPath as fileURLToPath7 } from "node:url";
113379
113449
  function parseArgs(argv) {
@@ -113479,7 +113549,7 @@ async function main(argv = process.argv.slice(2), options = {}) {
113479
113549
  case "doctor":
113480
113550
  return cmdDoctor();
113481
113551
  case "install-skill":
113482
- return cmdInstallSkill(flags, options.skillPath);
113552
+ return cmdInstallSkillRetired();
113483
113553
  case "guide":
113484
113554
  return cmdGuide(options.skillPath);
113485
113555
  case void 0:
@@ -113860,37 +113930,16 @@ function readSkill(skillPath) {
113860
113930
  async function cmdGuide(skillPath) {
113861
113931
  process.stdout.write(readSkill(skillPath).replace(/^---\n[\s\S]*?\n---\n+/, ""));
113862
113932
  }
113863
- function installTaskflowWorkflowSkill(home2, body, flags = {}) {
113864
- const wantClaude = flags.claude === true;
113865
- const wantGeneric = flags.agents === true || flags.codex === true;
113866
- const both = !wantClaude && !wantGeneric;
113867
- const targets = [];
113868
- if (both || wantClaude) targets.push(join50(home2, ".claude", "skills"));
113869
- if (both || wantGeneric) targets.push(join50(home2, ".agents", "skills"));
113870
- return targets.map((base2) => {
113871
- const dest = join50(base2, `${APP_SLUG}-workflows`);
113872
- mkdirSync17(dest, { recursive: true });
113873
- const path7 = join50(dest, "SKILL.md");
113874
- writeFileSync14(path7, body);
113875
- return path7;
113876
- });
113877
- }
113878
- async function cmdInstallSkill(flags, skillPath) {
113879
- let body;
113880
- try {
113881
- body = readSkill(skillPath);
113882
- } catch (err2) {
113883
- console.error(err2 instanceof Error ? err2.message : String(err2));
113884
- process.exitCode = 1;
113885
- return;
113886
- }
113887
- installTaskflowWorkflowSkill(homedir9(), body, {
113888
- claude: flags.claude,
113889
- agents: flags.agents,
113890
- codex: flags.codex
113891
- }).forEach((path7) => {
113892
- console.log(`installed skill \u2192 ${path7}`);
113893
- });
113933
+ function cmdInstallSkillRetired() {
113934
+ console.error(
113935
+ `${CLI_NAME} workflows install-skill has been retired. Install the skill with the Skills CLI instead:
113936
+
113937
+ npx skills add codions-labs/portta --skill portta-workflows -g
113938
+
113939
+ It supports Claude Code, Codex, OpenCode, Cursor, Zed and others, symlinks by default,
113940
+ and \`npx skills update\` keeps every agent current. See https://www.skills.sh.`
113941
+ );
113942
+ process.exitCode = 1;
113894
113943
  }
113895
113944
  function printHelp() {
113896
113945
  console.log(`${APP_NAME} workflows \u2014 run JS workflow files that orchestrate coding agents
@@ -113920,7 +113969,6 @@ Usage:
113920
113969
  ${CLI_NAME} workflows validate <file.workflow.js | name>
113921
113970
  ${CLI_NAME} workflows doctor
113922
113971
  ${CLI_NAME} workflows guide
113923
- ${CLI_NAME} workflows install-skill [--claude] [--agents|--codex] Install the ${APP_NAME} authoring skill
113924
113972
 
113925
113973
  Named workflows resolve by meta.name across three tiers (highest first): project
113926
113974
  (${PROJECT_CONFIG_DIR}/${PATH_NAMES.workflows}/), user (~/${GLOBAL_CONFIG_DIR}/${PATH_NAMES.workflows}/), and package built-ins.
@@ -113929,9 +113977,10 @@ Named workflows resolve by meta.name across three tiers (highest first): project
113929
113977
  ${CLI_NAME} workflows run deep-research --args '"<question>"'
113930
113978
  ${CLI_NAME} workflows run code-review [--args '{"target": "<ref|path>", "level": "high|xhigh|max"}']
113931
113979
 
113932
- Run journals are stored in ~/${GLOBAL_CONFIG_DIR}/${PATH_NAMES.runs}/<id>/. The guide, install-skill command,
113933
- and skills/portta-workflows/SKILL.md share one source of truth \u2014 run
113934
- \`${CLI_NAME} workflows guide\` to read it.`);
113980
+ Run journals are stored in ~/${GLOBAL_CONFIG_DIR}/${PATH_NAMES.runs}/<id>/. The guide and
113981
+ skills/portta-workflows/SKILL.md share one source of truth \u2014 run
113982
+ \`${CLI_NAME} workflows guide\` to read it. Install the skill into your agents with
113983
+ \`npx skills add codions-labs/portta --skill portta-workflows -g\`.`);
113935
113984
  }
113936
113985
  function isUserFacingError(err2) {
113937
113986
  if (err2 instanceof UsageError2 || err2 instanceof WorkflowSyntaxError || err2 instanceof WorkflowNotFoundError || err2 instanceof WorkflowError || err2 instanceof AgentError || err2 instanceof AgentInterrupted || err2 instanceof JournalNotFoundError || err2 instanceof ResumePreconditionError) {
@@ -120174,7 +120223,7 @@ var WORKFLOW_ENGINE_ACTIONS = [
120174
120223
  ["save", "Save a workflow file into the registry"],
120175
120224
  ["doctor", "Check the standalone workflow engine"],
120176
120225
  ["guide", "Print the workflow authoring guide"],
120177
- ["install-skill", "Install the workflow authoring skill for coding agents"]
120226
+ ["install-skill", "Retired \u2014 install with: npx skills add codions-labs/portta --skill portta-workflows -g"]
120178
120227
  ];
120179
120228
  var USAGE_HINT = "(run with --help for usage)";
120180
120229
  function parsePort2(value3) {
@@ -120302,7 +120351,14 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
120302
120351
  worktree is restarted with the new pane layout and commands; a closed
120303
120352
  one picks the new profile up on its next open.`
120304
120353
  );
120305
- leaf(flow, "remove <branch>", "Remove a worktree");
120354
+ helpAfter(
120355
+ leaf(flow, "remove <branch>", "Remove a worktree").option(
120356
+ "--force",
120357
+ "Remove even when the worktree holds uncommitted changes or commits that exist nowhere else"
120358
+ ),
120359
+ () => `Removing a worktree deletes its branch, so work that lives only there
120360
+ is gone. Without --force the removal is refused and says what it found.`
120361
+ );
120306
120362
  leaf(flow, "merge <branch>", "Merge a worktree into the main branch and remove it");
120307
120363
  leaf(flow, "send <branch> [prompt]", "Send a prompt to a running worktree agent").option("--prompt <text>", "Prompt text (alternative to positional arg)").option("--preamble <text>", "Preamble text sent before the prompt");
120308
120364
  helpAfter(
@@ -121127,14 +121183,7 @@ async function domainChecks(config3, env) {
121127
121183
  const domain2 = config3.domain;
121128
121184
  const panelExpose = env["PORTTA_WEB_EXPOSE"] || "local";
121129
121185
  if (domain2 === "localhost" || domain2.endsWith(".localhost")) {
121130
- const probe = await resolveIpv4("portta-probe.localhost");
121131
- checks.push(probe.length > 0 ? check2("dns.local", "pass", "local DNS", "*.localhost resolves to loopback") : check2(
121132
- "dns.local",
121133
- "warn",
121134
- "local DNS",
121135
- "could not confirm *.localhost resolution",
121136
- "see docs/product/guides/local-development.md if hostnames do not resolve"
121137
- ));
121186
+ checks.push(localhostDnsVerdict(await resolveIpv4("portta-probe.localhost")));
121138
121187
  if (panelExpose !== "local") {
121139
121188
  checks.push(check2(
121140
121189
  "domain.reachable",
@@ -121150,6 +121199,8 @@ async function domainChecks(config3, env) {
121150
121199
  const resolved2 = (await resolveIpv4(`portta-probe.${domain2}`))[0];
121151
121200
  if (!resolved2) {
121152
121201
  checks.push(check2("dns.wildcard", "fail", "wildcard DNS", `*.${domain2} does not resolve`, "portta dns setup"));
121202
+ } else if (isLoopbackIp(resolved2)) {
121203
+ checks.push(check2("dns.wildcard", "pass", "wildcard DNS", `*.${domain2} -> ${resolved2} (this machine)`));
121153
121204
  } else {
121154
121205
  const expected = env["PORTTA_PUBLIC_IP"] ?? "";
121155
121206
  checks.push(!expected ? check2("dns.wildcard", "pass", "wildcard DNS", `*.${domain2} -> ${resolved2}`) : resolved2 === expected ? check2("dns.wildcard", "pass", "wildcard DNS", `*.${domain2} -> ${resolved2} (this host)`) : check2(
@@ -121161,7 +121212,19 @@ async function domainChecks(config3, env) {
121161
121212
  ));
121162
121213
  }
121163
121214
  const bind = config3.bindAddress;
121164
- if (isLoopbackAddress(bind)) {
121215
+ const loopback = resolved2 ? loopbackDomainVerdict(domain2, resolved2, bind) : null;
121216
+ if (loopback) {
121217
+ checks.push(loopback);
121218
+ if (panelExpose !== "local") {
121219
+ checks.push(check2(
121220
+ "domain.reachable.remote",
121221
+ "warn",
121222
+ "project hostnames",
121223
+ `*.${domain2} resolves to loopback, and the panel is reached from elsewhere`,
121224
+ "point the wildcard at this host, or portta config set domain.mode auto"
121225
+ ));
121226
+ }
121227
+ } else if (isLoopbackAddress(bind)) {
121165
121228
  const publicIp = env["PORTTA_PUBLIC_IP"] ?? "";
121166
121229
  const fix = publicIp && isPrivateAddress(publicIp) ? `portta config set gateway.bindAddress ${publicIp} serves them on that network only` : "portta public enable exposes the HTTP services that opted in";
121167
121230
  checks.push(check2(
@@ -122067,17 +122130,17 @@ async function dnsSetup(options, command) {
122067
122130
 
122068
122131
  // src/commands/host-service.ts
122069
122132
  init_config2();
122070
- import { chmodSync as chmodSync10, existsSync as existsSync39, mkdirSync as mkdirSync19, readFileSync as readFileSync32, realpathSync as realpathSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync15 } from "node:fs";
122071
- import { homedir as homedir10 } from "node:os";
122133
+ import { chmodSync as chmodSync10, existsSync as existsSync39, mkdirSync as mkdirSync19, readFileSync as readFileSync32, realpathSync as realpathSync7, unlinkSync as unlinkSync6, writeFileSync as writeFileSync14 } from "node:fs";
122134
+ import { homedir as homedir9 } from "node:os";
122072
122135
  import { dirname as dirname29, join as join59 } from "node:path";
122073
122136
  init_context();
122074
122137
  init_errors3();
122075
122138
  var AUTO_PICKUP_ENV_VARS = ["LINEAR_API_KEY"];
122076
122139
  var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PATH", "PORTTA_ROOT"]);
122077
122140
  function logFile2() {
122078
- return join59(homedir10(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122141
+ return join59(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122079
122142
  }
122080
- function serviceFilePath(platform4, home2 = homedir10()) {
122143
+ function serviceFilePath(platform4, home2 = homedir9()) {
122081
122144
  return platform4 === "linux" ? join59(home2, ".config", "systemd", "user", `${SERVICE_IDENTITY.name}.service`) : join59(home2, "Library", "LaunchAgents", `${SERVICE_IDENTITY.launchdLabel}.plist`);
122082
122145
  }
122083
122146
  function escapePlistText(value3) {
@@ -122280,7 +122343,7 @@ ${notes.join("\n")}`);
122280
122343
  await confirm(`${installed ? "Reinstall" : "Install"} the ${SERVICE_IDENTITY.name} service?`, Boolean(options.yes));
122281
122344
  if (installed) await runAll(serviceCommands("uninstall", platform4, filePath), output2, true);
122282
122345
  mkdirSync19(dirname29(filePath), { recursive: true });
122283
- writeFileSync15(filePath, content);
122346
+ writeFileSync14(filePath, content);
122284
122347
  if (Object.keys(envVars).length > 0) chmodSync10(filePath, 384);
122285
122348
  await runAll(serviceCommands("install", platform4, filePath), output2);
122286
122349
  if (output2.json) output2.data({ installed: true, file: filePath });
@@ -122580,7 +122643,7 @@ function configPrepare(command) {
122580
122643
  init_src();
122581
122644
  init_context();
122582
122645
  import { chmodSync as chmodSync11, copyFileSync as copyFileSync4, cpSync, existsSync as existsSync40, mkdirSync as mkdirSync20, readdirSync as readdirSync9, realpathSync as realpathSync8, rmSync as rmSync11 } from "node:fs";
122583
- import { homedir as homedir11 } from "node:os";
122646
+ import { homedir as homedir10 } from "node:os";
122584
122647
  import { dirname as dirname30, join as join61, resolve as resolve31 } from "node:path";
122585
122648
  import { fileURLToPath as fileURLToPath8 } from "node:url";
122586
122649
  init_errors3();
@@ -122637,7 +122700,7 @@ async function setupCommand(options, command) {
122637
122700
  const output2 = new Output(global3);
122638
122701
  if (process.platform === "win32") throw new PreconditionError("setup requires a POSIX host");
122639
122702
  const currentRoot = findGatewayRoot();
122640
- const target = resolve31(options.dir ?? currentRoot ?? join61(homedir11(), "portta"));
122703
+ const target = resolve31(options.dir ?? currentRoot ?? join61(homedir10(), "portta"));
122641
122704
  const profile = options.profile ?? global3.profile ?? "local";
122642
122705
  const runtime2 = packagedRuntime();
122643
122706
  const steps = [];
@@ -123155,7 +123218,7 @@ async function shareGc(command) {
123155
123218
  // src/commands/tls.ts
123156
123219
  init_src();
123157
123220
  init_context();
123158
- import { chmodSync as chmodSync13, existsSync as existsSync42, mkdirSync as mkdirSync22, writeFileSync as writeFileSync16 } from "node:fs";
123221
+ import { chmodSync as chmodSync13, existsSync as existsSync42, mkdirSync as mkdirSync22, writeFileSync as writeFileSync15 } from "node:fs";
123159
123222
  import { platform as platform3 } from "node:os";
123160
123223
  import { join as join64 } from "node:path";
123161
123224
  init_errors3();
@@ -123306,7 +123369,7 @@ async function tlsInit(command) {
123306
123369
  }
123307
123370
  }
123308
123371
  output2.progress(`issued ${paths3.leafCertificate} for *.${domain2}`);
123309
- writeFileSync16(paths3.dynamic, localTlsDynamic());
123372
+ writeFileSync15(paths3.dynamic, localTlsDynamic());
123310
123373
  const envPath = join64(context.root, ".env");
123311
123374
  patchEnvFile(envPath, { TLS_ENABLED: "true", TLS_MODE: "local" });
123312
123375
  output2.progress("TLS enabled in .env");
@@ -123363,7 +123426,7 @@ function paths2(root2) {
123363
123426
  init_src();
123364
123427
  init_context();
123365
123428
  init_errors3();
123366
- import { chmodSync as chmodSync14, copyFileSync as copyFileSync5, cpSync as cpSync2, existsSync as existsSync43, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, rmSync as rmSync12, statSync as statSync12, writeFileSync as writeFileSync17 } from "node:fs";
123429
+ import { chmodSync as chmodSync14, copyFileSync as copyFileSync5, cpSync as cpSync2, existsSync as existsSync43, mkdirSync as mkdirSync23, mkdtempSync as mkdtempSync3, readFileSync as readFileSync36, rmSync as rmSync12, statSync as statSync12, writeFileSync as writeFileSync16 } from "node:fs";
123367
123430
  import { hostname as hostname3, tmpdir as tmpdir5 } from "node:os";
123368
123431
  import { dirname as dirname32, join as join65 } from "node:path";
123369
123432
  function globals16(command) {
@@ -123410,7 +123473,7 @@ async function backupCommand(options, command) {
123410
123473
  const staging = mkdtempSync3(join65(tmpdir5(), "portta-backup-"));
123411
123474
  chmodSync14(staging, 448);
123412
123475
  try {
123413
- writeFileSync17(join65(staging, "portta-backup.json"), renderManifest({
123476
+ writeFileSync16(join65(staging, "portta-backup.json"), renderManifest({
123414
123477
  version: BACKUP_VERSION,
123415
123478
  portta: context.version,
123416
123479
  created: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z"),
@@ -128587,7 +128650,7 @@ async function buildCommand(command) {
128587
128650
 
128588
128651
  // src/commands/remote.ts
128589
128652
  init_src();
128590
- import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync37, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync18 } from "node:fs";
128653
+ import { existsSync as existsSync44, mkdirSync as mkdirSync24, readFileSync as readFileSync37, readdirSync as readdirSync10, rmSync as rmSync13, writeFileSync as writeFileSync17 } from "node:fs";
128591
128654
  import { basename as basename20, join as join67 } from "node:path";
128592
128655
  import { createServer as createServer3 } from "node:net";
128593
128656
  import { randomBytes as randomBytes10 } from "node:crypto";
@@ -128867,7 +128930,7 @@ async function remoteAccessOpen(target, options, command) {
128867
128930
  throw new PreconditionError("the SSH tunnel exited immediately", `check that ${target} is reachable and that ${localPort} is free locally`);
128868
128931
  }
128869
128932
  const record6 = { id, pid, target, project: options.project, service: options.service, remotePort, localPort, started: Math.floor(Date.now() / 1e3) };
128870
- writeFileSync18(join67(directoryPath, `${id}.json`), renderTunnelRecord(record6));
128933
+ writeFileSync17(join67(directoryPath, `${id}.json`), renderTunnelRecord(record6));
128871
128934
  if (output2.json) {
128872
128935
  output2.data({ ...record6, address: `127.0.0.1:${localPort}` });
128873
128936
  return;
@@ -128932,7 +128995,7 @@ init_src();
128932
128995
  init_src();
128933
128996
  init_context();
128934
128997
  init_errors3();
128935
- import { chmodSync as chmodSync15, closeSync as closeSync3, existsSync as existsSync45, mkdirSync as mkdirSync25, openSync as openSync3, readFileSync as readFileSync38, rmSync as rmSync14, writeFileSync as writeFileSync19 } from "node:fs";
128998
+ import { chmodSync as chmodSync15, closeSync as closeSync3, existsSync as existsSync45, mkdirSync as mkdirSync25, openSync as openSync3, readFileSync as readFileSync38, rmSync as rmSync14, writeFileSync as writeFileSync18 } from "node:fs";
128936
128999
  import { ReadStream } from "node:tty";
128937
129000
  import { join as join68 } from "node:path";
128938
129001
  function globals20(command) {
@@ -129092,11 +129155,11 @@ async function tunnelSetup(options, command) {
129092
129155
  "copy the whole eyJ... string from the Cloudflare dashboard, not the install command around it"
129093
129156
  );
129094
129157
  }
129095
- writeFileSync19(paths3.credentials, renderTunnelCredentials(credentials), { mode: 384 });
129158
+ writeFileSync18(paths3.credentials, renderTunnelCredentials(credentials), { mode: 384 });
129096
129159
  chmodSync15(paths3.credentials, 384);
129097
129160
  const origin = options.origin || defaultOrigin(context);
129098
129161
  const config3 = { id: credentials.TunnelID, zone: options.zone, origin, credentialsFile: "/etc/cloudflared/credentials.json", includeApex: options.apex ?? false };
129099
- writeFileSync19(paths3.config, renderTunnelConfig(config3));
129162
+ writeFileSync18(paths3.config, renderTunnelConfig(config3));
129100
129163
  const envPath = join68(context.root, ".env");
129101
129164
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ZONE: options.zone, CLOUDFLARE_TUNNEL_ID: credentials.TunnelID });
129102
129165
  if (output2.json) {