@codions/portta 0.0.0-develop.171.sha-d749180 → 0.0.0-develop.172.sha-10ce987

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/assets/skills/portta-workflows/SKILL.md +1 -1
  2. package/dist/assets/workflows/bake-off.workflow.js +6 -5
  3. package/dist/assets/workflows/code-review.workflow.js +4 -4
  4. package/dist/assets/workflows/deep-research.workflow.js +4 -3
  5. package/dist/assets/workflows/multi-provider-review.workflow.js +5 -4
  6. package/dist/assets/workflows/provider-debate.workflow.js +7 -6
  7. package/dist/assets/workflows/second-opinion.workflow.js +4 -3
  8. package/dist/cli.js +794 -847
  9. package/dist/documentation.json +1 -1
  10. package/dist/host.js +53 -93
  11. package/dist/runtime/.env.example +8 -17
  12. package/dist/runtime/VERSION +1 -1
  13. package/dist/runtime/docker/compose/features/panel-host.yaml +4 -5
  14. package/dist/runtime/templates/README.md +9 -6
  15. package/dist/runtime/templates/overlays/07-worktree.env +1 -1
  16. package/dist/runtime/templates/project/PORTTA.md +3 -3
  17. package/dist/supervisor.js +0 -1
  18. package/package.json +2 -5
  19. package/dist/runtime/config/traefik/dynamic/auth.example.yaml.disabled +0 -24
  20. package/dist/runtime/docker/images/README.md +0 -12
  21. package/dist/runtime/docker/images/sandbox/Dockerfile +0 -79
  22. package/dist/runtime/docker/images/sandbox/README.md +0 -109
  23. package/dist/runtime/docker/images/sandbox/VERSION +0 -1
  24. package/dist/runtime/docker/images/sandbox/agents/claude-code.sh +0 -18
  25. package/dist/runtime/docker/images/sandbox/agents/codex.sh +0 -4
  26. package/dist/runtime/docker/images/sandbox/agents/opencode.sh +0 -4
  27. package/dist/runtime/docker/images/sandbox/agents/pi.sh +0 -4
  28. package/dist/runtime/docker/images/sandbox/scripts/entrypoint.sh +0 -8
  29. package/dist/runtime/docker/images/sandbox/scripts/generate-manifest.mjs +0 -81
  30. package/dist/runtime/docker/images/sandbox/scripts/install-tools.sh +0 -46
  31. package/dist/runtime/docker/images/sandbox/scripts/verify-image.sh +0 -18
package/dist/host.js CHANGED
@@ -40819,7 +40819,6 @@ var RUNTIME_IDENTITY = {
40819
40819
  tmuxBufferPrefix: `${APP_SLUG}-prompt`,
40820
40820
  dockerContainerPrefix: APP_SLUG,
40821
40821
  tempUploadDir: `${APP_SLUG}-uploads`,
40822
- dockerImage: "portta-sandbox",
40823
40822
  gitBaseConfigKey: `${APP_SLUG}.base`
40824
40823
  };
