Skip to content

fix: contribution setup#224

Closed
Dizzzmas wants to merge 1 commit into
anomalyco:devfrom
Dizzzmas:fix-contributing
Closed

fix: contribution setup#224
Dizzzmas wants to merge 1 commit into
anomalyco:devfrom
Dizzzmas:fix-contributing

Conversation

@Dizzzmas
Copy link
Copy Markdown
Contributor

On fresh clone when following the Contributing section of the README bun run packages/opencode/src/index.ts fails with:

╰─❯ bun run packages/opencode/src/index.ts
Caught panic:

runtime error: invalid memory address or nil pointer dereference

Restoring terminal...

goroutine 1 [running]:
runtime/debug.Stack()
        /usr/local/go/src/runtime/debug/stack.go:26 +0x64
runtime/debug.PrintStack()
        /usr/local/go/src/runtime/debug/stack.go:18 +0x1c
github.com/charmbracelet/bubbletea/v2.(*Program).recoverFromPanic(0x140001a3200, {0x10396b0c0, 0x103f35c70})
        /Users/dizzzmas/go/pkg/mod/github.com/charmbracelet/bubbletea/v2@v2.0.0-beta.3/tea.go:1134 +0xb0
github.com/charmbracelet/bubbletea/v2.(*Program).Run.func2()
        /Users/dizzzmas/go/pkg/mod/github.com/charmbracelet/bubbletea/v2@v2.0.0-beta.3/tea.go:871 +0xdc
panic({0x10396b0c0?, 0x103f35c70?})
        /usr/local/go/src/runtime/panic.go:792 +0x124
github.com/sst/opencode/internal/components/commands.(*commandsComponent).View(0x1400033c3c0)
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/components/commands/commands.go:110 +0xdf8
github.com/sst/opencode/internal/components/chat.(*messagesComponent).home(0x14000989508)
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/components/chat/messages.go:352 +0x758
github.com/sst/opencode/internal/components/chat.(*messagesComponent).View(0x14000a79848?)
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/components/chat/messages.go:288 +0x258
github.com/sst/opencode/internal/layout.(*container).View(0x1400099c000)
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/layout/container.go:103 +0x6f8
github.com/sst/opencode/internal/layout.(*flexLayout).View(0x140001bbe50)
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/layout/flex.go:79 +0x378
github.com/sst/opencode/internal/tui.appModel.View({0x0, 0x0, 0x140004442a0, {0x0, 0x0}, {0x103a30800, 0x1400045ec40}, {0x103a368c0, 0x14000996008}, {0x103a35528, ...}, ...})
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/internal/tui/tui.go:319 +0x2c
github.com/charmbracelet/bubbletea/v2.(*Program).render(0x140001a3200, {0x103a2e858?, 0x140001344d0?})
        /Users/dizzzmas/go/pkg/mod/github.com/charmbracelet/bubbletea/v2@v2.0.0-beta.3/tea.go:795 +0x13c
github.com/charmbracelet/bubbletea/v2.(*Program).Run(0x140001a3200)
        /Users/dizzzmas/go/pkg/mod/github.com/charmbracelet/bubbletea/v2@v2.0.0-beta.3/tea.go:1013 +0xac8
main.main()
        /Users/dizzzmas/Projects/oss/opencode/packages/tui/cmd/opencode/main.go:89 +0x70c

This seems to happen because of opencode.json in the root of the repo having empty keybinds object:

{
  "$schema": "https://opencode.ai/config.json",
  "keybinds": {},
  "mcp": {}
}

Another way to fix it would be to change that json structure, but wasn't sure what the change should be there, so went with checking for null pointer

@thdxr
Copy link
Copy Markdown
Member

thdxr commented Jun 20, 2025

hey appreciate this but i just removed the weird config file for now

