Skip to content

feat(cli): add jss install <name> subcommand (Phase 1 of #464) - #479

Merged
melvincarvalho merged 1 commit into
gh-pagesfrom
issue-478-jss-install
May 18, 2026
Merged

feat(cli): add jss install <name> subcommand (Phase 1 of #464)#479
melvincarvalho merged 1 commit into
gh-pagesfrom
issue-478-jss-install

Conversation

@melvincarvalho

Copy link
Copy Markdown
Contributor

Fixes #478. Phase 1 of the phased install plan (#464 comment).

What

`jss install ` clones `github.com/solid-apps/` and pushes it into the running pod at `/public/apps//`. Server operators using `jss start` directly no longer need a wrapper to install Solid apps.

```bash
jss install chrome
jss install vellum pdf hub # multi-arg
jss install chrome --pod http://other.host:5444 # remote pod
```

Implementation

Direct port of jspod's proven `runInstall` (~120 LoC). New file: `src/cli/install.js` exporting `runInstall(names, options)`. Subcommand wired into `bin/jss.js` via commander `.command('install <names...>')`.

The hard infrastructure (git auto-init `-b main`, regular-repo extraction via `updateInstead`, ACL-gated push) already lives in JSS — this is just the orchestration layer.

Behavior

  • Source resolution: `` → `https://github.com/solid-apps/` (Phase 1 hardcoded)
  • Auth: `POST /idp/credentials` for bearer token. If IDP isn't running (404), proceed without — supports `--public` mode pods
  • Clone: Full clone, no `--depth` (shallow pushes are rejected by JSS git-receive)
  • Push: Dual `HEAD:main` and `HEAD:gh-pages` so it works regardless of operator's `init.defaultBranch`. Whichever matches server-side HEAD triggers `updateInstead` and extracts the working tree
  • Skip-on-existing: Auto-init's "won't init non-empty path" 404 translated to a friendly `⊘ : skipped` message
  • Idempotency: Existing repo accepts the push normally; re-runs are safe
  • Output: Per-app `✓` / `⊘` / `✗` lines + summary
  • Exit code: 1 if any install failed; 0 if all succeeded or all were skipped

Flags

Flag Default Purpose
`--pod ` `http://localhost:4443\` Target pod URL
`--user ` `me` Username for token fetch
`--password ` `$JSS_SINGLE_USER_PASSWORD` or `me` Password

Verified end-to-end against a fresh `jss start`

  • `jss install chrome` → `/public/apps/chrome/index.html` returns 200
  • `jss install vellum pdf` → both installed, multi-arg works
  • `jss install chrome` (re-run) → idempotent, no error
  • `jss install ../etc/passwd` → validation error, exit 1
  • `jss install nonexistent-name-12345` → clone fails, exit 1
  • `jss install chrome --password wrong` → 401 auth fails, exit 1
  • `jss install --help` → subcommand help renders cleanly

Depends on

  • #477 — port default fallback (`--pod` default `http://localhost:4443\` aligns with the `config.js` default; the leftover `3000` fallbacks in `src/server.js` should be fixed separately)

Not in scope (later phases of #464)

  • Phase 2: `/` shorthand, full URLs, `#` pinning, `=`
  • Phase 3: `--did did:nostr:` resolution
  • Phase 4: `--nostr-privkey ` NIP-98 signed install
  • Phase 5: curated default set (no-arg `jss install`)
  • Phase 6: `--bundle ` (apt-style meta-packages)

Diff

  • `bin/jss.js` +24 (new subcommand block)
  • `src/cli/install.js` +205 (new file, the runInstall implementation)

Direct port of jspod's `runInstall` (~120 LoC) into a JSS-native
subcommand. Server operators using `jss start` no longer need to
drop to a wrapper to get the install command.

  jss install chrome
  jss install vellum pdf hub
  jss install chrome --pod http://other.host:5444

Behavior:
- Resolves <name> to https://github.com/solid-apps/<name>
- Full git clone (no --depth — shallow pushes are rejected on
  git-receive)
- Dual push (HEAD:main + HEAD:gh-pages) so it works regardless of
  the operator's init.defaultBranch
- Skip-on-existing-non-repo paths with a friendly ⊘ message
- Idempotent on re-run (existing repo accepts the push normally)
- Per-app status output (✓ / ⊘ / ✗), summary line, exit 1 if any
  failed

Auth via `POST <pod>/idp/credentials`. `--pod` / `--user` /
`--password` flags; password also reads JSS_SINGLE_USER_PASSWORD
env. If the IDP isn't running (--public mode), the install proceeds
without a token.

Verified end-to-end against a fresh `jss start` pod:
  - install chrome → /public/apps/chrome/index.html 200
  - install vellum pdf (multi-arg)
  - install chrome (re-run, idempotent)
  - install ../etc/passwd → validation error, exit 1
  - install nonexistent-name → clone-fails, exit 1
  - install chrome --password wrong → auth-fails, exit 1

Phases 2-6 (full spec, --did, --nostr-privkey, curated set,
--bundle) build on this same atom. See #464 comment for the
roadmap.

Fixes #478
@melvincarvalho
melvincarvalho merged commit e681c17 into gh-pages May 18, 2026
1 check passed
@melvincarvalho
melvincarvalho deleted the issue-478-jss-install branch May 18, 2026 04:12
melvincarvalho added a commit that referenced this pull request May 18, 2026
Includes since 0.0.197:
- jss install <name>            (#479, Phase 1 of #464)
- jss install generalized spec  (#481, Phase 2 of #464)
- jss install --nostr-privkey   (#483, Phase 4 of #464)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add jss install <name> subcommand (Phase 1 of #464)

1 participant