Paperclip's plugin-loader does ESM named imports of parseStdoutLine when
loading opencode_k8s, e.g.:
import { parseStdoutLine } from "paperclip-adapter-opencode-k8s/ui-parser"
The previous esbuild bundle wrote CJS via __toCommonJS getters, which
cjs-module-lexer can't statically detect — Node fails the link with:
SyntaxError: The requested module './ui-parser.js' does not provide
an export named 'parseStdoutLine'
Also, with the package.json `"type": "module"` field, dist/ui-parser.js
was being interpreted as ESM by the loader, compounding the failure.
Fix: emit ui-parser as a proper CJS sub-package.
- Move output to dist/ui-parser/ui-parser.js
- Generate dist/ui-parser/package.json with `{"type":"commonjs"}` so Node
treats the file as CJS regardless of the parent type:module
- Use `tsc -p tsconfig.ui-parser.json` (module: commonjs) instead of
esbuild — the output is plain `exports.parseStdoutLine = parseStdoutLine`
which cjs-module-lexer detects natively
- Update the exports map: `"./ui-parser": "./dist/ui-parser/ui-parser.js"`
- Drop the esbuild devDependency
Verified locally:
- `import { parseStdoutLine } from "...ui-parser"` works (Node 25)
- Read-file-as-text + `new Function(...)` worker pattern still works
- 382/382 tests pass; typecheck clean
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Run tailPodLogFile and waitForJobCompletion in parallel via Promise.allSettled;
completion sets stopSignal.stopped so the tail loop drains and exits. Without
this, tailPodLogFile loops forever — the only natural exit was fh.stat()
throwing on file removal, which never happened during normal job completion.
- Restructure tail loop to read-then-sleep, with a final drain after stopSignal
is set to capture bytes written between the last poll and terminal state.
- Port the c8429cf fix from paperclip-adapter-claude-k8s:
* buildPodLogPath now writes to /paperclip/instances/default/data/run-logs/...
to match the server PVC layout (the /data/ segment was missing).
* Drop the mkdir -p ... && from both init container command variants — the
PVC isn't mounted in the init container, so the mkdir was failing with
exit code 1 and the && short-circuit prevented the prompt copy.
- Test infrastructure:
* Hoisted fs/promises mock now uses importOriginal so readFile (used for
skill bundle loading) hits the real implementation.
* setMockJsonl() lets individual tests inject specific JSONL into the tail's
read buffer (previously dead constants in the test file).
* fh.read mock now writes into the caller's buffer instead of returning a
separate one.
- Add src/server/test.test.ts covering testEnvironment (was 0% → 98.5% stmts).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Paperclip UI loads each adapter's ui-parser.js inside a sandboxed
Web Worker via `new Function(...)` to render the run transcript. The
worker can only evaluate CJS — ESM `export` syntax silently fails to
register `parseStdoutLine`, and the run window falls back to dumping
raw JSONL.
tsc was emitting ESM `export function parseStdoutLine`, so every
published version since the parser was added has shipped a parser the
UI can't load. Add the same esbuild step the claude-k8s adapter uses
(0.2.4) to overwrite dist/ui-parser.js with a CJS bundle that assigns
to module.exports.
Also bump @paperclipai/adapter-utils from a stale 2026.415.0-canary.7
pin to ^2026.428.0 (current stable). All 406 tests pass against the
new types; no API drift in the imported surface.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
So we can answer "what's coverage?" without re-installing each time.
Run with: \`npx vitest run --coverage --coverage.provider=v8 --coverage.reporter=text-summary\`
Co-Authored-By: Paperclip <noreply@paperclip.ing>
When multiple tasks are assigned simultaneously, only one K8s job can run
at a time (shared PVC/session guard). Previously, all other tasks received
k8s_concurrent_run_blocked immediately and stayed blocked forever.
Now the guard retries once: wait for all blocking jobs to complete via
waitForJobCompletion, then re-check before proceeding to create a new job.
If the re-check still shows a running job, the error is returned as before.
The agentCreationMutex already serializes guard-check + job-create, so
tasks naturally queue up and execute one at a time without concurrent jobs.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- config-schema: add instructionsFilePath UI field (Core group, text type)
- server/index.ts: set supportsInstructionsBundle=true, instructionsPathKey="instructionsFilePath"
- execute.ts: read instructionsFilePath file + desired skill markdown files from PVC; pass to buildJobManifest as instructionsContent / skillsBundleContent
- job-manifest.ts: accept instructionsContent + skillsBundleContent in JobBuildInput; prepend both to prompt via joinPromptSections; add instructionsChars + skillsBundleChars to promptMetrics
- index.ts: document instructionsFilePath and skills injection in agentConfigurationDoc
- CLAUDE.md: document skill materialization (ephemeral mode) and instructionsFilePath field
- Bump version to 0.1.18
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Upgrade from ^2026.411.0-canary.8 to 2026.415.0-canary.7 to get
ServerAdapterModule capability flag fields (supportsInstructionsBundle,
instructionsPathKey, requiresMaterializedRuntimeSkills).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace joinPromptSections, stringifyPaperclipWakePayload, and
renderPaperclipWakePrompt with imports from adapter-utils/server-utils
(the fork's renderPaperclipWakePrompt adds execution stage routing,
resume delta sections, and full comment batch rendering)
- Replace local inferOpenAiCompatibleBiller with import from adapter-utils
- Declare sessionManagement using getAdapterSessionManagement("opencode_local")
with fallback defaults for proper session compaction policy
- Add log redaction via redactHomePathUserSegments in streamPodLogs
- Bump peerDependency to >=0.3.1 and version to 0.1.14
Co-Authored-By: Paperclip <noreply@paperclip.ing>
Lock file was stale at 0.1.11 with an outdated peerDependency constraint;
bring it in line with package.json (0.1.13, >=0.3.0).
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The UI wasn't surfacing config parameters because getConfigSchema wasn't
part of the ServerAdapterModule interface in adapter-utils >=0.3.0. The
canary release (2026.411.0-canary.8) adds ConfigFieldSchema,
AdapterConfigSchema, and getConfigSchema to the type. This removes the
local type augmentation workaround and the unsafe `as ServerAdapterModule`
cast, letting TypeScript properly validate the schema contract.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
- Add vitest with 26 passing tests for parse and job-manifest
- Set models to undefined for free-text model input
- Add fsGroupChangePolicy: "OnRootMismatch" to reduce volume chown delays
- Change job name prefix to agent-opencode- for adapter identification
- Add .npmrc to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>