@thdxr thdxr closed this Jun 20, 2025
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 26, 2026
…ommand wakeable TUI) (#5)

## Goal

Bare `gruntcode` (no subcommand) should Just Work — the launched TUI is
automatically wakeable. No `serve` + `attach` two-command dance, no
shell wrapper.

Nik framing 2026-05-26: "like i run gruntcode and things can get woken
up via hivemind".

## Behavior of bare `gruntcode` now

1. Probes http://127.0.0.1:4096/session — if a daemon is already serving
   there, attach to it.
2. If no daemon: spawns one as a detached child (`gruntcode serve
   --port 4096 --hostname 127.0.0.1 --print-logs`), waits up to 10s for
   readiness.
3. Re-execs into `gruntcode attach <url>` with all the relevant args
   passed through (--peer-id, --dir, --continue, --session, --fork). The
   user sees an unchanged TUI; implementation detail (the daemon) is
   hidden behind the bare command.
4. Daemon survives the TUI exit — second bare `gruntcode` invocation
   reuses it.

## Escape hatches

- `OPENCODE_DISABLE_AUTO_SERVE=1` skips the auto-serve and uses the
  legacy in-process worker (the path used today by upstream opencode).
- `OPENCODE_AUTO_SERVE_PORT` / `OPENCODE_AUTO_SERVE_HOST` override the
  defaults (4096 / 127.0.0.1).

## Implementation

- New `packages/opencode/src/cli/cmd/tui/auto-serve.ts` exports
  `ensureServeDaemon()`. Returns `{ok: true, url, bin}` or `{ok: false, reason}`.
  Logic:
  - Resolves gruntcode binary path (argv0 if compiled binary; `which
    gruntcode` if running via `bun run` in dev mode; fallback to `which
    opencode`).
  - Probes /session with 1.5s timeout.
  - If 200 → returns the URL.
  - If connection refused → spawns daemon as detached child, polls
    /session every 200ms until ready or 10s timeout.
- `packages/opencode/src/cli/cmd/tui/thread.ts` handler calls
  `ensureServeDaemon()` early. On success: builds attach argv from
  current args and re-execs via child_process.spawn with stdio inherited.
  On failure: logs the reason and falls through to the existing
  in-process worker path.

## Verification

End-to-end manual test:
1. Killed existing daemon. Confirmed `curl :4096/session` returns connection refused.
2. Launched bare TUI from patched source: `bun run src/index.ts --peer-id nik-test --project /tmp`.
3. Process tree showed: bun run → child `gruntcode serve --port 4096 ...` AND child
   `gruntcode attach http://127.0.0.1:4096 --dir /tmp --peer-id nik-test`.
4. `curl :4096/session` returned 200 with the active session.
5. `curl -X POST :4096/session/<id>/prompt_async` accepted (204) and the
   daemon log showed the LLM running. The wake response 'BARE-CMD-WORKS'
   was written to opencode.db (verified via `/session/<id>/message`).

## Known follow-up

The wake response sometimes doesn't render visually in the TUI even
though it's persisted server-side. This is a separate refinement of
patch 2c (SSE subscription) that needs investigation — the wake is
audit-complete and the system works for autonomous coordination, but
human-watcher UX needs polish. Tracked in hivemind anomalyco#221.

Refs hivemind anomalyco#224.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 26, 2026
#6)

When patch 2e spawns the serve daemon, explicitly set OPENCODE_SERVER_URL
in the daemon's env. This propagates to all MCP children the daemon
spawns (via sanitizedProcessEnv in opencode's MCP layer), so hivemind-mcp
+ similar coordination MCPs can discover the daemon's HTTP endpoint at
boot to query session info.

Without this, the MCP child has no way to know what port the daemon is on
(other than guessing :4096), and no way to find its session-id.

OPENCODE_PEER_ID was already inheriting via default env (set by
setPeerID() in the wrapper); making it explicit alongside SERVER_URL for
clarity isn't needed (the {...process.env, OPENCODE_SERVER_URL} pattern
keeps PEER_ID flowing naturally).

Refs hivemind anomalyco#224 wakeable-without-typing follow-up.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 26, 2026
)

The daemon + auto-attach architecture was a workaround for stock opencode's
non-wakeable TUI. With this patch the TUI worker itself binds an HTTP
listener on a pre-picked free localhost port, exposing the same
/session/<id>/prompt_async endpoint used by 'opencode serve' but
in-process. Wake POSTs land directly in the same process that owns the
session, so rendering Just Works (no SSE relay, no attach client, no
display bug).

Concretely:
- New pickFreePort() helper picks a free port via node:net before spawning
  the worker.
- Worker spawn env gets OPENCODE_WAKE_PORT + OPENCODE_SERVER_URL stamped
  in so MCP children inherit them via sanitizedProcessEnv (hivemind-mcp
  auto-announce reads OPENCODE_WAKE_PORT to register peers as wakeable).
