Skip to content

Releases: systeminit/swamp

swamp 20260227.175155.0-sha.0e6e91c3

27 Feb 17:52
Immutable release. Only release title and notes can be modified.
0e6e91c

Choose a tag to compare

What's Changed

  • refactor: rename tags to labels in extension manifest (#521)

Summary

Renames the tags field to labels in the extension manifest, introduced
in #508. This is a follow-up rename before the field sees any adoption.

Test plan

  • All existing tests updated and passing
  • deno check passes
  • Skill docs updated

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.175155.0-sha.0e6e91c3/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.175155.0-sha.0e6e91c3/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.175155.0-sha.0e6e91c3/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.175155.0-sha.0e6e91c3/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.173856.0-sha.27f1a954

27 Feb 17:39
Immutable release. Only release title and notes can be modified.
27f1a95

Choose a tag to compare

What's Changed

  • feat: track extracted files in upstream_extensions.json (#520)

Summary

  • Persist the list of extracted files in upstream_extensions.json when an extension is pulled
  • Add optional files: string[] field to UpstreamExtensionEntry (backward compatible — existing JSON files without it parse fine)
  • Add 3 unit tests and 1 integration test

Why this is needed

When an extension is pulled, the list of extracted files is computed and displayed to the user but never persisted. This means there's no way to know which files belong to which extension after the fact.

This is a prerequisite for extension rm — without knowing which files an extension installed, a remove command would have to guess or require the user to manually specify files. By recording the file list at pull time, a future extension rm can cleanly remove exactly the files that were installed.

The extractedFiles array was already computed during pull; this change simply saves it alongside the existing version and pulledAt fields.

Example output

After pulling an extension, upstream_extensions.json now looks like:

{
  "@keeb/ssh": {
    "version": "2026.02.26.1",
    "pulledAt": "2026-02-27T17:32:41.000Z",
    "files": [
      "extensions/models/ssh/ssh.yaml",
      "extensions/models/ssh/ssh.ts"
    ]
  }
}

Test plan

  • deno check — type checking passes
  • deno lint — linting passes
  • deno fmt — formatting passes
  • deno run test — all 2294 tests pass
  • Unit tests verify files are persisted, existing entries preserved, and empty arrays handled
  • Integration test pulls @keeb/ssh from registry and asserts files array is present and non-empty

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173856.0-sha.27f1a954/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173856.0-sha.27f1a954/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173856.0-sha.27f1a954/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173856.0-sha.27f1a954/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.173715.0-sha.547868b4

27 Feb 17:38
Immutable release. Only release title and notes can be modified.
547868b

Choose a tag to compare

What's Changed

  • fix: coerceInputTypes handles flat InputsSchema without properties wrapper (#519)

Summary

  • coerceInputTypes() only checked schema.properties, skipping type coercion entirely for flat schemas (properties directly on the schema object without a properties wrapper). This caused --input key=value with numeric/boolean types to fail validation since strings were never coerced.
  • Applied the same schema.properties ?? schema fallback pattern already used by InputValidationService and other InputsSchema consumers.
  • Added test covering flat schema coercion for number and boolean types.

Test Plan

  • Added coerceInputTypes: flat schema without properties wrapper test
  • All 2294 existing tests pass
  • deno check, deno lint, deno fmt all clean

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173715.0-sha.547868b4/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173715.0-sha.547868b4/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173715.0-sha.547868b4/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.173715.0-sha.547868b4/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.171331.0-sha.4405553a

27 Feb 17:14
Immutable release. Only release title and notes can be modified.
4405553

Choose a tag to compare

What's Changed

  • feat: add optional platforms and tags fields to extension manifest (#508)

Summary

Platforms

Extensions can contain platform-specific code that won't work across
OS/architecture boundaries:

  • Deno.Command() calls to OS-specific binaries (e.g. xdg-open on Linux)
  • FFI via Deno.dlopen() with platform-specific library paths (e.g.
    /usr/lib/libfoo.dylib vs /usr/lib/libfoo.so)
  • npm packages that conditionally load native bindings

The bundled output is pure JavaScript, so the system can't automatically
detect these cases — but extension authors know when their code has
platform dependencies. Today there's no way to communicate that to
consumers pulling an extension.

This adds an optional platforms string array to the manifest so authors
can declare which platforms their extension supports. The field is a
non-enforced hint — surfaced during extension push (in the resolved
summary) and during extension pull (as a warning-level message after
the archive is downloaded and the manifest is parsed).

This is the right solution because:

  • The system cannot auto-detect platform-specific code inside bundled JS
  • Enforcement would be wrong — we can't verify the author's claims
  • A manifest hint lets authors document known limitations so consumers can
    make informed decisions before adopting an extension

Tags

Adds an optional tags string array for categorization and discoverability
(e.g. aws, kubernetes, security). Displayed during push and pull.

Both fields

Both fields are fully optional — when omitted they default to [] and are
excluded entirely from the serialized archive manifest (no empty arrays
cluttering the YAML).

manifestVersion: 1
name: "@myorg/my-extension"
version: "2026.02.27.1"
platforms:
  - darwin-aarch64
  - linux-x86_64
tags:
  - aws
  - security
models:
  - my_model.ts

Test plan

  • parseExtensionManifest parses manifests with platforms field
  • parseExtensionManifest parses manifests with tags field
  • parseExtensionManifest defaults both to [] when omitted
  • Push output renders platforms and tags when present
  • Pull output renders platform hint when present
  • Empty fields are omitted from serialized archive manifest
  • deno check passes
  • deno lint passes
  • deno fmt passes
  • All tests pass

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.171331.0-sha.4405553a/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.171331.0-sha.4405553a/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.171331.0-sha.4405553a/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.171331.0-sha.4405553a/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.170532.0-sha.3923790a

27 Feb 17:06
Immutable release. Only release title and notes can be modified.
3923790

Choose a tag to compare

What's Changed

  • fix: skip macOS resource fork files during extension pull (#517)
  • Skip macOS AppleDouble resource fork files (._*) during extension pull extraction, file listing, and file copying
  • Set COPYFILE_DISABLE=1 on the tar extraction command to prevent macOS tar from creating resource fork files during extraction
  • Add debug-level logging of extracted archive contents for diagnosing pull issues

Context

A user on Arch Linux reported that swamp extension pull failed with:

"/tmp/swamp_pull_.../extension/models/._zfs_health.ts":
"Hidden files are not allowed in extensions."

The extension archive itself is clean — tar -tzf confirms it only contains zfs_health.ts, not .zfs_health.ts. The . file was
being created on the user's filesystem during or after extraction, not bundled in the archive.

Why this is the right fix

PR #516 added COPYFILE_DISABLE=1 to the push side, which prevents macOS tar from including ._ files when creating archives.
That fix is correct but insufficient — the ._ files can also appear on the pull side:

  1. macOS tar extraction — On macOS, tar can create ._ resource fork files when extracting, even if the archive doesn't contain
    them. Setting COPYFILE_DISABLE=1 on the extraction command prevents this.
  2. Filesystem-level creation — The reporting user was on Arch Linux with ZFS. Certain filesystem configurations or tools can
    create ._ AppleDouble files independently of tar. The archive was verified clean, yet the ._ file appeared in the temp
    extraction directory.
  3. Older archives — Archives pushed before PR #516 may still contain ._ files bundled inside them.

By filtering .* files in listFiles() and copyDir(), we handle all three cases regardless of origin. These files are
universally recognized as macOS metadata artifacts — they are never legitimate model files (they'd fail the existing hidden
file safety check anyway, and no model should start with .
).

The safety analyzer's hidden file check remains unchanged — it still catches genuinely suspicious hidden files like .env or
.secret. The ._* files simply never reach it because they're filtered out during file enumeration.

Test plan

  • Verify deno check passes
  • Verify deno run test passes
  • Verify deno run test integration/extension_pull_test.ts passes
  • Test swamp extension pull @bixu/zfs completes without resource fork errors
  • Test swamp extension pull @bixu/zfs --log-level debug shows "Archive contains:" lines

Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.170532.0-sha.3923790a/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.170532.0-sha.3923790a/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.170532.0-sha.3923790a/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.170532.0-sha.3923790a/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.134645.0-sha.c48e8ccf

27 Feb 13:47
Immutable release. Only release title and notes can be modified.
c48e8cc

Choose a tag to compare

What's Changed

  • fix: prevent macOS resource fork files in extension archives (#516)

Summary

On macOS, the system tar command automatically includes AppleDouble resource fork files (._* prefix) alongside every file in the archive. When these archives are pulled on Linux, the pull command's safety analyzer rejects them with "Hidden files are not allowed in extensions" because filenames starting with . are flagged as hidden.

This adds COPYFILE_DISABLE=1 to the tar command's environment in extension push. This is the standard macOS mechanism to suppress ._* resource fork inclusion. The variable is harmlessly ignored on non-macOS systems.

Why fix on push (not pull)

  • The ._* files are noise — they should never be in the archive in the first place
  • Fixing on push prevents the problem at the source for all consumers
  • The pull-side hidden file check is a valid security measure that should remain untouched

Change

src/cli/commands/extension_push.ts (line 445)

- env: { GZIP: "-9" },
+ env: { GZIP: "-9", COPYFILE_DISABLE: "1" },

Fixes #515

Test plan

  • deno check passes
  • deno lint passes
  • deno run test — 2290 tests pass, 0 failures
  • Manual: on macOS, run swamp extension push and inspect the resulting archive to confirm no ._* files are included

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.134645.0-sha.c48e8ccf/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.134645.0-sha.c48e8ccf/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.134645.0-sha.c48e8ccf/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.134645.0-sha.c48e8ccf/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.103255.0-sha.63faf259

27 Feb 10:33
Immutable release. Only release title and notes can be modified.
63faf25

Choose a tag to compare

What's Changed

  • fix: extension push resolves workflows from both indexer and extension dirs (#514)

Summary

Follow-up to #513. extension push now resolves workflow references from both workflow directories instead of just one:

  • workflows/ — the indexer symlink tree (created by swamp workflow create)
  • extensions/workflows/ — the extension workflows directory (where swamp extension pull places files, configurable via workflowsDir in .swamp.yaml)

Previously, after #513 landed, workflow resolution only checked the extension workflows dir (resolveWorkflowsDir(marker), default extensions/workflows/). This broke resolution of workflows created via swamp workflow create, which live at workflows/{name}/workflow.yaml as symlinks.

What changed

src/cli/commands/extension_push.ts

  • Workflow resolution now tries the indexer dir (workflows/) first, then falls back to the extension workflows dir (resolveWorkflowsDir(marker))
  • Error messages report both directories when a workflow can't be found in either location

integration/extension_push_test.ts

  • Reverted the existing workflow test back to using workflows/ (indexer symlinks) — confirms the indexer path works
  • Added a new test that places a workflow directly in extensions/workflows/ — confirms the extension path works

Testing

  1. Integration tests — All 11 tests pass, including both workflow resolution paths
  2. Manual end-to-end test — Compiled the binary, created a fresh repo in /tmp, created one workflow via swamp workflow create (indexer dir at workflows/) and one manually in extensions/workflows/, created a manifest referencing both, and ran swamp extension push --dry-run. Both workflows resolved successfully:
    extension·push: Workflows (2):
    extension·push:   "../../private/tmp/.swamp/workflows/workflow-ccc8cfbb-...yaml"
    extension·push:   "../../private/tmp/extensions/workflows/ext-wf.yaml"
    extension·push: Dry run complete
    
  3. deno check — pass
  4. deno lint — pass
  5. deno fmt — pass

Test plan

  • deno check passes
  • deno lint passes
  • deno fmt passes
  • Integration tests pass (11/11)
  • Manual test: workflow from workflows/ (indexer) resolves
  • Manual test: workflow from extensions/workflows/ resolves
  • Manual test: both in same manifest resolve together

🤖 Generated with Claude Code

Co-authored-by: Blake Irvin blakeirvin@me.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.103255.0-sha.63faf259/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.103255.0-sha.63faf259/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.103255.0-sha.63faf259/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.103255.0-sha.63faf259/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.101345.0-sha.b4c26639

27 Feb 10:14
Immutable release. Only release title and notes can be modified.
b4c2663

Choose a tag to compare

What's Changed

  • fix: extension push respects modelsDir/workflowsDir from .swamp.yaml (#513)

Summary

Fixes #512

swamp extension push hardcoded model and workflow directory paths (extensions/models and workflows) instead of reading them from .swamp.yaml. Other commands (extension pull, mod.ts) correctly use resolveModelsDir(marker) / resolveWorkflowsDir(marker) to respect user configuration. This PR makes extension push consistent with the rest of the codebase.

What changed

src/cli/commands/extension_push.ts

  • Added imports for resolveModelsDir, resolveWorkflowsDir, RepoMarkerRepository, and RepoPath
  • Replaced hardcoded resolve(repoDir, "extensions/models") with resolve(repoDir, resolveModelsDir(marker)) — reads modelsDir from .swamp.yaml, falls back to env var SWAMP_MODELS_DIR, then default extensions/models
  • Replaced hardcoded resolve(repoDir, "workflows") with resolve(repoDir, resolveWorkflowsDir(marker)) — reads workflowsDir from .swamp.yaml, falls back to env var SWAMP_WORKFLOWS_DIR, then default extensions/workflows

integration/extension_push_test.ts

  • Fixed existing workflow test to use extensions/workflows/ (the correct default from resolveWorkflowsDir) instead of the old hardcoded workflows/
  • Added new integration test that creates a repo with a custom modelsDir in .swamp.yaml, places model files in that custom directory, and verifies extension push --dry-run finds them correctly

Why this is the right fix

The resolver functions (resolveModelsDir / resolveWorkflowsDir) are the canonical way to determine directory paths throughout the codebase. They implement a clear priority chain: env var > .swamp.yaml config > default. Using them in extension push makes it consistent with extension pull and all other commands, and ensures users who configure custom directories in .swamp.yaml get the expected behavior.

Testing

  1. Integration tests — All 10 extension_push_test.ts tests pass, including the new custom modelsDir test
  2. Manual end-to-end test — Compiled the binary (deno run compile), created a fresh repo in /tmp with modelsDir: custom/my-models in .swamp.yaml, placed a model file in custom/my-models/echo.ts, and ran swamp extension push --dry-run. The command correctly resolved the model at the custom path and completed successfully:
    extension·push: Models (1):
    extension·push:   "custom/my-models/echo.ts"
    extension·push: Dry run complete for "@test/custom-dir-test"@"2026.02.27.1"
    
  3. deno check — pass
  4. deno lint — pass
  5. deno fmt — pass

Test plan

  • deno check passes
  • deno lint passes
  • deno fmt passes
  • Integration tests pass (10/10)
  • Manual test with compiled binary and custom modelsDir

🤖 Generated with Claude Code

Co-authored-by: Blake Irvin blakeirvin@me.com


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.101345.0-sha.b4c26639/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.101345.0-sha.b4c26639/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.101345.0-sha.b4c26639/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.101345.0-sha.b4c26639/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.033008.0-sha.c637ddd9

27 Feb 03:31
Immutable release. Only release title and notes can be modified.
c637ddd

Choose a tag to compare

What's Changed

  • fix: resolve path mismatches in extension push dedup and bundle naming (#509)

Summary

Fixes two path-handling bugs in swamp extension push that affect extensions with symlinked workflow files and nested model paths.

Bug 1: Workflow dedup path mismatch

When merging workflow files from the dependency resolver with those from the manifest, the code compares file paths to avoid duplicates. But the two sources produce different path formats for the same file:

  • Manifest paths: resolved via Deno.realPath(), which canonicalizes the entire path including parent directory symlinks (e.g. /tmp/private/tmp on macOS)
  • Dependency resolver paths: built with join(repoDir, ".swamp/workflows/..."), which doesn't resolve parent symlinks

This caused the dedup to miss matches when any part of the repo path was a symlink, potentially including duplicate workflow files in the archive.

Fix: realPath() the dependency resolver paths before comparison, so both sides use canonical absolute paths.

Bug 2: Bundle naming collision with nested model paths

Bundle entry names used basename(entryPoint, ".ts"), which strips all directory structure. For extensions with nested model paths, this causes silent collisions:

extensions/models/aws/ec2/instance.ts  → basename → instance.js
extensions/models/aws/ecs/instance.ts  → basename → instance.js  ← overwrites!

Only the last model bundled survives. The runtime (user_model_loader.ts) already expects bundles at their relative paths (e.g. .swamp/bundles/aws/ec2/instance.js), so the archive was inconsistent with what the runtime produces locally.

Fix: Use relative(modelsDir, entryPoint) as the bundle key, preserving the full directory structure (e.g. aws/ec2/instanceaws/ec2/instance.js). The pull side already uses a recursive copyDir() for bundles, so nested paths are extracted correctly.

Integration test

Adds a test that creates 3 workflows with symlinks (mimicking swamp's indexer: workflows/{name}/workflow.yaml.swamp/workflows/workflow-{uuid}.yaml), builds a manifest referencing all 3, and verifies all 3 appear in the --dry-run output.

User impact

  • Workflow dedup: Prevents edge-case duplicate workflows when the repo lives under a symlinked path. Most visible on macOS where /tmp is a symlink.
  • Bundle naming: Critical for anyone publishing models with nested directory structures (e.g. aws/ec2/instance.ts, aws/ecs/instance.ts). Without this fix, only one model per basename would survive in the archive. This is a blocker for publishing large extension sets organized in subdirectories.

Test plan

  • deno check — type checking passes
  • deno lint — no lint errors
  • deno fmt — formatting correct
  • deno run test — all 2288 tests pass
  • Integration test verifies multi-workflow archiving with symlinks

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.033008.0-sha.c637ddd9/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.033008.0-sha.c637ddd9/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.033008.0-sha.c637ddd9/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.033008.0-sha.c637ddd9/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

swamp 20260227.023412.0-sha.a76b58ce

27 Feb 02:35
Immutable release. Only release title and notes can be modified.
a76b58c

Choose a tag to compare

What's Changed

  • fix: use unique archive names for workflow files in extension push (#507)

Summary

  • Fix workflow file collision in archives: all {name}/workflow.yaml entries produced the same basename()workflow.yaml, so only the last workflow survived in the tar.gz
  • Fix workflow name extraction for dependency resolver: basename("namespace-debug/workflow.yaml", ".yaml") gave workflow for all entries instead of the actual workflow name
  • Skip auto-resolved model files that don't exist at the conventional path (they may already be in the manifest under a different filename)

Problem

A user published @john/k8s — an extension with 15 models and 13 workflows. When pulled, only 1 workflow was present. The manifest listed:

workflows:
  - namespace-debug/workflow.yaml
  - deployment-status/workflow.yaml
  - service-connectivity/workflow.yaml
  - cluster-health/workflow.yaml
  - security-audit/workflow.yaml
  - rbac-audit/workflow.yaml
  - storage-health/workflow.yaml
  - autoscaling-status/workflow.yaml
  - batch-jobs-status/workflow.yaml
  - network-audit/workflow.yaml
  - pod-inventory/workflow.yaml
  - pod-health-check/workflow.yaml
  - cluster-summary/workflow.yaml

The archive copy step used basename() to name files in the tar.gz:

// basename("namespace-debug/workflow.yaml") → "workflow.yaml"
// basename("deployment-status/workflow.yaml") → "workflow.yaml"
// basename("cluster-summary/workflow.yaml") → "workflow.yaml"
// ... all 13 resolve to the same filename
const destPath = join(extDir, "workflows", basename(wfFile));
await Deno.copyFile(wfFile, destPath);  // each overwrites the previous

Inspecting the published 2026.02.27.1.tar.gz confirmed only cluster-summary (the last manifest entry) survived:

$ tar -tzf 2026.02.27.1.tar.gz | grep workflows
extension/workflows/
extension/workflows/workflow.yaml       ← 1 file instead of 13

$ head -2 extension/workflows/workflow.yaml
id: eaea8dd8-54f0-4d86-ab75-68bd3dd5ec1b
name: cluster-summary                    ← last entry wins

The models directory was fine (15 unique filenames), but all 13 workflows collapsed into one.

Fix

Track each workflow's unique archive name derived from its manifest reference directory:

// "namespace-debug/workflow.yaml" → "namespace-debug.yaml"
// "deployment-status/workflow.yaml" → "deployment-status.yaml"
// "cluster-summary/workflow.yaml" → "cluster-summary.yaml"
const refDir = dirname(wfRef);
const archiveName = refDir !== "."
  ? `${refDir.replace(/\//g, "-")}.yaml`
  : basename(realPath);

Also fixed two related issues in the same flow:

  1. Workflow name extraction for dependency resolverbasename("namespace-debug/workflow.yaml", ".yaml") gave "workflow" for all entries. Now correctly extracts the directory name ("namespace-debug") so the resolver can look up the right workflows.

  2. Phantom model paths from dependency resolver — when models are at non-conventional paths (e.g., greeter.ts instead of @stack72/greeter/model.ts), the resolver guessed a path that didn't exist on disk and the safety analyzer blocked the push. Now validates file existence before adding auto-resolved model files.

Test plan

  • deno check passes
  • deno lint passes
  • deno fmt passes
  • All 2287 tests pass
  • Manual: created test project with 2 models + 2 workflows, verified archive contains both workflow files with unique names
  • Manual: verified project with model instances (dependency resolver) no longer fails with phantom model paths

🤖 Generated with Claude Code


Installation

macOS (Apple Silicon):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.023412.0-sha.a76b58ce/swamp-darwin-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

macOS (Intel):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.023412.0-sha.a76b58ce/swamp-darwin-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (x86_64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.023412.0-sha.a76b58ce/swamp-linux-x86_64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/

Linux (aarch64):

curl -L https://github.com/systeminit/swamp/releases/download/v20260227.023412.0-sha.a76b58ce/swamp-linux-aarch64 -o swamp
chmod +x swamp && sudo mv swamp /usr/local/bin/