@codions/portta 0.0.0-develop.159.sha-0da77d5 → 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
@@ -22384,7 +22384,7 @@ var init_package = __esm({
22384
22384
  "package.json"() {
22385
22385
  package_default = {
22386
22386
  name: "@codions/portta",
22387
- version: "0.0.0-develop.159.sha-0da77d5",
22387
+ version: "0.0.0-develop.162.sha-7b40859",
22388
22388
  description: "Machine-first CLI for a shared Docker development gateway",
22389
22389
  license: "MIT",
22390
22390
  type: "module",
@@ -22458,7 +22458,7 @@ var init_version = __esm({
22458
22458
  "use strict";
22459
22459
  init_package();
22460
22460
  CLI_VERSION = package_default.version;
22461
- CLI_BUILD_DATE = true ? "2026-09-17T17:01:02Z" : void 0;
22461
+ CLI_BUILD_DATE = true ? "2026-09-17T23:23:40Z" : void 0;
22462
22462
  }
22463
22463
  });
22464
22464
 
@@ -37280,7 +37280,7 @@ function parseLinearTarget(raw2) {
37280
37280
  if (LinearTeamKeySchema.safeParse(trimmed).success) return { kind: "team", teamKey: trimmed };
37281
37281
  return { kind: "invalid", raw: trimmed };
37282
37282
  }
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, 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;
37284
37284
  var init_schemas3 = __esm({
37285
37285
  "../contracts/src/taskflow/schemas.ts"() {
37286
37286
  "use strict";
@@ -37761,6 +37761,9 @@ var init_schemas3 = __esm({
37761
37761
  AvailableBranchesQuerySchema = external_exports.object({
37762
37762
  includeRemote: BooleanLikeSchema.optional()
37763
37763
  });
37764
+ RemoveWorktreeQuerySchema = external_exports.object({
37765
+ force: BooleanLikeSchema.optional()
37766
+ });
37764
37767
  NumberLikePathParamSchema = external_exports.union([
37765
37768
  external_exports.number().int().nonnegative(),
37766
37769
  external_exports.string().regex(/^\d+$/).transform((value3) => Number(value3))
@@ -38702,6 +38705,7 @@ var init_contract = __esm({
38702
38705
  summary: "Remove a worktree",
38703
38706
  path: apiPaths.removeWorktree,
38704
38707
  pathParams: WorktreeNameParamsSchema,
38708
+ query: RemoveWorktreeQuerySchema,
38705
38709
  responses: {
38706
38710
  200: OkResponseSchema,
38707
38711
  ...commonErrorResponses
@@ -54947,6 +54951,21 @@ var init_git = __esm({
54947
54951
  const result = tryRunGit(["diff", "HEAD", "--no-color"], cwd);
54948
54952
  return result.ok ? result.stdout : "";
54949
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
+ }
54950
54969
  listUnpushedCommits(cwd) {
54951
54970
  let result = tryRunGit(["log", "--oneline", "@{upstream}..HEAD"], cwd);
54952
54971
  if (!result.ok) {
@@ -58722,9 +58741,23 @@ var init_lifecycle_service = __esm({
58722
58741
  throw this.wrapOperationError(error61);
58723
58742
  }
58724
58743
  }
58725
- 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 = {}) {
58726
58750
  try {
58727
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
+ }
58728
58761
  await this.removeResolvedWorktree(resolved2);
58729
58762
  } catch (error61) {
58730
58763
  throw this.wrapOperationError(error61);
@@ -58735,15 +58768,21 @@ var init_lifecycle_service = __esm({
58735
58768
  const resolvedWorktrees = await this.resolveAllWorktrees();
58736
58769
  const sessionName = buildProjectSessionName(this.deps.projectRoot);
58737
58770
  const removedBranches = [];
58771
+ const keptBranches = [];
58738
58772
  for (const resolved2 of resolvedWorktrees) {
58739
58773
  const branch = resolved2.entry.branch ?? resolved2.entry.path;
58740
58774
  if (await this.deps.sessions.hasWindow(sessionName, buildWorktreeWindowName(branch))) {
58741
58775
  continue;
58742
58776
  }
58777
+ const unsaved = this.describeUnsavedWork(resolved2.entry);
58778
+ if (unsaved) {
58779
+ keptBranches.push({ branch, reason: unsaved });
58780
+ continue;
58781
+ }
58743
58782
  await this.removeResolvedWorktree(resolved2);
58744
58783
  removedBranches.push(branch);
58745
58784
  }
58746
- return { removedBranches };
58785
+ return { removedBranches, keptBranches };
58747
58786
  } catch (error61) {
58748
58787
  throw this.wrapOperationError(error61);
58749
58788
  }
@@ -59240,6 +59279,14 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59240
59279
  }
59241
59280
  return cleanupErrors.length > 0 ? cleanupErrors.join("; ") : null;
59242
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
+ }
59243
59290
  ensureNoUncommittedChanges(entry) {
59244
59291
  const status = this.deps.git.readWorktreeStatus(entry.path);
59245
59292
  if (status.dirty) {
@@ -59336,7 +59383,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
59336
59383
  const cleanupErrors = [];
59337
59384
  for (const branch of [...branches].reverse()) {
59338
59385
  try {
59339
- await this.removeWorktree(branch);
59386
+ await this.removeWorktree(branch, { force: true });
59340
59387
  } catch (error61) {
59341
59388
  cleanupErrors.push(`rollback failed for ${branch}: ${toErrorMessage2(error61)}`);
59342
59389
  }
@@ -68933,14 +68980,14 @@ ${resolvedPrompt}` : conversationContext;
68933
68980
  201
68934
68981
  );
68935
68982
  }
68936
- async function apiDeleteWorktree(project2, name) {
68983
+ async function apiDeleteWorktree(project2, name, force) {
68937
68984
  return project2.withRemovingBranch(name, async () => {
68938
68985
  log.info(`[worktree:rm] name=${name}`);
68939
68986
  const worktree = project2.runtime.projectRuntime.getWorktreeByBranch(name);
68940
68987
  const environmentId = worktree ? environmentIdForWorkspace(project2.environments.projectEnvironments(), worktree.worktreeId) : null;
68941
68988
  const environment = environmentId ? project2.environments.environmentForProject(environmentId) : null;
68942
68989
  if (environment) await project2.environments.destroyEnvironmentRecord(environment);
68943
- await project2.runtime.lifecycleService.removeWorktree(name);
68990
+ await project2.runtime.lifecycleService.removeWorktree(name, { force });
68944
68991
  log.debug(`[worktree:rm] done name=${name}`);
68945
68992
  return jsonResponse({ ok: true });
68946
68993
  });
@@ -69127,9 +69174,9 @@ function worktreeRoutes(deps) {
69127
69174
  const app = projectRouter();
69128
69175
  projectRoute(app, deps, "fetchWorktrees", "Worktrees", (project2) => apiGetWorktrees(project2));
69129
69176
  projectRoute(app, deps, "createWorktree", "Worktrees", (project2, { body }) => apiCreateWorktree(project2, body));
69130
- projectRoute(app, deps, "removeWorktree", "Worktrees", (project2, { params }) => {
69177
+ projectRoute(app, deps, "removeWorktree", "Worktrees", (project2, { params, query: query2 }) => {
69131
69178
  const name = worktreeName(params.name);
69132
- return name instanceof Response ? name : apiDeleteWorktree(project2, name);
69179
+ return name instanceof Response ? name : apiDeleteWorktree(project2, name, query2.force === true);
69133
69180
  });
69134
69181
  projectRoute(app, deps, "openWorktree", "Worktrees", (project2, { params, body }) => {
69135
69182
  const name = worktreeName(params.name);
@@ -89819,7 +89866,7 @@ function createDaemonTaskflowHost(context) {
89819
89866
  port: hostListen(env).port,
89820
89867
  workflowBuiltinsDir: taskflowAssets(env).workflowBuiltinsDir,
89821
89868
  version: env.PORTTA_VERSION || "0.0.0-local",
89822
- buildDate: true ? "2026-09-17T17:01:02Z" : (/* @__PURE__ */ new Date()).toISOString(),
89869
+ buildDate: true ? "2026-09-17T23:23:40Z" : (/* @__PURE__ */ new Date()).toISOString(),
89823
89870
  environmentStore: createEnvironmentStore(paths3.database),
89824
89871
  hostEnvironmentProvider: new HostEnvironmentProvider(),
89825
89872
  devContainerProvider: new DevContainerProvider(),
@@ -111967,11 +112014,12 @@ function worktreeRequestFromCli(action) {
111967
112014
  branch: requireWorktreeName(first),
111968
112015
  ...options.interface !== void 0 ? { interfaceMode: parseInterfaceMode(options.interface) } : {}
111969
112016
  };
112017
+ case "remove":
112018
+ return { command, branch: requireWorktreeName(first), force: options.force === true };
111970
112019
  case "close":
111971
112020
  case "refresh":
111972
112021
  case "archive":
111973
112022
  case "unarchive":
111974
- case "remove":
111975
112023
  case "merge":
111976
112024
  return { command, branch: requireWorktreeName(first) };
111977
112025
  case "label":
@@ -112225,6 +112273,9 @@ ${parsed.input.prompt}` : seed.data.conversationMarkdown;
112225
112273
  return 0;
112226
112274
  }
112227
112275
  const result = await runtime3.lifecycleService.pruneWorktrees();
112276
+ for (const kept of result.keptBranches) {
112277
+ stdout2(`Kept ${kept.branch}: ${kept.reason}`);
112278
+ }
112228
112279
  if (result.removedBranches.length === 0) {
112229
112280
  stdout2("No closed worktrees to prune.");
112230
112281
  return 0;
@@ -112461,7 +112512,9 @@ ${parsed.input.prompt}` : seed.data.conversationMarkdown;
112461
112512
  stdout2(`Restored worktree ${branch}`);
112462
112513
  return 0;
112463
112514
  case "remove":
112464
- await runtime2.lifecycleService.removeWorktree(branch);
112515
+ await runtime2.lifecycleService.removeWorktree(branch, {
112516
+ force: request2.command === "remove" && request2.force
112517
+ });
112465
112518
  stdout2(`Removed worktree ${branch}`);
112466
112519
  return 0;
112467
112520
  case "merge":
@@ -113374,7 +113427,6 @@ var cli_exports = {};
113374
113427
  __export(cli_exports, {
113375
113428
  UsageError: () => UsageError2,
113376
113429
  browserOpenCommand: () => browserOpenCommand,
113377
- installTaskflowWorkflowSkill: () => installTaskflowWorkflowSkill,
113378
113430
  isUserFacingError: () => isUserFacingError,
113379
113431
  main: () => main,
113380
113432
  openBrowser: () => openBrowser,
@@ -113389,11 +113441,9 @@ import {
113389
113441
  readFileSync as readFileSync28,
113390
113442
  realpathSync as realpathSync6,
113391
113443
  rmSync as rmSync9,
113392
- statSync as statSync10,
113393
- writeFileSync as writeFileSync14
113444
+ statSync as statSync10
113394
113445
  } from "node:fs";
113395
113446
  import { get as httpGet } from "node:http";
113396
- import { homedir as homedir9 } from "node:os";
113397
113447
  import { dirname as dirname28, join as join50, resolve as resolve30, sep as sep3 } from "node:path";
113398
113448
  import { fileURLToPath as fileURLToPath7 } from "node:url";
113399
113449
  function parseArgs(argv) {
@@ -113499,7 +113549,7 @@ async function main(argv = process.argv.slice(2), options = {}) {
113499
113549
  case "doctor":
113500
113550
  return cmdDoctor();
113501
113551
  case "install-skill":
113502
- return cmdInstallSkill(flags, options.skillPath);
113552
+ return cmdInstallSkillRetired();
113503
113553
  case "guide":
113504
113554
  return cmdGuide(options.skillPath);
113505
113555
  case void 0:
@@ -113880,37 +113930,16 @@ function readSkill(skillPath) {
113880
113930
  async function cmdGuide(skillPath) {
113881
113931
  process.stdout.write(readSkill(skillPath).replace(/^---\n[\s\S]*?\n---\n+/, ""));
113882
113932
  }
113883
- function installTaskflowWorkflowSkill(home2, body, flags = {}) {
113884
- const wantClaude = flags.claude === true;
113885
- const wantGeneric = flags.agents === true || flags.codex === true;
113886
- const both = !wantClaude && !wantGeneric;
113887
- const targets = [];
113888
- if (both || wantClaude) targets.push(join50(home2, ".claude", "skills"));
113889
- if (both || wantGeneric) targets.push(join50(home2, ".agents", "skills"));
113890
- return targets.map((base2) => {
113891
- const dest = join50(base2, `${APP_SLUG}-workflows`);
113892
- mkdirSync17(dest, { recursive: true });
113893
- const path7 = join50(dest, "SKILL.md");
113894
- writeFileSync14(path7, body);
113895
- return path7;
113896
- });
113897
- }
113898
- async function cmdInstallSkill(flags, skillPath) {
113899
- let body;
113900
- try {
113901
- body = readSkill(skillPath);
113902
- } catch (err2) {
113903
- console.error(err2 instanceof Error ? err2.message : String(err2));
113904
- process.exitCode = 1;
113905
- return;
113906
- }
113907
- installTaskflowWorkflowSkill(homedir9(), body, {
113908
- claude: flags.claude,
113909
- agents: flags.agents,
113910
- codex: flags.codex
113911
- }).forEach((path7) => {
113912
- console.log(`installed skill \u2192 ${path7}`);
113913
- });
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;
113914
113943
  }
113915
113944
  function printHelp() {
113916
113945
  console.log(`${APP_NAME} workflows \u2014 run JS workflow files that orchestrate coding agents
@@ -113940,7 +113969,6 @@ Usage:
113940
113969
  ${CLI_NAME} workflows validate <file.workflow.js | name>
113941
113970
  ${CLI_NAME} workflows doctor
113942
113971
  ${CLI_NAME} workflows guide
113943
- ${CLI_NAME} workflows install-skill [--claude] [--agents|--codex] Install the ${APP_NAME} authoring skill
113944
113972
 
113945
113973
  Named workflows resolve by meta.name across three tiers (highest first): project
113946
113974
  (${PROJECT_CONFIG_DIR}/${PATH_NAMES.workflows}/), user (~/${GLOBAL_CONFIG_DIR}/${PATH_NAMES.workflows}/), and package built-ins.
@@ -113949,9 +113977,10 @@ Named workflows resolve by meta.name across three tiers (highest first): project
113949
113977
  ${CLI_NAME} workflows run deep-research --args '"<question>"'
113950
113978
  ${CLI_NAME} workflows run code-review [--args '{"target": "<ref|path>", "level": "high|xhigh|max"}']
113951
113979
 
113952
- Run journals are stored in ~/${GLOBAL_CONFIG_DIR}/${PATH_NAMES.runs}/<id>/. The guide, install-skill command,
113953
- and skills/portta-workflows/SKILL.md share one source of truth \u2014 run
113954
- \`${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\`.`);
113955
113984
  }
113956
113985
  function isUserFacingError(err2) {
113957
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) {
@@ -120194,7 +120223,7 @@ var WORKFLOW_ENGINE_ACTIONS = [
120194
120223
  ["save", "Save a workflow file into the registry"],
120195
120224
  ["doctor", "Check the standalone workflow engine"],
120196
120225
  ["guide", "Print the workflow authoring guide"],
120197
- ["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"]
120198
120227
  ];
120199
120228
  var USAGE_HINT = "(run with --help for usage)";
120200
120229
  function parsePort2(value3) {
@@ -120322,7 +120351,14 @@ running, resume with \`${invocation2} --resume <branch> --prompt <text>\`).`
120322
120351
  worktree is restarted with the new pane layout and commands; a closed
120323
120352
  one picks the new profile up on its next open.`
120324
120353
  );
120325
- 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
+ );
120326
120362
  leaf(flow, "merge <branch>", "Merge a worktree into the main branch and remove it");
120327
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");
120328
120364
  helpAfter(
@@ -122094,17 +122130,17 @@ async function dnsSetup(options, command) {
122094
122130
 
122095
122131
  // src/commands/host-service.ts
122096
122132
  init_config2();
122097
- 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";
122098
- 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";
122099
122135
  import { dirname as dirname29, join as join59 } from "node:path";
122100
122136
  init_context();
122101
122137
  init_errors3();
122102
122138
  var AUTO_PICKUP_ENV_VARS = ["LINEAR_API_KEY"];
122103
122139
  var RESERVED_ENV_KEYS = /* @__PURE__ */ new Set(["PATH", "PORTTA_ROOT"]);
122104
122140
  function logFile2() {
122105
- return join59(homedir10(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122141
+ return join59(homedir9(), "Library", "Logs", SERVICE_IDENTITY.logFile);
122106
122142
  }
122107
- function serviceFilePath(platform4, home2 = homedir10()) {
122143
+ function serviceFilePath(platform4, home2 = homedir9()) {
122108
122144
  return platform4 === "linux" ? join59(home2, ".config", "systemd", "user", `${SERVICE_IDENTITY.name}.service`) : join59(home2, "Library", "LaunchAgents", `${SERVICE_IDENTITY.launchdLabel}.plist`);
122109
122145
  }
122110
122146
  function escapePlistText(value3) {
@@ -122307,7 +122343,7 @@ ${notes.join("\n")}`);
122307
122343
  await confirm(`${installed ? "Reinstall" : "Install"} the ${SERVICE_IDENTITY.name} service?`, Boolean(options.yes));
122308
122344
  if (installed) await runAll(serviceCommands("uninstall", platform4, filePath), output2, true);
122309
122345
  mkdirSync19(dirname29(filePath), { recursive: true });
122310
- writeFileSync15(filePath, content);
122346
+ writeFileSync14(filePath, content);
122311
122347
  if (Object.keys(envVars).length > 0) chmodSync10(filePath, 384);
122312
122348
  await runAll(serviceCommands("install", platform4, filePath), output2);
122313
122349
  if (output2.json) output2.data({ installed: true, file: filePath });
@@ -122607,7 +122643,7 @@ function configPrepare(command) {
122607
122643
  init_src();
122608
122644
  init_context();
122609
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";
122610
- import { homedir as homedir11 } from "node:os";
122646
+ import { homedir as homedir10 } from "node:os";
122611
122647
  import { dirname as dirname30, join as join61, resolve as resolve31 } from "node:path";
122612
122648
  import { fileURLToPath as fileURLToPath8 } from "node:url";
122613
122649
  init_errors3();
@@ -122664,7 +122700,7 @@ async function setupCommand(options, command) {
122664
122700
  const output2 = new Output(global3);
122665
122701
  if (process.platform === "win32") throw new PreconditionError("setup requires a POSIX host");
122666
122702
  const currentRoot = findGatewayRoot();
122667
- const target = resolve31(options.dir ?? currentRoot ?? join61(homedir11(), "portta"));
122703
+ const target = resolve31(options.dir ?? currentRoot ?? join61(homedir10(), "portta"));
122668
122704
  const profile = options.profile ?? global3.profile ?? "local";
122669
122705
  const runtime2 = packagedRuntime();
122670
122706
  const steps = [];
@@ -123182,7 +123218,7 @@ async function shareGc(command) {
123182
123218
  // src/commands/tls.ts
123183
123219
  init_src();
123184
123220
  init_context();
123185
- 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";
123186
123222
  import { platform as platform3 } from "node:os";
123187
123223
  import { join as join64 } from "node:path";
123188
123224
  init_errors3();
@@ -123333,7 +123369,7 @@ async function tlsInit(command) {
123333
123369
  }
123334
123370
  }
123335
123371
  output2.progress(`issued ${paths3.leafCertificate} for *.${domain2}`);
123336
- writeFileSync16(paths3.dynamic, localTlsDynamic());
123372
+ writeFileSync15(paths3.dynamic, localTlsDynamic());
123337
123373
  const envPath = join64(context.root, ".env");
123338
123374
  patchEnvFile(envPath, { TLS_ENABLED: "true", TLS_MODE: "local" });
123339
123375
  output2.progress("TLS enabled in .env");
@@ -123390,7 +123426,7 @@ function paths2(root2) {
123390
123426
  init_src();
123391
123427
  init_context();
123392
123428
  init_errors3();
123393
- 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";
123394
123430
  import { hostname as hostname3, tmpdir as tmpdir5 } from "node:os";
123395
123431
  import { dirname as dirname32, join as join65 } from "node:path";
123396
123432
  function globals16(command) {
@@ -123437,7 +123473,7 @@ async function backupCommand(options, command) {
123437
123473
  const staging = mkdtempSync3(join65(tmpdir5(), "portta-backup-"));
123438
123474
  chmodSync14(staging, 448);
123439
123475
  try {
123440
- writeFileSync17(join65(staging, "portta-backup.json"), renderManifest({
123476
+ writeFileSync16(join65(staging, "portta-backup.json"), renderManifest({
123441
123477
  version: BACKUP_VERSION,
123442
123478
  portta: context.version,
123443
123479
  created: (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d+Z$/, "Z"),
@@ -128614,7 +128650,7 @@ async function buildCommand(command) {
128614
128650
 
128615
128651
  // src/commands/remote.ts
128616
128652
  init_src();
128617
- 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";
128618
128654
  import { basename as basename20, join as join67 } from "node:path";
128619
128655
  import { createServer as createServer3 } from "node:net";
128620
128656
  import { randomBytes as randomBytes10 } from "node:crypto";
@@ -128894,7 +128930,7 @@ async function remoteAccessOpen(target, options, command) {
128894
128930
  throw new PreconditionError("the SSH tunnel exited immediately", `check that ${target} is reachable and that ${localPort} is free locally`);
128895
128931
  }
128896
128932
  const record6 = { id, pid, target, project: options.project, service: options.service, remotePort, localPort, started: Math.floor(Date.now() / 1e3) };
128897
- writeFileSync18(join67(directoryPath, `${id}.json`), renderTunnelRecord(record6));
128933
+ writeFileSync17(join67(directoryPath, `${id}.json`), renderTunnelRecord(record6));
128898
128934
  if (output2.json) {
128899
128935
  output2.data({ ...record6, address: `127.0.0.1:${localPort}` });
128900
128936
  return;
@@ -128959,7 +128995,7 @@ init_src();
128959
128995
  init_src();
128960
128996
  init_context();
128961
128997
  init_errors3();
128962
- 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";
128963
128999
  import { ReadStream } from "node:tty";
128964
129000
  import { join as join68 } from "node:path";
128965
129001
  function globals20(command) {
@@ -129119,11 +129155,11 @@ async function tunnelSetup(options, command) {
129119
129155
  "copy the whole eyJ... string from the Cloudflare dashboard, not the install command around it"
129120
129156
  );
129121
129157
  }
129122
- writeFileSync19(paths3.credentials, renderTunnelCredentials(credentials), { mode: 384 });
129158
+ writeFileSync18(paths3.credentials, renderTunnelCredentials(credentials), { mode: 384 });
129123
129159
  chmodSync15(paths3.credentials, 384);
129124
129160
  const origin = options.origin || defaultOrigin(context);
129125
129161
  const config3 = { id: credentials.TunnelID, zone: options.zone, origin, credentialsFile: "/etc/cloudflared/credentials.json", includeApex: options.apex ?? false };
129126
- writeFileSync19(paths3.config, renderTunnelConfig(config3));
129162
+ writeFileSync18(paths3.config, renderTunnelConfig(config3));
129127
129163
  const envPath = join68(context.root, ".env");
129128
129164
  patchEnvFile(envPath, { CLOUDFLARE_TUNNEL_ZONE: options.zone, CLOUDFLARE_TUNNEL_ID: credentials.TunnelID });
129129
129165
  if (output2.json) {