- Right after worker boot, TUI calls client.call('server', {port, host})
  which makes Server.listen() bind. Existing 'external' path (server, port
  flag) is preserved as before.
- Escape hatch: OPENCODE_DISABLE_WAKE_LISTENER=1 skips the bind (legacy
  non-wakeable mode, same as upstream).

Drops auto-serve.ts (the daemon-discovery module). The daemon mode is
gone. Closes anomalyco#224 follow-up.

bun typecheck clean.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 26, 2026
… + 'gruntcode' branding (#11)

The session slug is now derived from the launch context instead of a random
adjective-noun pair:

- If --peer-id (or OPENCODE_PEER_ID env) is set, slug = '<peer-id>-<5-char-hash>'
  (e.g. 'nik-test-a3f9k')
- Otherwise slug = '<cwd-basename>-<5-char-hash>'
  (e.g. 'gruntcode-x7p2n')
- Fallback to the random 'crisp-meadow' style only when neither is available

The slug is now rendered in the session sidebar under the title so Nik can tell
parallel tabs apart at a glance (and in screenshots) — previously the only
visible identifier was 'opencode <version>' in the footer.

Also rebrands the footer 'Open Code' -> 'grunt' (green) + 'code' (default text)
to match the GRUNTCODE splash.

New core API:
- Slug.createNamed(base: string): produces '<sanitized-base>-<5-char-hex>'
- getPeerID(): explicit getter to mirror setPeerID()

Sites changed:
- packages/core/src/util/slug.ts: new createNamed helper
- packages/core/src/util/opencode-process.ts: new getPeerID() getter
- packages/opencode/src/session/session.ts: derive slug from peer-id / cwd
- packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx: render slug + rebrand footer

Refs hivemind anomalyco#224 (sessions need visible names + must only show as wake
targets while their TUI is alive).
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 28, 2026
…ommand wakeable TUI) (#5)

## Goal

Bare `gruntcode` (no subcommand) should Just Work — the launched TUI is
automatically wakeable. No `serve` + `attach` two-command dance, no
shell wrapper.

Nik framing 2026-05-26: "like i run gruntcode and things can get woken
up via hivemind".

## Behavior of bare `gruntcode` now

1. Probes http://127.0.0.1:4096/session — if a daemon is already serving
   there, attach to it.
2. If no daemon: spawns one as a detached child (`gruntcode serve
   --port 4096 --hostname 127.0.0.1 --print-logs`), waits up to 10s for
   readiness.
3. Re-execs into `gruntcode attach <url>` with all the relevant args
   passed through (--peer-id, --dir, --continue, --session, --fork). The
   user sees an unchanged TUI; implementation detail (the daemon) is
   hidden behind the bare command.
4. Daemon survives the TUI exit — second bare `gruntcode` invocation
   reuses it.

## Escape hatches

- `OPENCODE_DISABLE_AUTO_SERVE=1` skips the auto-serve and uses the
  legacy in-process worker (the path used today by upstream opencode).
- `OPENCODE_AUTO_SERVE_PORT` / `OPENCODE_AUTO_SERVE_HOST` override the
  defaults (4096 / 127.0.0.1).

## Implementation

- New `packages/opencode/src/cli/cmd/tui/auto-serve.ts` exports
  `ensureServeDaemon()`. Returns `{ok: true, url, bin}` or `{ok: false, reason}`.
  Logic:
  - Resolves gruntcode binary path (argv0 if compiled binary; `which
    gruntcode` if running via `bun run` in dev mode; fallback to `which
    opencode`).
  - Probes /session with 1.5s timeout.
  - If 200 → returns the URL.
  - If connection refused → spawns daemon as detached child, polls
    /session every 200ms until ready or 10s timeout.
- `packages/opencode/src/cli/cmd/tui/thread.ts` handler calls
  `ensureServeDaemon()` early. On success: builds attach argv from
  current args and re-execs via child_process.spawn with stdio inherited.
  On failure: logs the reason and falls through to the existing
  in-process worker path.

## Verification

End-to-end manual test:
1. Killed existing daemon. Confirmed `curl :4096/session` returns connection refused.
2. Launched bare TUI from patched source: `bun run src/index.ts --peer-id nik-test --project /tmp`.
3. Process tree showed: bun run → child `gruntcode serve --port 4096 ...` AND child
   `gruntcode attach http://127.0.0.1:4096 --dir /tmp --peer-id nik-test`.
4. `curl :4096/session` returned 200 with the active session.
5. `curl -X POST :4096/session/<id>/prompt_async` accepted (204) and the
   daemon log showed the LLM running. The wake response 'BARE-CMD-WORKS'
   was written to opencode.db (verified via `/session/<id>/message`).

## Known follow-up

The wake response sometimes doesn't render visually in the TUI even
though it's persisted server-side. This is a separate refinement of
patch 2c (SSE subscription) that needs investigation — the wake is
audit-complete and the system works for autonomous coordination, but
human-watcher UX needs polish. Tracked in hivemind anomalyco#221.

Refs hivemind anomalyco#224.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 28, 2026
#6)

When patch 2e spawns the serve daemon, explicitly set OPENCODE_SERVER_URL
in the daemon's env. This propagates to all MCP children the daemon
spawns (via sanitizedProcessEnv in opencode's MCP layer), so hivemind-mcp
+ similar coordination MCPs can discover the daemon's HTTP endpoint at
boot to query session info.

Without this, the MCP child has no way to know what port the daemon is on
(other than guessing :4096), and no way to find its session-id.

OPENCODE_PEER_ID was already inheriting via default env (set by
setPeerID() in the wrapper); making it explicit alongside SERVER_URL for
clarity isn't needed (the {...process.env, OPENCODE_SERVER_URL} pattern
keeps PEER_ID flowing naturally).

Refs hivemind anomalyco#224 wakeable-without-typing follow-up.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 28, 2026
)

