Skip to content

feat(core): add Go export extraction to content extractor (closes #17)#69

Merged
smorchj merged 1 commit intomainfrom
feat/go-content-extractor
Apr 15, 2026
Merged

feat(core): add Go export extraction to content extractor (closes #17)#69
smorchj merged 1 commit intomainfrom
feat/go-content-extractor

Conversation

@smorchj
Copy link
Copy Markdown
Owner

@smorchj smorchj commented Apr 15, 2026

Summary

Adds Go (`.go`) support to the content extractor, mirroring the existing Python, Java, Ruby, and PHP blocks inside `extractExports()`.

Go conventions handled

Pattern Kind Notes
`func Name(...) returnType` `function` Top-level functions, only uppercase names
`func (r *Receiver) Name(...)` `function` Methods on struct receivers
`type Name struct` `class` Structs
`type Name interface` `interface` Interface types
`type Name OtherType` `type` Type aliases (excludes `struct`/`interface` via negative lookahead)
`const Name = ...` `const` Exported constants
`var Name = ...` `const` Exported vars (mapped to `const` kind — no `var` kind exists)

Go export rule enforced: only identifiers whose first letter is uppercase are emitted. Lowercase names like `privateHelper` or `internalState` are filtered out.

All names and signatures pass through the existing `sanitizeExportName` / `sanitizeExportSignature` helpers for injection hardening.

Tests

5 new tests inside a `describe('extractDirectoryContent — Go', ...)` block:

  1. `extracts exported top-level functions and methods` — verifies `Serve`, `Start` are extracted and `privateHelper` is filtered
  2. `extracts exported struct, interface, and type alias` — `Server → class`, `Handler → interface`, `UserID → type`
  3. `extracts exported const and var (var maps to const kind)` — `MaxRetries`, `DefaultTimeout`, `ErrNotFound` all → `const`
  4. `filters out all lowercase (unexported) identifiers` — confirms the Go convention is enforced
  5. `flags injection text in Go function names` — `IgnoreAllPreviousInstructions` → `[flagged]`

Total: 76/76 tests passing (up from 71).

How this PR was written

This PR was written by Claude running inside the Klonode Workstation chat panel, solving the task through its own UI. The user pasted the task description into the chat textarea, clicked send, and Claude used Read → Edit → Bash (test runner) → git checkout to produce the implementation. This is the second PR written end-to-end by Klonode-on-itself (PR #67 was PHP).

The task surfaced several Klonode UX bugs that are fixed in sibling PRs:

Closes

Closes #17.

smorchj added a commit that referenced this pull request Apr 15, 2026
Two separate issues combined to make long coding tasks inside the
Workstation chat panel hit a dead end with the generic fallback message
\"Claude brukte alle steg. Prøv et mer spesifikt spørsmål.\"

## Issue 1: max-turns was 50 for bypass mode

A realistic coding task — \"add a language extractor and 5-9 unit tests,
run the suite, commit on a branch\" — routinely needs 80-150 tool calls.
Bypass mode was capped at 50, which hit the ceiling mid-task and caused
Claude to return an empty result with num_turns = 50. The UI then
rendered the fallback \"alle steg\" message, making the session appear
dead.

Raise bypass and CO to 500. question (1) and plan (15) stay tight
because those modes exist precisely to cap turn spend.

## Issue 2: -p mode session IDs are not reliably resumable

Klonode captured the session_id from Claude CLI's first `init` stream
event and stored it as the tab's `cliSessionIds` entry. On the next
send, ChatPanel re-included it as `--resume <id>` so Claude would pick
up the conversation.

Problem: a session spawned with `-p` emits that session_id but does
NOT stay in Claude CLI's resumable session cache the same way
interactive sessions do. The next `--resume` spawn returns:

    No conversation found with session ID: <uuid>

Claude then emits a result of type `error_during_execution` with empty
text, and the UI falls back to \"Claude brukte alle steg.\" The session
appears unresponsive forever until the user clicks + for a new tab.

Fix: drop `--resume` entirely from the stream endpoint. Every send is a
fresh spawn, always with the system prompt prepended. Continuity on
the user side lives in the persisted `chatStore.messages`, and Claude
re-routes against the generated CLAUDE.md + CONTEXT.md on every
message, which matches Klonode's per-query routing philosophy.

## How these were found

Ran `klonode init` on the repo, saw the full contextualized tree in
the Workstation TreeView, sent a realistic task (\"add Go extractor
support with 9 tests\") through the chat textarea + send button. Got
the \"alle steg\" fallback. Direct CLI test with the stored sessionId
reproduced the \"No conversation found\" error. Sent again without
--resume, hit a separate cap at exactly 50 tool calls. Raised to 500
and dropped --resume in one change.

After this fix, the same task completes in ~6 tool calls and produces
a branch + tests + passing suite.

## Sibling PRs

- #68 fixes the `get is not defined` crash + demo graph repoPath + auto
  loading the real project graph at boot
- #67 and #69 are the \"this PR was written by Klonode itself\" PRs
  (PHP and Go extractors) that these blockers were preventing
smorchj added a commit that referenced this pull request Apr 15, 2026
Two separate issues combined to make long coding tasks inside the
Workstation chat panel hit a dead end with the generic fallback message
\"Claude brukte alle steg. Prøv et mer spesifikt spørsmål.\"

## Issue 1: max-turns was 50 for bypass mode

A realistic coding task — \"add a language extractor and 5-9 unit tests,
run the suite, commit on a branch\" — routinely needs 80-150 tool calls.
Bypass mode was capped at 50, which hit the ceiling mid-task and caused
Claude to return an empty result with num_turns = 50. The UI then
rendered the fallback \"alle steg\" message, making the session appear
dead.

Raise bypass and CO to 500. question (1) and plan (15) stay tight
because those modes exist precisely to cap turn spend.

## Issue 2: -p mode session IDs are not reliably resumable

Klonode captured the session_id from Claude CLI's first `init` stream
event and stored it as the tab's `cliSessionIds` entry. On the next
send, ChatPanel re-included it as `--resume <id>` so Claude would pick
up the conversation.

Problem: a session spawned with `-p` emits that session_id but does
NOT stay in Claude CLI's resumable session cache the same way
interactive sessions do. The next `--resume` spawn returns:

    No conversation found with session ID: <uuid>

Claude then emits a result of type `error_during_execution` with empty
text, and the UI falls back to \"Claude brukte alle steg.\" The session
appears unresponsive forever until the user clicks + for a new tab.

Fix: drop `--resume` entirely from the stream endpoint. Every send is a
fresh spawn, always with the system prompt prepended. Continuity on
the user side lives in the persisted `chatStore.messages`, and Claude
re-routes against the generated CLAUDE.md + CONTEXT.md on every
message, which matches Klonode's per-query routing philosophy.

## How these were found

Ran `klonode init` on the repo, saw the full contextualized tree in
the Workstation TreeView, sent a realistic task (\"add Go extractor
support with 9 tests\") through the chat textarea + send button. Got
the \"alle steg\" fallback. Direct CLI test with the stored sessionId
reproduced the \"No conversation found\" error. Sent again without
--resume, hit a separate cap at exactly 50 tool calls. Raised to 500
and dropped --resume in one change.

After this fix, the same task completes in ~6 tool calls and produces
a branch + tests + passing suite.

## Sibling PRs

- #68 fixes the `get is not defined` crash + demo graph repoPath + auto
  loading the real project graph at boot
- #67 and #69 are the \"this PR was written by Klonode itself\" PRs
  (PHP and Go extractors) that these blockers were preventing
Detects uppercase-only exported identifiers in .go files: top-level
functions, methods, struct/interface/type-alias types, const, and var
(mapped to const kind). Adds 5 new tests covering all constructs,
lowercase filtering, and injection sanitization.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@smorchj smorchj force-pushed the feat/go-content-extractor branch from 9d3a8ea to b5e185d Compare April 15, 2026 08:08
@smorchj smorchj merged commit 164e705 into main Apr 15, 2026
1 check passed
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 Go support to content extractor

1 participant