40825
40824
  var LINEAR_IDENTITY = {
@@ -40929,41 +40928,11 @@ import { readFileSync as readFileSync2 } from "node:fs";
40929
40928
  import { mkdir, writeFile } from "node:fs/promises";
40930
40929
  import { dirname as dirname2, resolve } from "node:path";
40931
40930
  var import_yaml = __toESM(require_dist(), 1);
40932
-
40933
- // ../host/src/modules/taskflow/lib/log.ts
40934
- var DEBUG = process.env[ENV_NAMES.debug] === "1";
40935
- function ts() {
40936
- return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
40937
- }
40938
- function redactSecrets(text) {
40939
- return text.replace(/Bearer\s+\S+/gi, "Bearer [REDACTED]").replace(new RegExp(`(${ENV_NAMES.controlToken}=)\\S+`, "gi"), "$1[REDACTED]");
40940
- }
40941
- function safe(msg) {
40942
- return redactSecrets(msg);
40943
- }
40944
- var log = {
40945
- info(msg) {
40946
- console.log(`[${ts()}] ${safe(msg)}`);
40947
- },
40948
- debug(msg) {
40949
- if (DEBUG) console.log(`[${ts()}] ${safe(msg)}`);
40950
- },
40951
- warn(msg) {
40952
- console.warn(`[${ts()}] ${safe(msg)}`);
40953
- },
40954
- error(msg, err2) {
40955
- const redacted = safe(msg);
40956
- err2 !== void 0 ? console.error(`[${ts()}] ${redacted}`, err2) : console.error(`[${ts()}] ${redacted}`);
40957
- }
40958
- };
40959
-
40960
- // ../host/src/modules/taskflow/adapters/config.ts
40961
40931
  function parseWorktreeRoot(raw2, fallback) {
40962
40932
  if (!isRecord(raw2)) return fallback;
40963
40933
  if (isRecord(raw2.worktrees) && typeof raw2.worktrees.root === "string" && raw2.worktrees.root.trim()) {
40964
40934
  return raw2.worktrees.root.trim();
40965
40935
  }
40966
- if (typeof raw2.worktreeRoot === "string" && raw2.worktreeRoot.trim()) return raw2.worktreeRoot.trim();
40967
40936
  return fallback;
40968
40937
  }
40969
40938
  function parseExposure(raw2) {
@@ -41108,18 +41077,15 @@ function parseProfile(raw2, fallbackRuntime) {
41108
41077
  ...typeof raw2.environment.cwd === "string" && raw2.environment.cwd.trim() ? { cwd: raw2.environment.cwd.trim() } : {},
41109
41078
  ...typeof raw2.environment.stopCommand === "string" && raw2.environment.stopCommand.trim() ? { stopCommand: raw2.environment.stopCommand.trim() } : {}
41110
41079
  } : void 0;
41111
- const legacyRuntimePane = environment && (environment.provider === "host" || environment.provider === "auto") && !environment.command ? panes.find((pane) => pane.id === "app" && pane.kind === "command" && Boolean(pane.command)) : void 0;
41112
- const effectiveEnvironment = legacyRuntimePane ? { ...environment, command: legacyRuntimePane.command } : environment;
41113
- const effectivePanes = legacyRuntimePane ? panes.filter((pane) => pane !== legacyRuntimePane) : panes;
41114
41080
  return {
41115
41081
  runtime,
41116
41082
  envPassthrough,
41117
41083
  ...raw2.yolo === true ? { yolo: true } : {},
41118
- panes: effectivePanes,
41084
+ panes,
41119
41085
  ...typeof raw2.systemPrompt === "string" && raw2.systemPrompt.length > 0 ? { systemPrompt: raw2.systemPrompt } : {},
41120
41086
  ...image ? { image } : {},
41121
41087
  ...mounts ? { mounts } : {},
41122
- ...effectiveEnvironment && Object.keys(effectiveEnvironment).length > 0 ? { environment: effectiveEnvironment } : {}
41088
+ ...environment && Object.keys(environment).length > 0 ? { environment } : {}
41123
41089
  };
41124
41090
  }
41125
41091
  function parseProfiles(raw2, includeDefaultProfile) {
@@ -41278,17 +41244,10 @@ function parseTeamKeyList(raw2) {
41278
41244
  const keys = raw2.filter((entry) => typeof entry === "string").map((entry) => entry.trim().toUpperCase()).filter((entry) => entry.length > 0);
41279
41245
  return keys.length > 0 ? Array.from(new Set(keys)) : void 0;
41280
41246
  }
41281
- var warnedLegacyLinearTeamId = false;
41282
41247
  function parseLinearIntegration(parsed) {
41283
41248
  const defaults = DEFAULT_CONFIG.integrations.linear;
41284
41249
  const linear = isRecord(parsed.integrations) && isRecord(parsed.integrations.linear) ? parsed.integrations.linear : null;
41285
41250
  if (!linear) return { ...defaults };
41286
- if (typeof linear.teamId === "string" && !warnedLegacyLinearTeamId) {
41287
- warnedLegacyLinearTeamId = true;
41288
- log.warn(
41289
- "[config] integrations.linear.teamId is no longer used \u2014 the ticket team is now picked at creation time in the dashboard"
41290
- );
41291
- }
41292
41251
  const watchTeams = parseTeamKeyList(linear.watchTeams);
41293
41252
  return {
41294
41253
  enabled: typeof linear.enabled === "boolean" ? linear.enabled : defaults.enabled,
@@ -48005,6 +47964,35 @@ exec ${JSON.stringify(executable)} "$@"
48005
47964
  // ../host/src/modules/taskflow/adapters/projects-registry.ts
48006
47965
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync4, renameSync, writeFileSync as writeFileSync2 } from "node:fs";
48007
47966
  import { dirname as dirname6 } from "node:path";
47967
+
47968
+ // ../host/src/modules/taskflow/lib/log.ts
47969
+ var DEBUG = process.env[ENV_NAMES.debug] === "1";
47970
+ function ts() {
47971
+ return (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
47972
+ }
47973
+ function redactSecrets(text) {
47974
+ return text.replace(/Bearer\s+\S+/gi, "Bearer [REDACTED]").replace(new RegExp(`(${ENV_NAMES.controlToken}=)\\S+`, "gi"), "$1[REDACTED]");
47975
+ }
47976
+ function safe(msg) {
47977
+ return redactSecrets(msg);
47978
+ }
47979
+ var log = {
47980
+ info(msg) {
47981
+ console.log(`[${ts()}] ${safe(msg)}`);
47982
+ },
47983
+ debug(msg) {
47984
+ if (DEBUG) console.log(`[${ts()}] ${safe(msg)}`);
47985
+ },
47986
+ warn(msg) {
47987
+ console.warn(`[${ts()}] ${safe(msg)}`);
47988
+ },
47989
+ error(msg, err2) {
47990
+ const redacted = safe(msg);
47991
+ err2 !== void 0 ? console.error(`[${ts()}] ${redacted}`, err2) : console.error(`[${ts()}] ${redacted}`);
47992
+ }
47993
+ };
47994
+
47995
+ // ../host/src/modules/taskflow/adapters/projects-registry.ts
48008
47996
  function defaultRegistryFile() {
48009
47997
  return globalPaths().projectsRegistry;
48010
47998
  }
@@ -50900,25 +50888,21 @@ function isRecord5(raw2) {
50900
50888
  function normalizeConversationMeta(raw2) {
50901
50889
  if (!raw2) return raw2;
50902
50890
  if (raw2.provider === "codexAppServer") {
50903
- const conversationId2 = raw2.conversationId || raw2.threadId;
50904
- const threadId = raw2.threadId || raw2.conversationId;
50905
- if (!conversationId2 || !threadId) return void 0;
50891
+ if (!raw2.conversationId || !raw2.threadId) return void 0;
50906
50892
  const normalized2 = {
50907
50893
  provider: "codexAppServer",
50908
- conversationId: conversationId2,
50909
- threadId,
50894
+ conversationId: raw2.conversationId,
50895
+ threadId: raw2.threadId,
50910
50896
  cwd: raw2.cwd,
50911
50897
  lastSeenAt: raw2.lastSeenAt
50912
50898
  };
50913
50899
  return normalized2;
50914
50900
  }
50915
- const conversationId = raw2.conversationId || raw2.sessionId;
50916
- const sessionId = raw2.sessionId || raw2.conversationId;
50917
- if (!conversationId || !sessionId) return void 0;
50901
+ if (!raw2.conversationId || !raw2.sessionId) return void 0;
50918
50902
  const normalized = {
50919
50903
  provider: "claudeCode",
50920
- conversationId,
50921
- sessionId,
50904
+ conversationId: raw2.conversationId,
50905
+ sessionId: raw2.sessionId,
50922
50906
  cwd: raw2.cwd,
50923
50907
  lastSeenAt: raw2.lastSeenAt
50924
50908
  };
@@ -53336,10 +53320,7 @@ ${oneshotPrompt}` : oneshotPrompt ?? baseSystemPrompt;
53336
53320
  return panes.length > 0 ? panes : [{ id: "runtime", kind: "runtime", cwd: "worktree" }];
53337
53321
  }
53338
53322
  if (panes.some((pane) => pane.kind === "runtime")) return panes;
53339
- const legacyShell = panes.findIndex((pane) => pane.id === "shell" && pane.kind === "shell");
53340
- const runtimePane = { id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" };
53341
- if (legacyShell >= 0) panes.splice(legacyShell, 1, runtimePane);
53342
- else panes.push(runtimePane);
53323
+ panes.push({ id: "runtime", kind: "runtime", split: "right", sizePct: 30, cwd: "worktree" });
53343
53324
  return panes;
53344
53325
  }
53345
53326
  requireDockerProfile(profile) {
@@ -60041,10 +60022,15 @@ var migrations = [
60041
60022
  input_json TEXT NOT NULL,
60042
60023
  status TEXT NOT NULL CHECK(status IN ('queued', 'provisioning', 'running', 'waiting_input', 'completed', 'failed', 'cancelled', 'interrupted')),
60043
60024
  workspace_policy TEXT NOT NULL CHECK(workspace_policy IN ('none', 'run')),
60025
+ workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch')),
60026
+ workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write')),
60044
60027
  workflow_snapshot_id TEXT,
60045
60028
  workspace_id TEXT,
60046
60029
  worktree_path TEXT,
60047
60030
  canonical_workspace_path TEXT,
60031
+ checkout_canonical_path TEXT,
60032
+ checkout_branch TEXT,
60033
+ environment_id TEXT,
60048
60034
  branch TEXT,
60049
60035
  base_branch TEXT,
60050
60036
  base_commit TEXT,
@@ -60072,6 +60058,7 @@ var migrations = [
60072
60058
  path TEXT NOT NULL,
60073
60059
  content_hash TEXT NOT NULL,
60074
60060
  engine_version TEXT NOT NULL,
60061
+ key_version TEXT NOT NULL DEFAULT 'v1',
60075
60062
  source TEXT NOT NULL,
60076
60063
  metadata_json TEXT NOT NULL,
60077
60064
  created_at TEXT NOT NULL
@@ -60096,6 +60083,7 @@ var migrations = [
60096
60083
  error TEXT,
60097
60084
  session_id TEXT,
60098
60085
  capabilities_json TEXT,
60086
+ checkpoint_json TEXT,
60099
60087
  started_at TEXT,
60100
60088
  completed_at TEXT,
60101
60089
  UNIQUE(run_id, node_key, attempt)
@@ -60107,10 +60095,7 @@ var migrations = [
60107
60095
  source TEXT NOT NULL,
60108
60096
  updated_at TEXT NOT NULL
60109
60097
  );
60110
- `,
60111
- "ALTER TABLE executions ADD COLUMN checkpoint_json TEXT;",
60112
- "ALTER TABLE workflow_snapshots ADD COLUMN key_version TEXT NOT NULL DEFAULT 'v1';",
60113
- `
60098
+
60114
60099
  CREATE TABLE IF NOT EXISTS run_events (
60115
60100
  id TEXT PRIMARY KEY,
60116
60101
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -60123,8 +60108,7 @@ var migrations = [
60123
60108
  payload_json TEXT NOT NULL,
60124
60109
  UNIQUE(run_id, sequence)
60125
60110
  );
60126
- `,
60127
- `
60111
+
60128
60112
  CREATE TABLE IF NOT EXISTS workspace_leases (
60129
60113
  id TEXT PRIMARY KEY,
60130
60114
  run_id TEXT NOT NULL REFERENCES runs(id),
@@ -60142,12 +60126,7 @@ var migrations = [
60142
60126
  updated_at TEXT NOT NULL,
60143
60127
  released_at TEXT
60144
60128
  );
60145
- `,
60146
- "ALTER TABLE runs ADD COLUMN workspace_strategy TEXT CHECK(workspace_strategy IN ('isolated_worktree', 'new_branch', 'current_branch'));",
60147
- "ALTER TABLE runs ADD COLUMN workspace_access TEXT CHECK(workspace_access IN ('shared_read', 'exclusive_write'));",
60148
- "ALTER TABLE runs ADD COLUMN checkout_canonical_path TEXT;",
60149
- "ALTER TABLE runs ADD COLUMN checkout_branch TEXT;",
60150
- `
60129
+
60151
60130
  CREATE TABLE IF NOT EXISTS checkout_claims (
60152
60131
  run_id TEXT PRIMARY KEY REFERENCES runs(id),
60153
60132
  project_id TEXT NOT NULL,
@@ -60156,8 +60135,7 @@ var migrations = [
60156
60135
  created_at TEXT NOT NULL
60157
60136
  );
60158
60137
  CREATE INDEX IF NOT EXISTS checkout_claims_path_idx ON checkout_claims(project_id, canonical_path);
60159
- `,
60160
- "ALTER TABLE runs ADD COLUMN environment_id TEXT;"
60138
+ `
60161
60139
  ];
60162
60140
  function defaultRunStorePath() {
60163
60141
  return globalPaths().database;
@@ -70927,7 +70905,7 @@ function createProjectApp(runtime, instancePrefix, host) {
70927
70905
  const reconciliationService = runtime.reconciliationService;
70928
70906
  const codexAppServerClient = new CodexAppServerClient({
70929
70907
  clientName: RUNTIME_IDENTITY.codexClientName,
70930
- clientVersion: "0.0.0"
70908
+ clientVersion: PORTTA_FLOW_VERSION
70931
70909
  });
70932
70910
  const claudeCliClient = new ClaudeCliClient();
70933
70911
  const worktreeConversationService = new WorktreeConversationService({
@@ -72364,8 +72342,8 @@ function createTaskflowHost(options) {
72364
72342
  manager,
72365
72343
  apps,
72366
72344
  allowlist: options.projectAllowlist,
72367
- // Tracks leftover on-add setup records for API compatibility. Registration
72368
- // no longer scaffolds or launches an agent; `taskflow init` remains the authoring path.
72345
+ // Backs the project-setup status listing. Registration itself does not
72346
+ // scaffold or launch an agent; `taskflow init` is the authoring path.
72369
72347
  initTracker: new ProjectInitTracker(),
72370
72348
  closeSockets: (prefix) => sockets.closeProject(prefix)
72371
72349
  });
@@ -72428,7 +72406,7 @@ function createDaemonTaskflowHost(context) {
72428
72406
  port: hostListen(env2).port,
72429
72407
  workflowBuiltinsDir: taskflowAssets(env2).workflowBuiltinsDir,
72430
72408
  version: env2.PORTTA_VERSION || "0.0.0-local",
72431
- buildDate: true ? "2026-09-18T00:56:55Z" : (/* @__PURE__ */ new Date()).toISOString(),
72409
+ buildDate: true ? "2026-09-18T02:24:34Z" : (/* @__PURE__ */ new Date()).toISOString(),
72432
72410
  environmentStore: createEnvironmentStore(paths.database),
72433
72411
  hostEnvironmentProvider: new HostEnvironmentProvider(),
72434
72412
  devContainerProvider: new DevContainerProvider(),
@@ -73666,24 +73644,6 @@ var upgradeWebSocket = defineWebSocketHelper(async (c, events, options) => {
73666
73644
  // ../core/src/diagnostics.ts
73667
73645
  var ENVIRONMENT_COLLECT_INTERVAL_MS = 5 * 60 * 1e3;
73668
73646
 
73669
- // ../core/src/endpoints.ts
73670
- var PROVIDERS = [
73671
- { id: "internal", scope: "internal", requires: null, optional: false },
73672
- { id: "local", scope: "local", requires: "localhost", optional: false },
73673
- { id: "lan", scope: "lan", requires: "lan", optional: true },
73674
- { id: "tailscale", scope: "private", requires: "tailscale", optional: true },
73675
- { id: "tailscale-serve", scope: "private", requires: "tailscale-https", optional: true },
73676
- { id: "public-ip", scope: "public", requires: "public-ipv4", optional: true },
73677
- { id: "auto-domain", scope: "public", requires: "auto-domain", optional: true },
73678
- { id: "custom-domain", scope: "public", requires: "custom-domain", optional: true },
73679
- { id: "cloudflare-tunnel", scope: "public", requires: "cloudflare-tunnel", optional: true },
73680
- { id: "bridge", scope: "local", requires: null, optional: true }
73681
- ];
73682
- var PROVIDERS_BY_ID = new Map(PROVIDERS.map((spec) => [spec.id, spec]));
73683
-
73684
- // ../core/src/host.ts
73685
- var MIB = 1024 * 1024;
73686
-
73687
73647
  // ../core/src/metrics.ts
73688
73648
  var HISTORY_RETENTION_SECONDS = 60 * 60;
73689
73649
  var DOCKER_SIZE_UNITS = {
@@ -1,4 +1,3 @@
1
- # Portta environment structure: 1
2
1
  # ============================================================================
3
2
  # Portta: configuration
4
3
  # ============================================================================
@@ -28,7 +27,7 @@ PORTTA_PROJECT_NAME=portta
28
27
  # Changing it changes the reference; files are not moved.
29
28
  # Default: ~/projects (user) or /srv/projects (root). Not PORTTA_HOME.
30
29
  PORTTA_PROJECTS_HOME=
31
- # PORTTA_PROJECTS_HOME=
30
+ # PORTTA_PROJECTS_HOME=/srv/projects
32
31
 
33
32
  # Shared external Docker network that consumer projects attach published
34
33
  # HTTP services to. Created by `bootstrap`, never removed automatically.
@@ -57,10 +56,6 @@ PORTTA_ACCESS_LOG=false
57
56
  # The remote-public profile raises this to `delete` on its own.
58
57
  PORTTA_ALIAS_HEADERS_STRATEGY=keep
59
58
 
60
- # ----------------------------------------------------------------------------
61
- # Local profile
62
- # ----------------------------------------------------------------------------
63
-
64
59
  # ----------------------------------------------------------------------------
65
60
  # Project domain: what every project hostname is built on
66
61
  # ----------------------------------------------------------------------------
@@ -185,7 +180,7 @@ PORTTA_PANEL_ADVERTISED_HOST=
185
180
  # access mode turns it on by itself.
186
181
  PORTTA_WEB_READ_ONLY=false
187
182
 
188
- # The panel's own front door, which is now the panel's own business.
183
+ # The panel's own front door.
189
184
  #
190
185
  # disabled every request is the local operator. Legal wherever the set of
191
186
  # people who can reach the panel is already an authenticated set:
@@ -264,19 +259,15 @@ PORTTA_WEB_DEV=false
264
259
 
265
260
  # Private, internal network carrying panel -> its own Docker socket proxy.
266
261
  PORTTA_WEB_NETWORK=portta-web
267
- # Host uid:gid, filled once by preparation so the containers can read/write state.
262
+ # The host uid:gid the panel and the authentication service run as. .env is
263
+ # owner-only, so the panel has to run as whoever owns it or the Settings page
264
+ # cannot save; the authentication service reads .env once and the owner-only
265
+ # protection store on every request. `setup`, `bootstrap` and `web up` record
266
+ # "$(id -u):$(id -g)" here when it is missing; the image's own `node` is only
267
+ # right when the host uid happens to be 1000.
268
268
  PORTTA_WEB_USER=
269
269
  PORTTA_AUTH_USER=
270
-
271
- # User the panel container runs as. .env is owner-only, so the panel has to run
272
- # as whoever owns it or the Settings page cannot save. `bootstrap`, `web up` and
273
- # the installer record "$(id -u):$(id -g)" here when it is missing; the image's
274
- # own `node` is only right when the host uid happens to be 1000.
275
270
  # PORTTA_WEB_USER=1000:1000
276
-
277
- # The user the authentication service runs as. Same reason as above: it reads
278
- # .env once and the owner-only protection store on every request, and both
279
- # belong to whoever installed Portta. The installer records the right value.
280
271
  # PORTTA_AUTH_USER=1000:1000
281
272
 
282
273
  # ----------------------------------------------------------------------------
@@ -1 +1 @@
1
- 0.0.0-develop.171.sha-d749180
1
+ 0.0.0-develop.172.sha-10ce987
@@ -9,11 +9,10 @@
9
9
  # WebSocket through its authorised proxy
10
10
  # (docs/development/adr/0047-host-daemon-and-panel-proxy.md).
11
11
  #
12
- # This used to ride with Task Flow, because Task Flow was the only thing that
13
- # needed the host. Issues need it too, and Issues are the panel's work surface
14
- # now (docs/development/adr/0018-github-issues-through-the-gh-cli.md) — so the
15
- # connection is part of having a panel, and Task Flow is left as the switch for
16
- # its own routes.
12
+ # Issues are the panel's work surface and are read through the daemon
13
+ # (docs/development/adr/0018-github-issues-through-the-gh-cli.md), so the
14
+ # connection is part of having a panel. PORTTA_TASKFLOW only switches Task
15
+ # Flow's own routes on; it does not decide whether this overlay applies.
17
16
  #
18
17
  # What this adds to the panel, and nothing else
19
18
  # ----------------------------------------------
@@ -1,11 +1,14 @@
1
1
  # Templates
2
2
 
3
- Reference overlays for the shapes a project usually has. They are **references
4
- to copy from**, not runtime that projects depend on: nothing here is included,
5
- mounted or extended by a consumer project. Copy the closest one, adjust the
6
- service names and ports, and it is yours.
7
-
8
- `portta env init <path>` generates the same thing from a project's actual
3
+ Reference overlays for the shapes a project usually has, for **manual mode**:
4
+ a project that owns its own `compose.portta.yaml` instead of the overlay
5
+ `portta adopt` generates (see
6
+ [Add an existing project](../docs/product/guides/adopting-projects.md#manual-mode)).
7
+ They are **references to copy from**, not runtime that projects depend on:
8
+ nothing here is included, mounted or extended by a consumer project. Copy the
9
+ closest one, adjust the service names and ports, and it is yours.
10
+
11
+ `portta envs init <path>` generates the same thing from a project's actual
9
12
  Compose file, which is usually faster.
10
13
 
11
14
  | Template | Shape |
@@ -15,7 +15,7 @@
15
15
  # The original environment keeps running. Nothing inside the project changed.
16
16
  # Derive the name instead of inventing one:
17
17
  #
18
- # portta env namespace
18
+ # portta envs namespace
19
19
  # ============================================================================
20
20
 
21
21
  COMPOSE_PROJECT_NAME=base-empresarial-issue59
@@ -1,8 +1,8 @@
1
1
  # Running this project on Portta
2
2
 
3
3
  > Copy this file into the project and adjust the names. It covers only what
4
- > someone working on *this* project needs. The rules themselves live in the Dev
5
- > Gateway repository, which stays the single source of truth.
4
+ > someone working on *this* project needs. The rules themselves live in the
5
+ > Portta repository, which stays the single source of truth.
6
6
 
7
7
  ## Prerequisites
8
8
 
@@ -71,7 +71,7 @@ Credentials are this project's, from its own `.env`.
71
71
  ## Working on two branches at once
72
72
 
73
73
  ```bash
74
- git worktree add ../<project>-issue59 issue59
74
+ git worktree add --relative-paths ../<project>-issue59 issue59
75
75
  cd ../<project>-issue59
76
76
  echo "COMPOSE_PROJECT_NAME=<project>-issue59" >> .env
77
77
  docker compose -f compose.yaml -f compose.portta.yaml up -d
@@ -79,7 +79,6 @@ var RUNTIME_IDENTITY = {
79
79
  tmuxBufferPrefix: `${APP_SLUG}-prompt`,
80
80
  dockerContainerPrefix: APP_SLUG,
81
81
  tempUploadDir: `${APP_SLUG}-uploads`,
82
- dockerImage: "portta-sandbox",
83
82
  gitBaseConfigKey: `${APP_SLUG}.base`
84
83
  };
85
84
  var LINEAR_IDENTITY = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codions/portta",
3
- "version": "0.0.0-develop.171.sha-d749180",
3
+ "version": "0.0.0-develop.172.sha-10ce987",
4
4
  "description": "Machine-first CLI for a shared Docker development gateway",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,10 +19,7 @@
19
19
  "typecheck": "tsc -p tsconfig.json --noEmit",
20
20
  "test": "vitest run",
21
21
  "prepack": "npm run build",
22
- "prepublishOnly": "npm run typecheck && npm test",
23
- "preversion": "node scripts/git-version.mjs check",
24
- "version": "node scripts/git-version.mjs sync",
25
- "postversion": "node scripts/git-version.mjs verify"
22
+ "prepublishOnly": "npm run typecheck && npm test"
26
23
  },
27
24
  "engines": {
28
25
  "node": ">=24"
@@ -1,24 +0,0 @@
1
- # ============================================================================
2
- # Portta project protection: the working middleware is generated for you
3
- # ============================================================================
4
- # Do not copy this file into the dynamic directory. `portta-auth.yaml` already
5
- # defines `portta-forward-auth`; this disabled example documents the project
6
- # label that opts one existing router into it.
7
- #
8
- # 1. Create or rotate the host credential:
9
- #
10
- # portta auth protect demo-web.example.com --project demo --service web
11
- #
12
- # 2. Add the middleware to that project's own router:
13
- #
14
- # labels:
15
- # - "traefik.http.routers.demo-web.middlewares=portta-forward-auth@file"
16
- #
17
- # Portta deliberately does not edit a consumer project's labels. The project
18
- # owns that router; Portta owns only the credential, login route and ForwardAuth
19
- # middleware. `/__portta/auth` is reserved on every protected hostname.
20
- #
21
- # To remove the credential (the project label remains yours to remove):
22
- #
23
- # portta auth unprotect demo-web.example.com
24
- # ============================================================================
@@ -1,12 +0,0 @@
1
- # Operational images
2
-
3
- These directories are self-contained build contexts for images used by the
4
- Portta runtime rather than by a Compose service directly:
5
-
6
- - `apply/` builds the opt-in applier that recreates the gateway after settings
7
- change.
8
- - `toolbox/` builds the pinned diagnostic and database-client toolbox.
9
-
10
- Application images stay with their applications. In particular,
11
- `apps/web/Dockerfile` remains under `apps/web` because it builds the web and
12
- authentication workspaces from the repository-root context.
@@ -1,79 +0,0 @@
1
- # syntax=docker/dockerfile:1.7
2
-
3
- FROM node:24-bookworm-slim
4
-
5
- ENV AWS_DEFAULT_REGION=auto \
6
- DEBIAN_FRONTEND=noninteractive \
7
- DISABLE_UPDATES=1 \
8
- NPM_CONFIG_PREFIX=/usr/local \
9
- PATH="/root/.local/bin:/usr/local/bin:/root/.bun/bin:/root/.cargo/bin:${PATH}" \
10
- PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
11
- PORTTA_FLOW_SANDBOX_MANIFEST=/etc/taskflow-sandbox/manifest.json
12
-
13
- RUN apt-get update \
14
- && apt-get install -y --no-install-recommends \
15
- build-essential \
16
- ca-certificates \
17
- curl \
18
- git \
19
- gnupg \
20
- groff \
21
- jq \
22
- less \
23
- openssh-client \
24
- ripgrep \
25
- sudo \
26
- unzip \
27
- && rm -rf /var/lib/apt/lists/*
28
-
29
- ARG TARGETARCH
30
- ARG ASCIINEMA_VERSION=3.2.1
31
- ARG ASCIINEMA_SHA256_AMD64=1b405bbda565b33c3c4718de67fedc3535580603c0694b1ff3fb04f363430a20
32
- ARG ASCIINEMA_SHA256_ARM64=b516a6d896844c0ffbc96e0a55afe4cbcc79216abde0fc64fdda4e39bee421ea
33
-
34
- RUN case "${TARGETARCH}" in \
35
- amd64) target=x86_64; sha256="${ASCIINEMA_SHA256_AMD64}" ;; \
36
- arm64) target=aarch64; sha256="${ASCIINEMA_SHA256_ARM64}" ;; \
37
- *) echo "Unsupported asciinema architecture: ${TARGETARCH}" >&2; exit 1 ;; \
38
- esac \
39
- && curl -fsSL -o /usr/local/bin/asciinema \
40
- "https://github.com/asciinema/asciinema/releases/download/v${ASCIINEMA_VERSION}/asciinema-${target}-unknown-linux-gnu" \
41
- && echo "${sha256} /usr/local/bin/asciinema" | sha256sum -c - \
42
- && chmod 0755 /usr/local/bin/asciinema
43
-
44
- COPY --chmod=0755 agents/ /usr/local/lib/taskflow-sandbox/agents/
45
- COPY --chmod=0755 scripts/ /usr/local/lib/taskflow-sandbox/scripts/
46
-
47
- ARG BUILD_DATE=unknown
48
- ARG BUILD_ID=local
49
- ARG SANDBOX_VERSION=dev
50
- ARG TOOLS_REFRESH=local
51
- ARG VCS_REF=unknown
52
-
53
- # TOOLS_REFRESH deliberately invalidates only the high-cadence tool layer.
54
- RUN echo "Refreshing volatile tools: ${TOOLS_REFRESH}" \
55
- && TARGETARCH="${TARGETARCH}" /usr/local/lib/taskflow-sandbox/scripts/install-tools.sh \
56
- && install -d -m 0755 /etc/taskflow-sandbox \
57
- && SANDBOX_VERSION="${SANDBOX_VERSION}" \
58
- BUILD_DATE="${BUILD_DATE}" \
59
- BUILD_ID="${BUILD_ID}" \
60
- VCS_REF="${VCS_REF}" \
61
- node /usr/local/lib/taskflow-sandbox/scripts/generate-manifest.mjs "${PORTTA_FLOW_SANDBOX_MANIFEST}" \
62
- && /usr/local/lib/taskflow-sandbox/scripts/verify-image.sh
63
-
64
- # Task Flow runs containers with the host UID/GID. Keep HOME traversable and
65
- # writable while tools remain installed read-only under /usr/local.
66
- RUN usermod -l agent -d /root -s /bin/bash node \
67
- && echo "agent ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/agent \
68
- && chmod 0440 /etc/sudoers.d/agent \
69
- && chmod -R 0777 /root /ms-playwright \
70
- && ln -sf /usr/local/lib/taskflow-sandbox/scripts/entrypoint.sh /usr/local/bin/entrypoint.sh
71
-
72
- LABEL org.opencontainers.image.created="${BUILD_DATE}" \
73
- org.opencontainers.image.description="Universal Task Flow agent sandbox" \
74
- org.opencontainers.image.revision="${VCS_REF}" \
75
- org.opencontainers.image.source="https://github.com/codions-labs/task-flow" \
76
- org.opencontainers.image.title="Task Flow Sandbox" \
77
- org.opencontainers.image.version="${SANDBOX_VERSION}"
78
-
79
- CMD ["sleep", "infinity"]