The daemon + auto-attach architecture was a workaround for stock opencode's
non-wakeable TUI. With this patch the TUI worker itself binds an HTTP
listener on a pre-picked free localhost port, exposing the same
/session/<id>/prompt_async endpoint used by 'opencode serve' but
in-process. Wake POSTs land directly in the same process that owns the
session, so rendering Just Works (no SSE relay, no attach client, no
display bug).

Concretely:
- New pickFreePort() helper picks a free port via node:net before spawning
  the worker.
- Worker spawn env gets OPENCODE_WAKE_PORT + OPENCODE_SERVER_URL stamped
  in so MCP children inherit them via sanitizedProcessEnv (hivemind-mcp
  auto-announce reads OPENCODE_WAKE_PORT to register peers as wakeable).
- Right after worker boot, TUI calls client.call('server', {port, host})
  which makes Server.listen() bind. Existing 'external' path (server, port
  flag) is preserved as before.
- Escape hatch: OPENCODE_DISABLE_WAKE_LISTENER=1 skips the bind (legacy
  non-wakeable mode, same as upstream).

Drops auto-serve.ts (the daemon-discovery module). The daemon mode is
gone. Closes anomalyco#224 follow-up.

bun typecheck clean.
terrxo added a commit to grunt-it/gruntcode that referenced this pull request May 28, 2026
… + 'gruntcode' branding (#11)

The session slug is now derived from the launch context instead of a random
adjective-noun pair:

- If --peer-id (or OPENCODE_PEER_ID env) is set, slug = '<peer-id>-<5-char-hash>'
  (e.g. 'nik-test-a3f9k')
- Otherwise slug = '<cwd-basename>-<5-char-hash>'
  (e.g. 'gruntcode-x7p2n')
- Fallback to the random 'crisp-meadow' style only when neither is available

The slug is now rendered in the session sidebar under the title so Nik can tell
parallel tabs apart at a glance (and in screenshots) — previously the only
visible identifier was 'opencode <version>' in the footer.

Also rebrands the footer 'Open Code' -> 'grunt' (green) + 'code' (default text)
to match the GRUNTCODE splash.

New core API:
- Slug.createNamed(base: string): produces '<sanitized-base>-<5-char-hex>'
- getPeerID(): explicit getter to mirror setPeerID()

Sites changed:
- packages/core/src/util/slug.ts: new createNamed helper
- packages/core/src/util/opencode-process.ts: new getPeerID() getter
- packages/opencode/src/session/session.ts: derive slug from peer-id / cwd
- packages/opencode/src/cli/cmd/tui/routes/session/sidebar.tsx: render slug + rebrand footer

Refs hivemind anomalyco#224 (sessions need visible names + must only show as wake
targets while their TUI is alive).
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.

2 participants